Merge: nitrpg: Move `nitrpg` to its own repository
authorJean Privat <jean@pryen.org>
Wed, 3 Jul 2019 18:50:57 +0000 (14:50 -0400)
committerJean Privat <jean@pryen.org>
Wed, 3 Jul 2019 18:50:57 +0000 (14:50 -0400)
`nitrpg` is broken since a long time. I think https:/api.github.com actually changed twice since it broke. I don't plan on killing it yet but I moved it to its own repository until I worked again on it (or never).

See https://github.com/Morriar/nitrpg.

Signed-off-by: Alexandre Terrasa <alexandre@moz-code.org>

Pull-Request: #2755

24 files changed:
contrib/nitrpg/.gitignore [deleted file]
contrib/nitrpg/Makefile [deleted file]
contrib/nitrpg/README.md [deleted file]
contrib/nitrpg/nitrpg.user.js [deleted file]
contrib/nitrpg/package.ini [deleted file]
contrib/nitrpg/src/achievements.nit [deleted file]
contrib/nitrpg/src/events.nit [deleted file]
contrib/nitrpg/src/events_generator.nit [deleted file]
contrib/nitrpg/src/game.nit [deleted file]
contrib/nitrpg/src/listener.nit [deleted file]
contrib/nitrpg/src/reactors.nit [deleted file]
contrib/nitrpg/src/statistics.nit [deleted file]
contrib/nitrpg/src/templates/panels.nit [deleted file]
contrib/nitrpg/src/templates/templates.nit [deleted file]
contrib/nitrpg/src/templates/templates_base.nit [deleted file]
contrib/nitrpg/src/templates/templates_events.nit [deleted file]
contrib/nitrpg/src/test_achievements.nit [deleted file]
contrib/nitrpg/src/test_events.nit [deleted file]
contrib/nitrpg/src/test_game.nit [deleted file]
contrib/nitrpg/src/test_helper.nit [deleted file]
contrib/nitrpg/src/test_listener.nit [deleted file]
contrib/nitrpg/src/test_statistics.nit [deleted file]
contrib/nitrpg/src/web.nit [deleted file]
contrib/nitrpg/www/styles/main.css [deleted file]

diff --git a/contrib/nitrpg/.gitignore b/contrib/nitrpg/.gitignore
deleted file mode 100644 (file)
index 24c4036..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-.github_data
-nitrpg_data
-listener
-web
diff --git a/contrib/nitrpg/Makefile b/contrib/nitrpg/Makefile
deleted file mode 100644 (file)
index 0270ede..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-# This file is part of NIT ( http://www.nitlanguage.org ).
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-NITC ?= nitc
-NITLS ?= nitls
-NITUNIT ?= nitunit
-NITDOC ?= nitdoc
-
-.PHONY: all
-all: bin/listener bin/web
-
-bin/listener: $(shell $(NITLS) -M src/listener.nit)
-       mkdir -p bin/
-       $(NITC) src/listener.nit -o bin/listener
-
-bin/web: $(shell $(NITLS) -M src/web.nit)
-       mkdir -p bin/
-       $(NITC) src/web.nit -o bin/web
-
-.PHONY: check
-check:
-       $(NITUNIT) .
-
-.PHONY: doc
-doc:
-       $(NITDOC) . -o doc/
-
-.PHONY: clean
-clean:
-       rm -rf bin/
-       rm -rf doc/
diff --git a/contrib/nitrpg/README.md b/contrib/nitrpg/README.md
deleted file mode 100644 (file)
index 5f6a02d..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-# Welcome to NitRPG!
-
-NitRPG is a Role Playing Game that takes place on [GitHub](https://github.com/).
-
-In NitRPG, GitHub users are represented by players that battle on repo for
-nitcoins and glory.
-
-## Features
-
-* Auto-update with GitHub hooks
-* Display repo statistics
-* Display players statsitics
-* Repo actions are rewarded by nitcoins
-* Players can unlock achievements
-
-## How to install
-
-From the `nit` root:
-
-~~~bash
-> cd contrib/nitrpg
-> make
-~~~
-
-### Configuring the GitHub hook
-
-NitRPG needs you to add a new GitHub hook on your repo to keep the game
-`listener` up-to-date automatically.
-
-Hook configuration:
-
-* **Payload URL**: URL and port to the listener (ex: `http://yourdomain.com:8080`)
-* **Content type**: `application/json`
-* **Wich events**: `Send me everything`
-
-Be sure to set the hook as `Active` in the GitHub admin panel.
-
-### Starting the listener
-
-The `listener` program is used to listen to GitHub hooks and update game data.
-It should alwaysd be up if you want your game to be kept up-to-date.
-
-To run the listener:
-
-~~~raw
-       ./listener <host> <port>
-~~~
-
-The arguments `host` and `port` must correspond to what you entered in your
-GitHub hook settings.
-
-### Starting the web server
-
-The `web` program act as a [nitcorn](http://nitlanguage.org/doc/stdlib/module_nitcorn__nitcorn.html) webserver that display the game results live.
-
-To run the webserver:
-
-~~~raw
-       ./web <host> <port> <root>
-~~~
-
-The arguments `host` and `port` must correspond to what you entered in your
-GitHub hook settings.
-The `root` argument is used to specify the path from the domain url to the
-NitRPG root.
-
-For example, if NitRPG is installed in `yourdomain.com/nitrpg`:
-
-~~~raw
-       ./web localhost 3000 "/nitrpg"
-~~~
-
-Leave it empty if NitRPG is installed at the root of the domain:
-
-~~~raw
-       ./web localhost 3000 ""
-~~~
-
-The webserver can then be accessed at `http://yourdomain.com:3000/nitrpg/`.
-
-## RoadMap
-
-NitRPG stills under heavy development.
-Incomming features contain (but are not limited to):
-
-* Periodized stats (weekly, monthly, yearly, overall)
-* Display graphs with stats
-* More achievements
-* Shop: exchange Nitcoins against glorifying items
-
-You can suggest new achievements or ideas in the
-[NitRPG RoadMap Issue](https://github.com/nitlang/nit/issues/1161).
diff --git a/contrib/nitrpg/nitrpg.user.js b/contrib/nitrpg/nitrpg.user.js
deleted file mode 100644 (file)
index 7e27fa1..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-// ==UserScript==
-// @name        Github.com - Add RPG tab
-// @namespace   nitlanguage/github/rpg
-// @description Adds a "Github RPG" Tab at the end of the tabs.
-// @include     https://github.com/*
-// @downloadURL https://github.com/nitlang/nit/raw/master/contrib/nitrpg/nitrpg.user.js
-// @version     2
-// @grant       none
-// ==/UserScript==
-
-// The nav bar with tabs
-var nav = document.getElementsByClassName('reponav');
-if (!nav || !nav[0]) return;
-
-// The current repo to link
-var repo = $("meta[name='octolytics-dimension-repository_nwo']").attr("content");
-//repo = "nitlang/nit";
-if (!repo) return;
-
-// The content of the new tab
-var html = '<a href="http://nitlanguage.org/rpg/games/' + repo + '" class="js-selected-navigation-item reponav-item" data-selected-links="nitrpg"><span class="octicon octicon-ruby"></span> Github RPG</a>';
-//html = '<p><span>x</span></p>';
-
-// Inject the new tab
-var div = document.createElement('div');
-div.innerHTML = html;
-nav[0].append(div.firstChild);
diff --git a/contrib/nitrpg/package.ini b/contrib/nitrpg/package.ini
deleted file mode 100644 (file)
index 7db8f35..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-[package]
-name=nitrpg
-tags=devel,web,cli
-maintainer=Alexandre Terrasa <alexandre@moz-code.org>
-license=Apache-2.0
-desc=NitRPG, a Role Playing Game that takes place on GitHub
-[upstream]
-browse=https://github.com/nitlang/nit/tree/master/contrib/nitrpg/
-git=https://github.com/nitlang/nit.git
-git.directory=contrib/nitrpg/
-homepage=http://nitlanguage.org
-issues=https://github.com/nitlang/nit/issues
diff --git a/contrib/nitrpg/src/achievements.nit b/contrib/nitrpg/src/achievements.nit
deleted file mode 100644 (file)
index 2097ec3..0000000
+++ /dev/null
@@ -1,532 +0,0 @@
-# This file is part of NIT ( http://www.nitlanguage.org ).
-#
-# Copyright 2014-2015 Alexandre Terrasa <alexandre@moz-code.org>
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# `nitrpg` achievements.
-#
-# Players can unlock achievements by performing remarkable actions on the repo.
-# Achievements are rewarded by nitcoins.
-module achievements
-
-import events
-import statistics
-
-redef class GameEntity
-
-       # Register a new achievement for this game entity.
-       #
-       # Saves the achievement in game data.
-       # Do nothing is the achievement is already registered.
-       #
-       # TODO should update the achievement?
-       fun add_achievement(achievement: Achievement) do
-               stats.inc("achievements")
-               achievement.owner = self
-               achievement.save
-       end
-
-       # Is `a` unlocked for this `Player`?
-       fun has_achievement(a: Achievement): Bool do return load_achievement(a.id) != null
-
-       # Load the event from its `id`.
-       #
-       # Looks for the event save file in game data.
-       # Returns `null` if the event cannot be found.
-       fun load_achievement(id: String): nullable Achievement do
-               var req = new JsonObject
-               req["id"] = id
-               req["game"] = game.key
-               req["owner"] = key
-               var obj = game.db.collection("achievements").find(req)
-               if obj isa JsonObject then
-                       return new Achievement.from_json(game, obj)
-               end
-               return null
-       end
-
-       # List all events registered in this entity.
-       #
-       # This list is reloaded from game data each time its called.
-       #
-       # To add events see `add_event`.
-       fun load_achievements: MapRead[String, Achievement] do
-               var req = new JsonObject
-               req["game"] = game.key
-               req["owner"] = key
-               var res = new HashMap[String, Achievement]
-               for obj in game.db.collection("achievements").find_all(req) do
-                       var achievement = new Achievement.from_json(game, obj)
-                       res[achievement.id] = achievement
-               end
-               return res
-       end
-end
-
-# Achievements are rewarded by `nitcoins`.
-#
-# An achievement represents a notable action performed by a `Player`.
-# Player that `unlock` achievements are rewarded by nitcoins.
-class Achievement
-       super GameEntity
-
-       redef var collection_name = "achievements"
-
-       redef var game
-
-       redef fun key do
-               var owner = self.owner
-               if owner == null then return id
-               return "{owner.key}-{id}"
-       end
-
-       # Uniq ID for this achievement.
-       var id: String
-
-       # Name of this achievement.
-       var name: String
-
-       # Description of the achievement.
-       var desc: String
-
-       # Reward that this achievement give in nitcoins.
-       var reward: Int
-
-       # Is this achievement unlocked by somebody?
-       var is_unlocked: Bool is lazy do return not load_events.is_empty
-
-       # Game entity this achievement is about.
-       var owner: nullable GameEntity = null
-
-       # Init `self` from a `json` object.
-       #
-       # Used to load achievements from storage.
-       init from_json(game: Game, json: JsonObject) do
-               init(game,
-                       json["id"].as(String),
-                       json["name"].as(String),
-                       json["desc"].as(String),
-                       json["reward"].as(Int))
-       end
-
-       redef fun to_json_object do
-               var json = super
-               json["id"] = id
-               json["name"] = name
-               json["desc"] = desc
-               json["reward"] = reward
-               json["game"] = game.key
-               var owner = self.owner
-               if owner != null then json["owner"] = owner.key
-               return json
-       end
-end
-
-redef class Player
-       # Unlocks an achievement for this Player based on a GithubEvent.
-       #
-       # Register the achievement and adds the achievement reward to the player
-       # nitcoins.
-       #
-       # Do nothing is this player has already unlocked the achievement.
-       #
-       # TODO: add abstraction so achievements do not depend on GithubEvent.
-       fun unlock_achievement(a: Achievement, event: GithubEvent) do
-               if has_achievement(a) then return
-               nitcoins += a.reward
-               add_achievement(a)
-               trigger_unlock_event(a, event)
-               save
-       end
-
-       # Create a new event that marks the achievement unlocking.
-       fun trigger_unlock_event(achievement: Achievement, event: GithubEvent) do
-               var obj = new JsonObject
-               obj["player"] = name
-               obj["reward"] = achievement.reward
-               obj["achievement"] = achievement.id
-               obj["github_event"] = event
-               var ge = new GameEvent(game, "achievement_unlocked", obj)
-               add_event(ge)
-               game.add_event(ge)
-               achievement.add_event(ge)
-       end
-end
-
-# `GameReactor` dedicated to achievements unlocking.
-interface AchievementReactor
-       super GameReactor
-
-       # Unic ID of the achievement this reactor unlocks.
-       fun id: String is abstract
-
-       # Name of the achievement this reactor unlocks.
-       fun name: String is abstract
-
-       # Description of the achievement this reactor unlocks.
-       fun desc: String is abstract
-
-       # Amount of nitcoins rewarded for unlocking the achievement.
-       fun reward: Int is abstract
-
-       # Return a new instance of the achievement to unlock.
-       fun new_achievement(game: Game): Achievement do
-               var achievement = new Achievement(game, id, name, desc, reward)
-               game.add_achievement(achievement)
-               return achievement
-       end
-end
-
-#####################
-### Issues
-#####################
-
-# Unlock achievement after X issues.
-#
-# Used to factorize behavior.
-abstract class PlayerXIssues
-       super AchievementReactor
-
-       # Number of PR required to unlock the achievement.
-       var threshold: Int is noinit
-
-       redef fun react_event(game, event) do
-               if not event isa IssuesEvent then return
-               if not event.action == "opened" then return
-               var player = event.issue.user.player(game)
-               if player.stats["issues"] == threshold then
-                       var a = new_achievement(game)
-                       player.unlock_achievement(a, event)
-               end
-       end
-end
-
-# Player open his first issue.
-class Player1Issue
-       super PlayerXIssues
-
-       redef var id = "player_1_issue"
-       redef var name = "First complaint"
-       redef var desc = "Open your first issue."
-       redef var reward = 10
-       redef var threshold = 1
-end
-
-# Player open 100 issues.
-class Player100Issues
-       super PlayerXIssues
-
-       redef var id = "player_100_issues"
-       redef var name = "Mature whiner"
-       redef var desc = "Open 100 issues in the game."
-       redef var reward = 100
-       redef var threshold = 100
-end
-
-# Player open 1 000 issues.
-class Player1KIssues
-       super PlayerXIssues
-
-       redef var id = "player_1000_issues"
-       redef var name = "You, sir, complain a lot"
-       redef var desc = "Open 1000 issues in the game."
-       redef var reward = 1000
-       redef var threshold = 1000
-end
-
-# Player open an issue about nitdoc.
-class IssueAboutNitdoc
-       super AchievementReactor
-
-       redef var id = "issue_about_nitdoc"
-       redef var name = "Say nitdoc again, I double dare you!"
-       redef var desc = "Open an issue with \"nitdoc\" in the title."
-       redef var reward = 10
-
-       redef fun react_event(game, event) do
-               if not event isa IssuesEvent then return
-               if not event.action == "opened" then return
-               var player = event.issue.user.player(game)
-               var re = "nitdoc".to_re
-               re.ignore_case = true
-               if event.issue.title.has(re) then
-                       var a = new_achievement(game)
-                       player.unlock_achievement(a, event)
-               end
-       end
-end
-
-# Player open an issue about FFI.
-class IssueAboutFFI
-       super PlayerXIssues
-
-       redef var id = "issue_about_ffi"
-       redef var name = "Polyglot what?"
-       redef var desc = "Open an issue with `ffi` in the title."
-       redef var reward = 10
-
-       redef fun react_event(game, event) do
-               if not event isa IssuesEvent then return
-               if not event.action == "opened" then return
-               var player = event.issue.user.player(game)
-               var re = "\\bffi\\b".to_re
-               re.ignore_case = true
-               if event.issue.title.has(re) then
-                       var a = new_achievement(game)
-                       player.unlock_achievement(a, event)
-               end
-       end
-end
-
-#####################
-### Pull requests
-#####################
-
-# Unlock achievement after X pull requests.
-#
-# Used to factorize behavior.
-abstract class PlayerXPulls
-       super AchievementReactor
-
-       # Number of PR required to unlock the achievement.
-       var threshold: Int is noinit
-
-       redef fun react_event(game, event) do
-               if not event isa PullRequestEvent then return
-               if not event.action == "opened" then return
-               var player = event.pull.user.player(game)
-               if player.stats["pulls"] == threshold then
-                       var a = new_achievement(game)
-                       player.unlock_achievement(a, event)
-               end
-       end
-end
-
-# Open your first pull request.
-class Player1Pull
-       super PlayerXPulls
-
-       redef var id = "player_1_pull"
-       redef var name = "First PR"
-       redef var desc = "Open your first pull request."
-       redef var reward = 10
-       redef var threshold = 1
-end
-
-# Author 100 pull requests.
-class Player100Pulls
-       super PlayerXPulls
-
-       redef var id = "player_100_pulls"
-       redef var name = "100 pull requests!!!"
-       redef var desc = "Open 100 pull requests in the game."
-       redef var reward = 100
-       redef var threshold = 100
-end
-
-# Author 1000 pull requests.
-class Player1KPulls
-       super PlayerXPulls
-
-       redef var id = "player_1000_pulls"
-       redef var name = "1000 PULL REQUESTS!!!"
-       redef var desc = "Open 1000 pull requests in the game."
-       redef var reward = 1000
-       redef var threshold = 1000
-end
-
-#####################
-### Commits
-#####################
-
-# Unlock achievement after X merged commits.
-#
-# Used to factorize behavior.
-abstract class PlayerXCommits
-       super AchievementReactor
-
-       # Number of PR required to unlock the achievement.
-       var threshold: Int is noinit
-
-       redef fun react_event(game, event) do
-               if not event isa PullRequestEvent then return
-               if not event.action == "closed" then return
-               if not event.pull.merged then return
-               var player = event.pull.user.player(game)
-               if player.stats["commits"] >= threshold then
-                       var a = new_achievement(game)
-                       player.unlock_achievement(a, event)
-               end
-       end
-end
-
-# Author your first commit in the game.
-class Player1Commit
-       super PlayerXCommits
-
-       redef var id = "player_1_commit"
-       redef var name = "First blood"
-       redef var desc = "Author your first commit in the game."
-       redef var reward = 10
-       redef var threshold = 1
-end
-
-# Author 100 commits.
-class Player100Commits
-       super PlayerXCommits
-
-       redef var id = "player_100_commits"
-       redef var name = "100 commits"
-       redef var desc = "Author 100 commits in the game."
-       redef var reward = 100
-       redef var threshold = 100
-end
-
-# Author 1 000 commits.
-class Player1KCommits
-       super PlayerXCommits
-
-       redef var id = "player_1000_commits"
-       redef var name = "1000 commits!!!"
-       redef var desc = "Author 1000 commits in the game."
-       redef var reward = 1000
-       redef var threshold = 1000
-end
-
-# Author 10 000 commits.
-class Player10KCommits
-       super PlayerXCommits
-
-       redef var id = "player_10000_commits"
-       redef var name = "10000 COMMITS!!!"
-       redef var desc = "Author 10000 commits in the game."
-       redef var reward = 10000
-       redef var threshold = 10000
-end
-
-#####################
-### Issue Comments
-#####################
-
-# Unlock achievement after X issue comments.
-#
-# Used to factorize behavior.
-abstract class PlayerXComments
-       super AchievementReactor
-
-       # Number of comments required to unlock the achievement.
-       var threshold: Int is noinit
-
-       redef fun react_event(game, event) do
-               if not event isa IssueCommentEvent then return
-               if not event.action == "created" then return
-               var player = event.comment.user.player(game)
-               if player.stats["comments"] == threshold then
-                       var a = new_achievement(game)
-                       player.unlock_achievement(a, event)
-               end
-       end
-end
-
-# Player author his first comment in issues.
-class Player1Comment
-       super PlayerXComments
-
-       redef var id = "player_1_comment"
-       redef var name = "From lurker to member"
-       redef var desc = "Comment on an issue."
-       redef var reward = 10
-       redef var threshold = 1
-end
-
-# Player author 100 issue comments.
-class Player100Comments
-       super PlayerXComments
-
-       redef var id = "player_100_comments"
-       redef var name = "Chatter"
-       redef var desc = "Comment 100 times on issues."
-       redef var reward = 100
-       redef var threshold = 100
-end
-
-# Player author 1000 issue comments.
-class Player1KComments
-       super PlayerXComments
-
-       redef var id = "player_1000_comments"
-       redef var name = "You sir, talk a lot!"
-       redef var desc = "Comment 1000 times on issues."
-       redef var reward = 1000
-       redef var threshold = 1000
-end
-
-# Ping @privat in a comment.
-class PlayerPingGod
-       super AchievementReactor
-
-       redef var id = "player_ping_god"
-       redef var name = "Ping god"
-       redef var desc = "Ping the owner of the repo for the first time."
-       redef var reward = 50
-
-       redef fun react_event(game, event) do
-               if not event isa IssueCommentEvent then return
-               var owner = game.repo.owner.login
-               if event.comment.body.has("@{owner}".to_re) then
-                       var player = event.comment.user.player(game)
-                       var a = new_achievement(game)
-                       player.unlock_achievement(a, event)
-               end
-       end
-end
-
-# Give your first +1
-class PlayerFirstReview
-       super AchievementReactor
-
-       redef var id = "player_first_review"
-       redef var name = "First +1"
-       redef var desc = "Give a +1 for the first time."
-       redef var reward = 10
-
-       redef fun react_event(game, event) do
-               if not event isa IssueCommentEvent then return
-               # FIXME use a more precise way to locate reviews
-               if event.comment.is_ack then
-                       var player = event.comment.user.player(game)
-                       var a = new_achievement(game)
-                       player.unlock_achievement(a, event)
-               end
-       end
-end
-
-# Talk about nitcoin in issue comments.
-class PlayerSaysNitcoin
-       super AchievementReactor
-
-       redef var id = "player_says_nitcoin"
-       redef var name = "Talking about money"
-       redef var desc = "Say something about nitcoins in a comment."
-       redef var reward = 10
-
-       redef fun react_event(game, event) do
-               if not event isa IssueCommentEvent then return
-               if event.comment.body.has("(n|N)itcoin".to_re) then
-                       var player = event.comment.user.player(game)
-                       var a = new_achievement(game)
-                       player.unlock_achievement(a, event)
-               end
-       end
-end
diff --git a/contrib/nitrpg/src/events.nit b/contrib/nitrpg/src/events.nit
deleted file mode 100644 (file)
index 08d387d..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-# This file is part of NIT ( http://www.nitlanguage.org ).
-#
-# Copyright 2014-2015 Alexandre Terrasa <alexandre@moz-code.org>
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# `nitrpg` game events.
-#
-# In this module we introduce the concept of `GameEvent`.
-# They can be attached to every GameEntities.
-module events
-
-import game
-
-redef class GameEntity
-
-       # Register a new game event for this entity.
-       fun add_event(event: GameEvent) do
-               event.owner = self
-               event.save
-       end
-
-       # List all events registered in this entity.
-       #
-       # This list is reloaded from game data each time its called.
-       #
-       # To add events see `add_event`.
-       fun load_events: Array[GameEvent] do
-               var req = new JsonObject
-               req["game"] = game.key
-               req["owner"] = key
-               var res = new Array[GameEvent]
-               for obj in game.db.collection("events").find_all(req) do
-                       res.add new GameEvent.from_json(game, obj)
-               end
-               (new EventTimeComparator).sort(res)
-               return res
-       end
-
-       # Load the event from its `id`.
-       #
-       # Looks for the event save file in game data.
-       # Returns `null` if the event cannot be found.
-       fun load_event(id: String): nullable GameEvent do
-               var req = new JsonObject
-               req["game"] = game.key
-               req["owner"] = key
-               req["internal_id"] = id
-               var res = game.db.collection("events").find(req)
-               if res != null then return new GameEvent.from_json(game, res)
-               return null
-       end
-end
-
-# An event that occurs in the `Game`.
-class GameEvent
-       super GameEntity
-
-       redef var collection_name = "events"
-
-       redef var game
-
-       # Entity this event belongs to.
-       var owner: nullable GameEntity = null
-
-       # String used to dissociate events in the display.
-       var kind: String
-
-       # GameEvents have raw data associated to them.
-       #
-       # These data are stored in a JsonObject.
-       var data: JsonObject is writable
-
-       # GameEvent uniq id used for storage.
-       var internal_id: String is noinit
-
-       redef var key = internal_id is lazy
-
-       # Date and time of the event.
-       var time: ISODate is noinit, writable
-
-       # An event initialized at now `time`.
-       init do
-               internal_id = "{get_time}{object_id}{100.rand}"
-               time = new ISODate
-       end
-
-       # Init `self` from a `json` object.
-       #
-       # Used to load events from json storage.
-       init from_json(game: Game, json: JsonObject) do
-               init(game, json["kind"].as(String), json["data"].as(JsonObject))
-               internal_id = json["internal_id"].as(String)
-               time = new ISODate.from_string(json["time"].as(String))
-       end
-
-       redef fun to_json_object do
-               var json = new JsonObject
-               json["internal_id"] = internal_id.to_s
-               json["kind"] = kind
-               json["time"] = time.to_s
-               json["data"] = data
-               json["game"] = game.key
-               var owner = self.owner
-               if owner != null then json["owner"] = owner.key
-               return json
-       end
-end
-
-# Compare `GameEvent` to sort them from the most recent to the older.
-class EventTimeComparator
-       super Comparator
-
-       redef type COMPARED: GameEvent
-
-       redef fun compare(a, b) do return b.time <=> a.time
-end
diff --git a/contrib/nitrpg/src/events_generator.nit b/contrib/nitrpg/src/events_generator.nit
deleted file mode 100644 (file)
index 9e5bf30..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-# This file is part of NIT ( http://www.nitlanguage.org ).
-#
-# Copyright 2014-2015 Alexandre Terrasa <alexandre@moz-code.org>
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Generate Github events from repo data.
-#
-# Mainly used for testing and history importation.
-module events_generator
-
-import github::events
-
-# Github events generator
-#
-# Generates events from repo data.
-class EventsGenerator
-
-       # API client used to get github data.
-       var api: GithubAPI
-
-       # Gen a fake id for events
-       fun gen_event_id: String do return get_time.to_s
-
-       # Issues
-
-       # Generate a new IssuesEvent from an issue.
-       fun issues_event(repo: Repo, action: String, issue: Issue): IssuesEvent do
-               return new IssuesEvent(gen_event_id, action, repo, issue)
-       end
-
-       # Generate a new IssuesEvent with an `opened` action.
-       fun issue_open(repo: Repo, issue: Issue): IssuesEvent do
-               return issues_event(repo, "opened", issue)
-       end
-
-       # Generate a new IssuesEvent with an `closed` action.
-       fun issue_close(repo: Repo, issue: Issue): IssuesEvent do
-               return issues_event(repo, "closed", issue)
-       end
-
-       # Generate a new IssuesEvent with an `reopened` action.
-       fun issue_reopen(repo: Repo, issue: Issue): IssuesEvent do
-               return issues_event(repo, "reopened", issue)
-       end
-
-       # Generate a new IssuesEvent from a IssueEvent.
-       fun issue_raw_event(repo: Repo, issue: Issue, event: IssueEvent): IssuesEvent do
-               return new IssuesEvent(event.id.to_s, event.event, repo, issue, event.labl, event.assignee)
-       end
-
-       # Generate a new IssueCommentEvent from a IssueComment.
-       fun issue_comment_event(repo: Repo, issue: Issue, comment: IssueComment): IssueCommentEvent do
-               return new IssueCommentEvent(gen_event_id, "created", repo, issue, comment)
-       end
-
-       # Pull requests
-
-       # Generate a new PullRequestEvent from a `pull` request.
-       fun pull_event(repo: Repo, action: String, pull: PullRequest): PullRequestEvent do
-               return new PullRequestEvent(gen_event_id, action, repo, pull.number, pull)
-       end
-
-       # Generate a new PullRequestEvent with an `opened` action.
-       fun pull_open(repo: Repo, pull: PullRequest): PullRequestEvent do
-               return pull_event(repo, "opened", pull)
-       end
-
-       # Generate a new PullRequestEvent with an `closed` action.
-       fun pull_close(repo: Repo, pull: PullRequest): PullRequestEvent do
-               return pull_event(repo, "closed", pull)
-       end
-
-       # Generate a new PullRequestEvent with an `reopened` action.
-       fun pull_reopen(repo: Repo, pull: PullRequest): PullRequestEvent do
-               return pull_event(repo, "reopened", pull)
-       end
-
-       # Generate a new PullRequestEvent from a IssueEvent.
-       fun pull_raw_event(repo: Repo, pull: PullRequest, event: IssueEvent): PullRequestEvent do
-               return new PullRequestEvent(event.id.to_s, event.event, repo, pull.number, pull)
-       end
-end
diff --git a/contrib/nitrpg/src/game.nit b/contrib/nitrpg/src/game.nit
deleted file mode 100644 (file)
index 5413f43..0000000
+++ /dev/null
@@ -1,337 +0,0 @@
-# This file is part of NIT ( http://www.nitlanguage.org ).
-#
-# Copyright 2014-2015 Alexandre Terrasa <alexandre@moz-code.org>
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# `nitrpg` game structures.
-#
-# Here we define the main game entities:
-#
-# * `Game` holds all the entities for a game and provides high level services.
-# * `Player` represents a `Github::User` which plays the `Game`.
-#
-# Developpers who wants to extend the game capabilities should look at
-# the `GameReactor` abstraction.
-module game
-
-import mongodb
-import github::events
-
-# An entity within a `Game`.
-#
-# All game entities can be saved in a json format.
-interface GameEntity
-       # The game instance containing `self`.
-       fun game: Game is abstract
-
-       # Collection `self` should be saved in.
-       fun collection_name: String is abstract
-
-       # Uniq key of this entity within the collection.
-       fun key: String is abstract
-
-       # Saves `self` in db.
-       fun save do game.db.collection(collection_name).save(to_json_object)
-
-       # Json representation of `self`.
-       fun to_json_object: JsonObject do
-               var json = new JsonObject
-               json["_id"] = key
-               return json
-       end
-
-       # Pretty print `self` to be displayed in a terminal.
-       fun pretty: String is abstract
-end
-
-# Holder for game data and main services.
-#
-# Game is a `GameEntity` so it can be saved.
-class Game
-       super GameEntity
-
-       redef fun game do return self
-
-       # We need a `GithubAPI` client to load Github data.
-       var api: GithubAPI
-
-       # A game takes place in a `github::Repo`.
-       var repo: Repo
-
-       # Game name
-       var name: String = repo.full_name is lazy
-
-       redef var key = name is lazy
-
-       # Mongo server url where this game data are stored.
-       var mongo_url = "mongodb://mongo:27017" is writable
-
-       # Mongo db client.
-       var client = new MongoClient(mongo_url) is lazy
-
-       # Mongo db name where this game data are stored.
-       var db_name = "nitrpg" is writable
-
-       # Mongo db instance for this game.
-       var db: MongoDb is lazy do return client.database(db_name)
-
-       redef var collection_name = "games"
-
-       # Init the Game and try to load saved data.
-       init from_mongo(api: GithubAPI, repo: Repo) do
-               init(api, repo)
-               var req = new JsonObject
-               req["name"] = repo.full_name
-               var res = db.collection("games").find(req)
-               if res != null then from_json(res)
-       end
-
-       # Init `self` from a JsonObject.
-       #
-       # Used to load entities from saved data.
-       fun from_json(json: JsonObject) do end
-
-       redef fun to_json_object do
-               var json = super
-               json["name"] = name
-               return json
-       end
-
-       # Create a player from a Github `User`.
-       #
-       # Or return the existing one from game data.
-       fun add_player(user: User): Player do
-               # check if player already exists
-               var player = load_player(user.login)
-               if player != null then return player
-               # create and store new player
-               player = new Player(self, user.login)
-               player.save
-               return player
-       end
-
-       # Get a Player from his `name` or null if no player was found.
-       #
-       # Looks for the player save file in game data.
-       #
-       # Returns `null` if the player cannot be found.
-       # In this case, the player can be created with `add_player`.
-       fun load_player(name: String): nullable Player do
-               var req = new JsonObject
-               req["name"] = name
-               req["game"] = game.key
-               var res = db.collection("players").find(req)
-               if res != null then return new Player.from_json(self, res)
-               return null
-       end
-
-       # List known players.
-       #
-       # This list is reloaded from game data each time its called.
-       #
-       # To add players see `add_player`.
-       fun load_players: MapRead[String, Player] do
-               var req = new JsonObject
-               req["game"] = game.key
-               var res = new HashMap[String, Player]
-               for obj in db.collection("players").find_all(req) do
-                       var player = new Player.from_json(self, obj)
-                       res[player.name] = player
-               end
-               return res
-       end
-
-       # Return a list of player name associated to their rank in the game.
-       fun player_ranking: MapRead[String, Int] do
-               var arr = load_players.values.to_a
-               var res = new HashMap[String, Int]
-               (new PlayerCoinComparator).sort(arr)
-               var rank = 1
-               for player in arr do
-                       res[player.name] = rank
-                       rank += 1
-               end
-               return res
-       end
-
-       # Erase all saved data for this game.
-       fun clear do db.collection(collection_name).remove(to_json_object)
-
-       # Verbosity level used fo stdout.
-       #
-       # * `-1` quiet
-       # * `0` error and warnings
-       # * `1` info
-       # * `2` debug
-       var verbose_lvl = 0 is writable
-
-       # Display `msg` if `lvl` >= `verbose_lvl`
-       fun message(lvl: Int, msg: String) do
-               if lvl > verbose_lvl then return
-               print msg
-       end
-
-       redef fun pretty do
-               var res = new FlatBuffer
-               res.append "-------------------------\n"
-               res.append "{repo.full_name}\n"
-               res.append "-------------------------\n"
-               res.append "# {load_players.length} players \n"
-               return res.write_to_string
-       end
-end
-
-# Players can battle on nitrpg for nitcoins and glory.
-#
-# A `Player` is linked to a `Github::User`.
-class Player
-       super GameEntity
-
-       # Stored in collection `players`.
-       redef var collection_name = "players"
-
-       redef var game
-
-       # FIXME contructor should be private
-
-       # Player name.
-       #
-       # This is the unic key for this player.
-       # Should be equal to the associated `Github::User::login`.
-       #
-       # The name is also used to load the user data lazilly from Github API.
-       var name: String
-
-       redef var key = name is lazy
-
-       # Player amount of nitcoins.
-       #
-       # Nitcoins is the currency used in nitrpg.
-       # They can be obtained by performing actions on the `Game::Repo`.
-       var nitcoins: Int = 0 is public writable
-
-       # `Github::User` linked to this player.
-       var user: User is lazy do
-               var user = game.api.load_user(name)
-               assert user isa User
-               return user
-       end
-
-       # Init `self` from a `json` object.
-       #
-       # Used to load players from saved data.
-       init from_json(game: Game, json: JsonObject) do
-               init(game, json["name"].as(String))
-               nitcoins = json["nitcoins"].as(Int)
-       end
-
-       redef fun to_json_object do
-               var json = super
-               json["game"] = game.key
-               json["name"] = name
-               json["nitcoins"] = nitcoins
-               return json
-       end
-
-       redef fun pretty do
-               var res = new FlatBuffer
-               res.append "-- {name} ({nitcoins} $)\n"
-               return res.write_to_string
-       end
-
-       redef fun to_s do return name
-end
-
-redef class User
-       # The player linked to `self`.
-       fun player(game: Game): Player do
-               var player = player_cache.get_or_null(game)
-               if player != null then return player
-               player = game.load_player(login)
-               if player == null then player = game.add_player(self)
-               player_cache[game] = player
-               return player
-       end
-
-       private var player_cache = new HashMap[Game, Player]
-end
-
-# A GameReactor reacts to event sent by a `Github::HookListener`.
-#
-# Subclasses of `GameReactor` are implemented to handle all kind of
-# `GithubEvent`.
-# Depending on the received event, the reactor is used to update game data.
-#
-# Reactors are mostly used with a `Github::HookListener` that dispatchs received
-# events from the Github API.
-#
-# Example:
-#
-# ~~~
-# import github::hooks
-#
-# # Reactor that prints received events in console.
-# class PrintReactor
-#      super GameReactor
-#
-#      redef fun react_event(game, e) do print e
-# end
-#
-# # Hook listener that redirect events to reactors.
-# class RpgHookListener
-#    super HookListener
-#
-#      redef fun apply_event(event) do
-#              var game = new Game(api, event.repo)
-#              var reactor = new PrintReactor
-#              reactor.react_event(game, event)
-#      end
-# end
-# ~~~
-#
-# See module `reactors` and `listener` for more examples.
-interface GameReactor
-
-       # Reacts to this `event` and update `game` accordingly.
-       #
-       # Concrete `GameReactor` implement this method to update game data
-       # for each specific GithubEvent.
-       fun react_event(game: Game, event: GithubEvent) is abstract
-end
-
-# utils
-
-# Sort games by descending number of players.
-#
-# The first in the list is the game with the more players.
-class GamePlayersComparator
-       super Comparator
-
-       redef type COMPARED: Game
-
-       redef fun compare(a, b) do
-               return b.load_players.length <=> a.load_players.length
-       end
-end
-
-# Sort players by descending number of nitcoins.
-#
-# The first in the list is the player with the more of nitcoins.
-class PlayerCoinComparator
-       super Comparator
-
-       redef type COMPARED: Player
-
-       redef fun compare(a, b) do return b.nitcoins <=> a.nitcoins
-end
diff --git a/contrib/nitrpg/src/listener.nit b/contrib/nitrpg/src/listener.nit
deleted file mode 100644 (file)
index 8bee99b..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-# This file is part of NIT ( http://www.nitlanguage.org ).
-#
-# Copyright 2014-2015 Alexandre Terrasa <alexandre@moz-code.org>
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# This tool is runned to listen to `Github::Event` and update the game.
-module listener
-
-import reactors
-import achievements
-import github::hooks
-
-# `HookListener` that redirects events to a `Game` instance.
-class RpgHookListener
-   super HookListener
-
-       # Registered reactors list.
-       var reactors = new Array[GameReactor]
-
-       # Dispatch event to registered `reactors`.
-       redef fun apply_event(event) do
-               var game = new Game(api, event.repo)
-               # TODO handle verbosity with opts
-               game.verbose_lvl = 1
-               game.message(1, "Received event {event} for {game.repo.full_name}")
-               for reactor in reactors do
-                       game.message(2, "Apply reactor {reactor} on {event}")
-                       reactor.react_event(game, event)
-               end
-       end
-
-       # Register a reactor for this listener.
-       fun add_reactor(reactors: GameReactor...) do self.reactors.add_all reactors
-end
-
-if args.length != 2 then
-       print "Error: missing argument"
-       print ""
-       print "Usage:"
-       print "listener <host> <port>"
-       exit 1
-end
-
-var host = args[0]
-var port = args[1].to_i
-
-var api = new GithubAPI(get_github_oauth)
-
-var l = new RpgHookListener(api, host, port)
-l.add_reactor(new StatisticsReactor, new PlayerReactor)
-l.add_reactor(new Player1Issue, new Player100Issues, new Player1KIssues)
-l.add_reactor(new Player1Pull, new Player100Pulls, new Player1KPulls)
-l.add_reactor(new Player1Commit, new Player100Commits, new Player1KCommits)
-l.add_reactor(new IssueAboutNitdoc, new IssueAboutFFI)
-l.add_reactor(new Player1Comment, new Player100Comments, new Player1KComments)
-l.add_reactor(new PlayerPingGod, new PlayerFirstReview, new PlayerSaysNitcoin)
-
-print "Listening events on {host}:{port}"
-l.listen
diff --git a/contrib/nitrpg/src/reactors.nit b/contrib/nitrpg/src/reactors.nit
deleted file mode 100644 (file)
index 616bd8a..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-# This file is part of NIT ( http://www.nitlanguage.org ).
-#
-# Copyright 2014-2015 Alexandre Terrasa <alexandre@moz-code.org>
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Various implementations of `GameReactor` can be found here.
-module reactors
-
-import events
-
-# Reacts to event that can affect players (like giving nitcoins).
-class PlayerReactor
-       super GameReactor
-
-       # Nitcoins rewarded when the player opens a new pull request.
-       var nc_pull_open = 10
-
-       # Nitcoins rewarded when the player reviews a pull request.
-       var nc_pull_review = 2
-
-       # Nitcoins rewarded when the player has a commit merged.
-       var nc_commit_merged = 1
-
-       redef fun react_event(game, e) do e.react_player_event(self, game)
-end
-
-redef class GithubEvent
-       # Reacts to a player related event.
-       #
-       # Called by `PlayerReactor::react_event`.
-       # No-op by default.
-       private fun react_player_event(reactor: PlayerReactor, game: Game) do end
-
-       # Generates a GameEvent preinitialized for a reward event.
-       private fun player_reward_event(kind: String, player: Player, reward: Int): GameEvent do
-               var obj = new JsonObject
-               obj["player"] = player.name
-               obj["reward"] = reward
-               obj["github_event"] = self
-               var event = new GameEvent(player.game, kind, obj)
-               player.game.add_event(event)
-               return event
-       end
-end
-
-redef class PullRequestEvent
-
-       # Rewards player for opened pull requests.
-       redef fun react_player_event(r, game) do
-               if action == "opened" or action == "reopened" then
-                       react_pull_open(r, game)
-               else if action == "closed" then
-                       react_pull_close(r, game)
-               end
-       end
-
-       private fun react_pull_open(r: PlayerReactor, game: Game) do
-               var player = pull.user.player(game)
-               player.nitcoins += r.nc_pull_open
-               player.save
-               var event = player_reward_event("pull_open", player, r.nc_pull_open)
-               player.add_event(event)
-       end
-
-       private fun react_pull_close(r: PlayerReactor, game: Game) do
-               var player = pull.user.player(game)
-               var reward
-               var event
-               if pull.merged then
-                       reward = pull.commits * r.nc_commit_merged
-                       event = player_reward_event("pull_merged", player, reward)
-               else
-                       reward = -r.nc_pull_open
-                       event = player_reward_event("pull_closed", player, reward)
-               end
-               player.nitcoins += reward
-               player.save
-               player.add_event(event)
-       end
-end
-
-redef class IssueCommentEvent
-
-       # Rewards player for review comments.
-       #
-       # TODO only give nitcoins if reviewers < 2
-       # TODO give more points to first reviewer
-       redef fun react_player_event(r, game) do
-               if comment.is_ack then
-                       react_player_review(r, game)
-               end
-       end
-
-       # TODO same player should not be authorized to review multiple times? How to handle rerols?
-       private fun react_player_review(r: PlayerReactor, game: Game) do
-               if issue.state == "closed" then return
-               var player = comment.user.player(game)
-               if issue.user == player.user then return
-               player.nitcoins += r.nc_pull_review
-               player.save
-               var event = player_reward_event("pull_review", player, r.nc_pull_review)
-               player.add_event(event)
-       end
-end
diff --git a/contrib/nitrpg/src/statistics.nit b/contrib/nitrpg/src/statistics.nit
deleted file mode 100644 (file)
index 764616f..0000000
+++ /dev/null
@@ -1,282 +0,0 @@
-# This file is part of NIT ( http://www.nitlanguage.org ).
-#
-# Copyright 2014-2015 Alexandre Terrasa <alexandre@moz-code.org>
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Statistics about the Game.
-#
-# This module uses `GameReactor` to extract statistics about the game from
-# triggered `Github::Event`.
-module statistics
-
-import game
-import github::hooks
-import counter
-
-redef class GameEntity
-
-       # Statistics manager for this entity.
-       fun stats: GameStatsManager is abstract
-end
-
-redef class Game
-
-       redef var stats is lazy do return new GameStatsManager(game, self)
-
-       redef fun pretty do
-               var res = new FlatBuffer
-               res.append super
-               res.append "# stats:\n"
-               res.append stats.pretty
-               return res.write_to_string
-       end
-
-       redef fun save do
-               super
-               stats.save
-       end
-end
-
-redef class Player
-
-       redef var stats is lazy do return new GameStatsManager(game, self)
-
-       redef fun nitcoins do return stats["nitcoins"]
-       redef fun nitcoins=(nc) do stats["nitcoins"] = nc
-
-       redef fun pretty do
-               var res = new FlatBuffer
-               res.append super
-               res.append "# stats:\n"
-               res.append stats.pretty
-               return res.write_to_string
-       end
-
-       redef fun save do
-               super
-               stats.save
-       end
-end
-
-# Store game stats for defined period.
-class GameStatsManager
-       super GameEntity
-       super Counter[String]
-
-       redef var game
-
-       # The GameEntity monitored by these statistics.
-       var owner: GameEntity
-
-       # Current date to extract stats
-       private var date = new Tm.gmtime
-
-       # Returns the `GameStats` instance for the overall statistics.
-       var overall: GameStats = load_stats_for("all") is lazy
-
-       # Returns the `GameStats` instance for the current year statistics.
-       var yearly: GameStats = load_stats_for(date.strftime("%Y")) is lazy
-
-       # Returns the `GameStats` instance for the current month statistics.
-       var monthly: GameStats = load_stats_for(date.strftime("%Y-%m")) is lazy
-
-       # Returns the `GameStats` instance for the current day statistics.
-       var daily: GameStats = load_stats_for(date.strftime("%Y-%m-%d")) is lazy
-
-       # Returns the `GameStats` instance for the current week statistics.
-       var weekly: GameStats = load_stats_for(date.strftime("%Y-W%U")) is lazy
-
-       # Load statistics for a `period` key.
-       fun load_stats_for(period: String): GameStats do
-               var req = new JsonObject
-               req["period"] = period
-               req["owner"] = owner.key
-               var obj = game.db.collection("statistics").find(req)
-               if obj isa JsonObject then
-                       return new GameStats.from_json(game, period, owner, obj)
-               else
-                       return new GameStats(game, period, owner)
-               end
-       end
-
-       redef fun [](key) do return overall[key]
-
-       redef fun []=(key, value) do
-               overall[key] = value
-               yearly[key] = value
-               monthly[key] = value
-               daily[key] = value
-               weekly[key] = value
-       end
-
-       redef fun inc(e) do
-               overall.inc(e)
-               yearly.inc(e)
-               monthly.inc(e)
-               daily.inc(e)
-               weekly.inc(e)
-       end
-
-       redef fun dec(e) do
-               overall.dec(e)
-               yearly.dec(e)
-               monthly.dec(e)
-               daily.dec(e)
-               weekly.dec(e)
-       end
-
-       redef fun save do
-               overall.save
-               yearly.save
-               monthly.save
-               daily.save
-               weekly.save
-       end
-
-       redef fun pretty do return overall.pretty
-end
-
-# Game statistics structure that can be saved as a `GameEntity`.
-class GameStats
-       super GameEntity
-       super Counter[String]
-
-       redef var game
-
-       redef var collection_name = "statistics"
-
-       # The period these stats are about.
-       var period: String
-
-       # The game entity these stats are about.
-       var owner: GameEntity
-
-       redef var key = "{owner.key}-{period}" is lazy
-
-       # Load `self` from saved data.
-       init from_json(game: Game, period: String, owner: GameEntity, json: JsonObject) do
-               init(game, period, owner)
-               var values = json.get_or_null("values")
-               if not values isa JsonObject then return
-               for k, v in values do self[k] = v.as(Int)
-       end
-
-       redef fun to_json_object do
-               var obj = super
-               obj["period"] = period
-               obj["owner"] = owner.key
-               var values = new JsonObject
-               values.add_all(self)
-               obj["values"] = values
-               return obj
-       end
-
-       redef fun pretty do
-               var res = new FlatBuffer
-               for k, v in self do
-                       res.append "# {v} {k}\n"
-               end
-               return res.write_to_string
-       end
-end
-
-# `GameReactor` that computes statistics about the game.
-class StatisticsReactor
-       super GameReactor
-
-       redef fun react_event(game, e) do e.react_stats_event(game)
-end
-
-redef class GithubEvent
-       # Reacts to a statistics related event.
-       #
-       # Called by `StatisticsReactor::react_event`.
-       # No-op by default.
-       private fun react_stats_event(game: Game) do end
-end
-
-redef class IssuesEvent
-
-       # Count opened and closed issues.
-       redef fun react_stats_event(game) do
-               var player = issue.user.player(game)
-               if action == "opened" then
-                       game.stats.inc("issues")
-                       game.stats.inc("issues_open")
-                       game.save
-                       player.stats.inc("issues")
-                       player.stats.inc("issues_open")
-                       player.save
-               else if action == "reopened" then
-                       game.stats.inc("issues_open")
-                       game.save
-                       player.stats.inc("issues_open")
-                       player.save
-               else if action == "closed" then
-                       game.stats.dec("issues_open")
-                       game.save
-                       player.stats.dec("issues_open")
-                       player.save
-               end
-       end
-end
-
-redef class PullRequestEvent
-
-       # Count opened and closed pull requests.
-       redef fun react_stats_event(game) do
-               var player = pull.user.player(game)
-               if action == "opened" then
-                       game.stats.inc("pulls")
-                       game.stats.inc("pulls_open")
-                       game.save
-                       player.stats.inc("pulls")
-                       player.stats.inc("pulls_open")
-                       player.save
-               else if action == "reopened" then
-                       game.stats.inc("pulls_open")
-                       game.save
-                       player.stats.inc("pulls_open")
-                       player.save
-               else if action == "closed" then
-                       game.stats.dec("pulls_open")
-                       player.stats.dec("pulls_open")
-                       if pull.merged then
-                               game.stats["commits"] += pull.commits
-                               player.stats["commits"] += pull.commits
-                       end
-                       game.save
-                       player.save
-               end
-       end
-end
-
-redef class IssueCommentEvent
-
-       # Count posted comments
-       redef fun react_stats_event(game) do
-               if action == "created" then
-                       var player = comment.user.player(game)
-                       game.stats.inc("comments")
-                       player.stats.inc("comments")
-                       # FIXME use a more precise way to locate reviews
-                       if comment.is_ack then
-                               game.stats.inc("reviews")
-                               player.stats.inc("reviews")
-                       end
-                       game.save
-                       player.save
-               end
-       end
-end
diff --git a/contrib/nitrpg/src/templates/panels.nit b/contrib/nitrpg/src/templates/panels.nit
deleted file mode 100644 (file)
index 8f27a5f..0000000
+++ /dev/null
@@ -1,569 +0,0 @@
-# This file is part of NIT ( http://www.nitlanguage.org ).
-#
-# Copyright 2014-2015 Alexandre Terrasa <alexandre@moz-code.org>
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Panels templates for `nitpg`.
-module panels
-
-import templates_events
-import markdown
-
-# A panel can be displayed in a html page.
-#
-# This display a Bootstrap panel.
-class Panel
-       super Template
-
-       redef fun rendering do
-               add """<div class="panel panel-default">
-                           <div class="panel-heading">
-                                <h3 class="panel-title">"""
-               render_title
-               add """  </h3>
-                           </div>
-                          <div class="panel-body">"""
-               render_body
-               add """</div>
-                         </div>"""
-       end
-
-       # Render the panel title.
-       # Betweem `<h4>` tags.
-       fun render_title do end
-
-       # Render the panel body.
-       fun render_body do end
-end
-
-# A panel that contain only a table as body.
-class TablePanel
-       super Panel
-
-       redef fun rendering do
-               add """<div class="panel panel-default">
-                           <div class="panel-heading">
-                            <h3 class="panel-title">"""
-               render_title
-               add """
-                            </h3>
-                           </div>"""
-               render_body
-               add """</div>"""
-       end
-end
-
-# Display an error message within a panel.
-class ErrorPanel
-       super Panel
-
-       redef fun rendering do
-               add """
-<div class="panel panel-danger">
-       <div class="panel-heading">
-               <h3 class="panel-title">"""
-               render_title
-               add """
-               </h3>
-       </div>
-       <div class="panel-body">"""
-               render_body
-               add """
-       </div>
-</div>
-"""
-       end
-
-       # The error message to display as panel body.
-       var msg: String
-
-       redef fun render_title do
-               add "<span class=\"glyphicon glyphicon-warning-sign\"></span>&nbsp;&nbsp;"
-               add "Error"
-       end
-
-       redef fun render_body do
-               add msg.html_escape
-       end
-
-end
-
-# A panel that display a markdown content rendered as HTML.
-class MDPanel
-       super Panel
-
-       # Markdown text to display.
-       var text: String
-
-       redef fun rendering do
-               add """<div class="panel">
-                           <div class="panel-body">{{{text.md_to_html}}}</div>
-                         </div>"""
-       end
-end
-
-# Display a list of active game.
-#
-# Used for NitRPG homepage.
-class GamesShortListPanel
-       super Panel
-
-       # Root url used for links.
-       var root_url: String
-
-       # List of NitRPG games to display.
-       var games: Array[Game]
-
-       redef fun render_title do
-               add "<span class=\"glyphicon glyphicon-home\"></span>&nbsp;&nbsp;"
-               add "<a href=\"{root_url}/games\">Active games</a>"
-       end
-
-       redef fun render_body do
-               if games.is_empty then
-                       add "<em>No game yet...</em>"
-                       return
-               end
-               var sorted = games.to_a
-               (new GamePlayersComparator).sort(sorted)
-               for game in sorted do
-                       add "{game.link} ({game.load_players.length} players)<br>"
-               end
-       end
-end
-
-# A panel that display a list of player in a repo.
-class GamesListPanel
-       super GamesShortListPanel
-       super TablePanel
-
-       redef fun render_title do
-               add "<span class=\"glyphicon glyphicon-home\"></span>&nbsp;&nbsp;"
-               add "<a href=\"{root_url}/games\">Active games</a>"
-       end
-
-       redef fun render_body do
-               if games.is_empty then
-                       add "<div class=\"panel-body\">"
-                       add "<em>No player yet...</em>"
-                       add "</div>"
-                       return
-               end
-               var sorted = games.to_a
-               (new GamePlayersComparator).sort(sorted)
-               add """<table class="table table-striped table-hover">
-                           <tr>
-                                <th>Game</th>
-                                <th>Players</th>
-                                <th>Achievements</th>
-                               </tr>"""
-               for game in sorted do
-                       add "<tr>"
-                       add " <td>{game.link}</td>"
-                       add " <td>{game.load_players.length}</td>"
-                       add " <td>{game.load_achievements.length}</td>"
-                       add "</tr>"
-               end
-               add "</table>"
-       end
-end
-
-# A panel that display repo statistics.
-class GameStatusPanel
-       super Panel
-
-       # Repo to display.
-       var game: Game
-
-       redef fun render_title do
-               add "<span class=\"glyphicon glyphicon-home\"></span>&nbsp;&nbsp;"
-               add "{game.link}"
-       end
-
-       redef fun render_body do
-               add "<strong class=\"text-success\">{game.load_players.length}</strong>"
-               add " <a href=\"{game.url}/players\">players</a><br>"
-               add "<strong class=\"text-success\">{game.stats["achievements"]}</strong>"
-               add " <a href=\"{game.url}/achievements\">achievements</a><br><br>"
-               add "<strong class=\"text-success\">{game.stats["pulls"]}</strong> pull requests"
-               add " (<strong>{game.stats["pulls_open"]}</strong> open)<br>"
-               add "<strong class=\"text-success\">{game.stats["issues"]}</strong> issues"
-               add " (<strong>{game.stats["issues_open"]}</strong> open)<br>"
-               add "<strong class=\"text-success\">{game.stats["commits"]}</strong> commits"
-       end
-end
-
-# Player status panel.
-class PlayerStatusPanel
-       super Panel
-
-       # Game instance.
-       var game: Game
-
-       # Target player.
-       var player: Player
-
-       redef fun render_title do
-               add "<a href=\"{player.url}\">"
-               add " <img class=\"img-circle\" style=\"width: 30px\""
-               add "   src=\"{player.user.avatar_url or else "#"}\" alt=\"{player.name}\">"
-               add "</a>&nbsp;&nbsp;{player.link}"
-       end
-
-       redef fun render_body do
-               var ranking = game.player_ranking
-               # TODO player.rank
-               add "<p class=\"lead\">ranked "
-               add " <span class=\"text-success\"># {ranking[player.name]}</span></p>"
-               add "<strong class=\"text-success\">{player.nitcoins}</strong> nitcoins<br><br>"
-               add "<strong class=\"text-success\">{player.stats["achievements"]}</strong> achievements<br><br>"
-               add "<strong>{player.stats["pulls"]}</strong> pull requests<br>"
-               add "<strong>{player.stats["issues"]}</strong> issues<br>"
-               add "<strong>{player.stats["commits"]}</strong> commits"
-       end
-end
-
-# A panel that display a list of player in a repo.
-class ShortListPlayersPanel
-       super Panel
-
-       # Game instance.
-       var game: Game
-
-       redef fun render_title do
-               add "<span class=\"glyphicon glyphicon-user\"></span>&nbsp;&nbsp;"
-               add "<a href=\"{game.url}/players\">Players</a>"
-       end
-
-       redef fun render_body do
-               var players = game.load_players.values.to_a
-               if players.is_empty then
-                       add "<em>No player yet...</em>"
-                       return
-               end
-               (new PlayerCoinComparator).sort(players)
-               for player in players do
-                       add "{player.nitcoins} - {player.link}<br>"
-               end
-       end
-end
-
-# A panel that display a list of player in a repo.
-class ListPlayersPanel
-       super TablePanel
-
-       # Game instance.
-       var game: Game
-
-       redef fun render_title do
-               add "<span class=\"glyphicon glyphicon-user\"></span>&nbsp;&nbsp;"
-               add "<a href=\"{game.url}/players\">Players</a>"
-       end
-
-       redef fun render_body do
-               var players = game.load_players.values.to_a
-               (new PlayerCoinComparator).sort(players)
-               if players.is_empty then
-                       add "<div class=\"panel-body\">"
-                       add "<em>No player yet...</em>"
-                       add "</div>"
-                       return
-               end
-               add """<table class="table table-striped table-hover">
-                           <tr>
-                                <th>#</th>
-                                <th>Player</th>
-                                <th>Nitcoins</th>
-                               </tr>"""
-               var rank = 1
-               for player in players do
-                       add "<tr>"
-                       add " <td>{rank}</td>"
-                       add " <td>{player.link}</td>"
-                       add " <td>{player.nitcoins}</td>"
-                       add "</tr>"
-                       rank += 1
-               end
-               add "</table>"
-       end
-end
-
-# A panel that display the podium.
-class PodiumPanel
-       super Panel
-
-       # Game instance.
-       var game: Game
-
-       redef fun render_title do
-               add "<span class=\"glyphicon glyphicon-stats\"></span>&nbsp;&nbsp;Hall of fame"
-       end
-
-       redef fun render_body do
-               var players = game.load_players.values.to_a
-               (new PlayerCoinComparator).sort(players)
-               if players.is_empty then
-                       add "<em>No players yet...</em>"
-                       return
-               end
-               add """
-                       <div class="container-fluid">
-                               <div id="podium" class="row row-sm-height">"""
-               var max = players.first.nitcoins
-               var orders = [3, 1, 0, 2, 4]
-               for order in orders do
-                       if order >= players.length then continue
-                       var player = players[order]
-                       var size = 0
-                       if max > 0 then size = player.nitcoins * 300 / max
-                       add """
-                               <div class="col-xs-2 col-xs-height col-xs-offset-{{{order}}} col-bottom"
-                                       style="text-align: center;">
-                                       <p>
-                                               <a href="{{{player.url}}}">
-                                                       <img class="img-circle" style="width: 80px"
-                                                               src="{{{player.user.avatar_url or else "#"}}}" alt="{{{player.name}}}">
-                                               </a>
-                                       </p>
-                                       <p>{{{player.link}}}</p>
-                                       <p>{{{player.nitcoins}}}</p>
-                                       <div class=" progress-bar-warning progress-bar-striped"
-                                               style="height: {{{size}}}px;"></div>
-                               </div>"""
-               end
-               add """
-                               </div>
-                       </div>"""
-       end
-end
-
-# A `Panel` that displays the list of PR to review for a `Player`.
-class PlayerReviewsPanel
-       super Panel
-
-       # Repo to display.
-       var game: Game
-
-       # Player to display customized list for.
-       var player: Player
-
-       redef fun render_title do
-               add "<span class=\"glyphicon glyphicon-check\"></span>&nbsp;&nbsp;"
-               add "Review pull requests and comment issues to gain nitcoins!"
-       end
-
-       redef fun render_body do
-               var q = "is:open label:need_review sort:updated-asc " +
-                       "-involves:{player.name}"
-
-               var q2 = "is:open label:request_for_comments sort:updated-asc " +
-                       "-involves:{player.name}"
-
-               var issues = new ArraySet[Issue]
-               issues.add_all game.api.search_repo_issues(game.repo, q)
-               issues.add_all game.api.search_repo_issues(game.repo, q2)
-               if issues.is_empty then
-                       add "<em>No pull request or issue to review yet...</em>"
-                       return
-               end
-               for issue in issues do
-                       var user = issue.user
-                       var uplay = user.player(game)
-                       add """<div class="media">
-                               <a class="media-left" href="{{{uplay.url}}}">
-                                        <img class=\"img-circle\" style="width:50px"
-                                                src="{{{user.avatar_url or else "#"}}}" alt="{{{uplay.name}}}">
-                                       </a>
-                                       <div class="media-body">
-                                        <h4 class="media-heading">
-                                               {{{issue.link}}} {{{issue.title}}}
-                                       </h4>
-                                        <span class="text-muted">opened by </span>
-                                        {{{uplay.link}}}
-                                       </div>
-                                  </div>"""
-               end
-       end
-end
-
-# A `Panel` that displays the work assigned or tagged.
-class PlayerWorkPanel
-       super Panel
-
-       # Repo to display.
-       var game: Game
-
-       # Player to display customized list for.
-       var player: Player
-
-       redef fun render_title do
-               add "<span class=\"glyphicon glyphicon-check\"></span>&nbsp;&nbsp;"
-               add "Do your tasks to gain nitcoins!"
-       end
-
-       redef fun render_body do
-               var q = "is:open label:need_work sort:updated-asc author:{player.name}"
-               var q2 = "is:open sort:updated-asc assignee:{player.name}"
-
-               var issues = new ArraySet[Issue]
-               issues.add_all game.api.search_repo_issues(game.repo, q)
-               issues.add_all game.api.search_repo_issues(game.repo, q2)
-               if issues.is_empty then
-                       add "<em>No work to do yet...</em>"
-                       return
-               end
-               for issue in issues do
-                       var user = issue.user
-                       var uplay = user.player(game)
-                       add """<div class="media">
-                               <a class="media-left" href="{{{uplay.url}}}">
-                                        <img class=\"img-circle\" style="width:50px"
-                                                src="{{{user.avatar_url or else "#"}}}" alt="{{{uplay.name}}}">
-                                       </a>
-                                       <div class="media-body">
-                                        <h4 class="media-heading">
-                                               {{{issue.link}}} {{{issue.title}}}
-                                       </h4>
-                                        <span class="text-muted">opened by </span>
-                                        {{{uplay.link}}}
-                                       </div>
-                                  </div>"""
-               end
-       end
-end
-
-# A `Panel` that displays a pagined list of events stored in the `entity`.
-#
-# This way the panel can be used to view events stored under `Game`, `Player`...
-class EventListPanel
-       super Panel
-
-       # Entity to load the events from.
-       var entity: GameEntity
-
-       # Number of events to display.
-       var limit: Int
-
-       # From where to start?
-       var from: Int
-
-       redef fun render_title do
-               add "<span class=\"glyphicon glyphicon-flash\"></span>&nbsp;&nbsp;"
-               add "Last events"
-       end
-
-       redef fun render_body do
-               var events = entity.load_events
-               if events.is_empty then
-                       add "<em>No event yet...</em>"
-                       return
-               end
-               # check input
-               if limit < 0 then limit = 10
-               if from < 0 then from = 0
-               # display events
-               for i in [from .. from + limit] do
-                       if i >= events.length then break
-                       add events[i].tpl_event.media_item
-               end
-               # pagination
-               if limit > events.length then return
-               add "<hr>"
-               add """<div class="btn-group" role="group">"""
-               if from > 0 then
-                       add """<a class="btn btn-default" role="button"
-                                       href="?pfrom={{{from - limit}}}&plimit={{{limit}}}">
-                                    <span class=\"glyphicon glyphicon-chevron-left\"></span></a>"""
-               end
-               if from + limit < events.length then
-                       add """
-                         <a class="btn btn-default" role="button"
-                                  href="?pfrom={{{from + limit}}}&plimit={{{limit}}}">
-                                   <span class=\"glyphicon glyphicon-chevron-right\"></span></a>"""
-               end
-               add "</div>"
-       end
-end
-
-# Achievement unlocked list panel.
-class AchievementsListPanel
-       super Panel
-
-       # Entity to load the events from.
-       var entity: GameEntity
-
-       redef fun render_title do
-               add "<span class=\"glyphicon glyphicon-list\"></span>&nbsp;&nbsp;"
-               add "Achievements unlocked"
-       end
-
-       redef fun render_body do
-               var achs = entity.load_achievements.values.to_a
-               if achs.is_empty then
-                       add "<em>No achievement yet...</em>"
-                       return
-               end
-               for ach in achs do add ach.list_item
-       end
-end
-
-# Achievement detail panel.
-class AchievementPanel
-       super Panel
-
-       # Achievement to display.
-       var achievement: Achievement
-
-       redef fun render_title do
-               add "<span class=\"glyphicon glyphicon-check\"></span>&nbsp;&nbsp;"
-               add "Achievement details"
-       end
-
-       redef fun render_body do
-               add """<p class=\"lead\">
-                               <span class="badge progress-bar-success"
-                                style="vertical-align: middle">+{{{achievement.reward}}}</span>
-                       {{{achievement.name}}}
-                      </p>
-                      <p><strong>{{{achievement.desc}}}</strong></p>"""
-
-               var events = achievement.load_events
-
-               if events.is_empty then
-                       add "<em>Never unlocked...</em>"
-                       return
-               end
-
-               var event = events.last
-               var tpl = event.tpl_event
-               var player = tpl.player
-               add "<hr>"
-               add """<div class="media">
-                       <a class="media-left" href="{{{player.url}}}">
-                                <span class="badge progress-bar-warning" style="position: absolute">#1</span>
-                        <img class=\"img-circle\" style="width:50px"
-                                        src="{{{player.user.avatar_url or else "#"}}}" alt="{{{player.name}}}">
-                       </a>
-                               <div class="media-body">
-                                <h4 class="media-heading">Unlocked first by {{{player.link}}}</h4>
-                                <span class="text-muted">at {{{event.time}}} </span>
-                               </div>
-                          </div>"""
-
-               if events.length > 1 then
-                       add """<p><br>Also unlocked by <strong class="text-success">
-                       {{{events.length}}} players</strong>.</p>"""
-               end
-       end
-end
diff --git a/contrib/nitrpg/src/templates/templates.nit b/contrib/nitrpg/src/templates/templates.nit
deleted file mode 100644 (file)
index 92a4915..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-# This file is part of NIT ( http://www.nitlanguage.org ).
-#
-# Copyright 2014-2015 Alexandre Terrasa <alexandre@moz-code.org>
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Templates that compose the `nitrpg` site.
-module templates
-
-import panels
-
-# A page in the nitrp site.
-class NitRpgPage
-       super Template
-
-       # URL used as prefix for all the links generated in this page.
-       var root_url: String
-
-       # Breadcrumbs to this page if any.
-       var breadcrumbs: nullable Breadcrumbs = null is public writable
-
-       # Panels to display in the sidebar.
-       var side_panels = new Array[Panel]
-
-       # Panels to display in the page main container.
-       var flow_panels = new Array[Panel]
-
-       redef fun rendering do
-               render_header
-               render_footer
-       end
-
-       # Render the header shared by all pages.
-       fun render_header do
-               add """
-<!DOCTYPE html>
-<html>
-       <head>
-               <meta charset="UTF-8">
-               <title>Github RPG</title>
-               <link rel="stylesheet"
-                       href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css">
-               <link rel="stylesheet" href="{{{root_url}}}/styles/main.css">
-       </head>
-       <body>
-               <nav class="navbar navbar-inverse navbar-fixed-top" role="navigation">
-                       <a class="navbar-brand" href="{{{root_url}}}/">Github RPG</a>"""
-               if not breadcrumbs == null then
-                       add breadcrumbs.as(not null)
-               end
-               add """
-               </nav>
-               <div class="container-fluid">
-                       <div class="row">"""
-               if not side_panels.is_empty then
-                       add """<div class="col-xs-3" id="side">"""
-                       for panel in side_panels do add panel
-                       add """</div>
-                                  <div class="col-xs-9" id="flow">"""
-               else
-                       add """<div class="col-xs-12" id="flow">"""
-               end
-               for panel in flow_panels do add panel
-               add """    </div>
-                       </div>
-               </div>
-"""
-       end
-
-       # Render the footer shared by all pages.
-       fun render_footer do
-               add """
-               <script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
-               <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/js/bootstrap.min.js"></script>
-       </body>
-</html>
-"""
-       end
-end
-
-# A Bootstrap breadcrumbs component.
-class Breadcrumbs
-       super Template
-
-       # Items to display in this breadcrumb.
-       var entries = new Array[String]
-
-       redef fun rendering do
-               add "<ol class=\"breadcrumb\">"
-               for entry in entries do
-                       add "<li>{entry}</li>"
-               end
-               add "</ol>"
-       end
-
-       # Add a link to the breadcrumbs.
-       fun add_link(href, name: String) do
-               entries.add "<a href=\"{href}\">{name}</a>"
-       end
-end
diff --git a/contrib/nitrpg/src/templates/templates_base.nit b/contrib/nitrpg/src/templates/templates_base.nit
deleted file mode 100644 (file)
index fe9efd8..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-# This file is part of NIT ( http://www.nitlanguage.org ).
-#
-# Copyright 2014-2015 Alexandre Terrasa <alexandre@moz-code.org>
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Base HTML rendering templates for `nitpg`.
-module templates_base
-
-import achievements
-
-redef class GameEntity
-
-       # Path to this entity from root.
-       fun path: String do return collection_name / key
-
-       # URL to this game entity page.
-       fun url: String do return game.url / path
-end
-
-redef class Game
-
-       # Root URL ise used as a prefix for `url`.
-       #
-       # This must be set before any access to `url`.
-       var root_url: String is noinit, writable
-
-       redef fun url do return "{root_url}/{path}"
-
-       # Return a HTML link to this Game.
-       fun link: String do return "<a href=\"{url}\">{name}</a>"
-end
-
-redef class Player
-       # Return a HTML link to this Player.
-       fun link: String do return "<a href=\"{url}\">{name}</a>"
-end
-
-redef class Issue
-       # Return a HTML link to this Issue.
-       fun link: String do return "<a href=\"{html_url or else "#"}\">#{number}</a>"
-end
-
-redef class Achievement
-       # Return a HTML link to this Issue.
-       fun link: String do return "<a href=\"{url}\">{name}</a>"
-
-       # Render self as a media item.
-       fun list_item: String do
-               return """<div class="media">
-                              <div class="media-left" style="width: 50px">
-                               <span class="glyphicon glyphicon-check"></span>
-                               <span class="badge progress-bar-success"
-                                style="position: absolute; margin-top: 10px;
-                                        margin-left: -5px;">+{{{reward}}}</span>
-                              </div>
-                              <div class="media-body">
-                               <h4 class="media-heading">{{{link}}}</h4>
-                               <span class="text-muted">{{{desc}}}</span>
-                              </div>
-                             </div>"""
-
-       end
-end
diff --git a/contrib/nitrpg/src/templates/templates_events.nit b/contrib/nitrpg/src/templates/templates_events.nit
deleted file mode 100644 (file)
index 3e141b9..0000000
+++ /dev/null
@@ -1,125 +0,0 @@
-# This file is part of NIT ( http://www.nitlanguage.org ).
-#
-# Copyright 2014-2015 Alexandre Terrasa <alexandre@moz-code.org>
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Templates to display `GameEvent` kinds.
-module templates_events
-
-import achievements
-import templates_base
-
-redef class GameEvent
-       # See `TplEvent`
-       fun tpl_event: TplEvent do
-               if kind == "pull_open" then
-                       return new TplPullOpened(self)
-               else if kind == "pull_merged" then
-                       return new TplPullMerged(self)
-               else if kind == "pull_review" then
-                       return new TplPullReview(self)
-               else if kind == "achievement_unlocked" then
-                       return new TplAchievementUnlocked(self)
-               end
-               abort
-       end
-end
-
-# A TplEvent factorizes HTML rendering methods for `GameEvent`.
-class TplEvent
-
-       # Event to display.
-       var event: GameEvent
-
-       # Title to display.
-       var title: String is lazy do return "raw event"
-
-       # Load Player from event data.
-       var player: nullable Player is lazy do
-               return event.game.load_player(event.data["player"].to_s)
-       end
-
-       # Load reward from event data.
-       var reward: Int is lazy do return event.data["reward"].as(Int)
-
-       # Load `github_event` data key as a PullRequestEvent.
-       var pull_event: PullRequestEvent is lazy do
-               return event.game.api.deserialize(event.data["github_event"].as(JsonObject).to_json).as(PullRequestEvent)
-       end
-
-       # Load `github_event` data key as a IssueCommentEvent.
-       var issue_comment_event: IssueCommentEvent is lazy do
-               return event.game.api.deserialize(event.data["github_event"].as(JsonObject).to_json).as(IssueCommentEvent)
-       end
-
-       # Load `achievement` data key as an Achievement.
-       var achievement: Achievement is lazy do
-               return player.load_achievement(event.data["achievement"].to_s).as(not null)
-       end
-
-       # Display a media item for a reward event.
-       fun media_item: String do
-               return """<div class="media">
-                       <a class="media-left" href="{{{player.url}}}">
-                                <span class="badge progress-bar-success"
-                                 style=\"position: absolute\">+{{{reward}}}</span>
-                                <img class=\"img-circle\" style="width:50px"
-                                src="{{{player.user.avatar_url or else "#"}}}" alt="{{{player.name}}}">
-                               </a>
-                               <div class="media-body">
-                                <h4 class="media-heading">{{{title}}}</h4>
-                                <span class="text-muted">at {{{event.time}}}</span>
-                               </div>
-                          </div>"""
-       end
-end
-
-# Event: pull_open
-class TplPullOpened
-       super TplEvent
-
-       redef var title is lazy do
-               var pull = pull_event.pull
-               return "{player.link} pushed {pull.link}"
-       end
-end
-
-# Event: pull_merged
-class TplPullMerged
-       super TplEvent
-
-       redef var title is lazy do
-               var pull = pull_event.pull
-               return "{player.link} merged <strong>{pull.commits}</strong> commits with {pull.link}"
-       end
-end
-
-# Event: pull_review
-class TplPullReview
-       super TplEvent
-
-       redef var title is lazy do
-               var issue = issue_comment_event.issue
-               return "{player.link} reviewed {issue.link}"
-       end
-end
-
-# Event: achievement_unlocked
-class TplAchievementUnlocked
-       super TplEvent
-
-       redef var title is lazy do
-               return "{player.link} unlocked {achievement.link}"
-       end
-end
diff --git a/contrib/nitrpg/src/test_achievements.nit b/contrib/nitrpg/src/test_achievements.nit
deleted file mode 100644 (file)
index 41d9dd1..0000000
+++ /dev/null
@@ -1,140 +0,0 @@
-# This file is part of NIT ( http://www.nitlanguage.org ).
-#
-# Copyright 2014-2015 Alexandre Terrasa <alexandre@moz-code.org>
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Test module for `achievements.nit`
-module test_achievements is test
-
-import test_helper
-import achievements
-
-class TestGame
-       super NitrpgTestHelper
-       test
-
-       fun test_add_achievement is test do
-               var db = gen_test_db
-               var game = load_game("Morriar/nit", db)
-               var a1 = new Achievement(game, "test_id1", "test_name", "test_desc", 15)
-               var a2 = new Achievement(game, "test_id2", "test_name", "test_desc", 15)
-               game.add_achievement(a1)
-               game.add_achievement(a2)
-               assert game.load_achievements.length == 2
-       end
-
-       fun test_load_achievement is test do
-               var db = gen_test_db
-               var game = load_game("Morriar/nit", db)
-               var a1 = new Achievement(game, "test_id1", "test_name", "test_desc", 15)
-               var a2 = new Achievement(game, "test_id2", "test_name", "test_desc", 15)
-               game.add_achievement(a1)
-               assert game.load_achievement(a1.id).id == "test_id1"
-               assert game.load_achievement(a2.id) == null
-       end
-
-       fun test_load_achievements is test do
-               var db = gen_test_db
-               var game = load_game("Morriar/nit", db)
-               var a1 = new Achievement(game, "test_id1", "test_name", "test_desc", 15)
-               var a2 = new Achievement(game, "test_id2", "test_name", "test_desc", 15)
-               var a3 = new Achievement(game, "test_id3", "test_name", "test_desc", 15)
-               game.add_achievement(a1)
-               game.add_achievement(a2)
-               game.db.collection("achievements").insert(a3.to_json_object)
-               var ok = [a1.id, a2.id]
-               var res = game.load_achievements
-               assert res.length == 2
-               for a in res.values do assert ok.has(a.id)
-       end
-end
-
-class TestPlayer
-       super NitrpgTestHelper
-       test
-
-       fun test_add_achievement is test do
-               var db = gen_test_db
-               var game = load_game("Morriar/nit", db)
-               var player1 = new Player(game, "Morriar")
-               var a1 = new Achievement(game, "test_id1", "test_name", "test_desc", 15)
-               var a2 = new Achievement(game, "test_id2", "test_name", "test_desc", 15)
-               player1.add_achievement(a1)
-               player1.add_achievement(a2)
-               assert player1.load_achievements.length == 2
-       end
-
-       fun test_load_achievement is test do
-               var db = gen_test_db
-               var game = load_game("Morriar/nit", db)
-               var player1 = new Player(game, "Morriar")
-               var player2 = new Player(game, "xymus")
-               var a1 = new Achievement(game, "test_id1", "test_name", "test_desc", 15)
-               var a2 = new Achievement(game, "test_id2", "test_name", "test_desc", 15)
-               player1.add_achievement(a1)
-               player2.add_achievement(a2)
-               assert player1.load_achievement(a1.id).id == "test_id1"
-               assert player1.load_achievement(a2.id) == null
-               assert player2.load_achievement(a2.id).id == "test_id2"
-               assert player2.load_achievement(a1.id) == null
-       end
-
-       fun test_load_achievements is test do
-               var db = gen_test_db
-               var game = load_game("Morriar/nit", db)
-               var player1 = new Player(game, "Morriar")
-               var player2 = new Player(game, "xymus")
-               var a1 = new Achievement(game, "test_id1", "test_name", "test_desc", 15)
-               var a2 = new Achievement(game, "test_id2", "test_name", "test_desc", 15)
-               var a3 = new Achievement(game, "test_id3", "test_name", "test_desc", 15)
-               player1.add_achievement(a1)
-               player1.add_achievement(a2)
-               player2.add_achievement(a3)
-               var ok = [a1.id, a2.id]
-               var res = player1.load_achievements
-               assert res.length == 2
-               for a in res.values do assert ok.has(a.id)
-       end
-end
-
-class TestAchievement
-       super NitrpgTestHelper
-       test
-
-       fun test_init is test do
-               var db = gen_test_db
-               var game = load_game("Morriar/nit", db)
-               var a = new Achievement(game, "test_id", "test_name", "test_desc", 15)
-               assert a.id == "test_id"
-               assert a.name == "test_name"
-               assert a.desc == "test_desc"
-               assert a.reward == 15
-       end
-
-       fun test_init_from_json is test do
-               var db = gen_test_db
-               var game = load_game("Morriar/nit", db)
-               var json = """{
-                       "id": "test_id",
-                       "name": "test_name",
-                       "desc": "test_desc",
-                       "reward": 15
-               }""".parse_json.as(JsonObject)
-               var a = new Achievement.from_json(game, json)
-               assert a.id == "test_id"
-               assert a.name == "test_name"
-               assert a.desc == "test_desc"
-               assert a.reward == 15
-       end
-end
diff --git a/contrib/nitrpg/src/test_events.nit b/contrib/nitrpg/src/test_events.nit
deleted file mode 100644 (file)
index efe24cf..0000000
+++ /dev/null
@@ -1,139 +0,0 @@
-# This file is part of NIT ( http://www.nitlanguage.org ).
-#
-# Copyright 2014-2015 Alexandre Terrasa <alexandre@moz-code.org>
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Test module for `events.nit`
-module test_events is test
-
-import test_helper
-import events
-
-class TestGame
-       super NitrpgTestHelper
-       test
-
-       fun test_add_event is test do
-               var db = gen_test_db
-               var game = load_game("Morriar/nit", db)
-               var event1 = new GameEvent(game, "test_kind", new JsonObject)
-               var event2 = new GameEvent(game, "test_kind", new JsonObject)
-               game.add_event(event1)
-               game.add_event(event2)
-               assert game.load_events.length == 2
-       end
-
-       fun test_load_event is test do
-               var db = gen_test_db
-               var game = load_game("Morriar/nit", db)
-               var event1 = new GameEvent(game, "test_kind", new JsonObject)
-               var event2 = new GameEvent(game, "test_kind", new JsonObject)
-               game.add_event(event1)
-               assert game.load_event(event1.internal_id).kind == "test_kind"
-               assert game.load_event(event2.internal_id) == null
-       end
-
-       fun test_load_events is test do
-               var db = gen_test_db
-               var game = load_game("Morriar/nit", db)
-               var event1 = new GameEvent(game, "test_kind", new JsonObject)
-               var event2 = new GameEvent(game, "test_kind", new JsonObject)
-               var event3 = new GameEvent(game, "test_kind", new JsonObject)
-               game.add_event(event1)
-               game.add_event(event2)
-               game.db.collection("events").insert(event3.to_json_object)
-               var ok = [event1.internal_id, event2.internal_id]
-               var res = game.load_events
-               assert res.length == 2
-               for event in res do assert ok.has(event.internal_id)
-       end
-end
-
-class TestPlayer
-       super NitrpgTestHelper
-       test
-
-       fun test_add_event is test do
-               var db = gen_test_db
-               var game = load_game("Morriar/nit", db)
-               var player1 = new Player(game, "Morriar")
-               var player2 = new Player(game, "xymus")
-               var event1 = new GameEvent(game, "test_kind", new JsonObject)
-               var event2 = new GameEvent(game, "test_kind", new JsonObject)
-               player1.add_event(event1)
-               player1.add_event(event2)
-               assert player1.load_events.length == 2
-               assert player2.load_events.length == 0
-       end
-
-       fun test_load_event is test do
-               var db = gen_test_db
-               var game = load_game("Morriar/nit", db)
-               var player1 = new Player(game, "Morriar")
-               var player2 = new Player(game, "xymus")
-               var event1 = new GameEvent(game, "test_kind", new JsonObject)
-               var event2 = new GameEvent(game, "test_kind", new JsonObject)
-               player1.add_event(event1)
-               player2.add_event(event2)
-               assert player1.load_event(event1.internal_id).kind == "test_kind"
-               assert player1.load_event(event2.internal_id) == null
-               assert player2.load_event(event2.internal_id).kind == "test_kind"
-               assert player2.load_event(event1.internal_id) == null
-       end
-
-       fun test_load_events is test do
-               var db = gen_test_db
-               var game = load_game("Morriar/nit", db)
-               var player1 = new Player(game, "Morriar")
-               var player2 = new Player(game, "xymus")
-               var event1 = new GameEvent(game, "test_kind", new JsonObject)
-               var event2 = new GameEvent(game, "test_kind", new JsonObject)
-               var event3 = new GameEvent(game, "test_kind", new JsonObject)
-               player1.add_event(event1)
-               player1.add_event(event2)
-               player2.add_event(event3)
-               assert player1.load_events.length == 2
-               assert player2.load_events.length == 1
-               var ok = [event1.internal_id, event2.internal_id]
-               for event in player1.load_events do assert ok.has(event.internal_id)
-       end
-end
-
-class TestGameEvent
-       super NitrpgTestHelper
-       test
-
-       fun test_init is test do
-               var db = gen_test_db
-               var game = load_game("Morriar/nit", db)
-               var event = new GameEvent(game, "test_kind", new JsonObject)
-               assert event.to_json_object["kind"] == "test_kind"
-       end
-
-       fun test_init_from_json is test do
-               var db = gen_test_db
-               var game = load_game("Morriar/nit", db)
-               var json = """{
-                       "internal_id": "test_id",
-                       "kind": "test_kind",
-                       "time": "2015-02-05T00:00:00Z",
-                       "data": {"test_field": "test_value"}
-               }""".parse_json.as(JsonObject)
-               var event = new GameEvent.from_json(game, json)
-               assert event.internal_id == "test_id"
-               assert event.kind == "test_kind"
-               assert event.data.to_json == """{"test_field":"test_value"}"""
-               assert event.time.to_s == "2015-02-05T00:00:00Z"
-       end
-end
diff --git a/contrib/nitrpg/src/test_game.nit b/contrib/nitrpg/src/test_game.nit
deleted file mode 100644 (file)
index c2aa677..0000000
+++ /dev/null
@@ -1,140 +0,0 @@
-# This file is part of NIT ( http://www.nitlanguage.org ).
-#
-# Copyright 2014-2015 Alexandre Terrasa <alexandre@moz-code.org>
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Test module for `game.nit`.
-module test_game is test
-
-import test_helper
-
-class TestGame
-       super NitrpgTestHelper
-       test
-
-       fun test_add_player is test do
-               var db = gen_test_db
-               var game = load_game("privat/nit", db)
-               var users = ["Morriar", "xymus"]
-               for name in users do
-                       game.add_player(game.api.load_user(name).as(not null))
-               end
-               var res = game.load_players.values
-               assert res.length == 2
-               for player in res do
-                       assert users.has(player.name)
-               end
-       end
-
-       fun test_load_player is test do
-               var db = gen_test_db
-               var game = load_game("privat/nit", db)
-               var ogame = load_game("Morriar/nit", db)
-
-               var player1 = new Player(game, "Morriar")
-               var player2 = new Player(ogame, "privat")
-               game.db.collection("players").insert(player1.to_json_object)
-               ogame.db.collection("players").insert(player2.to_json_object)
-
-               assert game.load_player("privat") == null
-               assert game.load_player("Morriar").name == "Morriar"
-               assert ogame.load_player("privat").name == "privat"
-               assert ogame.load_player("Morriar") == null
-       end
-
-       fun test_load_players is test do
-               var db = gen_test_db
-               var game = load_game("privat/nit", db)
-               var ogame = load_game("Morriar/nit", db)
-
-               var player1 = new Player(game, "Morriar")
-               var player2 = new Player(ogame, "privat")
-               var player3 = new Player(game, "xymus")
-               game.db.collection("players").insert(player1.to_json_object)
-               ogame.db.collection("players").insert(player2.to_json_object)
-               game.db.collection("players").insert(player3.to_json_object)
-
-               var players = game.load_players
-               var ok = ["Morriar", "xymus"]
-               for player in players.values do assert ok.has(player.name)
-       end
-end
-
-class TestPlayer
-       super NitrpgTestHelper
-       test
-
-       fun test_init is test do
-               var db = gen_test_db
-               var game = load_game("privat/nit", db)
-               var player = new Player(game, "Morriar")
-               assert player.name == "Morriar"
-               assert player.user.login == "Morriar"
-               assert player.nitcoins == 0
-       end
-
-       fun test_init_from_json is test do
-               var db = gen_test_db
-               var game = load_game("privat/nit", db)
-               var json = """{"name": "Morriar", "nitcoins": 10}""".parse_json
-               var player = new Player.from_json(game, json.as(JsonObject))
-               assert player.name == "Morriar"
-               assert player.user.login == "Morriar"
-               assert player.nitcoins == 10
-       end
-
-       fun test_save is test do
-               var db = gen_test_db
-               var game = load_game("privat/nit", db)
-               var json = """{"name": "Morriar", "nitcoins": 10}""".parse_json.as(JsonObject)
-               var player = new Player.from_json(game, json)
-               player.save
-               assert game.db.collection("players").find(json) != null
-       end
-
-       fun test_game_add_player is test do
-               var db = gen_test_db
-               var game = load_game("privat/nit", db)
-               game.add_player(game.api.load_user("Morriar").as(not null))
-               var json = """{"name": "Morriar"}""".parse_json.as(JsonObject)
-               assert game.db.collection("players").find(json) != null
-       end
-
-       fun test_game_load_player is test do
-               var db = gen_test_db
-               var game = load_game("privat/nit", db)
-               var json = """{"name": "Morriar", "nitcoins": 10}""".parse_json.as(JsonObject)
-               var player = new Player.from_json(game, json)
-               player.save
-               var oplayer = game.load_player("Morriar")
-               assert oplayer != null
-               assert player.nitcoins == oplayer.nitcoins
-       end
-end
-
-class TestUser
-       super NitrpgTestHelper
-       test
-
-       fun test_player is test do
-               var db = gen_test_db
-               var api = new GithubAPI(get_github_oauth)
-               var game = load_game("privat/nit", db)
-               var user = api.load_user("Morriar")
-               assert user != null
-               var player = user.player(game)
-               assert player.name == "Morriar"
-               game.clear
-       end
-end
diff --git a/contrib/nitrpg/src/test_helper.nit b/contrib/nitrpg/src/test_helper.nit
deleted file mode 100644 (file)
index 9d71ca3..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-# This file is part of NIT ( http://www.nitlanguage.org ).
-#
-# Copyright 2014-2015 Alexandre Terrasa <alexandre@moz-code.org>
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Test tools for NitRPG.
-module test_helper
-
-import game
-import github::cache
-
-# Used to factorize test treatments.
-abstract class NitrpgTestHelper
-
-       # Github API client
-       var api: GithubAPI do
-               var api = new GithubAPI(get_github_oauth)
-               api.enable_cache = true
-               return api
-       end
-
-       # Mongo API client
-       var mongo = new MongoClient("mongodb://mongo:27017/")
-
-       # Load a new test database by with a name
-       private fun load_db(name: String): MongoDb do return mongo.database(name)
-
-       # Load a repo by its name.
-       fun load_repo(name: String): Repo do
-               var repo = api.load_repo(name)
-               assert repo != null
-               return repo
-       end
-
-       # Load a game by its name.
-       fun load_game(name: String, db: MongoDb): Game do
-               var game = new Game(api, load_repo(name))
-               game.db_name = db.name
-               return game
-       end
-
-       # Stack of db used for testing.
-       var test_dbs = new Array[MongoDb]
-
-       # Gen a test db with a random name (to avoid race conditions).
-       fun gen_test_db: MongoDb do
-               var testid = "NIT_TESTING_ID".environ.to_i
-               var db_name = "test_nitrpg_{testid}"
-               var db = load_db(db_name)
-               test_dbs.add db
-               return db
-       end
-
-       # Should be called after your test.
-       fun drop_test_db do
-               var db = test_dbs.pop
-               db.drop
-       end
-
-       # Drop the databse after each test
-       fun after_test is after do drop_test_db
-end
diff --git a/contrib/nitrpg/src/test_listener.nit b/contrib/nitrpg/src/test_listener.nit
deleted file mode 100644 (file)
index d70f3aa..0000000
+++ /dev/null
@@ -1,359 +0,0 @@
-# This file is part of NIT ( http://www.nitlanguage.org ).
-#
-# Copyright 2014-2015 Alexandre Terrasa <alexandre@moz-code.org>
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Test module for `listener.nit`
-module test_listener is test
-
-import test_helper
-import reactors
-import achievements
-import events_generator
-
-private class DummyListener
-       super NitrpgTestHelper
-       test
-
-       var reactors = new Array[GameReactor]
-
-       fun apply_event(event: GithubEvent, db: MongoDb) do
-               var game = load_game(event.repo.full_name, db)
-               for reactor in reactors do
-                       reactor.react_event(game, event)
-               end
-       end
-
-       fun add_reactor(reactors: GameReactor...) do self.reactors.add_all reactors
-end
-
-class TestListener
-       super NitrpgTestHelper
-       test
-
-       var generator = new EventsGenerator(api)
-
-       var repo: Repo is lazy do return load_repo("Morriar/nit")
-
-       fun test_game_issue_stats is test do
-               var db = gen_test_db
-               var l = new DummyListener
-               l.add_reactor(new StatisticsReactor)
-
-               var issue = api.load_issue(repo, 322)
-               assert issue != null
-
-               l.apply_event(generator.issue_open(repo, issue), db)
-               var game = load_game("Morriar/nit", db)
-               assert game.stats.overall["issues"] == 1
-               assert game.stats.overall["issues_open"] == 1
-               l.apply_event(generator.issue_close(repo, issue), db)
-               game = load_game("Morriar/nit", db)
-               assert game.stats.overall["issues"] == 1
-               assert game.stats.overall["issues_open"] == 0
-               l.apply_event(generator.issue_reopen(repo, issue), db)
-               game = load_game("Morriar/nit", db)
-               assert game.stats.overall["issues"] == 1
-               assert game.stats.overall["issues_open"] == 1
-       end
-
-       fun test_player_issue_stats is test do
-               var db = gen_test_db
-               var game = load_game("Morriar/nit", db)
-               var l = new DummyListener
-               l.add_reactor(new StatisticsReactor)
-
-               var issue = api.load_issue(repo, 322)
-               assert issue != null
-
-               l.apply_event(generator.issue_open(repo, issue), db)
-               var player = new Player(game, "Morriar")
-               assert player.stats.overall["issues"] == 1
-               assert player.stats.overall["issues_open"] == 1
-               l.apply_event(generator.issue_close(repo, issue), db)
-               player = new Player(game, "Morriar")
-               assert player.stats.overall["issues"] == 1
-               assert player.stats.overall["issues_open"] == 0
-               l.apply_event(generator.issue_reopen(repo, issue), db)
-               player = new Player(game, "Morriar")
-               assert player.stats.overall["issues"] == 1
-               assert player.stats.overall["issues_open"] == 1
-       end
-
-       fun test_game_pr_stats is test do
-               var db = gen_test_db
-               var l = new DummyListener
-               l.add_reactor(new StatisticsReactor)
-
-               var pr = api.load_pull(repo, 275)
-               assert pr != null
-
-               l.apply_event(generator.pull_open(repo, pr), db)
-               var game = load_game("Morriar/nit", db)
-               assert game.stats.overall["pulls"] == 1
-               assert game.stats.overall["pulls_open"] == 1
-               assert game.stats.overall["commits"] == 0
-               pr.merged = false
-               l.apply_event(generator.pull_close(repo, pr), db)
-               game = load_game("Morriar/nit", db)
-               assert game.stats.overall["pulls"] == 1
-               assert game.stats.overall["pulls_open"] == 0
-               assert game.stats.overall["commits"] == 0
-               l.apply_event(generator.pull_reopen(repo, pr), db)
-               game = load_game("Morriar/nit", db)
-               assert game.stats.overall["pulls"] == 1
-               assert game.stats.overall["pulls_open"] == 1
-               assert game.stats.overall["commits"] == 0
-               pr.merged = true
-               l.apply_event(generator.pull_close(repo, pr), db)
-               game = load_game("Morriar/nit", db)
-               assert game.stats.overall["pulls"] == 1
-               assert game.stats.overall["pulls_open"] == 0
-               assert game.stats.overall["commits"] == 2
-       end
-
-       fun test_game_issue_comment_stats is test do
-               var db = gen_test_db
-               var l = new DummyListener
-               l.add_reactor(new StatisticsReactor)
-
-               var issue = api.load_issue(repo, 322)
-               assert issue != null
-               var comment = api.load_issue_comment(repo, 76119442)
-               assert comment != null
-
-               comment.body = "foo bar"
-               l.apply_event(generator.issue_comment_event(repo, issue, comment), db)
-               var game = load_game("Morriar/nit", db)
-               assert game.stats.overall["comments"] == 1
-               assert game.stats.overall["reviews"] == 0
-               comment.body = "foo +1 bar"
-               l.apply_event(generator.issue_comment_event(repo, issue, comment), db)
-               game = load_game("Morriar/nit", db)
-               assert game.stats.overall["comments"] == 2
-               assert game.stats.overall["reviews"] == 1
-       end
-
-       fun test_player_pull_reactor is test do
-               var db = gen_test_db
-               var game = load_game("Morriar/nit", db)
-               var l = new DummyListener
-               l.add_reactor(new PlayerReactor)
-
-               var pull = api.load_pull(repo, 275)
-               assert pull != null
-
-               l.apply_event(generator.pull_open(repo, pull), db)
-               var player = new Player(game, "itch76")
-               assert player.stats.overall["nitcoins"] == 10
-               pull.merged = false
-               l.apply_event(generator.pull_close(repo, pull), db)
-               player = new Player(game, "itch76")
-               assert player.stats.overall["nitcoins"] == 0
-               l.apply_event(generator.pull_reopen(repo, pull), db)
-               player = new Player(game, "itch76")
-               assert player.stats.overall["nitcoins"] == 10
-               pull.merged = true
-               l.apply_event(generator.pull_close(repo, pull), db)
-               player = new Player(game, "itch76")
-               assert player.stats.overall["nitcoins"] == 12
-       end
-
-       fun test_player_review_reactor is test do
-               var db = gen_test_db
-               var game = load_game("Morriar/nit", db)
-               var l = new DummyListener
-               l.add_reactor(new PlayerReactor)
-
-               var pull = api.load_pull(repo, 275)
-               assert pull != null
-               var comment = api.load_issue_comment(repo, 36961230)
-               assert comment != null
-
-               # TODO handle multiple review by the same user
-
-               # no review in opened issue
-               pull.state = "open"
-               comment.body = "foo bar"
-               l.apply_event(generator.issue_comment_event(repo, pull, comment), db)
-               var player = new Player(game, "Morriar")
-               assert player.stats.overall["nitcoins"] == 0
-
-               # review in opened issue
-               pull.state = "open"
-               comment.body = "foo +1 bar"
-               l.apply_event(generator.issue_comment_event(repo, pull, comment), db)
-               player = new Player(game, "Morriar")
-               print player.stats.overall["nitcoins"]
-               assert player.stats.overall["nitcoins"] == 2
-
-               # review in closed issue
-               pull.state = "closed"
-               comment.body = "foo +1 bar"
-               l.apply_event(generator.issue_comment_event(repo, pull, comment), db)
-               player = new Player(game, "Morriar")
-               assert player.stats.overall["nitcoins"] == 2
-
-               # review in reopened issue
-               pull.state = "open"
-               comment.body = "foo +1 bar"
-               l.apply_event(generator.issue_comment_event(repo, pull, comment), db)
-               player = new Player(game, "Morriar")
-               assert player.stats.overall["nitcoins"] == 4
-       end
-
-       fun test_X_issues_achievements is test do
-               var db = gen_test_db
-               var game = load_game("Morriar/nit", db)
-               var l = new DummyListener
-               l.add_reactor(new StatisticsReactor)
-               l.add_reactor(new Player1Issue, new Player100Issues, new Player1KIssues)
-
-               var issue = api.load_issue(repo, 322)
-               assert issue != null
-
-               for i in [0, 99, 999] do
-                       var id = "player_{i + 1}_issue"
-                       if i > 0 then id = "{id}s"
-                       var player = new Player(game, "Morriar")
-                       player.stats["issues"] = i
-                       player.save
-                       l.apply_event(generator.issue_open(repo, issue), db)
-                       assert player.load_achievements.has_key(id)
-               end
-               var player = new Player(game, "Morriar")
-               assert player.stats.overall["nitcoins"] == 1110
-       end
-
-       fun test_X_pulls_achievements is test do
-               var db = gen_test_db
-               var game = load_game("Morriar/nit", db)
-               var l = new DummyListener
-               l.add_reactor(new StatisticsReactor)
-               l.add_reactor(new Player1Pull, new Player100Pulls, new Player1KPulls)
-
-               var pull = api.load_pull(repo, 275)
-               assert pull != null
-
-               for i in [0, 99, 999] do
-                       var id = "player_{i + 1}_pull"
-                       if i > 0 then id = "{id}s"
-                       var player = new Player(game, "itch76")
-                       player.stats["pulls"] = i
-                       player.save
-                       l.apply_event(generator.pull_open(repo, pull), db)
-                       assert player.load_achievements.has_key(id)
-               end
-               var player = new Player(game, "itch76")
-               assert player.stats.overall["nitcoins"] == 1110
-       end
-
-       fun test_X_commits_achievements is test do
-               var db = gen_test_db
-               var game = load_game("Morriar/nit", db)
-               var l = new DummyListener
-               l.add_reactor(new StatisticsReactor)
-               l.add_reactor(new Player1Commit, new Player100Commits)
-               l.add_reactor(new Player1KCommits, new Player10KCommits)
-
-               var pull = api.load_pull(repo, 275)
-               assert pull != null
-               pull.state = "closed"
-               pull.merged = true
-
-               for i in [0, 99, 999, 9999] do
-                       var id = "player_{i + 1}_commit"
-                       if i > 0 then id = "{id}s"
-                       var player = new Player(game, "itch76")
-                       player.stats["commits"] = i
-                       player.save
-                       l.apply_event(generator.pull_close(repo, pull), db)
-                       assert player.load_achievements.has_key(id)
-               end
-               var player = new Player(game, "itch76")
-               assert player.stats.overall["nitcoins"] == 11110
-       end
-
-       fun test_X_comments_achievements is test do
-               var db = gen_test_db
-               var game = load_game("Morriar/nit", db)
-               var l = new DummyListener
-               l.add_reactor(new StatisticsReactor)
-               l.add_reactor(new Player1Comment, new Player100Comments, new Player1KComments)
-
-               var pull = api.load_pull(repo, 275)
-               assert pull != null
-               var comment = api.load_issue_comment(repo, 36961230)
-               assert comment != null
-
-               for i in [0, 99, 999] do
-                       var id = "player_{i + 1}_comment"
-                       if i > 0 then id = "{id}s"
-                       var player = new Player(game, "Morriar")
-                       player.stats["comments"] = i
-                       player.save
-                       l.apply_event(generator.issue_comment_event(repo, pull, comment), db)
-                       assert player.load_achievements.has_key(id)
-               end
-               var player = new Player(game, "Morriar")
-               assert player.stats.overall["nitcoins"] == 1110
-       end
-
-    fun test_issues_achievements is test do
-               var db = gen_test_db
-               var game = load_game("Morriar/nit", db)
-               var l = new DummyListener
-               l.add_reactor(new IssueAboutNitdoc, new IssueAboutFFI)
-
-               var issue = api.load_issue(repo, 322)
-               assert issue != null
-
-               issue.title = "nitdoc ffi"
-               l.apply_event(generator.issue_open(repo, issue), db)
-               var player = new Player(game, "Morriar")
-               assert player.load_achievements.has_key("issue_about_nitdoc")
-               assert player.load_achievements.has_key("issue_about_ffi")
-               assert player.stats.overall["nitcoins"] == 20
-       end
-
-       fun test_comments_reactor is test do
-               var db = gen_test_db
-               var game = load_game("Morriar/nit", db)
-               var l = new DummyListener
-               l.add_reactor(new PlayerPingGod, new PlayerFirstReview, new PlayerSaysNitcoin)
-
-               var pull = api.load_pull(repo, 275)
-               assert pull != null
-               var comment = api.load_issue_comment(repo, 36961230)
-               assert comment != null
-
-               comment.body = "@{game.repo.owner.login}"
-               l.apply_event(generator.issue_comment_event(repo, pull, comment), db)
-               var player = new Player(game, "Morriar")
-               assert player.load_achievements.has_key("player_ping_god")
-               assert player.stats.overall["nitcoins"] == 50
-
-               comment.body = "+1"
-               l.apply_event(generator.issue_comment_event(repo, pull, comment), db)
-               player = new Player(game, "Morriar")
-               assert player.load_achievements.has_key("player_first_review")
-               assert player.stats.overall["nitcoins"] == 60
-
-               comment.body = "Nitcoins"
-               l.apply_event(generator.issue_comment_event(repo, pull, comment), db)
-               player = new Player(game, "Morriar")
-               assert player.load_achievements.has_key("player_says_nitcoin")
-               assert player.stats.overall["nitcoins"] == 70
-       end
-end
diff --git a/contrib/nitrpg/src/test_statistics.nit b/contrib/nitrpg/src/test_statistics.nit
deleted file mode 100644 (file)
index 9bdf8fa..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-# This file is part of NIT ( http://www.nitlanguage.org ).
-#
-# Copyright 2014-2015 Alexandre Terrasa <alexandre@moz-code.org>
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Test module for `stats.nit`
-module test_statistics is test
-
-import test_helper
-import statistics
-
-class TestGame
-       super NitrpgTestHelper
-       test
-
-       fun test_game_stats is test do
-               var db = gen_test_db
-               var game = load_game("privat/nit", db)
-               var stats = game.stats
-               assert stats.overall["test"] == 0
-               stats.overall.inc("test")
-               assert stats.overall["test"] == 1
-               stats.save
-               var ogame = load_game("privat/nit", db)
-               var ostats = ogame.stats
-               ostats.overall.inc("test")
-               assert ostats.overall["test"] == 2
-       end
-end
-
-class TestPlayer
-       super NitrpgTestHelper
-       test
-
-       fun test_player_stats is test do
-               var db = gen_test_db
-               var game = load_game("privat/nit", db)
-               var player = new Player(game, "Morriar")
-               var stats = player.stats
-               assert stats.overall["test"] == 0
-               stats.overall.inc("test")
-               assert stats.overall["test"] == 1
-               stats.save
-               var oplayer = new Player(game, "Morriar")
-               var ostats = oplayer.stats
-               ostats.overall.inc("test")
-               assert ostats.overall["test"] == 2
-       end
-end
-
-class TestGameStats
-       super NitrpgTestHelper
-       test
-
-       fun test_init_from_json is test do
-               var db = gen_test_db
-               var game = load_game("privat/nit", db)
-               var owner = new Player(game, "Morriar")
-               var json = """{
-                       "period": "2015",
-                       "owner": "Morriar",
-                       "values": {
-                               "test1": 10,
-                               "test2": 20
-                       }
-               }""".parse_json.as(JsonObject)
-               var stats = new GameStats.from_json(game, "2015", owner, json)
-               assert stats["test0"] == 0
-               assert stats["test1"] == 10
-               assert stats["test2"] == 20
-       end
-end
diff --git a/contrib/nitrpg/src/web.nit b/contrib/nitrpg/src/web.nit
deleted file mode 100644 (file)
index 3d54672..0000000
+++ /dev/null
@@ -1,313 +0,0 @@
-# This file is part of NIT ( http://www.nitlanguage.org ).
-#
-# Copyright 2014-2015 Alexandre Terrasa <alexandre@moz-code.org>
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Display `nitrpg` data as a website.
-module web
-
-import nitcorn
-import templates
-
-# A custom action forn `nitrpg`.
-class RpgAction
-       super Action
-
-       # Root URL is used as a prefix for all URL generated by the actions.
-       var root_url: String
-
-       # Github oauth token used for GithubAPI.
-       var auth: String is lazy do return get_github_oauth
-
-       # API client used to import data from Github.
-       var api: GithubAPI is lazy do
-               var api = new GithubAPI(auth)
-               return api
-       end
-
-       init do
-               super
-               if auth.is_empty then
-                       print "Error: Invalid Github oauth token!"
-                       exit 1
-               end
-       end
-
-       # Return an Error reponse page.
-       fun bad_request(msg: String): HttpResponse do
-               var rsp = new HttpResponse(400)
-               var page = new NitRpgPage(root_url)
-               var error = new ErrorPanel(msg)
-               page.flow_panels.add error
-               rsp.body = page
-               return rsp
-       end
-
-       # Returns the game with `name` or null if no game exists with this name.
-       fun load_game(name: String): nullable Game do
-               var repo = api.load_repo(name)
-               if repo == null then return null
-               var game = new Game.from_mongo(api, repo)
-               game.root_url = root_url
-               return game
-       end
-
-       # Returns the list of saved games from NitRPG data.
-       fun load_games: Array[Game] do
-               var res = new Array[Game]
-               # TODO should be option
-               var mongo = new MongoClient("mongodb://mongo:27017")
-               var db = mongo.database("nitrpg")
-               for obj in db.collection("games").find_all(new JsonObject) do
-                       var repo = api.load_repo(obj["name"].to_s)
-                       assert repo != null
-                       var game = new Game(api, repo)
-                       game.from_json(obj)
-                       game.root_url = root_url
-                       res.add game
-               end
-               return res
-       end
-end
-
-# Repo overview page.
-class RpgHome
-       super RpgAction
-
-       # Response page stub.
-       var page: NitRpgPage is noinit
-
-       redef fun answer(request, url) do
-               var readme = load_readme
-               var games = load_games
-               var response = new HttpResponse(200)
-               page = new NitRpgPage(root_url)
-               page.side_panels.add new GamesShortListPanel(root_url, games)
-               page.flow_panels.add new MDPanel(readme)
-               response.body = page
-               return response
-       end
-
-       # Load the string content of the nitrpg readme file.
-       private fun load_readme: String do
-               var readme = "README.md"
-               if not readme.file_exists then
-                       return "Unable to locate README file."
-               end
-               var file = new FileReader.open(readme)
-               var text = file.read_all
-               file.close
-               return text
-       end
-end
-
-# Display the list of active game.
-class ListGames
-       super RpgAction
-
-       # Response page stub.
-       var page: NitRpgPage is noinit
-
-       redef fun answer(request, url) do
-               var games = load_games
-               var response = new HttpResponse(200)
-               page = new NitRpgPage(root_url)
-               page.breadcrumbs = new Breadcrumbs
-               page.breadcrumbs.add_link(root_url / "games", "games")
-               page.flow_panels.add new GamesListPanel(root_url, games)
-               response.body = page
-               return response
-       end
-end
-
-# An action that require a game.
-class GameAction
-       super RpgAction
-
-       # Response page stub.
-       var page: NitRpgPage is noinit
-
-       # Target game.
-       var game: Game is noinit
-
-       redef fun answer(request, url) is abstract
-
-       # Check errors and prepare response.
-       private fun prepare_response(request: HttpRequest, url: String): HttpResponse do
-               var owner = request.param("owner")
-               var repo_name = request.param("repo")
-               if owner == null or repo_name == null then
-                       var msg = "Bad request: should look like /games/:owner/:repo."
-                       return bad_request(msg)
-               end
-               var game = load_game("{owner}/{repo_name}")
-               if game == null then
-                       var msg = api.last_error.message
-                       return bad_request("Repo Error: {msg}")
-               end
-               self.game = game
-               var response = new HttpResponse(200)
-               page = new NitRpgPage(root_url)
-               page.side_panels.add new GameStatusPanel(game)
-               page.breadcrumbs = new Breadcrumbs
-               page.breadcrumbs.add_link(game.url, game.name)
-               prepare_pagination(request)
-               return response
-       end
-
-       # Parse pagination related parameters.
-       private fun prepare_pagination(request: HttpRequest) do
-               var args = request.get_args
-               list_from = args.get_or_default("pfrom", "0").to_i
-               list_limit = args.get_or_default("plimit", "10").to_i
-       end
-
-       # Limit of events to display in lists.
-       var list_limit = 10
-
-       # From where to start the display of events related lists.
-       var list_from = 0
-
-       # TODO should also check 201, 203 ...
-       private fun is_response_error(response: HttpResponse): Bool do
-               return response.status_code != 200
-       end
-end
-
-# Repo overview page.
-class RepoHome
-       super GameAction
-
-       redef fun answer(request, url) do
-               var rsp = prepare_response(request, url)
-               if is_response_error(rsp) then return rsp
-               page.side_panels.add new ShortListPlayersPanel(game)
-               page.flow_panels.add new PodiumPanel(game)
-               page.flow_panels.add new EventListPanel(game, list_limit, list_from)
-               page.flow_panels.add new AchievementsListPanel(game)
-               rsp.body = page
-               return rsp
-       end
-end
-
-# Repo players list.
-class ListPlayers
-       super GameAction
-
-       redef fun answer(request, url) do
-               var rsp = prepare_response(request, url)
-               if is_response_error(rsp) then return rsp
-               page.breadcrumbs.add_link(game.url / "players", "players")
-               page.flow_panels.add new ListPlayersPanel(game)
-               rsp.body = page
-               return rsp
-       end
-end
-
-# Player details page.
-class PlayerHome
-       super GameAction
-
-       redef fun answer(request, url) do
-               var rsp = prepare_response(request, url)
-               if is_response_error(rsp) then return rsp
-               var name = request.param("player")
-               if name == null then
-                       var msg = "Bad request: should look like /:owner/:repo/:players/:name."
-                       return bad_request(msg)
-               end
-               var player = game.load_player(name)
-               if player == null then
-                       return bad_request("Request Error: unknown player {name}.")
-               end
-               page.breadcrumbs.add_link(game.url / "players", "players")
-               page.breadcrumbs.add_link(player.url, name)
-               page.side_panels.clear
-               page.side_panels.add new PlayerStatusPanel(game, player)
-               page.flow_panels.add new PlayerReviewsPanel(game, player)
-               page.flow_panels.add new PlayerWorkPanel(game, player)
-               page.flow_panels.add new AchievementsListPanel(player)
-               page.flow_panels.add new EventListPanel(player, list_limit, list_from)
-               rsp.body = page
-               return rsp
-       end
-end
-
-# Display the list of achievements unlocked for this game.
-class ListAchievements
-       super GameAction
-
-       redef fun answer(request, url) do
-               var rsp = prepare_response(request, url)
-               if is_response_error(rsp) then return rsp
-               page.breadcrumbs.add_link(game.url / "achievements", "achievements")
-               page.flow_panels.add new AchievementsListPanel(game)
-               rsp.body = page
-               return rsp
-       end
-end
-
-# Player details page.
-class AchievementHome
-       super GameAction
-
-       redef fun answer(request, url) do
-               var rsp = prepare_response(request, url)
-               if is_response_error(rsp) then return rsp
-               var name = request.param("achievement")
-               if name == null then
-                       var msg = "Bad request: should look like /:owner/:repo/achievements/:achievement."
-                       return bad_request(msg)
-               end
-               var achievement = game.load_achievement(name)
-               if achievement == null then
-                       return bad_request("Request Error: unknown achievement {name}.")
-               end
-               page.breadcrumbs.add_link(game.url / "achievements", "achievements")
-               page.breadcrumbs.add_link(achievement.url, achievement.name)
-               page.flow_panels.add new AchievementPanel(achievement)
-               page.flow_panels.add new EventListPanel(achievement, list_limit, list_from)
-               rsp.body = page
-               return rsp
-       end
-end
-
-if args.length != 3 then
-       print "Error: missing argument"
-       print ""
-       print "Usage:"
-       print "web <host> <port> <root_url>"
-       exit 1
-end
-
-var host = args[0]
-var port = args[1]
-var root = args[2]
-
-var iface = "{host}:{port}"
-var vh = new VirtualHost(iface)
-vh.routes.add new Route("/styles/", new FileServer("www/styles"))
-vh.routes.add new Route("/games/:owner/:repo/players/:player", new PlayerHome(root))
-vh.routes.add new Route("/games/:owner/:repo/players", new ListPlayers(root))
-vh.routes.add new Route("/games/:owner/:repo/achievements/:achievement", new AchievementHome(root))
-vh.routes.add new Route("/games/:owner/:repo/achievements", new ListAchievements(root))
-vh.routes.add new Route("/games/:owner/:repo", new RepoHome(root))
-vh.routes.add new Route("/games", new ListGames(root))
-vh.routes.add new Route("/", new RpgHome(root))
-
-var fac = new HttpFactory.and_libevent
-fac.config.virtual_hosts.add vh
-
-print "Launching server on http://{iface}/"
-fac.run
diff --git a/contrib/nitrpg/www/styles/main.css b/contrib/nitrpg/www/styles/main.css
deleted file mode 100644 (file)
index 865123e..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-body { padding-top: 70px; }
-
-.navbar .breadcrumb {
-       background-color: transparent;
-       margin-bottom: 0;
-       margin-top: 0.5em;
-}
-
-/* columns of same height styles */
-.container-xs-height {
-    display:table;
-    padding-left:0px;
-    padding-right:0px;
-}
-.row-xs-height {
-    display:table-row;
-}
-.col-xs-height {
-    display:table-cell;
-    float:none;
-}
-@media (min-width: 768px) {
-    .container-sm-height {
-        display:table;
-        padding-left:0px;
-        padding-right:0px;
-    }
-    .row-sm-height {
-        display:table-row;
-    }
-    .col-sm-height {
-        display:table-cell;
-        float:none;
-    }
-}
-@media (min-width: 992px) {
-    .container-md-height {
-        display:table;
-        padding-left:0px;
-        padding-right:0px;
-    }
-    .row-md-height {
-        display:table-row;
-    }
-    .col-md-height {
-        display:table-cell;
-        float:none;
-    }
-}
-@media (min-width: 1200px) {
-    .container-lg-height {
-        display:table;
-        padding-left:0px;
-        padding-right:0px;
-    }
-    .row-lg-height {
-        display:table-row;
-    }
-    .col-lg-height {
-        display:table-cell;
-        float:none;
-    }
-}
-
-/* vertical alignment styles */
-.col-top {
-    vertical-align:top;
-}
-.col-middle {
-    vertical-align:middle;
-}
-.col-bottom {
-    vertical-align:bottom;
-}