├── .travis.yml ├── LICENSE ├── README.md ├── api ├── funders.js ├── index.js ├── iteration.js └── iterations.js ├── config.js ├── development.md ├── docs.md ├── docs └── economics-of-opensource.md ├── index.js ├── lib ├── auto-api.js ├── badge.js ├── certs.js ├── get.js ├── https-redirect.js └── qr.js ├── package.json ├── static ├── LICENSE ├── grumpy.jpg ├── index.html └── style.css ├── templates └── index.html ├── test ├── fixtures │ ├── collaborators.json │ ├── comments.json │ ├── funders.json │ ├── issues.json │ ├── iteration.json │ ├── iteration2.json │ ├── iterations.json │ └── wallet.json ├── funders.js └── iterations.js └── views ├── index.js ├── iteration.js └── layout.js /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 0.6 4 | - 0.8 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Dominic Tarr 2 | 3 | Permission is hereby granted, free of charge, 4 | to any person obtaining a copy of this software and 5 | associated documentation files (the "Software"), to 6 | deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, 8 | merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom 10 | the Software is furnished to do so, 11 | subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 18 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 20 | ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Feed Open Source 2 | 3 | We need another way to fund software. All the other ways are 4 | [broken or unscalable]( 5 | http://dominictarr.com/post/71958587606/some-thoughts-on-the-economics-of-software-development). 6 | We need to align the interests of the users with developers. 7 | We need to feed developers, and the software needs to be freely distributable. 8 | 9 | ## The Problem 10 | 11 | Software only needs to be written once. 12 | Bugs need to be patched, but a bug only needs to be patched once. 13 | 14 | Why do we pay for software many times, or not at all? 15 | Software should be paid for exactly once. 16 | 17 | You can't sell software like you sell physical items, 18 | software is too easy to copy. 19 | 20 | But here is something you can sell: _a promise to write software_ 21 | 22 | ## The Vision 23 | 24 | Take agile consulting to the crowds. 25 | 26 | Work is funded in iterations, on a fixed time basis, a week or two at a time. 27 | Clients and developers negotiate what features they are most need in the next iteration. 28 | The developers implement that, and the clients evaluate it. Repeat. 29 | Every one is constantly in the loop. 30 | 31 | *feedopensource* is different to agile consulting because "the clients" 32 | are a crowd of people. 33 | *feedopensource* is different to crowd-funding platforms because clients 34 | will have real power to influence a project, and keep it on task. 35 | 36 | A client does not commit all their money at once, so the developers 37 | must keep them satisfied to receive funding in the future. 38 | For the client, most of the uncertainty about the project is removed, 39 | because they see it improve at each stage. 40 | 41 | Less uncertainty means clients can fund more, 42 | because they know the value they are getting. 43 | 44 | ## This is _not_ a startup. 45 | 46 | This is not Anything as a Service. 47 | This is not an Anything-Platform. 48 | 49 | This is just an open source tool for feeding open source projects. 50 | 51 | *feedopensource* has a [liberal open-source license](./LICENSE). 52 | 53 | You may use *feedopensource* to fund your own projects, 54 | as *feedopensource* feeds itself with *feedopensource* 55 | 56 | ## The Prototype 57 | 58 | The prototype has progressed to iteration 2! 59 | 60 | [![feedopensource badge](https://feedopensource.com/iteration/dominictarr/feedopensource/18oBEV9hFdDMEct9Ys2bSAuEY4bi2KSMHi.png#1.2)]( 61 | https://feedopensource.com/iteration/dominictarr/feedopensource/18oBEV9hFdDMEct9Ys2bSAuEY4bi2KSMHi 62 | ) 63 | 64 | Currently, feedopensource can: 65 | * track the state of a project on github, 66 | * represent this as a png (embeddable in github issues) and as a web page 67 | (https://feedopensource.com/iteration/dominictarr/feedopensource/1PTAwipYpP63uNrcxfm5FewxRdZyar6ceu) 68 | * associate a bitcoin transaction with a github user. 69 | 70 | This is very simple, but with the support of iteration 1's 71 | [funders](https://feedopensource.com/iteration/1PTAwipYpP63uNrcxfm5FewxRdZyar6ceu) 72 | 73 | ## Iteration 2 74 | 75 | Tasks for iteration 2 are listed [here](https://github.com/dominictarr/feedopensource/issues/20) 76 | 77 | ### Bitcoin 78 | 79 | Transfer btc into `18oBEV9hFdDMEct9Ys2bSAuEY4bi2KSMHi` to fund iteration 2. 80 | 81 | Please post a comment [here](https://github.com/dominictarr/feedopensource/issues/4) 82 | with your transaction id. 83 | 84 | Not sure how to buy bitcoin? [Learn how you can buy bitcoin in your country](http://howtobuybitcoins.info) 85 | Also see [this issue](https://github.com/dominictarr/feedopensource/issues/5) 86 | 87 | ### Credit-card 88 | 89 | If you would rather fund this with normal money please 90 | comment with the amount you'd like to pay on 91 | [this issue](https://github.com/dominictarr/feedopensource/issues/6) 92 | 93 | ## The Plan 94 | 95 | `Clients` and `Developers` post issues to `Tasks` and plan `Iterations`. 96 | (on github or [similar](https://github.com/dominictarr/feedopensource/issues/7)) 97 | 98 | *feedopensoure* will be implemented as a bot that posts to and scrapes/apis Github. 99 | This avoids the problem of having to implement a fresh discussion platform, Notifications, 100 | User system, etc! 101 | 102 | Please comment on the [first iteration!](https://github.com/dominictarr/feedopensource/issues/4) 103 | 104 | ## The Workflow 105 | 106 | In the future you might use *feedopensource* like this: 107 | 108 | * `Clients` post issues requesting features or bug fixes. 109 | (["Tasks"](https://github.com/dominictarr/feedopensource/issues/1)) 110 | * `Tasks` are grouped into an [Iteration](https://github.com/dominictarr/feedopensource/issues/3) 111 | (an `"Iteration"` is just an issue that links to a set of `Tasks` with a 112 | [progress bar](https://github.com/dominictarr/feedopensource/issues/2)) 113 | `Clients` and `Developers` can discuss that iteration, and decide to fund it or not. 114 | * progress can be tracked by posting to the `Iteration` issue, or to the Task issues. 115 | as the Tasks progress (are closed) the progress bar updates, this time to show work done. 116 | * There will be progress bar pngs representing project status and history which can easily 117 | be added into github issues and readmes. 118 | * Users will have a way to associate a bitcoin wallet with a github account, so they can 119 | [claim their payment](https://github.com/dominictarr/feedopensource/issues/5) 120 | 121 | -------------------------------------------------------------------------------- /api/funders.js: -------------------------------------------------------------------------------- 1 | 2 | //parse comments 3 | //pull out users and their payment transactions. 4 | 5 | var transaction = /([0-9a-f]{64})/ 6 | 7 | function find(txs, test) { 8 | for(var t in txs) { 9 | if(test(txs[t])) return txs[t] 10 | } 11 | } 12 | 13 | function getHash(hash) { 14 | return function (obj) { 15 | return obj.hash === hash 16 | } 17 | } 18 | 19 | module.exports = function (comments, wallet) { 20 | var address = wallet.address 21 | var users = {} 22 | var txs = {} 23 | var paid = {} 24 | wallet.txs = wallet.txs || [] 25 | comments.forEach(function (comment) { 26 | var name = comment.user.login 27 | var user = users[name] = users[name] || comment.user 28 | user.txs = user.txs || [] 29 | user.sum = user.sum || 0 30 | 31 | var body = comment.body 32 | var m = transaction.exec(body) 33 | 34 | var hash = m && m[1] 35 | 36 | if(hash) { 37 | var tx = find(wallet.txs, function (tx) { 38 | return tx.hash === hash 39 | }) 40 | if(tx) tx.out.forEach(function (e) { 41 | if(e.addr === address) { //this transaction is into the iteration wallet. 42 | user.sum += e.value 43 | user.txs.push(tx) 44 | paid[hash] = true 45 | } 46 | }) 47 | } 48 | }) 49 | 50 | //remove users who commented but didn't fund anything. 51 | for(var user in users) { 52 | if(!users[user].sum) 53 | delete users[user] 54 | } 55 | 56 | //mark any remaining transactions as unclaimed 57 | var unclaimed = {unclaimed: true, txs: [], sum: 0, login: '**unclaimed**'} 58 | 59 | wallet.txs.forEach(function (tx) { 60 | if(!paid[tx.hash]) { 61 | tx.out.forEach(function (e) { 62 | if(e.addr === address) { //this transaction is into the iteration wallet. 63 | unclaimed.txs.push(tx) 64 | unclaimed.sum += e.value 65 | } 66 | }) 67 | 68 | } 69 | }) 70 | 71 | var ordered = [] 72 | 73 | for(var user in users) 74 | ordered.push(users[user]) 75 | ordered.push(unclaimed) 76 | 77 | ordered.sort(function (a, b) { 78 | return b.sum - a.sum 79 | }) 80 | return ordered 81 | } 82 | 83 | if(!module.parent) 84 | console.log(module.exports(require('./comments.json'), require('./into-wallet.json'))) 85 | -------------------------------------------------------------------------------- /api/index.js: -------------------------------------------------------------------------------- 1 | var get = require('../lib/get') 2 | var resolve = require('url').resolve 3 | var join = require('path').join 4 | var funders = require('./funders') 5 | var iterations = require('./iterations') 6 | var iteration = require('./iteration') 7 | var config = require('../config') 8 | 9 | var auth = ( 10 | config.id && config.secret ? 11 | '?client_id='+config.id+'&client_secret='+config.secret 12 | : '' 13 | ) 14 | 15 | function ghApi() { 16 | return resolve('https://api.github.com', join.apply(null, arguments)) + auth + (auth ? '&' : '?') + 'per_page=100' 17 | } 18 | 19 | function bcApi() { 20 | return resolve('https://blockchain.info', join.apply(null, arguments) + '?format=json') 21 | } 22 | 23 | var api = exports 24 | 25 | api.funders = function (user, repo, issue, wallet, cb) { 26 | get.all([ 27 | ghApi('repos', user, repo, 'issues', issue, 'comments'), 28 | bcApi('address', wallet) 29 | ], function (err, args) { 30 | if(err) return cb(err) 31 | cb(null, funders.apply(null, args)) 32 | }) 33 | } 34 | 35 | api.iterations = function (user, repo, cb) { 36 | get.all([ 37 | ghApi('repos', user, repo, 'issues'), 38 | ghApi('repos', user, repo, 'collaborators') 39 | ], function (err, data) { 40 | if(err) return cb(err) 41 | cb(null, iterations(data[0], data[1], user, repo)) 42 | }) 43 | } 44 | 45 | api.iteration = function (user, repo, wallet, cb) { 46 | api.iterations(user, repo, function (err, data) { 47 | if(err) return cb(err) 48 | for(var i in data) { 49 | if(data[i].wallet === wallet) { 50 | var iter = data[i] 51 | return api.funders(user, repo, ''+iter.number, wallet, function (err, funders) { 52 | if(err) return cb(err) 53 | return cb(null, iteration(iter, funders)) 54 | }) 55 | } 56 | } 57 | cb(new Error('could not find iteration')) 58 | }) 59 | } 60 | 61 | if(!module.parent) { 62 | var args = process.argv.slice(2) 63 | var method = args.shift() 64 | var p = console.error 65 | if(!api[method]) { 66 | p('expected one of:', Object.keys(api).join(', ')) 67 | p() 68 | p('try:') 69 | p('node ./api/index.js funders dominictarr feedopensource 4 1PTAwipYpP63uNrcxfm5FewxRdZyar6ceu') 70 | p('node ./api/index.js iterations dominictarr feedopensource') 71 | p('node ./api/index.js iteration dominictarr feedopensource 1PTAwipYpP63uNrcxfm5FewxRdZyar6ceu') 72 | return 73 | } else if(api[method].length - 1 !== args.length) { 74 | p(JSON.stringify(method) +' command takes ' + (api[method].length - 1) + ' arguments') 75 | return 76 | } 77 | 78 | api[method].apply(null, args.concat(function (err, data) { 79 | if(err) throw err 80 | console.log(JSON.stringify(data, null, 2)) 81 | process.exit() 82 | })) 83 | 84 | } 85 | -------------------------------------------------------------------------------- /api/iteration.js: -------------------------------------------------------------------------------- 1 | 2 | function setStatus (iteration) { 3 | var state = iteration.state = { 4 | funded: iteration.target <= iteration.sum, 5 | draft: !iteration.total, 6 | complete: iteration.total && (iteration.total <= iteration.complete), 7 | progress: (iteration.sum || 0) / (iteration.target || 1) 8 | } 9 | iteration.progress = (iteration.sum || 0) / (iteration.target || 1) 10 | 11 | iteration.status = ( 12 | state.funded && state.complete ? 'complete' 13 | : state.funded && !state.complete ? 'progress' 14 | : !state.funded && iteration.sum ? 'funding' 15 | : 'ready' 16 | ) 17 | 18 | return iteration 19 | } 20 | 21 | module.exports = function (iteration, funders) { 22 | iteration.funders = funders || [] 23 | iteration.sum = funders.reduce(function (a, b) { 24 | return a + b.sum 25 | }, 0) / 1e8 26 | 27 | setStatus(iteration) 28 | 29 | return iteration 30 | } 31 | 32 | module.exports.random = function () { 33 | var target = 1 + (1*Math.random()) 34 | var sum = Math.min(target, target * Math.random()*1.3) 35 | var total = 2 + ~~(5*Math.random()) 36 | var complete = ~~Math.min(total, total * Math.random() * (sum < target ? 1.1 : 1.5)) 37 | 38 | var tasks = [] 39 | for(var i = 0; i < total; i++) { 40 | tasks.push({closed: complete > i}) 41 | } 42 | 43 | tasks.sort(function () { return Math.random() - 0.5 }) 44 | 45 | return setStatus({ 46 | target : target, 47 | sum : sum, 48 | total : total, 49 | complete : complete, 50 | progress : complete / total, 51 | status : ['created', 'funding', 'progress', 'complete'][~~(Math.random()*4)], 52 | links : tasks 53 | }) 54 | } 55 | -------------------------------------------------------------------------------- /api/iterations.js: -------------------------------------------------------------------------------- 1 | var resolve = require('url').resolve 2 | var join = require('path').join 3 | var config = require('../config') 4 | 5 | var host = config.host 6 | var regex = /^iteration/i // starts with 'Iteration' 7 | 8 | var progressbar = new RegExp( 9 | "https?:\\/\\/" + host.replace(/\./, "\\.") + "\\/iteration\\/[0-z_\-]+\\/[0-z_\-]+\\/(1[1-km-z]{33}).png(?:.*)#(\\d+(?:\\.\\d+))") 10 | var issueFull = /https?:\/\/github.com\/([0-z_\-]+)\/([0-z_\-]+)\/issues\/(\d+)/ 11 | var issueNum = /\s#(\d+)\s/ 12 | var issueUserNum = /\s([0-z_-]+)#(\d+)\s/ 13 | var issueUserRepoNum = /\s([0-z_-]+)\/([0-z_-]+)#(\d+)\s/ 14 | 15 | function matchAll(r, s) { 16 | var matches = [] 17 | var m 18 | while(m = r.exec(s)) { 19 | matches.push(m) 20 | s = s.substring(m.index + 1) 21 | } 22 | return matches 23 | } 24 | 25 | 26 | module.exports = function (issues, collaborators, user, repo) { 27 | 28 | var iterations = [] 29 | var wallets = {} 30 | 31 | var names = {} 32 | 33 | collaborators.forEach(function (user) { 34 | names[user.login] = true 35 | }) 36 | 37 | var all = {} 38 | issues.forEach(function (issue) { 39 | all[issue.url] = issue 40 | }) 41 | 42 | issues.forEach(function (issue) { 43 | 44 | //if(iteration.test(issue.title)) 45 | if(!names[issue.user.login]) return 46 | var m = progressbar.exec(issue.body) 47 | 48 | issue.owner = user 49 | issue.repo = repo 50 | 51 | //console.log(issue.body) 52 | if(!m) return 53 | issue.wallet = m[1] 54 | issue.target = m[2] 55 | issue.feedopensource_url = 'https://' + host + '/iteration/' + user + '/' + repo + '/' + m[1] 56 | issue.badge_url = issue.feedopensource_url + '.png#' + issue.target 57 | 58 | if(!wallets[issue.wallet]) { 59 | 60 | issue.links = 61 | matchAll(issueFull, issue.body) 62 | .concat(matchAll(issueNum, issue.body)) 63 | .concat(matchAll(issueUserNum, issue.body)) 64 | .concat(matchAll(issueUserRepoNum, issue.body)) 65 | .map(function (m) { 66 | var matches = [].slice.call(m, 1) 67 | var issue = matches.pop() 68 | var _username = matches.shift() || user 69 | var _repo = matches.shift() || repo 70 | return { 71 | html_url: m, 72 | url: resolve('https://api.github.com', 73 | join('repos', _username, _repo, 'issues', issue)), 74 | closed: false 75 | } 76 | }) 77 | 78 | // check for closed issues. 79 | // this doesn't work if the task is in another repo. 80 | // (fix that later) 81 | var total = 0, complete = 0 82 | issue.links.forEach(function (e) { 83 | total ++ 84 | if(!all[e.url]) 85 | complete ++ 86 | 87 | e.closed = !all[e.url] 88 | }) 89 | issue.total = total 90 | issue.complete = complete 91 | iterations.push(issue) 92 | } 93 | wallets[issue.wallet] = true 94 | }) 95 | 96 | return iterations 97 | 98 | } 99 | 100 | -------------------------------------------------------------------------------- /config.js: -------------------------------------------------------------------------------- 1 | var join = require('path').join 2 | 3 | var home = process.env.SUDO_USER 4 | ? join('/home', process.env.SUDO_USER) 5 | : process.env.HOME || '/root' 6 | 7 | module.exports = require('rc')('feedopensource', { 8 | cert: join(home, '.feedopensource', 'server-cert.pem'), 9 | key : join(home, '.feedopensource', 'server-key.pem'), 10 | ca : join(home, '.feedopensource', 'ca-bundle.pem'), 11 | port: 8000, //development (non-secure) port 12 | host: "feedopensource.com" 13 | }) 14 | -------------------------------------------------------------------------------- /development.md: -------------------------------------------------------------------------------- 1 | ## install 2 | 3 | ``` js 4 | git clone git:github.com/dominictarr/feedopensource.git 5 | cd feedopensource 6 | npm install 7 | ``` 8 | 9 | ## deploy 10 | 11 | you'll need to aquire an ssl cert, a domain, and a server. 12 | 13 | ### generate ssl key and cert 14 | 15 | ``` js 16 | cd ~ 17 | mkdir .feedopensource 18 | cd .feedopensource 19 | 20 | ### generate a ssl cert 21 | 22 | openssl genrsa -out server-key.pem 4096 23 | openssl req -new -key server-key.pem -out server-csr.pem 24 | 25 | ``` 26 | 27 | and enter your details. when it asks for "FQDN" 28 | "fully qualified domain name" enter the domain name you wish to use. 29 | get a cacert. I got a free cert from https://www.cacert.org 30 | you'll need to paste in the contents of the server-csr.pem file, 31 | and the certificate authority will give you a new pem file, 32 | save this as .feedopensource/server-cert.pem 33 | 34 | ### github application id 35 | 36 | If you don't auth to the github api you'll be limited to 60 requests persecond. 37 | If your project gets popular, or you are doing development on it `feedopensource`, 38 | you'll probably go over this. 39 | 40 | first [register your application](https://github.com/settings/applications/new) 41 | then put the `id` and `secret` in your `.feedopensource/config` file. 42 | 43 | ``` js 44 | { 45 | "id": "{client_id}", 46 | "secret": "{client_secret}" 47 | } 48 | ``` 49 | must be valid JSON or INI format. See [rc](https://github.com/dominictarr/rc) 50 | 51 | ### configuration 52 | 53 | currently default configuration will work. 54 | 55 | ### starting the server 56 | 57 | ``` 58 | sudo node index.js 59 | ``` 60 | now you have your own feedopensource instance! 61 | I run my server on archlinux, so I use systemd. 62 | use [this tool](https://github.com/dominictarr/create-systemd-service) 63 | for an easy way to create a `systemd` service. 64 | 65 | 66 | ### api queries, views, and badge are unixy. 67 | 68 | feedopensource is just aggregates from 69 | https://github.com and https://blockchain.info 70 | 71 | one part of this is gathering JSON, and mushing it together to 72 | get the stuff that matters to feedopensource. 73 | 74 | the other part is generating from that data for a human to view. 75 | 76 | each part is separated, for ease of testing. 77 | 78 | use feedopensource as a cli tool, to get api data. 79 | 80 | ``` js 81 | > node ./api/index.js iteration dominictarr feedopensource 1PTAwipYpP63uNrcxfm5FewxRdZyar6ceu 82 | #lots of JSON 83 | ``` 84 | you can get exactly the same data from the api. 85 | 86 | ``` js 87 | >node index.js & 88 | >curl localhost:8000/iteration/dominictarr/feedopensource/1PTAwipYpP63uNrcxfm5FewxRdZyar6ceu.json 89 | #lots of JSON 90 | ``` 91 | 92 | the html views are really just a transform, taking data and turning it into html. 93 | they can be used via a web browser, but also by pipeing data into the view on stdin. 94 | 95 | ``` js 96 | #save iteration.json to use while testing views/iteration.js 97 | > node ./api/index.js iteration dominictarr feedopensource 1PTAwipYpP63uNrcxfm5FewxRdZyar6ceu > iteration.json 98 | > node ./views/index.js iteration < iteration.json 99 | # lots of HTML 100 | ``` 101 | # progress bar 102 | 103 | pipe output of iteration query into badge generation, get png data 104 | ``` js 105 | node ./api/index.js iteration \ 106 | dominictarr feedopensource \ 107 | 1PTAwipYpP63uNrcxfm5FewxRdZyar6ceu \ 108 | | node ./lib/badge.js > badge.png 109 | ``` 110 | This means you can work on the html offline, 111 | and get expected output for tests, etc. 112 | 113 | -------------------------------------------------------------------------------- /docs.md: -------------------------------------------------------------------------------- 1 | # run your own feedopensource project. 2 | 3 | If you want to run your own `feedopensource` 4 | project you need two things: 5 | 6 | 1. bitcoin wallet (you don't need any bitcoins yet) 7 | 2. github account 8 | 3. a prototype of a cool opensource project. 9 | 10 | I'm assuming you already have `2 & 3` under control. 11 | 12 | ## first iteration. 13 | 14 | create an github issue describing the next iteration. 15 | to be a valid feedopensource iteration it only needs two things 16 | 17 | * A `feedopensource` progress bar badge. 18 | * links to other issues that are to be implemented in the iteration. 19 | 20 | each iteration MUST use a new bitcoin address. the progress bar represents 21 | the total deposits into that address, not the current balance. 22 | feel free to transfer that money into another address. 23 | 24 | links to tasks MUST be in the post that creates the issue, 25 | not in a comment. You can always edit an issue to add or remove links. 26 | 27 | ## badge 28 | 29 | ``` js 30 | [![feedopensource badge]( 31 | https://feedopensource.com/iteration/{github_user}/{github_repo}/{bitcoin_address}.png#{target} 32 | )]( 33 | https://feedopensource.com/iteration/{github_user}/{github_repo}/{bitcoin_address} 34 | ) 35 | ``` 36 | note the `.png` and `#{target}` fragment. these are both essential. 37 | `#{target}` should be a decimal abount in bitcoins. 38 | 39 | ## that's all! 40 | 41 | Now find some other people who want your project to exist 42 | but do not have time/expertise to work on it. 43 | 44 | Currently `feedopensource` is very simple. 45 | It's up to you to decide how to use it best, 46 | and keep your funders satisfied. 47 | -------------------------------------------------------------------------------- /docs/economics-of-opensource.md: -------------------------------------------------------------------------------- 1 | # Some Thoughts on the Economics of Software Development 2 | 3 | The problem with software development, is that the ways used to fund it 4 | are either more suited to physical products, or are otherwise out of line 5 | with the interests of the users of the software. Here are my thoughts 6 | on the ways this fails, and also an idea for another approach. 7 | 8 | ## A Summary of the Current Methods 9 | 10 | * VC-funded free service 11 | * proprietary software licensed for a fee 12 | * open source, funded by charity, or by the creative drive of it's author. 13 | 14 | Each of these methods create a different kind of software. 15 | Essentially, different ways of funding mean different motivations, 16 | and these result in different decisions by the developers. 17 | 18 | ## The "Free" Service 19 | 20 | VC-funded software seems very good at first, but, they aren't really doing 21 | it for free. 22 | 23 | The investors are looking to make money, and there is often 24 | a "business model" question hanging over such software. 25 | This question is nearly always resolved by changing what the software does, 26 | from something that enables users, to something that manipulates the user. 27 | If this is the sort of software you would like to use (be used by), 28 | then you are already well catered to! Your Welcome! 29 | 30 | ## Private Source 31 | 32 | Someone builds the software, then you buy it from them. 33 | 34 | What could be simpler? This works well with physical goods, 35 | because the exchange is easy to enforce. For example, I have made a bicycle, 36 | and you want to buy it. You give me some pieces of paper with the pictures 37 | of George Washington, or Chairman Mao or whatever, and I give you a bicycle. 38 | This is naturally in line with the physics of physical items, but software is wholly 39 | different. Instead of giving you the bike, with software, I would copy the bike to you. 40 | Now there are two bikes. What's more, it's trivial for you to copy the bike to someone else. 41 | Now there are a lot of people riding my bike, without me being able to recover the value 42 | that I think I deserve for creating it. 43 | 44 | So, to make the private source model work, you have to add extra code (copy protection) 45 | to make the software behave more like a physical good. Like turnstiles on a subway, 46 | these copy-protection features prevent you from accessing the natural physics of software. 47 | This takes extra work, and so you end up paying not just for the product itself, 48 | but also for the work to cripple the product so that it's more difficult to replicate. 49 | 50 | If the value of the software is high enough (enterprise), 51 | then they can just use lawyers instead of copy protection 52 | features in the software. I'm not sure which is worse. 53 | 54 | This is widely used for games, or enterprise applications. 55 | the apple app store is a great example of an elaborate system 56 | for making software difficult to copy. 57 | 58 | You purchase a crippled phone that can only install software that apple likes, 59 | and then you can pay for software, and also 30% to apple for 60 | the service of stopping you from being able to install anything else. 61 | 62 | ## Open Source 63 | 64 | Instead of going to the hassle of charging for software, 65 | open source just gives it away. 66 | 67 | This eliminates the costs of erecting or maintaining turnstiles. It also reduces the 68 | cost of evaluating software. You don't have to pay for something 69 | to try it out. Open Source has created all the best operating systems, 70 | programming languages, developer tools, and databases. 71 | 72 | But the scope of Open Source is pretty much limited to this. 73 | Open Source is created by enthusiasts, and it does get paid for, 74 | but intangibly. 75 | 76 | A project usually starts because someone thinks 77 | it might be fun to implement. But then, if that project becomes useful, 78 | it becomes in the interest of other well funded parties. Any large project 79 | requires an extraordinary amount of attention to detail and refinements. 80 | 81 | It would not be possible to pursue such a project at hobby scale. 82 | though, still, there is a huge amount of valuable software essentially 83 | created by hobbyists. Tragically, these hobbyists may work a day job 84 | writing "free" services or private software. 85 | 86 | ## Moving Forward 87 | 88 | There have recently been some attempts to move beyond the hobby economics 89 | of open source. Each of these are interesting in their own way. 90 | 91 | ### gittip 92 | 93 | [gittip.com](https://gittip.com) enables you to anonymously 94 | donate to someone. This is the digital equivalent of busking. 95 | 96 | You can easily give a small amount of money as encouragement to an artist who's creating things you enjoy. 97 | But this doesn't really influence them in any way. This is an interesting model, 98 | but not many people are earning enough to survive (and thus devote themselves 99 | fully to their art). 100 | 101 | By the way, if you enjoy my creations, please feel free to offer me a token of your appreciation: [gittip.com/dominictarr](https://gittip.com/dominictarr) 102 | 103 | ### Kickstarter, Indiegogo, etc. 104 | 105 | Another approach is crowdfunding the development of a project. 106 | 107 | The developer makes a bunch of promises of what they want to deliver, 108 | and how much they think it will cost. People either fund it or not. 109 | And then, development begins. If you have been following any of these 110 | projects recently, it won't be hard to think of examples of one that 111 | hasn't really gone according to plan. 112 | 113 | All the crowdfunding platforms 114 | and geared towards a single, large, funding round. So, all promises 115 | and plans must be made up front, well in advance. 116 | 117 | The problem with promises made well in advance is that they are hard to keep. 118 | Not necessarily because you didn't mean them, but just because the situation changes, 119 | and when you start coding you learn things you didn't know when you started. 120 | 121 | Like representational democracy, you don't know if the party you elect (fund) 122 | will keep their promises, or even are capable of achieving them. 123 | 124 | Essentially, kickstarter forces you to use the 125 | [waterfall model](http://wikipedia.com/en/waterfall_model). 126 | The waterfall model is widely understood to result in low quality, over-budget software. 127 | Quality software must be built iteratively, changing the plan as your learn things, 128 | but the economics of crowdfunding platforms prevent this. 129 | 130 | ### Bountysource 131 | 132 | Bountysource takes the opposite approach of kickstarter. 133 | 134 | Instead of funding a whole project all at once, you can fund a specific issue, 135 | or feature that you want. It's really too early to say what will happen with 136 | Bountysource, but my feeling is that it is too specific where upfront funding is too vague. 137 | The features of a software project are not isolated. You can't just buy a feature 138 | or bug fix. There may be a refactor that simplifies multiple features, or eliminates multiple bugs. 139 | It takes too much understanding from the funder to understand the specific features/bugs that 140 | most need funding. 141 | 142 | ## One more way 143 | 144 | There is one more way software is funded. 145 | 146 | If you have a software problem that is particular to you, or just want your own thing, 147 | you can hire a consulting company and get them to make you something bespoke. 148 | This can actually work pretty well, provided that communication between the developers 149 | and the clients is good, and an iterative process of building a prototype, testing it against 150 | client expectations, and refining/rebuilding the design. 151 | This process is often known as [Agile Development](http://wikipedia.org/en/agile_development). 152 | 153 | The developers and the clients both have power in their relationship. The developers have 154 | the technical expertise to write the software, but the clients have the cheque book. 155 | If a project is going badly, they can always (depending on their contract) abandon it 156 | and find new consultants. 157 | 158 | A lot of software is built this way, but it's completely unscalable. Or is it? 159 | 160 | ## My idea 161 | 162 | What we need is something that aligns the interests of the developers and users, 163 | and also with the natural physics of software development. Something that scales, 164 | so that you can use to fund end-user software - not just developer tools. 165 | 166 | Something halfway between Kickstarter, and Bountysource, but with the best part of 167 | Agile development. Development and funding must be iterative. The developers should 168 | not have to make promises that will 169 | be hard to keep. Instead, they build trust with the clients by making steady 170 | incremental progress. If the progress is in the wrong direction, or the developers 171 | turn out to be incompetent, then clients can abandon the project without having over committed. 172 | And if the project goes well, the clients can continue to fund the project. 173 | Since the uncertainty decreases as the developers build the clients trust, 174 | they could potentially fund much more than they would which a single batch of funding, 175 | not really knowing how useful the software will be, or even whether the project will eventually deviler. 176 | 177 | Watch this space! I am currently working on a minimal prototype of this idea, 178 | expect an announcement soon! 179 | 180 | 181 | ## Another Possibility! 182 | 183 | I think we need something halfway between Bountysource and Kickstarter. 184 | 185 | Here is my idea. Crowdsource funding, but instead of funding all at once, 186 | encouraging the waterfall module, fund iteratively to encourage the 187 | [agile development model](http://wikipedia.org/en/agile_development). 188 | 189 | Everybody knows that the best customer is a repeat customer. 190 | When you are a repeat customer, you have a more equal power in the relationship. 191 | 192 | You may only pay a few dollars today, but potentially you may pay a very large amount 193 | over the course of years or decades. The flow of this value is contingent on your 194 | satisfaction with the vendor. You can always threaten to take your custom 195 | elsewhere, and so the vendor is motivated to satisfy you. 196 | 197 | Not only is the best customer a repeat customer, but the best vendor is a vendor 198 | you freely choose to use repeatedly (this does not apply to monopolies). 199 | 200 | Instead of funding a software project for it's entire life span, you should fund 201 | only a small amount, like 2 weeks worth. After two weeks the developers 202 | must have some progress to show you, and if it's going in a good direction you 203 | like, you can choose to fund again. This will workout for the developer as well. 204 | Since you are invested in the project, you are motivated to provide useful feedback. 205 | 206 | Software can be duplicated endlessly for virtually no cost, but it still needs to 207 | be written once, and then bugs fixed, etc. Work needs to be done by someone 208 | who is talented and experienced, but it only needs to be done once. 209 | 210 | It doesn't matter who pays for it, but someone needs to feed those developers 211 | while they work. What is needed is to align the economics of software development 212 | with the physics of software development. 213 | 214 | To reduce the friction between creating the best possible software with living in the real world. 215 | 216 | ## [Agile Crowdfunding??? AgileFund?] 217 | 218 | This is my attempt to solve this problem. [name of project] is not a startup. 219 | 220 | It's an open source project that funds open source projects. It will not be 221 | run as a platform, but a project you can install and run yourself, like wordpress and not like tumblr. 222 | The prototype is very simple (only a few hours worth of work) and the initial target for the next iteration 223 | is very low. The first test is just whether people are willing to fund a project via a method like this! 224 | 225 | Please see the [project website] for more specific details, and if you have more questions, 226 | please post an issue on the [github project]. 227 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env node 2 | 3 | var https = require('https') 4 | var http = require('http') 5 | var fs = require('fs') 6 | var join = require('path').join 7 | 8 | var btcprogress = require('btcprogress') 9 | var route = require('tiny-route') 10 | var ecstatic = require('ecstatic') 11 | var stack = require('stack') 12 | 13 | var redirect = require('./lib/https-redirect') 14 | var config = require('./config') 15 | var api = require('./api') 16 | var views = require('./views') 17 | 18 | var badge = require('./lib/badge').getBadge 19 | var qrcode = require('./lib/qr') 20 | var autoApi = require('./lib/auto-api') 21 | var certs = require('./lib/certs') 22 | 23 | var app = stack( 24 | //TODO: remove 25 | route('/badge', btcprogress()), 26 | //the new badge with api 27 | autoApi(api, views, {png: {iteration: badge, qr: qrcode}}), 28 | ecstatic(join(__dirname, 'static')) 29 | ) 30 | 31 | var secure = process.getuid() === 0 32 | var ca = certs(fs.readFileSync(config.ca, 'ascii')) 33 | 34 | if(secure) { 35 | // var ca = fs.readFileSync(config.ca) 36 | https.createServer({ 37 | cert: fs.readFileSync(config.cert), 38 | key : fs.readFileSync(config.key), 39 | ca : ca, 40 | }, app).listen(443) 41 | 42 | http.createServer(redirect()).listen(80) 43 | 44 | process.on('uncaughtException', function (err) { 45 | console.log('*****************************') 46 | console.error('Error at:', new Date) 47 | console.error(err.stack) 48 | console.log('*****************************') 49 | }) 50 | 51 | } else { 52 | http.createServer(app).listen(config.port) 53 | } 54 | -------------------------------------------------------------------------------- /lib/auto-api.js: -------------------------------------------------------------------------------- 1 | var parseUrl = require('url').parse 2 | var path = require('path') 3 | 4 | 5 | module.exports = function autoApi(api, views, exts, headers) { 6 | exts = exts || {} 7 | exts.html = exts.html || views 8 | exts.json = exts.json || function (data) { 9 | return JSON.stringify(data, null, 2) 10 | } 11 | 12 | return function (req, res, next) { 13 | var url = parseUrl(req.url).pathname 14 | var ext = path.extname(url) || '' 15 | url = url.substring(0, url.length - ext.length) 16 | ext = (ext || '.html').substring(1) 17 | 18 | var args = url.split('/').filter(Boolean) 19 | var name = args.shift() 20 | var method = api[name] || (exts[ext] && exts[ext][name]) 21 | 22 | var view = exts[ext] 23 | if(view && 'function' !== typeof view) 24 | view = view[name] 25 | 26 | if(!view) return next() 27 | if(!method) return next() 28 | if(method.length !== args.length + 1) 29 | return next() 30 | 31 | var stream = method.apply(null, args.concat(function (err, data) { 32 | if(err) return next(err) 33 | //make github not cache badges 34 | if(ext == 'png') { 35 | res.setHeader('cache-control', 'no-cache') 36 | res.setHeader('content-type', 'image/png') 37 | } 38 | res.end(view(data)) 39 | })) 40 | 41 | if(stream) { 42 | if(ext == 'png') { 43 | res.setHeader('cache-control', 'no-cache') 44 | res.setHeader('content-type', 'image/png') 45 | } 46 | stream.pipe(res) 47 | } 48 | } 49 | } 50 | 51 | -------------------------------------------------------------------------------- /lib/badge.js: -------------------------------------------------------------------------------- 1 | function drawTitle(ctx, iteration) { 2 | var title = iteration.title 3 | var textHeight = parseInt(ctx.font) 4 | ctx.fillStyle = '#333333' 5 | ctx.fillText(title, 1, 1 + textHeight) 6 | // ctx.translate(0, textHeight + 6) 7 | } 8 | function drawState (ctx, status) { 9 | var textHeight = parseInt(ctx.font) 10 | ctx.fillStyle = '#333333' 11 | 12 | var width = ctx.measureText(status).width 13 | console.error('width:', ctx.canvas.width, width, ctx.canvas.width - width) 14 | ctx.fillText(status, ctx.canvas.width - width, textHeight) 15 | ctx.translate(0, textHeight + 6) 16 | 17 | } 18 | 19 | //not used currently 20 | function drawStates (ctx, j, list) { 21 | var textHeight = parseInt(ctx.font) 22 | ctx.fillStyle = '#ddeedd' 23 | 24 | var width = 0, currentWidth 25 | var totalWidth = ctx.measureText(list.join('').toUpperCase()).width 26 | var space = ~~((ctx.canvas.width - totalWidth-4) / (list.length - 1)) 27 | 28 | list.forEach(function (word, i) { 29 | var LOUD = word.toUpperCase() 30 | 31 | ctx.fillStyle = ( 32 | i < j ? '#999999' //done 33 | : i === j ? '#333333' //current 34 | : '#ddeedd' //todo 35 | ) 36 | 37 | ctx.fillText(LOUD, width, textHeight) 38 | ctx.fill() 39 | width += ctx.measureText(LOUD).width 40 | 41 | if(i == j) current = width 42 | width += space 43 | }) 44 | 45 | ctx.beginPath() 46 | ctx.strokeStyle = '#333333' 47 | ctx.moveTo(0, textHeight + 3) 48 | if(current) { 49 | ctx.lineTo(current + 3, textHeight + 3) 50 | ctx.lineTo(current + 3, 0) 51 | ctx.stroke() 52 | } 53 | 54 | ctx.translate(0, textHeight + 6) 55 | } 56 | 57 | function drawBar (ctx, ratio, width, message) { 58 | var textHeight = parseInt(ctx.font) 59 | var height = textHeight*2 60 | ratio = Math.min(ratio, 1) 61 | var barpos = ~~(width*ratio) 62 | ctx.fillStyle = 'lightgreen' 63 | ctx.fillRect(0, 1, width, height - 2) 64 | ctx.fillStyle = 'green' 65 | ctx.fillRect(0, 1, barpos, height - 2) 66 | 67 | if(message) { 68 | ctx.textAlign = 'right' 69 | ctx.fillStyle = '#eeeeee' 70 | var w = ctx.measureText(message).width 71 | ctx.fillText(message, Math.max(width*ratio - height*0.25, w+height*0.25), height*0.70) 72 | } 73 | 74 | ctx.translate(0, height + 2) 75 | } 76 | 77 | function drawTasks(ctx, tasks, width) { 78 | ctx.save() 79 | var height = ~~(parseInt(ctx.font)*1.4) 80 | 81 | tasks.forEach(function (done, i) { 82 | ctx.fillStyle = 'lightgray' 83 | ctx.fillRect(0, 0, height, height) 84 | 85 | ctx.fillStyle = 'white' //done ? '#00ff00' : 'darkgray' 86 | ctx.fillRect(2, 2, height - 4, height - 4) 87 | 88 | if(done) { 89 | var h = height 90 | ctx.fillStyle = '#00ff00' 91 | ctx.beginPath() 92 | ctx.moveTo(h*.2, h*.2) 93 | ctx.lineTo(h*.45, h*.5) 94 | ctx.lineTo(h*1.1, h*-.2) 95 | ctx.lineTo(h*.4, h*.9) 96 | ctx.lineTo(h*.2, h*.2) 97 | ctx.fill() 98 | } 99 | 100 | ctx.translate(height*1.5 + 3 , 0) 101 | }) 102 | } 103 | 104 | var states = ['created', 'funding', 'progress', 'complete'] 105 | 106 | function b () { 107 | return Math.random () > 0.5 108 | } 109 | 110 | function percent(r) { 111 | return ~~(r*100) + '%' 112 | } 113 | 114 | 115 | var badge = module.exports = function (ctx, iteration) { 116 | ctx.save() 117 | var width = ctx.canvas.width, state = 0 118 | var height = ~~(ctx.canvas.height/5) 119 | ctx.font = height+'px sans' 120 | 121 | drawTitle(ctx, iteration) 122 | drawState(ctx, iteration.status) 123 | //state = states.indexOf(iteration.status), states) 124 | var r 125 | 126 | drawBar(ctx, r = iteration.sum/iteration.target, width, 127 | iteration.sum.toPrecision(3) + '(/' + (+iteration.target).toPrecision(3) + ') ' 128 | + percent(r) 129 | ) 130 | 131 | var lh = ~~(ctx.canvas.height/6) 132 | 133 | ctx.save() 134 | drawTasks(ctx, iteration.links.map(function (e) {return e.closed})) 135 | ctx.restore() 136 | ctx.restore() 137 | ctx.font = lh+'px sans' 138 | ctx.textAlign = 'right' 139 | ctx.fillStyle = '#333333' 140 | ctx.fillText('FEEDOPENSOURCE', width, lh*1.4) 141 | 142 | if(state === states.length-1) { 143 | ctx.restore() 144 | ctx.fillStyle = 'red' 145 | ctx.textAlign = 'center' 146 | ctx.font = 2.2*height+'px sans' 147 | ctx.translate(width*0.65, ctx.canvas.height*.6) 148 | ctx.rotate(Math.PI*0.2) 149 | ctx.fillText('DONE!', 0, 0) 150 | } 151 | } 152 | 153 | module.exports.getBadge = function (data) { 154 | var Canvas = require('canvas-browserify') 155 | var canvas = new Canvas() 156 | canvas.font = '20px sans' 157 | canvas.width = 300 158 | canvas.height = canvas.width / 5 159 | var ctx = CTX = canvas.getContext('2d') 160 | ctx.font = '12px sans' 161 | badge(ctx, data) 162 | return canvas.toBuffer() 163 | } 164 | 165 | if(process.title === 'browser' || !module.parent) { 166 | 167 | var Canvas = require('canvas-browserify') 168 | var canvas = new Canvas() 169 | canvas.font = '20px sans' 170 | canvas.width = 300 171 | canvas.height = canvas.width / 5 172 | var ctx = CTX = canvas.getContext('2d') 173 | ctx.font = '12px sans' 174 | 175 | var randomIteration = require('../api/iteration').random 176 | 177 | if(process.title === 'browser') { 178 | badge(ctx, randomIteration()) 179 | document.body.appendChild(canvas) 180 | } else if(process.stdin.isTTY) { 181 | badge(ctx, randomIteration()) 182 | canvas.pngStream().pipe(process.stdout) 183 | } else { 184 | var data = '' 185 | process.stdin.on('data', function (d) { 186 | data += d 187 | }).on('end', function () { 188 | badge(ctx, JSON.parse(data)) 189 | return canvas.pngStream().pipe(process.stdout) 190 | }) 191 | } 192 | } 193 | 194 | -------------------------------------------------------------------------------- /lib/certs.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | module.exports = function (certs) { 4 | var c = '', list = [] 5 | certs.split('\n').forEach(function (line) { 6 | c += line + '\n' 7 | if(/-+END CERTIFICATE-+/.test(line)) 8 | list.push(c), c = '' 9 | }) 10 | return list 11 | } 12 | -------------------------------------------------------------------------------- /lib/get.js: -------------------------------------------------------------------------------- 1 | var request = require('request') 2 | 3 | var cache = {} 4 | 5 | var github = new RegExp('^https://api.github.com') 6 | var blockchain = new RegExp('^https://blockchain.info') 7 | 8 | function getRate (url) { 9 | 10 | // if(github.test(url)) 11 | if(blockchain.test(url)) return 20e3 //twenty seconds 12 | 13 | 14 | //okay, github is a little more complicated. 15 | //can request 60 times an hour... 16 | //but if sign up 5000 times. 17 | //just do this for now. 18 | 19 | return 5e3 20 | } 21 | 22 | //log url without auth 23 | function strip (url) { 24 | return url 25 | .replace(/client_id=[^&]+/, 'client_id=*****') 26 | .replace(/client_secret=([^&]+)/, 'client_secret=*****') 27 | } 28 | 29 | var get = module.exports = function (url, cb) { 30 | if(cache[url]) 31 | cb(null, cache[url]) 32 | 33 | console.error('GET', strip(url)) 34 | request({ 35 | url: url, 36 | json: true, 37 | headers: {'User-Agent': 'node@'+process.version} 38 | }, 39 | function (err, res, json) { 40 | console.error(''+res.statusCode, strip(url)) 41 | setTimeout(function () { 42 | delete cache[url] 43 | }, getRate(url)) 44 | 45 | cb(err || (json && json.error), json) 46 | }) 47 | } 48 | 49 | module.exports.all = function (ary, cb) { 50 | var output = [], n = 0, error 51 | ary.forEach(function (url, i) { 52 | n ++ 53 | get(url, function (err, data) { 54 | if(error) return 55 | if(error = err) return cb(err) 56 | output[i] = data 57 | process.nextTick(next) 58 | }) 59 | }) 60 | 61 | function next () { 62 | if(--n) return 63 | cb(null, output) 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /lib/https-redirect.js: -------------------------------------------------------------------------------- 1 | module.exports = function () { 2 | return function (req, res, next) { 3 | if (!req.headers.host) { 4 | res.statusCode = 400 5 | res.end() 6 | return 7 | } 8 | var location = 'https://' + req.headers.host.split(':')[0] + req.url 9 | res.statusCode = 301 10 | res.setHeader('Connection', 'close') 11 | res.setHeader('Content-Length', '0') 12 | res.setHeader('Location', location) 13 | res.end() 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /lib/qr.js: -------------------------------------------------------------------------------- 1 | var qr = require('qr-image') 2 | 3 | module.exports = function (data, _) { 4 | return qr.image(data, {type: 'png'}) 5 | } 6 | 7 | if(!module.parent) 8 | module.exports(process.argv[2]).pipe(process.stdout) 9 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "feedopensource", 3 | "description": "iteratively fund open-source projects", 4 | "version": "0.0.0", 5 | "homepage": "https://github.com/dominictarr/feedopensource", 6 | "repository": { 7 | "type": "git", 8 | "url": "git://github.com/dominictarr/feedopensource.git" 9 | }, 10 | "author": "Dominic Tarr (dominictarr.com)", 11 | "license": "MIT", 12 | "dependencies": { 13 | "tiny-route": "~2.1.0", 14 | "stack": "~0.1.0", 15 | "ecstatic": "~0.4.13", 16 | "btcprogress": "*", 17 | "request": "~2.31.0", 18 | "tape": "~2.3.2", 19 | "rc": "~0.3.2", 20 | "html-element": "https://github.com/dominictarr/html-element/archive/master.tar.gz", 21 | "hyperscript": "~1.4.0", 22 | "canvas-browserify": "~1.1.1", 23 | "qr-image": "~1.1.0" 24 | }, 25 | "devDependencies": { 26 | "carpenter": "0.1", 27 | "himark": "1.0" 28 | }, 29 | "bin": "./index.js", 30 | "scripts": { 31 | "build": "carpenter templates/index.html > static/index.html", 32 | "run": "./index.js", 33 | "test": "set -e; for t in test/*.js; do node \"$t\"; done" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /static/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Dominic Tarr 2 | 3 | Permission is hereby granted, free of charge, 4 | to any person obtaining a copy of this software and 5 | associated documentation files (the "Software"), to 6 | deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, 8 | merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom 10 | the Software is furnished to do so, 11 | subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 18 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 20 | ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /static/grumpy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dominictarr/feedopensource/ea9df8382058ed33a3d116b2552494c4930a2232/static/grumpy.jpg -------------------------------------------------------------------------------- /static/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | feedopensource 6 | 19 | 20 | 21 | Fork me on GitHub 22 |
23 |

Feed Open Source

24 |

We need another way to fund software. All the other ways are 25 | broken or unscalable. 26 | We need to align the interests of the users with developers. 27 | We need to feed developers, and the software needs to be freely distributable.

28 |

The Problem

29 |

Software only needs to be written once.
Bugs need to be patched, but a bug only needs to be patched once.

30 |

Why do we pay for software many times, or not at all?
Software should be paid for exactly once.

31 |

You can't sell software like you sell physical items, 32 | software is too easy to copy.

33 |

But here is something you can sell: a promise to write software

34 |

The Vision

35 |

Take agile consulting to the crowds.

36 |

Work is funded in iterations, on a fixed time basis, a week or two at a time. 37 | Clients and developers negotiate what features they are most need in the next iteration. 38 | The developers implement that, and the clients evaluate it. Repeat. 39 | Every one is constantly in the loop.

40 |

feedopensource is different to agile consulting because "the clients" 41 | are a crowd of people. 42 | feedopensource is different to crowd-funding platforms because clients 43 | will have real power to influence a project, and keep it on task.

44 |

A client does not commit all their money at once, so the developers 45 | must keep them satisfied to receive funding in the future. 46 | For the client, most of the uncertainty about the project is removed, 47 | because they see it improve at each stage.

48 |

Less uncertainty means clients can fund more, 49 | because they know the value they are getting.

50 |

This is not a startup.

51 |

This is not Anything as a Service.
This is not an Anything-Platform.

52 |

This is just an open source tool for feeding open source projects.

53 |

feedopensource has a liberal open-source license.

54 |

You may use feedopensource to fund your own projects, 55 | as feedopensource feeds itself with feedopensource

56 |

The Prototype

57 |

The prototype has progressed to iteration 2!

58 |

feedopensource badge

59 |

Currently, feedopensource can:

60 | 66 |

This is very simple, but with the support of iteration 1's 67 | funders

68 |

Iteration 2

69 |

Tasks for iteration 2 are listed here

70 |

Bitcoin

71 |

Transfer btc into 18oBEV9hFdDMEct9Ys2bSAuEY4bi2KSMHi to fund iteration 2.

72 |

Please post a comment here 73 | with your transaction id.

74 |

Not sure how to buy bitcoin? Learn how you can buy bitcoin in your country 75 | Also see this issue

76 |

Credit-card

77 |

If you would rather fund this with normal money please 78 | comment with the amount you'd like to pay on 79 | this issue

80 |

The Plan

81 |

Clients and Developers post issues to Tasks and plan Iterations. 82 | (on github or similar)

83 |

feedopensoure will be implemented as a bot that posts to and scrapes/apis Github. 84 | This avoids the problem of having to implement a fresh discussion platform, Notifications, 85 | User system, etc!

86 |

Please comment on the first iteration!

87 |

The Workflow

88 |

In the future you might use feedopensource like this:

89 | 103 | 104 | 105 |
106 | 107 | 108 | -------------------------------------------------------------------------------- /static/style.css: -------------------------------------------------------------------------------- 1 | #content { 2 | max-width: 900px; 3 | margin: auto; 4 | color: #333333; 5 | background-color: #ffffff; 6 | padding-left: 20px; 7 | padding-right: 20px; 8 | border: 1px solid #bbbbbb; 9 | border-radius: 5px; 10 | box-shadow: 5px 3px 5px hsla(0,0%,50%,0.1); 11 | padding-bottom: 20px; 12 | //; 13 | } 14 | 15 | body { 16 | background-color: #eeeeee; 17 | } 18 | 19 | li, p { 20 | color: #3d3d3d; 21 | } 22 | 23 | .front_page li, p { 24 | font-size: 1.5em; 25 | line-height: 1.4em; 26 | } 27 | 28 | h1, h2, h3 { 29 | font-family: Serif; 30 | border-bottom: 1px dotted hsla(0, 100%, 50%, 0.5); 31 | } 32 | 33 | .uline { 34 | border-bottom: 1px dotted hsla(0, 100%, 50%, 0.5); 35 | } 36 | 37 | h1 { font-size: 3em; } 38 | h2 { font-size: 2em; } 39 | h3 { font-size: 1.5em; } 40 | 41 | //.inline { display: inline-block; } 42 | 43 | //use fixed layout like twitter bootstrap / flatUI 44 | 45 | .span6 { width: 480px; } 46 | .span5 { width: 400px; } 47 | .span4 { width: 320px; } 48 | .span3 { width: 240px; } 49 | .span2 { width: 160px; } 50 | .span1 { width: 80px; } 51 | 52 | .i6 { width: 4800px; } 53 | .i4 { width: 320px; } 54 | .i3 { width: 240px; } 55 | .i2 { width: 160px; } 56 | 57 | .v1 { margin-top: 10px; } 58 | 59 | .sm { font-size: 0.8em; font-family: monospace } 60 | .dk { background-color: #eeeeee; } 61 | 62 | 63 | [class*="span"] { 64 | float : left; 65 | margin-left: 20px 66 | } 67 | 68 | [class*="i"] { 69 | display: inline-block; 70 | } 71 | 72 | .row:after, .row:before { 73 | display: table; 74 | line-height: 0px; 75 | content: ""; 76 | } 77 | 78 | .row:after { 79 | clear: both; 80 | } 81 | 82 | .row { 83 | display: block; 84 | margin-left: -20px; 85 | margin-right: -20px; 86 | margin-top: 20px 87 | } 88 | 89 | .avatar { 90 | margin-left: -80px; 91 | position: absolute; 92 | } 93 | 94 | .funder { 95 | // padding-left: 10px; 96 | // padding-right: 10px; 97 | margin-left: 120px; 98 | margin-top: 10px; 99 | height: 80px; 100 | // border: 1px solid lightgray; 101 | // border-left: none; 102 | overflow: hidden; 103 | border-radius: 2px; 104 | } 105 | .nml { 106 | margin-left: -20px 107 | } 108 | 109 | .fit { 110 | width: 100%; 111 | // display: block; 112 | } 113 | 114 | .ib { 115 | display: inline-block 116 | } 117 | 118 | .pad10 { 119 | padding-left: 10px; 120 | padding-right: 10px; 121 | } 122 | 123 | -------------------------------------------------------------------------------- /templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | feedopensource 6 | 19 | 20 | 21 | Fork me on GitHub 22 |
23 | {{{! himark README.md }}} 24 |
25 | 26 | 27 | -------------------------------------------------------------------------------- /test/fixtures/collaborators.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "login": "dominictarr", 4 | "id": 259374, 5 | "avatar_url": "https://gravatar.com/avatar/8225d7ca5e83a3f9f0bb89a61d5df72c?d=https%3A%2F%2Fidenticons.github.com%2F6b7bbeffb7d27119a32f65804f7af00a.png&r=x", 6 | "gravatar_id": "8225d7ca5e83a3f9f0bb89a61d5df72c", 7 | "url": "https://api.github.com/users/dominictarr", 8 | "html_url": "https://github.com/dominictarr", 9 | "followers_url": "https://api.github.com/users/dominictarr/followers", 10 | "following_url": "https://api.github.com/users/dominictarr/following{/other_user}", 11 | "gists_url": "https://api.github.com/users/dominictarr/gists{/gist_id}", 12 | "starred_url": "https://api.github.com/users/dominictarr/starred{/owner}{/repo}", 13 | "subscriptions_url": "https://api.github.com/users/dominictarr/subscriptions", 14 | "organizations_url": "https://api.github.com/users/dominictarr/orgs", 15 | "repos_url": "https://api.github.com/users/dominictarr/repos", 16 | "events_url": "https://api.github.com/users/dominictarr/events{/privacy}", 17 | "received_events_url": "https://api.github.com/users/dominictarr/received_events", 18 | "type": "User", 19 | "site_admin": false 20 | }, 21 | { 22 | "login": "kyledrake", 23 | "id": 28153, 24 | "avatar_url": "https://gravatar.com/avatar/62a43048a3c2c688654274abdc0ecb9c?d=https%3A%2F%2Fidenticons.github.com%2Ffde07ba82b25f95afa9d080819f95717.png&r=x", 25 | "gravatar_id": "62a43048a3c2c688654274abdc0ecb9c", 26 | "url": "https://api.github.com/users/kyledrake", 27 | "html_url": "https://github.com/kyledrake", 28 | "followers_url": "https://api.github.com/users/kyledrake/followers", 29 | "following_url": "https://api.github.com/users/kyledrake/following{/other_user}", 30 | "gists_url": "https://api.github.com/users/kyledrake/gists{/gist_id}", 31 | "starred_url": "https://api.github.com/users/kyledrake/starred{/owner}{/repo}", 32 | "subscriptions_url": "https://api.github.com/users/kyledrake/subscriptions", 33 | "organizations_url": "https://api.github.com/users/kyledrake/orgs", 34 | "repos_url": "https://api.github.com/users/kyledrake/repos", 35 | "events_url": "https://api.github.com/users/kyledrake/events{/privacy}", 36 | "received_events_url": "https://api.github.com/users/kyledrake/received_events", 37 | "type": "User", 38 | "site_admin": false 39 | }, 40 | { 41 | "login": "NHQ", 42 | "id": 194352, 43 | "avatar_url": "https://gravatar.com/avatar/0c6d52336339c552eb3a2ec9b9348549?d=https%3A%2F%2Fidenticons.github.com%2Faf5a0492a69ab63e34b6ceef2c09d01b.png&r=x", 44 | "gravatar_id": "0c6d52336339c552eb3a2ec9b9348549", 45 | "url": "https://api.github.com/users/NHQ", 46 | "html_url": "https://github.com/NHQ", 47 | "followers_url": "https://api.github.com/users/NHQ/followers", 48 | "following_url": "https://api.github.com/users/NHQ/following{/other_user}", 49 | "gists_url": "https://api.github.com/users/NHQ/gists{/gist_id}", 50 | "starred_url": "https://api.github.com/users/NHQ/starred{/owner}{/repo}", 51 | "subscriptions_url": "https://api.github.com/users/NHQ/subscriptions", 52 | "organizations_url": "https://api.github.com/users/NHQ/orgs", 53 | "repos_url": "https://api.github.com/users/NHQ/repos", 54 | "events_url": "https://api.github.com/users/NHQ/events{/privacy}", 55 | "received_events_url": "https://api.github.com/users/NHQ/received_events", 56 | "type": "User", 57 | "site_admin": false 58 | }, 59 | { 60 | "login": "ralphtheninja", 61 | "id": 308049, 62 | "avatar_url": "https://gravatar.com/avatar/845fa52df723d253516a80a86ffe1a29?d=https%3A%2F%2Fidenticons.github.com%2F95e7c6733a0a8c4a48236dad384dd3a0.png&r=x", 63 | "gravatar_id": "845fa52df723d253516a80a86ffe1a29", 64 | "url": "https://api.github.com/users/ralphtheninja", 65 | "html_url": "https://github.com/ralphtheninja", 66 | "followers_url": "https://api.github.com/users/ralphtheninja/followers", 67 | "following_url": "https://api.github.com/users/ralphtheninja/following{/other_user}", 68 | "gists_url": "https://api.github.com/users/ralphtheninja/gists{/gist_id}", 69 | "starred_url": "https://api.github.com/users/ralphtheninja/starred{/owner}{/repo}", 70 | "subscriptions_url": "https://api.github.com/users/ralphtheninja/subscriptions", 71 | "organizations_url": "https://api.github.com/users/ralphtheninja/orgs", 72 | "repos_url": "https://api.github.com/users/ralphtheninja/repos", 73 | "events_url": "https://api.github.com/users/ralphtheninja/events{/privacy}", 74 | "received_events_url": "https://api.github.com/users/ralphtheninja/received_events", 75 | "type": "User", 76 | "site_admin": false 77 | } 78 | ] 79 | -------------------------------------------------------------------------------- /test/fixtures/comments.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "url": "https://api.github.com/repos/dominictarr/feedopensource/issues/comments/31484312", 4 | "html_url": "https://github.com/dominictarr/feedopensource/issues/4#issuecomment-31484312", 5 | "issue_url": "https://api.github.com/repos/dominictarr/feedopensource/issues/4", 6 | "id": 31484312, 7 | "user": { 8 | "login": "ralphtheninja", 9 | "id": 308049, 10 | "avatar_url": "https://gravatar.com/avatar/845fa52df723d253516a80a86ffe1a29?d=https%3A%2F%2Fidenticons.github.com%2F95e7c6733a0a8c4a48236dad384dd3a0.png&r=x", 11 | "gravatar_id": "845fa52df723d253516a80a86ffe1a29", 12 | "url": "https://api.github.com/users/ralphtheninja", 13 | "html_url": "https://github.com/ralphtheninja", 14 | "followers_url": "https://api.github.com/users/ralphtheninja/followers", 15 | "following_url": "https://api.github.com/users/ralphtheninja/following{/other_user}", 16 | "gists_url": "https://api.github.com/users/ralphtheninja/gists{/gist_id}", 17 | "starred_url": "https://api.github.com/users/ralphtheninja/starred{/owner}{/repo}", 18 | "subscriptions_url": "https://api.github.com/users/ralphtheninja/subscriptions", 19 | "organizations_url": "https://api.github.com/users/ralphtheninja/orgs", 20 | "repos_url": "https://api.github.com/users/ralphtheninja/repos", 21 | "events_url": "https://api.github.com/users/ralphtheninja/events{/privacy}", 22 | "received_events_url": "https://api.github.com/users/ralphtheninja/received_events", 23 | "type": "User", 24 | "site_admin": false 25 | }, 26 | "created_at": "2014-01-02T21:02:38Z", 27 | "updated_at": "2014-01-02T21:02:38Z", 28 | "body": "I'll back half of that. Making this repo public soon?" 29 | }, 30 | { 31 | "url": "https://api.github.com/repos/dominictarr/feedopensource/issues/comments/31505475", 32 | "html_url": "https://github.com/dominictarr/feedopensource/issues/4#issuecomment-31505475", 33 | "issue_url": "https://api.github.com/repos/dominictarr/feedopensource/issues/4", 34 | "id": 31505475, 35 | "user": { 36 | "login": "dominictarr", 37 | "id": 259374, 38 | "avatar_url": "https://gravatar.com/avatar/8225d7ca5e83a3f9f0bb89a61d5df72c?d=https%3A%2F%2Fidenticons.github.com%2F6b7bbeffb7d27119a32f65804f7af00a.png&r=x", 39 | "gravatar_id": "8225d7ca5e83a3f9f0bb89a61d5df72c", 40 | "url": "https://api.github.com/users/dominictarr", 41 | "html_url": "https://github.com/dominictarr", 42 | "followers_url": "https://api.github.com/users/dominictarr/followers", 43 | "following_url": "https://api.github.com/users/dominictarr/following{/other_user}", 44 | "gists_url": "https://api.github.com/users/dominictarr/gists{/gist_id}", 45 | "starred_url": "https://api.github.com/users/dominictarr/starred{/owner}{/repo}", 46 | "subscriptions_url": "https://api.github.com/users/dominictarr/subscriptions", 47 | "organizations_url": "https://api.github.com/users/dominictarr/orgs", 48 | "repos_url": "https://api.github.com/users/dominictarr/repos", 49 | "events_url": "https://api.github.com/users/dominictarr/events{/privacy}", 50 | "received_events_url": "https://api.github.com/users/dominictarr/received_events", 51 | "type": "User", 52 | "site_admin": false 53 | }, 54 | "created_at": "2014-01-03T04:55:46Z", 55 | "updated_at": "2014-01-03T04:55:46Z", 56 | "body": "Awesome! yes I will make it public soon, just a few more small things to do.\r\n\r\nThis iteration is only the first step. We'll probably (guessing) need 3 or so to get to something that is easy to use on other projects, and maybe more than that to get something really usable, I don't really know yet because I havn't used the system yet.\r\nSo, i think it's best to fund an amount that you could afford to continue to fund for a while.\r\nLike, just fund one 6th, but for 3 iterations." 57 | }, 58 | { 59 | "url": "https://api.github.com/repos/dominictarr/feedopensource/issues/comments/31514474", 60 | "html_url": "https://github.com/dominictarr/feedopensource/issues/4#issuecomment-31514474", 61 | "issue_url": "https://api.github.com/repos/dominictarr/feedopensource/issues/4", 62 | "id": 31514474, 63 | "user": { 64 | "login": "ralphtheninja", 65 | "id": 308049, 66 | "avatar_url": "https://gravatar.com/avatar/845fa52df723d253516a80a86ffe1a29?d=https%3A%2F%2Fidenticons.github.com%2F95e7c6733a0a8c4a48236dad384dd3a0.png&r=x", 67 | "gravatar_id": "845fa52df723d253516a80a86ffe1a29", 68 | "url": "https://api.github.com/users/ralphtheninja", 69 | "html_url": "https://github.com/ralphtheninja", 70 | "followers_url": "https://api.github.com/users/ralphtheninja/followers", 71 | "following_url": "https://api.github.com/users/ralphtheninja/following{/other_user}", 72 | "gists_url": "https://api.github.com/users/ralphtheninja/gists{/gist_id}", 73 | "starred_url": "https://api.github.com/users/ralphtheninja/starred{/owner}{/repo}", 74 | "subscriptions_url": "https://api.github.com/users/ralphtheninja/subscriptions", 75 | "organizations_url": "https://api.github.com/users/ralphtheninja/orgs", 76 | "repos_url": "https://api.github.com/users/ralphtheninja/repos", 77 | "events_url": "https://api.github.com/users/ralphtheninja/events{/privacy}", 78 | "received_events_url": "https://api.github.com/users/ralphtheninja/received_events", 79 | "type": "User", 80 | "site_admin": false 81 | }, 82 | "created_at": "2014-01-03T10:15:40Z", 83 | "updated_at": "2014-01-03T10:15:40Z", 84 | "body": "Sounds good!" 85 | }, 86 | { 87 | "url": "https://api.github.com/repos/dominictarr/feedopensource/issues/comments/31555518", 88 | "html_url": "https://github.com/dominictarr/feedopensource/issues/4#issuecomment-31555518", 89 | "issue_url": "https://api.github.com/repos/dominictarr/feedopensource/issues/4", 90 | "id": 31555518, 91 | "user": { 92 | "login": "NHQ", 93 | "id": 194352, 94 | "avatar_url": "https://gravatar.com/avatar/0c6d52336339c552eb3a2ec9b9348549?d=https%3A%2F%2Fidenticons.github.com%2Faf5a0492a69ab63e34b6ceef2c09d01b.png&r=x", 95 | "gravatar_id": "0c6d52336339c552eb3a2ec9b9348549", 96 | "url": "https://api.github.com/users/NHQ", 97 | "html_url": "https://github.com/NHQ", 98 | "followers_url": "https://api.github.com/users/NHQ/followers", 99 | "following_url": "https://api.github.com/users/NHQ/following{/other_user}", 100 | "gists_url": "https://api.github.com/users/NHQ/gists{/gist_id}", 101 | "starred_url": "https://api.github.com/users/NHQ/starred{/owner}{/repo}", 102 | "subscriptions_url": "https://api.github.com/users/NHQ/subscriptions", 103 | "organizations_url": "https://api.github.com/users/NHQ/orgs", 104 | "repos_url": "https://api.github.com/users/NHQ/repos", 105 | "events_url": "https://api.github.com/users/NHQ/events{/privacy}", 106 | "received_events_url": "https://api.github.com/users/NHQ/received_events", 107 | "type": "User", 108 | "site_admin": false 109 | }, 110 | "created_at": "2014-01-03T21:33:51Z", 111 | "updated_at": "2014-01-07T23:57:57Z", 112 | "body": "johnny honestly backs this IT with a fifth of a bit\r\n" 113 | }, 114 | { 115 | "url": "https://api.github.com/repos/dominictarr/feedopensource/issues/comments/31949334", 116 | "html_url": "https://github.com/dominictarr/feedopensource/issues/4#issuecomment-31949334", 117 | "issue_url": "https://api.github.com/repos/dominictarr/feedopensource/issues/4", 118 | "id": 31949334, 119 | "user": { 120 | "login": "dominictarr", 121 | "id": 259374, 122 | "avatar_url": "https://gravatar.com/avatar/8225d7ca5e83a3f9f0bb89a61d5df72c?d=https%3A%2F%2Fidenticons.github.com%2F6b7bbeffb7d27119a32f65804f7af00a.png&r=x", 123 | "gravatar_id": "8225d7ca5e83a3f9f0bb89a61d5df72c", 124 | "url": "https://api.github.com/users/dominictarr", 125 | "html_url": "https://github.com/dominictarr", 126 | "followers_url": "https://api.github.com/users/dominictarr/followers", 127 | "following_url": "https://api.github.com/users/dominictarr/following{/other_user}", 128 | "gists_url": "https://api.github.com/users/dominictarr/gists{/gist_id}", 129 | "starred_url": "https://api.github.com/users/dominictarr/starred{/owner}{/repo}", 130 | "subscriptions_url": "https://api.github.com/users/dominictarr/subscriptions", 131 | "organizations_url": "https://api.github.com/users/dominictarr/orgs", 132 | "repos_url": "https://api.github.com/users/dominictarr/repos", 133 | "events_url": "https://api.github.com/users/dominictarr/events{/privacy}", 134 | "received_events_url": "https://api.github.com/users/dominictarr/received_events", 135 | "type": "User", 136 | "site_admin": false 137 | }, 138 | "created_at": "2014-01-09T16:28:31Z", 139 | "updated_at": "2014-01-09T16:28:31Z", 140 | "body": "okay, I put in https://blockchain.info/tx/bc0fbffd92993aa3eed60bb69e7320283100ffea36c5d26f851a8ebcb616f592 just to check things where working before I go live..." 141 | }, 142 | { 143 | "url": "https://api.github.com/repos/dominictarr/feedopensource/issues/comments/31952119", 144 | "html_url": "https://github.com/dominictarr/feedopensource/issues/4#issuecomment-31952119", 145 | "issue_url": "https://api.github.com/repos/dominictarr/feedopensource/issues/4", 146 | "id": 31952119, 147 | "user": { 148 | "login": "dominictarr", 149 | "id": 259374, 150 | "avatar_url": "https://gravatar.com/avatar/8225d7ca5e83a3f9f0bb89a61d5df72c?d=https%3A%2F%2Fidenticons.github.com%2F6b7bbeffb7d27119a32f65804f7af00a.png&r=x", 151 | "gravatar_id": "8225d7ca5e83a3f9f0bb89a61d5df72c", 152 | "url": "https://api.github.com/users/dominictarr", 153 | "html_url": "https://github.com/dominictarr", 154 | "followers_url": "https://api.github.com/users/dominictarr/followers", 155 | "following_url": "https://api.github.com/users/dominictarr/following{/other_user}", 156 | "gists_url": "https://api.github.com/users/dominictarr/gists{/gist_id}", 157 | "starred_url": "https://api.github.com/users/dominictarr/starred{/owner}{/repo}", 158 | "subscriptions_url": "https://api.github.com/users/dominictarr/subscriptions", 159 | "organizations_url": "https://api.github.com/users/dominictarr/orgs", 160 | "repos_url": "https://api.github.com/users/dominictarr/repos", 161 | "events_url": "https://api.github.com/users/dominictarr/events{/privacy}", 162 | "received_events_url": "https://api.github.com/users/dominictarr/received_events", 163 | "type": "User", 164 | "site_admin": false 165 | }, 166 | "created_at": "2014-01-09T16:51:38Z", 167 | "updated_at": "2014-01-09T16:51:38Z", 168 | "body": "*this is now live*" 169 | }, 170 | { 171 | "url": "https://api.github.com/repos/dominictarr/feedopensource/issues/comments/31972637", 172 | "html_url": "https://github.com/dominictarr/feedopensource/issues/4#issuecomment-31972637", 173 | "issue_url": "https://api.github.com/repos/dominictarr/feedopensource/issues/4", 174 | "id": 31972637, 175 | "user": { 176 | "login": "ralphtheninja", 177 | "id": 308049, 178 | "avatar_url": "https://gravatar.com/avatar/845fa52df723d253516a80a86ffe1a29?d=https%3A%2F%2Fidenticons.github.com%2F95e7c6733a0a8c4a48236dad384dd3a0.png&r=x", 179 | "gravatar_id": "845fa52df723d253516a80a86ffe1a29", 180 | "url": "https://api.github.com/users/ralphtheninja", 181 | "html_url": "https://github.com/ralphtheninja", 182 | "followers_url": "https://api.github.com/users/ralphtheninja/followers", 183 | "following_url": "https://api.github.com/users/ralphtheninja/following{/other_user}", 184 | "gists_url": "https://api.github.com/users/ralphtheninja/gists{/gist_id}", 185 | "starred_url": "https://api.github.com/users/ralphtheninja/starred{/owner}{/repo}", 186 | "subscriptions_url": "https://api.github.com/users/ralphtheninja/subscriptions", 187 | "organizations_url": "https://api.github.com/users/ralphtheninja/orgs", 188 | "repos_url": "https://api.github.com/users/ralphtheninja/repos", 189 | "events_url": "https://api.github.com/users/ralphtheninja/events{/privacy}", 190 | "received_events_url": "https://api.github.com/users/ralphtheninja/received_events", 191 | "type": "User", 192 | "site_admin": false 193 | }, 194 | "created_at": "2014-01-09T20:29:06Z", 195 | "updated_at": "2014-01-09T20:29:06Z", 196 | "body": "Yay!" 197 | }, 198 | { 199 | "url": "https://api.github.com/repos/dominictarr/feedopensource/issues/comments/32000866", 200 | "html_url": "https://github.com/dominictarr/feedopensource/issues/4#issuecomment-32000866", 201 | "issue_url": "https://api.github.com/repos/dominictarr/feedopensource/issues/4", 202 | "id": 32000866, 203 | "user": { 204 | "login": "binarykitchen", 205 | "id": 177641, 206 | "avatar_url": "https://gravatar.com/avatar/e113ffc49039a4e71fe98fe536789341?d=https%3A%2F%2Fidenticons.github.com%2Fd06323323c58f67cccd41fffa8c4f1df.png&r=x", 207 | "gravatar_id": "e113ffc49039a4e71fe98fe536789341", 208 | "url": "https://api.github.com/users/binarykitchen", 209 | "html_url": "https://github.com/binarykitchen", 210 | "followers_url": "https://api.github.com/users/binarykitchen/followers", 211 | "following_url": "https://api.github.com/users/binarykitchen/following{/other_user}", 212 | "gists_url": "https://api.github.com/users/binarykitchen/gists{/gist_id}", 213 | "starred_url": "https://api.github.com/users/binarykitchen/starred{/owner}{/repo}", 214 | "subscriptions_url": "https://api.github.com/users/binarykitchen/subscriptions", 215 | "organizations_url": "https://api.github.com/users/binarykitchen/orgs", 216 | "repos_url": "https://api.github.com/users/binarykitchen/repos", 217 | "events_url": "https://api.github.com/users/binarykitchen/events{/privacy}", 218 | "received_events_url": "https://api.github.com/users/binarykitchen/received_events", 219 | "type": "User", 220 | "site_admin": false 221 | }, 222 | "created_at": "2014-01-10T03:52:04Z", 223 | "updated_at": "2014-01-10T03:52:04Z", 224 | "body": "Awesome stuff! Curious to see if this is going to work ...\r\n\r\nJust did a small transaction with the ID b669c10b631217487437b284f811dc97c9a7f45520ef8fc2a263d268bb3c8560-000" 225 | }, 226 | { 227 | "url": "https://api.github.com/repos/dominictarr/feedopensource/issues/comments/32002651", 228 | "html_url": "https://github.com/dominictarr/feedopensource/issues/4#issuecomment-32002651", 229 | "issue_url": "https://api.github.com/repos/dominictarr/feedopensource/issues/4", 230 | "id": 32002651, 231 | "user": { 232 | "login": "substack", 233 | "id": 12631, 234 | "avatar_url": "https://gravatar.com/avatar/d4a2f12ceae3b7f211b661576d22bfb9?d=https%3A%2F%2Fidenticons.github.com%2F84adf1b967670705085ec0ca0cf48e31.png&r=x", 235 | "gravatar_id": "d4a2f12ceae3b7f211b661576d22bfb9", 236 | "url": "https://api.github.com/users/substack", 237 | "html_url": "https://github.com/substack", 238 | "followers_url": "https://api.github.com/users/substack/followers", 239 | "following_url": "https://api.github.com/users/substack/following{/other_user}", 240 | "gists_url": "https://api.github.com/users/substack/gists{/gist_id}", 241 | "starred_url": "https://api.github.com/users/substack/starred{/owner}{/repo}", 242 | "subscriptions_url": "https://api.github.com/users/substack/subscriptions", 243 | "organizations_url": "https://api.github.com/users/substack/orgs", 244 | "repos_url": "https://api.github.com/users/substack/repos", 245 | "events_url": "https://api.github.com/users/substack/events{/privacy}", 246 | "received_events_url": "https://api.github.com/users/substack/received_events", 247 | "type": "User", 248 | "site_admin": false 249 | }, 250 | "created_at": "2014-01-10T04:53:00Z", 251 | "updated_at": "2014-01-10T04:53:00Z", 252 | "body": "f064ade31e374a57ebd03d9435f30ca8c8809b068974317394f433d153828112" 253 | }, 254 | { 255 | "url": "https://api.github.com/repos/dominictarr/feedopensource/issues/comments/32006031", 256 | "html_url": "https://github.com/dominictarr/feedopensource/issues/4#issuecomment-32006031", 257 | "issue_url": "https://api.github.com/repos/dominictarr/feedopensource/issues/4", 258 | "id": 32006031, 259 | "user": { 260 | "login": "ralphtheninja", 261 | "id": 308049, 262 | "avatar_url": "https://gravatar.com/avatar/845fa52df723d253516a80a86ffe1a29?d=https%3A%2F%2Fidenticons.github.com%2F95e7c6733a0a8c4a48236dad384dd3a0.png&r=x", 263 | "gravatar_id": "845fa52df723d253516a80a86ffe1a29", 264 | "url": "https://api.github.com/users/ralphtheninja", 265 | "html_url": "https://github.com/ralphtheninja", 266 | "followers_url": "https://api.github.com/users/ralphtheninja/followers", 267 | "following_url": "https://api.github.com/users/ralphtheninja/following{/other_user}", 268 | "gists_url": "https://api.github.com/users/ralphtheninja/gists{/gist_id}", 269 | "starred_url": "https://api.github.com/users/ralphtheninja/starred{/owner}{/repo}", 270 | "subscriptions_url": "https://api.github.com/users/ralphtheninja/subscriptions", 271 | "organizations_url": "https://api.github.com/users/ralphtheninja/orgs", 272 | "repos_url": "https://api.github.com/users/ralphtheninja/repos", 273 | "events_url": "https://api.github.com/users/ralphtheninja/events{/privacy}", 274 | "received_events_url": "https://api.github.com/users/ralphtheninja/received_events", 275 | "type": "User", 276 | "site_admin": false 277 | }, 278 | "created_at": "2014-01-10T06:46:25Z", 279 | "updated_at": "2014-01-10T06:46:25Z", 280 | "body": "https://blockchain.info/tx/3010b4d93dda15df8345ede9164b9adf2e25e1ecb9d978c74e2cfdd36315c735" 281 | }, 282 | { 283 | "url": "https://api.github.com/repos/dominictarr/feedopensource/issues/comments/32015350", 284 | "html_url": "https://github.com/dominictarr/feedopensource/issues/4#issuecomment-32015350", 285 | "issue_url": "https://api.github.com/repos/dominictarr/feedopensource/issues/4", 286 | "id": 32015350, 287 | "user": { 288 | "login": "bluntworks", 289 | "id": 120600, 290 | "avatar_url": "https://gravatar.com/avatar/afdea4b6698ba60737124c4279976939?d=https%3A%2F%2Fidenticons.github.com%2F4b9a75aa52791826aae5a465bc0521aa.png&r=x", 291 | "gravatar_id": "afdea4b6698ba60737124c4279976939", 292 | "url": "https://api.github.com/users/bluntworks", 293 | "html_url": "https://github.com/bluntworks", 294 | "followers_url": "https://api.github.com/users/bluntworks/followers", 295 | "following_url": "https://api.github.com/users/bluntworks/following{/other_user}", 296 | "gists_url": "https://api.github.com/users/bluntworks/gists{/gist_id}", 297 | "starred_url": "https://api.github.com/users/bluntworks/starred{/owner}{/repo}", 298 | "subscriptions_url": "https://api.github.com/users/bluntworks/subscriptions", 299 | "organizations_url": "https://api.github.com/users/bluntworks/orgs", 300 | "repos_url": "https://api.github.com/users/bluntworks/repos", 301 | "events_url": "https://api.github.com/users/bluntworks/events{/privacy}", 302 | "received_events_url": "https://api.github.com/users/bluntworks/received_events", 303 | "type": "User", 304 | "site_admin": false 305 | }, 306 | "created_at": "2014-01-10T10:02:36Z", 307 | "updated_at": "2014-01-10T10:02:36Z", 308 | "body": "https://blockchain.info/tx/ac2afeb9400f401b67eb39f25d4b4d046d35308117f0db6dace7165c89af6c0d" 309 | }, 310 | { 311 | "url": "https://api.github.com/repos/dominictarr/feedopensource/issues/comments/32036793", 312 | "html_url": "https://github.com/dominictarr/feedopensource/issues/4#issuecomment-32036793", 313 | "issue_url": "https://api.github.com/repos/dominictarr/feedopensource/issues/4", 314 | "id": 32036793, 315 | "user": { 316 | "login": "gotcha", 317 | "id": 105204, 318 | "avatar_url": "https://gravatar.com/avatar/fa370c58c6265e0e496668f4cb39e14a?d=https%3A%2F%2Fidenticons.github.com%2F0d19d8eb54cb918bd88faa73f1627c2f.png&r=x", 319 | "gravatar_id": "fa370c58c6265e0e496668f4cb39e14a", 320 | "url": "https://api.github.com/users/gotcha", 321 | "html_url": "https://github.com/gotcha", 322 | "followers_url": "https://api.github.com/users/gotcha/followers", 323 | "following_url": "https://api.github.com/users/gotcha/following{/other_user}", 324 | "gists_url": "https://api.github.com/users/gotcha/gists{/gist_id}", 325 | "starred_url": "https://api.github.com/users/gotcha/starred{/owner}{/repo}", 326 | "subscriptions_url": "https://api.github.com/users/gotcha/subscriptions", 327 | "organizations_url": "https://api.github.com/users/gotcha/orgs", 328 | "repos_url": "https://api.github.com/users/gotcha/repos", 329 | "events_url": "https://api.github.com/users/gotcha/events{/privacy}", 330 | "received_events_url": "https://api.github.com/users/gotcha/received_events", 331 | "type": "User", 332 | "site_admin": false 333 | }, 334 | "created_at": "2014-01-10T15:33:45Z", 335 | "updated_at": "2014-01-10T15:33:45Z", 336 | "body": "https://blockchain.info/tx/5cd0556cb8522fb3485a6e1f79f3e7091d2bdacc98c8fe9c8e097752548a6a6d" 337 | }, 338 | { 339 | "url": "https://api.github.com/repos/dominictarr/feedopensource/issues/comments/32115619", 340 | "html_url": "https://github.com/dominictarr/feedopensource/issues/4#issuecomment-32115619", 341 | "issue_url": "https://api.github.com/repos/dominictarr/feedopensource/issues/4", 342 | "id": 32115619, 343 | "user": { 344 | "login": "julianduque", 345 | "id": 733877, 346 | "avatar_url": "https://gravatar.com/avatar/c2d1139b787a469e13229070d6be918c?d=https%3A%2F%2Fidenticons.github.com%2Fcd761eb60d020963e0e23ec1e48949cb.png&r=x", 347 | "gravatar_id": "c2d1139b787a469e13229070d6be918c", 348 | "url": "https://api.github.com/users/julianduque", 349 | "html_url": "https://github.com/julianduque", 350 | "followers_url": "https://api.github.com/users/julianduque/followers", 351 | "following_url": "https://api.github.com/users/julianduque/following{/other_user}", 352 | "gists_url": "https://api.github.com/users/julianduque/gists{/gist_id}", 353 | "starred_url": "https://api.github.com/users/julianduque/starred{/owner}{/repo}", 354 | "subscriptions_url": "https://api.github.com/users/julianduque/subscriptions", 355 | "organizations_url": "https://api.github.com/users/julianduque/orgs", 356 | "repos_url": "https://api.github.com/users/julianduque/repos", 357 | "events_url": "https://api.github.com/users/julianduque/events{/privacy}", 358 | "received_events_url": "https://api.github.com/users/julianduque/received_events", 359 | "type": "User", 360 | "site_admin": false 361 | }, 362 | "created_at": "2014-01-12T05:17:45Z", 363 | "updated_at": "2014-01-12T05:17:45Z", 364 | "body": "https://blockchain.info/tx/eca34ac3d130d1fe29668c4bb9d10d7d08d1b22f62cae9488105303e1494d06e" 365 | }, 366 | { 367 | "url": "https://api.github.com/repos/dominictarr/feedopensource/issues/comments/32117021", 368 | "html_url": "https://github.com/dominictarr/feedopensource/issues/4#issuecomment-32117021", 369 | "issue_url": "https://api.github.com/repos/dominictarr/feedopensource/issues/4", 370 | "id": 32117021, 371 | "user": { 372 | "login": "hansent", 373 | "id": 137617, 374 | "avatar_url": "https://gravatar.com/avatar/fb39a4c30656a954fffe6015a6e0c50e?d=https%3A%2F%2Fidenticons.github.com%2F7bc74a3dbf870e2efa020cfd0c19a91e.png&r=x", 375 | "gravatar_id": "fb39a4c30656a954fffe6015a6e0c50e", 376 | "url": "https://api.github.com/users/hansent", 377 | "html_url": "https://github.com/hansent", 378 | "followers_url": "https://api.github.com/users/hansent/followers", 379 | "following_url": "https://api.github.com/users/hansent/following{/other_user}", 380 | "gists_url": "https://api.github.com/users/hansent/gists{/gist_id}", 381 | "starred_url": "https://api.github.com/users/hansent/starred{/owner}{/repo}", 382 | "subscriptions_url": "https://api.github.com/users/hansent/subscriptions", 383 | "organizations_url": "https://api.github.com/users/hansent/orgs", 384 | "repos_url": "https://api.github.com/users/hansent/repos", 385 | "events_url": "https://api.github.com/users/hansent/events{/privacy}", 386 | "received_events_url": "https://api.github.com/users/hansent/received_events", 387 | "type": "User", 388 | "site_admin": false 389 | }, 390 | "created_at": "2014-01-12T07:20:21Z", 391 | "updated_at": "2014-01-12T07:20:21Z", 392 | "body": "GyX//+gwsjKPS/03enVZFEkmnavF794Dyfki/ATbHPEMRut6US/QhqqiX/D/yfUyHCJHUCIUWNbE2QgB8eDBIe4=\r\n\r\nhttps://blockchain.info/tx/a92f09c0926f64479e060b24d0aa7f0af0f793ec81611f04e20e6c2a7f77c406" 393 | }, 394 | { 395 | "url": "https://api.github.com/repos/dominictarr/feedopensource/issues/comments/32117292", 396 | "html_url": "https://github.com/dominictarr/feedopensource/issues/4#issuecomment-32117292", 397 | "issue_url": "https://api.github.com/repos/dominictarr/feedopensource/issues/4", 398 | "id": 32117292, 399 | "user": { 400 | "login": "levity", 401 | "id": 193667, 402 | "avatar_url": "https://gravatar.com/avatar/51ac8ca0bfc70f0bca64c3bec0cb473c?d=https%3A%2F%2Fidenticons.github.com%2F787907eaa93e7a5f65334b9cfe537e9e.png&r=x", 403 | "gravatar_id": "51ac8ca0bfc70f0bca64c3bec0cb473c", 404 | "url": "https://api.github.com/users/levity", 405 | "html_url": "https://github.com/levity", 406 | "followers_url": "https://api.github.com/users/levity/followers", 407 | "following_url": "https://api.github.com/users/levity/following{/other_user}", 408 | "gists_url": "https://api.github.com/users/levity/gists{/gist_id}", 409 | "starred_url": "https://api.github.com/users/levity/starred{/owner}{/repo}", 410 | "subscriptions_url": "https://api.github.com/users/levity/subscriptions", 411 | "organizations_url": "https://api.github.com/users/levity/orgs", 412 | "repos_url": "https://api.github.com/users/levity/repos", 413 | "events_url": "https://api.github.com/users/levity/events{/privacy}", 414 | "received_events_url": "https://api.github.com/users/levity/received_events", 415 | "type": "User", 416 | "site_admin": false 417 | }, 418 | "created_at": "2014-01-12T07:42:03Z", 419 | "updated_at": "2014-01-12T07:42:03Z", 420 | "body": "https://blockchain.info/tx/3be0bfb93638f01007e023faf51e28a1c690c0cb0130d749d4c4dfbf6a8d339b" 421 | }, 422 | { 423 | "url": "https://api.github.com/repos/dominictarr/feedopensource/issues/comments/32117586", 424 | "html_url": "https://github.com/dominictarr/feedopensource/issues/4#issuecomment-32117586", 425 | "issue_url": "https://api.github.com/repos/dominictarr/feedopensource/issues/4", 426 | "id": 32117586, 427 | "user": { 428 | "login": "dominictarr", 429 | "id": 259374, 430 | "avatar_url": "https://gravatar.com/avatar/8225d7ca5e83a3f9f0bb89a61d5df72c?d=https%3A%2F%2Fidenticons.github.com%2F6b7bbeffb7d27119a32f65804f7af00a.png&r=x", 431 | "gravatar_id": "8225d7ca5e83a3f9f0bb89a61d5df72c", 432 | "url": "https://api.github.com/users/dominictarr", 433 | "html_url": "https://github.com/dominictarr", 434 | "followers_url": "https://api.github.com/users/dominictarr/followers", 435 | "following_url": "https://api.github.com/users/dominictarr/following{/other_user}", 436 | "gists_url": "https://api.github.com/users/dominictarr/gists{/gist_id}", 437 | "starred_url": "https://api.github.com/users/dominictarr/starred{/owner}{/repo}", 438 | "subscriptions_url": "https://api.github.com/users/dominictarr/subscriptions", 439 | "organizations_url": "https://api.github.com/users/dominictarr/orgs", 440 | "repos_url": "https://api.github.com/users/dominictarr/repos", 441 | "events_url": "https://api.github.com/users/dominictarr/events{/privacy}", 442 | "received_events_url": "https://api.github.com/users/dominictarr/received_events", 443 | "type": "User", 444 | "site_admin": false 445 | }, 446 | "created_at": "2014-01-12T08:10:03Z", 447 | "updated_at": "2014-01-12T08:10:03Z", 448 | "body": "thanks, you guys rule!" 449 | }, 450 | { 451 | "url": "https://api.github.com/repos/dominictarr/feedopensource/issues/comments/32119771", 452 | "html_url": "https://github.com/dominictarr/feedopensource/issues/4#issuecomment-32119771", 453 | "issue_url": "https://api.github.com/repos/dominictarr/feedopensource/issues/4", 454 | "id": 32119771, 455 | "user": { 456 | "login": "eugeneware", 457 | "id": 38154, 458 | "avatar_url": "https://gravatar.com/avatar/7eab3f90d1d3164608293f3d38759e4e?d=https%3A%2F%2Fidenticons.github.com%2Fe7eb6d06172005c7bd96c8672cf4dd46.png&r=x", 459 | "gravatar_id": "7eab3f90d1d3164608293f3d38759e4e", 460 | "url": "https://api.github.com/users/eugeneware", 461 | "html_url": "https://github.com/eugeneware", 462 | "followers_url": "https://api.github.com/users/eugeneware/followers", 463 | "following_url": "https://api.github.com/users/eugeneware/following{/other_user}", 464 | "gists_url": "https://api.github.com/users/eugeneware/gists{/gist_id}", 465 | "starred_url": "https://api.github.com/users/eugeneware/starred{/owner}{/repo}", 466 | "subscriptions_url": "https://api.github.com/users/eugeneware/subscriptions", 467 | "organizations_url": "https://api.github.com/users/eugeneware/orgs", 468 | "repos_url": "https://api.github.com/users/eugeneware/repos", 469 | "events_url": "https://api.github.com/users/eugeneware/events{/privacy}", 470 | "received_events_url": "https://api.github.com/users/eugeneware/received_events", 471 | "type": "User", 472 | "site_admin": false 473 | }, 474 | "created_at": "2014-01-12T10:48:39Z", 475 | "updated_at": "2014-01-12T10:49:16Z", 476 | "body": "http://blockchain.info/tx/f11a08dcc2e336095c5118bb95124be30e379aaee4a98a532e524e475fcf563b" 477 | }, 478 | { 479 | "url": "https://api.github.com/repos/dominictarr/feedopensource/issues/comments/32122078", 480 | "html_url": "https://github.com/dominictarr/feedopensource/issues/4#issuecomment-32122078", 481 | "issue_url": "https://api.github.com/repos/dominictarr/feedopensource/issues/4", 482 | "id": 32122078, 483 | "user": { 484 | "login": "ralphtheninja", 485 | "id": 308049, 486 | "avatar_url": "https://gravatar.com/avatar/845fa52df723d253516a80a86ffe1a29?d=https%3A%2F%2Fidenticons.github.com%2F95e7c6733a0a8c4a48236dad384dd3a0.png&r=x", 487 | "gravatar_id": "845fa52df723d253516a80a86ffe1a29", 488 | "url": "https://api.github.com/users/ralphtheninja", 489 | "html_url": "https://github.com/ralphtheninja", 490 | "followers_url": "https://api.github.com/users/ralphtheninja/followers", 491 | "following_url": "https://api.github.com/users/ralphtheninja/following{/other_user}", 492 | "gists_url": "https://api.github.com/users/ralphtheninja/gists{/gist_id}", 493 | "starred_url": "https://api.github.com/users/ralphtheninja/starred{/owner}{/repo}", 494 | "subscriptions_url": "https://api.github.com/users/ralphtheninja/subscriptions", 495 | "organizations_url": "https://api.github.com/users/ralphtheninja/orgs", 496 | "repos_url": "https://api.github.com/users/ralphtheninja/repos", 497 | "events_url": "https://api.github.com/users/ralphtheninja/events{/privacy}", 498 | "received_events_url": "https://api.github.com/users/ralphtheninja/received_events", 499 | "type": "User", 500 | "site_admin": false 501 | }, 502 | "created_at": "2014-01-12T13:08:27Z", 503 | "updated_at": "2014-01-12T13:08:27Z", 504 | "body": "Soon up to 1.2. Awesome!" 505 | }, 506 | { 507 | "url": "https://api.github.com/repos/dominictarr/feedopensource/issues/comments/32136754", 508 | "html_url": "https://github.com/dominictarr/feedopensource/issues/4#issuecomment-32136754", 509 | "issue_url": "https://api.github.com/repos/dominictarr/feedopensource/issues/4", 510 | "id": 32136754, 511 | "user": { 512 | "login": "eins78", 513 | "id": 134942, 514 | "avatar_url": "https://gravatar.com/avatar/9bcfab393e252df79fa12b0eae4701f4?d=https%3A%2F%2Fidenticons.github.com%2F47b5a953ac68315383732de7e1fbb9e4.png&r=x", 515 | "gravatar_id": "9bcfab393e252df79fa12b0eae4701f4", 516 | "url": "https://api.github.com/users/eins78", 517 | "html_url": "https://github.com/eins78", 518 | "followers_url": "https://api.github.com/users/eins78/followers", 519 | "following_url": "https://api.github.com/users/eins78/following{/other_user}", 520 | "gists_url": "https://api.github.com/users/eins78/gists{/gist_id}", 521 | "starred_url": "https://api.github.com/users/eins78/starred{/owner}{/repo}", 522 | "subscriptions_url": "https://api.github.com/users/eins78/subscriptions", 523 | "organizations_url": "https://api.github.com/users/eins78/orgs", 524 | "repos_url": "https://api.github.com/users/eins78/repos", 525 | "events_url": "https://api.github.com/users/eins78/events{/privacy}", 526 | "received_events_url": "https://api.github.com/users/eins78/received_events", 527 | "type": "User", 528 | "site_admin": false 529 | }, 530 | "created_at": "2014-01-12T22:43:26Z", 531 | "updated_at": "2014-01-12T22:44:01Z", 532 | "body": ":bell: *ding ding ding* :bell: \r\nhttps://blockchain.info/tx/96ebb5159544d6c3a3dc89f6b6886812c23e012e849f6ad92cfa6aef2f491c8d\r\n\r\n> Total Received\t1.26125445 BTC" 533 | }, 534 | { 535 | "url": "https://api.github.com/repos/dominictarr/feedopensource/issues/comments/32136788", 536 | "html_url": "https://github.com/dominictarr/feedopensource/issues/4#issuecomment-32136788", 537 | "issue_url": "https://api.github.com/repos/dominictarr/feedopensource/issues/4", 538 | "id": 32136788, 539 | "user": { 540 | "login": "ralphtheninja", 541 | "id": 308049, 542 | "avatar_url": "https://gravatar.com/avatar/845fa52df723d253516a80a86ffe1a29?d=https%3A%2F%2Fidenticons.github.com%2F95e7c6733a0a8c4a48236dad384dd3a0.png&r=x", 543 | "gravatar_id": "845fa52df723d253516a80a86ffe1a29", 544 | "url": "https://api.github.com/users/ralphtheninja", 545 | "html_url": "https://github.com/ralphtheninja", 546 | "followers_url": "https://api.github.com/users/ralphtheninja/followers", 547 | "following_url": "https://api.github.com/users/ralphtheninja/following{/other_user}", 548 | "gists_url": "https://api.github.com/users/ralphtheninja/gists{/gist_id}", 549 | "starred_url": "https://api.github.com/users/ralphtheninja/starred{/owner}{/repo}", 550 | "subscriptions_url": "https://api.github.com/users/ralphtheninja/subscriptions", 551 | "organizations_url": "https://api.github.com/users/ralphtheninja/orgs", 552 | "repos_url": "https://api.github.com/users/ralphtheninja/repos", 553 | "events_url": "https://api.github.com/users/ralphtheninja/events{/privacy}", 554 | "received_events_url": "https://api.github.com/users/ralphtheninja/received_events", 555 | "type": "User", 556 | "site_admin": false 557 | }, 558 | "created_at": "2014-01-12T22:44:32Z", 559 | "updated_at": "2014-01-12T22:44:32Z", 560 | "body": "@eins78 Haha, nice amount too! :)" 561 | }, 562 | { 563 | "url": "https://api.github.com/repos/dominictarr/feedopensource/issues/comments/32143778", 564 | "html_url": "https://github.com/dominictarr/feedopensource/issues/4#issuecomment-32143778", 565 | "issue_url": "https://api.github.com/repos/dominictarr/feedopensource/issues/4", 566 | "id": 32143778, 567 | "user": { 568 | "login": "dominictarr", 569 | "id": 259374, 570 | "avatar_url": "https://gravatar.com/avatar/8225d7ca5e83a3f9f0bb89a61d5df72c?d=https%3A%2F%2Fidenticons.github.com%2F6b7bbeffb7d27119a32f65804f7af00a.png&r=x", 571 | "gravatar_id": "8225d7ca5e83a3f9f0bb89a61d5df72c", 572 | "url": "https://api.github.com/users/dominictarr", 573 | "html_url": "https://github.com/dominictarr", 574 | "followers_url": "https://api.github.com/users/dominictarr/followers", 575 | "following_url": "https://api.github.com/users/dominictarr/following{/other_user}", 576 | "gists_url": "https://api.github.com/users/dominictarr/gists{/gist_id}", 577 | "starred_url": "https://api.github.com/users/dominictarr/starred{/owner}{/repo}", 578 | "subscriptions_url": "https://api.github.com/users/dominictarr/subscriptions", 579 | "organizations_url": "https://api.github.com/users/dominictarr/orgs", 580 | "repos_url": "https://api.github.com/users/dominictarr/repos", 581 | "events_url": "https://api.github.com/users/dominictarr/events{/privacy}", 582 | "received_events_url": "https://api.github.com/users/dominictarr/received_events", 583 | "type": "User", 584 | "site_admin": false 585 | }, 586 | "created_at": "2014-01-13T03:36:56Z", 587 | "updated_at": "2014-01-13T12:02:56Z", 588 | "body": "THANKS EVERYONE!\r\n\r\nOkay, time to get to work!\r\n\r\nI'll be posting progress here..." 589 | } 590 | ] 591 | -------------------------------------------------------------------------------- /test/fixtures/funders.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "login": "hansent", 4 | "id": 137617, 5 | "avatar_url": "https://gravatar.com/avatar/fb39a4c30656a954fffe6015a6e0c50e?d=https%3A%2F%2Fidenticons.github.com%2F7bc74a3dbf870e2efa020cfd0c19a91e.png&r=x", 6 | "gravatar_id": "fb39a4c30656a954fffe6015a6e0c50e", 7 | "url": "https://api.github.com/users/hansent", 8 | "html_url": "https://github.com/hansent", 9 | "followers_url": "https://api.github.com/users/hansent/followers", 10 | "following_url": "https://api.github.com/users/hansent/following{/other_user}", 11 | "gists_url": "https://api.github.com/users/hansent/gists{/gist_id}", 12 | "starred_url": "https://api.github.com/users/hansent/starred{/owner}{/repo}", 13 | "subscriptions_url": "https://api.github.com/users/hansent/subscriptions", 14 | "organizations_url": "https://api.github.com/users/hansent/orgs", 15 | "repos_url": "https://api.github.com/users/hansent/repos", 16 | "events_url": "https://api.github.com/users/hansent/events{/privacy}", 17 | "received_events_url": "https://api.github.com/users/hansent/received_events", 18 | "type": "User", 19 | "site_admin": false, 20 | "txs": [ 21 | { 22 | "result": 2000000, 23 | "block_height": 280050, 24 | "time": 1389510868, 25 | "inputs": [ 26 | { 27 | "prev_out": { 28 | "n": 0, 29 | "value": 50000000, 30 | "addr": "1EF2pabTPjUfWwhgMxwW5cgg8EPjunKbMn", 31 | "tx_index": 107269707, 32 | "type": 0 33 | } 34 | }, 35 | { 36 | "prev_out": { 37 | "n": 2, 38 | "value": 379582, 39 | "addr": "1GfoUdxiTb7jK4LRRZJsQYFiMt4s3G2xCN", 40 | "tx_index": 107264813, 41 | "type": 0 42 | } 43 | } 44 | ], 45 | "vout_sz": 2, 46 | "relayed_by": "127.0.0.1", 47 | "hash": "a92f09c0926f64479e060b24d0aa7f0af0f793ec81611f04e20e6c2a7f77c406", 48 | "vin_sz": 2, 49 | "tx_index": 107265696, 50 | "ver": 1, 51 | "out": [ 52 | { 53 | "n": 0, 54 | "value": 50000000, 55 | "addr": "1PTAwipYpP63uNrcxfm5FewxRdZyar6ceu", 56 | "tx_index": 107265696, 57 | "type": 0 58 | }, 59 | { 60 | "n": 1, 61 | "value": 359582, 62 | "addr": "1K4AW4VJEjBKvX2Fs6YbbtTfgXQyrkKTyS", 63 | "tx_index": 107265696, 64 | "type": 0 65 | } 66 | ], 67 | "size": 439 68 | } 69 | ], 70 | "sum": 50000000 71 | }, 72 | { 73 | "unclaimed": true, 74 | "txs": [ 75 | { 76 | "result": 2055446, 77 | "block_height": 280062, 78 | "time": 1389515352, 79 | "inputs": [ 80 | { 81 | "prev_out": { 82 | "n": 0, 83 | "value": 1000000, 84 | "addr": "1F6Puy4AgQJBm4nbvMRsQz12jEvugjRsG3", 85 | "tx_index": 99839859, 86 | "type": 0 87 | } 88 | } 89 | ], 90 | "vout_sz": 1, 91 | "relayed_by": "82.90.118.127", 92 | "hash": "612d6490306bcdac471839e2817e34a5d24522a7fd3ebae6db39898f0ee0ba62", 93 | "vin_sz": 1, 94 | "tx_index": 107275892, 95 | "ver": 1, 96 | "out": [ 97 | { 98 | "n": 0, 99 | "value": 990000, 100 | "addr": "1PTAwipYpP63uNrcxfm5FewxRdZyar6ceu", 101 | "tx_index": 107275892, 102 | "type": 0 103 | } 104 | ], 105 | "size": 191 106 | }, 107 | { 108 | "result": 50000000, 109 | "block_height": 280037, 110 | "time": 1389502493, 111 | "inputs": [ 112 | { 113 | "prev_out": { 114 | "n": 1, 115 | "value": 844270, 116 | "addr": "14wWWNFU9aZaBLjbcVQnQrUMqHzkDQygHT", 117 | "tx_index": 107248779, 118 | "type": 0 119 | } 120 | }, 121 | { 122 | "prev_out": { 123 | "n": 0, 124 | "value": 1000000, 125 | "addr": "14xqv7Z7tWYwQYgYi3RhAn5QZMAKAYHaoC", 126 | "tx_index": 107257973, 127 | "type": 0 128 | } 129 | } 130 | ], 131 | "vout_sz": 2, 132 | "relayed_by": "91.230.204.45", 133 | "hash": "9b4a49a76336a8737bcc81085e9629a91d4d469eb05420e96a02ac37f6e29e3e", 134 | "vin_sz": 2, 135 | "tx_index": 107258336, 136 | "ver": 1, 137 | "out": [ 138 | { 139 | "n": 0, 140 | "value": 1000000, 141 | "addr": "1PTAwipYpP63uNrcxfm5FewxRdZyar6ceu", 142 | "tx_index": 107258336, 143 | "type": 0 144 | }, 145 | { 146 | "n": 1, 147 | "value": 824270, 148 | "addr": "1NR2GZAq2XLuxfTixqW14RNCnvGzjEBcA5", 149 | "tx_index": 107258336, 150 | "type": 0 151 | } 152 | ], 153 | "size": 437 154 | }, 155 | { 156 | "result": 2500000, 157 | "block_height": 279640, 158 | "time": 1389333274, 159 | "inputs": [ 160 | { 161 | "prev_out": { 162 | "n": 0, 163 | "value": 100000000, 164 | "addr": "18QaFQTYePmxBJxvwCU1Dqp62suf1jozNW", 165 | "tx_index": 97749433, 166 | "type": 0 167 | } 168 | } 169 | ], 170 | "vout_sz": 2, 171 | "relayed_by": "184.56.88.71", 172 | "hash": "b3df16687b4414f43926e2546de3edd90a4e6812f7110c8350da8941b91ec89b", 173 | "vin_sz": 1, 174 | "tx_index": 106952853, 175 | "ver": 1, 176 | "out": [ 177 | { 178 | "n": 0, 179 | "value": 20000000, 180 | "addr": "1PTAwipYpP63uNrcxfm5FewxRdZyar6ceu", 181 | "tx_index": 106952853, 182 | "type": 0 183 | }, 184 | { 185 | "n": 1, 186 | "value": 79990000, 187 | "addr": "1KEpBnziPgEiHryq8hyTyS8yEHLaS3Knru", 188 | "tx_index": 106952853, 189 | "type": 0 190 | } 191 | ], 192 | "size": 225 193 | }, 194 | { 195 | "result": 20000000, 196 | "block_height": 279604, 197 | "time": 1389316807, 198 | "inputs": [ 199 | { 200 | "prev_out": { 201 | "n": 0, 202 | "value": 66379776, 203 | "addr": "1jb55g498MEa274Z1YWUXQFxZE5NzvhV7", 204 | "tx_index": 106910379, 205 | "type": 0 206 | } 207 | } 208 | ], 209 | "vout_sz": 2, 210 | "relayed_by": "127.0.0.1", 211 | "hash": "a70271dc6984b50aec36040a8745e3eaf59a7ca2533a54b94f158fbac5dcc75e", 212 | "vin_sz": 1, 213 | "tx_index": 106925020, 214 | "ver": 1, 215 | "out": [ 216 | { 217 | "n": 0, 218 | "value": 1500000, 219 | "addr": "1PTAwipYpP63uNrcxfm5FewxRdZyar6ceu", 220 | "tx_index": 106925020, 221 | "type": 0 222 | }, 223 | { 224 | "n": 1, 225 | "value": 64869776, 226 | "addr": "1jb55g498MEa274Z1YWUXQFxZE5NzvhV7", 227 | "tx_index": 106925020, 228 | "type": 0 229 | } 230 | ], 231 | "size": 259 232 | } 233 | ], 234 | "sum": 23490000, 235 | "login": "**unclaimed**" 236 | }, 237 | { 238 | "login": "ralphtheninja", 239 | "id": 308049, 240 | "avatar_url": "https://gravatar.com/avatar/845fa52df723d253516a80a86ffe1a29?d=https%3A%2F%2Fidenticons.github.com%2F95e7c6733a0a8c4a48236dad384dd3a0.png&r=x", 241 | "gravatar_id": "845fa52df723d253516a80a86ffe1a29", 242 | "url": "https://api.github.com/users/ralphtheninja", 243 | "html_url": "https://github.com/ralphtheninja", 244 | "followers_url": "https://api.github.com/users/ralphtheninja/followers", 245 | "following_url": "https://api.github.com/users/ralphtheninja/following{/other_user}", 246 | "gists_url": "https://api.github.com/users/ralphtheninja/gists{/gist_id}", 247 | "starred_url": "https://api.github.com/users/ralphtheninja/starred{/owner}{/repo}", 248 | "subscriptions_url": "https://api.github.com/users/ralphtheninja/subscriptions", 249 | "organizations_url": "https://api.github.com/users/ralphtheninja/orgs", 250 | "repos_url": "https://api.github.com/users/ralphtheninja/repos", 251 | "events_url": "https://api.github.com/users/ralphtheninja/events{/privacy}", 252 | "received_events_url": "https://api.github.com/users/ralphtheninja/received_events", 253 | "type": "User", 254 | "site_admin": false, 255 | "txs": [ 256 | { 257 | "result": 500000, 258 | "block_height": 279585, 259 | "time": 1389306192, 260 | "inputs": [ 261 | { 262 | "prev_out": { 263 | "n": 1, 264 | "value": 216553341, 265 | "addr": "1HYmvU61669fvRxJNue9TUyihjAFB4HFER", 266 | "tx_index": 106359331, 267 | "type": 0 268 | } 269 | } 270 | ], 271 | "vout_sz": 2, 272 | "relayed_by": "127.0.0.1", 273 | "hash": "3010b4d93dda15df8345ede9164b9adf2e25e1ecb9d978c74e2cfdd36315c735", 274 | "vin_sz": 1, 275 | "tx_index": 106905086, 276 | "ver": 1, 277 | "out": [ 278 | { 279 | "n": 0, 280 | "value": 20000000, 281 | "addr": "1PTAwipYpP63uNrcxfm5FewxRdZyar6ceu", 282 | "tx_index": 106905086, 283 | "type": 0 284 | }, 285 | { 286 | "n": 1, 287 | "value": 196553341, 288 | "addr": "1HYmvU61669fvRxJNue9TUyihjAFB4HFER", 289 | "tx_index": 106905086, 290 | "type": 0 291 | } 292 | ], 293 | "size": 259 294 | } 295 | ], 296 | "sum": 20000000 297 | }, 298 | { 299 | "login": "eins78", 300 | "id": 134942, 301 | "avatar_url": "https://gravatar.com/avatar/9bcfab393e252df79fa12b0eae4701f4?d=https%3A%2F%2Fidenticons.github.com%2F47b5a953ac68315383732de7e1fbb9e4.png&r=x", 302 | "gravatar_id": "9bcfab393e252df79fa12b0eae4701f4", 303 | "url": "https://api.github.com/users/eins78", 304 | "html_url": "https://github.com/eins78", 305 | "followers_url": "https://api.github.com/users/eins78/followers", 306 | "following_url": "https://api.github.com/users/eins78/following{/other_user}", 307 | "gists_url": "https://api.github.com/users/eins78/gists{/gist_id}", 308 | "starred_url": "https://api.github.com/users/eins78/starred{/owner}{/repo}", 309 | "subscriptions_url": "https://api.github.com/users/eins78/subscriptions", 310 | "organizations_url": "https://api.github.com/users/eins78/orgs", 311 | "repos_url": "https://api.github.com/users/eins78/repos", 312 | "events_url": "https://api.github.com/users/eins78/events{/privacy}", 313 | "received_events_url": "https://api.github.com/users/eins78/received_events", 314 | "type": "User", 315 | "site_admin": false, 316 | "txs": [ 317 | { 318 | "result": 0, 319 | "block_height": 280187, 320 | "time": 1389566474, 321 | "inputs": [ 322 | { 323 | "prev_out": { 324 | "n": 0, 325 | "value": 30000000, 326 | "addr": "14HyQdmwD5x2LGGcyHsxYPjAQXqHomCvtv", 327 | "tx_index": 105484188, 328 | "type": 0 329 | } 330 | } 331 | ], 332 | "vout_sz": 2, 333 | "relayed_by": "127.0.0.1", 334 | "hash": "96ebb5159544d6c3a3dc89f6b6886812c23e012e849f6ad92cfa6aef2f491c8d", 335 | "vin_sz": 1, 336 | "tx_index": 107357783, 337 | "ver": 1, 338 | "out": [ 339 | { 340 | "n": 0, 341 | "value": 13370000, 342 | "addr": "1PTAwipYpP63uNrcxfm5FewxRdZyar6ceu", 343 | "tx_index": 107357783, 344 | "type": 0 345 | }, 346 | { 347 | "n": 1, 348 | "value": 16629000, 349 | "addr": "17mNBpwcytHf6d2QZxakd31y9yisuszcWs", 350 | "tx_index": 107357783, 351 | "type": 0 352 | } 353 | ], 354 | "size": 258 355 | } 356 | ], 357 | "sum": 13370000 358 | }, 359 | { 360 | "login": "substack", 361 | "id": 12631, 362 | "avatar_url": "https://gravatar.com/avatar/d4a2f12ceae3b7f211b661576d22bfb9?d=https%3A%2F%2Fidenticons.github.com%2F84adf1b967670705085ec0ca0cf48e31.png&r=x", 363 | "gravatar_id": "d4a2f12ceae3b7f211b661576d22bfb9", 364 | "url": "https://api.github.com/users/substack", 365 | "html_url": "https://github.com/substack", 366 | "followers_url": "https://api.github.com/users/substack/followers", 367 | "following_url": "https://api.github.com/users/substack/following{/other_user}", 368 | "gists_url": "https://api.github.com/users/substack/gists{/gist_id}", 369 | "starred_url": "https://api.github.com/users/substack/starred{/owner}{/repo}", 370 | "subscriptions_url": "https://api.github.com/users/substack/subscriptions", 371 | "organizations_url": "https://api.github.com/users/substack/orgs", 372 | "repos_url": "https://api.github.com/users/substack/repos", 373 | "events_url": "https://api.github.com/users/substack/events{/privacy}", 374 | "received_events_url": "https://api.github.com/users/substack/received_events", 375 | "type": "User", 376 | "site_admin": false, 377 | "txs": [ 378 | { 379 | "result": 1799999, 380 | "block_height": 279567, 381 | "time": 1389302061, 382 | "inputs": [ 383 | { 384 | "prev_out": { 385 | "n": 0, 386 | "value": 10000000, 387 | "addr": "196A7czbZum2nKNNwhHDeFcaGdacxPwfPB", 388 | "tx_index": 60451263, 389 | "type": 0 390 | } 391 | } 392 | ], 393 | "vout_sz": 2, 394 | "relayed_by": "127.0.0.1", 395 | "hash": "f064ade31e374a57ebd03d9435f30ca8c8809b068974317394f433d153828112", 396 | "vin_sz": 1, 397 | "tx_index": 106890544, 398 | "ver": 1, 399 | "out": [ 400 | { 401 | "n": 0, 402 | "value": 6000000, 403 | "addr": "1PTAwipYpP63uNrcxfm5FewxRdZyar6ceu", 404 | "tx_index": 106890544, 405 | "type": 0 406 | }, 407 | { 408 | "n": 1, 409 | "value": 4000000, 410 | "addr": "196A7czbZum2nKNNwhHDeFcaGdacxPwfPB", 411 | "tx_index": 106890544, 412 | "type": 0 413 | } 414 | ], 415 | "size": 258 416 | } 417 | ], 418 | "sum": 6000000 419 | }, 420 | { 421 | "login": "julianduque", 422 | "id": 733877, 423 | "avatar_url": "https://gravatar.com/avatar/c2d1139b787a469e13229070d6be918c?d=https%3A%2F%2Fidenticons.github.com%2Fcd761eb60d020963e0e23ec1e48949cb.png&r=x", 424 | "gravatar_id": "c2d1139b787a469e13229070d6be918c", 425 | "url": "https://api.github.com/users/julianduque", 426 | "html_url": "https://github.com/julianduque", 427 | "followers_url": "https://api.github.com/users/julianduque/followers", 428 | "following_url": "https://api.github.com/users/julianduque/following{/other_user}", 429 | "gists_url": "https://api.github.com/users/julianduque/gists{/gist_id}", 430 | "starred_url": "https://api.github.com/users/julianduque/starred{/owner}{/repo}", 431 | "subscriptions_url": "https://api.github.com/users/julianduque/subscriptions", 432 | "organizations_url": "https://api.github.com/users/julianduque/orgs", 433 | "repos_url": "https://api.github.com/users/julianduque/repos", 434 | "events_url": "https://api.github.com/users/julianduque/events{/privacy}", 435 | "received_events_url": "https://api.github.com/users/julianduque/received_events", 436 | "type": "User", 437 | "site_admin": false, 438 | "txs": [ 439 | { 440 | "result": 1000000, 441 | "block_height": 279941, 442 | "time": 1389464047, 443 | "inputs": [ 444 | { 445 | "prev_out": { 446 | "n": 1, 447 | "value": 3410000, 448 | "addr": "1DHnRVa3JYGpwNaofVQa8NuPXnCuvNHEq1", 449 | "tx_index": 91743626, 450 | "type": 0 451 | } 452 | } 453 | ], 454 | "vout_sz": 1, 455 | "relayed_by": "46.195.57.63", 456 | "hash": "eca34ac3d130d1fe29668c4bb9d10d7d08d1b22f62cae9488105303e1494d06e", 457 | "vin_sz": 1, 458 | "tx_index": 107189711, 459 | "ver": 1, 460 | "out": [ 461 | { 462 | "n": 0, 463 | "value": 3410000, 464 | "addr": "1PTAwipYpP63uNrcxfm5FewxRdZyar6ceu", 465 | "tx_index": 107189711, 466 | "type": 0 467 | } 468 | ], 469 | "size": 193 470 | } 471 | ], 472 | "sum": 3410000 473 | }, 474 | { 475 | "login": "gotcha", 476 | "id": 105204, 477 | "avatar_url": "https://gravatar.com/avatar/fa370c58c6265e0e496668f4cb39e14a?d=https%3A%2F%2Fidenticons.github.com%2F0d19d8eb54cb918bd88faa73f1627c2f.png&r=x", 478 | "gravatar_id": "fa370c58c6265e0e496668f4cb39e14a", 479 | "url": "https://api.github.com/users/gotcha", 480 | "html_url": "https://github.com/gotcha", 481 | "followers_url": "https://api.github.com/users/gotcha/followers", 482 | "following_url": "https://api.github.com/users/gotcha/following{/other_user}", 483 | "gists_url": "https://api.github.com/users/gotcha/gists{/gist_id}", 484 | "starred_url": "https://api.github.com/users/gotcha/starred{/owner}{/repo}", 485 | "subscriptions_url": "https://api.github.com/users/gotcha/subscriptions", 486 | "organizations_url": "https://api.github.com/users/gotcha/orgs", 487 | "repos_url": "https://api.github.com/users/gotcha/repos", 488 | "events_url": "https://api.github.com/users/gotcha/events{/privacy}", 489 | "received_events_url": "https://api.github.com/users/gotcha/received_events", 490 | "type": "User", 491 | "site_admin": false, 492 | "txs": [ 493 | { 494 | "result": 3410000, 495 | "block_height": 279821, 496 | "time": 1389367986, 497 | "inputs": [ 498 | { 499 | "prev_out": { 500 | "n": 1, 501 | "value": 15380000, 502 | "addr": "18JDyQaLq5iopEN3zPBbmDvM7rt457YPCf", 503 | "tx_index": 106977311, 504 | "type": 0 505 | } 506 | } 507 | ], 508 | "vout_sz": 2, 509 | "relayed_by": "127.0.0.1", 510 | "hash": "5cd0556cb8522fb3485a6e1f79f3e7091d2bdacc98c8fe9c8e097752548a6a6d", 511 | "vin_sz": 1, 512 | "tx_index": 106999626, 513 | "ver": 1, 514 | "out": [ 515 | { 516 | "n": 0, 517 | "value": 2500000, 518 | "addr": "1PTAwipYpP63uNrcxfm5FewxRdZyar6ceu", 519 | "tx_index": 106999626, 520 | "type": 0 521 | }, 522 | { 523 | "n": 1, 524 | "value": 12880000, 525 | "addr": "18JDyQaLq5iopEN3zPBbmDvM7rt457YPCf", 526 | "tx_index": 106999626, 527 | "type": 0 528 | } 529 | ], 530 | "size": 259 531 | } 532 | ], 533 | "sum": 2500000 534 | }, 535 | { 536 | "login": "eugeneware", 537 | "id": 38154, 538 | "avatar_url": "https://gravatar.com/avatar/7eab3f90d1d3164608293f3d38759e4e?d=https%3A%2F%2Fidenticons.github.com%2Fe7eb6d06172005c7bd96c8672cf4dd46.png&r=x", 539 | "gravatar_id": "7eab3f90d1d3164608293f3d38759e4e", 540 | "url": "https://api.github.com/users/eugeneware", 541 | "html_url": "https://github.com/eugeneware", 542 | "followers_url": "https://api.github.com/users/eugeneware/followers", 543 | "following_url": "https://api.github.com/users/eugeneware/following{/other_user}", 544 | "gists_url": "https://api.github.com/users/eugeneware/gists{/gist_id}", 545 | "starred_url": "https://api.github.com/users/eugeneware/starred{/owner}{/repo}", 546 | "subscriptions_url": "https://api.github.com/users/eugeneware/subscriptions", 547 | "organizations_url": "https://api.github.com/users/eugeneware/orgs", 548 | "repos_url": "https://api.github.com/users/eugeneware/repos", 549 | "events_url": "https://api.github.com/users/eugeneware/events{/privacy}", 550 | "received_events_url": "https://api.github.com/users/eugeneware/received_events", 551 | "type": "User", 552 | "site_admin": false, 553 | "txs": [ 554 | { 555 | "result": 13370000, 556 | "block_height": 280076, 557 | "time": 1389523640, 558 | "inputs": [ 559 | { 560 | "prev_out": { 561 | "n": 1, 562 | "value": 2400000, 563 | "addr": "1Bh6NWU286myjXBW3ZTZ8i1Bzon8xQVTZf", 564 | "tx_index": 101326588, 565 | "type": 0 566 | } 567 | } 568 | ], 569 | "vout_sz": 2, 570 | "relayed_by": "173.52.44.134", 571 | "hash": "f11a08dcc2e336095c5118bb95124be30e379aaee4a98a532e524e475fcf563b", 572 | "vin_sz": 1, 573 | "tx_index": 107286003, 574 | "ver": 1, 575 | "out": [ 576 | { 577 | "n": 0, 578 | "value": 2055446, 579 | "addr": "1PTAwipYpP63uNrcxfm5FewxRdZyar6ceu", 580 | "tx_index": 107286003, 581 | "type": 0 582 | }, 583 | { 584 | "n": 1, 585 | "value": 334554, 586 | "addr": "1Bh6NWU286myjXBW3ZTZ8i1Bzon8xQVTZf", 587 | "tx_index": 107286003, 588 | "type": 0 589 | } 590 | ], 591 | "size": 258 592 | } 593 | ], 594 | "sum": 2055446 595 | }, 596 | { 597 | "login": "levity", 598 | "id": 193667, 599 | "avatar_url": "https://gravatar.com/avatar/51ac8ca0bfc70f0bca64c3bec0cb473c?d=https%3A%2F%2Fidenticons.github.com%2F787907eaa93e7a5f65334b9cfe537e9e.png&r=x", 600 | "gravatar_id": "51ac8ca0bfc70f0bca64c3bec0cb473c", 601 | "url": "https://api.github.com/users/levity", 602 | "html_url": "https://github.com/levity", 603 | "followers_url": "https://api.github.com/users/levity/followers", 604 | "following_url": "https://api.github.com/users/levity/following{/other_user}", 605 | "gists_url": "https://api.github.com/users/levity/gists{/gist_id}", 606 | "starred_url": "https://api.github.com/users/levity/starred{/owner}{/repo}", 607 | "subscriptions_url": "https://api.github.com/users/levity/subscriptions", 608 | "organizations_url": "https://api.github.com/users/levity/orgs", 609 | "repos_url": "https://api.github.com/users/levity/repos", 610 | "events_url": "https://api.github.com/users/levity/events{/privacy}", 611 | "received_events_url": "https://api.github.com/users/levity/received_events", 612 | "type": "User", 613 | "site_admin": false, 614 | "txs": [ 615 | { 616 | "result": 990000, 617 | "block_height": 280054, 618 | "time": 1389512479, 619 | "inputs": [ 620 | { 621 | "prev_out": { 622 | "n": 0, 623 | "value": 2000000, 624 | "addr": "14EtTGnuATHSCud19ttNfVhwAfSCxAGUhu", 625 | "tx_index": 107265859, 626 | "type": 0 627 | } 628 | }, 629 | { 630 | "prev_out": { 631 | "n": 1, 632 | "value": 878057, 633 | "addr": "1P23j92YDL9rjkzhV93mgctJjSo2KGyXUo", 634 | "tx_index": 107265507, 635 | "type": 0 636 | } 637 | } 638 | ], 639 | "vout_sz": 2, 640 | "relayed_by": "127.0.0.1", 641 | "hash": "3be0bfb93638f01007e023faf51e28a1c690c0cb0130d749d4c4dfbf6a8d339b", 642 | "vin_sz": 2, 643 | "tx_index": 107272018, 644 | "ver": 1, 645 | "out": [ 646 | { 647 | "n": 0, 648 | "value": 2000000, 649 | "addr": "1PTAwipYpP63uNrcxfm5FewxRdZyar6ceu", 650 | "tx_index": 107272018, 651 | "type": 0 652 | }, 653 | { 654 | "n": 1, 655 | "value": 858057, 656 | "addr": "1EFnsp19MtjJ4eb5tKD49sWP4xsH5RC2yo", 657 | "tx_index": 107272018, 658 | "type": 0 659 | } 660 | ], 661 | "size": 439 662 | } 663 | ], 664 | "sum": 2000000 665 | }, 666 | { 667 | "login": "bluntworks", 668 | "id": 120600, 669 | "avatar_url": "https://gravatar.com/avatar/afdea4b6698ba60737124c4279976939?d=https%3A%2F%2Fidenticons.github.com%2F4b9a75aa52791826aae5a465bc0521aa.png&r=x", 670 | "gravatar_id": "afdea4b6698ba60737124c4279976939", 671 | "url": "https://api.github.com/users/bluntworks", 672 | "html_url": "https://github.com/bluntworks", 673 | "followers_url": "https://api.github.com/users/bluntworks/followers", 674 | "following_url": "https://api.github.com/users/bluntworks/following{/other_user}", 675 | "gists_url": "https://api.github.com/users/bluntworks/gists{/gist_id}", 676 | "starred_url": "https://api.github.com/users/bluntworks/starred{/owner}{/repo}", 677 | "subscriptions_url": "https://api.github.com/users/bluntworks/subscriptions", 678 | "organizations_url": "https://api.github.com/users/bluntworks/orgs", 679 | "repos_url": "https://api.github.com/users/bluntworks/repos", 680 | "events_url": "https://api.github.com/users/bluntworks/events{/privacy}", 681 | "received_events_url": "https://api.github.com/users/bluntworks/received_events", 682 | "type": "User", 683 | "site_admin": false, 684 | "txs": [ 685 | { 686 | "result": 20000000, 687 | "block_height": 279583, 688 | "time": 1389306132, 689 | "inputs": [ 690 | { 691 | "prev_out": { 692 | "n": 1, 693 | "value": 8791000, 694 | "addr": "1KGs4wAKWXtiowE7Yhv5KXNUP9xnAtyFs7", 695 | "tx_index": 106807114, 696 | "type": 0 697 | } 698 | } 699 | ], 700 | "vout_sz": 2, 701 | "relayed_by": "127.0.0.1", 702 | "hash": "ac2afeb9400f401b67eb39f25d4b4d046d35308117f0db6dace7165c89af6c0d", 703 | "vin_sz": 1, 704 | "tx_index": 106905969, 705 | "ver": 1, 706 | "out": [ 707 | { 708 | "n": 0, 709 | "value": 1799999, 710 | "addr": "1PTAwipYpP63uNrcxfm5FewxRdZyar6ceu", 711 | "tx_index": 106905969, 712 | "type": 0 713 | }, 714 | { 715 | "n": 1, 716 | "value": 6981000, 717 | "addr": "1KGs4wAKWXtiowE7Yhv5KXNUP9xnAtyFs7", 718 | "tx_index": 106905969, 719 | "type": 0 720 | } 721 | ], 722 | "size": 257 723 | } 724 | ], 725 | "sum": 1799999 726 | }, 727 | { 728 | "login": "dominictarr", 729 | "id": 259374, 730 | "avatar_url": "https://gravatar.com/avatar/8225d7ca5e83a3f9f0bb89a61d5df72c?d=https%3A%2F%2Fidenticons.github.com%2F6b7bbeffb7d27119a32f65804f7af00a.png&r=x", 731 | "gravatar_id": "8225d7ca5e83a3f9f0bb89a61d5df72c", 732 | "url": "https://api.github.com/users/dominictarr", 733 | "html_url": "https://github.com/dominictarr", 734 | "followers_url": "https://api.github.com/users/dominictarr/followers", 735 | "following_url": "https://api.github.com/users/dominictarr/following{/other_user}", 736 | "gists_url": "https://api.github.com/users/dominictarr/gists{/gist_id}", 737 | "starred_url": "https://api.github.com/users/dominictarr/starred{/owner}{/repo}", 738 | "subscriptions_url": "https://api.github.com/users/dominictarr/subscriptions", 739 | "organizations_url": "https://api.github.com/users/dominictarr/orgs", 740 | "repos_url": "https://api.github.com/users/dominictarr/repos", 741 | "events_url": "https://api.github.com/users/dominictarr/events{/privacy}", 742 | "received_events_url": "https://api.github.com/users/dominictarr/received_events", 743 | "type": "User", 744 | "site_admin": false, 745 | "txs": [ 746 | { 747 | "result": 6000000, 748 | "block_height": 279516, 749 | "time": 1389284574, 750 | "inputs": [ 751 | { 752 | "prev_out": { 753 | "n": 0, 754 | "value": 203350935, 755 | "addr": "1HfmCZgSDadW5MoXGj44MrQitmJFye6TJ5", 756 | "tx_index": 106585251, 757 | "type": 0 758 | } 759 | } 760 | ], 761 | "vout_sz": 2, 762 | "relayed_by": "69.42.0.24", 763 | "hash": "bc0fbffd92993aa3eed60bb69e7320283100ffea36c5d26f851a8ebcb616f592", 764 | "vin_sz": 1, 765 | "tx_index": 106852165, 766 | "ver": 1, 767 | "out": [ 768 | { 769 | "n": 0, 770 | "value": 202250935, 771 | "addr": "1HXS3dwXGkC84Nx9VRUXct9GnifcwKbqvA", 772 | "tx_index": 106852165, 773 | "type": 0 774 | }, 775 | { 776 | "n": 1, 777 | "value": 1000000, 778 | "addr": "1PTAwipYpP63uNrcxfm5FewxRdZyar6ceu", 779 | "tx_index": 106852165, 780 | "type": 0 781 | } 782 | ], 783 | "size": 257 784 | } 785 | ], 786 | "sum": 1000000 787 | }, 788 | { 789 | "login": "binarykitchen", 790 | "id": 177641, 791 | "avatar_url": "https://gravatar.com/avatar/e113ffc49039a4e71fe98fe536789341?d=https%3A%2F%2Fidenticons.github.com%2Fd06323323c58f67cccd41fffa8c4f1df.png&r=x", 792 | "gravatar_id": "e113ffc49039a4e71fe98fe536789341", 793 | "url": "https://api.github.com/users/binarykitchen", 794 | "html_url": "https://github.com/binarykitchen", 795 | "followers_url": "https://api.github.com/users/binarykitchen/followers", 796 | "following_url": "https://api.github.com/users/binarykitchen/following{/other_user}", 797 | "gists_url": "https://api.github.com/users/binarykitchen/gists{/gist_id}", 798 | "starred_url": "https://api.github.com/users/binarykitchen/starred{/owner}{/repo}", 799 | "subscriptions_url": "https://api.github.com/users/binarykitchen/subscriptions", 800 | "organizations_url": "https://api.github.com/users/binarykitchen/orgs", 801 | "repos_url": "https://api.github.com/users/binarykitchen/repos", 802 | "events_url": "https://api.github.com/users/binarykitchen/events{/privacy}", 803 | "received_events_url": "https://api.github.com/users/binarykitchen/received_events", 804 | "type": "User", 805 | "site_admin": false, 806 | "txs": [ 807 | { 808 | "result": 1500000, 809 | "block_height": 279596, 810 | "time": 1389313576, 811 | "inputs": [ 812 | { 813 | "prev_out": { 814 | "n": 0, 815 | "value": 32098166, 816 | "addr": "1AyicnATbD2QB5qGWav9KqjCmtHPLumN5v", 817 | "tx_index": 81884008, 818 | "type": 0 819 | } 820 | } 821 | ], 822 | "vout_sz": 2, 823 | "relayed_by": "222.155.112.183", 824 | "hash": "b669c10b631217487437b284f811dc97c9a7f45520ef8fc2a263d268bb3c8560", 825 | "vin_sz": 1, 826 | "tx_index": 106919951, 827 | "ver": 1, 828 | "out": [ 829 | { 830 | "n": 0, 831 | "value": 31588166, 832 | "addr": "1M2rd4ofhnaV6AnG6ALoBVYtWguLz3rCaE", 833 | "tx_index": 106919951, 834 | "type": 0 835 | }, 836 | { 837 | "n": 1, 838 | "value": 500000, 839 | "addr": "1PTAwipYpP63uNrcxfm5FewxRdZyar6ceu", 840 | "tx_index": 106919951, 841 | "type": 0 842 | } 843 | ], 844 | "size": 226 845 | } 846 | ], 847 | "sum": 500000 848 | } 849 | ] 850 | -------------------------------------------------------------------------------- /test/fixtures/iteration.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://api.github.com/repos/dominictarr/feedopensource/issues/4", 3 | "labels_url": "https://api.github.com/repos/dominictarr/feedopensource/issues/4/labels{/name}", 4 | "comments_url": "https://api.github.com/repos/dominictarr/feedopensource/issues/4/comments", 5 | "events_url": "https://api.github.com/repos/dominictarr/feedopensource/issues/4/events", 6 | "html_url": "https://github.com/dominictarr/feedopensource/issues/4", 7 | "id": 24984538, 8 | "number": 4, 9 | "title": "Iteration 1.", 10 | "user": { 11 | "login": "dominictarr", 12 | "id": 259374, 13 | "avatar_url": "https://gravatar.com/avatar/8225d7ca5e83a3f9f0bb89a61d5df72c?d=https%3A%2F%2Fidenticons.github.com%2F6b7bbeffb7d27119a32f65804f7af00a.png&r=x", 14 | "gravatar_id": "8225d7ca5e83a3f9f0bb89a61d5df72c", 15 | "url": "https://api.github.com/users/dominictarr", 16 | "html_url": "https://github.com/dominictarr", 17 | "followers_url": "https://api.github.com/users/dominictarr/followers", 18 | "following_url": "https://api.github.com/users/dominictarr/following{/other_user}", 19 | "gists_url": "https://api.github.com/users/dominictarr/gists{/gist_id}", 20 | "starred_url": "https://api.github.com/users/dominictarr/starred{/owner}{/repo}", 21 | "subscriptions_url": "https://api.github.com/users/dominictarr/subscriptions", 22 | "organizations_url": "https://api.github.com/users/dominictarr/orgs", 23 | "repos_url": "https://api.github.com/users/dominictarr/repos", 24 | "events_url": "https://api.github.com/users/dominictarr/events{/privacy}", 25 | "received_events_url": "https://api.github.com/users/dominictarr/received_events", 26 | "type": "User", 27 | "site_admin": false 28 | }, 29 | "labels": [], 30 | "state": { 31 | "funded": true, 32 | "draft": false, 33 | "complete": false, 34 | "progress": 0.25 35 | }, 36 | "assignee": null, 37 | "milestone": null, 38 | "comments": 24, 39 | "created_at": "2014-01-02T20:14:17Z", 40 | "updated_at": "2014-01-15T10:28:34Z", 41 | "closed_at": null, 42 | "pull_request": { 43 | "html_url": null, 44 | "diff_url": null, 45 | "patch_url": null 46 | }, 47 | "body": "These are the features to be addressed in the first iteration,\r\nas well as the prototype of the iteration tracker.\r\n\r\nhere are links to the tasks this iteration seeks to implement:\r\n\r\n* get status of a task (open or closed) \r\n https://github.com/dominictarr/feedopensource/issues/1\r\n* generate a iteration status badge: \r\n https://github.com/dominictarr/feedopensource/issues/2\r\n* handle basic payments:\r\n dominictarr#3\r\n* use https\r\n dominictarr/feedopensource#10\r\n\r\n[![progress bar](https://feedopensource.com/badge/1PTAwipYpP63uNrcxfm5FewxRdZyar6ceu/1.2)](bitcoin:1PTAwipYpP63uNrcxfm5FewxRdZyar6ceu)\r\n\r\n(edit: added progress bar - note, this is being cached by github, because it's yet not served over https)\r\n(edit: use all the link formats that github supports)\r\n\r\nI'm gonna be conservative and give this two weeks.\r\nThis is new stuff, so problems are likely to crop up,\r\n\r\nI am only gonna ask for 1.2 btc, which very much for hiring a developer for that length of time, but the most important thing here is to validate the idea by testing whether people are actually prepared to pay, and 1.2 btc is enough to be a real test, but not too much either.\r\n\r\nOf course, you'd probably never see a kickstarter for this little, but the whole point is that this is iterative, and so there is a real way to monitor the progress and provide meaningful feedback.", 48 | "wallet": "1PTAwipYpP63uNrcxfm5FewxRdZyar6ceu", 49 | "target": "1.2", 50 | "links": [ 51 | { 52 | "url": "https://api.github.com/repos/dominictarr/feedopensource/issues/1", 53 | "closed": false 54 | }, 55 | { 56 | "url": "https://api.github.com/repos/dominictarr/feedopensource/issues/2", 57 | "closed": false 58 | }, 59 | { 60 | "url": "https://api.github.com/repos/dominictarr/feedopensource/issues/3", 61 | "closed": false 62 | }, 63 | { 64 | "url": "https://api.github.com/repos/dominictarr/feedopensource/issues/10", 65 | "closed": true 66 | } 67 | ], 68 | "total": 4, 69 | "complete": 1, 70 | "funders": [ 71 | { 72 | "login": "hansent", 73 | "id": 137617, 74 | "avatar_url": "https://gravatar.com/avatar/fb39a4c30656a954fffe6015a6e0c50e?d=https%3A%2F%2Fidenticons.github.com%2F7bc74a3dbf870e2efa020cfd0c19a91e.png&r=x", 75 | "gravatar_id": "fb39a4c30656a954fffe6015a6e0c50e", 76 | "url": "https://api.github.com/users/hansent", 77 | "html_url": "https://github.com/hansent", 78 | "followers_url": "https://api.github.com/users/hansent/followers", 79 | "following_url": "https://api.github.com/users/hansent/following{/other_user}", 80 | "gists_url": "https://api.github.com/users/hansent/gists{/gist_id}", 81 | "starred_url": "https://api.github.com/users/hansent/starred{/owner}{/repo}", 82 | "subscriptions_url": "https://api.github.com/users/hansent/subscriptions", 83 | "organizations_url": "https://api.github.com/users/hansent/orgs", 84 | "repos_url": "https://api.github.com/users/hansent/repos", 85 | "events_url": "https://api.github.com/users/hansent/events{/privacy}", 86 | "received_events_url": "https://api.github.com/users/hansent/received_events", 87 | "type": "User", 88 | "site_admin": false, 89 | "txs": [ 90 | { 91 | "result": 2000000, 92 | "block_height": 280050, 93 | "time": 1389510868, 94 | "inputs": [ 95 | { 96 | "prev_out": { 97 | "n": 2, 98 | "value": 379582, 99 | "addr": "1GfoUdxiTb7jK4LRRZJsQYFiMt4s3G2xCN", 100 | "tx_index": 107264813, 101 | "type": 0 102 | } 103 | }, 104 | { 105 | "prev_out": { 106 | "n": 0, 107 | "value": 50000000, 108 | "addr": "1EF2pabTPjUfWwhgMxwW5cgg8EPjunKbMn", 109 | "tx_index": 107269707, 110 | "type": 0 111 | } 112 | } 113 | ], 114 | "vout_sz": 2, 115 | "relayed_by": "127.0.0.1", 116 | "hash": "a92f09c0926f64479e060b24d0aa7f0af0f793ec81611f04e20e6c2a7f77c406", 117 | "vin_sz": 2, 118 | "tx_index": 107265696, 119 | "ver": 1, 120 | "out": [ 121 | { 122 | "n": 0, 123 | "value": 50000000, 124 | "addr": "1PTAwipYpP63uNrcxfm5FewxRdZyar6ceu", 125 | "tx_index": 107265696, 126 | "type": 0 127 | }, 128 | { 129 | "n": 1, 130 | "value": 359582, 131 | "addr": "1K4AW4VJEjBKvX2Fs6YbbtTfgXQyrkKTyS", 132 | "tx_index": 107265696, 133 | "type": 0 134 | } 135 | ], 136 | "size": 439 137 | } 138 | ], 139 | "sum": 50000000 140 | }, 141 | { 142 | "unclaimed": true, 143 | "txs": [ 144 | { 145 | "result": 2055446, 146 | "block_height": 280062, 147 | "time": 1389515352, 148 | "inputs": [ 149 | { 150 | "prev_out": { 151 | "n": 0, 152 | "value": 1000000, 153 | "addr": "1F6Puy4AgQJBm4nbvMRsQz12jEvugjRsG3", 154 | "tx_index": 99839859, 155 | "type": 0 156 | } 157 | } 158 | ], 159 | "vout_sz": 1, 160 | "relayed_by": "82.90.118.127", 161 | "hash": "612d6490306bcdac471839e2817e34a5d24522a7fd3ebae6db39898f0ee0ba62", 162 | "vin_sz": 1, 163 | "tx_index": 107275892, 164 | "ver": 1, 165 | "out": [ 166 | { 167 | "n": 0, 168 | "value": 990000, 169 | "addr": "1PTAwipYpP63uNrcxfm5FewxRdZyar6ceu", 170 | "tx_index": 107275892, 171 | "type": 0 172 | } 173 | ], 174 | "size": 191 175 | }, 176 | { 177 | "result": 50000000, 178 | "block_height": 280037, 179 | "time": 1389502493, 180 | "inputs": [ 181 | { 182 | "prev_out": { 183 | "n": 1, 184 | "value": 844270, 185 | "addr": "14wWWNFU9aZaBLjbcVQnQrUMqHzkDQygHT", 186 | "tx_index": 107248779, 187 | "type": 0 188 | } 189 | }, 190 | { 191 | "prev_out": { 192 | "n": 0, 193 | "value": 1000000, 194 | "addr": "14xqv7Z7tWYwQYgYi3RhAn5QZMAKAYHaoC", 195 | "tx_index": 107257973, 196 | "type": 0 197 | } 198 | } 199 | ], 200 | "vout_sz": 2, 201 | "relayed_by": "91.230.204.45", 202 | "hash": "9b4a49a76336a8737bcc81085e9629a91d4d469eb05420e96a02ac37f6e29e3e", 203 | "vin_sz": 2, 204 | "tx_index": 107258336, 205 | "ver": 1, 206 | "out": [ 207 | { 208 | "n": 0, 209 | "value": 1000000, 210 | "addr": "1PTAwipYpP63uNrcxfm5FewxRdZyar6ceu", 211 | "tx_index": 107258336, 212 | "type": 0 213 | }, 214 | { 215 | "n": 1, 216 | "value": 824270, 217 | "addr": "1NR2GZAq2XLuxfTixqW14RNCnvGzjEBcA5", 218 | "tx_index": 107258336, 219 | "type": 0 220 | } 221 | ], 222 | "size": 437 223 | }, 224 | { 225 | "result": 2500000, 226 | "block_height": 279640, 227 | "time": 1389333274, 228 | "inputs": [ 229 | { 230 | "prev_out": { 231 | "n": 0, 232 | "value": 100000000, 233 | "addr": "18QaFQTYePmxBJxvwCU1Dqp62suf1jozNW", 234 | "tx_index": 97749433, 235 | "type": 0 236 | } 237 | } 238 | ], 239 | "vout_sz": 2, 240 | "relayed_by": "184.56.88.71", 241 | "hash": "b3df16687b4414f43926e2546de3edd90a4e6812f7110c8350da8941b91ec89b", 242 | "vin_sz": 1, 243 | "tx_index": 106952853, 244 | "ver": 1, 245 | "out": [ 246 | { 247 | "n": 0, 248 | "value": 20000000, 249 | "addr": "1PTAwipYpP63uNrcxfm5FewxRdZyar6ceu", 250 | "tx_index": 106952853, 251 | "type": 0 252 | }, 253 | { 254 | "n": 1, 255 | "value": 79990000, 256 | "addr": "1KEpBnziPgEiHryq8hyTyS8yEHLaS3Knru", 257 | "tx_index": 106952853, 258 | "type": 0 259 | } 260 | ], 261 | "size": 225 262 | }, 263 | { 264 | "result": 20000000, 265 | "block_height": 279604, 266 | "time": 1389316807, 267 | "inputs": [ 268 | { 269 | "prev_out": { 270 | "addr_tag": "William Casarin (jb55)", 271 | "n": 0, 272 | "value": 66379776, 273 | "addr": "1jb55g498MEa274Z1YWUXQFxZE5NzvhV7", 274 | "tx_index": 106910379, 275 | "type": 0, 276 | "addr_tag_link": "http://jb55.com" 277 | } 278 | } 279 | ], 280 | "vout_sz": 2, 281 | "relayed_by": "127.0.0.1", 282 | "hash": "a70271dc6984b50aec36040a8745e3eaf59a7ca2533a54b94f158fbac5dcc75e", 283 | "vin_sz": 1, 284 | "tx_index": 106925020, 285 | "ver": 1, 286 | "out": [ 287 | { 288 | "n": 0, 289 | "value": 1500000, 290 | "addr": "1PTAwipYpP63uNrcxfm5FewxRdZyar6ceu", 291 | "tx_index": 106925020, 292 | "type": 0 293 | }, 294 | { 295 | "addr_tag": "William Casarin (jb55)", 296 | "n": 1, 297 | "value": 64869776, 298 | "addr": "1jb55g498MEa274Z1YWUXQFxZE5NzvhV7", 299 | "tx_index": 106925020, 300 | "type": 0, 301 | "addr_tag_link": "http://jb55.com" 302 | } 303 | ], 304 | "size": 259 305 | } 306 | ], 307 | "sum": 23490000, 308 | "login": "**unclaimed**" 309 | }, 310 | { 311 | "login": "ralphtheninja", 312 | "id": 308049, 313 | "avatar_url": "https://gravatar.com/avatar/845fa52df723d253516a80a86ffe1a29?d=https%3A%2F%2Fidenticons.github.com%2F95e7c6733a0a8c4a48236dad384dd3a0.png&r=x", 314 | "gravatar_id": "845fa52df723d253516a80a86ffe1a29", 315 | "url": "https://api.github.com/users/ralphtheninja", 316 | "html_url": "https://github.com/ralphtheninja", 317 | "followers_url": "https://api.github.com/users/ralphtheninja/followers", 318 | "following_url": "https://api.github.com/users/ralphtheninja/following{/other_user}", 319 | "gists_url": "https://api.github.com/users/ralphtheninja/gists{/gist_id}", 320 | "starred_url": "https://api.github.com/users/ralphtheninja/starred{/owner}{/repo}", 321 | "subscriptions_url": "https://api.github.com/users/ralphtheninja/subscriptions", 322 | "organizations_url": "https://api.github.com/users/ralphtheninja/orgs", 323 | "repos_url": "https://api.github.com/users/ralphtheninja/repos", 324 | "events_url": "https://api.github.com/users/ralphtheninja/events{/privacy}", 325 | "received_events_url": "https://api.github.com/users/ralphtheninja/received_events", 326 | "type": "User", 327 | "site_admin": false, 328 | "txs": [ 329 | { 330 | "result": 500000, 331 | "block_height": 279585, 332 | "time": 1389306192, 333 | "inputs": [ 334 | { 335 | "prev_out": { 336 | "n": 1, 337 | "value": 216553341, 338 | "addr": "1HYmvU61669fvRxJNue9TUyihjAFB4HFER", 339 | "tx_index": 106359331, 340 | "type": 0 341 | } 342 | } 343 | ], 344 | "vout_sz": 2, 345 | "relayed_by": "127.0.0.1", 346 | "hash": "3010b4d93dda15df8345ede9164b9adf2e25e1ecb9d978c74e2cfdd36315c735", 347 | "vin_sz": 1, 348 | "tx_index": 106905086, 349 | "ver": 1, 350 | "out": [ 351 | { 352 | "n": 0, 353 | "value": 20000000, 354 | "addr": "1PTAwipYpP63uNrcxfm5FewxRdZyar6ceu", 355 | "tx_index": 106905086, 356 | "type": 0 357 | }, 358 | { 359 | "n": 1, 360 | "value": 196553341, 361 | "addr": "1HYmvU61669fvRxJNue9TUyihjAFB4HFER", 362 | "tx_index": 106905086, 363 | "type": 0 364 | } 365 | ], 366 | "size": 259 367 | } 368 | ], 369 | "sum": 20000000 370 | }, 371 | { 372 | "login": "eins78", 373 | "id": 134942, 374 | "avatar_url": "https://gravatar.com/avatar/9bcfab393e252df79fa12b0eae4701f4?d=https%3A%2F%2Fidenticons.github.com%2F47b5a953ac68315383732de7e1fbb9e4.png&r=x", 375 | "gravatar_id": "9bcfab393e252df79fa12b0eae4701f4", 376 | "url": "https://api.github.com/users/eins78", 377 | "html_url": "https://github.com/eins78", 378 | "followers_url": "https://api.github.com/users/eins78/followers", 379 | "following_url": "https://api.github.com/users/eins78/following{/other_user}", 380 | "gists_url": "https://api.github.com/users/eins78/gists{/gist_id}", 381 | "starred_url": "https://api.github.com/users/eins78/starred{/owner}{/repo}", 382 | "subscriptions_url": "https://api.github.com/users/eins78/subscriptions", 383 | "organizations_url": "https://api.github.com/users/eins78/orgs", 384 | "repos_url": "https://api.github.com/users/eins78/repos", 385 | "events_url": "https://api.github.com/users/eins78/events{/privacy}", 386 | "received_events_url": "https://api.github.com/users/eins78/received_events", 387 | "type": "User", 388 | "site_admin": false, 389 | "txs": [ 390 | { 391 | "result": 0, 392 | "block_height": 280187, 393 | "time": 1389566474, 394 | "inputs": [ 395 | { 396 | "prev_out": { 397 | "n": 0, 398 | "value": 30000000, 399 | "addr": "14HyQdmwD5x2LGGcyHsxYPjAQXqHomCvtv", 400 | "tx_index": 105484188, 401 | "type": 0 402 | } 403 | } 404 | ], 405 | "vout_sz": 2, 406 | "relayed_by": "127.0.0.1", 407 | "hash": "96ebb5159544d6c3a3dc89f6b6886812c23e012e849f6ad92cfa6aef2f491c8d", 408 | "vin_sz": 1, 409 | "tx_index": 107357783, 410 | "ver": 1, 411 | "out": [ 412 | { 413 | "n": 0, 414 | "value": 13370000, 415 | "addr": "1PTAwipYpP63uNrcxfm5FewxRdZyar6ceu", 416 | "tx_index": 107357783, 417 | "type": 0 418 | }, 419 | { 420 | "n": 1, 421 | "value": 16629000, 422 | "addr": "17mNBpwcytHf6d2QZxakd31y9yisuszcWs", 423 | "tx_index": 107357783, 424 | "type": 0 425 | } 426 | ], 427 | "size": 258 428 | } 429 | ], 430 | "sum": 13370000 431 | }, 432 | { 433 | "login": "substack", 434 | "id": 12631, 435 | "avatar_url": "https://gravatar.com/avatar/d4a2f12ceae3b7f211b661576d22bfb9?d=https%3A%2F%2Fidenticons.github.com%2F84adf1b967670705085ec0ca0cf48e31.png&r=x", 436 | "gravatar_id": "d4a2f12ceae3b7f211b661576d22bfb9", 437 | "url": "https://api.github.com/users/substack", 438 | "html_url": "https://github.com/substack", 439 | "followers_url": "https://api.github.com/users/substack/followers", 440 | "following_url": "https://api.github.com/users/substack/following{/other_user}", 441 | "gists_url": "https://api.github.com/users/substack/gists{/gist_id}", 442 | "starred_url": "https://api.github.com/users/substack/starred{/owner}{/repo}", 443 | "subscriptions_url": "https://api.github.com/users/substack/subscriptions", 444 | "organizations_url": "https://api.github.com/users/substack/orgs", 445 | "repos_url": "https://api.github.com/users/substack/repos", 446 | "events_url": "https://api.github.com/users/substack/events{/privacy}", 447 | "received_events_url": "https://api.github.com/users/substack/received_events", 448 | "type": "User", 449 | "site_admin": false, 450 | "txs": [ 451 | { 452 | "result": 1799999, 453 | "block_height": 279567, 454 | "time": 1389302061, 455 | "inputs": [ 456 | { 457 | "prev_out": { 458 | "n": 0, 459 | "value": 10000000, 460 | "addr": "196A7czbZum2nKNNwhHDeFcaGdacxPwfPB", 461 | "tx_index": 60451263, 462 | "type": 0 463 | } 464 | } 465 | ], 466 | "vout_sz": 2, 467 | "relayed_by": "127.0.0.1", 468 | "hash": "f064ade31e374a57ebd03d9435f30ca8c8809b068974317394f433d153828112", 469 | "vin_sz": 1, 470 | "tx_index": 106890544, 471 | "ver": 1, 472 | "out": [ 473 | { 474 | "n": 0, 475 | "value": 6000000, 476 | "addr": "1PTAwipYpP63uNrcxfm5FewxRdZyar6ceu", 477 | "tx_index": 106890544, 478 | "type": 0 479 | }, 480 | { 481 | "n": 1, 482 | "value": 4000000, 483 | "addr": "196A7czbZum2nKNNwhHDeFcaGdacxPwfPB", 484 | "tx_index": 106890544, 485 | "type": 0 486 | } 487 | ], 488 | "size": 258 489 | } 490 | ], 491 | "sum": 6000000 492 | }, 493 | { 494 | "login": "julianduque", 495 | "id": 733877, 496 | "avatar_url": "https://gravatar.com/avatar/c2d1139b787a469e13229070d6be918c?d=https%3A%2F%2Fidenticons.github.com%2Fcd761eb60d020963e0e23ec1e48949cb.png&r=x", 497 | "gravatar_id": "c2d1139b787a469e13229070d6be918c", 498 | "url": "https://api.github.com/users/julianduque", 499 | "html_url": "https://github.com/julianduque", 500 | "followers_url": "https://api.github.com/users/julianduque/followers", 501 | "following_url": "https://api.github.com/users/julianduque/following{/other_user}", 502 | "gists_url": "https://api.github.com/users/julianduque/gists{/gist_id}", 503 | "starred_url": "https://api.github.com/users/julianduque/starred{/owner}{/repo}", 504 | "subscriptions_url": "https://api.github.com/users/julianduque/subscriptions", 505 | "organizations_url": "https://api.github.com/users/julianduque/orgs", 506 | "repos_url": "https://api.github.com/users/julianduque/repos", 507 | "events_url": "https://api.github.com/users/julianduque/events{/privacy}", 508 | "received_events_url": "https://api.github.com/users/julianduque/received_events", 509 | "type": "User", 510 | "site_admin": false, 511 | "txs": [ 512 | { 513 | "result": 1000000, 514 | "block_height": 279941, 515 | "time": 1389464047, 516 | "inputs": [ 517 | { 518 | "prev_out": { 519 | "n": 1, 520 | "value": 3410000, 521 | "addr": "1DHnRVa3JYGpwNaofVQa8NuPXnCuvNHEq1", 522 | "tx_index": 91743626, 523 | "type": 0 524 | } 525 | } 526 | ], 527 | "vout_sz": 1, 528 | "relayed_by": "46.195.57.63", 529 | "hash": "eca34ac3d130d1fe29668c4bb9d10d7d08d1b22f62cae9488105303e1494d06e", 530 | "vin_sz": 1, 531 | "tx_index": 107189711, 532 | "ver": 1, 533 | "out": [ 534 | { 535 | "n": 0, 536 | "value": 3410000, 537 | "addr": "1PTAwipYpP63uNrcxfm5FewxRdZyar6ceu", 538 | "tx_index": 107189711, 539 | "type": 0 540 | } 541 | ], 542 | "size": 193 543 | } 544 | ], 545 | "sum": 3410000 546 | }, 547 | { 548 | "login": "gotcha", 549 | "id": 105204, 550 | "avatar_url": "https://gravatar.com/avatar/fa370c58c6265e0e496668f4cb39e14a?d=https%3A%2F%2Fidenticons.github.com%2F0d19d8eb54cb918bd88faa73f1627c2f.png&r=x", 551 | "gravatar_id": "fa370c58c6265e0e496668f4cb39e14a", 552 | "url": "https://api.github.com/users/gotcha", 553 | "html_url": "https://github.com/gotcha", 554 | "followers_url": "https://api.github.com/users/gotcha/followers", 555 | "following_url": "https://api.github.com/users/gotcha/following{/other_user}", 556 | "gists_url": "https://api.github.com/users/gotcha/gists{/gist_id}", 557 | "starred_url": "https://api.github.com/users/gotcha/starred{/owner}{/repo}", 558 | "subscriptions_url": "https://api.github.com/users/gotcha/subscriptions", 559 | "organizations_url": "https://api.github.com/users/gotcha/orgs", 560 | "repos_url": "https://api.github.com/users/gotcha/repos", 561 | "events_url": "https://api.github.com/users/gotcha/events{/privacy}", 562 | "received_events_url": "https://api.github.com/users/gotcha/received_events", 563 | "type": "User", 564 | "site_admin": false, 565 | "txs": [ 566 | { 567 | "result": 3410000, 568 | "block_height": 279821, 569 | "time": 1389367986, 570 | "inputs": [ 571 | { 572 | "prev_out": { 573 | "n": 1, 574 | "value": 15380000, 575 | "addr": "18JDyQaLq5iopEN3zPBbmDvM7rt457YPCf", 576 | "tx_index": 106977311, 577 | "type": 0 578 | } 579 | } 580 | ], 581 | "vout_sz": 2, 582 | "relayed_by": "127.0.0.1", 583 | "hash": "5cd0556cb8522fb3485a6e1f79f3e7091d2bdacc98c8fe9c8e097752548a6a6d", 584 | "vin_sz": 1, 585 | "tx_index": 106999626, 586 | "ver": 1, 587 | "out": [ 588 | { 589 | "n": 0, 590 | "value": 2500000, 591 | "addr": "1PTAwipYpP63uNrcxfm5FewxRdZyar6ceu", 592 | "tx_index": 106999626, 593 | "type": 0 594 | }, 595 | { 596 | "n": 1, 597 | "value": 12880000, 598 | "addr": "18JDyQaLq5iopEN3zPBbmDvM7rt457YPCf", 599 | "tx_index": 106999626, 600 | "type": 0 601 | } 602 | ], 603 | "size": 259 604 | } 605 | ], 606 | "sum": 2500000 607 | }, 608 | { 609 | "login": "eugeneware", 610 | "id": 38154, 611 | "avatar_url": "https://gravatar.com/avatar/7eab3f90d1d3164608293f3d38759e4e?d=https%3A%2F%2Fidenticons.github.com%2Fe7eb6d06172005c7bd96c8672cf4dd46.png&r=x", 612 | "gravatar_id": "7eab3f90d1d3164608293f3d38759e4e", 613 | "url": "https://api.github.com/users/eugeneware", 614 | "html_url": "https://github.com/eugeneware", 615 | "followers_url": "https://api.github.com/users/eugeneware/followers", 616 | "following_url": "https://api.github.com/users/eugeneware/following{/other_user}", 617 | "gists_url": "https://api.github.com/users/eugeneware/gists{/gist_id}", 618 | "starred_url": "https://api.github.com/users/eugeneware/starred{/owner}{/repo}", 619 | "subscriptions_url": "https://api.github.com/users/eugeneware/subscriptions", 620 | "organizations_url": "https://api.github.com/users/eugeneware/orgs", 621 | "repos_url": "https://api.github.com/users/eugeneware/repos", 622 | "events_url": "https://api.github.com/users/eugeneware/events{/privacy}", 623 | "received_events_url": "https://api.github.com/users/eugeneware/received_events", 624 | "type": "User", 625 | "site_admin": false, 626 | "txs": [ 627 | { 628 | "result": 13370000, 629 | "block_height": 280076, 630 | "time": 1389523640, 631 | "inputs": [ 632 | { 633 | "prev_out": { 634 | "n": 1, 635 | "value": 2400000, 636 | "addr": "1Bh6NWU286myjXBW3ZTZ8i1Bzon8xQVTZf", 637 | "tx_index": 101326588, 638 | "type": 0 639 | } 640 | } 641 | ], 642 | "vout_sz": 2, 643 | "relayed_by": "173.52.44.134", 644 | "hash": "f11a08dcc2e336095c5118bb95124be30e379aaee4a98a532e524e475fcf563b", 645 | "vin_sz": 1, 646 | "tx_index": 107286003, 647 | "ver": 1, 648 | "out": [ 649 | { 650 | "n": 0, 651 | "value": 2055446, 652 | "addr": "1PTAwipYpP63uNrcxfm5FewxRdZyar6ceu", 653 | "tx_index": 107286003, 654 | "type": 0 655 | }, 656 | { 657 | "n": 1, 658 | "value": 334554, 659 | "addr": "1Bh6NWU286myjXBW3ZTZ8i1Bzon8xQVTZf", 660 | "tx_index": 107286003, 661 | "type": 0 662 | } 663 | ], 664 | "size": 258 665 | } 666 | ], 667 | "sum": 2055446 668 | }, 669 | { 670 | "login": "levity", 671 | "id": 193667, 672 | "avatar_url": "https://gravatar.com/avatar/51ac8ca0bfc70f0bca64c3bec0cb473c?d=https%3A%2F%2Fidenticons.github.com%2F787907eaa93e7a5f65334b9cfe537e9e.png&r=x", 673 | "gravatar_id": "51ac8ca0bfc70f0bca64c3bec0cb473c", 674 | "url": "https://api.github.com/users/levity", 675 | "html_url": "https://github.com/levity", 676 | "followers_url": "https://api.github.com/users/levity/followers", 677 | "following_url": "https://api.github.com/users/levity/following{/other_user}", 678 | "gists_url": "https://api.github.com/users/levity/gists{/gist_id}", 679 | "starred_url": "https://api.github.com/users/levity/starred{/owner}{/repo}", 680 | "subscriptions_url": "https://api.github.com/users/levity/subscriptions", 681 | "organizations_url": "https://api.github.com/users/levity/orgs", 682 | "repos_url": "https://api.github.com/users/levity/repos", 683 | "events_url": "https://api.github.com/users/levity/events{/privacy}", 684 | "received_events_url": "https://api.github.com/users/levity/received_events", 685 | "type": "User", 686 | "site_admin": false, 687 | "txs": [ 688 | { 689 | "result": 990000, 690 | "block_height": 280054, 691 | "time": 1389512479, 692 | "inputs": [ 693 | { 694 | "prev_out": { 695 | "n": 1, 696 | "value": 878057, 697 | "addr": "1P23j92YDL9rjkzhV93mgctJjSo2KGyXUo", 698 | "tx_index": 107265507, 699 | "type": 0 700 | } 701 | }, 702 | { 703 | "prev_out": { 704 | "n": 0, 705 | "value": 2000000, 706 | "addr": "14EtTGnuATHSCud19ttNfVhwAfSCxAGUhu", 707 | "tx_index": 107265859, 708 | "type": 0 709 | } 710 | } 711 | ], 712 | "vout_sz": 2, 713 | "relayed_by": "127.0.0.1", 714 | "hash": "3be0bfb93638f01007e023faf51e28a1c690c0cb0130d749d4c4dfbf6a8d339b", 715 | "vin_sz": 2, 716 | "tx_index": 107272018, 717 | "ver": 1, 718 | "out": [ 719 | { 720 | "n": 0, 721 | "value": 2000000, 722 | "addr": "1PTAwipYpP63uNrcxfm5FewxRdZyar6ceu", 723 | "tx_index": 107272018, 724 | "type": 0 725 | }, 726 | { 727 | "n": 1, 728 | "value": 858057, 729 | "addr": "1EFnsp19MtjJ4eb5tKD49sWP4xsH5RC2yo", 730 | "tx_index": 107272018, 731 | "type": 0 732 | } 733 | ], 734 | "size": 439 735 | } 736 | ], 737 | "sum": 2000000 738 | }, 739 | { 740 | "login": "bluntworks", 741 | "id": 120600, 742 | "avatar_url": "https://gravatar.com/avatar/afdea4b6698ba60737124c4279976939?d=https%3A%2F%2Fidenticons.github.com%2F4b9a75aa52791826aae5a465bc0521aa.png&r=x", 743 | "gravatar_id": "afdea4b6698ba60737124c4279976939", 744 | "url": "https://api.github.com/users/bluntworks", 745 | "html_url": "https://github.com/bluntworks", 746 | "followers_url": "https://api.github.com/users/bluntworks/followers", 747 | "following_url": "https://api.github.com/users/bluntworks/following{/other_user}", 748 | "gists_url": "https://api.github.com/users/bluntworks/gists{/gist_id}", 749 | "starred_url": "https://api.github.com/users/bluntworks/starred{/owner}{/repo}", 750 | "subscriptions_url": "https://api.github.com/users/bluntworks/subscriptions", 751 | "organizations_url": "https://api.github.com/users/bluntworks/orgs", 752 | "repos_url": "https://api.github.com/users/bluntworks/repos", 753 | "events_url": "https://api.github.com/users/bluntworks/events{/privacy}", 754 | "received_events_url": "https://api.github.com/users/bluntworks/received_events", 755 | "type": "User", 756 | "site_admin": false, 757 | "txs": [ 758 | { 759 | "result": 20000000, 760 | "block_height": 279583, 761 | "time": 1389306132, 762 | "inputs": [ 763 | { 764 | "prev_out": { 765 | "n": 1, 766 | "value": 8791000, 767 | "addr": "1KGs4wAKWXtiowE7Yhv5KXNUP9xnAtyFs7", 768 | "tx_index": 106807114, 769 | "type": 0 770 | } 771 | } 772 | ], 773 | "vout_sz": 2, 774 | "relayed_by": "127.0.0.1", 775 | "hash": "ac2afeb9400f401b67eb39f25d4b4d046d35308117f0db6dace7165c89af6c0d", 776 | "vin_sz": 1, 777 | "tx_index": 106905969, 778 | "ver": 1, 779 | "out": [ 780 | { 781 | "n": 0, 782 | "value": 1799999, 783 | "addr": "1PTAwipYpP63uNrcxfm5FewxRdZyar6ceu", 784 | "tx_index": 106905969, 785 | "type": 0 786 | }, 787 | { 788 | "n": 1, 789 | "value": 6981000, 790 | "addr": "1KGs4wAKWXtiowE7Yhv5KXNUP9xnAtyFs7", 791 | "tx_index": 106905969, 792 | "type": 0 793 | } 794 | ], 795 | "size": 257 796 | } 797 | ], 798 | "sum": 1799999 799 | }, 800 | { 801 | "login": "dominictarr", 802 | "id": 259374, 803 | "avatar_url": "https://gravatar.com/avatar/8225d7ca5e83a3f9f0bb89a61d5df72c?d=https%3A%2F%2Fidenticons.github.com%2F6b7bbeffb7d27119a32f65804f7af00a.png&r=x", 804 | "gravatar_id": "8225d7ca5e83a3f9f0bb89a61d5df72c", 805 | "url": "https://api.github.com/users/dominictarr", 806 | "html_url": "https://github.com/dominictarr", 807 | "followers_url": "https://api.github.com/users/dominictarr/followers", 808 | "following_url": "https://api.github.com/users/dominictarr/following{/other_user}", 809 | "gists_url": "https://api.github.com/users/dominictarr/gists{/gist_id}", 810 | "starred_url": "https://api.github.com/users/dominictarr/starred{/owner}{/repo}", 811 | "subscriptions_url": "https://api.github.com/users/dominictarr/subscriptions", 812 | "organizations_url": "https://api.github.com/users/dominictarr/orgs", 813 | "repos_url": "https://api.github.com/users/dominictarr/repos", 814 | "events_url": "https://api.github.com/users/dominictarr/events{/privacy}", 815 | "received_events_url": "https://api.github.com/users/dominictarr/received_events", 816 | "type": "User", 817 | "site_admin": false, 818 | "txs": [ 819 | { 820 | "result": 6000000, 821 | "block_height": 279516, 822 | "time": 1389284574, 823 | "inputs": [ 824 | { 825 | "prev_out": { 826 | "n": 0, 827 | "value": 203350935, 828 | "addr": "1HfmCZgSDadW5MoXGj44MrQitmJFye6TJ5", 829 | "tx_index": 106585251, 830 | "type": 0 831 | } 832 | } 833 | ], 834 | "vout_sz": 2, 835 | "relayed_by": "69.42.0.24", 836 | "hash": "bc0fbffd92993aa3eed60bb69e7320283100ffea36c5d26f851a8ebcb616f592", 837 | "vin_sz": 1, 838 | "tx_index": 106852165, 839 | "ver": 1, 840 | "out": [ 841 | { 842 | "n": 0, 843 | "value": 202250935, 844 | "addr": "1HXS3dwXGkC84Nx9VRUXct9GnifcwKbqvA", 845 | "tx_index": 106852165, 846 | "type": 0 847 | }, 848 | { 849 | "n": 1, 850 | "value": 1000000, 851 | "addr": "1PTAwipYpP63uNrcxfm5FewxRdZyar6ceu", 852 | "tx_index": 106852165, 853 | "type": 0 854 | } 855 | ], 856 | "size": 257 857 | } 858 | ], 859 | "sum": 1000000 860 | }, 861 | { 862 | "login": "binarykitchen", 863 | "id": 177641, 864 | "avatar_url": "https://gravatar.com/avatar/e113ffc49039a4e71fe98fe536789341?d=https%3A%2F%2Fidenticons.github.com%2Fd06323323c58f67cccd41fffa8c4f1df.png&r=x", 865 | "gravatar_id": "e113ffc49039a4e71fe98fe536789341", 866 | "url": "https://api.github.com/users/binarykitchen", 867 | "html_url": "https://github.com/binarykitchen", 868 | "followers_url": "https://api.github.com/users/binarykitchen/followers", 869 | "following_url": "https://api.github.com/users/binarykitchen/following{/other_user}", 870 | "gists_url": "https://api.github.com/users/binarykitchen/gists{/gist_id}", 871 | "starred_url": "https://api.github.com/users/binarykitchen/starred{/owner}{/repo}", 872 | "subscriptions_url": "https://api.github.com/users/binarykitchen/subscriptions", 873 | "organizations_url": "https://api.github.com/users/binarykitchen/orgs", 874 | "repos_url": "https://api.github.com/users/binarykitchen/repos", 875 | "events_url": "https://api.github.com/users/binarykitchen/events{/privacy}", 876 | "received_events_url": "https://api.github.com/users/binarykitchen/received_events", 877 | "type": "User", 878 | "site_admin": false, 879 | "txs": [ 880 | { 881 | "result": 1500000, 882 | "block_height": 279596, 883 | "time": 1389313576, 884 | "inputs": [ 885 | { 886 | "prev_out": { 887 | "n": 0, 888 | "value": 32098166, 889 | "addr": "1AyicnATbD2QB5qGWav9KqjCmtHPLumN5v", 890 | "tx_index": 81884008, 891 | "type": 0 892 | } 893 | } 894 | ], 895 | "vout_sz": 2, 896 | "relayed_by": "222.155.112.183", 897 | "hash": "b669c10b631217487437b284f811dc97c9a7f45520ef8fc2a263d268bb3c8560", 898 | "vin_sz": 1, 899 | "tx_index": 106919951, 900 | "ver": 1, 901 | "out": [ 902 | { 903 | "n": 0, 904 | "value": 31588166, 905 | "addr": "1M2rd4ofhnaV6AnG6ALoBVYtWguLz3rCaE", 906 | "tx_index": 106919951, 907 | "type": 0 908 | }, 909 | { 910 | "n": 1, 911 | "value": 500000, 912 | "addr": "1PTAwipYpP63uNrcxfm5FewxRdZyar6ceu", 913 | "tx_index": 106919951, 914 | "type": 0 915 | } 916 | ], 917 | "size": 226 918 | } 919 | ], 920 | "sum": 500000 921 | } 922 | ], 923 | "sum": 1.26125445, 924 | "progress": 0.25, 925 | "status": "progress" 926 | } 927 | -------------------------------------------------------------------------------- /test/fixtures/iteration2.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "https://api.github.com/repos/dominictarr/feedopensource/issues/20", 3 | "labels_url": "https://api.github.com/repos/dominictarr/feedopensource/issues/20/labels{/name}", 4 | "comments_url": "https://api.github.com/repos/dominictarr/feedopensource/issues/20/comments", 5 | "events_url": "https://api.github.com/repos/dominictarr/feedopensource/issues/20/events", 6 | "html_url": "https://github.com/dominictarr/feedopensource/issues/20", 7 | "id": 25522271, 8 | "number": 20, 9 | "title": "Iteration 2", 10 | "user": { 11 | "login": "dominictarr", 12 | "id": 259374, 13 | "avatar_url": "https://gravatar.com/avatar/8225d7ca5e83a3f9f0bb89a61d5df72c?d=https%3A%2F%2Fidenticons.github.com%2F6b7bbeffb7d27119a32f65804f7af00a.png&r=x", 14 | "gravatar_id": "8225d7ca5e83a3f9f0bb89a61d5df72c", 15 | "url": "https://api.github.com/users/dominictarr", 16 | "html_url": "https://github.com/dominictarr", 17 | "followers_url": "https://api.github.com/users/dominictarr/followers", 18 | "following_url": "https://api.github.com/users/dominictarr/following{/other_user}", 19 | "gists_url": "https://api.github.com/users/dominictarr/gists{/gist_id}", 20 | "starred_url": "https://api.github.com/users/dominictarr/starred{/owner}{/repo}", 21 | "subscriptions_url": "https://api.github.com/users/dominictarr/subscriptions", 22 | "organizations_url": "https://api.github.com/users/dominictarr/orgs", 23 | "repos_url": "https://api.github.com/users/dominictarr/repos", 24 | "events_url": "https://api.github.com/users/dominictarr/events{/privacy}", 25 | "received_events_url": "https://api.github.com/users/dominictarr/received_events", 26 | "type": "User", 27 | "site_admin": false 28 | }, 29 | "labels": [], 30 | "state": { 31 | "funded": false, 32 | "draft": false, 33 | "complete": false, 34 | "progress": 0.8333333333333334 35 | }, 36 | "assignee": null, 37 | "milestone": null, 38 | "comments": 28, 39 | "created_at": "2014-01-13T19:39:06Z", 40 | "updated_at": "2014-03-06T06:08:21Z", 41 | "closed_at": null, 42 | "pull_request": { 43 | "html_url": null, 44 | "diff_url": null, 45 | "patch_url": null 46 | }, 47 | "body": "Okay, I wont know what is actually going in this until users have seen the result of iteration 1.\r\nI'm only creating this to test the code that detects iteration states.\r\n\r\n\r\n[![progress bar](https://feedopensource.com/iteration/dominictarr/feedopensource/18oBEV9hFdDMEct9Ys2bSAuEY4bi2KSMHi.png?rrrrr#1.2)](https://feedopensource.com/iteration/dominictarr/feedopensource/18oBEV9hFdDMEct9Ys2bSAuEY4bi2KSMHi#1.2)\r\n\r\nto fund: `18oBEV9hFdDMEct9Ys2bSAuEY4bi2KSMHi`\r\n\r\n* https://github.com/dominictarr/feedopensource/issues/40 (spending from mobile is more convienent for hot wallets)\r\n* cache properly https://github.com/dominictarr/feedopensource/issues/46 (make the github api client code more intelligent, storing stuff locally, and requesting individual issues to confirm their state)\r\n* decouple payment confirmation, to make it easy to use alternative currencies, such as DOGE or maybe even usd (https://github.com/dominictarr/feedopensource/issues/9#issuecomment-33108381)\r\n* UI changes to badge https://github.com/dominictarr/feedopensource/issues/33\r\n* UI changes to summary page: https://github.com/dominictarr/feedopensource/issues/41\r\n* put target on badge: https://github.com/dominictarr/feedopensource/issues/48\r\n* correct progress on iteration page: https://github.com/dominictarr/feedopensource/issues/49\r\n\r\nanything else?\r\n", 48 | "owner": "dominictarr", 49 | "repo": "feedopensource", 50 | "wallet": "18oBEV9hFdDMEct9Ys2bSAuEY4bi2KSMHi", 51 | "target": "1.2", 52 | "feedopensource_url": "https://feedopensource.com/iteration/dominictarr/feedopensource/18oBEV9hFdDMEct9Ys2bSAuEY4bi2KSMHi", 53 | "badge_url": "https://feedopensource.com/iteration/dominictarr/feedopensource/18oBEV9hFdDMEct9Ys2bSAuEY4bi2KSMHi.png#1.2", 54 | "links": [ 55 | { 56 | "html_url": [ 57 | "https://github.com/dominictarr/feedopensource/issues/40", 58 | "dominictarr", 59 | "feedopensource", 60 | "40" 61 | ], 62 | "url": "https://api.github.com/repos/dominictarr/feedopensource/issues/40", 63 | "closed": false 64 | }, 65 | { 66 | "html_url": [ 67 | "https://github.com/dominictarr/feedopensource/issues/46", 68 | "dominictarr", 69 | "feedopensource", 70 | "46" 71 | ], 72 | "url": "https://api.github.com/repos/dominictarr/feedopensource/issues/46", 73 | "closed": false 74 | }, 75 | { 76 | "html_url": [ 77 | "https://github.com/dominictarr/feedopensource/issues/9", 78 | "dominictarr", 79 | "feedopensource", 80 | "9" 81 | ], 82 | "url": "https://api.github.com/repos/dominictarr/feedopensource/issues/9", 83 | "closed": false 84 | }, 85 | { 86 | "html_url": [ 87 | "https://github.com/dominictarr/feedopensource/issues/33", 88 | "dominictarr", 89 | "feedopensource", 90 | "33" 91 | ], 92 | "url": "https://api.github.com/repos/dominictarr/feedopensource/issues/33", 93 | "closed": false 94 | }, 95 | { 96 | "html_url": [ 97 | "https://github.com/dominictarr/feedopensource/issues/41", 98 | "dominictarr", 99 | "feedopensource", 100 | "41" 101 | ], 102 | "url": "https://api.github.com/repos/dominictarr/feedopensource/issues/41", 103 | "closed": false 104 | }, 105 | { 106 | "html_url": [ 107 | "https://github.com/dominictarr/feedopensource/issues/48", 108 | "dominictarr", 109 | "feedopensource", 110 | "48" 111 | ], 112 | "url": "https://api.github.com/repos/dominictarr/feedopensource/issues/48", 113 | "closed": false 114 | }, 115 | { 116 | "html_url": [ 117 | "https://github.com/dominictarr/feedopensource/issues/49", 118 | "dominictarr", 119 | "feedopensource", 120 | "49" 121 | ], 122 | "url": "https://api.github.com/repos/dominictarr/feedopensource/issues/49", 123 | "closed": false 124 | } 125 | ], 126 | "total": 7, 127 | "complete": 0, 128 | "funders": [ 129 | { 130 | "login": "Raynos", 131 | "id": 479538, 132 | "avatar_url": "https://gravatar.com/avatar/d840cb1fb7e828284011cc08f40a1015?d=https%3A%2F%2Fidenticons.github.com%2Fde418baf42bdd628b8c46fbc140098a5.png&r=x", 133 | "gravatar_id": "d840cb1fb7e828284011cc08f40a1015", 134 | "url": "https://api.github.com/users/Raynos", 135 | "html_url": "https://github.com/Raynos", 136 | "followers_url": "https://api.github.com/users/Raynos/followers", 137 | "following_url": "https://api.github.com/users/Raynos/following{/other_user}", 138 | "gists_url": "https://api.github.com/users/Raynos/gists{/gist_id}", 139 | "starred_url": "https://api.github.com/users/Raynos/starred{/owner}{/repo}", 140 | "subscriptions_url": "https://api.github.com/users/Raynos/subscriptions", 141 | "organizations_url": "https://api.github.com/users/Raynos/orgs", 142 | "repos_url": "https://api.github.com/users/Raynos/repos", 143 | "events_url": "https://api.github.com/users/Raynos/events{/privacy}", 144 | "received_events_url": "https://api.github.com/users/Raynos/received_events", 145 | "type": "User", 146 | "site_admin": false, 147 | "txs": [ 148 | { 149 | "result": 10000000, 150 | "block_height": 282853, 151 | "time": 1390893210, 152 | "inputs": [ 153 | { 154 | "prev_out": { 155 | "n": 2, 156 | "value": 3079387, 157 | "addr": "1HU1J5HKr8MmRaV3v1xESJBPNA3yVZQfJ4", 158 | "tx_index": 109940080, 159 | "type": 0 160 | } 161 | }, 162 | { 163 | "prev_out": { 164 | "n": 0, 165 | "value": 20000000, 166 | "addr": "19N8qHRMcK2Yc4bvMjx12J2Pzo6wDoKtpj", 167 | "tx_index": 109948257, 168 | "type": 0 169 | } 170 | } 171 | ], 172 | "vout_sz": 2, 173 | "relayed_by": "127.0.0.1", 174 | "hash": "7e334ddcd649482e1f1672e09aaf2ec4f1ffe01e4c03642f86a7f4ef3ae5dc55", 175 | "vin_sz": 2, 176 | "tx_index": 109948263, 177 | "ver": 1, 178 | "out": [ 179 | { 180 | "n": 0, 181 | "value": 20000000, 182 | "addr": "18oBEV9hFdDMEct9Ys2bSAuEY4bi2KSMHi", 183 | "tx_index": 109948263, 184 | "type": 0 185 | }, 186 | { 187 | "n": 1, 188 | "value": 3059387, 189 | "addr": "1A228dUxBU5JCkLm3Qnyswa8VSAJJRPmot", 190 | "tx_index": 109948263, 191 | "type": 0 192 | } 193 | ], 194 | "size": 438 195 | } 196 | ], 197 | "sum": 20000000 198 | }, 199 | { 200 | "login": "jhs", 201 | "id": 17575, 202 | "avatar_url": "https://gravatar.com/avatar/dc5c27144fe63c00375ee47da00c5621?d=https%3A%2F%2Fidenticons.github.com%2Fec160682cb3586d851071e80ec63d6c0.png&r=x", 203 | "gravatar_id": "dc5c27144fe63c00375ee47da00c5621", 204 | "url": "https://api.github.com/users/jhs", 205 | "html_url": "https://github.com/jhs", 206 | "followers_url": "https://api.github.com/users/jhs/followers", 207 | "following_url": "https://api.github.com/users/jhs/following{/other_user}", 208 | "gists_url": "https://api.github.com/users/jhs/gists{/gist_id}", 209 | "starred_url": "https://api.github.com/users/jhs/starred{/owner}{/repo}", 210 | "subscriptions_url": "https://api.github.com/users/jhs/subscriptions", 211 | "organizations_url": "https://api.github.com/users/jhs/orgs", 212 | "repos_url": "https://api.github.com/users/jhs/repos", 213 | "events_url": "https://api.github.com/users/jhs/events{/privacy}", 214 | "received_events_url": "https://api.github.com/users/jhs/received_events", 215 | "type": "User", 216 | "site_admin": false, 217 | "txs": [ 218 | { 219 | "result": 20000000, 220 | "block_height": 282828, 221 | "time": 1390873940, 222 | "inputs": [ 223 | { 224 | "prev_out": { 225 | "n": 0, 226 | "value": 50000000, 227 | "addr": "129AKYeogMfnjQYG3eL3JgWnsaV2VSVzj4", 228 | "tx_index": 108522569, 229 | "type": 0 230 | } 231 | } 232 | ], 233 | "vout_sz": 2, 234 | "relayed_by": "127.0.0.1", 235 | "hash": "a344749d6aff42703e943d6fdeef7b9e622c9b7552747b7713db242da5965edd", 236 | "vin_sz": 1, 237 | "tx_index": 109891505, 238 | "ver": 1, 239 | "out": [ 240 | { 241 | "n": 0, 242 | "value": 20000000, 243 | "addr": "18oBEV9hFdDMEct9Ys2bSAuEY4bi2KSMHi", 244 | "tx_index": 109891505, 245 | "type": 0 246 | }, 247 | { 248 | "n": 1, 249 | "value": 30000000, 250 | "addr": "129AKYeogMfnjQYG3eL3JgWnsaV2VSVzj4", 251 | "tx_index": 109891505, 252 | "type": 0 253 | } 254 | ], 255 | "size": 257 256 | } 257 | ], 258 | "sum": 20000000 259 | }, 260 | { 261 | "unclaimed": true, 262 | "txs": [ 263 | { 264 | "result": 12346789, 265 | "block_height": 283842, 266 | "time": 1391384848, 267 | "inputs": [ 268 | { 269 | "prev_out": { 270 | "n": 0, 271 | "value": 41640000, 272 | "addr": "196A7czbZum2nKNNwhHDeFcaGdacxPwfPB", 273 | "tx_index": 68161951, 274 | "type": 0 275 | } 276 | } 277 | ], 278 | "vout_sz": 2, 279 | "relayed_by": "127.0.0.1", 280 | "hash": "bda7ebd93513bfe69678170331f0926154f4eae459c597093602dfc2bd0e3f12", 281 | "vin_sz": 1, 282 | "tx_index": 111097505, 283 | "ver": 1, 284 | "out": [ 285 | { 286 | "n": 0, 287 | "value": 10000000, 288 | "addr": "18oBEV9hFdDMEct9Ys2bSAuEY4bi2KSMHi", 289 | "tx_index": 111097505, 290 | "type": 0 291 | }, 292 | { 293 | "n": 1, 294 | "value": 31640000, 295 | "addr": "196A7czbZum2nKNNwhHDeFcaGdacxPwfPB", 296 | "tx_index": 111097505, 297 | "type": 0 298 | } 299 | ], 300 | "size": 257 301 | }, 302 | { 303 | "result": 10000000, 304 | "block_height": 283813, 305 | "time": 1391372802, 306 | "inputs": [ 307 | { 308 | "prev_out": { 309 | "n": 1, 310 | "value": 79990000, 311 | "addr": "1KEpBnziPgEiHryq8hyTyS8yEHLaS3Knru", 312 | "tx_index": 106952853, 313 | "type": 0 314 | } 315 | } 316 | ], 317 | "vout_sz": 2, 318 | "relayed_by": "213.112.67.210", 319 | "hash": "c0c300a15049e3d3eb23db9f2ad9ab8343f4d217f52e0a26b7a39780db794330", 320 | "vin_sz": 1, 321 | "tx_index": 111066863, 322 | "ver": 1, 323 | "out": [ 324 | { 325 | "n": 0, 326 | "value": 10000000, 327 | "addr": "18oBEV9hFdDMEct9Ys2bSAuEY4bi2KSMHi", 328 | "tx_index": 111066863, 329 | "type": 0 330 | }, 331 | { 332 | "n": 1, 333 | "value": 69980000, 334 | "addr": "1KEpBnziPgEiHryq8hyTyS8yEHLaS3Knru", 335 | "tx_index": 111066863, 336 | "type": 0 337 | } 338 | ], 339 | "size": 227 340 | } 341 | ], 342 | "sum": 20000000, 343 | "login": "**unclaimed**" 344 | }, 345 | { 346 | "login": "joates", 347 | "id": 490654, 348 | "avatar_url": "https://gravatar.com/avatar/60091579cd14b6052b33aa0072be84f9?d=https%3A%2F%2Fidenticons.github.com%2Fd52b7567532cac2a2e1c487986bfe76b.png&r=x", 349 | "gravatar_id": "60091579cd14b6052b33aa0072be84f9", 350 | "url": "https://api.github.com/users/joates", 351 | "html_url": "https://github.com/joates", 352 | "followers_url": "https://api.github.com/users/joates/followers", 353 | "following_url": "https://api.github.com/users/joates/following{/other_user}", 354 | "gists_url": "https://api.github.com/users/joates/gists{/gist_id}", 355 | "starred_url": "https://api.github.com/users/joates/starred{/owner}{/repo}", 356 | "subscriptions_url": "https://api.github.com/users/joates/subscriptions", 357 | "organizations_url": "https://api.github.com/users/joates/orgs", 358 | "repos_url": "https://api.github.com/users/joates/repos", 359 | "events_url": "https://api.github.com/users/joates/events{/privacy}", 360 | "received_events_url": "https://api.github.com/users/joates/received_events", 361 | "type": "User", 362 | "site_admin": false, 363 | "txs": [ 364 | { 365 | "result": 13370, 366 | "block_height": 284052, 367 | "time": 1391485022, 368 | "inputs": [ 369 | { 370 | "prev_out": { 371 | "n": 0, 372 | "value": 32000000, 373 | "addr": "1FLY928LZbGpsGP1mYR6irVjgqYdbH9vDm", 374 | "tx_index": 111275397, 375 | "type": 0 376 | } 377 | } 378 | ], 379 | "vout_sz": 2, 380 | "relayed_by": "162.209.4.125", 381 | "hash": "532ae78faea5db6e1aa9853493618db601e1bb01aa3e4c37751448d114ebeeb2", 382 | "vin_sz": 1, 383 | "tx_index": 111341833, 384 | "ver": 1, 385 | "out": [ 386 | { 387 | "n": 0, 388 | "value": 12346789, 389 | "addr": "18oBEV9hFdDMEct9Ys2bSAuEY4bi2KSMHi", 390 | "tx_index": 111341833, 391 | "type": 0 392 | }, 393 | { 394 | "n": 1, 395 | "value": 19643211, 396 | "addr": "1Cxb7kZg4RvABFxVeuXh1F9KxsC4N1FWd6", 397 | "tx_index": 111341833, 398 | "type": 0 399 | } 400 | ], 401 | "size": 258 402 | }, 403 | { 404 | "result": 4000000, 405 | "block_height": 284120, 406 | "time": 1391519049, 407 | "inputs": [ 408 | { 409 | "prev_out": { 410 | "n": 1, 411 | "value": 19643211, 412 | "addr": "1Cxb7kZg4RvABFxVeuXh1F9KxsC4N1FWd6", 413 | "tx_index": 111341833, 414 | "type": 0 415 | } 416 | } 417 | ], 418 | "vout_sz": 2, 419 | "relayed_by": "86.148.50.235", 420 | "hash": "bd408bf50da0c1f62715579e71450a5116c4ad02d150c722a0b60778cec84565", 421 | "vin_sz": 1, 422 | "tx_index": 111415845, 423 | "ver": 1, 424 | "out": [ 425 | { 426 | "n": 0, 427 | "value": 13370, 428 | "addr": "18oBEV9hFdDMEct9Ys2bSAuEY4bi2KSMHi", 429 | "tx_index": 111415845, 430 | "type": 0 431 | }, 432 | { 433 | "n": 1, 434 | "value": 19619841, 435 | "addr": "1KLrbAkbpwum3TnnXicJUhd5BuahMEA3Qi", 436 | "tx_index": 111415845, 437 | "type": 0 438 | } 439 | ], 440 | "size": 225 441 | } 442 | ], 443 | "sum": 12360159 444 | }, 445 | { 446 | "login": "ralphtheninja", 447 | "id": 308049, 448 | "avatar_url": "https://gravatar.com/avatar/845fa52df723d253516a80a86ffe1a29?d=https%3A%2F%2Fidenticons.github.com%2F95e7c6733a0a8c4a48236dad384dd3a0.png&r=x", 449 | "gravatar_id": "845fa52df723d253516a80a86ffe1a29", 450 | "url": "https://api.github.com/users/ralphtheninja", 451 | "html_url": "https://github.com/ralphtheninja", 452 | "followers_url": "https://api.github.com/users/ralphtheninja/followers", 453 | "following_url": "https://api.github.com/users/ralphtheninja/following{/other_user}", 454 | "gists_url": "https://api.github.com/users/ralphtheninja/gists{/gist_id}", 455 | "starred_url": "https://api.github.com/users/ralphtheninja/starred{/owner}{/repo}", 456 | "subscriptions_url": "https://api.github.com/users/ralphtheninja/subscriptions", 457 | "organizations_url": "https://api.github.com/users/ralphtheninja/orgs", 458 | "repos_url": "https://api.github.com/users/ralphtheninja/repos", 459 | "events_url": "https://api.github.com/users/ralphtheninja/events{/privacy}", 460 | "received_events_url": "https://api.github.com/users/ralphtheninja/received_events", 461 | "type": "User", 462 | "site_admin": false, 463 | "txs": [ 464 | { 465 | "result": 10000000, 466 | "block_height": 282926, 467 | "time": 1390936613, 468 | "inputs": [ 469 | { 470 | "prev_out": { 471 | "n": 1, 472 | "value": 22465341, 473 | "addr": "1HYmvU61669fvRxJNue9TUyihjAFB4HFER", 474 | "tx_index": 109713833, 475 | "type": 0 476 | } 477 | } 478 | ], 479 | "vout_sz": 2, 480 | "relayed_by": "127.0.0.1", 481 | "hash": "d46aedaf368f81e50137ff8771a5b49e9e2085cec0637f09b8027dc990224204", 482 | "vin_sz": 1, 483 | "tx_index": 110064637, 484 | "ver": 1, 485 | "out": [ 486 | { 487 | "n": 0, 488 | "value": 10000000, 489 | "addr": "18oBEV9hFdDMEct9Ys2bSAuEY4bi2KSMHi", 490 | "tx_index": 110064637, 491 | "type": 0 492 | }, 493 | { 494 | "n": 1, 495 | "value": 12455341, 496 | "addr": "1HYmvU61669fvRxJNue9TUyihjAFB4HFER", 497 | "tx_index": 110064637, 498 | "type": 0 499 | } 500 | ], 501 | "size": 259 502 | } 503 | ], 504 | "sum": 10000000 505 | }, 506 | { 507 | "login": "RobbieClarken", 508 | "id": 663161, 509 | "avatar_url": "https://gravatar.com/avatar/a8e465c905f5ad94866395bec5587d9a?d=https%3A%2F%2Fidenticons.github.com%2Fe7a033c2bd6b0a21211f9ff22a016f10.png&r=x", 510 | "gravatar_id": "a8e465c905f5ad94866395bec5587d9a", 511 | "url": "https://api.github.com/users/RobbieClarken", 512 | "html_url": "https://github.com/RobbieClarken", 513 | "followers_url": "https://api.github.com/users/RobbieClarken/followers", 514 | "following_url": "https://api.github.com/users/RobbieClarken/following{/other_user}", 515 | "gists_url": "https://api.github.com/users/RobbieClarken/gists{/gist_id}", 516 | "starred_url": "https://api.github.com/users/RobbieClarken/starred{/owner}{/repo}", 517 | "subscriptions_url": "https://api.github.com/users/RobbieClarken/subscriptions", 518 | "organizations_url": "https://api.github.com/users/RobbieClarken/orgs", 519 | "repos_url": "https://api.github.com/users/RobbieClarken/repos", 520 | "events_url": "https://api.github.com/users/RobbieClarken/events{/privacy}", 521 | "received_events_url": "https://api.github.com/users/RobbieClarken/received_events", 522 | "type": "User", 523 | "site_admin": false, 524 | "txs": [ 525 | { 526 | "result": 10000000, 527 | "block_height": 283177, 528 | "time": 1391074526, 529 | "inputs": [ 530 | { 531 | "prev_out": { 532 | "n": 1, 533 | "value": 18348640, 534 | "addr": "1C9HFrDCzskANC8ym3XqwFdio9zBSernMP", 535 | "tx_index": 110389339, 536 | "type": 0 537 | } 538 | } 539 | ], 540 | "vout_sz": 2, 541 | "relayed_by": "5.199.133.193", 542 | "hash": "1a0fe73e0ac38d96f9f146fcc843abefced06a3cad29ebf12be89a4a54993645", 543 | "vin_sz": 1, 544 | "tx_index": 110399209, 545 | "ver": 1, 546 | "out": [ 547 | { 548 | "n": 0, 549 | "value": 8338640, 550 | "addr": "1GitnUKU2PVJHSDxsYLGodp7VxD5nztMhP", 551 | "tx_index": 110399209, 552 | "type": 0 553 | }, 554 | { 555 | "n": 1, 556 | "value": 10000000, 557 | "addr": "18oBEV9hFdDMEct9Ys2bSAuEY4bi2KSMHi", 558 | "tx_index": 110399209, 559 | "type": 0 560 | } 561 | ], 562 | "size": 226 563 | } 564 | ], 565 | "sum": 10000000 566 | }, 567 | { 568 | "login": "binarykitchen", 569 | "id": 177641, 570 | "avatar_url": "https://gravatar.com/avatar/e113ffc49039a4e71fe98fe536789341?d=https%3A%2F%2Fidenticons.github.com%2Fd06323323c58f67cccd41fffa8c4f1df.png&r=x", 571 | "gravatar_id": "e113ffc49039a4e71fe98fe536789341", 572 | "url": "https://api.github.com/users/binarykitchen", 573 | "html_url": "https://github.com/binarykitchen", 574 | "followers_url": "https://api.github.com/users/binarykitchen/followers", 575 | "following_url": "https://api.github.com/users/binarykitchen/following{/other_user}", 576 | "gists_url": "https://api.github.com/users/binarykitchen/gists{/gist_id}", 577 | "starred_url": "https://api.github.com/users/binarykitchen/starred{/owner}{/repo}", 578 | "subscriptions_url": "https://api.github.com/users/binarykitchen/subscriptions", 579 | "organizations_url": "https://api.github.com/users/binarykitchen/orgs", 580 | "repos_url": "https://api.github.com/users/binarykitchen/repos", 581 | "events_url": "https://api.github.com/users/binarykitchen/events{/privacy}", 582 | "received_events_url": "https://api.github.com/users/binarykitchen/received_events", 583 | "type": "User", 584 | "site_admin": false, 585 | "txs": [ 586 | { 587 | "result": 3639841, 588 | "block_height": 284198, 589 | "time": 1391559317, 590 | "inputs": [ 591 | { 592 | "prev_out": { 593 | "n": 0, 594 | "value": 31588166, 595 | "addr": "1M2rd4ofhnaV6AnG6ALoBVYtWguLz3rCaE", 596 | "tx_index": 106919951, 597 | "type": 0 598 | } 599 | } 600 | ], 601 | "vout_sz": 2, 602 | "relayed_by": "176.198.82.229", 603 | "hash": "e19608d824601343af871a254fd9ce33ff8a07a2d1f1322bdff4c2230330e69e", 604 | "vin_sz": 1, 605 | "tx_index": 111541540, 606 | "ver": 1, 607 | "out": [ 608 | { 609 | "n": 0, 610 | "value": 27588166, 611 | "addr": "18QH7SNR91fDFJXhR2GX1yQZNAof8hkC9q", 612 | "tx_index": 111541540, 613 | "type": 0 614 | }, 615 | { 616 | "n": 1, 617 | "value": 4000000, 618 | "addr": "18oBEV9hFdDMEct9Ys2bSAuEY4bi2KSMHi", 619 | "tx_index": 111541540, 620 | "type": 0 621 | } 622 | ], 623 | "size": 226 624 | } 625 | ], 626 | "sum": 4000000 627 | }, 628 | { 629 | "login": "clehner", 630 | "id": 95347, 631 | "avatar_url": "https://gravatar.com/avatar/02970f9bc81a4c8c3956912bf1eaa0e0?d=https%3A%2F%2Fidenticons.github.com%2F3d42353538c86da8d87fc105e973ed14.png&r=x", 632 | "gravatar_id": "02970f9bc81a4c8c3956912bf1eaa0e0", 633 | "url": "https://api.github.com/users/clehner", 634 | "html_url": "https://github.com/clehner", 635 | "followers_url": "https://api.github.com/users/clehner/followers", 636 | "following_url": "https://api.github.com/users/clehner/following{/other_user}", 637 | "gists_url": "https://api.github.com/users/clehner/gists{/gist_id}", 638 | "starred_url": "https://api.github.com/users/clehner/starred{/owner}{/repo}", 639 | "subscriptions_url": "https://api.github.com/users/clehner/subscriptions", 640 | "organizations_url": "https://api.github.com/users/clehner/orgs", 641 | "repos_url": "https://api.github.com/users/clehner/repos", 642 | "events_url": "https://api.github.com/users/clehner/events{/privacy}", 643 | "received_events_url": "https://api.github.com/users/clehner/received_events", 644 | "type": "User", 645 | "site_admin": false, 646 | "txs": [ 647 | { 648 | "result": 0, 649 | "block_height": 284212, 650 | "time": 1391564790, 651 | "inputs": [ 652 | { 653 | "prev_out": { 654 | "n": 0, 655 | "value": 870000, 656 | "addr": "1MFLR4Ksfq4fR3w5FyWqkMvpAspUsgyoja", 657 | "tx_index": 101446311, 658 | "type": 0 659 | } 660 | }, 661 | { 662 | "prev_out": { 663 | "n": 0, 664 | "value": 350184514, 665 | "addr": "1ApxwdHFFPuM3wUrrJkBqyCUy59yuaiC3n", 666 | "tx_index": 102208529, 667 | "type": 0 668 | } 669 | } 670 | ], 671 | "vout_sz": 2, 672 | "relayed_by": "128.71.99.158", 673 | "hash": "8d5ee79f2aae765a2477d252164ccc07389533abb16c236127f1d3ebf5ae2ba8", 674 | "vin_sz": 2, 675 | "tx_index": 111554936, 676 | "ver": 1, 677 | "out": [ 678 | { 679 | "n": 0, 680 | "value": 347394673, 681 | "addr": "121j56d6iDeyhJFTP3yMNdi5k4nHoxdQVv", 682 | "tx_index": 111554936, 683 | "type": 0 684 | }, 685 | { 686 | "n": 1, 687 | "value": 3639841, 688 | "addr": "18oBEV9hFdDMEct9Ys2bSAuEY4bi2KSMHi", 689 | "tx_index": 111554936, 690 | "type": 0 691 | } 692 | ], 693 | "size": 437 694 | } 695 | ], 696 | "sum": 3639841 697 | } 698 | ], 699 | "sum": 1, 700 | "progress": 0.8333333333333334, 701 | "status": "funding" 702 | } 703 | -------------------------------------------------------------------------------- /test/fixtures/iterations.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "url": "https://api.github.com/repos/dominictarr/feedopensource/issues/20", 4 | "labels_url": "https://api.github.com/repos/dominictarr/feedopensource/issues/20/labels{/name}", 5 | "comments_url": "https://api.github.com/repos/dominictarr/feedopensource/issues/20/comments", 6 | "events_url": "https://api.github.com/repos/dominictarr/feedopensource/issues/20/events", 7 | "html_url": "https://github.com/dominictarr/feedopensource/issues/20", 8 | "id": 25522271, 9 | "number": 20, 10 | "title": "Iteration 2", 11 | "user": { 12 | "login": "dominictarr", 13 | "id": 259374, 14 | "avatar_url": "https://gravatar.com/avatar/8225d7ca5e83a3f9f0bb89a61d5df72c?d=https%3A%2F%2Fidenticons.github.com%2F6b7bbeffb7d27119a32f65804f7af00a.png&r=x", 15 | "gravatar_id": "8225d7ca5e83a3f9f0bb89a61d5df72c", 16 | "url": "https://api.github.com/users/dominictarr", 17 | "html_url": "https://github.com/dominictarr", 18 | "followers_url": "https://api.github.com/users/dominictarr/followers", 19 | "following_url": "https://api.github.com/users/dominictarr/following{/other_user}", 20 | "gists_url": "https://api.github.com/users/dominictarr/gists{/gist_id}", 21 | "starred_url": "https://api.github.com/users/dominictarr/starred{/owner}{/repo}", 22 | "subscriptions_url": "https://api.github.com/users/dominictarr/subscriptions", 23 | "organizations_url": "https://api.github.com/users/dominictarr/orgs", 24 | "repos_url": "https://api.github.com/users/dominictarr/repos", 25 | "events_url": "https://api.github.com/users/dominictarr/events{/privacy}", 26 | "received_events_url": "https://api.github.com/users/dominictarr/received_events", 27 | "type": "User", 28 | "site_admin": false 29 | }, 30 | "labels": [], 31 | "state": "open", 32 | "assignee": null, 33 | "milestone": null, 34 | "comments": 0, 35 | "created_at": "2014-01-13T19:39:06Z", 36 | "updated_at": "2014-01-14T11:13:02Z", 37 | "closed_at": null, 38 | "pull_request": { 39 | "html_url": null, 40 | "diff_url": null, 41 | "patch_url": null 42 | }, 43 | "body": "Okay, I wont know what is actually going in this until users have seen the result of iteration 1.\r\nI'm only creating this to test the code that detects iteration states.\r\n\r\n\r\n[![progress bar](https://feedopensource.com/badge/18oBEV9hFdDMEct9Ys2bSAuEY4bi2KSMHi/1.2)](bitcoin:18oBEV9hFdDMEct9Ys2bSAuEY4bi2KSMHi)\r\n", 44 | "wallet": "18oBEV9hFdDMEct9Ys2bSAuEY4bi2KSMHi", 45 | "target": "1.2", 46 | "links": [], 47 | "total": 0, 48 | "complete": 0 49 | }, 50 | { 51 | "url": "https://api.github.com/repos/dominictarr/feedopensource/issues/4", 52 | "labels_url": "https://api.github.com/repos/dominictarr/feedopensource/issues/4/labels{/name}", 53 | "comments_url": "https://api.github.com/repos/dominictarr/feedopensource/issues/4/comments", 54 | "events_url": "https://api.github.com/repos/dominictarr/feedopensource/issues/4/events", 55 | "html_url": "https://github.com/dominictarr/feedopensource/issues/4", 56 | "id": 24984538, 57 | "number": 4, 58 | "title": "Iteration 1.", 59 | "user": { 60 | "login": "dominictarr", 61 | "id": 259374, 62 | "avatar_url": "https://gravatar.com/avatar/8225d7ca5e83a3f9f0bb89a61d5df72c?d=https%3A%2F%2Fidenticons.github.com%2F6b7bbeffb7d27119a32f65804f7af00a.png&r=x", 63 | "gravatar_id": "8225d7ca5e83a3f9f0bb89a61d5df72c", 64 | "url": "https://api.github.com/users/dominictarr", 65 | "html_url": "https://github.com/dominictarr", 66 | "followers_url": "https://api.github.com/users/dominictarr/followers", 67 | "following_url": "https://api.github.com/users/dominictarr/following{/other_user}", 68 | "gists_url": "https://api.github.com/users/dominictarr/gists{/gist_id}", 69 | "starred_url": "https://api.github.com/users/dominictarr/starred{/owner}{/repo}", 70 | "subscriptions_url": "https://api.github.com/users/dominictarr/subscriptions", 71 | "organizations_url": "https://api.github.com/users/dominictarr/orgs", 72 | "repos_url": "https://api.github.com/users/dominictarr/repos", 73 | "events_url": "https://api.github.com/users/dominictarr/events{/privacy}", 74 | "received_events_url": "https://api.github.com/users/dominictarr/received_events", 75 | "type": "User", 76 | "site_admin": false 77 | }, 78 | "labels": [], 79 | "state": "open", 80 | "assignee": null, 81 | "milestone": null, 82 | "comments": 23, 83 | "created_at": "2014-01-02T20:14:17Z", 84 | "updated_at": "2014-01-14T11:10:34Z", 85 | "closed_at": null, 86 | "pull_request": { 87 | "html_url": null, 88 | "diff_url": null, 89 | "patch_url": null 90 | }, 91 | "body": "These are the features to be addressed in the first iteration,\r\nas well as the prototype of the iteration tracker.\r\n\r\nhere are links to the tasks this iteration seeks to implement:\r\n\r\n* get status of a task (open or closed) \r\n https://github.com/dominictarr/feedopensource/issues/1\r\n* generate a iteration status badge: \r\n https://github.com/dominictarr/feedopensource/issues/2\r\n* handle basic payments:\r\n dominictarr#3\r\n* use https\r\n dominictarr/feedopensource#10\r\n\r\n[![progress bar](https://feedopensource.com/badge/1PTAwipYpP63uNrcxfm5FewxRdZyar6ceu/1.2)](bitcoin:1PTAwipYpP63uNrcxfm5FewxRdZyar6ceu)\r\n\r\n(edit: added progress bar - note, this is being cached by github, because it's yet not served over https)\r\n(edit: use all the link formats that github supports)\r\n\r\nI'm gonna be conservative and give this two weeks.\r\nThis is new stuff, so problems are likely to crop up,\r\n\r\nI am only gonna ask for 1.2 btc, which very much for hiring a developer for that length of time, but the most important thing here is to validate the idea by testing whether people are actually prepared to pay, and 1.2 btc is enough to be a real test, but not too much either.\r\n\r\nOf course, you'd probably never see a kickstarter for this little, but the whole point is that this is iterative, and so there is a real way to monitor the progress and provide meaningful feedback.", 92 | "wallet": "1PTAwipYpP63uNrcxfm5FewxRdZyar6ceu", 93 | "target": "1.2", 94 | "links": [ 95 | { 96 | "url": "https://api.github.com/repos/dominictarr/feedopensource/issues/1", 97 | "closed": false 98 | }, 99 | { 100 | "url": "https://api.github.com/repos/dominictarr/feedopensource/issues/2", 101 | "closed": false 102 | }, 103 | { 104 | "url": "https://api.github.com/repos/dominictarr/feedopensource/issues/3", 105 | "closed": false 106 | }, 107 | { 108 | "url": "https://api.github.com/repos/dominictarr/feedopensource/issues/10", 109 | "closed": true 110 | } 111 | ], 112 | "total": 4, 113 | "complete": 1 114 | } 115 | ] 116 | -------------------------------------------------------------------------------- /test/fixtures/wallet.json: -------------------------------------------------------------------------------- 1 | { 2 | "hash160":"f645e1f481074d12f85c757d910808dd0d602825", 3 | "address":"1PTAwipYpP63uNrcxfm5FewxRdZyar6ceu", 4 | "n_tx":15, 5 | "total_received":126125445, 6 | "total_sent":0, 7 | "final_balance":126125445, 8 | "txs":[{"result":0,"block_height":280187,"time":1389566474,"inputs":[{"prev_out":{"n":0,"value":30000000,"addr":"14HyQdmwD5x2LGGcyHsxYPjAQXqHomCvtv","tx_index":105484188,"type":0}}],"vout_sz":2,"relayed_by":"127.0.0.1","hash":"96ebb5159544d6c3a3dc89f6b6886812c23e012e849f6ad92cfa6aef2f491c8d","vin_sz":1,"tx_index":107357783,"ver":1,"out":[{"n":0,"value":13370000,"addr":"1PTAwipYpP63uNrcxfm5FewxRdZyar6ceu","tx_index":107357783,"type":0},{"n":1,"value":16629000,"addr":"17mNBpwcytHf6d2QZxakd31y9yisuszcWs","tx_index":107357783,"type":0}],"size":258},{"result":13370000,"block_height":280076,"time":1389523640,"inputs":[{"prev_out":{"n":1,"value":2400000,"addr":"1Bh6NWU286myjXBW3ZTZ8i1Bzon8xQVTZf","tx_index":101326588,"type":0}}],"vout_sz":2,"relayed_by":"173.52.44.134","hash":"f11a08dcc2e336095c5118bb95124be30e379aaee4a98a532e524e475fcf563b","vin_sz":1,"tx_index":107286003,"ver":1,"out":[{"n":0,"value":2055446,"addr":"1PTAwipYpP63uNrcxfm5FewxRdZyar6ceu","tx_index":107286003,"type":0},{"n":1,"value":334554,"addr":"1Bh6NWU286myjXBW3ZTZ8i1Bzon8xQVTZf","tx_index":107286003,"type":0}],"size":258},{"result":2055446,"block_height":280062,"time":1389515352,"inputs":[{"prev_out":{"n":0,"value":1000000,"addr":"1F6Puy4AgQJBm4nbvMRsQz12jEvugjRsG3","tx_index":99839859,"type":0}}],"vout_sz":1,"relayed_by":"82.90.118.127","hash":"612d6490306bcdac471839e2817e34a5d24522a7fd3ebae6db39898f0ee0ba62","vin_sz":1,"tx_index":107275892,"ver":1,"out":[{"n":0,"value":990000,"addr":"1PTAwipYpP63uNrcxfm5FewxRdZyar6ceu","tx_index":107275892,"type":0}],"size":191},{"result":990000,"block_height":280054,"time":1389512479,"inputs":[{"prev_out":{"n":0,"value":2000000,"addr":"14EtTGnuATHSCud19ttNfVhwAfSCxAGUhu","tx_index":107265859,"type":0}},{"prev_out":{"n":1,"value":878057,"addr":"1P23j92YDL9rjkzhV93mgctJjSo2KGyXUo","tx_index":107265507,"type":0}}],"vout_sz":2,"relayed_by":"127.0.0.1","hash":"3be0bfb93638f01007e023faf51e28a1c690c0cb0130d749d4c4dfbf6a8d339b","vin_sz":2,"tx_index":107272018,"ver":1,"out":[{"n":0,"value":2000000,"addr":"1PTAwipYpP63uNrcxfm5FewxRdZyar6ceu","tx_index":107272018,"type":0},{"n":1,"value":858057,"addr":"1EFnsp19MtjJ4eb5tKD49sWP4xsH5RC2yo","tx_index":107272018,"type":0}],"size":439},{"result":2000000,"block_height":280050,"time":1389510868,"inputs":[{"prev_out":{"n":0,"value":50000000,"addr":"1EF2pabTPjUfWwhgMxwW5cgg8EPjunKbMn","tx_index":107269707,"type":0}},{"prev_out":{"n":2,"value":379582,"addr":"1GfoUdxiTb7jK4LRRZJsQYFiMt4s3G2xCN","tx_index":107264813,"type":0}}],"vout_sz":2,"relayed_by":"127.0.0.1","hash":"a92f09c0926f64479e060b24d0aa7f0af0f793ec81611f04e20e6c2a7f77c406","vin_sz":2,"tx_index":107265696,"ver":1,"out":[{"n":0,"value":50000000,"addr":"1PTAwipYpP63uNrcxfm5FewxRdZyar6ceu","tx_index":107265696,"type":0},{"n":1,"value":359582,"addr":"1K4AW4VJEjBKvX2Fs6YbbtTfgXQyrkKTyS","tx_index":107265696,"type":0}],"size":439},{"result":50000000,"block_height":280037,"time":1389502493,"inputs":[{"prev_out":{"n":1,"value":844270,"addr":"14wWWNFU9aZaBLjbcVQnQrUMqHzkDQygHT","tx_index":107248779,"type":0}},{"prev_out":{"n":0,"value":1000000,"addr":"14xqv7Z7tWYwQYgYi3RhAn5QZMAKAYHaoC","tx_index":107257973,"type":0}}],"vout_sz":2,"relayed_by":"91.230.204.45","hash":"9b4a49a76336a8737bcc81085e9629a91d4d469eb05420e96a02ac37f6e29e3e","vin_sz":2,"tx_index":107258336,"ver":1,"out":[{"n":0,"value":1000000,"addr":"1PTAwipYpP63uNrcxfm5FewxRdZyar6ceu","tx_index":107258336,"type":0},{"n":1,"value":824270,"addr":"1NR2GZAq2XLuxfTixqW14RNCnvGzjEBcA5","tx_index":107258336,"type":0}],"size":437},{"result":1000000,"block_height":279941,"time":1389464047,"inputs":[{"prev_out":{"n":1,"value":3410000,"addr":"1DHnRVa3JYGpwNaofVQa8NuPXnCuvNHEq1","tx_index":91743626,"type":0}}],"vout_sz":1,"relayed_by":"46.195.57.63","hash":"eca34ac3d130d1fe29668c4bb9d10d7d08d1b22f62cae9488105303e1494d06e","vin_sz":1,"tx_index":107189711,"ver":1,"out":[{"n":0,"value":3410000,"addr":"1PTAwipYpP63uNrcxfm5FewxRdZyar6ceu","tx_index":107189711,"type":0}],"size":193},{"result":3410000,"block_height":279821,"time":1389367986,"inputs":[{"prev_out":{"n":1,"value":15380000,"addr":"18JDyQaLq5iopEN3zPBbmDvM7rt457YPCf","tx_index":106977311,"type":0}}],"vout_sz":2,"relayed_by":"127.0.0.1","hash":"5cd0556cb8522fb3485a6e1f79f3e7091d2bdacc98c8fe9c8e097752548a6a6d","vin_sz":1,"tx_index":106999626,"ver":1,"out":[{"n":0,"value":2500000,"addr":"1PTAwipYpP63uNrcxfm5FewxRdZyar6ceu","tx_index":106999626,"type":0},{"n":1,"value":12880000,"addr":"18JDyQaLq5iopEN3zPBbmDvM7rt457YPCf","tx_index":106999626,"type":0}],"size":259},{"result":2500000,"block_height":279640,"time":1389333274,"inputs":[{"prev_out":{"n":0,"value":100000000,"addr":"18QaFQTYePmxBJxvwCU1Dqp62suf1jozNW","tx_index":97749433,"type":0}}],"vout_sz":2,"relayed_by":"184.56.88.71","hash":"b3df16687b4414f43926e2546de3edd90a4e6812f7110c8350da8941b91ec89b","vin_sz":1,"tx_index":106952853,"ver":1,"out":[{"n":0,"value":20000000,"addr":"1PTAwipYpP63uNrcxfm5FewxRdZyar6ceu","tx_index":106952853,"type":0},{"n":1,"value":79990000,"addr":"1KEpBnziPgEiHryq8hyTyS8yEHLaS3Knru","tx_index":106952853,"type":0}],"size":225},{"result":20000000,"block_height":279604,"time":1389316807,"inputs":[{"prev_out":{"n":0,"value":66379776,"addr":"1jb55g498MEa274Z1YWUXQFxZE5NzvhV7","tx_index":106910379,"type":0}}],"vout_sz":2,"relayed_by":"127.0.0.1","hash":"a70271dc6984b50aec36040a8745e3eaf59a7ca2533a54b94f158fbac5dcc75e","vin_sz":1,"tx_index":106925020,"ver":1,"out":[{"n":0,"value":1500000,"addr":"1PTAwipYpP63uNrcxfm5FewxRdZyar6ceu","tx_index":106925020,"type":0},{"n":1,"value":64869776,"addr":"1jb55g498MEa274Z1YWUXQFxZE5NzvhV7","tx_index":106925020,"type":0}],"size":259},{"result":1500000,"block_height":279596,"time":1389313576,"inputs":[{"prev_out":{"n":0,"value":32098166,"addr":"1AyicnATbD2QB5qGWav9KqjCmtHPLumN5v","tx_index":81884008,"type":0}}],"vout_sz":2,"relayed_by":"222.155.112.183","hash":"b669c10b631217487437b284f811dc97c9a7f45520ef8fc2a263d268bb3c8560","vin_sz":1,"tx_index":106919951,"ver":1,"out":[{"n":0,"value":31588166,"addr":"1M2rd4ofhnaV6AnG6ALoBVYtWguLz3rCaE","tx_index":106919951,"type":0},{"n":1,"value":500000,"addr":"1PTAwipYpP63uNrcxfm5FewxRdZyar6ceu","tx_index":106919951,"type":0}],"size":226},{"result":500000,"block_height":279585,"time":1389306192,"inputs":[{"prev_out":{"n":1,"value":216553341,"addr":"1HYmvU61669fvRxJNue9TUyihjAFB4HFER","tx_index":106359331,"type":0}}],"vout_sz":2,"relayed_by":"127.0.0.1","hash":"3010b4d93dda15df8345ede9164b9adf2e25e1ecb9d978c74e2cfdd36315c735","vin_sz":1,"tx_index":106905086,"ver":1,"out":[{"n":0,"value":20000000,"addr":"1PTAwipYpP63uNrcxfm5FewxRdZyar6ceu","tx_index":106905086,"type":0},{"n":1,"value":196553341,"addr":"1HYmvU61669fvRxJNue9TUyihjAFB4HFER","tx_index":106905086,"type":0}],"size":259},{"result":20000000,"block_height":279583,"time":1389306132,"inputs":[{"prev_out":{"n":1,"value":8791000,"addr":"1KGs4wAKWXtiowE7Yhv5KXNUP9xnAtyFs7","tx_index":106807114,"type":0}}],"vout_sz":2,"relayed_by":"127.0.0.1","hash":"ac2afeb9400f401b67eb39f25d4b4d046d35308117f0db6dace7165c89af6c0d","vin_sz":1,"tx_index":106905969,"ver":1,"out":[{"n":0,"value":1799999,"addr":"1PTAwipYpP63uNrcxfm5FewxRdZyar6ceu","tx_index":106905969,"type":0},{"n":1,"value":6981000,"addr":"1KGs4wAKWXtiowE7Yhv5KXNUP9xnAtyFs7","tx_index":106905969,"type":0}],"size":257},{"result":1799999,"block_height":279567,"time":1389302061,"inputs":[{"prev_out":{"n":0,"value":10000000,"addr":"196A7czbZum2nKNNwhHDeFcaGdacxPwfPB","tx_index":60451263,"type":0}}],"vout_sz":2,"relayed_by":"127.0.0.1","hash":"f064ade31e374a57ebd03d9435f30ca8c8809b068974317394f433d153828112","vin_sz":1,"tx_index":106890544,"ver":1,"out":[{"n":0,"value":6000000,"addr":"1PTAwipYpP63uNrcxfm5FewxRdZyar6ceu","tx_index":106890544,"type":0},{"n":1,"value":4000000,"addr":"196A7czbZum2nKNNwhHDeFcaGdacxPwfPB","tx_index":106890544,"type":0}],"size":258},{"result":6000000,"block_height":279516,"time":1389284574,"inputs":[{"prev_out":{"n":0,"value":203350935,"addr":"1HfmCZgSDadW5MoXGj44MrQitmJFye6TJ5","tx_index":106585251,"type":0}}],"vout_sz":2,"relayed_by":"69.42.0.24","hash":"bc0fbffd92993aa3eed60bb69e7320283100ffea36c5d26f851a8ebcb616f592","vin_sz":1,"tx_index":106852165,"ver":1,"out":[{"n":0,"value":202250935,"addr":"1HXS3dwXGkC84Nx9VRUXct9GnifcwKbqvA","tx_index":106852165,"type":0},{"n":1,"value":1000000,"addr":"1PTAwipYpP63uNrcxfm5FewxRdZyar6ceu","tx_index":106852165,"type":0}],"size":257}] 9 | } -------------------------------------------------------------------------------- /test/funders.js: -------------------------------------------------------------------------------- 1 | var tape = require('tape') 2 | 3 | var funders = require('../api/funders') 4 | 5 | var comments = require('./fixtures/comments.json') 6 | var wallet = require('./fixtures/wallet.json') 7 | 8 | //return console.log(JSON.stringify(funders(comments, wallet), null, 2)) 9 | 10 | var expected = require('./fixtures/funders.json') 11 | 12 | 13 | tape('find funders', function (t) { 14 | var actual = funders(comments, wallet) 15 | t.deepEqual(actual, expected) 16 | t.end() 17 | }) 18 | -------------------------------------------------------------------------------- /test/iterations.js: -------------------------------------------------------------------------------- 1 | 2 | var issues = require('./fixtures/issues.json') 3 | var collaborators = require('./fixtures/collaborators') 4 | var iterations = require('../api/iterations') 5 | 6 | var tape = require('tape') 7 | 8 | //return console.log(JSON.stringify(iterations(issues, collaborators, 'dominictarr', 'feedopensource'), null, 2)) 9 | var expected = require('./fixtures/iterations.json') 10 | 11 | tape('issues', function (t) { 12 | 13 | var actual = iterations(issues, collaborators, 'dominictarr', 'feedopensource') 14 | t.deepEqual(actual, expected) 15 | t.end() 16 | 17 | }) 18 | -------------------------------------------------------------------------------- /views/index.js: -------------------------------------------------------------------------------- 1 | 2 | var views = exports 3 | var layout = require('./layout') 4 | 5 | views.iteration = layout(require('./iteration')) 6 | 7 | if(!module.parent) { 8 | var method = process.argv[2] 9 | var data = '' 10 | process.stdin.on('data', function (d) { 11 | data += d 12 | }) 13 | .on('end', function () { 14 | console.log(views[method](JSON.parse(data))) 15 | }) 16 | } 17 | -------------------------------------------------------------------------------- /views/iteration.js: -------------------------------------------------------------------------------- 1 | 2 | require('html-element') 3 | var h = require('hyperscript') 4 | 5 | 6 | function a (href, linked, classes) { 7 | return h('a'+(classes || ''), {href: href}, linked) 8 | } 9 | 10 | function img (src, width, classes) { 11 | return h('img'+(classes || ''), {src: src, width: width ? width+'px' : null}) 12 | } 13 | 14 | //okay, so funders object should also have data about the iteration. 15 | //that is the wallet, the tasks, etc. 16 | //we want to show the state at the top (fundedness, started, finished) 17 | //which can also be represented within the progress bar. 18 | //given that, it will be easy to generate the detailed progress bar. 19 | 20 | module.exports = function (iteration) { 21 | var total = 0 22 | var funders = iteration.funders 23 | return h('div', 24 | h('h1', 25 | a( 26 | iteration.html_url, 27 | h('span', iteration.title) 28 | ) 29 | ), 30 | 31 | h('h3', 'Funding', iteration.state.funded ? ' (Funded)' : ''), 32 | h('div', img(iteration.badge_url, null, '.badge')), 33 | h('a', {style: {float: 'right'}}, {href: 'bitcoin:' + iteration.wallet}, 34 | img('/qr/' + iteration.wallet + '.png', null, '.qr'), 35 | iteration.wallet 36 | ), 37 | // a( + iteration.wallet, 'bitcoin: '+ iteration.wallet), 38 | 39 | h('h3', 'Tasks', iteration.state.complete ? '(Complete)' : ''), 40 | h('div', 41 | h('ul', 42 | iteration.links.map(function (l) { 43 | var url = l.url.replace('https://api.github.com/repos', 'https://github.com') 44 | return h('li', a(url, url), l.closed ? h('bold',' (DONE)') : null) 45 | }) 46 | ) 47 | ), 48 | 49 | h('h3', 'Funders', 50 | ' ('+iteration.sum.toPrecision(4) +' btc, ' 51 | + (100*iteration.progress).toPrecision(4) 52 | + '% funded)' 53 | ), 54 | h('div.row', 55 | funders.map(function (funder) { 56 | total += funder.sum 57 | 58 | /* 59 | +----+ 60 | |THMB| USERNAME 0.123 61 | | | 62 | +----+ trx,... 63 | */ 64 | 65 | return h('div.ib', 66 | h('div.funder', 67 | a(funder.html_url, img(funder.avatar_url || '/grumpy.jpg', 80), '.avatar'), 68 | h('div.uline.fit', 69 | h('span.pad10', 70 | h('span.i2', a(funder.html_url, funder.login)), 71 | h('span', funder.sum/1e8) 72 | ) 73 | ), 74 | h('div.v1.pad10', 75 | funder.txs.map(function (e) { 76 | return h('div.sm', a('https://blockchain.info/tx/' + e.hash, e.hash.substring(0, 45)+'...')) 77 | }) 78 | ) 79 | ) 80 | ) 81 | }) 82 | ) 83 | ) 84 | } 85 | -------------------------------------------------------------------------------- /views/layout.js: -------------------------------------------------------------------------------- 1 | require('html-element') 2 | var h = require('hyperscript') 3 | 4 | module.exports = function (view) { 5 | return function (data) { 6 | return h('html', 7 | h('head', 8 | h('link', {rel: 'stylesheet', href: '/style.css'}), 9 | h('title', 'feedopensource') 10 | ), 11 | h('div#content', view(data)) 12 | ).outerHTML 13 | } 14 | } 15 | --------------------------------------------------------------------------------