Eswari Pravallika Swarna vor 10 Jahren
Commit
6e45e27e5a
42 geänderte Dateien mit 2578 neuen und 0 gelöschten Zeilen
  1. 9 0
      .hgignore
  2. 249 0
      README.md
  3. 20 0
      bower.json
  4. 0 0
      hackathon_starter/hackathon/__init__.py
  5. 5 0
      hackathon_starter/hackathon/admin.py
  6. 11 0
      hackathon_starter/hackathon/forms.py
  7. 0 0
      hackathon_starter/hackathon/migrations/__init__.py
  8. 11 0
      hackathon_starter/hackathon/models.py
  9. 0 0
      hackathon_starter/hackathon/scripts/__init__.py
  10. 162 0
      hackathon_starter/hackathon/scripts/github.py
  11. 24 0
      hackathon_starter/hackathon/scripts/linkedin.py
  12. 29 0
      hackathon_starter/hackathon/scripts/steam.py
  13. 150 0
      hackathon_starter/hackathon/scripts/tumblr.py
  14. 26 0
      hackathon_starter/hackathon/static/css/form.css
  15. BIN
      hackathon_starter/hackathon/static/img/github.png
  16. BIN
      hackathon_starter/hackathon/static/img/linkedin.jpg
  17. BIN
      hackathon_starter/hackathon/static/img/steam.png
  18. BIN
      hackathon_starter/hackathon/static/img/tumblr.png
  19. 16 0
      hackathon_starter/hackathon/templates/hackathon/api_examples.html
  20. 61 0
      hackathon_starter/hackathon/templates/hackathon/base.html
  21. 110 0
      hackathon_starter/hackathon/templates/hackathon/github.html
  22. 14 0
      hackathon_starter/hackathon/templates/hackathon/index.html
  23. 25 0
      hackathon_starter/hackathon/templates/hackathon/linkedin.html
  24. 47 0
      hackathon_starter/hackathon/templates/hackathon/login.html
  25. 40 0
      hackathon_starter/hackathon/templates/hackathon/navbar.html
  26. 42 0
      hackathon_starter/hackathon/templates/hackathon/register.html
  27. 12 0
      hackathon_starter/hackathon/templates/hackathon/steam.html
  28. 61 0
      hackathon_starter/hackathon/templates/hackathon/tumblr.html
  29. 3 0
      hackathon_starter/hackathon/tests.py
  30. 0 0
      hackathon_starter/hackathon/unittests/__init__.py
  31. 8 0
      hackathon_starter/hackathon/unittests/testcase.py
  32. 192 0
      hackathon_starter/hackathon/unittests/testgithub.py
  33. 925 0
      hackathon_starter/hackathon/unittests/teststeam.py
  34. 31 0
      hackathon_starter/hackathon/unittests/testtumblr.py
  35. 16 0
      hackathon_starter/hackathon/urls.py
  36. 117 0
      hackathon_starter/hackathon/views.py
  37. 0 0
      hackathon_starter/hackathon_starter/__init__.py
  38. 109 0
      hackathon_starter/hackathon_starter/settings.py
  39. 8 0
      hackathon_starter/hackathon_starter/urls.py
  40. 14 0
      hackathon_starter/hackathon_starter/wsgi.py
  41. 10 0
      hackathon_starter/manage.py
  42. 21 0
      requirements.txt

+ 9 - 0
.hgignore

@@ -0,0 +1,9 @@
+syntax: glob
+
+.DS_Store
+db.sqlite3
+*.pyc
+bower_components/
+migrations/
+*.coverage
+Thumbs.db

+ 249 - 0
README.md

@@ -0,0 +1,249 @@
+Django Hackathon Starter
+------------------------
+
+## What is Django Hackathon Starter
+
+> Django Hackathon Starter aims to be a project which will aggegrate data from several APIs, producing a RESTful API which can be consumed by a client (also intended to be built). 
+
+Our deployment can be found [here](http://django-hackathon-starter.herokuapp.com/hackathon/).
+
+## Running this project
+
+In order to run this project, do the following:
+
+    # Install the requirements
+    pip install -r requirements.txt
+
+    # Perform database migrations
+    python manage.py migrate
+
+    # Run the server
+    python manage.py runserver
+
+## Front End dependencies
+
+This project relies on Bower for all front end libraries, to avoid pushing up large libraries such as `jQuery` and `Bootstrap`. To install `bower`, you will need to install `npm`, which now comes bundled with `node.js`. To install `npm`, simply install [node as follows](https://github.com/joyent/node/wiki/installing-node.js-via-package-manager). 
+
+First, install `bower`:
+
+    npm install -g bower
+
+Then:
+
+    bower install
+
+This will download and extract all the packages listed within `bower.json`. **Under no circumstance should any front-end libraries manually be pushed up to the repository.**
+
+Two routes have currently been set up, which are located at:
+
+    # First test route
+    http://127.0.0.1:8000/hackathon/
+
+    # Second test route
+    http://127.0.0.1:8000/hackathon/test
+
+
+## Testing
+
+This project aims to be as close to 100% tested as possible. For a good guide to testing using Python and `Mock`, `Nosetests` and `Unittests` libraries, please [read here](http://docs.python-guide.org/en/latest/writing/tests/).
+
+To run the tests:
+
+    hackthon-starter $ python manage.py test hackathon/unittests/
+
+You will see an output as shown below:
+
+    Name                                   Stmts   Miss  Cover   Missing
+    --------------------------------------------------------------------
+    hackathon/__init__.py                      0      0   100%
+    hackathon/admin.py                         3      3     0%   1-5
+    hackathon/forms.py                         9      9     0%   1-11
+    hackathon/migrations/0001_initial.py       6      0   100%
+    hackathon/migrations/__init__.py           0      0   100%
+    hackathon/models.py                        6      6     0%   1-11
+    hackathon/scripts/__init__.py              0      0   100%
+    hackathon/scripts/github.py              106     96     9%   17-34, 41-64, 69-97, 102-121, 126-132, 139-165, 169-175
+    hackathon/scripts/linkedin.py             19     19     0%   1-24
+    hackathon/scripts/samplescript.py   NoSource: No source for code: '/Users/DrkSephy/Documents/django-hackathon-starter/hackathon_starter/hackathon/scripts/samplescript.py'.
+    hackathon/scripts/steam.py                15     15     0%   3-29
+    hackathon/scripts/tumblr.py               60     60     0%   1-85
+    hackathon/tests.py                         1      0   100%
+    hackathon/urls.py                          3      3     0%   1-5
+    hackathon/views.py                        76     76     0%   1-157
+    --------------------------------------------------------------------
+    TOTAL                                    304    287     6%
+    ----------------------------------------------------------------------
+    Ran 2 tests in 0.002s
+
+    OK
+    Destroying test database for alias 'default'...
+
+## Code evaluation
+
+In order to write clean code with a consistent style guide, we'll be using `Pylint` to maintain our code. Pylint will display a ton of messages regarding things that should be fixed. A sample output from running `pylint views.py` is shown below:
+
+    (web)λ pylint views.py
+    No config file found, using default configuration
+    ************* Module hackathon.views
+    C:  7, 0: Trailing whitespace (trailing-whitespace)
+    W: 11, 0: Found indentation with tabs instead of spaces (mixed-indentation)
+    W: 12, 0: Found indentation with tabs instead of spaces (mixed-indentation)
+    W: 15, 0: Found indentation with tabs instead of spaces (mixed-indentation)
+    C: 59, 0: Wrong continued indentation.
+                'hackathon/register.html',
+                ^     | (bad-continuation)
+    C: 60, 0: Wrong continued indentation.
+                {'user_form': user_form, 'registered': registered} )
+                ^     | (bad-continuation)
+    C: 60, 0: No space allowed before bracket
+                {'user_form': user_form, 'registered': registered} )
+                                                                   ^ (bad-whitespace)
+    C: 69, 0: Line too long (103/100) (line-too-long)
+    C:116, 0: Exactly one space required after comma
+        return render(request,'hackathon/steam.html', {"game": game })
+                             ^ (bad-whitespace)
+    C:116, 0: No space allowed before bracket
+        return render(request,'hackathon/steam.html', {"game": game })
+                                                                    ^ (bad-whitespace)
+    C:  1, 0: Missing module docstring (missing-docstring)
+    W:  7, 0: Relative import 'scripts.steam', should be 'hackathon.scripts.steam' (relative-import)
+    C: 10, 0: Missing function docstring (missing-docstring)
+    C: 14, 0: Missing function docstring (missing-docstring)
+    W: 14, 9: Unused argument 'request' (unused-argument)
+    C: 17, 0: Missing function docstring (missing-docstring)
+    C: 21, 0: Missing function docstring (missing-docstring)
+    C: 62, 0: Missing function docstring (missing-docstring)
+    C:103, 0: Missing function docstring (missing-docstring)
+    C:110, 0: Missing function docstring (missing-docstring)
+    C:113, 4: Invalid variable name "SteamUN" (invalid-name)
+    C:114, 4: Invalid variable name "steamID" (invalid-name)
+    C:118, 0: Missing function docstring (missing-docstring)
+    W:  4, 0: Unused RequestContext imported from django.template (unused-import)
+    W:  4, 0: Unused loader imported from django.template (unused-import)
+
+
+    Report
+    ======
+    53 statements analysed.
+
+    Statistics by type
+    ------------------
+
+    +---------+-------+-----------+-----------+------------+---------+
+    |type     |number |old number |difference |%documented |%badname |
+    +=========+=======+===========+===========+============+=========+
+    |module   |1      |NC         |NC         |0.00        |0.00     |
+    +---------+-------+-----------+-----------+------------+---------+
+    |class    |0      |NC         |NC         |0           |0        |
+    +---------+-------+-----------+-----------+------------+---------+
+    |method   |0      |NC         |NC         |0           |0        |
+    +---------+-------+-----------+-----------+------------+---------+
+    |function |8      |NC         |NC         |0.00        |0.00     |
+    +---------+-------+-----------+-----------+------------+---------+
+
+
+
+    External dependencies
+    ---------------------
+    ::
+
+        django
+          \-contrib
+          | \-auth (hackathon.views)
+          \-http (hackathon.views)
+          \-shortcuts (hackathon.views)
+          \-template (hackathon.views)
+            \-loader (hackathon.views)
+        hackathon
+          \-forms (hackathon.views)
+          \-scripts
+            \-steam (hackathon.views)
+
+
+
+    Raw metrics
+    -----------
+
+    +----------+-------+------+---------+-----------+
+    |type      |number |%     |previous |difference |
+    +==========+=======+======+=========+===========+
+    |code      |59     |59.00 |NC       |NC         |
+    +----------+-------+------+---------+-----------+
+    |docstring |1      |1.00  |NC       |NC         |
+    +----------+-------+------+---------+-----------+
+    |comment   |29     |29.00 |NC       |NC         |
+    +----------+-------+------+---------+-----------+
+    |empty     |11     |11.00 |NC       |NC         |
+    +----------+-------+------+---------+-----------+
+
+
+
+    Duplication
+    -----------
+
+    +-------------------------+------+---------+-----------+
+    |                         |now   |previous |difference |
+    +=========================+======+=========+===========+
+    |nb duplicated lines      |0     |NC       |NC         |
+    +-------------------------+------+---------+-----------+
+    |percent duplicated lines |0.000 |NC       |NC         |
+    +-------------------------+------+---------+-----------+
+
+
+
+    Messages by category
+    --------------------
+
+    +-----------+-------+---------+-----------+
+    |type       |number |previous |difference |
+    +===========+=======+=========+===========+
+    |convention |18     |NC       |NC         |
+    +-----------+-------+---------+-----------+
+    |refactor   |0      |NC       |NC         |
+    +-----------+-------+---------+-----------+
+    |warning    |7      |NC       |NC         |
+    +-----------+-------+---------+-----------+
+    |error      |0      |NC       |NC         |
+    +-----------+-------+---------+-----------+
+
+
+
+    Messages
+    --------
+
+    +--------------------+------------+
+    |message id          |occurrences |
+    +====================+============+
+    |missing-docstring   |9           |
+    +--------------------+------------+
+    |mixed-indentation   |3           |
+    +--------------------+------------+
+    |bad-whitespace      |3           |
+    +--------------------+------------+
+    |unused-import       |2           |
+    +--------------------+------------+
+    |invalid-name        |2           |
+    +--------------------+------------+
+    |bad-continuation    |2           |
+    +--------------------+------------+
+    |unused-argument     |1           |
+    +--------------------+------------+
+    |trailing-whitespace |1           |
+    +--------------------+------------+
+    |relative-import     |1           |
+    +--------------------+------------+
+    |line-too-long       |1           |
+    +--------------------+------------+
+
+
+
+    Global evaluation
+    -----------------
+    Your code has been rated at 5.28/10
+
+## Contributors
+
+* David Leonard
+* Eswari Swarna
+* Marco Quezada 
+* Wan Kim Mok

+ 20 - 0
bower.json

@@ -0,0 +1,20 @@
+{
+  "name": "django-hackathon-starter",
+  "version": "0.0.0",
+  "authors": [
+    "David Leonard <sephirothcloud1025@yahoo.com>"
+  ],
+  "description": "Django boilerplate project for hackathons",
+  "keywords": [
+    "Django",
+    "Python",
+    "API",
+    "RESTful"
+  ],
+  "license": "MIT",
+  "dependencies": {
+    "bootstrap": "~3.3.4",
+    "jquery": "~2.1.3",
+    "bootstrap-social":"~4"
+  }
+}

+ 0 - 0
hackathon_starter/hackathon/__init__.py


+ 5 - 0
hackathon_starter/hackathon/admin.py

@@ -0,0 +1,5 @@
+from django.contrib import admin
+from hackathon.models import UserProfile
+
+# Register your models here.
+admin.site.register(UserProfile)

+ 11 - 0
hackathon_starter/hackathon/forms.py

@@ -0,0 +1,11 @@
+from django.contrib.auth.forms import UserCreationForm
+from django.contrib.auth.models import User
+from django import forms
+from hackathon.models import UserProfile
+
+class UserForm(forms.ModelForm):
+    password = forms.CharField(widget=forms.PasswordInput())
+
+    class Meta:
+        model = User
+        fields = ('username', 'email', 'password')

+ 0 - 0
hackathon_starter/hackathon/migrations/__init__.py


+ 11 - 0
hackathon_starter/hackathon/models.py

@@ -0,0 +1,11 @@
+from django.db import models
+from django.contrib.auth.models import User
+
+# Create your models here.
+class UserProfile(models.Model):
+    # This line is required. Links UserProfile to a User model instance.
+    user = models.OneToOneField(User)
+
+    # Override the __unicode__() method to return out something meaningful!
+    def __unicode__(self):
+        return self.user.username

+ 0 - 0
hackathon_starter/hackathon/scripts/__init__.py


+ 162 - 0
hackathon_starter/hackathon/scripts/github.py

@@ -0,0 +1,162 @@
+'''
+Module github.py contains a handful of methods
+for interacting with Github data.
+'''
+
+import requests
+import simplejson as json
+
+########################
+# GITHUB API CONSTANTS #
+########################
+
+API_BASE_URL = 'https://api.github.com/users/DrkSephy'
+
+def getUserData(clientID, clientSecret):
+	'''Get generic Github User data.'''
+	url = API_BASE_URL + '?' + clientID + '&' + clientSecret
+	req = requests.get(url)
+	jsonList = []
+	jsonList.append(json.loads(req.content))
+	parsedData = []
+	userData = {}
+	for data in jsonList: 
+		userData['name'] = data['name']
+		userData['blog'] = data['blog']
+		userData['email'] = data['email']
+		userData['public_gists'] = data['public_gists']
+		userData['public_repos'] = data['public_repos']
+		userData['avatar_url'] = data['avatar_url']
+		userData['followers'] = data['followers']
+		userData['following'] = data['following']
+	parsedData.append(userData)
+
+	return parsedData
+	
+
+def getUserRepositories(clientID, clientSecret):
+	'''Get a list of all repositories owned by a User.'''
+
+	pageNumber = 1
+
+
+	jsonList = []
+	repositories = []
+
+	while True:
+		req = requests.get('https://api.github.com/users/DrkSephy/repos?page=' + str(pageNumber) + '&' + clientID + '&' + clientSecret)
+		jsonList.append(json.loads(req.content))
+		if len(json.loads(req.content)) < 30:
+			break
+		elif len(json.loads(req.content)) >= 30:
+			pageNumber += 1
+
+	
+	for data in jsonList:
+		for datum in data:
+			repositories.append(datum['name'])
+			
+	return repositories
+
+def getForkedRepositories(clientID, clientSecret):
+	'''Get a list of all forked repositories by a user.'''
+	
+	pageNumber = 1
+
+	
+	jsonList = []
+
+	
+	forkedRepositories = []
+ 
+	while True:
+		req = requests.get('https://api.github.com/users/DrkSephy/repos?page=' + str(pageNumber) + '&' + clientID + '&' + clientSecret)
+		jsonList.append(json.loads(req.content))
+		if len(json.loads(req.content)) < 30:
+			break
+		elif len(json.loads(req.content)) >= 30:
+			pageNumber += 1
+
+
+	forkedRepos = {}
+	for data in jsonList:
+		for datum in data:
+			if datum['fork'] == True:
+				forkedRepos['name'] = datum['name']
+				forkedRepositories.append(forkedRepos)
+				forkedRepos = {}
+
+	return forkedRepositories
+
+def getTopContributedRepositories(repos, clientID, clientSecret):
+	'''Get a list of all commits for each repository owned.'''
+
+	jsonList = []
+	for repo in repos:
+		req = requests.get('https://api.github.com/repos/DrkSephy/' + repo + '/stats/contributors' + '?' + clientID + '&' + clientSecret)
+		jsonList.append(json.loads(req.content))
+
+	parsedData = []
+
+	indexNumber = -1
+	for item in jsonList:
+		indexNumber += 1
+		commits = {}
+		for data in item:
+			if data['author']['login'] == 'DrkSephy':
+				commits['author'] = data['author']['login']
+				commits['total'] = data['total']
+				commits['repo_name'] = repos[indexNumber]
+				parsedData.append(commits)
+
+	return parsedData
+
+def filterCommits(data):
+	'''Returns the top 10 committed repositories.'''
+
+	maxCommits = []
+	for i in range(1, 10):
+		maxCommitedRepo = max(data, key=lambda x:x['total'])
+		maxCommits.append(maxCommitedRepo)
+		index = data.index(maxCommitedRepo)
+		data.pop(index)
+	return maxCommits
+	
+	
+def getStarGazerCount(clientID, clientSecret):
+	'''Get Stargazer counts for all repositories.'''
+	
+	pageNumber = 1
+	jsonList = []
+	stargazers = []
+	while True:
+		req = requests.get('https://api.github.com/users/DrkSephy/repos?page=' + str(pageNumber) + '&' + clientID + '&' + clientSecret)
+		jsonList.append(json.loads(req.content))
+		if len(json.loads(req.content)) < 30:
+			break
+		elif len(json.loads(req.content)) >= 30:
+			pageNumber += 1
+
+
+	for data in jsonList:
+		for datum in data:
+			starData = {}
+			starData['stargazers_count'] = datum['stargazers_count']
+			starData['name'] = datum['name']
+			stargazers.append(starData)
+			
+	return stargazers
+
+def filterStarGazerCount(data):
+	'''Return top 10 starred repositories.'''
+	maxStars= []
+	for i in range(1, 10):
+		maxStarGazers = max(data, key=lambda x:x['stargazers_count'])
+		maxStars.append(maxStarGazers)
+		index = data.index(maxStarGazers)
+		data.pop(index)
+	return maxStars
+
+
+
+

+ 24 - 0
hackathon_starter/hackathon/scripts/linkedin.py

@@ -0,0 +1,24 @@
+import requests
+import simplejson as json
+
+
+consumer_key    = "7895bbnlh1k0mn"
+consumer_secret = "7CjUx1xTsF2WDRAI"
+oauth_token  	= "60b8f2c4-28b6-498d-a645-9dffb8baf47d"
+oauth_secret	= "3114e3d4-d725-482d-a11c-2e7607025a27"
+
+def getUserInfo():
+	req = requests.get("https://api.linkedin.com/v1/people/~")
+	jlist = []
+	jlist.append(json.loads(req.content))
+	parsedData = []
+	userData = {}
+	for data in jlist: 
+		userData['firstname'] = data['firstname']
+		userData['lasttname'] = data['lastname']
+		userData['email'] = data['email']
+		userData['connections'] = data['connections']
+		
+	parsedData.append(userData)
+
+	return parsedData

+ 29 - 0
hackathon_starter/hackathon/scripts/steam.py

@@ -0,0 +1,29 @@
+# pylint: disable=C0303
+
+import requests
+import json
+
+SteamUN = "Marorin"
+key = '231E98D442E52B87110816C3D5114A1D'
+
+def gamesPulling(steamID,key):
+    # Returns the JSON data from the Steam API based of one's 
+    # Steam ID number and returns a dictionary of gameids and minutes played.
+    steaminfo = {
+        'key': key, 
+        'steamid': steamID,
+        'format':'JSON',
+        'include_appinfo':'1'
+    }
+    r = requests.get('http://api.steampowered.com/IPlayerService/GetOwnedGames/v0001/', params=steaminfo)
+    d = json.loads(r.content)
+    return d['response']['games']
+ 
+def steamIDPulling(SteamUN,key):
+    #Pulls out and returns the steam id number for use in steam queries.
+    steaminfo = {'key': key,'vanityurl': SteamUN}
+    a = requests.get('http://api.steampowered.com/ISteamUser/ResolveVanityURL/v0001/', params=steaminfo)
+    k = json.loads(a.content)
+    SteamID = k['response']['steamid']
+    
+    return SteamID

+ 150 - 0
hackathon_starter/hackathon/scripts/tumblr.py

@@ -0,0 +1,150 @@
+import requests
+import simplejson as json
+import time 
+import urllib
+import re
+from bs4 import BeautifulSoup
+import urlparse
+import oauth2
+
+request_token_url   = 'http://www.tumblr.com/oauth/request_token'
+authorize_url       = 'http://www.tumblr.com/oauth/authorize'
+access_token_url    = 'http://www.tumblr.com/oauth/access_token'
+user_uri			= "http://api.tumblr.com/v2/user/info"
+blog_uri			= "http://api.tumblr.com/v2/blog/"
+
+class TumblrOauthClient(object):
+
+	token = None
+	oauth_token_secret = None
+	oauth_verifier = None
+
+
+	def __init__(self, consumer_key, consumer_secret, oauth_token =''):
+		self.consumer_key = consumer_key
+		self.consumer_secret = consumer_secret
+		self.consumer = oauth2.Consumer(consumer_key, consumer_secret)
+		self.oauth_token = oauth_token
+
+
+	def get_authorize_url(self):
+		client = oauth2.Client(self.consumer)
+		resp, content = client.request(request_token_url, "GET")
+
+		#if int(resp['status']) != 200:
+		#	raise Exception("Invalid response %s." % resp['status'])
+
+		#parse content
+		if not self.oauth_token:
+			request_token = dict(urlparse.parse_qsl(content))
+			self.oauth_token = request_token['oauth_token'] #'QBXdeeMKAnLzDbIG7dDNewTzRYyQoHZLbcn3bAFTCEFF5EXurl'
+			self.oauth_token_secret = request_token['oauth_token_secret']#'u10SuRl2nzS8vFK4K7UPQexAvbIFBFrZBjA79XDlgoXFxv9ZhO'
+
+		link = authorize_url+"?oauth_token="+self.oauth_token+"&redirect_uri=http%3A%2F%2Flocalhost%3A8000/hackathon/tumblr"
+		return link
+
+#"""
+
+	def get_access_token_url(self, oauth_verifier):
+		#print "verifier"
+		self.oauth_verifier = oauth_verifier
+		token = oauth2.Token(self.oauth_token, self.oauth_token_secret)
+		token.set_verifier(self.oauth_verifier)
+
+		client = oauth2.Client(self.consumer, token)
+		resp, content = client.request(access_token_url,"POST")
+
+		#print resp['status']
+
+		access_token = dict(urlparse.parse_qsl(content))
+		#print access_token
+
+		#set verified token
+		self.token = oauth2.Token(access_token['oauth_token'], access_token['oauth_token_secret'])
+
+	
+	def getUserInfo(self):
+		''' Returns users information. '''
+		client = oauth2.Client(self.consumer, self.token)
+		#print client
+		resp, content = client.request(user_uri, "POST")
+		if int(resp['status']) != 200:
+			raise Exception("Invalid response %s." % resp['status'])
+
+		#return content in json format
+		jsonlist = json.loads(content)
+		response = jsonlist['response']
+		user_info = response['user']
+		#print user_info
+		return user_info
+
+	def getBlogInfo(self, user):
+		''' Returns blogger's blog information '''
+		blog_info = blog_uri + user + ".tumblr.com/info?api_key="+self.consumer_key
+		req = requests.get(blog_info)
+		
+		if int(req.status_code) != 200:
+			raise Exception("Invalid response %s." % resp['status'])
+		
+
+		jsonlist = json.loads(req.content)
+		response = jsonlist['response']
+		blog 	 = response['blog']
+		blog['updated'] = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(blog['updated']))
+
+		return blog
+
+	def getTaggedInfo(self, tag):
+		''' Return tags related to blog with certain tag. '''
+
+		tagged_uri = "http://api.tumblr.com/v2/tagged?tag="+tag+"&api_key="+self.consumer_key+"&limit=20"
+		req = requests.get(tagged_uri)
+		jsonlist = json.loads(req.content)
+
+		tags = []
+
+		meta = jsonlist['meta']
+		body = jsonlist['response']
+		for blog in body:
+			for data in blog:
+				if data == "tags":
+					#print blog[data]
+					for i in blog[data]:
+						m = re.match("(.*)(s*)s(t*)t(a*)a(r*)r(b*)b(u*)u(c*)c(k*)k(.*)", i.lower())
+						if not m:
+							tags.append(i)					
+
+		return tags	
+
+	def getTaggedBlog(self, tag):
+		''' Return the tagged blogs's captions or post.'''
+		
+		tagged_uri = "http://api.tumblr.com/v2/tagged?tag="+tag+"&api_key="+self.consumer_key+"&limit=20"
+		req = requests.get(tagged_uri)
+		jsonlist = json.loads(req.content)
+		
+		meta = jsonlist['meta']
+		body = jsonlist['response']
+
+		tagtext = []
+
+		for blog in body:
+			#print "####"
+			for data in blog:
+				#post
+				if data == "body":
+					if blog[data]:
+						#print blog[data]
+						soup = BeautifulSoup(blog[data])
+						text = soup.get_text()
+						tagtext.append(text)
+				#an image
+				if data == "caption":
+					if blog[data]:
+						#print blog[data]
+						soup = BeautifulSoup(blog[data])
+						text = soup.get_text()					
+						tagtext.append(text)
+		
+		return tagtext
+#"""

+ 26 - 0
hackathon_starter/hackathon/static/css/form.css

@@ -0,0 +1,26 @@
+
+div.well{
+  height: 250px;
+} 
+
+.Absolute-Center {
+  margin: auto;
+  position: absolute;
+  top: 0; left: 0; bottom: 0; right: 0;
+}
+
+.Absolute-Center.is-Responsive {
+  width: 50%; 
+  height: 50%;
+  min-width: 200px;
+  max-width: 400px;
+  padding: 40px;
+}
+
+#logo-container{
+  margin: auto;
+  margin-bottom: 10px;
+  width:200px;
+  height:30px;
+  background-image:url('http://placehold.it/200x30/000000/ffffff/&text=Django+Hackathon+Starter');
+}

BIN
hackathon_starter/hackathon/static/img/github.png


BIN
hackathon_starter/hackathon/static/img/linkedin.jpg


BIN
hackathon_starter/hackathon/static/img/steam.png


BIN
hackathon_starter/hackathon/static/img/tumblr.png


+ 16 - 0
hackathon_starter/hackathon/templates/hackathon/api_examples.html

@@ -0,0 +1,16 @@
+<html>
+{% include 'hackathon/base.html' %}
+<body>
+
+
+	<div class="row text-center">
+	    <div class="col-sm-4"><a href="http://127.0.0.1:8000/hackathon/github/"><img src="/static/img/github.png"></a></div>
+	    <div class="col-sm-4"><a href="http://127.0.0.1:8000/hackathon/steam/"><img src="/static/img/steam.png"></a></div>
+	    <div class="col-sm-4"><img src="/static/img/github.png"></div>
+	    <div class="col-sm-4"><a href={{tumblr_url}}><img src="/static/img/tumblr.png"></a></div>
+		<div class="col-sm-4"><a href="http://127.0.0.1:8000/hackathon/linkedin/"><img src="/static/img/linkedin.jpg"></a></div>
+
+  	</div>
+
+</body>
+</html>

+ 61 - 0
hackathon_starter/hackathon/templates/hackathon/base.html

@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <title> Django Hackathon Starter </title>
+    <script src="/static/bower_components/jquery/dist/jquery.js"></script>
+    <script type="text/javascript" src="/static/bower_components/bootstrap/dist/js/bootstrap.min.js"></script>
+    
+    
+    <link rel="stylesheet" href="/static/bower_components/bootstrap/dist/css/bootstrap.min.css">
+    <link rel="stylesheet" href="/static/bower_components/bootstrap/dist/css/bootstrap-theme.min.css">
+    <link rel="stylesheet" href="/static/bower_components/bootstrap-social/bootstrap-social.css">
+    <link rel="stylesheet" href="/static/bower_components/font-awesome/css/font-awesome.min.css">
+
+  </head>
+    
+  <body>
+    <nav class="navbar navbar-default" role="navigation">
+      <div class="container-fluid">
+        <!-- Brand and toggle get grouped for better mobile display -->
+        <div class="navbar-header">
+          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
+            <span class="sr-only">Toggle navigation</span>
+            <span class="icon-bar"></span>
+            <span class="icon-bar"></span>
+            <span class="icon-bar"></span>
+          </button>
+          <a class="navbar-brand" href="/hackathon">Django Hackathon Starter</a>
+      </div>
+
+      <!-- Collect the nav links, forms, and other content for toggling -->
+      <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
+        <ul class="nav navbar-nav navbar-left">
+          {% if user.is_authenticated %}
+          <li><a href="/hackathon/api">API</a></li>
+          {% endif %}
+        </ul>
+        <ul class="nav navbar-nav navbar-right">
+          {% if not user.is_authenticated %}
+            <li class="active"><a href="/hackathon/register">Register <span class="sr-only">(current)</span></a></li>
+            
+            <li><a href="/hackathon/login">Login</a></li>
+          {% endif %}
+            
+        </ul>
+        
+        <ul  class="nav navbar-nav navbar-right">
+          {% if user.is_authenticated %}
+    
+            <li><a>Hello {{user}}</a></li>
+            <li><a href="/hackathon/logout/">Logout</a></li>
+          {% endif %}
+        </ul>
+          
+          
+          </li>
+         </ul>
+        </div><!-- /.navbar-collapse -->
+      </div><!-- /.container-fluid -->
+    </nav>
+  </body>
+</html>

+ 110 - 0
hackathon_starter/hackathon/templates/hackathon/github.html

@@ -0,0 +1,110 @@
+<!DOCTYPE html>
+<html>
+<body>
+	{% include 'hackathon/base.html' %}
+
+    <h1 class="text-center"> Github Resume </h1>
+	<div class="col-lg-12">
+        <div class="table-responsive">
+            <table class="table table-bordered table-hover table-striped tablesorter">
+                <thead>
+                <tr>
+                <th class="header"> Username <i class="icon-sort"></i></th>
+                <th class="header"> Blog <i class="icon-sort"></i></th>
+                <th class="header"> Public Repos <i class="icon-sort"></i></th>
+                <th class="header"> Public Gists <i class="icon-sort"></i></th>
+                <th class="header"> Email <i class="icon-sort"></i></th>
+                <th class="header"> Followers <i class="icon-sort"></i></th>
+                <th class="header"> Following <i class="icon-sort"></i></th>
+                </tr>
+            </thead>
+            <tbody>
+
+            {% for key in data.userData %}
+                <tr>
+                    <td>{{ key.name }}</td>
+                    <td>{{ key.blog }}</td>
+                    <td>{{ key.public_repos }}</td>
+                    <td>{{ key.public_gists }}</td>
+                    <td>{{ key.email }}</td>
+                    <td>{{ key.followers }}</td>
+                    <td>{{ key.following }}</td>
+    			</tr>
+            {% endfor %}
+
+            </tbody>
+            </table>
+        </div>
+    </div>
+
+    <div class="col-xs-4">
+        <h2> Top Contributed Repositories </h2>
+        <div class="table-responsive">
+            <table class="table table-bordered table-hover table-striped tablesorter">
+                <thead>
+                <tr>
+                <th class="header"> Repository <i class="icon-sort"></i></th>
+                <th class="header"> Total <i class="icon-sort"></i></th>
+                </tr>
+            </thead>
+            <tbody>
+
+            {% for key in data.filteredData %}
+                <tr>
+                    <td>{{ key.repo_name }}</td>
+                    <td>{{ key.total }}</td>
+                </tr>
+            {% endfor %}
+
+            </tbody>
+            </table>
+        </div>
+    </div>
+    <div class="col-xs-4">
+        <h2> Top Starred Repositories </h2>
+        <div class="table-responsive">
+            <table class="table table-bordered table-hover table-striped tablesorter">
+                <thead>
+                <tr>
+                <th class="header"> Repository <i class="icon-sort"></i></th>
+                <th class="header"> Count <i class="icon-sort"></i></th>
+                </tr>
+            </thead>
+            <tbody>
+
+            {% for key in data.filteredStargazers %}
+                <tr>
+                    <td>{{ key.name }}</td>
+                    <td>{{ key.stargazers_count }}</td>
+                </tr>
+            {% endfor %}
+
+            </tbody>
+            </table>
+        </div>
+    </div>
+
+    <div class="col-xs-4">
+        <h2> Contributions </h2>
+        <div class="table-responsive">
+            <table class="table table-bordered table-hover table-striped tablesorter">
+                <thead>
+                <tr>
+                <th class="header"> Repository <i class="icon-sort"></i></th>
+                </tr>
+            </thead>
+            <tbody>
+
+            {% for key in data.forkedRepos %}
+                <tr>
+                    <td>{{ key.name }}</td>
+                </tr>
+            {% endfor %}
+
+            </tbody>
+            </table>
+        </div>
+    </div>
+
+</body>
+</html>

+ 14 - 0
hackathon_starter/hackathon/templates/hackathon/index.html

@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+
+<html>
+    {% include 'hackathon/base.html' %}
+
+    <body>
+    	{% if user.is_authenticated %}
+        	<h1>Api Example</h1>
+        	<strong>{{ boldmessage }}</strong><br />
+        {% else %}
+        	<h1> Please register/login! </h1>
+        {% endif %}
+    </body>
+</html>

+ 25 - 0
hackathon_starter/hackathon/templates/hackathon/linkedin.html

@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+<body>
+	{% include 'hackathon/base.html' %}
+	<h1>user information</h1>
+	<table>
+	<tr>
+	<th>First name</th>
+	<th>lastname</th>
+	<th>email</th>
+	<th>connection</th>
+	</tr>
+	{% for key in userinfo %}
+    <tr>
+    <td>{{ key.firstname }}</td>
+    <td>{{ key.lastname}}</td>
+    <td>{{ key.email }}</td>
+    <td>{{ key.connectionss }}</td>
+    </tr>
+    {% endfor %}
+
+     </table>
+</body>
+</html>
+

+ 47 - 0
hackathon_starter/hackathon/templates/hackathon/login.html

@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<html>
+    {% include 'hackathon/base.html' %}
+    <style>
+      .form-signin {
+        max-width: 550px;
+        padding: 15px;
+        margin: 0 auto;
+      }    
+    </style>
+
+    <body>
+      <div class="container text-center">
+        <form class="form-signin" id="login_form" method="post" action="/hackathon/login/">
+          {% csrf_token %}
+          {% load bootstrap %}
+          <h2 class="form-signin-heading">Login</h2>
+          <br>
+          <input type="text" name="username" class="form-control" placeholder="Username" value="" required autofocus>
+          <br>
+          <input type="password" name="password" class="form-control" placeholder="Password" value=""required>
+          <br>
+          <button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
+          <input type="hidden" name="submit" value="submit" />
+        </form>
+      </div>
+
+      <div class="form-signin">
+        <a class="btn btn-block btn-social btn-facebook">
+          <i class="fa fa-facebook"></i>
+          Sign in with Facebook
+        </a>          
+        <a class="btn btn-block btn-social btn-twitter">
+          <i class="fa fa-twitter"></i>
+          Sign in with Twitter
+        </a>
+        <a class="btn btn-block btn-social btn-instagram">
+          <i class="fa fa-instagram"></i>
+          Sign in with Instagram
+        </a>
+        <a class="btn btn-block btn-social btn-google-plus">
+          <i class="fa fa-google-plus"></i>
+          Sign in with Google
+        </a>          
+      </div>
+    </body>
+</html>

+ 40 - 0
hackathon_starter/hackathon/templates/hackathon/navbar.html

@@ -0,0 +1,40 @@
+<body>
+  <nav class="navbar navbar-default" role="navigation">
+      <div class="container-fluid">
+        <!-- Brand and toggle get grouped for better mobile display -->
+        <div class="navbar-header">
+          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
+            <span class="sr-only">Toggle navigation</span>
+            <span class="icon-bar"></span>
+            <span class="icon-bar"></span>
+            <span class="icon-bar"></span>
+          </button>
+          <a class="navbar-brand" href="#">Django Hackathon Starter</a>
+      </div>
+
+      <!-- Collect the nav links, forms, and other content for toggling -->
+      <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
+        <ul class="nav navbar-nav navbar-right">
+          {% if not user.is_authenticated %}
+            <li class="active"><a href="/hackathon/register">Register <span class="sr-only">(current)</span></a></li>
+            
+            <li><a href="/hackathon/login">Login</a></li>
+          {% endif %}
+            
+        </ul>
+        
+        <ul  class="nav navbar-nav navbar-right">
+          {% if user.is_authenticated %}
+    
+            <li><a>Hello {{user}}</a></li>
+            <li><a href="/hackathon/logout/">Logout</a></li>
+          {% endif %}
+        </ul>
+          
+          
+          </li>
+        </ul>
+      </div><!-- /.navbar-collapse -->
+    </div><!-- /.container-fluid -->
+  </nav>
+</body>

+ 42 - 0
hackathon_starter/hackathon/templates/hackathon/register.html

@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<html>
+    {% include 'hackathon/base.html' %}
+    <link rel="stylesheet" href="/static/css/form.css">
+    <body>
+        {% if registered %}
+          <strong>Thank you for registering!</strong>
+          <a href="/hackathon/">Return to the homepage.</a><br />
+        
+        {% else %}
+          <div class='container text-center'>
+              <h2 class="form-signin-heading">Sign Up</h2>
+              <br>
+              <form class="form-horizontal" id="user_form" method="post" action="/hackathon/register/"
+                enctype="multipart/form-data">
+                {% csrf_token %}
+                {% load bootstrap %} 
+
+                <table>
+                  <tr>
+                     
+                      <td class="container text-center">{{ user_form.username | bootstrap_horizontal}}</td>
+                  </tr>
+
+                  <tr>
+                     
+                      <td class="container text-center">{{ user_form.email | bootstrap_horizontal}}</td>
+                  </tr>
+
+                  <tr>
+                     
+                      <td class="container text-center">{{ user_form.password | bootstrap_horizontal}}</td>
+                  </tr>
+                </table>
+                <button class="btn btn-lg btn-primary" type="submit">Register</button>
+                <input type="hidden" name="submit" value="Register" />
+              </form>
+            </div>
+          {% endif %}
+    </body>
+</html>
+

+ 12 - 0
hackathon_starter/hackathon/templates/hackathon/steam.html

@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+<body>
+<table>
+  <tr><th>Game ID</th><th>Game Name</th><th>Minutes Played</th></tr>
+  {% for game in game %}
+    {% comment %}  each game object is a dictionary with "appid", "name " and "playtime_forever" keys {% endcomment %}
+    <tr><td>{{ game.appid }}</td><td>{{game.name}} </td><td>{{ game.playtime_forever }}</td></tr>
+{% endfor %}
+</table>
+</body>
+</html>

+ 61 - 0
hackathon_starter/hackathon/templates/hackathon/tumblr.html

@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+<html>
+<body>
+	{% include 'hackathon/base.html' %}
+	<h1 class="text-center"> {{ title }}</h1> 
+	<br>	
+	<div class="col-lg-12">
+		<div class="table-responsive">
+			<h2> BLOGGER </h2>
+			<table class="table table-bordered">
+				<tr>
+					<th>Name</th>
+					<td>{{blogData.name}}</td>
+				</tr>
+				<tr>
+					<th>Posts</th>
+					<td>{{blogData.posts}}</td>				
+				</tr>
+				<tr>
+					<th>Blog title</th>
+					<td>{{blogData.title}}</td>				
+				</tr>
+				<tr>
+					<th>Last updated</th>
+					<td>{{blogData.updated}}</td>				
+				</tr>
+				<tr>
+					<th>Description</th>
+					<td>{{blogData.description}}</td>				
+				</tr>				
+			</table>
+		</div>
+	</div>
+
+	<div class="col-md-4">
+		<div class="table-responsive">
+			<h2> #starbucks </h2>
+			<table class="table table-bordered">
+				{% for i in blogTag %}
+				<tr>
+					<td> {{i}} </td>
+				</tr>
+				{% endfor %}		
+			</table>
+		</div>
+	</div>
+
+	<div class="col-md-4">
+		<div class="table-responsive">
+			<h2> Comments </h2>
+			<table class="table table-bordered">
+				{% for i in blogontag %}
+				<tr>
+					<td> {{i}} </td>
+				</tr>
+				{% endfor %}		
+			</table>
+		</div>
+	</div>
+
+</html>

+ 3 - 0
hackathon_starter/hackathon/tests.py

@@ -0,0 +1,3 @@
+from django.test import TestCase
+
+# Create your tests here.

+ 0 - 0
hackathon_starter/hackathon/unittests/__init__.py


+ 8 - 0
hackathon_starter/hackathon/unittests/testcase.py

@@ -0,0 +1,8 @@
+import unittest
+
+def fun(x):
+    return x + 1
+
+class MyTest(unittest.TestCase):
+    def test(self):
+        self.assertEqual(fun(3), 4)

Datei-Diff unterdrückt, da er zu groß ist
+ 192 - 0
hackathon_starter/hackathon/unittests/testgithub.py


+ 925 - 0
hackathon_starter/hackathon/unittests/teststeam.py

@@ -0,0 +1,925 @@
+import unittest
+from mock import Mock, patch, MagicMock
+from django.conf import settings
+from hackathon.scripts.steam import *
+
+
+class SteamTests(unittest.TestCase):
+
+    def setup(self):
+        self.API_URL = 'http://api.steampowered.com/IPlayerService/GetOwnedGames/v0001/'
+        self.APIKEY = '231E98D442E52B87110816C3D5114A1D'
+        self.userID = 'Marorin'
+        self.steamnum = '76561197997115778'
+
+    def testGetUserIDNum(self):
+        '''Test for steam.py method'''
+        
+        # Pulling from setUp
+        userID = self.userID
+        API_URL = self.API_URL
+        APIKEY = self.APIKEY   
+ 
+        # constructing the URL
+        self.url = API_URL + '?' + APIKEY + '&' + userID
+
+        with patch('hackathon.scripts.steam.steamIDpulling') as mock_steamIDPulling:
+            # Mocking the return value of this method.
+            mock_steamIDpulling = 76561197997115778
+            self.assertEqual(steamIDPulling(userID,APIKEY),mock_steamIDpulling)
+
+    def testgamespulling(self):
+        '''Test gamesPulling method'''
+        with patch('hackathon.scripts.steam.gamesPulling) as mock_gamesPulling:
+            jsonList = [{
+				"appid": 4000,
+				"name": "Garry's Mod",
+				"playtime_forever": 0,
+				"img_icon_url": "d9101cbeddcc4ff06c7fa1936c3f381b0bbf2e92",
+				"img_logo_url": "dca12980667e32ab072d79f5dbe91884056a03a2",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 6550,
+				"name": "Devil May Cry 3: Special Edition",
+				"playtime_forever": 217,
+				"img_icon_url": "5c216acd743413bee9ae18c0d5302e5939ca689f",
+				"img_logo_url": "b26ae9eee26c206b2b3bfab7d365f707e20854a3"
+			},
+			{
+				"appid": 10500,
+				"name": "Empire: Total War",
+				"playtime_forever": 0,
+				"img_icon_url": "dc10f7bad53d3d922c196d116b1c5d6a4b274768",
+				"img_logo_url": "d60c77df97439e8434f0d0be9c3e2d9f39699991",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 17460,
+				"name": "Mass Effect",
+				"playtime_forever": 1242,
+				"img_icon_url": "57be81f70afa48c65437df93d75ba167a29687bc",
+				"img_logo_url": "7501ea5009533fa5c017ec1f4b94725d67ad4936"
+			},
+			{
+				"appid": 12810,
+				"name": "Overlord II",
+				"playtime_forever": 0,
+				"img_icon_url": "cc38122745bd44454e7e122e86023fb35e652d9d",
+				"img_logo_url": "7107ed1429c4be7637571fdf262f61af6bc7d4a2"
+			},
+			{
+				"appid": 45700,
+				"name": "Devil May Cry 4",
+				"playtime_forever": 925,
+				"img_icon_url": "1f869ad15ffdc1eb406c5d1635c9c0efb2e91f12",
+				"img_logo_url": "5b274e94aec7806da9a1b5ba5334668781ff0fd2"
+			},
+			{
+				"appid": 24980,
+				"name": "Mass Effect 2",
+				"playtime_forever": 4040,
+				"img_icon_url": "e6f3b9b0762fd4d42a732abfc41887f6c5903a52",
+				"img_logo_url": "d446fe6d77c9f434cd7fd871400b978fc01fb4e7"
+			},
+			{
+				"appid": 4540,
+				"name": "Titan Quest",
+				"playtime_forever": 0,
+				"img_icon_url": "d59f857aed0d38c69960a9d80e3d23e0863f4e01",
+				"img_logo_url": "e82186f6efe8d5d593c2fb1b57f8b1e056e6d82e",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 21100,
+				"name": "F.E.A.R. 3",
+				"playtime_forever": 0,
+				"img_icon_url": "01b73115a3ff7315d14f0bcf7beff01ef76162b4",
+				"img_logo_url": "d2fcf83ec76e845ed19f4ff8324304e2981af391",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 620,
+				"name": "Portal 2",
+				"playtime_forever": 29,
+				"img_icon_url": "2e478fc6874d06ae5baf0d147f6f21203291aa02",
+				"img_logo_url": "d2a1119ddc202fab81d9b87048f495cbd6377502",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 45760,
+				"name": "Ultra Street Fighter IV",
+				"playtime_forever": 111,
+				"img_icon_url": "473fcea2eb516528608dff7f9e3e61009d76a282",
+				"img_logo_url": "bdd481249e579f852056b51db32a6279444d4f47",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 21090,
+				"name": "F.E.A.R.",
+				"playtime_forever": 0,
+				"img_icon_url": "71f118282be5aaa34eb82506593130ecfcc6a90b",
+				"img_logo_url": "df122e0ee9eb2a5371910ffda0f8a3382e09232e"
+			},
+			{
+				"appid": 21110,
+				"name": "F.E.A.R.: Extraction Point",
+				"playtime_forever": 0,
+				"img_icon_url": "153d4f89ef0bd59a0039c396ff963a31d4d5e71b",
+				"img_logo_url": "df122e0ee9eb2a5371910ffda0f8a3382e09232e"
+			},
+			{
+				"appid": 21120,
+				"name": "F.E.A.R.: Perseus Mandate",
+				"playtime_forever": 0,
+				"img_icon_url": "7b1d0271f2735ca66e1cb681eb4da1a7c985d53f",
+				"img_logo_url": "df122e0ee9eb2a5371910ffda0f8a3382e09232e"
+			},
+			{
+				"appid": 16450,
+				"name": "F.E.A.R. 2: Project Origin",
+				"playtime_forever": 0,
+				"img_icon_url": "6611d8b01c7a2cc3538c478c044d1e09f3140eaa",
+				"img_logo_url": "41734347c3f05fe7dd797570130f5069c08f9d1b"
+			},
+			{
+				"appid": 32800,
+				"name": "The Lord of the Rings: War in the North",
+				"playtime_forever": 0,
+				"img_icon_url": "56dcf3fe99a90c25daae1cbe84319bb8af3c6ac5",
+				"img_logo_url": "b90d899806ebaff87ed7d2cdc4d9e0a3f11b73b0",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 107100,
+				"name": "Bastion",
+				"playtime_forever": 45,
+				"img_icon_url": "8377b4460f19465c261673f76f2656bdb3288273",
+				"img_logo_url": "d113d66ef88069d7d35a74cfaf2e2ee917f61133",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 55230,
+				"name": "Saints Row: The Third",
+				"playtime_forever": 246,
+				"img_icon_url": "ec83645f13643999e7c91da75d418053d6b56529",
+				"img_logo_url": "1129528455a8b297fb6404cbb90e802a62881b11",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 34270,
+				"name": "SEGA Genesis & Mega Drive Classics",
+				"playtime_forever": 4,
+				"img_icon_url": "48a187fa87c58b798646a430d446dd36eeabd1a4",
+				"img_logo_url": "212f55b3ea1a8c70427890896e93a37b49f57187",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 71340,
+				"name": "Sonic Generations",
+				"playtime_forever": 520,
+				"img_icon_url": "efda039147f0968bc726c547ff3809f98b69964a",
+				"img_logo_url": "21ec1e24c31a50500bbddb8c8c8add451e6dcbe1",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 72850,
+				"name": "The Elder Scrolls V: Skyrim",
+				"playtime_forever": 2431,
+				"img_icon_url": "b9aca8a189abd8d6aaf09047dbb0f57582683e1c",
+				"img_logo_url": "c5af3cde13610fca25cd17634a96d72487d21e74",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 41070,
+				"name": "Serious Sam 3: BFE",
+				"playtime_forever": 0,
+				"img_icon_url": "2e7a17d4b345ffb13ef3d9e39257c2659fe4a86b",
+				"img_logo_url": "cc3a3c30187b5fbbd0a8861ad08b4f7d779ba239",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 57400,
+				"name": "Batman: Arkham City™",
+				"playtime_forever": 1271,
+				"img_icon_url": "4c208d1365ea5614326717ecfcfea1196ef48e70",
+				"img_logo_url": "5456a41d4076244a6c593cbb260c3384493a7727",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 200260,
+				"name": "Batman: Arkham City GOTY",
+				"playtime_forever": 592,
+				"img_icon_url": "746ecf3ce44b2525eb7ad643e76a3b60913d2662",
+				"img_logo_url": "9b229e12fd5ce27bd101d5862c19b1a6e3d01239",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 108710,
+				"name": "Alan Wake",
+				"playtime_forever": 0,
+				"img_icon_url": "ec7953511aaaf5a2c2093b872b5b43c6cab56462",
+				"img_logo_url": "0f9b6613ac50bf42639ed6a2e16e9b78e846ef0a",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 207490,
+				"name": "Rayman Origins",
+				"playtime_forever": 585,
+				"img_icon_url": "1e155c2bc13e8793aed8bb61fdac798fe0d49de7",
+				"img_logo_url": "ebfd3f8da2b0416d71724a2929740a72a6eaabf4"
+			},
+			{
+				"appid": 41500,
+				"name": "Torchlight",
+				"playtime_forever": 130,
+				"img_icon_url": "b2a2a43e401dce3c69898b67b1b8af4481d96b08",
+				"img_logo_url": "e36226c6a0575e6e1838e1f915e91f8b31ab3008",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 200710,
+				"name": "Torchlight II",
+				"playtime_forever": 1011,
+				"img_icon_url": "40776762bb63c4eded37d1a2b4431a90aa57ea84",
+				"img_logo_url": "fd37abb86628ff54ed304f75c2fb7cf75a4f6902",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 205350,
+				"name": "Mortal Kombat Kollection",
+				"playtime_forever": 0,
+				"img_icon_url": "048e463386c8f0049d6e08bbf8f5ebb5d232394f",
+				"img_logo_url": "44281a64a93a583fdd2435036ac794e7dcc7beb8",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 202750,
+				"name": "Alan Wake's American Nightmare",
+				"playtime_forever": 0,
+				"img_icon_url": "313aabf37ed0b521ad969d3fe21768d31300f1ca",
+				"img_logo_url": "d3593fa14e4ea8685dc6b1f71dbaa980c013ff02",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 113200,
+				"name": "The Binding of Isaac",
+				"playtime_forever": 503,
+				"img_icon_url": "383cf045ca20625db18f68ef5e95169012118b9e",
+				"img_logo_url": "d9a7ee7e07dffed1700cb8b3b9482105b88cc5b5",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 35140,
+				"name": "Batman: Arkham Asylum GOTY Edition",
+				"playtime_forever": 0,
+				"img_icon_url": "e52f91ecb0d3f20263e96fe188de1bcc8c91643e",
+				"img_logo_url": "172e0928b845c18491f1a8fee0dafe7a146ac129",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 211420,
+				"name": "Dark Souls: Prepare to Die Edition",
+				"playtime_forever": 5309,
+				"img_icon_url": "a24804c6c8412c8cd9d50efd06bf03fa58ff80a9",
+				"img_logo_url": "d293c8e38f56de2c7097b2c7a975caca49029a8b",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 204300,
+				"name": "Awesomenauts",
+				"playtime_forever": 9,
+				"img_icon_url": "4996933171d0804bd0ceb7b9a0e224b3139d18ba",
+				"img_logo_url": "a2eba6157703c60bfcc199f06df5f1568c9835bb",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 204630,
+				"name": "Retro City Rampage™ DX",
+				"playtime_forever": 0,
+				"img_icon_url": "423b87d4a5a00ff6e807558e565b0b515fadf61b",
+				"img_logo_url": "3ca51d2767c5de3358c4f1824f1b362a9494983f",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 214560,
+				"name": "Mark of the Ninja",
+				"playtime_forever": 1,
+				"img_icon_url": "220f33169c93c2f6381cd785399fb52bfc79309f",
+				"img_logo_url": "c20501309696e5bcda98e9e4f2649abc5720a1d1",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 49520,
+				"name": "Borderlands 2",
+				"playtime_2weeks": 24,
+				"playtime_forever": 7526,
+				"img_icon_url": "a3f4945226e69b6196074df4c776e342d3e5a3be",
+				"img_logo_url": "86b0fa5ddb41b4dfff7df194a017f3418130d668",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 205950,
+				"name": "Jet Set Radio",
+				"playtime_forever": 644,
+				"img_icon_url": "884cfa9f5f615e297f8c53a2010f1b63835e44b5",
+				"img_logo_url": "3272dfd2e30df5629bfbaa851ea503e9ee28b75a",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 213610,
+				"name": "Sonic Adventure™ 2 ",
+				"playtime_forever": 0,
+				"img_icon_url": "0ff2b133493b0bf7f1c16a38a83e7053f0b90f2d",
+				"img_logo_url": "b59ee5bd744212a79db6fd8f71aec6729671da2b",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 205790,
+				"name": "Dota 2 Test",
+				"playtime_forever": 20,
+				"img_icon_url": "",
+				"img_logo_url": ""
+			},
+			{
+				"appid": 218680,
+				"name": "Scribblenauts Unlimited",
+				"playtime_forever": 0,
+				"img_icon_url": "e933a9993b7d0b905dbb37636a97339a2c277e0f",
+				"img_logo_url": "c3f8420cd87dd772df8a35013e3538e964ecc2b8",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 223220,
+				"name": "Giana Sisters: Twisted Dreams",
+				"playtime_forever": 115,
+				"img_icon_url": "ac543243f2541e7a7728bf2165c5f3ebc57679fb",
+				"img_logo_url": "9c8baddbab7938b5b995843d36526a30bd12bb1d",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 4920,
+				"name": "Natural Selection 2",
+				"playtime_forever": 0,
+				"img_icon_url": "df709ad4689cbfb82c2971be4adba431e755875f",
+				"img_logo_url": "ab7b1142e17865e6d3472d3fd4b345620ec5f36f",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 219950,
+				"name": "NiGHTS into Dreams...",
+				"playtime_forever": 0,
+				"img_icon_url": "630fb86750aaa5d9ca713df086fa93d9804e9f02",
+				"img_logo_url": "7316d46b1ce35a260ddedc6a1f7590a8b98dea92",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 4560,
+				"name": "Company of Heroes",
+				"playtime_forever": 0,
+				"img_icon_url": "64946619217da497c9b29bc817bb40dd7d28c912",
+				"img_logo_url": "e12e8695c6766b47a089351dd9c4531e669c2a7b"
+			},
+			{
+				"appid": 9340,
+				"name": "Company of Heroes: Opposing Fronts",
+				"playtime_forever": 0,
+				"img_icon_url": "29725d719946c3e1aa4eea15d262c9fd789c1392",
+				"img_logo_url": "830c99099ea2cfecfe74c41f376fc892a09dd181"
+			},
+			{
+				"appid": 20540,
+				"name": "Company of Heroes: Tales of Valor",
+				"playtime_forever": 0,
+				"img_icon_url": "64946619217da497c9b29bc817bb40dd7d28c912",
+				"img_logo_url": "ed0c55412acea558d025a3e238e2b7341edc5c41"
+			},
+			{
+				"appid": 43110,
+				"name": "Metro 2033",
+				"playtime_forever": 0,
+				"img_icon_url": "a70fe6dc214f24107d20596f3040dbfa220ed42d",
+				"img_logo_url": "df9a163ac1f28dfc84c93a6fc0dc51719eaef518",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 50620,
+				"name": "Darksiders",
+				"playtime_forever": 925,
+				"img_icon_url": "e429cee10d864faf2aae2ea9cd75e8e1942fbe08",
+				"img_logo_url": "14bd29bc9b291081b63258e3bfbbf5bb655c2347",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 55110,
+				"name": "Red Faction: Armageddon",
+				"playtime_forever": 0,
+				"img_icon_url": "e59c7e741c05c9071176b270bdbb733afe55c751",
+				"img_logo_url": "19f894d0e08dff8e284d4facc5968a1025da997d",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 228200,
+				"name": "Company of Heroes (New Steam Version)",
+				"playtime_forever": 0,
+				"img_icon_url": "df92dc239acb3cf5d3e3eba645f3df2aaf7f91ad",
+				"img_logo_url": "87aa009e93d5aa56a55d0e9056708d018ddd6483",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 201790,
+				"name": "Orcs Must Die! 2",
+				"playtime_forever": 0,
+				"img_icon_url": "fabd8658e8e76f7c99c56f26b69d29882756f9b4",
+				"img_logo_url": "c345d9b205f349f0e7f4e6cdf8af4d0b7d242505",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 4570,
+				"name": "Warhammer 40,000: Dawn of War - Game of the Year Edition",
+				"playtime_forever": 5,
+				"img_icon_url": "a4c7a8cce43d797c275aaf601d6855b90ba87769",
+				"img_logo_url": "2068980dca52521b069abc109f976d72ba0b1651",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 71230,
+				"name": "Crazy Taxi",
+				"playtime_forever": 0,
+				"img_icon_url": "e71b220f8103e3515bd56de6a42395121e31e2cf",
+				"img_logo_url": "be180e020c4e1ca0a13ec1a9006a1235b6a9eb50",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 71240,
+				"name": "SEGA Bass Fishing",
+				"playtime_forever": 0,
+				"img_icon_url": "fac67362e11293a673158e6d3c8c67693816868f",
+				"img_logo_url": "6255f428036c011b325b40ebf1c53daa4db7e1f1",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 71250,
+				"name": "Sonic Adventure DX",
+				"playtime_forever": 0,
+				"img_icon_url": "6568d25b43e2d1d07fc16cbe3ac9278ca51c2fb3",
+				"img_logo_url": "e8374c63e76724af4648cdea5331f4ae39af4d06",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 71260,
+				"name": "Space Channel 5: Part 2",
+				"playtime_forever": 366,
+				"img_icon_url": "82aec5f26e9d40c5275b1cd9bf692c4057c108ef",
+				"img_logo_url": "fad43b313c2f6869c42bf0d7c4959363c5394d9a",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 50650,
+				"name": "Darksiders II",
+				"playtime_forever": 1591,
+				"img_icon_url": "a2d5549090144f1bfd9e00f1b460c1ad0aa9c366",
+				"img_logo_url": "b0b8edfa57f332dc529c04b4dd2f5475227e71ac",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 35720,
+				"name": "Trine 2",
+				"playtime_forever": 0,
+				"img_icon_url": "061ecbbd7c70ae1c052377bad136c7759cbb708d",
+				"img_logo_url": "7d7c3b93bd85ad1db2a07f6cca01a767069c6407",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 226320,
+				"name": "Marvel Heroes 2015",
+				"playtime_forever": 0,
+				"img_icon_url": "a0c1c35208af7b63759361305631da48539d45cc",
+				"img_logo_url": "7121a66719963c4790d6169d38b9c65ad8f238bc",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 225260,
+				"name": "Brütal Legend",
+				"playtime_forever": 0,
+				"img_icon_url": "e3f25fba8538e5fb1ead751e767c2774df4fb0b4",
+				"img_logo_url": "cc8b60ac1fa649c950ff7a9881b98709b8372f94",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 210770,
+				"name": "Sanctum 2",
+				"playtime_forever": 0,
+				"img_icon_url": "4cdfa1d19be460374a111b718ce3a204f21ea1dc",
+				"img_logo_url": "333a8c65480bb85148bb3a185843a8520ae5d90f",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 234710,
+				"name": "Poker Night 2",
+				"playtime_forever": 7,
+				"img_icon_url": "b3073e6f089447a9cf1eeabf7579600061546322",
+				"img_logo_url": "0b274bb5ade23104ce267a05ce7ac0f7aaa0248d",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 31100,
+				"name": "Wallace & Gromit Ep 1: Fright of the Bumblebees",
+				"playtime_forever": 0,
+				"img_icon_url": "1c8b457c265e36e6ac08d8d5ae5709124eae3025",
+				"img_logo_url": "6b303e67e65d39cd3747ed21efb42de9ddb0d251"
+			},
+			{
+				"appid": 31110,
+				"name": "Wallace & Gromit Ep 2: The Last Resort",
+				"playtime_forever": 0,
+				"img_icon_url": "e6d415690e4c05b3d716030984346442f10e87e9",
+				"img_logo_url": "7cda224cf65955e5e763ce8eff0b099add72f04e"
+			},
+			{
+				"appid": 31120,
+				"name": "Wallace & Gromit Ep 3: Muzzled!",
+				"playtime_forever": 0,
+				"img_icon_url": "70475b4d75934174a0fff9969315be9a4993c150",
+				"img_logo_url": "3910a6ff5e48c5f7ed249b48387bc321504db73c"
+			},
+			{
+				"appid": 31130,
+				"name": "Wallace & Gromit Ep 4: The Bogey Man",
+				"playtime_forever": 0,
+				"img_icon_url": "9072b2096b4542529aa47f4115bff48ab781ff6e",
+				"img_logo_url": "8a5313cf2bdd01a0516c56b3ce952428de85d430"
+			},
+			{
+				"appid": 31220,
+				"name": "Sam & Max 301: The Penal Zone",
+				"playtime_forever": 335,
+				"img_icon_url": "2c9c4ac6dfa50c4c479b6b436f04974a372588f7",
+				"img_logo_url": "517196c999fe6316134332e749782154bde9adf5"
+			},
+			{
+				"appid": 31230,
+				"name": "Sam & Max 302: The Tomb of Sammun-Mak",
+				"playtime_forever": 72,
+				"img_icon_url": "e83fbb799f46b349586ca55fcf612350cc88ffe7",
+				"img_logo_url": "517196c999fe6316134332e749782154bde9adf5"
+			},
+			{
+				"appid": 31240,
+				"name": "Sam & Max 303: They Stole Max's Brain!",
+				"playtime_forever": 0,
+				"img_icon_url": "bf1ebfe347a80e2ac31577e0569de3aa201cd17f",
+				"img_logo_url": "517196c999fe6316134332e749782154bde9adf5"
+			},
+			{
+				"appid": 31250,
+				"name": "Sam & Max 304: Beyond the Alley of the Dolls",
+				"playtime_forever": 0,
+				"img_icon_url": "d4f834ac9d48cd59645f453d0cb30655dee6f629",
+				"img_logo_url": "62ef5af2ce55bb787ff490126c110c41131043bc"
+			},
+			{
+				"appid": 31260,
+				"name": "Sam & Max 305: The City that Dares not Sleep",
+				"playtime_forever": 0,
+				"img_icon_url": "9e41c6d0c777cd0a7fb4e96da4f20d2227841725",
+				"img_logo_url": "62ef5af2ce55bb787ff490126c110c41131043bc"
+			},
+			{
+				"appid": 31270,
+				"name": "Puzzle Agent",
+				"playtime_forever": 0,
+				"img_icon_url": "d0cae0b07b2512302968bd7625a9bf12cebdfba8",
+				"img_logo_url": "f1bd7dd0bae1026b17c61a605a567ed68e683fef"
+			},
+			{
+				"appid": 31280,
+				"name": "Poker Night at the Inventory",
+				"playtime_forever": 0,
+				"img_icon_url": "7d50bd1f5e7cfe68397e9ca0041836ad18153dfb",
+				"img_logo_url": "d962cde096bca06ee10d09880e9f3d6257941161",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 31290,
+				"name": "Back to the Future: Ep 1 - It's About Time",
+				"playtime_forever": 0,
+				"img_icon_url": "a9a9b1683209e3223779ad2315e4bf03e27619d7",
+				"img_logo_url": "252a22c149c29a2d93fcb0080f3ee9d2dbbd9a2f"
+			},
+			{
+				"appid": 94500,
+				"name": "Back to the Future: Ep 2 - Get Tannen!",
+				"playtime_forever": 0,
+				"img_icon_url": "d5382aedd7594e088a078341034e4b369210ec9a",
+				"img_logo_url": "ae0d863314d6111e6debaef7c9cdcf2940738b1e"
+			},
+			{
+				"appid": 94510,
+				"name": "Back to the Future: Ep 3 - Citizen Brown",
+				"playtime_forever": 0,
+				"img_icon_url": "a51c4795b44f689628bd76bc64cad310385ba1a2",
+				"img_logo_url": "7fe46585ad7fbc8fedb38db7f8dd8608be5a46ee"
+			},
+			{
+				"appid": 94520,
+				"name": "Back to the Future: Ep 4 - Double Visions",
+				"playtime_forever": 0,
+				"img_icon_url": "5a7fd98c15742b9fca4e443b5eaadf953a6c83d3",
+				"img_logo_url": "ac9fc7c15ae656d200299003ce22ab84185e54e4"
+			},
+			{
+				"appid": 94530,
+				"name": "Back to the Future: Ep 5 - OUTATIME",
+				"playtime_forever": 0,
+				"img_icon_url": "3d034831533383bc5a58787763925660684de8c4",
+				"img_logo_url": "76361dfc1ef09dbb7f6572a6da7ab38a811f54af"
+			},
+			{
+				"appid": 94590,
+				"name": "Puzzle Agent 2",
+				"playtime_forever": 0,
+				"img_icon_url": "d558eb6bddeb55f5f145822f3949ab50bc02aff9",
+				"img_logo_url": "b7aac2e076fb1c5178681e2cab0f8bae4380c96d",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 94600,
+				"name": "Hector: Ep 1",
+				"playtime_forever": 0,
+				"img_icon_url": "aa0a113e80b8cdeff47a523a87dd2fad1f43d73e",
+				"img_logo_url": "fae3324a5c43647dda98be23bf1db4480c031273"
+			},
+			{
+				"appid": 94610,
+				"name": "Hector: Ep 2",
+				"playtime_forever": 0,
+				"img_icon_url": "0bfad503074efc1c46755d05d36be4755945f8fe",
+				"img_logo_url": "52a3e61842a22bf75f6bf6d355400d5b3776f9b4"
+			},
+			{
+				"appid": 94620,
+				"name": "Hector: Ep 3",
+				"playtime_forever": 0,
+				"img_icon_url": "aa0a113e80b8cdeff47a523a87dd2fad1f43d73e",
+				"img_logo_url": "97ec609986c7672a3928e7dca14d9aead4cbf65f"
+			},
+			{
+				"appid": 236090,
+				"name": "Dust: An Elysian Tail",
+				"playtime_forever": 563,
+				"img_icon_url": "3779535aba1ad565d504a7d52c6dd5c9eeb47fb2",
+				"img_logo_url": "544fd60b00696d8c3402828da7055fea64d619ca",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 229480,
+				"name": "Dungeons & Dragons: Chronicles of Mystara",
+				"playtime_forever": 91,
+				"img_icon_url": "270699bf34b75a6789370de8b0cb98e163832f71",
+				"img_logo_url": "cb7b16b064562469c375a22d9d07a7ab11abdab6",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 208610,
+				"name": "Skullgirls ∞Endless Beta∞",
+				"playtime_forever": 292,
+				"img_icon_url": "7bf859db736b8825045b0cc79acc4bb7be8cd7b9",
+				"img_logo_url": "33974b81779c888b3b4d9c4b91d86ef0907b11f3",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 237110,
+				"name": "Mortal Kombat Komplete Edition",
+				"playtime_forever": 365,
+				"img_icon_url": "3b9c627b90f42cf650d5848e2fdd779fa4e6eb19",
+				"img_logo_url": "307dc1eacffd54e5a7a02b663cec1c5105059811",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 245170,
+				"name": "Skullgirls",
+				"playtime_forever": 1152,
+				"img_icon_url": "7bf859db736b8825045b0cc79acc4bb7be8cd7b9",
+				"img_logo_url": "ca3f7bd4fbb3cf73855ebce91b6dafc2104d651b",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 222940,
+				"name": "THE KING OF FIGHTERS XIII STEAM EDITION",
+				"playtime_forever": 322,
+				"img_icon_url": "de8d9bf86ae8983464d69743b55cef3992330ccf",
+				"img_logo_url": "9f2bec35f18bfc1a80ffab64bc51a09a880343b6",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 250760,
+				"name": "Shovel Knight",
+				"playtime_forever": 1,
+				"img_icon_url": "9b8866653bcaf20db1424653df8560205939cdba",
+				"img_logo_url": "23fca16e3df2ed731136574b320988406eb0f712",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 250900,
+				"name": "The Binding of Isaac: Rebirth",
+				"playtime_forever": 95,
+				"img_icon_url": "16d46c8630499bfc54d20745ac90786a302cd643",
+				"img_logo_url": "c7a76988c53e7f3a3aa1cf224aaf4dbd067ebbf9",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 111900,
+				"name": "Guardians of Middle-earth",
+				"playtime_forever": 0,
+				"img_icon_url": "5ab636ac90b8476892d6e0ae377624d5b934f600",
+				"img_logo_url": "08a7116bebd1bf44bb8e86495358dca14224d223",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 234670,
+				"name": "NARUTO SHIPPUDEN: Ultimate Ninja STORM 3 Full Burst",
+				"playtime_forever": 1405,
+				"img_icon_url": "ddd956cc6ec3370449f96298653d4119c5666fff",
+				"img_logo_url": "12895039c12ec92be72faa2d13acb88886b8cb97",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 42910,
+				"name": "Magicka",
+				"playtime_forever": 0,
+				"img_icon_url": "0eb97d0cd644ee08b1339d2160c7a6adf2ea0a65",
+				"img_logo_url": "8c59c674ef40f59c3bafde8ff0d59b7994c66477",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 212480,
+				"name": "Sonic & All-Stars Racing Transformed",
+				"playtime_forever": 0,
+				"img_icon_url": "95767af7b08d7ecebf1e9cb1ed1c92c98e4c084f",
+				"img_logo_url": "351603b89e1863831c84aacab7bf3a315f03443b",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 261640,
+				"name": "Borderlands: The Pre-Sequel",
+				"playtime_2weeks": 838,
+				"playtime_forever": 1157,
+				"img_icon_url": "af5ef05eac8b1eb618e4f57354ac7b3e918ab1bd",
+				"img_logo_url": "df64c72fd335a03dbcc0a19b1f81acc8db1b94ba",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 39150,
+				"name": "FINAL FANTASY VIII",
+				"playtime_forever": 119,
+				"img_icon_url": "e2b0371cd72160603e7ecaaf95b238a46ba254e6",
+				"img_logo_url": "0c912769e975586cdcfe4a6b008d538f1f96a032",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 235460,
+				"name": "METAL GEAR RISING: REVENGEANCE",
+				"playtime_forever": 1268,
+				"img_icon_url": "ad0f84fe48b57f3861b6c6d743f26b98d670c21f",
+				"img_logo_url": "a21384421dafa03783e3672a5f4754f70e63235e",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 550,
+				"name": "Left 4 Dead 2",
+				"playtime_forever": 0,
+				"img_icon_url": "7d5a243f9500d2f8467312822f8af2a2928777ed",
+				"img_logo_url": "205863cc21e751a576d6fff851984b3170684142",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 236430,
+				"name": "DARK SOULS™ II",
+				"playtime_forever": 8872,
+				"img_icon_url": "8d5b3da903efb047d4efb670c08714a4d1071e83",
+				"img_logo_url": "d16871e0aa9196e5e7d865f76fbed278a0309e85",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 282900,
+				"name": "Hyperdimension Neptunia Re;Birth1",
+				"playtime_forever": 1647,
+				"img_icon_url": "0cd228210df4f44ef8e77f62b18d1a9af81a72d4",
+				"img_logo_url": "c2835cfa39dbaf8e7e1f668e4bf491855a274947",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 254700,
+				"name": "resident evil 4 / biohazard 4",
+				"playtime_forever": 737,
+				"img_icon_url": "535bfea3332662271f1e3a972832bc0b4aba5a38",
+				"img_logo_url": "532d72710af44f29cc123c5796e95e0382461ee5",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 231430,
+				"name": "Company of Heroes 2",
+				"playtime_forever": 0,
+				"img_icon_url": "9efafff369d37ea19c44139de4476e6c63319b6b",
+				"img_logo_url": "2c413e4cc731862e0b3307ed9c23b1cd20087130",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 317170,
+				"name": "Company of Heroes 2 - Beta",
+				"playtime_forever": 0,
+				"img_icon_url": "9efafff369d37ea19c44139de4476e6c63319b6b",
+				"img_logo_url": "62afc50b5f0970c1070951f56a7dd0c0b943b013",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 294810,
+				"name": "BlazBlue: Continuum Shift Extend",
+				"playtime_forever": 82,
+				"img_icon_url": "244644a6721480f40e4de61e4bb7a337d999e435",
+				"img_logo_url": "b7105e9443e1f3bed7bb3fd1599a140e75dcf2c6",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 294860,
+				"name": "Valkyria Chronicles™",
+				"playtime_forever": 65,
+				"img_icon_url": "176c6dcafc9bf0fbb87f9adeb224df88c8248a66",
+				"img_logo_url": "08316e1d6a45d8e13de7f5e1a1480cf4efff15cf",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 285440,
+				"name": "Crimzon Clover  WORLD IGNITION",
+				"playtime_forever": 8,
+				"img_icon_url": "8f4f6490c9b48e8d6e2b688c4a097f9bdd8fb56d",
+				"img_logo_url": "72ab0aac6800b9ec9f79571d6f425f0e687d04ca",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 314030,
+				"name": "Guilty Gear X2 #Reload",
+				"playtime_forever": 99,
+				"img_icon_url": "bde7b6e8d891b310fad62d25a0cf009c979db84c",
+				"img_logo_url": "94edca39fa971bc8beeb0066afc99993246a9976"
+			},
+			{
+				"appid": 206420,
+				"name": "Saints Row IV",
+				"playtime_forever": 205,
+				"img_icon_url": "b5e8448a3e2ea31ddf3595addae4e1eee2375c0d",
+				"img_logo_url": "49d796621c286130a8ddeea918d9aae8c8441455",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 21690,
+				"name": "Resident Evil 5 / Biohazard 5",
+				"playtime_forever": 782,
+				"img_icon_url": "26108f5caff3638c9f522dd79ee84a12761f373a",
+				"img_logo_url": "e277ab70fff98bb2300a39bf8e2371a746fe50b1",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 222480,
+				"name": "Resident Evil Revelations / Biohazard Revelations UE",
+				"playtime_forever": 476,
+				"img_icon_url": "5725845fe83f846a04135034c5be55aef008c725",
+				"img_logo_url": "cf242207e0e06251f55baf2f89c37ded12c79329",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 323470,
+				"name": "DRAGON BALL XENOVERSE",
+				"playtime_2weeks": 24,
+				"playtime_forever": 815,
+				"img_icon_url": "810b2bab6e3197b5d63d3abffcebafaac8dc6312",
+				"img_logo_url": "f8724eeddf94534d66b8057cf770a9cd8318a14a",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 730,
+				"name": "Counter-Strike: Global Offensive",
+				"playtime_forever": 62,
+				"img_icon_url": "69f7ebe2735c366c65c0b33dae00e12dc40edbe4",
+				"img_logo_url": "d0595ff02f5c79fd19b06f4d6165c3fda2372820",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 222440,
+				"name": "THE KING OF FIGHTERS 2002 UNLIMITED MATCH",
+				"playtime_2weeks": 1,
+				"playtime_forever": 1,
+				"img_icon_url": "c9235efbfa66ad95a6ece092a7860ca8b92cfa6f",
+				"img_logo_url": "787a8b76a5c9348784f50798403b2672e488c557",
+				"has_community_visible_stats": true
+			},
+			{
+				"appid": 247000,
+				"name": "Talisman: Digital Edition",
+				"playtime_forever": 0,
+				"img_icon_url": "ab50e24b04d5fa8faf219fe622199061b57bcf20",
+				"img_logo_url": "73b7daee45a29a5dfe5c0efef72223943bf8722f",
+				"has_community_visible_stats": true
+			}]
+        self.assertEqual(gamesPulling(steamnum,APIKEY),jsonList)

+ 31 - 0
hackathon_starter/hackathon/unittests/testtumblr.py

@@ -0,0 +1,31 @@
+import unittest
+from mock import Mock, patch, MagicMock
+from hackathon.scripts.tumblr import *
+import oauth2
+import urlparse
+from django.conf import settings
+
+class TestTumblr(unittest.TestCase):
+
+	def setUp(self):
+		self.consumer_key = 'KrSbAc9cYLmIgVAn1D21FjRR97QWsutNMxkPDFBxo8CMWtMk4M'
+		self.consumer_secret = 'lKWMtL2Lj8zr5pY51PVqT8ugeoG0DjrdgoFewM0QTSyJ12jP8d'
+		self.consumer = oauth2.Consumer(key=self.consumer_key, secret=self.consumer_secret)
+		self.tumblrclient = TumblrOauthClient(self.consumer_key, self.consumer_secret, 'QBXdeeMKAnLzDbIG7dDNewTzRYyQoHZLbcn3bAFTCEFF5EXurl')
+		self.authorize = self.tumblrclient.get_authorize_url()
+
+		
+	def test_init(self):
+		self.assertEqual(self.consumer.key, self.consumer_key)
+		self.assertEqual(self.consumer.secret, self.consumer_secret)
+
+	def test_get_authorize_url(self):
+		self.client = oauth2.Client(self.consumer)
+		self.assertEqual(self.client.consumer, self.consumer)
+		with patch('hackathon.scripts.tumblr.TumblrOauthClient.get_authorize_url') as mock_get_authorize_url:
+			mock_get_authorize_url.return_value = "oauth_token=QBXdeeMKAnLzDbIG7dDNewTzRYyQoHZLbcn3bAFTCEFF5EXurl&oauth_token_secret=u10SuRl2nzS8vFK4K7UPQexAvbIFBFrZBjA79XDlgoXFxv9ZhO&oauth_callback_confirmed=true"
+			self.request_token = dict(urlparse.parse_qsl(mock_get_authorize_url.return_value))
+			self.oauth_token = self.request_token['oauth_token']
+			self.oauth_token_secret = self.request_token['oauth_token_secret']		
+			link = "http://www.tumblr.com/oauth/authorize?oauth_token="+self.oauth_token+"&redirect_uri=http%3A%2F%2Flocalhost%3A8000/hackathon/tumblr"
+			self.assertEqual(self.authorize,link )

+ 16 - 0
hackathon_starter/hackathon/urls.py

@@ -0,0 +1,16 @@
+from django.conf.urls import patterns, url
+
+from hackathon import views
+
+urlpatterns = patterns('',
+    url(r'^$', views.index, name='index'),
+    url(r'^test/$', views.test, name='test'),
+    url(r'^register/$', views.register, name='register'),
+    url(r'^login/$', views.user_login, name='login'),
+    url(r'^logout/$', views.user_logout, name='logout'),
+    url(r'^api/$', views.api_examples, name='api'),
+    url(r'^steam/$', views.steam, name='steam'),
+    url(r'^github/$', views.github, name='github'),
+    url(r'^tumblr/$', views.tumblr, name='tumblr'),
+    url(r'^linkedin/$', views.linkedin, name='linkedin')
+)

+ 117 - 0
hackathon_starter/hackathon/views.py

@@ -0,0 +1,117 @@
+from django.shortcuts import render
+from hackathon.forms import UserForm
+from django.contrib.auth import logout
+from django.template import RequestContext, loader
+from django.contrib.auth import authenticate, login
+from django.http import HttpResponse, HttpResponseRedirect
+from scripts.steam import gamesPulling, steamIDPulling 
+from scripts.github import *
+from scripts.tumblr import *
+from django.conf import settings
+
+getTumblr = TumblrOauthClient(settings.TUMBLR_CONSUMER_KEY, settings.TUMBLR_CONSUMER_SECRET)
+
+def index(request):
+    context = {'hello': 'world'}
+    return render(request, 'hackathon/index.html', context)
+
+def test(request):
+    return HttpResponse('meow')
+
+def api_examples(request):
+    obtain_oauth_verifier = getTumblr.get_authorize_url()#simpleoauthurl(settings.TUMBLR_CONSUMER_KEY, settings.TUMBLR_CONSUMER_SECRET)
+    context = {'title': 'API Examples Page', 'tumblr_url': obtain_oauth_verifier}
+    return render(request, 'hackathon/api_examples.html', context)
+
+def register(request):
+    registered = False
+    if request.method == 'POST':
+        user_form = UserForm(data=request.POST)
+        if user_form.is_valid():
+            user = user_form.save()
+            user.set_password(user.password)
+            user.save()
+            registered = True
+        else:
+            print user_form.errors
+    else:
+        user_form = UserForm()
+
+    
+    return render(request,
+            'hackathon/register.html',
+            {'user_form': user_form, 'registered': registered} )
+
+def user_login(request):
+
+    
+    if request.method == 'POST':
+        username = request.POST.get('username')
+        password = request.POST.get('password')
+
+
+        user = authenticate(username=username, password=password)
+
+
+        if user:
+            if user.is_active:
+                login(request, user)
+                return HttpResponseRedirect('/hackathon/')
+            else:
+                return HttpResponse("Your Django Hackathon account is disabled.")
+        else:
+            print ("Invalid login details: {0}, {1}".format(username, password))
+            return HttpResponse("Invalid login details supplied.")
+
+    else:
+        return render(request, 'hackathon/login.html', {})
+
+def user_logout(request):
+    logout(request)
+    return HttpResponseRedirect('/hackathon/')
+
+def steam(request):
+    #Should link to test of Steam API example.
+    key = '231E98D442E52B87110816C3D5114A1D'
+    SteamUN = "Marorin"
+    steamID = steamIDPulling(SteamUN, key)
+    game = gamesPulling(steamID, key)
+    return render(request,'hackathon/steam.html', {"game": game })
+
+def github(request):
+    allData = {}
+    userData = getUserData(settings.GITHUB_CLIENT_ID, settings.GITHUB_CLIENT_SECRET)
+    repositories = getUserRepositories(settings.GITHUB_CLIENT_ID, settings.GITHUB_CLIENT_SECRET)
+    list = getTopContributedRepositories(repositories, settings.GITHUB_CLIENT_ID, settings.GITHUB_CLIENT_SECRET)
+    filtered = filterCommits(list)
+    stargazers = getStarGazerCount(settings.GITHUB_CLIENT_ID, settings.GITHUB_CLIENT_SECRET)
+    filteredStargazers = filterStarGazerCount(stargazers)
+    forkedRepos = getForkedRepositories(settings.GITHUB_CLIENT_ID, settings.GITHUB_CLIENT_SECRET)
+    allData['userData'] = userData
+    allData['filteredData'] = filtered
+    allData['filteredStargazers'] = filteredStargazers
+    allData['forkedRepos'] = forkedRepos
+
+    return render(request, 'hackathon/github.html', { 'data': allData })
+
+def tumblr(request):
+    ''' Tumblr api calls '''
+    #retrieve verifier via url link
+    if not request.GET.items():
+        return HttpResponseRedirect('/hackathon/api/')
+    else:
+        getTumblr.get_access_token_url(request.GET.get('oauth_verifier'))
+        #get blogger twitterthecomic's blog information
+        blog = getTumblr.getBlogInfo('twitterthecomic')
+        #get tags that was tagged along starbucks
+        tagged_blog = getTumblr.getTaggedInfo("starbucks")
+        #get blog information tagged with starbucks
+        blogontag = getTumblr.getTaggedBlog("starbucks")
+        context = {'title': "What's up Starbucks?", 'blogData': blog, 'blogTag': tagged_blog, 'blogontag': blogontag}
+        return render(request, 'hackathon/tumblr.html', context)
+
+def linkedin(request):
+    userinfo = getUserInfo()
+    context = {'title': 'linkedin Example','userdata': userinfo}
+    return render(request, 'hackathon/linkedin.html', context)
+

+ 0 - 0
hackathon_starter/hackathon_starter/__init__.py


+ 109 - 0
hackathon_starter/hackathon_starter/settings.py

@@ -0,0 +1,109 @@
+"""
+Django settings for hackathon_starter project.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/1.7/topics/settings/
+
+For the full list of settings and their values, see
+https://docs.djangoproject.com/en/1.7/ref/settings/
+"""
+
+# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
+import os
+BASE_DIR = os.path.dirname(os.path.dirname(__file__))
+
+
+# Quick-start development settings - unsuitable for production
+# See https://docs.djangoproject.com/en/1.7/howto/deployment/checklist/
+
+# SECURITY WARNING: keep the secret key used in production secret!
+SECRET_KEY = 'keuhh=0*%do-ayvy*m2k=vss*$7)j8q!@u0+d^na7mi2(^!l!d'
+
+# SECURITY WARNING: don't run with debug turned on in production!
+DEBUG = True
+
+TEMPLATE_DEBUG = True
+
+ALLOWED_HOSTS = []
+
+
+# Application definition
+
+INSTALLED_APPS = (
+    'django.contrib.admin',
+    'django.contrib.auth',
+    'django.contrib.contenttypes',
+    'django.contrib.sessions',
+    'django.contrib.messages',
+    'django.contrib.staticfiles',
+    'hackathon',
+    'bootstrapform',
+    # 'django_openid',
+    'django_nose',
+)
+
+MIDDLEWARE_CLASSES = (
+    'django.contrib.sessions.middleware.SessionMiddleware',
+    'django.middleware.common.CommonMiddleware',
+    'django.middleware.csrf.CsrfViewMiddleware',
+    'django.contrib.auth.middleware.AuthenticationMiddleware',
+    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
+    'django.contrib.messages.middleware.MessageMiddleware',
+    'django.middleware.clickjacking.XFrameOptionsMiddleware',
+    #'django_openid_consumer.SessionConsumer',
+)
+
+ROOT_URLCONF = 'hackathon_starter.urls'
+
+WSGI_APPLICATION = 'hackathon_starter.wsgi.application'
+
+
+# Database
+# https://docs.djangoproject.com/en/1.7/ref/settings/#databases
+
+DATABASES = {
+    'default': {
+        'ENGINE': 'django.db.backends.sqlite3',
+        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
+    }
+}
+
+# Internationalization
+# https://docs.djangoproject.com/en/1.7/topics/i18n/
+
+LANGUAGE_CODE = 'en-us'
+
+TIME_ZONE = 'UTC'
+
+USE_I18N = True
+
+USE_L10N = True
+
+USE_TZ = True
+
+
+# Static files (CSS, JavaScript, Images)
+# https://docs.djangoproject.com/en/1.7/howto/static-files/
+
+STATIC_URL = '/static/'
+
+TEMPLATE_DIRS = [os.path.join(BASE_DIR, 'templates')]
+
+# Use nose to run all tests
+TEST_RUNNER = 'django_nose.NoseTestSuiteRunner'
+
+# Tell nose to measure coverage on the 'foo' and 'bar' apps
+NOSE_ARGS = [
+    '--with-coverage',
+    '--cover-package=hackathon/scripts',
+]
+
+############
+#   KEYS   #
+############
+
+GITHUB_CLIENT_ID = 'client_id=2404a1e21aebd902f6db'
+GITHUB_CLIENT_SECRET = 'client_secret=3da44769d4b7c9465fa4c812669148a163607c23'
+TUMBLR_CONSUMER_KEY = 'KrSbAc9cYLmIgVAn1D21FjRR97QWsutNMxkPDFBxo8CMWtMk4M'
+TUMBLR_CONSUMER_SECRET ='lKWMtL2Lj8zr5pY51PVqT8ugeoG0DjrdgoFewM0QTSyJ12jP8d'
+

+ 8 - 0
hackathon_starter/hackathon_starter/urls.py

@@ -0,0 +1,8 @@
+from django.conf.urls import patterns, include, url
+from django.contrib import admin
+
+urlpatterns = patterns('',
+    url(r'^hackathon/', include('hackathon.urls')),
+    url(r'^admin/', include(admin.site.urls)),
+    # url(r'^openid/(.*)', SessionConsumer()),
+)

+ 14 - 0
hackathon_starter/hackathon_starter/wsgi.py

@@ -0,0 +1,14 @@
+"""
+WSGI config for hackathon_starter project.
+
+It exposes the WSGI callable as a module-level variable named ``application``.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/1.7/howto/deployment/wsgi/
+"""
+
+import os
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "hackathon_starter.settings")
+
+from django.core.wsgi import get_wsgi_application
+application = get_wsgi_application()

+ 10 - 0
hackathon_starter/manage.py

@@ -0,0 +1,10 @@
+#!/usr/bin/env python
+import os
+import sys
+
+if __name__ == "__main__":
+    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "hackathon_starter.settings")
+
+    from django.core.management import execute_from_command_line
+
+    execute_from_command_line(sys.argv)

+ 21 - 0
requirements.txt

@@ -0,0 +1,21 @@
+Django==1.7.6
+PyTumblr==0.0.6
+astroid==1.3.6
+beautifulsoup4==4.3.2
+coverage==4.0a5
+django-bootstrap-form==3.2
+django-bootstrap-forms==0.1
+django-bower==5.0.2
+django-nose==1.3
+httplib2==0.9
+httpretty==0.8.8
+logilab-common==0.63.2
+mock==1.0.1
+nose==1.3.4
+oauth2==1.5.211
+pylint==1.4.3
+python-openid==2.2.5
+requests==2.6.0
+simplejson==3.6.5
+six==1.9.0
+wsgiref==0.1.2