GithubHelp home page GithubHelp logo

uhyo / jinrou Goto Github PK

View Code? Open in Web Editor NEW
79.0 12.0 31.0 10.12 MB

Are you a werewolf?

License: Other

JavaScript 3.12% CoffeeScript 49.91% CSS 0.12% HTML 0.26% TypeScript 27.57% Dockerfile 0.03% Stylus 0.56% Pug 18.43%
werewolves

jinrou's Introduction

Table of Contents

月下人狼

Are you a werewolf?

月下人狼サーバー稼働中!

version

1.15.1

requirements

  • Redis
  • MongoDB >= 3.2

usage

  1. Copy the source code
    1. `git clone git://github.com/uhyo/jinrou.git`
  2. Install dependencies
    1. `cd jinrou`
    2. `npm install`
  3. Configure
    1. `cp -r config.default config`
    2. edit `config/app.coffee`
  4. Build front-end scripts
    1. `cd front`
    2. `npm install`
    3. `npm run production-build`
    4. `cd ..`
  5. Run databases
    1. run MongoDB
    2. run redis
  6. Run the application serverj
    1. SS_ENV=production SS_PACK=1 node app.js

development

To run in development mode, just run `node app.js`.

notes on front-end scripts

Built assets will be placed at `client/static/front-assets`. Also, intermediate files are placed at `front/dist-esm`.

Building procedures are cpu- and memory- expensive. If you do not want to build on your server, you can build locally and copy the results to the server.

For development, use `npm run watch` in the `front/` directory to keey updating the front-end assets.

In production mode, contents of `client/static/front-assets/` can be served with `Cache-Control: immutable`. This will increace the effect of caches.

using Docker

Optionally, one can use Docker to run the jinrou service.

The `Dockerfile` file and `docker` directory are only for this purpose.

docker image

To build the docker image for jinrou, run `docker build .` in the project directory. `Dockerfile` defines the image.

docker-compose

To run jinrou in an isolated environment using docker-compose, enther `docker` directory and run `docker-compose up --build`. This starts the jinrou docker image along with mongodb and redis Docker containers. The `docker/config.docker` directory contains a config file for running jinrou in this environment.

jobs

全80種くらい?

基本

  • 村人
  • 占い師
  • 霊能者
  • 狂人
  • 狩人
  • 共有者
  • 埋毒者
  • 人狼
  • 妖狐
  • 埋毒者
  • 大狼
  • 子狐

桃栗特殊

  • こうもり
  • 貴族
  • 奴隷
  • 魔術師
  • スパイ
  • 人狼占い

桃栗期間限定

  • 逃走者
  • 商人
  • 女王感戦者
  • 狂人狼
  • 嘘つき
  • スパイⅡ
  • コピー

うそつき人狼

  • **者
  • 予言者のママ
  • 罠師
  • 狼少年
  • 王様

究極の人狼

いろいろ

月夜の人狼

  • 看板娘
  • 慎重な狼
などなど

options

  • 決定者
  • 権力者
  • 死神の手帳
  • 闇鍋
  • 一部闇鍋
  • 量子人狼

jinrou's People

Contributors

dependabot[bot] avatar hakoniwawind avatar mm018347 avatar sunev avatar uhyo avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

jinrou's Issues

BUG: Guarded(Werewolf) could be Counseled

Guarded(Werewolf) could be Counseled by Counselor because of this. At this line, we would get a undefined if target is any class which extended form class Complex but is not class Chemical, such as Friend, Guarded, HolyProtected, BombTrapped and so on, as their .getMyChemicalTeam() is defined in class Complex but would not work.

users' data duplicated

You may try this on your server.

const crypto = require('crypto');

// mongoexport --db jinrou --collection users --jsonArray --out user.json
const users = require("./user.json")
var list = {}
for (let i in users) {
    let user = users[i];
    if (user.userid) {
        let hashid = crypto.createHash("md5")
        hashid.update(user.userid)
        user.userid = hashid.digest("hex")
        if (list[user.userid] == undefined) {
            list[user.userid] = 1
        } else {
            list[user.userid]++;
        }
    }
}

var result = JSON.parse(JSON.stringify(list, (key, value) => {
    if (value && value <= 1) {
        return undefined
    } else {
        return value
    }
}))

console.log(JSON.stringify(result, null, 4))
console.log(`${Object.keys(result).length} users duplicated`)
process.exit(0)

I got 50 users duplicated

戦績表示

A user can choose to show following information to others:

  • win/lose
  • gone
  • ???

It may be good to show recent information besides his all history.

Requires:

  • DB structure to store recent information
  • DB updates
  • UI
  • A new repair.js

BloodyMary bug

BloodyMary's night skill will not work when BloodyMary is class Complex.

  1. Once $("#jobform") of BloodyMary is submitted, it would be reset immediately like there was nothing happened after the click. Player cannot get a splashlog, nor a Error alert at this time.
  2. But it was submitted normally, as it got logged into db.games→gamelogs, like
                {
                        "id" : "A",
                        "type" : "BloodyMary",
                        "target" : "B",
                        "event" : "job",
                        "flag" : null,
                        "day" : 5
                },

And this log may appear for multiple times, if the player tried that.

Penalty for 突然死

The upgraded blacklist system may enable automatic limitation to user who did 突然死 several times.

Kick and protect

  • A GM can optionally choose to kick a user and forbid him reentering

Stop rooms easily

Sadly, some rooms stops working while not ended, mainly due to bugs.
Provide an admin interface to terminate such rooms.
Update room.mode to "end" and game.finished to true,
and delete the instance of Game.

More Advice and Bug Reporting for Chemical Werewolf

Advices:

  1. Always, FrankensteinsMonster absorbs someone's main job with a tip like “〇〇 absorbed the skill of TroubleMaker from ××”,while in Chemical Werewolf we found that tip becomes “〇〇 absorbed the skill of TroubleMaker×HolyMarked from ××”. Actually, the FrankensteinsMonster only absorbed the skill of TroubleMaker, the main job. Would you like to take this tip as kind of spoiler?

Bugs:

  1. Lonely Friend still exists. It seems that not only occurs when BadLady proposed to someone. In [this room](http://www.werewolf.online/room/26833)  (Chinese), 2 Cupids created 2 pairs of Friends separately, one pair acts normally and the other pair not.
    
  2. Devil×sth.
    Game never ends while Devil×sth achieved all his Victory Conditions. Even though x was bitten by werewolf and hanged at the next sunset. With flag not defined in class Chemical.
if @players.some((x)->x.isJobType "Devil" && x.flag=="winner" && x.team=="Devil")
    team="Devil"
x.isJobType "Devil" #   true
x.flag=="winner" #  false
  1. Fugitive×sth.
    Fugitive×sth won't die when run to some Target who was bitten by werewolf or Vampire. Because x.target is undefined.
runners=game.players.filter (x)=>!x.dead && x.isJobType("Fugitive") && x.target==t.id
x.isJobType "Fugitive"       #  true
x.target==t.id #false
  1. Ushinotokimairi×sth.
    ushinotokimairi_curse acts randomly, as midnightSort didn't got redefined in class Chemical. midnightSort of Ushinotokimairi×sth is 100 as default instead of 90 for Ushinotokimairi. And we can imagine the mess of all other Jobs whose midnightSort is not 100.
  2. Sth×ToughGuy.
    At the next sunset after bitten by werewolf, ToughGuy, the subjob, setDead himself normally, while the mainjob Sth and the top Object class Chemical doesn't. Sth×ToughGuy becomes Walking Dead. The Heaven is visible to him. And what’s worse, ToughGuy @setFlag null for himself, Sth×ToughGuy becomes Invincible to Werewolf.
    Example:
{
    "type": "Complex",
    "dead": false,
    "flag": null
    "Complex_main": {
        "type": "Couple",
        "dead": false,
        "flag": null
    },
    "Complex_sub": {
        "type": "ToughGuy",
        "dead": true,
        "flag": null
    },
    "Complex_type": "Chemical",
    "Complex_flag": null
}

BAN VIRUS

A banned account writes a user's cookie, localStorage and other storage so that a user is restricted on making accounts and other activities on that browser.
Also, the ban system should be extended so that activities other than entering rooms can be restricted.

Mail confirmation option

パスワード・メールアドレスを変更するときに現在のメールアドレスにメールを送り確認するオプションを追加

Related: #47

"node app.js" failed

~/jinrou# node app.js
Failed to load config file.
Copy config.default/app.coffee to config/app.coffee, edit app.coffee, and retry.
[Error: Use CoffeeScript.register() or require the coffee-script/register module to require .coffee.md files.]

I have already copied and edited config/app.coffee, but still failed to load config file.

Here is my npm list:
~/jinrou# npm list
[email protected] /root/jinrou
├─┬ [email protected]
│ ├── [email protected]
│ ├── [email protected]
│ ├── [email protected]
│ └── [email protected]
├─┬ [email protected]
│ ├── [email protected]
│ ├─┬ [email protected]
│ │ ├─┬ [email protected]
│ │ │ └── [email protected]
│ │ └─┬ [email protected]
│ │ └── [email protected]
│ ├── [email protected]
│ ├─┬ [email protected]
│ │ └─┬ [email protected]
│ │ └── [email protected]
│ ├─┬ [email protected]
│ │ ├── [email protected]
│ │ └─┬ [email protected]
│ │ └── [email protected]
│ ├─┬ [email protected]
│ │ └── [email protected]
│ ├─┬ [email protected]
│ │ ├─┬ [email protected]
│ │ │ ├── [email protected]
│ │ │ └── [email protected]
│ │ ├─┬ [email protected]
│ │ │ └── [email protected]
│ │ └─┬ [email protected]
│ │ ├─┬ [email protected]
│ │ │ └── [email protected]
│ │ └─┬ [email protected]
│ │ └── [email protected]
│ ├─┬ [email protected]
│ │ ├── [email protected]
│ │ ├─┬ [email protected]
│ │ │ └── [email protected]
│ │ ├── [email protected]
│ │ └─┬ [email protected]
│ │ ├── [email protected]
│ │ ├── [email protected]
│ │ ├── [email protected]
│ │ └── [email protected]
│ ├── [email protected]
│ └─┬ [email protected]
│ ├── [email protected]
│ └── [email protected]
├─┬ [email protected]
│ ├── [email protected]
│ ├─┬ [email protected]
│ │ ├── [email protected]
│ │ └─┬ [email protected]
│ │ └── [email protected]
│ └─┬ [email protected]
│ ├── [email protected]
│ ├── [email protected]
│ ├── [email protected]
│ └── [email protected]
├─┬ [email protected]
│ ├── [email protected]
│ └── [email protected]
├── [email protected]
├─┬ [email protected]
│ ├── [email protected]
│ ├── [email protected]
│ ├─┬ [email protected]
│ │ ├── [email protected]
│ │ ├── [email protected]
│ │ ├─┬ [email protected]
│ │ │ └── [email protected]
│ │ ├── [email protected]
│ │ ├── [email protected]
│ │ ├─┬ [email protected]
│ │ │ └── [email protected]
│ │ ├── [email protected]
│ │ ├── [email protected]
│ │ └─┬ [email protected]
│ │ ├── [email protected]
│ │ └─┬ [email protected]
│ │ └── [email protected]
│ ├─┬ [email protected]
│ │ ├── [email protected]
│ │ └─┬ [email protected]
│ │ ├── [email protected]
│ │ ├─┬ [email protected]
│ │ │ ├── [email protected]
│ │ │ └── [email protected]
│ │ └─┬ [email protected]
│ │ ├── [email protected]
│ │ ├── [email protected]
│ │ ├── [email protected]
│ │ └── [email protected]
│ ├─┬ [email protected]
│ │ └── [email protected]
│ ├── [email protected]
│ ├── [email protected]
│ ├─┬ [email protected]
│ │ ├─┬ [email protected]
│ │ │ ├─┬ [email protected]
│ │ │ │ └── [email protected]
│ │ │ └── [email protected]
│ │ ├── [email protected]
│ │ ├─┬ [email protected]
│ │ │ └── [email protected]
│ │ ├─┬ [email protected]
│ │ │ └── [email protected]
│ │ ├── [email protected]
│ │ └── [email protected]
│ ├─┬ [email protected]
│ │ ├─┬ [email protected]
│ │ │ └── [email protected]
│ │ └─┬ [email protected]
│ │ └─┬ [email protected]
│ │ └── [email protected]
│ ├─┬ [email protected]
│ │ ├─┬ [email protected]
│ │ │ └── [email protected]
│ │ └── [email protected]
│ ├─┬ [email protected]
│ │ ├── [email protected]
│ │ ├── [email protected]
│ │ ├── [email protected]
│ │ └── [email protected]
│ ├─┬ [email protected]
│ │ ├── [email protected]
│ │ └── [email protected]
│ ├─┬ [email protected]
│ │ ├─┬ [email protected]
│ │ │ └── [email protected]
│ │ └── [email protected]
│ ├─┬ [email protected]
│ │ └── [email protected]
│ ├─┬ [email protected]
│ │ ├── [email protected]
│ │ ├── [email protected]
│ │ ├─┬ [email protected]
│ │ │ ├── [email protected]
│ │ │ ├── [email protected]
│ │ │ ├── [email protected]
│ │ │ └─┬ [email protected]
│ │ │ └── [email protected]
│ │ └─┬ [email protected]
│ │ ├── [email protected]
│ │ └── [email protected]
│ ├─┬ [email protected]
│ │ ├── [email protected]
│ │ ├─┬ [email protected]
│ │ │ └── [email protected]
│ │ ├─┬ [email protected]
│ │ │ ├── [email protected]
│ │ │ ├── [email protected]
│ │ │ ├── [email protected]
│ │ │ ├── [email protected]
│ │ │ ├─┬ [email protected]
│ │ │ │ └── [email protected]
│ │ │ └── [email protected]
│ │ └─┬ [email protected]
│ │ ├── [email protected]
│ │ ├── [email protected]
│ │ └── [email protected]
│ ├── [email protected]
│ ├── [email protected]
│ ├─┬ [email protected]
│ │ ├── [email protected]
│ │ ├── [email protected]
│ │ ├── [email protected]
│ │ ├─┬ [email protected]
│ │ │ └── [email protected]
│ │ ├── [email protected]
│ │ ├── [email protected]
│ │ └─┬ [email protected]
│ │ ├── [email protected]
│ │ └── [email protected]
│ ├── [email protected]
│ ├── [email protected]
│ ├── [email protected]
│ ├─┬ [email protected]
│ │ ├── [email protected]
│ │ ├── [email protected]
│ │ ├── [email protected]
│ │ ├─┬ [email protected]
│ │ │ └── [email protected]
│ │ ├── [email protected]
│ │ ├── [email protected]
│ │ ├── [email protected]
│ │ ├─┬ [email protected]
│ │ │ └── [email protected]
│ │ └── [email protected]
│ ├─┬ [email protected]
│ │ ├─┬ [email protected]
│ │ │ └── [email protected]
│ │ ├── [email protected]
│ │ └── [email protected]
│ ├─┬ [email protected]
│ │ └─┬ [email protected]
│ │ ├── [email protected]
│ │ ├── [email protected]
│ │ ├── [email protected]
│ │ ├─┬ [email protected]
│ │ │ └── [email protected]
│ │ ├── [email protected]
│ │ ├── [email protected]
│ │ ├── [email protected]
│ │ ├─┬ [email protected]
│ │ │ └── [email protected]
│ │ └── [email protected]
│ ├── [email protected]
│ ├── [email protected]
│ ├── [email protected]
│ └── [email protected]
├─┬ [email protected]
│ ├─┬ [email protected]
│ │ ├── [email protected]
│ │ ├── [email protected]
│ │ ├── [email protected]
│ │ ├── [email protected]
│ │ ├─┬ [email protected]
│ │ │ └─┬ [email protected]
│ │ │ └─┬ [email protected]
│ │ │ └─┬ [email protected]
│ │ │ ├── [email protected]
│ │ │ └── [email protected]
│ │ ├─┬ [email protected]
│ │ │ ├─┬ [email protected]
│ │ │ │ ├── [email protected]
│ │ │ │ └── [email protected]
│ │ │ ├─┬ [email protected]
│ │ │ │ └── [email protected]
│ │ │ └─┬ [email protected]
│ │ │ ├─┬ [email protected]
│ │ │ │ └── [email protected]
│ │ │ └─┬ [email protected]
│ │ │ └── [email protected]
│ │ └─┬ [email protected]
│ │ └─┬ [email protected]
│ │ ├── [email protected]
│ │ ├─┬ [email protected]
│ │ │ └── [email protected]
│ │ ├─┬ [email protected]
│ │ │ └── [email protected]
│ │ └── [email protected]
│ └─┬ [email protected]
│ ├── [email protected]
│ ├─┬ [email protected]
│ │ └── [email protected]
│ ├── [email protected]
│ └─┬ [email protected]
│ ├── [email protected]
│ ├── [email protected]
│ ├── [email protected]
│ └── [email protected]
├─┬ [email protected]
│ └─┬ [email protected]
│ ├── [email protected]
│ ├── [email protected]
│ └── [email protected]
├─┬ [email protected]
│ └── [email protected]
└─┬ [email protected]
├─┬ [email protected]
│ └─┬ [email protected]
│ ├── [email protected]
│ ├─┬ [email protected]
│ │ └── [email protected]
│ ├─┬ [email protected]
│ │ ├── [email protected]
│ │ └─┬ [email protected]
│ │ ├── [email protected]
│ │ └── [email protected]
│ ├── [email protected]
│ └── [email protected]
└─┬ [email protected]
├── [email protected]
├─┬ [email protected]
│ └── [email protected]
├─┬ [email protected]
│ ├── [email protected]
│ └─┬ [email protected]
│ ├── [email protected]
│ └── [email protected]
├── [email protected]
├── [email protected]
└─┬ [email protected]
└── [email protected]

midnightSort of GotChocolate

As there are 41% chance that player who GotChocolate would have his fortuneResult changed. What about lift GotChocolate.midnightSort to 90?

By the way, I am not really sure if it would be better to take Patissiere as same as WolfBoy.

bug in mode of runoff

Under mode runoff, if it needs 2 or more players got punished, like the DrawGirl was bitten, first player would got punished as usual, but the candidate keeps to be player of tops. It leads to a Sudden Death of the candidate, as the only candidate could not vote to himself (although this could be avoided by setting ). After that, it comes to be Sudden Death of everyone, because there is no alive candidate but the system asks a vote.

Decider Bug

I got reported a bug that a Guard(Decider), who protected himself and got bitten by Werewolf, was found dead at sunrise. According to my tests, those Guards without Decider survives normally. Is this related with the deepest Darkness?
And please take your thesis as the most important thing. This bug does not appear very often.

Support for ワンナイト人狼

  • Full support for ワンナイト人狼
  • Support some ワンナイト人狼-only jobs like てるてる
  • Available jobs should be restricted in ワンナイト人狼 because the rule is not capable of handling the full feature of our jinrou

Upvote/downvote users

  • A user (with enough playing history) can upvote/downvote another user.
  • A user can get prizes if he has many upvotes

BUG: FrankensteinsMonster's Sin of Gluttony

When new dead was found in this loop, such as a Friend or Blasphemy had suicided, we can expect that FrankensteinsMonster.beforebury() will be called for many times.
If the earlier dead player is of Human team, he would got eatten for many times.

switch HTTP and HTTPS

Before moving to HTTPS, it is preferable to allow users to switch between HTTP and HTTPS,
in case a user does not remember his password but is logging in using his password saved in localStorage.

投票時間延長ボタン

GMが押すと投票時間が延びるやつ(投票だけでなく昼や夜も時間をのばせる?)

BUG: Werewolf get killed together with Guard by Trapper

My friends and I carried out a test in this room. According to the same test at my server, I am sure there is something wrong with TrapGuarded now.

In this room, the Diviner got Guarded, TrapGuarded, and Bitten at same night, and the Werewolf get killed together with the Guard. It seems that the TrapGuarded failed to @uncomplex game after he had killed the Guard in @checkGuard()

Advices and Bug Reporting for Chemical Werewolf

First of all, thank you very much for developing Chemical Werewolf. It is so attractive that my friends and I just spent a whole night on it. Yet, it seems exist something would make players confused and some bugs those I cannot handle with.
Advices:

  1. Players found confused about which team they belong to. Should we add some instruction about their teams into div#jobinfo?
  2. Now div#jobinfo displays job information like "You are A×B(Details of B·Details of A)". If we could change that into "You are A×B(Details of A·Details of B)", I think it would make players feel better.

Bugs:

  1. For some job whose skill could be used every night (e.g. Diviner, Guard, WolfDiviner), which I named as A. If a player get a Chemical Werewolf as 「A×A」, that skill of A could be used for unlimited times during one night.
    1.1. If that skill of A could cause Sudden Death (gone-night), it will.
    1.2. Exceptions to Vampire, 「Vampire×Vampire」 can attack for only once, and then gone-night.
    1.3. Exceptions to Cat, 「Cat×Cat」 can revive some others for twice normally without gone-night.
    1.4. 「Werewolf×Werewolf」 can attacks others normally, as there exists the counter of werewolf_target_remain.
    1.5. For those jobs whose night skill could be used for only once (e.g. Bomber), they behave normally.
  2. For some job with passive skill (e.g. Prince, ToughGuy) token as A. A's passive skill would never acts if A becomes a sub job. For example:
    2.1. If a player becomes 「Something×Prince」, the player could be hanged after first voted.
    2.2. If a player becomes 「Something×ToughGuy」, the player will die after attacked by Werewolf.
    2.3. Anyone touched 「Others×PsychoKiller」 won't die, while those touched 「PsychoKiller×PsychoKiller」 will die normally
  3. 「Others×QueenSpectator」 will lead to a situation that nobody can see the Tip like “Someone is QueenSpectator”, even the QueenSpectator herself, which is dangerous; 「QueenSpectator×Others」 is kind of visible but still comes with limit:
    Let us take some job of Human Team as H, and some job out of Human Team as N. Players like 「H×N」 can identify the QueenSpectator and those like 「N×H」 cannot, while QueenSpectator should not be visible to both of them. Normally, we assert that only players like 「H×another H」 could make sure who is the QueenSpectator.
  4. In some situation, which I have not make sure how to repeat, BadLady(X) proposed to someone(Y), then Y became a lonely Friend, instead of Friend of X. In that situation, Y gets instruction at div#jobinfo like “Friends are Y” instead of “Friends are X, Y”, while X gets “Friends are X, Y”. More than that, Y would not suicide if X died but X would.

Security improvement

ユーザーのパスワードをsalt付きで保存する(既存のデータはログイン時にアップグレード)

Related: #47

"Dead Resistance" in class Complex

Guard created by Merchant seems not have Dead Resistance, as hasDeadResistance is not defined in class Complex
I am not sure whether it is a negligence or your designing.

Handle "mixed content" problem

When using HTTPS, loading HTTP contents is called "mixed content" and is considered not secure.
In our service it occurs mainly because users' icons are served using HTTP.
We need to automatically switch to HTTPS as much as possible.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.