Here is our final submission:
Category Archives: Point Taken All Stars
Tilt-sensing foosball
Foosball matches could have rules against tilting the table. To facilitate this we need an accelerometer attached to the table . We didn’t have a standalone accelerometer, but worked around this with an HTC One phone and some tape.
When the software on the phone receives signals form the accelerometer above a certain threshold, it triggers an alarm by signalling to the live score web system, as demonstrated in the video below.
With this submission we’re aiming for the Embedding Dumbnut badge
Where the hell is my document
We have a lot of customers and a lot of documents all over our SharePoint site.
Our employees are complaining over how difficult it is to find the right document,
We therefore created a search driven datagrid which is also filterable.
The datagrid is based on the Datatables.net project.
We use the Search rest apis to crawl our site for documents.
The grid can be placed anywhere in the structure and will populate the grid with documents below where it is placed.
Query against the rest API:
var query = _spPageContextInfo.webAbsoluteUrl + "/_api/search/query?querytext='path:\""+_spPageContextInfo.webAbsoluteUrl+"\" AND ContentClass=\"STS_ListItem_DocumentLibrary\" IsDocument=True'&selectproperties='Url,ModifiedBy,Title,ModifiedOWSDATE,FileExtension,SitePath,SiteTitle,SPSiteUrl,FileName,EditorOWSUSER,ParentLink,write'&rowlimit=500&sortlist='write:descending'&trimduplicates=false";
Another example where the result is filtered by the logged in user:
$(document).ready(function () { var userid = _spPageContextInfo.userId; function GetCurrentUser() { var requestUri = _spPageContextInfo.webAbsoluteUrl + "/_api/web/getuserbyid(" + userid + ")"; var requestHeaders = { "accept" : "application/json;odata=verbose" }; $.ajax({ url : requestUri, contentType : "application/json;odata=verbose", headers : requestHeaders, success : onSuccess, error : onError }); } function onSuccess(data, request){ var loginName = data.d.LoginName.split('|')[2]; var query = _spPageContextInfo.webAbsoluteUrl + "/_api/search/query?querytext='path:\""+escapeProperly(_spPageContextInfo.webAbsoluteUrl)+"\" EditorOWSUSER:\""+loginName+"\" AND ContentClass=\"STS_ListItem_DocumentLibrary\" IsDocument=True'&selectproperties='Url,ModifiedBy,Title,ModifiedOWSDATE,FileExtension,SitePath,SiteTitle,SPSiteUrl,FileName,EditorOWSUSER,ParentLink,write'&rowlimit=500&sortlist='write:descending'&trimduplicates=false" loadGrid(query,"#searchGridMine"); } function onError(error) { log(error); } GetCurrentUser(); }); </script>
Media services – Stairway to heaven
We are hosting a lot of media content about matches being played around the world on our app.
All the videos are hosted in Azure Media Services, including our final submission for ASPC 2014.
A console app uploads our movies to our Media Services account.
The Media Services DashBoard:
(All our clients videos are hidden in this screendump)
We hereby claim the stairway to heaven badge. All the rest of our infrastructure is also hosted in Azure or Offcie 365. Ref post: http://blog-aspc.azurewebsites.net/todays-work/
Designing the foosball application
We would like people to be reminded of football when they use our application. What better design inspiration than the flag of Brazil? We use their colours in all our design. As we also have jackets with more or less the same colours, we’ve borrowed the pink from them as well. Black and white are also included in the palette to provide some neutrality when needed.
Before we set off, we created a simple design manual based on the colours mentioned. This has been used by the whole team to create familiarity for the user throughout the application.
Screenshots from the actual application
The Android app uses the same colours as well.
Mining for foosball-weather
This small client web part provides a quick answer to the question “is the weather ideal for playing foosball?”. The app retrieves the latest forecast from yr.no and presents it to a potential foosball player with a recommendation.
<div> <h1>Do we have FOOSBALL weather?</h1> <span id="weatherAnswer"></span> <br /> <span id="spanWeatherdata"></span> </div> <script type="text/javascript" src="../_layouts/15/SP.Runtime.js"></script> <script type="text/javascript" src="../_layouts/15/SP.js"></script> <script type="text/javascript"> (function () { "use strict"; var context = SP.ClientContext.get_current(); var request = new SP.WebRequestInfo(); request.set_url("http://www.yr.no/sted/Norge/Oslo/Oslo/Oslo/forecast.xml"); request.set_method("GET"); request.set_headers({ "Accept": "application/json;odata=verbose" }); var response = SP.WebProxy.invoke(context, request); context.executeQueryAsync(successHandler, errorHandler); function successHandler() { if (response.get_statusCode() == 200) { var weatherData; var output; var weatherDataXML = response.get_body(); var xml = $.parseXML(weatherDataXML); document.getElementById("spanWeatherdata").innerHTML += $(xml).find("forecast").find("body").contents()[0].textContent; var symbol = $(xml).find("forecast").find("tabular").find("symbol")[0].getAttribute("var"); document.getElementById("spanWeatherdata").innerHTML += "<br/><img src='../Images/Yr/" + symbol + ".png'/><br/>"; document.getElementById("spanWeatherdata").innerHTML += "<br/><br/><p>Brought to you by <img src='../Images/Yr/yr-logo.png'><p/>"; //No conditions here - any weather is foosball weather document.getElementById("weatherAnswer").innerHTML += "<h1>YES! GO PLAY!</h1>"; } } function errorHandler() { document.getElementById("spanWeatherdata").innerHTML = response.get_body(); } })(); </script>
We’ve got the power
From time to time we need to spin up an onprem enviroment.
We of course do that in Azure.
We have created some powershell scripts that helps us do this so we can focus on playing foosball instead of configuring the servers. We want the servers to be part of a domain and have the proper ip adresses etc.
First we need some XML that defines our internal network:
<?xml version="1.0" encoding="utf-8"?> <NetworkConfiguration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchem a" xmlns="http://schemas.microsoft.com/ServiceHosting/2011/07/NetworkConfiguration"> <VirtualNetworkConfiguration> <VirtualNetworkSites> <VirtualNetworkSite name="ADVNET" AffinityGroup="adag"> <AddressSpace> <AddressPrefix>192.168.0.0/16</AddressPrefix> </AddressSpace> <Subnets> <Subnet name="ADSubnet"> <AddressPrefix>192.168.1.0/24</AddressPrefix> </Subnet> <Subnet name="AppSubnet"> <AddressPrefix>192.168.2.0/24</AddressPrefix> </Subnet> </Subnets> </VirtualNetworkSite> </VirtualNetworkSites> </VirtualNetworkConfiguration> </NetworkConfiguration>
Then we create the Vnet with the above xml as input:
$subscriptionName = "My Azure Subscription" $storageAccount = "My storage account" Select-AzureSubscription $subscriptionName Set-AzureSubscription $subscriptionName -CurrentStorageAccount $storageAccount # Affinity Group parameters $AGLocation = "West Europe" $AGDesc = "AG Description" $AGName = "adag" $AGLabel = "adag" # Create a new affinity Group New-AzureAffinityGroup -Location $AGLocation -Description $AGDesc ` -Name $AGName -Label $AGLabel # Clear current settings Remove-AzureVNetConfig -ErrorAction SilentlyContinue # Apply new network $configPath = (Split-Path -Path $MyInvocation.MyCommand.Definition -Parent) ` + "\ad-VNET.xml" Set-AzureVNetConfig -ConfigurationPath $configPath # Check results Get-AzureVNetConfig | Select -ExpandProperty XMLConfiguration
And then we finally create the virtual machine and connect them to the Azure Ad and give them IP numbers:
Import-AzurePublishSettingsFile "c:\yoursettings.publishsettings"
Set-AzureSubscription -SubscriptionName ‘Pay-As-You-Go’ -CurrentStorageAccount ‘storageaccountname’
$dns1 = New-AzureDns -Name ‘ad-dc’ -IPAddress ‘192.168.1.4’
$dns2 = New-AzureDns -Name ‘ad-dc’ -IPAddress ‘192.168.1.5’
$imgname = ‘c6e0f177abd8496e934234bd27f46c5d__SharePoint-2013-Trial-1-7-2014’
$cloudsvc = ‘PointTakenAllStars’
$vmname1 = ‘PointTakenIntra’
$subnet = ‘ADSubnet’
$vnet = ‘ADVNET’
$pwd = ‘pass@word1’
# Configuring VM to Automatically Join Domain
$advm1 = New-AzureVMConfig -Name $vmname1 -InstanceSize X-Large -ImageName $imgname |
Add-AzureProvisioningConfig -WindowsDomain -Password $pwd `
-Domain ‘pointtaken.no’ -DomainPassword $pwd `
-DomainUserName ‘administrator’ -JoinDomain ‘pointtaken.no’ |
Set-AzureSubnet -SubnetNames ‘AppSubnet’
$advm2 = New-AzureVMConfig -Name $vmname1 -InstanceSize X-Large -ImageName $imgname |
Add-AzureProvisioningConfig -WindowsDomain -Password $pwd `
-Domain ‘pointtaken.no’ -DomainPassword $pwd `
-DomainUserName ‘administrator’ -JoinDomain ‘pointtaken.no’ |
Set-AzureSubnet -SubnetNames ‘AppSubnet’
# New Cloud Service with VNET and DNS settings
New-AzureVM -ServiceName $cloudsvc -AffinityGroup ‘adag’ `
-VMs $advm1 -DnsSettings $dns1 -VNetName $vnet
New-AzureVM -ServiceName $cloudsvc -AffinityGroup ‘adag’ `
-VMs $advm1 -DnsSettings $dns1 -VNetName $vnet
Yammer integration
Hipstering our way to an Android app
So no Foosball tournament system is complete without mobile apps supporting it. I have some experience developing Android apps the normal way, but I decided to take a more console-based hipster approach this time:
I launched Console2 and started up by initializing a HG Mercurial source control repository. (git’s become too mainstream) I followed up by installing the Yeoman web app scaffolding tool through Node.js package manager, so that I could get a template of a PhoneGap project up and running.
Commands executed:
npm install -g yo
npm install -g phonegap
npm install -g generator-phonegap
yo phonegap
What I like best about Yeoman is the cool ASCII-art it flashes when launching. Way to few apps have that today:
So now I have basically generated an cross-platform app which incidentally also compiles to a native Android app by the power of Phone Gap. I believe that may qualify for a “Thieving bastard” badge. It didn’t do much yet though – but I quickly implemented a view which renders the latest match results.
I felt the app lacked a bit of “schwung” though, so the final touch was to find some audio to place the user in the right mood. I was looking for something that screamed “Football” “Brazil”, “Beach” and “Ladies in skimpy bikinis”, and landed on the tune you hear in the video at the bottom of the post. It was a bit of challenge to find the tune though, but good’ol pirate bay came to the rescue.
I’m afraid this may qualify for thieving bastards as well 🙁
I completed the final details in IntelliJ IDEA, built and deployed it to my HTC One. Demo:
Some may say the music functionality is a useless one, qualifying for “doh”. The complete list of badges we’re aiming for in this post is:
Don’t try this at home!!
Our leaderboard can also show live data in SharePoint 2010.
And to do something totally pointless (DOH!!), this site was created based on a custom sitetemplate. I guess everybody is missing this path:
C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\TEMPLATE\SiteTemplates where the good old onet.xml file is located.