{"action":"created","comment":{"url":"https://api.github.com/repos/numfocus/gsoc/pulls/comments/56755278","id":56755278,"diff_hunk":"@@ -0,0 +1,404 @@\n+Result-aggregation server for the installation-test scripts \n+============================================================== \n+ \n+Contents \n+-------------- \n+1. **Abstract** \n+2. **Technical Details** \n+3. **Schedule of deliverables** \n+4. **Future Works** \n+5. **Open Source Development Experience** \n+6. **Academic Experience** \n+7. **Why this Project ?** \n+ \n+## Abstract \n+Software Carpentry has been teaching researchers in science, engineering, medicine, and related disciplines the computing skills they need to get more done in less time and with less pain. Several workshops are held in which students are required to setup their system by installing necessary packages.\n+\n+Currently software carpentry provides the [installation-test scripts](https://github.com/wking/swc-setup-installation-test) so that, students can check whether they've successfully installed all software required during the workshop. But the results generated by the scripts are not collected anywhere.\n+\n+In this project a server is to be written for storing results of installation-testing scripts, and also enhancing the testing scripts by adding an option for users to collect results and send them to the server. It will help in figuring out what all problems students usually face in installations ,and also the packages which need to be deprecated in future.\n+ \n+## Technical Details \n+I am breaking it down to several steps in which this project has to be approached : \n+### System Information collection \n+The installation-test script needs to be modified to retrieve some useful information about the user and the environment in which they are running the installation-test-script. \n+* Operating System information, which includes : \n+  * System information ( Linux / windows / Mac etc ) \n+  * Distribution information ( redhat / debian / fedora etc) \n+  * Machine Architecture information ( x86 / x64 ) \n+  * Complete platform information \n+  * Uname ( System info like kernel-name, kernel-version etc ) \n+  * Version ( System’s release version ) \n+  * Machine information ( Machine type, e.g. 'i386' )\n+  * Python Version\n+  \n+All of this information can be retrieved by using a library in python called `Platform`, code of which I wrote in my [demo](https://github.com/prerit2010/DemoAPI) application. The code snippet : \n+```python \n+import platform \n+ \n+system_dist = str(platform.dist()) \n+system = platform.system() \n+machine = platform.machine() \n+system_platform = platform.platform() \n+uname = platform.uname() \n+version = platform.version() \n+python_version = platform.python_version() \n+``` \n+\n+Sample of output generated in case of Ubuntu : \n+``` \n+Python version: ['2.7.3 (default, Sep 26 2012, 21:51:14) ', '[GCC 4.7.2]'] \n+dist: ('Ubuntu', '12.10', 'quantal') \n+linux_distribution: ('Ubuntu', '12.10', 'quantal') \n+system: Linux \n+machine: x86_64 \n+platform: Linux-3.5.0-22-generic-x86_64-with-Ubuntu-12.10-quantal \n+uname: ('Linux', 'stijn-W150HRM', '3.5.0-22-generic', '#34-Ubuntu SMP Tue Jan 8 21:47:00 UTC 2013', 'x86_64', 'x86_64') \n+version: #34-Ubuntu SMP Tue Jan 8 21:47:00 UTC 2013 \n+``` \n+Some or most of these information are being retrieved in the [installation-test-scripts](https://github.com/wking/swc-setup-installation-test).\n+### Success/Failure of packages information collection \n+* **Successful Installs** list is already provided by the script. A list `successes` contains both checker and the version. Server can just grab the full name by `checker.full_name()` and `version` of the successfully installed packages. \n+* **Failed Checks** list is also provided by the script with the name of the package, error description and also the cause for some cases. e.g. : \n+```\n+check for IPython script (ipython) failed: ( Name : IPython script (ipython) )\n+  errors finding IPython script (ipython) version  <-- Description\n+causes:\n+  check for IPython script (ipython) failed:\n+    could not find 'ipython' executable  <-- Cause\n+```\n+### Other information \n+* Diagnostic information \n+* Timestamp \n+* User email address\n+* Workshop Id\n+\n+### Server and API\n+Following are the components of this project :\n+* API\n+* Database\n+* Client (installation-test-scripts)\n+* Admin Console (Front end)\n+\n+The interation between components shall take place as depicted below :\n+![flow](http://i.imgur.com/ASFyavS.png)\n+\n+### API\n+An API is to be developed to store the results generated by the test script. I shall be using Python's web framework [FLASK](http://flask.pocoo.org/) for this purpose. Reason being, flask is a [microframework](https://en.wikipedia.org/wiki/Microframework) which is incredibly flexible and easily scalable. Very little initial code is needed for small projects, and which can be ramped up with relative ease in case the project becomes complex. This is in contrast to something like the Django framework, which, despite its strengths, depends on convention rather than flexibility. So, flask is the most suitable option as it seems. \n+\n+This would involve : \n+* **Modification of the installation-test-scrips** and giving the user an option to send the data to the server by making a [POST](https://en.wikipedia.org/wiki/POST_(HTTP)) request to the API endpoint with payload of all the information collected. Code Snippet : \n+```python\n+import requests \n+ \n+headers = { \n+    \"Content-Type\": \"application/json\", \n+} \n+HOST = \"http://127.0.0.1:5000\" \n+os_end_point = \"/system_info/\" \n+data = {\"system_dist\" : system_dist , \"version\": version} \n+uri = '{}{}'.format(HOST, os_end_point)\n+response = requests.post(uri, data=json.dumps(data), headers=headers) \n+``` \n+* This API will follow the [REST](https://en.wikipedia.org/wiki/Representational_state_transfer) standard, and all the data shall be sent in [JSON](http://www.json.org/) to the API. \n+ \n+* Setting up the **Database**. As mentioned in the description of the idea, [SQLite](https://www.sqlite.org/) is preferred, but it suffers some problems in case 40-50 people send the data simultaneously. After going through the comparison given [here](https://www.digitalocean.com/community/tutorials/sqlite-vs-mysql-vs-postgresql-a-comparison-of-relational-database-management-systems), I would personally prefer [MySQL](https://www.mysql.com/) or [PostgreSQL](http://www.postgresql.org/) in this project. But that can be decided later as per the discussion with mentors. All interactions with the database shall be done using **SQLAlchemy** and **Alembic**.\n+ \n+* Modelling the information collected at the client end. There shall be Tables in the database for user_system_info, successful installs and failed installs. All shall be referenced with a **unique id**, which will be used as a **foreign key** in all the tables, to identify a particular user associated with that entry in DB. \n+  \n+\n+### Database Schema\n+* User shall be prompted to enter the `workshop_id` and `email_id` before sending the data to the server, as it would enable the server to associate each result with the workshop, and summarize conclusions that are workshop specific and also overall.\n+* Combination of `workshop_id` and `email_id` would give us a unique id per user per workshop, and thus would prevent duplicate entries in the table for the same student attending the same workshop.\n+* Everytime a call is made to the API, it will first check whether an entry is already there for particular `workshop_id` and `email_id`. If yes, UPDATE query shall be made instead of INSERT query.\n+* Initial Proposed schema :\n+\n+![diagram](http://i.imgur.com/vTTrkDP.png)\n+\n+* I suggest using [SQLAlchemy](http://www.sqlalchemy.org/) for querying and handling the database. It has several advantages over using traditional SQL connectors, such as producing code, which is more readable, easier to maintain, less prone to errors and less vulnerable to attacks. SQLAlchemy does not consider a database as just a set of tables, rows and columns, but rather as a relational algebra engine. Writing complex raw queries can lead to difficult to maintain code. Any schematic changes in the database can be easily taken care of using SQLAlchemy. Sample code snippet :\n+```python\n+import os\n+ \n+from sqlalchemy import Column, DateTime, String, Integer, func\n+from sqlalchemy.orm import relationship, backref\n+from sqlalchemy.ext.declarative import declarative_base\n+from sqlalchemy import create_engine\n+from sqlalchemy.orm import sessionmaker\n+ \n+Base = declarative_base()\n+\n+class UserSystemInfo(Base):\n+    __tablename__ = 'user_system_info'\n+    user_id = Column(Integer, primary_key=True)\n+    system_dist = Column(String)\n+    uname  = Column(String)\n+    version = Column(String)\n+    system_dist = Column(String)\n+    system = Column(String)\n+    machine = Column(String)\n+    system_platform = Column(String) \n+    uname = Column(String)\n+    version = Column(String)\n+    python_version = Column(String)\n+    workshop_id = Column(String)\n+    email_id = Column(String)\n+    Create_time = Column(DateTime, default=func.now())\n+ \n+class SuccessfulInstalls(Base):\n+    __tablename__ = 'successful_installs'\n+    success_id = Column(Integer, primary_key=True)\n+    name = Column(String)\n+    Version = Column(String)\n+    user_id = Column(\n+        Integer,\n+        ForeignKey('user_system_info.user_id', ondelete='CASCADE'),\n+        nullable=False,\n+    )\n+    Create_time = Column(DateTime, default=func.now())\n+    user_system_info = relationship(\n+        UserSystemInfo,\n+        backref=backref('successful_installs',\n+                         uselist=True,\n+                         cascade='delete,all'))\n+\n+Class FailedInstalls(Base):\n+    __tablename__ = 'failed_installs'\n+    fail_id = Column(Integer, primary_key=True)\n+    name = Column(String)\n+    version = Column(String)\n+    error_description = Column(String)\n+    error_cause = Column(String)\n+    user_id = Column(\n+        Integer,\n+        ForeignKey('user_system_info.user_id', ondelete='CASCADE'),\n+        nullable=False,\n+    )\n+    Create_time = Column(DateTime, default=func.now())\n+    user_system_info = relationship(\n+        UserSystemInfo,\n+        backref=backref('failed_installs',\n+                         uselist=True,\n+                         cascade='delete,all'))\n+ \n+db_name = 'installation_server.sqlite'\n+if os.path.exists(db_name):\n+    os.remove(db_name)\n+ \n+engine = create_engine('sqlite:///' + db_name)\n+ \n+session = sessionmaker()\n+session.configure(bind=engine)\n+Base.metadata.create_all(engine)\n+```\n+### Database migration\n+\n+There are several ways to perform database migration, like SQLalchemy-migrate, Flask-migrate, [Alembic](https://alembic.readthedocs.org/en/latest/), which is specifically built for SQLAlchemy. For this I plan to use [Flask-Migrate](https://flask-migrate.readthedocs.org/en/latest/), a migration tool based on alembic.\n+Code Snippet :\n+```python\n+from flask import Flask\n+from flask.ext.sqlalchemy import SQLAlchemy\n+from flask.ext.script import Manager\n+from flask.ext.migrate import Migrate, MigrateCommand\n+\n+app = Flask(__name__)\n+app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///app.db'\n+\n+db = SQLAlchemy(app)\n+migrate = Migrate(app, db)\n+\n+manager = Manager(app)\n+manager.add_command('db', MigrateCommand)\n+\n+if __name__ == '__main__':\n+    manager.run()\n+```\n+\n+### Frontend\n+* For the Server Administrator, a basic **frontend** can be developed for them to manage and analyse the results, e.g. \n+ * Common install problems faced in a particular workshop \n+ * Common install problems faced by students overall. \n+ * Which version of package is most prone to errors, etc. \n+  \n+* The front end can be developed using simple HTML, CSS, [Bootstrap](http://getbootstrap.com/) , Javascript.  \n+* For the greater good, some plots can be generated by extracting useful information about the failures. This can be done using [Plotly](https://plot.ly/). This will provide better understanding by visualization. Code Snippet :\n+```python\n+import plotly.plotly as py\n+import plotly.graph_objs as go\n+\n+data = [\n+            go.Bar(\n+                x=['Ubuntu' , 'Redhat' , 'Fedora'],\n+                y=[30 , 20 , 40] ,\n+            )\n+        ]\n+        file_name = \"filename\"\n+        plot_url = py.plot(data, filename=file_name , auto_open=False)\n+```\n+\n+### Examples of results and Plots :\n+* Figuring out the most error prone package during installation\n+![install_plot](http://i.imgur.com/z85Nx40.png)\n+* Figuring out the most error prone Operating system and environment in installation of a particular package.\n+![os_plot](http://i.imgur.com/bajsojc.png)\n+\n+### API Structure\n+* `run.py` : Server shall be run from this file.\n+* `manage.py`: Migration script to perform database migration using Flask-migrate.\n+* `config.py` : Application directory, SQLALCHEMY_DATABASE_URI , Secret keys etc shall be put in this file.\n+* `models.py` : All the models shall be defined using SQLAlchemy in this file.\n+* `views.py` : All the controllers, API endpoints shall be defined here.\n+* `__init__.py` : Defining the database object, database creation shall be done here.\n+* `templates` : The front end HTML files shall be kept here.\n+* `static` : The Bootstrap, js, CSS files, images (if any) etc shall be kept here.\n+\n+**Rough Directory Structure** :\n+```\n+~/Installation_server\n+    |-- run.py\n+    |-- manage.py\n+    |-- config.py\n+    |__ /env             # Virtual Environment\n+    |__ /app             # Our Application        \n+         |-- __init__.py\n+         |-- views.py\n+         |-- models.py\n+         |__ /templates\n+             |-- 404.html\n+             |__ /auth\n+                 |-- signin.html\n+         |__ /static\n+```\n+**Tentative python modules** to be used :\n+`flask`, `flask-SQLAlchemy`, `Jinja2`, `SQLAlchemy`, `flask-migrate`, `flask-login` , 'platform', `plotly.plotly`, `plotly.graph_objs`, `requests`, `datetime`, `os`, `unittest` , `logging` etc..","path":"2016/proposals/result-aggregation-server-garg-prerit.md","position":null,"original_position":272,"commit_id":"93a37359468a2a672a33785efffeb2833ba58056","original_commit_id":"381774be7663f0192fcf88dc805022dc0574dbd7","user":{"login":"prerit2010","id":5612204,"avatar_url":"https://avatars.githubusercontent.com/u/5612204?v=3","gravatar_id":"","url":"https://api.github.com/users/prerit2010","html_url":"https://github.com/prerit2010","followers_url":"https://api.github.com/users/prerit2010/followers","following_url":"https://api.github.com/users/prerit2010/following{/other_user}","gists_url":"https://api.github.com/users/prerit2010/gists{/gist_id}","starred_url":"https://api.github.com/users/prerit2010/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/prerit2010/subscriptions","organizations_url":"https://api.github.com/users/prerit2010/orgs","repos_url":"https://api.github.com/users/prerit2010/repos","events_url":"https://api.github.com/users/prerit2010/events{/privacy}","received_events_url":"https://api.github.com/users/prerit2010/received_events","type":"User","site_admin":false},"body":"Done!","created_at":"2016-03-19T21:19:28Z","updated_at":"2016-03-19T21:19:28Z","html_url":"https://github.com/numfocus/gsoc/pull/103#discussion_r56755278","pull_request_url":"https://api.github.com/repos/numfocus/gsoc/pulls/103","_links":{"self":{"href":"https://api.github.com/repos/numfocus/gsoc/pulls/comments/56755278"},"html":{"href":"https://github.com/numfocus/gsoc/pull/103#discussion_r56755278"},"pull_request":{"href":"https://api.github.com/repos/numfocus/gsoc/pulls/103"}}},"pull_request":{"url":"https://api.github.com/repos/numfocus/gsoc/pulls/103","id":61914322,"html_url":"https://github.com/numfocus/gsoc/pull/103","diff_url":"https://github.com/numfocus/gsoc/pull/103.diff","patch_url":"https://github.com/numfocus/gsoc/pull/103.patch","issue_url":"https://api.github.com/repos/numfocus/gsoc/issues/103","number":103,"state":"open","locked":false,"title":"Prerit Garg : Result Aggregation Server for installation-test-scripts","user":{"login":"prerit2010","id":5612204,"avatar_url":"https://avatars.githubusercontent.com/u/5612204?v=3","gravatar_id":"","url":"https://api.github.com/users/prerit2010","html_url":"https://github.com/prerit2010","followers_url":"https://api.github.com/users/prerit2010/followers","following_url":"https://api.github.com/users/prerit2010/following{/other_user}","gists_url":"https://api.github.com/users/prerit2010/gists{/gist_id}","starred_url":"https://api.github.com/users/prerit2010/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/prerit2010/subscriptions","organizations_url":"https://api.github.com/users/prerit2010/orgs","repos_url":"https://api.github.com/users/prerit2010/repos","events_url":"https://api.github.com/users/prerit2010/events{/privacy}","received_events_url":"https://api.github.com/users/prerit2010/received_events","type":"User","site_admin":false},"body":"Checklist for prospect students for Google Summer of Code 2016:\r\n\r\n- [x] I contacted NumFOCUS mentors before writing my proposal\r\n- [x] I showed you my contribution (it can be any form: proof-of-concept project idea, some sample code or just a link to your commits from other project)\r\n- [x] I linked to my sample contribution from the proposal\r\n- [x] I linked to my opened issues in numfocus/gsoc repository from the proposal\r\n\r\n","created_at":"2016-03-07T13:05:24Z","updated_at":"2016-03-19T21:19:28Z","closed_at":null,"merged_at":null,"merge_commit_sha":"686fb6be64fd85408f23a1929360c9a5da270454","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/numfocus/gsoc/pulls/103/commits","review_comments_url":"https://api.github.com/repos/numfocus/gsoc/pulls/103/comments","review_comment_url":"https://api.github.com/repos/numfocus/gsoc/pulls/comments{/number}","comments_url":"https://api.github.com/repos/numfocus/gsoc/issues/103/comments","statuses_url":"https://api.github.com/repos/numfocus/gsoc/statuses/93a37359468a2a672a33785efffeb2833ba58056","head":{"label":"prerit2010:master","ref":"master","sha":"93a37359468a2a672a33785efffeb2833ba58056","user":{"login":"prerit2010","id":5612204,"avatar_url":"https://avatars.githubusercontent.com/u/5612204?v=3","gravatar_id":"","url":"https://api.github.com/users/prerit2010","html_url":"https://github.com/prerit2010","followers_url":"https://api.github.com/users/prerit2010/followers","following_url":"https://api.github.com/users/prerit2010/following{/other_user}","gists_url":"https://api.github.com/users/prerit2010/gists{/gist_id}","starred_url":"https://api.github.com/users/prerit2010/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/prerit2010/subscriptions","organizations_url":"https://api.github.com/users/prerit2010/orgs","repos_url":"https://api.github.com/users/prerit2010/repos","events_url":"https://api.github.com/users/prerit2010/events{/privacy}","received_events_url":"https://api.github.com/users/prerit2010/received_events","type":"User","site_admin":false},"repo":{"id":53066530,"name":"gsoc","full_name":"prerit2010/gsoc","owner":{"login":"prerit2010","id":5612204,"avatar_url":"https://avatars.githubusercontent.com/u/5612204?v=3","gravatar_id":"","url":"https://api.github.com/users/prerit2010","html_url":"https://github.com/prerit2010","followers_url":"https://api.github.com/users/prerit2010/followers","following_url":"https://api.github.com/users/prerit2010/following{/other_user}","gists_url":"https://api.github.com/users/prerit2010/gists{/gist_id}","starred_url":"https://api.github.com/users/prerit2010/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/prerit2010/subscriptions","organizations_url":"https://api.github.com/users/prerit2010/orgs","repos_url":"https://api.github.com/users/prerit2010/repos","events_url":"https://api.github.com/users/prerit2010/events{/privacy}","received_events_url":"https://api.github.com/users/prerit2010/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/prerit2010/gsoc","description":"Numfocus Google Summer of Code Materials","fork":true,"url":"https://api.github.com/repos/prerit2010/gsoc","forks_url":"https://api.github.com/repos/prerit2010/gsoc/forks","keys_url":"https://api.github.com/repos/prerit2010/gsoc/keys{/key_id}","collaborators_url":"https://api.github.com/repos/prerit2010/gsoc/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/prerit2010/gsoc/teams","hooks_url":"https://api.github.com/repos/prerit2010/gsoc/hooks","issue_events_url":"https://api.github.com/repos/prerit2010/gsoc/issues/events{/number}","events_url":"https://api.github.com/repos/prerit2010/gsoc/events","assignees_url":"https://api.github.com/repos/prerit2010/gsoc/assignees{/user}","branches_url":"https://api.github.com/repos/prerit2010/gsoc/branches{/branch}","tags_url":"https://api.github.com/repos/prerit2010/gsoc/tags","blobs_url":"https://api.github.com/repos/prerit2010/gsoc/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/prerit2010/gsoc/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/prerit2010/gsoc/git/refs{/sha}","trees_url":"https://api.github.com/repos/prerit2010/gsoc/git/trees{/sha}","statuses_url":"https://api.github.com/repos/prerit2010/gsoc/statuses/{sha}","languages_url":"https://api.github.com/repos/prerit2010/gsoc/languages","stargazers_url":"https://api.github.com/repos/prerit2010/gsoc/stargazers","contributors_url":"https://api.github.com/repos/prerit2010/gsoc/contributors","subscribers_url":"https://api.github.com/repos/prerit2010/gsoc/subscribers","subscription_url":"https://api.github.com/repos/prerit2010/gsoc/subscription","commits_url":"https://api.github.com/repos/prerit2010/gsoc/commits{/sha}","git_commits_url":"https://api.github.com/repos/prerit2010/gsoc/git/commits{/sha}","comments_url":"https://api.github.com/repos/prerit2010/gsoc/comments{/number}","issue_comment_url":"https://api.github.com/repos/prerit2010/gsoc/issues/comments{/number}","contents_url":"https://api.github.com/repos/prerit2010/gsoc/contents/{+path}","compare_url":"https://api.github.com/repos/prerit2010/gsoc/compare/{base}...{head}","merges_url":"https://api.github.com/repos/prerit2010/gsoc/merges","archive_url":"https://api.github.com/repos/prerit2010/gsoc/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/prerit2010/gsoc/downloads","issues_url":"https://api.github.com/repos/prerit2010/gsoc/issues{/number}","pulls_url":"https://api.github.com/repos/prerit2010/gsoc/pulls{/number}","milestones_url":"https://api.github.com/repos/prerit2010/gsoc/milestones{/number}","notifications_url":"https://api.github.com/repos/prerit2010/gsoc/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/prerit2010/gsoc/labels{/name}","releases_url":"https://api.github.com/repos/prerit2010/gsoc/releases{/id}","deployments_url":"https://api.github.com/repos/prerit2010/gsoc/deployments","created_at":"2016-03-03T16:43:39Z","updated_at":"2016-03-03T07:21:49Z","pushed_at":"2016-03-19T21:16:15Z","git_url":"git://github.com/prerit2010/gsoc.git","ssh_url":"git@github.com:prerit2010/gsoc.git","clone_url":"https://github.com/prerit2010/gsoc.git","svn_url":"https://github.com/prerit2010/gsoc","homepage":"http://numfocus.org/programs/gsoc.html","size":1552,"stargazers_count":0,"watchers_count":0,"language":null,"has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"numfocus:master","ref":"master","sha":"3e107964de8530fc70309e49f57605688c4799d2","user":{"login":"numfocus","id":1421094,"avatar_url":"https://avatars.githubusercontent.com/u/1421094?v=3","gravatar_id":"","url":"https://api.github.com/users/numfocus","html_url":"https://github.com/numfocus","followers_url":"https://api.github.com/users/numfocus/followers","following_url":"https://api.github.com/users/numfocus/following{/other_user}","gists_url":"https://api.github.com/users/numfocus/gists{/gist_id}","starred_url":"https://api.github.com/users/numfocus/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/numfocus/subscriptions","organizations_url":"https://api.github.com/users/numfocus/orgs","repos_url":"https://api.github.com/users/numfocus/repos","events_url":"https://api.github.com/users/numfocus/events{/privacy}","received_events_url":"https://api.github.com/users/numfocus/received_events","type":"Organization","site_admin":false},"repo":{"id":30978155,"name":"gsoc","full_name":"numfocus/gsoc","owner":{"login":"numfocus","id":1421094,"avatar_url":"https://avatars.githubusercontent.com/u/1421094?v=3","gravatar_id":"","url":"https://api.github.com/users/numfocus","html_url":"https://github.com/numfocus","followers_url":"https://api.github.com/users/numfocus/followers","following_url":"https://api.github.com/users/numfocus/following{/other_user}","gists_url":"https://api.github.com/users/numfocus/gists{/gist_id}","starred_url":"https://api.github.com/users/numfocus/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/numfocus/subscriptions","organizations_url":"https://api.github.com/users/numfocus/orgs","repos_url":"https://api.github.com/users/numfocus/repos","events_url":"https://api.github.com/users/numfocus/events{/privacy}","received_events_url":"https://api.github.com/users/numfocus/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/numfocus/gsoc","description":"Numfocus Google Summer of Code Materials","fork":false,"url":"https://api.github.com/repos/numfocus/gsoc","forks_url":"https://api.github.com/repos/numfocus/gsoc/forks","keys_url":"https://api.github.com/repos/numfocus/gsoc/keys{/key_id}","collaborators_url":"https://api.github.com/repos/numfocus/gsoc/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/numfocus/gsoc/teams","hooks_url":"https://api.github.com/repos/numfocus/gsoc/hooks","issue_events_url":"https://api.github.com/repos/numfocus/gsoc/issues/events{/number}","events_url":"https://api.github.com/repos/numfocus/gsoc/events","assignees_url":"https://api.github.com/repos/numfocus/gsoc/assignees{/user}","branches_url":"https://api.github.com/repos/numfocus/gsoc/branches{/branch}","tags_url":"https://api.github.com/repos/numfocus/gsoc/tags","blobs_url":"https://api.github.com/repos/numfocus/gsoc/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/numfocus/gsoc/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/numfocus/gsoc/git/refs{/sha}","trees_url":"https://api.github.com/repos/numfocus/gsoc/git/trees{/sha}","statuses_url":"https://api.github.com/repos/numfocus/gsoc/statuses/{sha}","languages_url":"https://api.github.com/repos/numfocus/gsoc/languages","stargazers_url":"https://api.github.com/repos/numfocus/gsoc/stargazers","contributors_url":"https://api.github.com/repos/numfocus/gsoc/contributors","subscribers_url":"https://api.github.com/repos/numfocus/gsoc/subscribers","subscription_url":"https://api.github.com/repos/numfocus/gsoc/subscription","commits_url":"https://api.github.com/repos/numfocus/gsoc/commits{/sha}","git_commits_url":"https://api.github.com/repos/numfocus/gsoc/git/commits{/sha}","comments_url":"https://api.github.com/repos/numfocus/gsoc/comments{/number}","issue_comment_url":"https://api.github.com/repos/numfocus/gsoc/issues/comments{/number}","contents_url":"https://api.github.com/repos/numfocus/gsoc/contents/{+path}","compare_url":"https://api.github.com/repos/numfocus/gsoc/compare/{base}...{head}","merges_url":"https://api.github.com/repos/numfocus/gsoc/merges","archive_url":"https://api.github.com/repos/numfocus/gsoc/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/numfocus/gsoc/downloads","issues_url":"https://api.github.com/repos/numfocus/gsoc/issues{/number}","pulls_url":"https://api.github.com/repos/numfocus/gsoc/pulls{/number}","milestones_url":"https://api.github.com/repos/numfocus/gsoc/milestones{/number}","notifications_url":"https://api.github.com/repos/numfocus/gsoc/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/numfocus/gsoc/labels{/name}","releases_url":"https://api.github.com/repos/numfocus/gsoc/releases{/id}","deployments_url":"https://api.github.com/repos/numfocus/gsoc/deployments","created_at":"2015-02-18T17:54:16Z","updated_at":"2016-03-18T05:37:58Z","pushed_at":"2016-03-19T21:16:16Z","git_url":"git://github.com/numfocus/gsoc.git","ssh_url":"git@github.com:numfocus/gsoc.git","clone_url":"https://github.com/numfocus/gsoc.git","svn_url":"https://github.com/numfocus/gsoc","homepage":"http://numfocus.org/programs/gsoc.html","size":1656,"stargazers_count":19,"watchers_count":19,"language":null,"has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":58,"mirror_url":null,"open_issues_count":34,"forks":58,"open_issues":34,"watchers":19,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/numfocus/gsoc/pulls/103"},"html":{"href":"https://github.com/numfocus/gsoc/pull/103"},"issue":{"href":"https://api.github.com/repos/numfocus/gsoc/issues/103"},"comments":{"href":"https://api.github.com/repos/numfocus/gsoc/issues/103/comments"},"review_comments":{"href":"https://api.github.com/repos/numfocus/gsoc/pulls/103/comments"},"review_comment":{"href":"https://api.github.com/repos/numfocus/gsoc/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/numfocus/gsoc/pulls/103/commits"},"statuses":{"href":"https://api.github.com/repos/numfocus/gsoc/statuses/93a37359468a2a672a33785efffeb2833ba58056"}}}}