diff --git a/samples/react-socket-io/Deploy-Solution.ps1 b/samples/react-socket-io/Deploy-Solution.ps1
new file mode 100644
index 000000000..cf8036089
--- /dev/null
+++ b/samples/react-socket-io/Deploy-Solution.ps1
@@ -0,0 +1,147 @@
+[CmdletBinding()]
+Param(
+ [Parameter(Mandatory=$True,Position=1)]
+ [string]$SiteUrl,
+
+ [Parameter(Mandatory=$True)]
+ [string]$UserName,
+
+ [Parameter(Mandatory=$True)]
+ [string]$Password
+)
+
+$0 = $myInvocation.MyCommand.Definition
+$CommandDirectory = [System.IO.Path]::GetDirectoryName($0)
+
+Set-Location $CommandDirectory
+
+# -----------------------------------------------------
+# SharePoint Configuration
+# -----------------------------------------------------
+
+# Connect to the site
+$PasswordAsSecure = ConvertTo-SecureString $Password -AsPlainText -Force
+$Credentials = New-Object System.Management.Automation.PSCredential ($UserName , $PasswordAsSecure)
+Connect-SPOnline -Url $SiteUrl -Credentials $Credentials
+
+Write-Host -ForegroundColor Magenta "Apply PnP template to site '$SiteUrl'..."
+
+# Create the SharePoint list in the dev site
+Apply-SPOProvisioningTemplate -Path ".\template.xml"
+
+Write-Host -ForegroundColor Green "Done!"
+
+# -----------------------------------------------------
+# Azure Configuration
+# -----------------------------------------------------
+
+Write-Host -ForegroundColor Magenta "Login to Azure..."
+Login-AzureRmAccount
+
+$GitPublishingUserName = "tempdeployuser" + [Guid]::NewGuid();
+$GitPublishingUserPassword = "socketio123!"
+$AzureSBNamespace = "SPFxSocketIOServiceBus";
+$AzureWebAppName = "SPFxSocketIOWebApp"+[Guid]::NewGuid()
+$AppServicePlanName = "SPFxSocketIOServicePlan"
+$TemplateFilePath = ".\azure-deploy.json"
+$AzureResourceGroupLocation = "East US2"
+$AzureResourceGroupName = "SPFxSocketIODemo"
+$AzureRmResourceGroupDeploymentName = "SPFxSocketIODemo"
+$ServerCodeFolderLocation = ".\server"
+
+# Set the publishing user and password for the local Git deployment
+$PropertiesObject = @{
+ "publishingUserName" = $GitPublishingUserName;
+ "publishingPassword" = $GitPublishingUserPassword;
+}
+
+Set-AzureRmResource -PropertyObject $PropertiesObject -ResourceId /providers/Microsoft.Web/publishingUsers/web -ApiVersion 2015-08-01 -Force
+
+Write-Host -ForegroundColor Magenta "Creating the Azure resource Group [$AzureResourceGroupName]..."
+New-AzureRmResourceGroup -Name $AzureResourceGroupName -Location $AzureResourceGroupLocation
+
+# Deploy the Azure Resource Group using an ARM template
+# More information here: https://azure.microsoft.com/en-us/documentation/articles/resource-group-authoring-templates/#resources
+
+$TemplateParameters = @{
+ "ServiceBusNameSpace"=$AzureSBNamespace;
+ "AppServicePlanName"= $AppServicePlanName;
+ "SiteName"=$AzureWebAppName;
+ "Location"=$AzureResourceGroupLocation
+}
+
+Write-Host -ForegroundColor Magenta "Deploying Azure resources using ARM template..."
+Test-AzureRmResourceGroupDeployment -ResourceGroupName $AzureResourceGroupName -TemplateFile $TemplateFilePath -TemplateParameterObject $TemplateParameters
+New-AzureRmResourceGroupDeployment -Name $AzureRmResourceGroupDeploymentName -ResourceGroupName $AzureResourceGroupName -TemplateFile $TemplateFilePath -TemplateParameterObject $TemplateParameters
+Write-Host -ForegroundColor Green "Done!"
+
+Write-Host -ForegroundColor Magenta "Updating Web Application settings..."
+$CurrentNamespace = Get-AzureSBNamespace -Name $AzureSBNamespace
+
+# Check if the namespace already exists or needs to be created
+if ($CurrentNamespace) {
+ # Set the Web Applicatio settings
+ $AppSettings = New-Object Hashtable
+ $AppSettings["AZURE_SERVICEBUS_ACCESS_KEY"]=$CurrentNamespace.ConnectionString
+
+ # Set application settings and enable WebSockets
+ Set-AzureWebsite -Name $AzureWebAppName -AppSettings $AppSettings
+}
+Write-Host -ForegroundColor Green "Done!"
+
+# Deploy the code to the Web Application using Local Git
+
+# Note: the part below is only valid for this demo. In a real world situation, you may want link to your TFS/GitHub/BitBucket repository instead.
+# See https://azure.microsoft.com/en-us/documentation/articles/app-service-deploy-local-git/ for more information
+Write-Host -ForegroundColor Magenta "Deploying the Web Application Node JS code using Local Git..."
+
+# Go to the location where the code for the server is located and commit/push it to the local git repository of the web application.
+Push-Location $ServerCodeFolderLocation
+
+# Remove previous git config if exists
+if (Test-Path .git) {
+ Remove-Item -Recurse .git -Force
+}
+
+git init
+
+git add -A
+
+git commit -m "SPFx Socket IO Demo - Server code"
+
+# Build the git clone URL with embbed password
+$GitCloneURL = "https://$GitPublishingUserName" + ":$GitPublishingUserPassword@$AzureWebAppName.scm.azurewebsites.net:443/$AzureWebAppName.git"
+
+# Make sure there is no 502 error and the git URL is up and running (can take few seconds)
+$Timeout = New-TimeSpan -Minutes 1
+$sw = [Diagnostics.Stopwatch]::StartNew()
+
+Write-Host -ForegroundColor Yellow "Wait for the git clone URL is up and running" -NoNewline
+while ($sw.elapsed -lt $Timeout) {
+
+ if ((Invoke-WebRequest -Uri $GitCloneURL).StatusCode -eq 200) {
+
+ Write-Host "`n"
+
+ git remote add azure $GitCloneURL 2>&1 | %{ "$_" }
+
+ # We force the push to overwrite remote with local files avoiding update conflicts (don't use this in production)
+
+ git push azure master --force 2>&1 | %{ "$_" }
+
+ # Update URLs in the client side code according to the web app name
+
+ Pop-Location
+
+ $files = @(".\client\config\config.json",".\client\src\webparts\realTimeNewsFeed\components\RealTimeNewsFeed.tsx")
+ $files | ForEach-Object { (Get-Content $_) -replace 'https:\/\/(\S*)\.azurewebsites\.net', "https://$AzureWebAppName.azurewebsites.net" | Set-Content $_ }
+
+ Write-Host -ForegroundColor Green "Done!"
+
+ return
+ }
+
+ Start-Sleep -Seconds 5
+ Write-Host -ForegroundColor Yellow "."
+}
+Write-Warning "The git clone URL timed out!"
\ No newline at end of file
diff --git a/samples/react-socket-io/README.md b/samples/react-socket-io/README.md
new file mode 100644
index 000000000..5bba5aa6b
--- /dev/null
+++ b/samples/react-socket-io/README.md
@@ -0,0 +1,163 @@
+# Real Time News Feed using SPFx, Flow, Azure and socket.io #
+
+## Summary
+
+This sample shows you how to implement real time web parts using the SPFx, Microsoft Flow and socket.io.
+
+
+
+
+
+### Solution Architecture ###
+
+Here is the solution overview:
+
+
+
+
+
+1. The SPFx Web Part first connects to the Azure web application via socket.io and subscribes to events (the web application have to be in https and allow cross domain calls (CORS)).
+2. Microsoft Flow is used to catch new item creation events in the SharPoint list.
+3. When an item is added, the flow sends its id to an Azure service bus queue using JSON format.
+4. A Node JS Azure web application listens to the queue and check for new messages every 5 ms.
+5. When a new message is available, the web application emits the data to all subscribers via socket.io.
+6. The SPFx Web Part notifies user there are new items available. Items are effectively retrieved via REST according to received ids when the user clicks on the notification.
+
+## Applies to
+
+* [SharePoint Framework Developer Preview](http://dev.office.com/sharepoint/docs/spfx/sharepoint-framework-overview)
+* [Office 365 developer tenant](http://dev.office.com/sharepoint/docs/spfx/set-up-your-developer-tenant)
+
+## Prerequisites
+
+Before starting, you'll need to install some prerequisites:
+
+- Install the [Azure PowerShell SDK](https://azure.microsoft.com/en-us/documentation/articles/powershell-install-configure/). Make sure you've installed the AzureRM module as well.
+- Install the latest release of [PnP PowerShell cmdlets 'SharePointPnPPowerShellOnline'](https://github.com/OfficeDev/PnP-PowerShell/releases) or a version compatible with the 201605 PnP schema version.
+- Install [Node.js](https://nodejs.org/en/) on your machine.
+- Install [Git for Windows](https://git-scm.com/download/win).
+- Get the [latest version](https://dev.office.com/sharepoint/docs/spfx/set-up-your-development-environment) of the SharePoint Framework yeoman generator (in this case **SPFx Drop 5**) and make sure TypeScript 2.0 is available on your machine (`npm install -g typescript@latest`).
+- Create a site collection with the developer template.
+- Go to the ".\client" folder and install all dependencies listed in the package.json file by running the `npm install` cmd.
+
+## Solution
+
+Solution|Author(s)
+--------|---------
+samples\react-socket-io | Franck Cornu (MVP, @franckcornu)
+
+## Version history
+
+Version|Date|Comments
+-------|----|--------
+1.0|October 25, 2016 | Initial commit
+
+## Disclaimer
+**THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.**
+
+---
+
+## Minimal Path to Awesome
+
+1. Download the source code as ZIP from GitHub and extract it to your destination folder
+2. On a remote machine (basically, where PnP & Azure cmdlets are installed), start new PowerShell session as an **administrator** an call the `Deploy-Solution.ps1` script with your parameters like this:
+
+ ```csharp
+ $UserName = "username@.onmicrosoft.com"
+ $Password = ""
+ $SiteUrl = "https://.sharepoint.com/sites/"
+
+ Set-Location "\samples\react-socket-io"
+
+ $Script = ".\Deploy-Solution.ps1"
+ & $Script -SiteUrl $SiteUrl -UserName $UserName -Password $Password
+
+ ```
+
+ It will configure the targeted SharePoint site and create the Azure resource group for the server part using an Azure Resource Manager template (JSON file).
+
+ **IMPORTANT NOTES**
+
+ It is recommended to deploy this solution on a test Azure subscription because by default, the script will override the local git deployment credentials configured for your subscription (for the web application provisioning).
+ If you want to set you own parameters, update the `Deploy-Solution.ps1` script and replace tokens with your desired configuration.
+ Notice that some values have to be unique within the whole Azure platform (for instance, the web application name and the deployment user name), that's why we use a random guid each time.
+
+
+ ```ps
+
+ # -----------------------------------------------------
+ # Azure Configuration
+ # -----------------------------------------------------
+
+ Login-AzureRmAccount
+
+ $GitPublishingUserName = "tempdeployuser" + [Guid]::NewGuid();
+ $GitPublishingUserPassword = "socketio123!"
+ $AzureSBNamespace = "SPFxSocketIOServiceBus";
+ $AzureWebAppName = "SPFxSocketIOWebApp"+[Guid]::NewGuid()
+ $AppServicePlanName = "SPFxSocketIOServicePlan"
+ $TemplateFilePath = ".\azure-deploy.json"
+ $AzureResourceGroupLocation = "East US2"
+ $AzureResourceGroupName = "SPFxSocketIODemo"
+ $AzureRmResourceGroupDeploymentName = "SPFxSocketIODemo"
+ $ServerCodeFolderLocation = ".\server"
+
+ ```
+3. When prompted, enter your Azure credentials
+4. Wait for the installation to finish. It can take several minutes to complete due to the npm packages installation on the Azure web application.
+5. Go to the ".\client" folder and run the `gulp serve` cmd to launch the SharePoint Workbench on localhost. Open the network panel in developer console and make sure the Azure web application can be reached.
+
+
+
+
+
+ You can let the `gulp serve` cmd running.
+
+6. Because there is no automated mechanism to provision new template in the Microsoft Flow application, you have to manually create the flow on the SharePoint list in your developer site.
+ Go the 'NewsList' and create a new flow from scratch and add the following steps:
+
+- **[Condition]** *"SharePoint - When a new item is created"*
+- **[Action]** *"Service Bus - Send Message"*
+
+
+
+
+
+ **TIP**
+
+ The first time you will add the "Service bus - Send Message" action, you will asked to enter the service bus connection string:
+
+
+
+
+
+ To get it, go to your Azure portal and select the "*SPFxSocketIODemo*" resource group and click on the service bus resource.
+ From here your will be able to get the primary connection string:
+
+
+
+
+
+7. Go back to your list and add initial items in the list.
+8. In your SharePoint site, [upload the workbench.aspx page](https://dev.office.com/sharepoint/docs/spfx/set-up-your-developer-tenant) in the *Documents* library and add the *"RealTimeNewsFeed"* Web Part to your page. You should see newly created items.
+
+
+
+
+
+9. Go back to your list and create some others items. Because of the flow is asynchronous, you should see new items appear after few seconds (between 5 and 30 seconds) on the opened Workbench page.
+
+
+
+
+
+
+## Features
+
+This Web Part illustrates the following concepts on top of the SharePoint Framework:
+
+- Using web sockets through the socket.io library to implement real time communications with an Azure back end server.
+- Using PnP JS library (1.0.5) to get items from a list.
+- Using Office UI Fabric React components to build a beautiful desgin
+
+
\ No newline at end of file
diff --git a/samples/react-socket-io/assets/animated-demo.gif b/samples/react-socket-io/assets/animated-demo.gif
new file mode 100644
index 000000000..cd6b64bad
Binary files /dev/null and b/samples/react-socket-io/assets/animated-demo.gif differ
diff --git a/samples/react-socket-io/assets/flow.png b/samples/react-socket-io/assets/flow.png
new file mode 100644
index 000000000..51dcef221
Binary files /dev/null and b/samples/react-socket-io/assets/flow.png differ
diff --git a/samples/react-socket-io/assets/network-console.png b/samples/react-socket-io/assets/network-console.png
new file mode 100644
index 000000000..4e99307bf
Binary files /dev/null and b/samples/react-socket-io/assets/network-console.png differ
diff --git a/samples/react-socket-io/assets/service-bus-new-connection.png b/samples/react-socket-io/assets/service-bus-new-connection.png
new file mode 100644
index 000000000..88fdfe33f
Binary files /dev/null and b/samples/react-socket-io/assets/service-bus-new-connection.png differ
diff --git a/samples/react-socket-io/assets/service-bus.png b/samples/react-socket-io/assets/service-bus.png
new file mode 100644
index 000000000..7d2edd174
Binary files /dev/null and b/samples/react-socket-io/assets/service-bus.png differ
diff --git a/samples/react-socket-io/assets/solution_overview.png b/samples/react-socket-io/assets/solution_overview.png
new file mode 100644
index 000000000..7b4cf5e7e
Binary files /dev/null and b/samples/react-socket-io/assets/solution_overview.png differ
diff --git a/samples/react-socket-io/assets/spfx-initial.png b/samples/react-socket-io/assets/spfx-initial.png
new file mode 100644
index 000000000..a7bd03400
Binary files /dev/null and b/samples/react-socket-io/assets/spfx-initial.png differ
diff --git a/samples/react-socket-io/assets/spfx-newitem.png b/samples/react-socket-io/assets/spfx-newitem.png
new file mode 100644
index 000000000..803a7b75d
Binary files /dev/null and b/samples/react-socket-io/assets/spfx-newitem.png differ
diff --git a/samples/react-socket-io/azure-deploy.json b/samples/react-socket-io/azure-deploy.json
new file mode 100644
index 000000000..06091cde2
--- /dev/null
+++ b/samples/react-socket-io/azure-deploy.json
@@ -0,0 +1,152 @@
+{
+ "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
+ "contentVersion": "1.0.0.0",
+ "parameters": {
+ "ServiceBusNameSpace": {
+ "defaultValue": "",
+ "type": "string"
+ },
+ "AppServicePlanName": {
+ "defaultValue": "",
+ "type": "string"
+ },
+ "SiteName": {
+ "defaultValue": "",
+ "type": "string"
+ },
+ "AuthorizationRules_RootManageSharedAccessKey_name": {
+ "defaultValue": "[concat(parameters('ServiceBusNameSpace'),'/RootManageSharedAccessKey')]",
+ "type": "string"
+ },
+ "Location": {
+ "defaultValue": "East US2",
+ "type": "string"
+ },
+ "ServiceBusQueueName": {
+ "defaultValue": "news",
+ "type": "string"
+ }
+ },
+ "variables": {},
+ "resources": [
+ {
+ "comments": "",
+ "type": "Microsoft.ServiceBus/namespaces",
+ "sku": {
+ "name": "Basic",
+ "tier": "Basic"
+ },
+ "kind": "Messaging",
+ "name": "[parameters('ServiceBusNameSpace')]",
+ "apiVersion": "2015-08-01",
+ "location": "[parameters('Location')]",
+ "tags": {},
+ "resources": [
+ {
+ "apiVersion": "2015-08-01",
+ "name": "[parameters('ServiceBusQueueName')]",
+ "type": "queues",
+ "location": "[parameters('Location')]",
+ "dependsOn": [
+ "[concat('Microsoft.ServiceBus/namespaces/', parameters('ServiceBusNameSpace'))]"
+ ],
+ "properties": {
+ "path": "[parameters('ServiceBusQueueName')]",
+ "defaultMessageTimeToLive": "14.00:00:00"
+ }
+ }
+ ],
+ "dependsOn": []
+ },
+ {
+ "comments": "",
+ "type": "Microsoft.Web/serverfarms",
+ "sku": {
+ "name": "B1",
+ "tier": "Basic",
+ "size": "B1",
+ "family": "B",
+ "capacity": 1
+ },
+ "name": "[parameters('AppServicePlanName')]",
+ "apiVersion": "2015-08-01",
+ "location": "[parameters('Location')]",
+ "properties": {
+ "name": "[parameters('AppServicePlanName')]",
+ "numberOfWorkers": 1
+ },
+ "resources": [],
+ "dependsOn": []
+ },
+ {
+ "comments": "",
+ "type": "Microsoft.Web/sites",
+ "name": "[parameters('SiteName')]",
+ "apiVersion": "2015-08-01",
+ "location": "[parameters('Location')]",
+ "tags": {
+ },
+ "properties": {
+ "name": "[parameters('SiteName')]",
+ "hostNames": [
+ "[concat(parameters('SiteName'),'.azurewebsites.net')]"
+ ],
+ "enabledHostNames": [
+ "[concat(parameters('SiteName'),'.azurewebsites.net')]",
+ "[concat(parameters('SiteName'),'.scm.azurewebsites.net')]"
+ ],
+ "hostNameSslStates": [
+ {
+ "name": "[concat(parameters('SiteName'),'.azurewebsites.net')]",
+ "sslState": 0,
+ "thumbprint": null,
+ "ipBasedSslState": 0
+ },
+ {
+ "name": "[concat(parameters('SiteName'),'.scm.azurewebsites.net')]",
+ "sslState": 0,
+ "thumbprint": null,
+ "ipBasedSslState": 0
+ }
+ ],
+ "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', parameters('AppServicePlanName'))]"
+ },
+ "resources": [
+ {
+ "apiVersion": "2015-08-01",
+ "location": "[parameters('Location')]",
+ "name": "web",
+ "type": "config",
+ "properties": {
+ "scmType": "LocalGit",
+ "webSocketsEnabled": true,
+ "phpVersion": " "
+ },
+ "dependsOn": [
+ "[resourceId('Microsoft.Web/sites', parameters('SiteName'))]"
+ ]
+ }
+ ],
+ "dependsOn": [
+ "[resourceId('Microsoft.Web/serverfarms', parameters('AppServicePlanName'))]"
+ ]
+ },
+ {
+ "comments": "",
+ "type": "Microsoft.ServiceBus/namespaces/AuthorizationRules",
+ "name": "[parameters('AuthorizationRules_RootManageSharedAccessKey_name')]",
+ "apiVersion": "2015-08-01",
+ "properties": {
+ "rights": [
+ "Listen",
+ "Manage",
+ "Send"
+ ]
+ },
+ "resources": [],
+ "dependsOn": [
+ "[resourceId('Microsoft.ServiceBus/namespaces', parameters('ServiceBusNameSpace'))]"
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/samples/react-socket-io/client/.editorconfig b/samples/react-socket-io/client/.editorconfig
new file mode 100644
index 000000000..8ffcdc4ec
--- /dev/null
+++ b/samples/react-socket-io/client/.editorconfig
@@ -0,0 +1,25 @@
+# EditorConfig helps developers define and maintain consistent
+# coding styles between different editors and IDEs
+# editorconfig.org
+
+root = true
+
+
+[*]
+
+# change these settings to your own preference
+indent_style = space
+indent_size = 2
+
+# we recommend you to keep these unchanged
+end_of_line = lf
+charset = utf-8
+trim_trailing_whitespace = true
+insert_final_newline = true
+
+[*.md]
+trim_trailing_whitespace = false
+
+[{package,bower}.json]
+indent_style = space
+indent_size = 2
\ No newline at end of file
diff --git a/samples/react-socket-io/client/.gitattributes b/samples/react-socket-io/client/.gitattributes
new file mode 100644
index 000000000..212566614
--- /dev/null
+++ b/samples/react-socket-io/client/.gitattributes
@@ -0,0 +1 @@
+* text=auto
\ No newline at end of file
diff --git a/samples/react-socket-io/client/.gitignore b/samples/react-socket-io/client/.gitignore
new file mode 100644
index 000000000..63c4ae010
--- /dev/null
+++ b/samples/react-socket-io/client/.gitignore
@@ -0,0 +1,32 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+
+# Dependency directories
+node_modules
+
+# Build generated files
+dist
+lib
+solution
+temp
+*.spapp
+
+# Coverage directory used by tools like istanbul
+coverage
+
+# OSX
+.DS_Store
+
+# Visual Studio files
+.ntvs_analysis.dat
+.vs
+bin
+obj
+
+# Resx Generated Code
+*.resx.ts
+
+# Styles Generated Code
+*.scss.ts
diff --git a/samples/react-socket-io/client/.npmignore b/samples/react-socket-io/client/.npmignore
new file mode 100644
index 000000000..2c93a9384
--- /dev/null
+++ b/samples/react-socket-io/client/.npmignore
@@ -0,0 +1,14 @@
+# Folders
+.vscode
+coverage
+node_modules
+sharepoint
+src
+temp
+
+# Files
+*.csproj
+.git*
+.yo-rc.json
+gulpfile.js
+tsconfig.json
diff --git a/samples/react-socket-io/client/.yo-rc.json b/samples/react-socket-io/client/.yo-rc.json
new file mode 100644
index 000000000..e09552821
--- /dev/null
+++ b/samples/react-socket-io/client/.yo-rc.json
@@ -0,0 +1,7 @@
+{
+ "@microsoft/generator-sharepoint": {
+ "libraryName": "spfx-socket-io",
+ "libraryId": "a89569d5-e511-4f93-8cba-eabdd0567ee5",
+ "framework": "react"
+ }
+}
\ No newline at end of file
diff --git a/samples/react-socket-io/client/config/config.json b/samples/react-socket-io/client/config/config.json
new file mode 100644
index 000000000..fc0b6bc47
--- /dev/null
+++ b/samples/react-socket-io/client/config/config.json
@@ -0,0 +1,22 @@
+{
+ "entries": [
+ {
+ "entry": "./lib/webparts/realTimeNewsFeed/RealTimeNewsFeedWebPart.js",
+ "manifest": "./src/webparts/realTimeNewsFeed/RealTimeNewsFeedWebPart.manifest.json",
+ "outputPath": "./dist/real-time-news-feed.bundle.js"
+ }
+ ],
+ "externals": {
+ "@microsoft/sp-client-base": "node_modules/@microsoft/sp-client-base/dist/sp-client-base.js",
+ "@microsoft/sp-client-preview": "node_modules/@microsoft/sp-client-preview/dist/sp-client-preview.js",
+ "@microsoft/sp-lodash-subset": "node_modules/@microsoft/sp-lodash-subset/dist/sp-lodash-subset.js",
+ "office-ui-fabric-react": "node_modules/office-ui-fabric-react/dist/office-ui-fabric-react.js",
+ "react": "node_modules/react/dist/react.min.js",
+ "react-dom": "node_modules/react-dom/dist/react-dom.min.js",
+ "react-dom/server": "node_modules/react-dom/dist/react-dom-server.min.js",
+ "socket.io-client": "https://SPFxSocketIOWebAppdde17113-805a-4806-b5e6-43dbb5f61b9f.azurewebsites.net/socket.io/socket.io.js"
+ },
+ "localizedResources": {
+ "realTimeNewsFeedStrings": "webparts/realTimeNewsFeed/loc/{locale}.js"
+ }
+}
diff --git a/samples/react-socket-io/client/config/deploy-azure-storage.json b/samples/react-socket-io/client/config/deploy-azure-storage.json
new file mode 100644
index 000000000..fd310b68a
--- /dev/null
+++ b/samples/react-socket-io/client/config/deploy-azure-storage.json
@@ -0,0 +1,6 @@
+{
+ "workingDir": "./temp/deploy/",
+ "account": "",
+ "container": "spfx-socket-io",
+ "accessKey": ""
+}
\ No newline at end of file
diff --git a/samples/react-socket-io/client/config/package-solution.json b/samples/react-socket-io/client/config/package-solution.json
new file mode 100644
index 000000000..dca10f30e
--- /dev/null
+++ b/samples/react-socket-io/client/config/package-solution.json
@@ -0,0 +1,10 @@
+{
+ "solution": {
+ "name": "spfx-socket-io-client-side-solution",
+ "id": "a89569d5-e511-4f93-8cba-eabdd0567ee5",
+ "version": "1.0.0.0"
+ },
+ "paths": {
+ "zippedPackage": "solution/spfx-socket-io.spapp"
+ }
+}
diff --git a/samples/react-socket-io/client/config/prepare-deploy.json b/samples/react-socket-io/client/config/prepare-deploy.json
new file mode 100644
index 000000000..6aca63656
--- /dev/null
+++ b/samples/react-socket-io/client/config/prepare-deploy.json
@@ -0,0 +1,3 @@
+{
+ "deployCdnPath": "temp/deploy"
+}
diff --git a/samples/react-socket-io/client/config/serve.json b/samples/react-socket-io/client/config/serve.json
new file mode 100644
index 000000000..087899637
--- /dev/null
+++ b/samples/react-socket-io/client/config/serve.json
@@ -0,0 +1,9 @@
+{
+ "port": 4321,
+ "initialPage": "https://localhost:5432/workbench",
+ "https": true,
+ "api": {
+ "port": 5432,
+ "entryPath": "node_modules/@microsoft/sp-webpart-workbench/lib/api/"
+ }
+}
diff --git a/samples/react-socket-io/client/config/tslint.json b/samples/react-socket-io/client/config/tslint.json
new file mode 100644
index 000000000..bf3362c87
--- /dev/null
+++ b/samples/react-socket-io/client/config/tslint.json
@@ -0,0 +1,51 @@
+{
+ // Display errors as warnings
+ "displayAsWarning": true,
+ // The TSLint task may have been configured with several custom lint rules
+ // before this config file is read (for example lint rules from the tslint-microsoft-contrib
+ // project). If true, this flag will deactivate any of these rules.
+ "removeExistingRules": true,
+ // When true, the TSLint task is configured with some default TSLint "rules.":
+ "useDefaultConfigAsBase": false,
+ // Since removeExistingRules=true and useDefaultConfigAsBase=false, there will be no lint rules
+ // which are active, other than the list of rules below.
+ "lintConfig": {
+ // Opt-in to Lint rules which help to eliminate bugs in JavaScript
+ "rules": {
+ "class-name": false,
+ "export-name": false,
+ "forin": false,
+ "label-position": false,
+ "label-undefined": false,
+ "member-access": true,
+ "no-arg": false,
+ "no-console": false,
+ "no-construct": false,
+ "no-duplicate-case": true,
+ "no-duplicate-key": false,
+ "no-duplicate-variable": true,
+ "no-eval": false,
+ "no-function-expression": true,
+ "no-internal-module": true,
+ "no-shadowed-variable": true,
+ "no-switch-case-fall-through": true,
+ "no-unnecessary-semicolons": true,
+ "no-unused-expression": true,
+ "no-unused-imports": true,
+ "no-unused-variable": true,
+ "no-unreachable": true,
+ "no-use-before-declare": true,
+ "no-with-statement": true,
+ "semicolon": true,
+ "trailing-comma": false,
+ "typedef": false,
+ "typedef-whitespace": false,
+ "use-named-parameter": true,
+ "valid-typeof": true,
+ "variable-name": false,
+ "whitespace": false,
+ "prefer-const": true,
+ "a11y-role": true
+ }
+ }
+}
\ No newline at end of file
diff --git a/samples/react-socket-io/client/config/write-manifests.json b/samples/react-socket-io/client/config/write-manifests.json
new file mode 100644
index 000000000..0a4bafb06
--- /dev/null
+++ b/samples/react-socket-io/client/config/write-manifests.json
@@ -0,0 +1,3 @@
+{
+ "cdnBasePath": ""
+}
\ No newline at end of file
diff --git a/samples/react-socket-io/client/gulpfile.js b/samples/react-socket-io/client/gulpfile.js
new file mode 100644
index 000000000..7d36ddb1c
--- /dev/null
+++ b/samples/react-socket-io/client/gulpfile.js
@@ -0,0 +1,6 @@
+'use strict';
+
+const gulp = require('gulp');
+const build = require('@microsoft/sp-build-web');
+
+build.initialize(gulp);
diff --git a/samples/react-socket-io/client/package.json b/samples/react-socket-io/client/package.json
new file mode 100644
index 000000000..8bc9e3bea
--- /dev/null
+++ b/samples/react-socket-io/client/package.json
@@ -0,0 +1,35 @@
+{
+ "name": "spfx-socket-io",
+ "version": "0.0.1",
+ "private": true,
+ "engines": {
+ "node": ">=0.10.0"
+ },
+ "author": {
+ "name": "Franck Cornu @FranckCornu (http://thecollaborationcorner.com)"
+ },
+ "dependencies": {
+ "@microsoft/sp-client-base": "~0.4.0",
+ "@microsoft/sp-client-preview": "~0.5.0",
+ "@types/pluralize": "0.0.27",
+ "@types/socket.io-client": "^1.4.27",
+ "office-ui-fabric-react": "0.36.0",
+ "pluralize": "^3.0.0",
+ "react": "0.14.8",
+ "react-addons-update": "^15.3.2",
+ "react-dom": "0.14.8",
+ "socket.io-client": "^1.5.0",
+ "sp-pnp-js": "^1.0.5"
+ },
+ "devDependencies": {
+ "@microsoft/sp-build-web": "~0.7.0",
+ "@microsoft/sp-module-interfaces": "~0.4.0",
+ "@microsoft/sp-webpart-workbench": "~0.5.0",
+ "gulp": "~3.9.1"
+ },
+ "scripts": {
+ "build": "gulp bundle",
+ "clean": "gulp nuke",
+ "test": "gulp test"
+ }
+}
diff --git a/samples/react-socket-io/client/spfx-socket-io.njsproj b/samples/react-socket-io/client/spfx-socket-io.njsproj
new file mode 100644
index 000000000..6bdec73aa
--- /dev/null
+++ b/samples/react-socket-io/client/spfx-socket-io.njsproj
@@ -0,0 +1,86 @@
+
+
+
+ Debug
+ 2.0
+ {a89569d5-e511-4f93-8cba-eabdd0567ee5}
+
+ ProjectFiles
+ node_modules\gulp\bin\gulp.js
+ .
+ .
+ {3AF33F2E-1136-4D97-BBB7-1795711AC8B8};{349c5851-65df-11da-9384-00065b846f21};{9092AA53-FB77-4645-B42D-1CCCA6BD08BD}
+ true
+ CommonJS
+ false
+ 11.0
+ $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
+ serve
+ True
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ False
+ True
+ 0
+ /
+ http://localhost:48022/
+ False
+ True
+ http://localhost:1337
+ False
+
+
+
+
+
+
+ CurrentPage
+ True
+ False
+ False
+ False
+
+
+
+
+
+
+
+
+ False
+ False
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/react-socket-io/client/src/tests.js b/samples/react-socket-io/client/src/tests.js
new file mode 100644
index 000000000..cb4bb5cf2
--- /dev/null
+++ b/samples/react-socket-io/client/src/tests.js
@@ -0,0 +1,5 @@
+var context = require.context('.', true, /.+\.test\.js?$/);
+
+context.keys().forEach(context);
+
+module.exports = context;
diff --git a/samples/react-socket-io/client/src/webparts/realTimeNewsFeed/IRealTimeNewsFeedWebPartProps.ts b/samples/react-socket-io/client/src/webparts/realTimeNewsFeed/IRealTimeNewsFeedWebPartProps.ts
new file mode 100644
index 000000000..7e367e721
--- /dev/null
+++ b/samples/react-socket-io/client/src/webparts/realTimeNewsFeed/IRealTimeNewsFeedWebPartProps.ts
@@ -0,0 +1,3 @@
+export interface IRealTimeNewsFeedWebPartProps {
+ listTitle: string;
+}
diff --git a/samples/react-socket-io/client/src/webparts/realTimeNewsFeed/MockHttpClient.ts b/samples/react-socket-io/client/src/webparts/realTimeNewsFeed/MockHttpClient.ts
new file mode 100644
index 000000000..2918c69bc
--- /dev/null
+++ b/samples/react-socket-io/client/src/webparts/realTimeNewsFeed/MockHttpClient.ts
@@ -0,0 +1,30 @@
+import { INewsItem } from './RealTimeNewsFeedWebPart';
+
+export default class MockHttpClient {
+
+ private static _items: INewsItem[] = [
+ { Title: 'News Item 1',
+ Id: 1,
+ Description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
+ PreviewImageUrl: { Url:'http://placehold.it/50x50', Description: "Dummy placeholder" }
+ },
+ { Title: 'News Item 2',
+ Id: 1,
+ Description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
+ PreviewImageUrl: { Url:'http://placehold.it/50x50', Description: "Dummy placeholder" }
+ },
+ { Title: 'News Item 2',
+ Id: 1,
+ Description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
+ PreviewImageUrl: { Url:'http://placehold.it/50x50', Description: "Dummy placeholder" }
+ }
+ ];
+
+ public static get(restUrl: string): Promise {
+ return new Promise((resolve) => {
+ setTimeout(()=> {
+ resolve(MockHttpClient._items);
+ }, 3000);
+ });
+ }
+}
\ No newline at end of file
diff --git a/samples/react-socket-io/client/src/webparts/realTimeNewsFeed/RealTimeNewsFeed.module.scss b/samples/react-socket-io/client/src/webparts/realTimeNewsFeed/RealTimeNewsFeed.module.scss
new file mode 100644
index 000000000..ab0d96ca5
--- /dev/null
+++ b/samples/react-socket-io/client/src/webparts/realTimeNewsFeed/RealTimeNewsFeed.module.scss
@@ -0,0 +1,105 @@
+.ms-newsFeed-itemCell {
+ min-height: 54px;
+ padding: 10px;
+ box-sizing: border-box;
+ border-bottom: 1px solid #eaeaea;
+ display: -webkit-box;
+ display: -ms-flexbox;
+ display: flex;
+ &::-moz-focus-inner {
+ border: 0;
+ }
+ outline: transparent;
+ position: relative;
+}
+
+.ms-Fabric.is-focusVisible .ms-newsFeed-itemCell:focus:after {
+ content: '';
+ position: absolute;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ pointer-events: none;
+ border: 1px solid #666666;
+}
+
+.ms-newsFeed-itemCell:hover {
+ background: #EEE;
+}
+
+.ms-newsFeed-itemImage {
+ -ms-flex-negative: 0;
+ flex-shrink: 0;
+}
+
+.ms-newsFeed-itemContent {
+ overflow: hidden;
+ -webkit-box-flex: 1;
+ -ms-flex-positive: 1;
+ flex-grow: 1;
+}
+
+html {
+ &[dir=ltr] .ms-newsFeed-itemContent {
+ margin-left: 10px;
+ }
+ &[dir=rtl] .ms-newsFeed-itemContent {
+ margin-right: 10px;
+ }
+}
+
+.ms-newsFeed-itemName {
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.ms-newsFeed-itemIndex {
+ font-size: 12px;
+ color: #a6a6a6;
+ margin-bottom: 10px;
+}
+
+.ms-newsFeed-chevron {
+ -ms-flex-item-align: center;
+ align-self: center;
+ color: #a6a6a6;
+ font-size: 17px;
+ -ms-flex-negative: 0;
+ flex-shrink: 0;
+}
+
+html {
+ &[dir=ltr] .ms-newsFeed-chevron {
+ margin-left: 10px;
+ }
+ &[dir=rtl] .ms-newsFeed-chevron {
+ margin-right: 10px;
+ }
+}
+
+.ms-notificationCallout-callout {
+ max-width: 300px;
+}
+
+.ms-notificationCallout-inner {
+ height: 100%;
+ padding: 10px;
+}
+
+.ms-notificationCallout-subText {
+ margin: 0;
+ font-family: "Segoe UI WestEuropean","Segoe UI",-apple-system,BlinkMacSystemFont,Roboto,"Helvetica Neue",sans-serif;
+ -webkit-font-smoothing: antialiased;
+ font-size: 12px;
+ font-weight: 400;
+ color: #333333;
+ font-weight: 300;
+}
+
+.center {
+ display: table;
+ margin: 0 auto;
+}
+
diff --git a/samples/react-socket-io/client/src/webparts/realTimeNewsFeed/RealTimeNewsFeedWebPart.manifest.json b/samples/react-socket-io/client/src/webparts/realTimeNewsFeed/RealTimeNewsFeedWebPart.manifest.json
new file mode 100644
index 000000000..d03b528fe
--- /dev/null
+++ b/samples/react-socket-io/client/src/webparts/realTimeNewsFeed/RealTimeNewsFeedWebPart.manifest.json
@@ -0,0 +1,19 @@
+{
+ "$schema": "../../../node_modules/@microsoft/sp-module-interfaces/lib/manifestSchemas/jsonSchemas/clientSideComponentManifestSchema.json",
+
+ "id": "bd6bb470-57d5-4061-88f9-58d25d095f73",
+ "componentType": "WebPart",
+ "version": "0.0.1",
+ "manifestVersion": 2,
+
+ "preconfiguredEntries": [{
+ "groupId": "bd6bb470-57d5-4061-88f9-58d25d095f73",
+ "group": { "default": "SPFx Demo" },
+ "title": { "default": "RealTimeNewsFeed" },
+ "description": { "default": "A real time SharePoint news feed using Socket IO, Azure Service Bus and Microsoft Flow" },
+ "officeFabricIconFontName": "Page",
+ "properties": {
+ "listTitle": "NewsList"
+ }
+ }]
+}
diff --git a/samples/react-socket-io/client/src/webparts/realTimeNewsFeed/RealTimeNewsFeedWebPart.ts b/samples/react-socket-io/client/src/webparts/realTimeNewsFeed/RealTimeNewsFeedWebPart.ts
new file mode 100644
index 000000000..bbc0eaa07
--- /dev/null
+++ b/samples/react-socket-io/client/src/webparts/realTimeNewsFeed/RealTimeNewsFeedWebPart.ts
@@ -0,0 +1,63 @@
+import * as React from 'react';
+import * as ReactDom from 'react-dom';
+import {
+ BaseClientSideWebPart,
+ IPropertyPaneSettings,
+ IWebPartContext,
+ PropertyPaneTextField
+} from '@microsoft/sp-client-preview';
+
+import * as strings from 'realTimeNewsFeedStrings';
+import RealTimeNewsFeed, { IRealTimeNewsFeedProps } from './components/RealTimeNewsFeed';
+import { IRealTimeNewsFeedWebPartProps } from './IRealTimeNewsFeedWebPartProps';
+
+// Corresponds to the SharePoint site column internal names for a news item
+export interface INewsItem {
+ Title: string;
+ Id: number;
+ Description: string,
+ PreviewImageUrl: any
+}
+
+export interface IList {
+ Title: string;
+}
+
+export default class RealTimeNewsFeedWebPart extends BaseClientSideWebPart {
+
+ public constructor(context: IWebPartContext) {
+ super(context);
+ }
+
+ public render(): void {
+ const element: React.ReactElement = React.createElement(RealTimeNewsFeed, {
+ listTitle: this.properties.listTitle,
+ environmentType: this.context.environment.type,
+ siteUrl: this.context.pageContext.web.absoluteUrl,
+ });
+
+ ReactDom.render(element, this.domElement);
+ }
+
+ protected get propertyPaneSettings(): IPropertyPaneSettings {
+ return {
+ pages: [
+ {
+ header: {
+ description: strings.PropertyPaneDescription
+ },
+ groups: [
+ {
+ groupName: strings.BasicGroupName,
+ groupFields: [
+ PropertyPaneTextField('listTitle', {
+ label: strings.ListTitleFieldLabel
+ })
+ ]
+ }
+ ]
+ }
+ ]
+ };
+ }
+}
diff --git a/samples/react-socket-io/client/src/webparts/realTimeNewsFeed/components/RealTimeNewsFeed.tsx b/samples/react-socket-io/client/src/webparts/realTimeNewsFeed/components/RealTimeNewsFeed.tsx
new file mode 100644
index 000000000..6e8c148d8
--- /dev/null
+++ b/samples/react-socket-io/client/src/webparts/realTimeNewsFeed/components/RealTimeNewsFeed.tsx
@@ -0,0 +1,260 @@
+import * as React from 'react';
+import styles from '../RealTimeNewsFeed.module.scss';
+import { IRealTimeNewsFeedWebPartProps } from '../IRealTimeNewsFeedWebPartProps';
+import { INewsItem } from '../RealTimeNewsFeedWebPart';
+import {
+ Spinner,
+ Link,
+ MessageBar,
+ MessageBarType,
+ FocusZone,
+ FocusZoneDirection,
+ Image,
+ ImageFit,
+ List,
+ Callout,
+ DirectionalHint, } from 'office-ui-fabric-react';
+import MockHttpClient from '../MockHttpClient';
+import { EnvironmentType } from '@microsoft/sp-client-base';
+import { Web } from 'sp-pnp-js';
+import * as io from 'socket.io-client';
+import * as _ from 'lodash';
+import * as pluralize from 'pluralize';
+
+const update = require("react-addons-update");
+
+export interface IRealTimeNewsFeedProps extends IRealTimeNewsFeedWebPartProps {
+ environmentType: EnvironmentType;
+ siteUrl: string;
+ listTitle: string;
+}
+
+export interface IRealTimeNewsFeedState {
+ items?: INewsItem[];
+ addedItems?: string[];
+ error?: boolean;
+ loading?: boolean;
+}
+
+export default class RealTimeNewsFeed extends React.Component {
+
+ private _listElement: HTMLElement;
+
+ constructor(props: IRealTimeNewsFeedProps) {
+ super(props);
+
+ // Equals to getInitialState
+ this.state = {
+ items: [],
+ addedItems: [],
+ error: false,
+ loading: true
+ };
+
+ // Define event handlers
+ this._onItemAdded = this._onItemAdded.bind(this);
+ this._getAvailableItemsAsync = this._getAvailableItemsAsync.bind(this);
+ }
+
+ public componentDidMount(): void {
+
+ // Connect to the server
+ const socket = io("https://SPFxSocketIOWebAppdde17113-805a-4806-b5e6-43dbb5f61b9f.azurewebsites.net");
+
+ // Add the socket io listeners
+ socket.on('item:added', (data) => {
+ this._onItemAdded(data.customProperties.id);
+ });
+
+ // Fetch initial data
+ this._getItemsAsync();
+ }
+
+ public componentWillReceiveProps(): void {
+
+ // Invoked when a property is updated is the Web Part property panel
+ this._getItemsAsync();
+ }
+
+ public render(): JSX.Element {
+
+ let newItemNotification: JSX.Element = null;
+
+ if (this.state.addedItems.length > 0 ) {
+
+ newItemNotification =
+
+
+
+
+
+ { this.state.addedItems.length } new { pluralize("item", this.state.addedItems.length)} available
+
+
+
+ ;
+ }
+
+ const loading: JSX.Element = this.state.loading ? :
;
+
+ const newsList: JSX.Element =
+
+
+ this._listElement = listElementAnchor } >
+ (
+
+
+
+
{ item.Title }
+
{ `Item ${ index }` }
+
{ item.Description }
+
+
+ ) }
+ />
+
;
+
+ const error: JSX.Element = this.state.error ?
+ { this.state.error } :
;
+
+ return (
+
+ {error}
+ {newItemNotification}
+
+ {loading}
+
+ {newsList}
+
+ );
+ }
+
+ /* Event Handlers */
+ private _onItemAdded(id: string): void {
+
+ // Check if the id is not present in current displayed items
+ if(!_(this.state.items).find((e) => {return e.Id === parseInt(id);})) {
+
+ let updatedItems = this.state.addedItems;
+ updatedItems.push(id);
+
+ this.setState({
+ addedItems: updatedItems
+ });
+ }
+ }
+
+ /* Async functions */
+ private _getItemsAsync(): void {
+
+ // Local environment
+ if (this.props.environmentType === EnvironmentType.Local) {
+ this._getMockedNewsItems().then((response) => {
+ this.setState({
+ items: response,
+ error: null,
+ loading: false
+ });
+ });
+ } else {
+
+ // SharePoint environment (Classic or Modern Page experience)
+ this._getNewsItems()
+ .then((response) => {
+ this.setState({
+ items: response,
+ error: null,
+ loading: false
+ });
+ }).catch((errorMsg) => {
+ this.setState({
+ items: [],
+ error: errorMsg,
+ loading: false
+ });
+ });
+ }
+ }
+
+ private _getAvailableItemsAsync(): void {
+
+ // Local environment
+ if (this.props.environmentType !== EnvironmentType.Local) {
+
+ this.setState({
+ addedItems: [],
+ loading: true
+ });
+
+ const { addedItems } = this.state;
+ let filters: string[] = [];
+
+ // Build the request to get all new items by their ids.
+ _.map(addedItems, (itemId) => {
+
+ filters.push("(Id eq " + itemId + ")");
+ });
+
+ const query = _.join(filters, " or ");
+
+ this._getNewsItems(query).then((items) => {
+
+ // Add items to the state
+ let updatedItems = update(this.state.items, {$unshift: items.reverse()});
+
+ this.setState({
+ items: updatedItems,
+ loading: false
+ });
+
+ }).catch((errorMsg) => {
+
+ this.setState({
+ error: errorMsg,
+ loading: false
+ });
+ });
+ }
+ }
+
+ private _getMockedNewsItems(): Promise {
+ return MockHttpClient.get(this.props.siteUrl)
+ .then((data: INewsItem[]) => {
+ return data;
+ }) as Promise;
+ }
+
+ private _getNewsItems(filterQuery: string = ""): Promise {
+
+ const p = new Promise((resolve, reject) => {
+
+ let web = new Web(this.props.siteUrl);
+
+ web.lists.getByTitle(this.props.listTitle).items.filter(filterQuery).orderBy("Created", false).get().then((items)=> {
+
+ resolve(items as INewsItem[]);
+
+ }).catch((errorMsg) => {
+
+ reject(errorMsg);
+
+ });
+
+ });
+
+ return p;
+ }
+}
diff --git a/samples/react-socket-io/client/src/webparts/realTimeNewsFeed/loc/en-us.js b/samples/react-socket-io/client/src/webparts/realTimeNewsFeed/loc/en-us.js
new file mode 100644
index 000000000..9464b983c
--- /dev/null
+++ b/samples/react-socket-io/client/src/webparts/realTimeNewsFeed/loc/en-us.js
@@ -0,0 +1,7 @@
+define([], function() {
+ return {
+ "PropertyPaneDescription": "Web Part configuration",
+ "BasicGroupName": "Miscellaneous",
+ "ListTitleFieldLabel": "List Title"
+ }
+});
\ No newline at end of file
diff --git a/samples/react-socket-io/client/src/webparts/realTimeNewsFeed/loc/mystrings.d.ts b/samples/react-socket-io/client/src/webparts/realTimeNewsFeed/loc/mystrings.d.ts
new file mode 100644
index 000000000..5a689ae17
--- /dev/null
+++ b/samples/react-socket-io/client/src/webparts/realTimeNewsFeed/loc/mystrings.d.ts
@@ -0,0 +1,10 @@
+declare interface IRealTimeNewsFeedStrings {
+ PropertyPaneDescription: string;
+ BasicGroupName: string;
+ ListTitleFieldLabel: string;
+}
+
+declare module 'realTimeNewsFeedStrings' {
+ const strings: IRealTimeNewsFeedStrings;
+ export = strings;
+}
diff --git a/samples/react-socket-io/client/src/webparts/realTimeNewsFeed/tests/RealTimeNewsFeed.test.ts b/samples/react-socket-io/client/src/webparts/realTimeNewsFeed/tests/RealTimeNewsFeed.test.ts
new file mode 100644
index 000000000..f18ebcd78
--- /dev/null
+++ b/samples/react-socket-io/client/src/webparts/realTimeNewsFeed/tests/RealTimeNewsFeed.test.ts
@@ -0,0 +1,7 @@
+import * as assert from 'assert';
+
+describe('RealTimeNewsFeedWebPart', () => {
+ it('should do something', () => {
+ assert.ok(true);
+ });
+});
diff --git a/samples/react-socket-io/client/tsconfig.json b/samples/react-socket-io/client/tsconfig.json
new file mode 100644
index 000000000..98c8662a9
--- /dev/null
+++ b/samples/react-socket-io/client/tsconfig.json
@@ -0,0 +1,9 @@
+{
+ "compilerOptions": {
+ "target": "es5",
+ "module": "commonjs",
+ "jsx": "react",
+ "declaration": true,
+ "sourceMap": true
+ }
+}
diff --git a/samples/react-socket-io/client/typings/@ms/odsp-webpack.d.ts b/samples/react-socket-io/client/typings/@ms/odsp-webpack.d.ts
new file mode 100644
index 000000000..f2b3b03df
--- /dev/null
+++ b/samples/react-socket-io/client/typings/@ms/odsp-webpack.d.ts
@@ -0,0 +1,13 @@
+// Type definitions for webpack in Microsoft ODSP projects
+// Project: ODSP-WEBPACK
+
+/*
+ * This definition of webpack require overrides all other definitions of require in our toolchain
+ * Make sure all other definitions of require are commented out e.g. in node.d.ts
+ */
+declare var require: {
+ (path: string): any;
+ (paths: string[], callback: (...modules: any[]) => void): void;
+ resolve: (id: string) => string;
+ ensure: (paths: string[], callback: (require: (path: string) => T) => void, path: string) => void;
+};
\ No newline at end of file
diff --git a/samples/react-socket-io/client/typings/@ms/odsp.d.ts b/samples/react-socket-io/client/typings/@ms/odsp.d.ts
new file mode 100644
index 000000000..ae3334fe0
--- /dev/null
+++ b/samples/react-socket-io/client/typings/@ms/odsp.d.ts
@@ -0,0 +1,10 @@
+// Type definitions for Microsoft ODSP projects
+// Project: ODSP
+
+///
+
+/* Global definition for DEBUG builds */
+declare const DEBUG: boolean;
+
+/* Global definition for UNIT_TEST builds */
+declare const UNIT_TEST: boolean;
\ No newline at end of file
diff --git a/samples/react-socket-io/client/typings/assertion-error/assertion-error.d.ts b/samples/react-socket-io/client/typings/assertion-error/assertion-error.d.ts
new file mode 100644
index 000000000..08217c9e5
--- /dev/null
+++ b/samples/react-socket-io/client/typings/assertion-error/assertion-error.d.ts
@@ -0,0 +1,15 @@
+// Type definitions for assertion-error 1.0.0
+// Project: https://github.com/chaijs/assertion-error
+// Definitions by: Bart van der Schoor
+// Definitions: https://github.com/borisyankov/DefinitelyTyped
+
+declare module 'assertion-error' {
+ class AssertionError implements Error {
+ constructor(message: string, props?: any, ssf?: Function);
+ name: string;
+ message: string;
+ showDiff: boolean;
+ stack: string;
+ }
+ export = AssertionError;
+}
diff --git a/samples/react-socket-io/client/typings/chai/chai.d.ts b/samples/react-socket-io/client/typings/chai/chai.d.ts
new file mode 100644
index 000000000..da4d718e1
--- /dev/null
+++ b/samples/react-socket-io/client/typings/chai/chai.d.ts
@@ -0,0 +1,388 @@
+// Type definitions for chai 3.2.0
+// Project: http://chaijs.com/
+// Definitions by: Jed Mao ,
+// Bart van der Schoor ,
+// Andrew Brown ,
+// Olivier Chevet
+// Definitions: https://github.com/borisyankov/DefinitelyTyped
+
+//
+
+declare module Chai {
+
+ interface ChaiStatic {
+ expect: ExpectStatic;
+ should(): Should;
+ /**
+ * Provides a way to extend the internals of Chai
+ */
+ use(fn: (chai: any, utils: any) => void): any;
+ assert: AssertStatic;
+ config: Config;
+ AssertionError: AssertionError;
+ }
+
+ export interface ExpectStatic extends AssertionStatic {
+ fail(actual?: any, expected?: any, message?: string, operator?: string): void;
+ }
+
+ export interface AssertStatic extends Assert {
+ }
+
+ export interface AssertionStatic {
+ (target: any, message?: string): Assertion;
+ }
+
+ interface ShouldAssertion {
+ equal(value1: any, value2: any, message?: string): void;
+ Throw: ShouldThrow;
+ throw: ShouldThrow;
+ exist(value: any, message?: string): void;
+ }
+
+ interface Should extends ShouldAssertion {
+ not: ShouldAssertion;
+ fail(actual: any, expected: any, message?: string, operator?: string): void;
+ }
+
+ interface ShouldThrow {
+ (actual: Function): void;
+ (actual: Function, expected: string|RegExp, message?: string): void;
+ (actual: Function, constructor: Error|Function, expected?: string|RegExp, message?: string): void;
+ }
+
+ interface Assertion extends LanguageChains, NumericComparison, TypeComparison {
+ not: Assertion;
+ deep: Deep;
+ any: KeyFilter;
+ all: KeyFilter;
+ a: TypeComparison;
+ an: TypeComparison;
+ include: Include;
+ includes: Include;
+ contain: Include;
+ contains: Include;
+ ok: Assertion;
+ true: Assertion;
+ false: Assertion;
+ null: Assertion;
+ undefined: Assertion;
+ NaN: Assertion;
+ exist: Assertion;
+ empty: Assertion;
+ arguments: Assertion;
+ Arguments: Assertion;
+ equal: Equal;
+ equals: Equal;
+ eq: Equal;
+ eql: Equal;
+ eqls: Equal;
+ property: Property;
+ ownProperty: OwnProperty;
+ haveOwnProperty: OwnProperty;
+ ownPropertyDescriptor: OwnPropertyDescriptor;
+ haveOwnPropertyDescriptor: OwnPropertyDescriptor;
+ length: Length;
+ lengthOf: Length;
+ match: Match;
+ matches: Match;
+ string(string: string, message?: string): Assertion;
+ keys: Keys;
+ key(string: string): Assertion;
+ throw: Throw;
+ throws: Throw;
+ Throw: Throw;
+ respondTo: RespondTo;
+ respondsTo: RespondTo;
+ itself: Assertion;
+ satisfy: Satisfy;
+ satisfies: Satisfy;
+ closeTo(expected: number, delta: number, message?: string): Assertion;
+ members: Members;
+ increase: PropertyChange;
+ increases: PropertyChange;
+ decrease: PropertyChange;
+ decreases: PropertyChange;
+ change: PropertyChange;
+ changes: PropertyChange;
+ extensible: Assertion;
+ sealed: Assertion;
+ frozen: Assertion;
+
+ }
+
+ interface LanguageChains {
+ to: Assertion;
+ be: Assertion;
+ been: Assertion;
+ is: Assertion;
+ that: Assertion;
+ which: Assertion;
+ and: Assertion;
+ has: Assertion;
+ have: Assertion;
+ with: Assertion;
+ at: Assertion;
+ of: Assertion;
+ same: Assertion;
+ }
+
+ interface NumericComparison {
+ above: NumberComparer;
+ gt: NumberComparer;
+ greaterThan: NumberComparer;
+ least: NumberComparer;
+ gte: NumberComparer;
+ below: NumberComparer;
+ lt: NumberComparer;
+ lessThan: NumberComparer;
+ most: NumberComparer;
+ lte: NumberComparer;
+ within(start: number, finish: number, message?: string): Assertion;
+ }
+
+ interface NumberComparer {
+ (value: number, message?: string): Assertion;
+ }
+
+ interface TypeComparison {
+ (type: string, message?: string): Assertion;
+ instanceof: InstanceOf;
+ instanceOf: InstanceOf;
+ }
+
+ interface InstanceOf {
+ (constructor: Object, message?: string): Assertion;
+ }
+
+ interface Deep {
+ equal: Equal;
+ include: Include;
+ property: Property;
+ members: Members;
+ }
+
+ interface KeyFilter {
+ keys: Keys;
+ }
+
+ interface Equal {
+ (value: any, message?: string): Assertion;
+ }
+
+ interface Property {
+ (name: string, value?: any, message?: string): Assertion;
+ }
+
+ interface OwnProperty {
+ (name: string, message?: string): Assertion;
+ }
+
+ interface OwnPropertyDescriptor {
+ (name: string, descriptor: PropertyDescriptor, message?: string): Assertion;
+ (name: string, message?: string): Assertion;
+ }
+
+ interface Length extends LanguageChains, NumericComparison {
+ (length: number, message?: string): Assertion;
+ }
+
+ interface Include {
+ (value: Object, message?: string): Assertion;
+ (value: string, message?: string): Assertion;
+ (value: number, message?: string): Assertion;
+ keys: Keys;
+ members: Members;
+ any: KeyFilter;
+ all: KeyFilter;
+ }
+
+ interface Match {
+ (regexp: RegExp|string, message?: string): Assertion;
+ }
+
+ interface Keys {
+ (...keys: string[]): Assertion;
+ (keys: any[]): Assertion;
+ (keys: Object): Assertion;
+ }
+
+ interface Throw {
+ (): Assertion;
+ (expected: string, message?: string): Assertion;
+ (expected: RegExp, message?: string): Assertion;
+ (constructor: Error, expected?: string, message?: string): Assertion;
+ (constructor: Error, expected?: RegExp, message?: string): Assertion;
+ (constructor: Function, expected?: string, message?: string): Assertion;
+ (constructor: Function, expected?: RegExp, message?: string): Assertion;
+ }
+
+ interface RespondTo {
+ (method: string, message?: string): Assertion;
+ }
+
+ interface Satisfy {
+ (matcher: Function, message?: string): Assertion;
+ }
+
+ interface Members {
+ (set: any[], message?: string): Assertion;
+ }
+
+ interface PropertyChange {
+ (object: Object, prop: string, msg?: string): Assertion;
+ }
+
+ export interface Assert {
+ /**
+ * @param expression Expression to test for truthiness.
+ * @param message Message to display on error.
+ */
+ (expression: any, message?: string): void;
+
+ fail(actual?: any, expected?: any, msg?: string, operator?: string): void;
+
+ ok(val: any, msg?: string): void;
+ isOk(val: any, msg?: string): void;
+ notOk(val: any, msg?: string): void;
+ isNotOk(val: any, msg?: string): void;
+
+ equal(act: any, exp: any, msg?: string): void;
+ notEqual(act: any, exp: any, msg?: string): void;
+
+ strictEqual(act: any, exp: any, msg?: string): void;
+ notStrictEqual(act: any, exp: any, msg?: string): void;
+
+ deepEqual(act: any, exp: any, msg?: string): void;
+ notDeepEqual(act: any, exp: any, msg?: string): void;
+
+ isTrue(val: any, msg?: string): void;
+ isFalse(val: any, msg?: string): void;
+
+ isNull(val: any, msg?: string): void;
+ isNotNull(val: any, msg?: string): void;
+
+ isUndefined(val: any, msg?: string): void;
+ isDefined(val: any, msg?: string): void;
+
+ isNaN(val: any, msg?: string): void;
+ isNotNaN(val: any, msg?: string): void;
+
+ isAbove(val: number, abv: number, msg?: string): void;
+ isBelow(val: number, blw: number, msg?: string): void;
+
+ isFunction(val: any, msg?: string): void;
+ isNotFunction(val: any, msg?: string): void;
+
+ isObject(val: any, msg?: string): void;
+ isNotObject(val: any, msg?: string): void;
+
+ isArray(val: any, msg?: string): void;
+ isNotArray(val: any, msg?: string): void;
+
+ isString(val: any, msg?: string): void;
+ isNotString(val: any, msg?: string): void;
+
+ isNumber(val: any, msg?: string): void;
+ isNotNumber(val: any, msg?: string): void;
+
+ isBoolean(val: any, msg?: string): void;
+ isNotBoolean(val: any, msg?: string): void;
+
+ typeOf(val: any, type: string, msg?: string): void;
+ notTypeOf(val: any, type: string, msg?: string): void;
+
+ instanceOf(val: any, type: Function, msg?: string): void;
+ notInstanceOf(val: any, type: Function, msg?: string): void;
+
+ include(exp: string, inc: any, msg?: string): void;
+ include(exp: any[], inc: any, msg?: string): void;
+
+ notInclude(exp: string, inc: any, msg?: string): void;
+ notInclude(exp: any[], inc: any, msg?: string): void;
+
+ match(exp: any, re: RegExp, msg?: string): void;
+ notMatch(exp: any, re: RegExp, msg?: string): void;
+
+ property(obj: Object, prop: string, msg?: string): void;
+ notProperty(obj: Object, prop: string, msg?: string): void;
+ deepProperty(obj: Object, prop: string, msg?: string): void;
+ notDeepProperty(obj: Object, prop: string, msg?: string): void;
+
+ propertyVal(obj: Object, prop: string, val: any, msg?: string): void;
+ propertyNotVal(obj: Object, prop: string, val: any, msg?: string): void;
+
+ deepPropertyVal(obj: Object, prop: string, val: any, msg?: string): void;
+ deepPropertyNotVal(obj: Object, prop: string, val: any, msg?: string): void;
+
+ lengthOf(exp: any, len: number, msg?: string): void;
+ //alias frenzy
+ throw(fn: Function, msg?: string): void;
+ throw(fn: Function, regExp: RegExp): void;
+ throw(fn: Function, errType: Function, msg?: string): void;
+ throw(fn: Function, errType: Function, regExp: RegExp): void;
+
+ throws(fn: Function, msg?: string): void;
+ throws(fn: Function, regExp: RegExp): void;
+ throws(fn: Function, errType: Function, msg?: string): void;
+ throws(fn: Function, errType: Function, regExp: RegExp): void;
+
+ Throw(fn: Function, msg?: string): void;
+ Throw(fn: Function, regExp: RegExp): void;
+ Throw(fn: Function, errType: Function, msg?: string): void;
+ Throw(fn: Function, errType: Function, regExp: RegExp): void;
+
+ doesNotThrow(fn: Function, msg?: string): void;
+ doesNotThrow(fn: Function, regExp: RegExp): void;
+ doesNotThrow(fn: Function, errType: Function, msg?: string): void;
+ doesNotThrow(fn: Function, errType: Function, regExp: RegExp): void;
+
+ operator(val: any, operator: string, val2: any, msg?: string): void;
+ closeTo(act: number, exp: number, delta: number, msg?: string): void;
+
+ sameMembers(set1: any[], set2: any[], msg?: string): void;
+ sameDeepMembers(set1: any[], set2: any[], msg?: string): void;
+ includeMembers(superset: any[], subset: any[], msg?: string): void;
+
+ ifError(val: any, msg?: string): void;
+
+ isExtensible(obj: {}, msg?: string): void;
+ extensible(obj: {}, msg?: string): void;
+ isNotExtensible(obj: {}, msg?: string): void;
+ notExtensible(obj: {}, msg?: string): void;
+
+ isSealed(obj: {}, msg?: string): void;
+ sealed(obj: {}, msg?: string): void;
+ isNotSealed(obj: {}, msg?: string): void;
+ notSealed(obj: {}, msg?: string): void;
+
+ isFrozen(obj: Object, msg?: string): void;
+ frozen(obj: Object, msg?: string): void;
+ isNotFrozen(obj: Object, msg?: string): void;
+ notFrozen(obj: Object, msg?: string): void;
+
+
+ }
+
+ export interface Config {
+ includeStack: boolean;
+ }
+
+ export class AssertionError {
+ constructor(message: string, _props?: any, ssf?: Function);
+ name: string;
+ message: string;
+ showDiff: boolean;
+ stack: string;
+ }
+}
+
+declare var chai: Chai.ChaiStatic;
+
+declare module "chai" {
+ export = chai;
+}
+
+interface Object {
+ should: Chai.Assertion;
+}
diff --git a/samples/react-socket-io/client/typings/combokeys/combokeys.d.ts b/samples/react-socket-io/client/typings/combokeys/combokeys.d.ts
new file mode 100644
index 000000000..f7e1e5b03
--- /dev/null
+++ b/samples/react-socket-io/client/typings/combokeys/combokeys.d.ts
@@ -0,0 +1,107 @@
+// Type definitions for Combokeys v2.4.6
+// Project: https://github.com/PolicyStat/combokeys
+// Definitions by: Ian Clanton-Thuon
+// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
+
+declare namespace Combokeys {
+ interface CombokeysStatic {
+ new (element: Element): Combokeys;
+
+ /**
+ * all instances of Combokeys
+ */
+ instances: Combokeys[];
+
+ /**
+ * reset all instances
+ */
+ reset(): void;
+ }
+
+ interface Combokeys {
+ element: Element;
+
+ /**
+ * binds an event to Combokeys
+ *
+ * can be a single key, a combination of keys separated with +,
+ * an array of keys, or a sequence of keys separated by spaces
+ *
+ * be sure to list the modifier keys first to make sure that the
+ * correct key ends up getting bound (the last key in the pattern)
+ *
+ * @param {keys} key combination or combinations
+ * @param {callback} callback function
+ * @param {handler} optional - one of "keypress", "keydown", or "keyup"
+ * @returns void
+ */
+ bind(keys: string | string[], callback: () => void, action?: string): void;
+
+
+ /**
+ * binds multiple combinations to the same callback
+ *
+ * @param {keys} key combinations
+ * @param {callback} callback function
+ * @param {handler} optional - one of "keypress", "keydown", or "keyup"
+ * @returns void
+ */
+ bindMultiple(keys: string[], callback: () => void, action?: string): void;
+
+ /**
+ * unbinds an event to Combokeys
+ *
+ * the unbinding sets the callback function of the specified key combo
+ * to an empty function and deletes the corresponding key in the
+ * directMap dict.
+ *
+ * the keycombo+action has to be exactly the same as
+ * it was defined in the bind method
+ *
+ * @param {keys} key combination or combinations
+ * @param {action} optional - one of "keypress", "keydown", or "keyup"
+ * @returns void
+ */
+ unbind(keys: string | string[], action?: string): void;
+
+ /**
+ * triggers an event that has already been bound
+ *
+ * @param {keys} key combination
+ * @param {action} optional - one of "keypress", "keydown", or "keyup"
+ * @returns void
+ */
+ trigger(keys: string, action?: string): void;
+
+ /**
+ * resets the library back to its initial state. This is useful
+ * if you want to clear out the current keyboard shortcuts and bind
+ * new ones - for example if you switch to another page
+ *
+ * @returns void
+ */
+ reset(): void;
+
+ /**
+ * should we stop this event before firing off callbacks
+ *
+ * @param {e} event
+ * @param {element} bound element
+ * @return {boolean}
+ */
+ stopCallback(e: Event, element: Element): boolean;
+
+ /**
+ * detach all listners from the bound element
+ *
+ * @return {void}
+ */
+ detach(): void;
+ }
+}
+
+declare var combokeys: Combokeys.CombokeysStatic;
+
+declare module "combokeys" {
+ export = combokeys;
+}
diff --git a/samples/react-socket-io/client/typings/es6-collections/es6-collections.d.ts b/samples/react-socket-io/client/typings/es6-collections/es6-collections.d.ts
new file mode 100644
index 000000000..bc39df295
--- /dev/null
+++ b/samples/react-socket-io/client/typings/es6-collections/es6-collections.d.ts
@@ -0,0 +1,113 @@
+// Type definitions for es6-collections v0.5.1
+// Project: https://github.com/WebReflection/es6-collections/
+// Definitions by: Ron Buckton
+// Definitions: https://github.com/borisyankov/DefinitelyTyped
+
+/* *****************************************************************************
+Copyright (c) Microsoft Corporation. All rights reserved.
+Licensed under the Apache License, Version 2.0 (the "License"); you may not use
+this file except in compliance with the License. You may obtain a copy of the
+License at http://www.apache.org/licenses/LICENSE-2.0
+
+THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
+WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
+MERCHANTABLITY OR NON-INFRINGEMENT.
+
+See the Apache Version 2.0 License for specific language governing permissions
+and limitations under the License.
+***************************************************************************** */
+
+interface IteratorResult {
+ done: boolean;
+ value?: T;
+}
+
+interface Iterator {
+ next(value?: any): IteratorResult;
+ return?(value?: any): IteratorResult;
+ throw?(e?: any): IteratorResult;
+}
+
+interface ForEachable {
+ forEach(callbackfn: (value: T) => void): void;
+}
+
+interface Map {
+ clear(): void;
+ delete(key: K): boolean;
+ forEach(callbackfn: (value: V, index: K, map: Map) => void, thisArg?: any): void;
+ get(key: K): V;
+ has(key: K): boolean;
+ set(key: K, value?: V): Map;
+ entries(): Iterator<[K, V]>;
+ keys(): Iterator;
+ values(): Iterator;
+ size: number;
+}
+
+interface MapConstructor {
+ new (): Map;
+ new (iterable: ForEachable<[K, V]>): Map;
+ prototype: Map;
+}
+
+declare var Map: MapConstructor;
+
+interface Set {
+ add(value: T): Set;
+ clear(): void;
+ delete(value: T): boolean;
+ forEach(callbackfn: (value: T, index: T, set: Set) => void, thisArg?: any): void;
+ has(value: T): boolean;
+ entries(): Iterator<[T, T]>;
+ keys(): Iterator;
+ values(): Iterator;
+ size: number;
+}
+
+interface SetConstructor {
+ new (): Set;
+ new (iterable: ForEachable): Set;
+ prototype: Set;
+}
+
+declare var Set: SetConstructor;
+
+interface WeakMap {
+ delete(key: K): boolean;
+ clear(): void;
+ get(key: K): V;
+ has(key: K): boolean;
+ set(key: K, value?: V): WeakMap;
+}
+
+interface WeakMapConstructor {
+ new (): WeakMap;
+ new (iterable: ForEachable<[K, V]>): WeakMap;
+ prototype: WeakMap;
+}
+
+declare var WeakMap: WeakMapConstructor;
+
+interface WeakSet {
+ delete(value: T): boolean;
+ clear(): void;
+ add(value: T): WeakSet;
+ has(value: T): boolean;
+}
+
+interface WeakSetConstructor {
+ new (): WeakSet;
+ new (iterable: ForEachable): WeakSet;
+ prototype: WeakSet;
+}
+
+declare var WeakSet: WeakSetConstructor;
+
+declare module "es6-collections" {
+ var Map: MapConstructor;
+ var Set: SetConstructor;
+ var WeakMap: WeakMapConstructor;
+ var WeakSet: WeakSetConstructor;
+}
\ No newline at end of file
diff --git a/samples/react-socket-io/client/typings/knockout/knockout.d.ts b/samples/react-socket-io/client/typings/knockout/knockout.d.ts
new file mode 100644
index 000000000..267f3174c
--- /dev/null
+++ b/samples/react-socket-io/client/typings/knockout/knockout.d.ts
@@ -0,0 +1,631 @@
+// Type definitions for Knockout v3.2.0
+// Project: http://knockoutjs.com
+// Definitions by: Boris Yankov , Igor Oleinikov , Clément Bourgeois
+// Definitions: https://github.com/borisyankov/DefinitelyTyped
+
+
+interface KnockoutSubscribableFunctions {
+ [key: string]: KnockoutBindingHandler;
+
+ notifySubscribers(valueToWrite?: T, event?: string): void;
+}
+
+interface KnockoutComputedFunctions {
+ [key: string]: KnockoutBindingHandler;
+}
+
+interface KnockoutObservableFunctions {
+ [key: string]: KnockoutBindingHandler;
+
+ equalityComparer(a: any, b: any): boolean;
+}
+
+interface KnockoutObservableArrayFunctions {
+ // General Array functions
+ indexOf(searchElement: T, fromIndex?: number): number;
+ slice(start: number, end?: number): T[];
+ splice(start: number): T[];
+ splice(start: number, deleteCount: number, ...items: T[]): T[];
+ pop(): T;
+ push(...items: T[]): void;
+ shift(): T;
+ unshift(...items: T[]): number;
+ reverse(): KnockoutObservableArray;
+ sort(): KnockoutObservableArray;
+ sort(compareFunction: (left: T, right: T) => number): KnockoutObservableArray;
+
+ // Ko specific
+ [key: string]: KnockoutBindingHandler;
+
+ replace(oldItem: T, newItem: T): void;
+
+ remove(item: T): T[];
+ remove(removeFunction: (item: T) => boolean): T[];
+ removeAll(items: T[]): T[];
+ removeAll(): T[];
+
+ destroy(item: T): void;
+ destroy(destroyFunction: (item: T) => boolean): void;
+ destroyAll(items: T[]): void;
+ destroyAll(): void;
+}
+
+interface KnockoutSubscribableStatic {
+ fn: KnockoutSubscribableFunctions;
+
+ new (): KnockoutSubscribable;
+}
+
+interface KnockoutSubscription {
+ dispose(): void;
+}
+
+interface KnockoutSubscribable extends KnockoutSubscribableFunctions {
+ subscribe(callback: (newValue: T) => void, target?: any, event?: string): KnockoutSubscription;
+ subscribe(callback: (newValue: TEvent) => void, target: any, event: string): KnockoutSubscription;
+ extend(requestedExtenders: { [key: string]: any; }): KnockoutSubscribable;
+ getSubscriptionsCount(): number;
+}
+
+interface KnockoutComputedStatic {
+ fn: KnockoutComputedFunctions;
+
+ (): KnockoutComputed;
+ (func: () => T, context?: any, options?: any): KnockoutComputed;
+ (def: KnockoutComputedDefine, context?: any): KnockoutComputed;
+}
+
+interface KnockoutComputed extends KnockoutObservable, KnockoutComputedFunctions {
+ fn: KnockoutComputedFunctions;
+
+ dispose(): void;
+ isActive(): boolean;
+ getDependenciesCount(): number;
+ extend(requestedExtenders: { [key: string]: any; }): KnockoutComputed;
+}
+
+interface KnockoutObservableArrayStatic {
+ fn: KnockoutObservableArrayFunctions;
+
+ (value?: T[]): KnockoutObservableArray;
+}
+
+interface KnockoutObservableArray extends KnockoutObservable, KnockoutObservableArrayFunctions {
+ extend(requestedExtenders: { [key: string]: any; }): KnockoutObservableArray;
+}
+
+interface KnockoutObservableStatic {
+ fn: KnockoutObservableFunctions;
+
+ (value?: T): KnockoutObservable;
+}
+
+interface KnockoutObservable extends KnockoutSubscribable, KnockoutObservableFunctions {
+ (): T;
+ (value: T): void;
+
+ peek(): T;
+ valueHasMutated?:{(): void;};
+ valueWillMutate?:{(): void;};
+ extend(requestedExtenders: { [key: string]: any; }): KnockoutObservable;
+}
+
+interface KnockoutComputedDefine {
+ read(): T;
+ write? (value: T): void;
+ disposeWhenNodeIsRemoved?: Node;
+ disposeWhen? (): boolean;
+ owner?: any;
+ deferEvaluation?: boolean;
+ pure?: boolean;
+}
+
+interface KnockoutBindingContext {
+ $parent: any;
+ $parents: any[];
+ $root: any;
+ $data: any;
+ $rawData: any | KnockoutObservable;
+ $index?: KnockoutObservable;
+ $parentContext?: KnockoutBindingContext;
+ $component: any;
+ $componentTemplateNodes: Node[];
+
+ extend(properties: any): any;
+ createChildContext(dataItemOrAccessor: any, dataItemAlias?: any, extendCallback?: Function): any;
+}
+
+interface KnockoutAllBindingsAccessor {
+ (): any;
+ get(name: string): any;
+ has(name: string): boolean;
+}
+
+interface KnockoutBindingHandler {
+ after?: Array;
+ init?: (element: any, valueAccessor: () => any, allBindingsAccessor?: KnockoutAllBindingsAccessor, viewModel?: any, bindingContext?: KnockoutBindingContext) => void | { controlsDescendantBindings: boolean; };
+ update?: (element: any, valueAccessor: () => any, allBindingsAccessor?: KnockoutAllBindingsAccessor, viewModel?: any, bindingContext?: KnockoutBindingContext) => void;
+ options?: any;
+ preprocess?: (value: string, name: string, addBindingCallback?: (name: string, value: string) => void) => string;
+}
+
+interface KnockoutBindingHandlers {
+ [bindingHandler: string]: KnockoutBindingHandler;
+
+ // Controlling text and appearance
+ visible: KnockoutBindingHandler;
+ text: KnockoutBindingHandler;
+ html: KnockoutBindingHandler;
+ css: KnockoutBindingHandler;
+ style: KnockoutBindingHandler;
+ attr: KnockoutBindingHandler;
+
+ // Control Flow
+ foreach: KnockoutBindingHandler;
+ if: KnockoutBindingHandler;
+ ifnot: KnockoutBindingHandler;
+ with: KnockoutBindingHandler;
+
+ // Working with form fields
+ click: KnockoutBindingHandler;
+ event: KnockoutBindingHandler;
+ submit: KnockoutBindingHandler;
+ enable: KnockoutBindingHandler;
+ disable: KnockoutBindingHandler;
+ value: KnockoutBindingHandler;
+ textInput: KnockoutBindingHandler;
+ hasfocus: KnockoutBindingHandler;
+ checked: KnockoutBindingHandler;
+ options: KnockoutBindingHandler;
+ selectedOptions: KnockoutBindingHandler;
+ uniqueName: KnockoutBindingHandler;
+
+ // Rendering templates
+ template: KnockoutBindingHandler;
+
+ // Components (new for v3.2)
+ component: KnockoutBindingHandler;
+}
+
+interface KnockoutMemoization {
+ memoize(callback: () => string): string;
+ unmemoize(memoId: string, callbackParams: any[]): boolean;
+ unmemoizeDomNodeAndDescendants(domNode: any, extraCallbackParamsArray: any[]): boolean;
+ parseMemoText(memoText: string): string;
+}
+
+interface KnockoutVirtualElement {}
+
+interface KnockoutVirtualElements {
+ allowedBindings: { [bindingName: string]: boolean; };
+ emptyNode(node: KnockoutVirtualElement ): void;
+ firstChild(node: KnockoutVirtualElement ): KnockoutVirtualElement;
+ insertAfter( container: KnockoutVirtualElement, nodeToInsert: Node, insertAfter: Node ): void;
+ nextSibling(node: KnockoutVirtualElement): Node;
+ prepend(node: KnockoutVirtualElement, toInsert: Node ): void;
+ setDomNodeChildren(node: KnockoutVirtualElement, newChildren: { length: number;[index: number]: Node; } ): void;
+ childNodes(node: KnockoutVirtualElement ): Node[];
+}
+
+interface KnockoutExtenders {
+ throttle(target: any, timeout: number): KnockoutComputed;
+ notify(target: any, notifyWhen: string): any;
+
+ rateLimit(target: any, timeout: number): any;
+ rateLimit(target: any, options: { timeout: number; method?: string; }): any;
+
+ trackArrayChanges(target: any): any;
+}
+
+//
+// NOTE TO MAINTAINERS AND CONTRIBUTORS : pay attention to only include symbols that are
+// publicly exported in the minified version of ko, without that you can give the false
+// impression that some functions will be available in production builds.
+//
+interface KnockoutUtils {
+ //////////////////////////////////
+ // utils.domData.js
+ //////////////////////////////////
+
+ domData: {
+ get (node: Element, key: string): any;
+
+ set (node: Element, key: string, value: any): void;
+
+ getAll(node: Element, createIfNotFound: boolean): any;
+
+ clear(node: Element): boolean;
+ };
+
+ //////////////////////////////////
+ // utils.domNodeDisposal.js
+ //////////////////////////////////
+
+ domNodeDisposal: {
+ addDisposeCallback(node: Element, callback: Function): void;
+
+ removeDisposeCallback(node: Element, callback: Function): void;
+
+ cleanNode(node: Node): Element;
+
+ removeNode(node: Node): void;
+ };
+
+ addOrRemoveItem(array: T[] | KnockoutObservable, value: T, included: T): void;
+
+ arrayFilter(array: T[], predicate: (item: T) => boolean): T[];
+
+ arrayFirst(array: T[], predicate: (item: T) => boolean, predicateOwner?: any): T;
+
+ arrayForEach(array: T[], action: (item: T, index: number) => void): void;
+
+ arrayGetDistinctValues(array: T[]): T[];
+
+ arrayIndexOf(array: T[], item: T): number;
+
+ arrayMap(array: T[], mapping: (item: T) => U): U[];
+
+ arrayPushAll(array: T[] | KnockoutObservableArray, valuesToPush: T[]): T[];
+
+ arrayRemoveItem(array: any[], itemToRemove: any): void;
+
+ compareArrays(a: T[], b: T[]): Array>;
+
+ extend(target: Object, source: Object): Object;
+
+ fieldsIncludedWithJsonPost: any[];
+
+ getFormFields(form: any, fieldName: string): any[];
+
+ objectForEach(obj: any, action: (key: any, value: any) => void): void;
+
+ parseHtmlFragment(html: string): any[];
+
+ parseJson(jsonString: string): any;
+
+ postJson(urlOrForm: any, data: any, options: any): void;
+
+ peekObservable(value: KnockoutObservable): T;
+
+ range(min: any, max: any): any;
+
+ registerEventHandler(element: any, eventType: any, handler: Function): void;
+
+ setHtml(node: Element, html: () => string): void;
+
+ setHtml(node: Element, html: string): void;
+
+ setTextContent(element: any, textContent: string | KnockoutObservable): void;
+
+ stringifyJson(data: any, replacer?: Function, space?: string): string;
+
+ toggleDomNodeCssClass(node: any, className: string, shouldHaveClass: boolean): void;
+
+ triggerEvent(element: any, eventType: any): void;
+
+ unwrapObservable(value: KnockoutObservable | T): T;
+
+ // NOT PART OF THE MINIFIED API SURFACE (ONLY IN knockout-{version}.debug.js) https://github.com/SteveSanderson/knockout/issues/670
+ // forceRefresh(node: any): void;
+ // ieVersion: number;
+ // isIe6: boolean;
+ // isIe7: boolean;
+ // jQueryHtmlParse(html: string): any[];
+ // makeArray(arrayLikeObject: any): any[];
+ // moveCleanedNodesToContainerElement(nodes: any[]): HTMLElement;
+ // replaceDomNodes(nodeToReplaceOrNodeArray: any, newNodesArray: any[]): void;
+ // setDomNodeChildren(domNode: any, childNodes: any[]): void;
+ // setElementName(element: any, name: string): void;
+ // setOptionNodeSelectionState(optionNode: any, isSelected: boolean): void;
+ // simpleHtmlParse(html: string): any[];
+ // stringStartsWith(str: string, startsWith: string): boolean;
+ // stringTokenize(str: string, delimiter: string): string[];
+ // stringTrim(str: string): string;
+ // tagNameLower(element: any): string;
+}
+
+interface KnockoutArrayChange {
+ status: string;
+ value: T;
+ index: number;
+ moved?: number;
+}
+
+//////////////////////////////////
+// templateSources.js
+//////////////////////////////////
+
+interface KnockoutTemplateSourcesDomElement {
+ text(): any;
+ text(value: any): void;
+
+ data(key: string): any;
+ data(key: string, value: any): any;
+}
+
+interface KnockoutTemplateAnonymous extends KnockoutTemplateSourcesDomElement {
+ nodes(): any;
+ nodes(value: any): void;
+}
+
+interface KnockoutTemplateSources {
+
+ domElement: {
+ prototype: KnockoutTemplateSourcesDomElement
+ new (element: Element): KnockoutTemplateSourcesDomElement
+ };
+
+ anonymousTemplate: {
+ prototype: KnockoutTemplateAnonymous;
+ new (element: Element): KnockoutTemplateAnonymous;
+ };
+}
+
+//////////////////////////////////
+// nativeTemplateEngine.js
+//////////////////////////////////
+
+interface KnockoutNativeTemplateEngine {
+
+ renderTemplateSource(templateSource: Object, bindingContext?: KnockoutBindingContext, options?: Object): any[];
+}
+
+//////////////////////////////////
+// templateEngine.js
+//////////////////////////////////
+
+interface KnockoutTemplateEngine extends KnockoutNativeTemplateEngine {
+
+ createJavaScriptEvaluatorBlock(script: string): string;
+
+ makeTemplateSource(template: any, templateDocument?: Document): any;
+
+ renderTemplate(template: any, bindingContext: KnockoutBindingContext, options: Object, templateDocument: Document): any;
+
+ isTemplateRewritten(template: any, templateDocument: Document): boolean;
+
+ rewriteTemplate(template: any, rewriterCallback: Function, templateDocument: Document): void;
+}
+
+/////////////////////////////////
+
+interface KnockoutStatic {
+ utils: KnockoutUtils;
+ memoization: KnockoutMemoization;
+
+ bindingHandlers: KnockoutBindingHandlers;
+ getBindingHandler(handler: string): KnockoutBindingHandler;
+
+ virtualElements: KnockoutVirtualElements;
+ extenders: KnockoutExtenders;
+
+ applyBindings(viewModelOrBindingContext?: any, rootNode?: any): void;
+ applyBindingsToDescendants(viewModelOrBindingContext: any, rootNode: any): void;
+ applyBindingAccessorsToNode(node: Node, bindings: (bindingContext: KnockoutBindingContext, node: Node) => {}, bindingContext: KnockoutBindingContext): void;
+ applyBindingAccessorsToNode(node: Node, bindings: {}, bindingContext: KnockoutBindingContext): void;
+ applyBindingAccessorsToNode(node: Node, bindings: (bindingContext: KnockoutBindingContext, node: Node) => {}, viewModel: any): void;
+ applyBindingAccessorsToNode(node: Node, bindings: {}, viewModel: any): void;
+ applyBindingsToNode(node: Node, bindings: any, viewModelOrBindingContext?: any): any;
+
+ subscribable: KnockoutSubscribableStatic;
+ observable: KnockoutObservableStatic;
+
+ computed: KnockoutComputedStatic;
+ pureComputed(evaluatorFunction: () => T, context?: any): KnockoutComputed;
+ pureComputed(options: KnockoutComputedDefine, context?: any): KnockoutComputed;
+
+ observableArray: KnockoutObservableArrayStatic;
+
+ contextFor(node: any): any;
+ isSubscribable(instance: any): boolean;
+ toJSON(viewModel: any, replacer?: Function, space?: any): string;
+ toJS(viewModel: any): any;
+ isObservable(instance: any): boolean;
+ isWriteableObservable(instance: any): boolean;
+ isComputed(instance: any): boolean;
+ dataFor(node: any): any;
+ removeNode(node: Element): void;
+ cleanNode(node: Element): Element;
+ renderTemplate(template: Function, viewModel: any, options?: any, target?: any, renderMode?: any): any;
+ renderTemplate(template: string, viewModel: any, options?: any, target?: any, renderMode?: any): any;
+ unwrap(value: KnockoutObservable | T): T;
+
+ computedContext: KnockoutComputedContext;
+
+ //////////////////////////////////
+ // templateSources.js
+ //////////////////////////////////
+
+ templateSources: KnockoutTemplateSources;
+
+ //////////////////////////////////
+ // templateEngine.js
+ //////////////////////////////////
+
+ templateEngine: {
+
+ prototype: KnockoutTemplateEngine;
+
+ new (): KnockoutTemplateEngine;
+ };
+
+ //////////////////////////////////
+ // templateRewriting.js
+ //////////////////////////////////
+
+ templateRewriting: {
+
+ ensureTemplateIsRewritten(template: Node, templateEngine: KnockoutTemplateEngine, templateDocument: Document): any;
+ ensureTemplateIsRewritten(template: string, templateEngine: KnockoutTemplateEngine, templateDocument: Document): any;
+
+ memoizeBindingAttributeSyntax(htmlString: string, templateEngine: KnockoutTemplateEngine): any;
+
+ applyMemoizedBindingsToNextSibling(bindings: any, nodeName: string): string;
+ };
+
+ //////////////////////////////////
+ // nativeTemplateEngine.js
+ //////////////////////////////////
+
+ nativeTemplateEngine: {
+
+ prototype: KnockoutNativeTemplateEngine;
+
+ new (): KnockoutNativeTemplateEngine;
+
+ instance: KnockoutNativeTemplateEngine;
+ };
+
+ //////////////////////////////////
+ // jqueryTmplTemplateEngine.js
+ //////////////////////////////////
+
+ jqueryTmplTemplateEngine: {
+
+ prototype: KnockoutTemplateEngine;
+
+ renderTemplateSource(templateSource: Object, bindingContext: KnockoutBindingContext, options: Object): Node[];
+
+ createJavaScriptEvaluatorBlock(script: string): string;
+
+ addTemplate(templateName: string, templateMarkup: string): void;
+ };
+
+ //////////////////////////////////
+ // templating.js
+ //////////////////////////////////
+
+ setTemplateEngine(templateEngine: KnockoutNativeTemplateEngine): void;
+
+ renderTemplate(template: Function, dataOrBindingContext: KnockoutBindingContext, options: Object, targetNodeOrNodeArray: Node, renderMode: string): any;
+ renderTemplate(template: any, dataOrBindingContext: KnockoutBindingContext, options: Object, targetNodeOrNodeArray: Node, renderMode: string): any;
+ renderTemplate(template: Function, dataOrBindingContext: any, options: Object, targetNodeOrNodeArray: Node, renderMode: string): any;
+ renderTemplate(template: any, dataOrBindingContext: any, options: Object, targetNodeOrNodeArray: Node, renderMode: string): any;
+ renderTemplate(template: Function, dataOrBindingContext: KnockoutBindingContext, options: Object, targetNodeOrNodeArray: Node[], renderMode: string): any;
+ renderTemplate(template: any, dataOrBindingContext: KnockoutBindingContext, options: Object, targetNodeOrNodeArray: Node[], renderMode: string): any;
+ renderTemplate(template: Function, dataOrBindingContext: any, options: Object, targetNodeOrNodeArray: Node[], renderMode: string): any;
+ renderTemplate(template: any, dataOrBindingContext: any, options: Object, targetNodeOrNodeArray: Node[], renderMode: string): any;
+
+ renderTemplateForEach(template: Function, arrayOrObservableArray: any[], options: Object, targetNode: Node, parentBindingContext: KnockoutBindingContext): any;
+ renderTemplateForEach(template: any, arrayOrObservableArray: any[], options: Object, targetNode: Node, parentBindingContext: KnockoutBindingContext): any;
+ renderTemplateForEach(template: Function, arrayOrObservableArray: KnockoutObservable, options: Object, targetNode: Node, parentBindingContext: KnockoutBindingContext): any;
+ renderTemplateForEach(template: any, arrayOrObservableArray: KnockoutObservable, options: Object, targetNode: Node, parentBindingContext: KnockoutBindingContext): any;
+
+ expressionRewriting: {
+ bindingRewriteValidators: any;
+ parseObjectLiteral: { (objectLiteralString: string): any[] }
+ };
+
+ /////////////////////////////////
+
+ bindingProvider: {
+ instance: KnockoutBindingProvider;
+ new (): KnockoutBindingProvider;
+ }
+
+ /////////////////////////////////
+ // selectExtensions.js
+ /////////////////////////////////
+
+ selectExtensions: {
+
+ readValue(element: HTMLElement): any;
+
+ writeValue(element: HTMLElement, value: any): void;
+ };
+
+ components: KnockoutComponents;
+}
+
+interface KnockoutBindingProvider {
+ nodeHasBindings(node: Node): boolean;
+ getBindings(node: Node, bindingContext: KnockoutBindingContext): {};
+ getBindingAccessors?(node: Node, bindingContext: KnockoutBindingContext): { [key: string]: string; };
+}
+
+interface KnockoutComputedContext {
+ getDependenciesCount(): number;
+ isInitial: () => boolean;
+ isSleeping: boolean;
+}
+
+//
+// refactored types into a namespace to reduce global pollution
+// and used Union Types to simplify overloads (requires TypeScript 1.4)
+//
+declare module KnockoutComponentTypes {
+
+ interface Config {
+ viewModel?: ViewModelFunction | ViewModelSharedInstance | ViewModelFactoryFunction | AMDModule;
+ template: string | Node[]| DocumentFragment | TemplateElement | AMDModule;
+ synchronous?: boolean;
+ }
+
+ interface ComponentConfig {
+ viewModel?: ViewModelFunction | ViewModelSharedInstance | ViewModelFactoryFunction | AMDModule;
+ template: any;
+ createViewModel?: any;
+ }
+
+ interface EmptyConfig {
+ }
+
+ // common AMD type
+ interface AMDModule {
+ require: string;
+ }
+
+ // viewmodel types
+ interface ViewModelFunction {
+ (params?: any): any;
+ }
+
+ interface ViewModelSharedInstance {
+ instance: any;
+ }
+
+ interface ViewModelFactoryFunction {
+ createViewModel: (params?: any, componentInfo?: ComponentInfo) => any;
+ }
+
+ interface ComponentInfo {
+ element: Node;
+ templateNodes: Node[];
+ }
+
+ interface TemplateElement {
+ element: string | Node;
+ }
+
+ interface Loader {
+ getConfig? (componentName: string, callback: (result: ComponentConfig) => void): void;
+ loadComponent? (componentName: string, config: ComponentConfig, callback: (result: Definition) => void): void;
+ loadTemplate? (componentName: string, templateConfig: any, callback: (result: Node[]) => void): void;
+ loadViewModel? (componentName: string, viewModelConfig: any, callback: (result: any) => void): void;
+ suppressLoaderExceptions?: boolean;
+ }
+
+ interface Definition {
+ template: Node[];
+ createViewModel? (params: any, options: { element: Node; }): any;
+ }
+}
+
+interface KnockoutComponents {
+ // overloads for register method:
+ register(componentName: string, config: KnockoutComponentTypes.Config | KnockoutComponentTypes.EmptyConfig): void;
+
+ isRegistered(componentName: string): boolean;
+ unregister(componentName: string): void;
+ get(componentName: string, callback: (definition: KnockoutComponentTypes.Definition) => void): void;
+ clearCachedDefinition(componentName: string): void
+ defaultLoader: KnockoutComponentTypes.Loader;
+ loaders: KnockoutComponentTypes.Loader[];
+ getComponentNameForNode(node: Node): string;
+}
+
+declare var ko: KnockoutStatic;
+
+declare module "knockout" {
+ export = ko;
+}
diff --git a/samples/react-socket-io/client/typings/lodash/lodash.d.ts b/samples/react-socket-io/client/typings/lodash/lodash.d.ts
new file mode 100644
index 000000000..1e39d223f
--- /dev/null
+++ b/samples/react-socket-io/client/typings/lodash/lodash.d.ts
@@ -0,0 +1,20808 @@
+// Type definitions for Lo-Dash
+// Project: http://lodash.com/
+// Definitions by: Brian Zengel , Ilya Mochalov , Stepan Mikhaylyuk
+// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
+
+
+/**
+### 4.0.0 Changelog (https://github.com/lodash/lodash/wiki/Changelog)
+
+#### TODO:
+removed:
+- [x] Removed _.support
+- [x] Removed _.findWhere in favor of _.find with iteratee shorthand
+- [x] Removed _.where in favor of _.filter with iteratee shorthand
+- [x] Removed _.pluck in favor of _.map with iteratee shorthand
+
+renamed:
+- [x] Renamed _.first to _.head
+- [x] Renamed _.indexBy to _.keyBy
+- [x] Renamed _.invoke to _.invokeMap
+- [x] Renamed _.overArgs to _.overArgs
+- [x] Renamed _.padLeft & _.padRight to _.padStart & _.padEnd
+- [x] Renamed _.pairs to _.toPairs
+- [x] Renamed _.rest to _.tail
+- [x] Renamed _.restParam to _.rest
+- [x] Renamed _.sortByOrder to _.orderBy
+- [x] Renamed _.trimLeft & _.trimRight to _.trimStart & _.trimEnd
+- [x] Renamed _.trunc to _.truncate
+
+split:
+- [x] Split _.indexOf & _.lastIndexOf into _.sortedIndexOf & _.sortedLastIndexOf
+- [x] Split _.max & _.min into _.maxBy & _.minBy
+- [x] Split _.omit & _.pick into _.omitBy & _.pickBy
+- [x] Split _.sample into _.sampleSize
+- [x] Split _.sortedIndex into _.sortedIndexBy
+- [x] Split _.sortedLastIndex into _.sortedLastIndexBy
+- [x] Split _.uniq into _.sortedUniq, _.sortedUniqBy, & _.uniqBy
+
+changes:
+- [x] Absorbed _.sortByAll into _.sortBy
+- [x] Changed the category of _.at to “Object”
+- [x] Changed the category of _.bindAll to “Utility”
+- [x] Made _.capitalize uppercase the first character & lowercase the rest
+- [x] Made _.functions return only own method names
+
+
+added 23 array methods:
+- [x] _.concat
+- [x] _.differenceBy
+- [x] _.differenceWith
+- [x] _.flatMap
+- [x] _.fromPairs
+- [x] _.intersectionBy
+- [x] _.intersectionWith
+- [x] _.join
+- [x] _.pullAll
+- [x] _.pullAllBy
+- [x] _.reverse
+- [x] _.sortedIndexBy
+- [x] _.sortedIndexOf
+- [x] _.sortedLastIndexBy
+- [x] _.sortedLastIndexOf
+- [x] _.sortedUniq
+- [x] _.sortedUniqBy
+- [x] _.unionBy
+- [x] _.unionWith
+- [x] _.uniqBy
+- [x] _.uniqWith
+- [x] _.xorBy
+- [x] _.xorWith
+
+added 18 lang methods:
+- [x] _.cloneDeepWith
+- [x] _.cloneWith
+- [x] _.eq
+- [x] _.isArrayLike
+- [x] _.isArrayLikeObject
+- [x] _.isEqualWith
+- [x] _.isInteger
+- [x] _.isLength
+- [x] _.isMatchWith
+- [x] _.isNil
+- [x] _.isObjectLike
+- [x] _.isSafeInteger
+- [x] _.isSymbol
+- [x] _.toInteger
+- [x] _.toLength
+- [x] _.toNumber
+- [x] _.toSafeInteger
+- [x] _.toString
+
+added 13 object methods:
+- [x] _.assignIn
+- [x] _.assignInWith
+- [x] _.assignWith
+- [x] _.functionsIn
+- [x] _.hasIn
+- [x] _.mergeWith
+- [x] _.omitBy
+- [x] _.pickBy
+
+
+added 8 string methods:
+- [x] _.lowerCase
+- [x] _.lowerFirst
+- [x] _.upperCase
+- [x] _.upperFirst
+- [x] _.toLower
+- [x] _.toUpper
+
+added 8 utility methods:
+- [x] _.toPath
+
+added 4 math methods:
+- [x] _.maxBy
+- [x] _.mean
+- [x] _.minBy
+- [x] _.sumBy
+
+added 2 function methods:
+- [x] _.flip
+- [x] _.unary
+
+added 2 number methods:
+- [x] _.clamp
+- [x] _.subtract
+
+added collection method:
+- [x] _.sampleSize
+
+Added 3 aliases
+
+- [x] _.first as an alias of _.head
+
+Removed 17 aliases
+- [x] Removed aliase _.all
+- [x] Removed aliase _.any
+- [x] Removed aliase _.backflow
+- [x] Removed aliase _.callback
+- [x] Removed aliase _.collect
+- [x] Removed aliase _.compose
+- [x] Removed aliase _.contains
+- [x] Removed aliase _.detect
+- [x] Removed aliase _.foldl
+- [x] Removed aliase _.foldr
+- [x] Removed aliase _.include
+- [x] Removed aliase _.inject
+- [x] Removed aliase _.methods
+- [x] Removed aliase _.object
+- [x] Removed aliase _.run
+- [x] Removed aliase _.select
+- [x] Removed aliase _.unique
+
+Other changes
+- [x] Added support for array buffers to _.isEqual
+- [x] Added support for converting iterators to _.toArray
+- [x] Added support for deep paths to _.zipObject
+- [x] Changed UMD to export to window or self when available regardless of other exports
+- [x] Ensured debounce cancel clears args & thisArg references
+- [x] Ensured _.add, _.subtract, & _.sum don’t skip NaN values
+- [x] Ensured _.clone treats generators like functions
+- [x] Ensured _.clone produces clones with the source’s [[Prototype]]
+- [x] Ensured _.defaults assigns properties that shadow Object.prototype
+- [x] Ensured _.defaultsDeep doesn’t merge a string into an array
+- [x] Ensured _.defaultsDeep & _.merge don’t modify sources
+- [x] Ensured _.defaultsDeep works with circular references
+- [x] Ensured _.keys skips “length” on strict mode arguments objects in Safari 9
+- [x] Ensured _.merge doesn’t convert strings to arrays
+- [x] Ensured _.merge merges plain-objects onto non plain-objects
+- [x] Ensured _#plant resets iterator data of cloned sequences
+- [x] Ensured _.random swaps min & max if min is greater than max
+- [x] Ensured _.range preserves the sign of start of -0
+- [x] Ensured _.reduce & _.reduceRight use getIteratee in their array branch
+- [x] Fixed rounding issue with the precision param of _.floor
+
+** LATER **
+Misc:
+- [ ] Made _.forEach, _.forIn, _.forOwn, & _.times implicitly end a chain sequence
+- [ ] Removed thisArg params from most methods
+- [ ] Made “By” methods provide a single param to iteratees
+- [ ] Made _.words chainable by default
+- [ ] Removed isDeep params from _.clone & _.flatten
+- [ ] Removed _.bindAll support for binding all methods when no names are provided
+- [ ] Removed func-first param signature from _.before & _.after
+- [ ] _.extend as an alias of _.assignIn
+- [ ] _.extendWith as an alias of _.assignInWith
+- [ ] Added clear method to _.memoize.Cache
+- [ ] Added flush method to debounced & throttled functions
+- [ ] Added support for ES6 maps, sets, & symbols to _.clone, _.isEqual, & _.toArray
+- [ ] Enabled _.flow & _.flowRight to accept an array of functions
+- [ ] Ensured “Collection” methods treat functions as objects
+- [ ] Ensured _.assign, _.defaults, & _.merge coerce object values to objects
+- [ ] Ensured _.bindKey bound functions call object[key] when called with the new operator
+- [ ] Ensured _.isFunction returns true for generator functions
+- [ ] Ensured _.merge assigns typed arrays directly
+- [ ] Made _(...) an iterator & iterable
+- [ ] Made _.drop, _.take, & right forms coerce n of undefined to 0
+
+Methods:
+- [ ] _.concat
+- [ ] _.differenceBy
+- [ ] _.differenceWith
+- [ ] _.flatMap
+- [ ] _.fromPairs
+- [ ] _.intersectionBy
+- [ ] _.intersectionWith
+- [ ] _.join
+- [ ] _.pullAll
+- [ ] _.pullAllBy
+- [ ] _.reverse
+- [ ] _.sortedLastIndexOf
+- [ ] _.unionBy
+- [ ] _.unionWith
+- [ ] _.uniqWith
+- [ ] _.xorBy
+- [ ] _.xorWith
+- [ ] _.toString
+
+- [ ] _.invoke
+- [ ] _.setWith
+- [ ] _.toPairs
+- [ ] _.toPairsIn
+- [ ] _.unset
+
+- [ ] _.replace
+- [ ] _.split
+
+- [ ] _.cond
+- [ ] _.conforms
+- [ ] _.nthArg
+- [ ] _.over
+- [ ] _.overEvery
+- [ ] _.overSome
+- [ ] _.rangeRight
+
+- [ ] _.next
+*/
+
+declare var _: _.LoDashStatic;
+
+declare module _ {
+ interface LoDashStatic {
+ /**
+ * Creates a lodash object which wraps the given value to enable intuitive method chaining.
+ *
+ * In addition to Lo-Dash methods, wrappers also have the following Array methods:
+ * concat, join, pop, push, reverse, shift, slice, sort, splice, and unshift
+ *
+ * Chaining is supported in custom builds as long as the value method is implicitly or
+ * explicitly included in the build.
+ *
+ * The chainable wrapper functions are:
+ * after, assign, bind, bindAll, bindKey, chain, chunk, compact, compose, concat, countBy,
+ * createCallback, curry, debounce, defaults, defer, delay, difference, filter, flatten,
+ * forEach, forEachRight, forIn, forInRight, forOwn, forOwnRight, functions, groupBy,
+ * keyBy, initial, intersection, invert, invoke, keys, map, max, memoize, merge, min,
+ * object, omit, once, pairs, partial, partialRight, pick, pluck, pull, push, range, reject,
+ * remove, rest, reverse, sample, shuffle, slice, sort, sortBy, splice, tap, throttle, times,
+ * toArray, transform, union, uniq, unset, unshift, unzip, values, where, without, wrap, and zip
+ *
+ * The non-chainable wrapper functions are:
+ * clone, cloneDeep, contains, escape, every, find, findIndex, findKey, findLast,
+ * findLastIndex, findLastKey, has, identity, indexOf, isArguments, isArray, isBoolean,
+ * isDate, isElement, isEmpty, isEqual, isFinite, isFunction, isNaN, isNull, isNumber,
+ * isObject, isPlainObject, isRegExp, isString, isUndefined, join, lastIndexOf, mixin,
+ * noConflict, parseInt, pop, random, reduce, reduceRight, result, shift, size, some,
+ * sortedIndex, runInContext, template, unescape, uniqueId, and value
+ *
+ * The wrapper functions first and last return wrapped values when n is provided, otherwise
+ * they return unwrapped values.
+ *
+ * Explicit chaining can be enabled by using the _.chain method.
+ **/
+ (value: number): LoDashImplicitWrapper;
+ (value: string): LoDashImplicitStringWrapper;
+ (value: boolean): LoDashImplicitWrapper;
+ (value: Array): LoDashImplicitNumberArrayWrapper;
+ (value: Array): LoDashImplicitArrayWrapper;
+ (value: T): LoDashImplicitObjectWrapper;
+ (value: any): LoDashImplicitWrapper;
+
+ /**
+ * The semantic version number.
+ **/
+ VERSION: string;
+
+ /**
+ * By default, the template delimiters used by Lo-Dash are similar to those in embedded Ruby
+ * (ERB). Change the following template settings to use alternative delimiters.
+ **/
+ templateSettings: TemplateSettings;
+ }
+
+ /**
+ * By default, the template delimiters used by Lo-Dash are similar to those in embedded Ruby
+ * (ERB). Change the following template settings to use alternative delimiters.
+ **/
+ interface TemplateSettings {
+ /**
+ * The "escape" delimiter.
+ **/
+ escape?: RegExp;
+
+ /**
+ * The "evaluate" delimiter.
+ **/
+ evaluate?: RegExp;
+
+ /**
+ * An object to import into the template as local variables.
+ **/
+ imports?: Dictionary;
+
+ /**
+ * The "interpolate" delimiter.
+ **/
+ interpolate?: RegExp;
+
+ /**
+ * Used to reference the data object in the template text.
+ **/
+ variable?: string;
+ }
+
+ /**
+ * Creates a cache object to store key/value pairs.
+ */
+ interface MapCache {
+ /**
+ * Removes `key` and its value from the cache.
+ * @param key The key of the value to remove.
+ * @return Returns `true` if the entry was removed successfully, else `false`.
+ */
+ delete(key: string): boolean;
+
+ /**
+ * Gets the cached value for `key`.
+ * @param key The key of the value to get.
+ * @return Returns the cached value.
+ */
+ get(key: string): any;
+
+ /**
+ * Checks if a cached value for `key` exists.
+ * @param key The key of the entry to check.
+ * @return Returns `true` if an entry for `key` exists, else `false`.
+ */
+ has(key: string): boolean;
+
+ /**
+ * Sets `value` to `key` of the cache.
+ * @param key The key of the value to cache.
+ * @param value The value to cache.
+ * @return Returns the cache object.
+ */
+ set(key: string, value: any): _.Dictionary;
+ }
+
+ interface LoDashWrapperBase { }
+
+ interface LoDashImplicitWrapperBase extends LoDashWrapperBase { }
+
+ interface LoDashExplicitWrapperBase extends LoDashWrapperBase { }
+
+ interface LoDashImplicitWrapper extends LoDashImplicitWrapperBase> { }
+
+ interface LoDashExplicitWrapper extends LoDashExplicitWrapperBase> { }
+
+ interface LoDashImplicitStringWrapper extends LoDashImplicitWrapper { }
+
+ interface LoDashExplicitStringWrapper extends LoDashExplicitWrapper { }
+
+ interface LoDashImplicitObjectWrapper extends LoDashImplicitWrapperBase> { }
+
+ interface LoDashExplicitObjectWrapper extends LoDashExplicitWrapperBase> { }
+
+ interface LoDashImplicitArrayWrapper extends LoDashImplicitWrapperBase> {
+ pop(): T;
+ push(...items: T[]): LoDashImplicitArrayWrapper;
+ shift(): T;
+ sort(compareFn?: (a: T, b: T) => number): LoDashImplicitArrayWrapper;
+ splice(start: number): LoDashImplicitArrayWrapper;
+ splice(start: number, deleteCount: number, ...items: any[]): LoDashImplicitArrayWrapper;
+ unshift(...items: T[]): LoDashImplicitArrayWrapper;
+ }
+
+ interface LoDashExplicitArrayWrapper extends LoDashExplicitWrapperBase> { }
+
+ interface LoDashImplicitNumberArrayWrapper extends LoDashImplicitArrayWrapper { }
+
+ interface LoDashExplicitNumberArrayWrapper extends LoDashExplicitArrayWrapper { }
+
+ /*********
+ * Array *
+ *********/
+
+ //_.chunk
+ interface LoDashStatic {
+ /**
+ * Creates an array of elements split into groups the length of size. If collection can’t be split evenly, the
+ * final chunk will be the remaining elements.
+ *
+ * @param array The array to process.
+ * @param size The length of each chunk.
+ * @return Returns the new array containing chunks.
+ */
+ chunk(
+ array: List,
+ size?: number
+ ): T[][];
+ }
+
+ interface LoDashImplicitArrayWrapper {
+ /**
+ * @see _.chunk
+ */
+ chunk(size?: number): LoDashImplicitArrayWrapper;
+ }
+
+ interface LoDashImplicitObjectWrapper {
+ /**
+ * @see _.chunk
+ */
+ chunk(size?: number): LoDashImplicitArrayWrapper;
+ }
+
+ interface LoDashExplicitArrayWrapper {
+ /**
+ * @see _.chunk
+ */
+ chunk(size?: number): LoDashExplicitArrayWrapper;
+ }
+
+ interface LoDashExplicitObjectWrapper {
+ /**
+ * @see _.chunk
+ */
+ chunk(size?: number): LoDashExplicitArrayWrapper;
+ }
+
+ //_.compact
+ interface LoDashStatic {
+ /**
+ * Creates an array with all falsey values removed. The values false, null, 0, "", undefined, and NaN are
+ * falsey.
+ *
+ * @param array The array to compact.
+ * @return (Array) Returns the new array of filtered values.
+ */
+ compact(array?: List): T[];
+ }
+
+ interface LoDashImplicitArrayWrapper {
+ /**
+ * @see _.compact
+ */
+ compact(): LoDashImplicitArrayWrapper;
+ }
+
+ interface LoDashImplicitObjectWrapper {
+ /**
+ * @see _.compact
+ */
+ compact(): LoDashImplicitArrayWrapper;
+ }
+
+ interface LoDashExplicitArrayWrapper {
+ /**
+ * @see _.compact
+ */
+ compact(): LoDashExplicitArrayWrapper;
+ }
+
+ interface LoDashExplicitObjectWrapper {
+ /**
+ * @see _.compact
+ */
+ compact(): LoDashExplicitArrayWrapper;
+ }
+
+ //_.concat DUMMY
+ interface LoDashStatic {
+ /**
+ * Creates a new array concatenating `array` with any additional arrays
+ * and/or values.
+ *
+ * @static
+ * @memberOf _
+ * @category Array
+ * @param {Array} array The array to concatenate.
+ * @param {...*} [values] The values to concatenate.
+ * @returns {Array} Returns the new concatenated array.
+ * @example
+ *
+ * var array = [1];
+ * var other = _.concat(array, 2, [3], [[4]]);
+ *
+ * console.log(other);
+ * // => [1, 2, 3, [4]]
+ *
+ * console.log(array);
+ * // => [1]
+ */
+ concat(...values: (T[]|List)[]) : T[];
+ }
+
+ //_.difference
+ interface LoDashStatic {
+ /**
+ * Creates an array of unique array values not included in the other provided arrays using SameValueZero for
+ * equality comparisons.
+ *
+ * @param array The array to inspect.
+ * @param values The arrays of values to exclude.
+ * @return Returns the new array of filtered values.
+ */
+ difference(
+ array: T[]|List,
+ ...values: Array>
+ ): T[];
+ }
+
+ interface LoDashImplicitArrayWrapper {
+ /**
+ * @see _.difference
+ */
+ difference(...values: (T[]|List)[]): LoDashImplicitArrayWrapper;
+ }
+
+ interface LoDashImplicitObjectWrapper {
+ /**
+ * @see _.difference
+ */
+ difference(...values: (TValue[]|List)[]): LoDashImplicitArrayWrapper;
+ }
+
+ interface LoDashExplicitArrayWrapper {
+ /**
+ * @see _.difference
+ */
+ difference(...values: (T[]|List)[]): LoDashExplicitArrayWrapper;
+ }
+
+ interface LoDashExplicitObjectWrapper {
+ /**
+ * @see _.difference
+ */
+ difference(...values: (TValue[]|List)[]): LoDashExplicitArrayWrapper;
+ }
+
+ //_.differenceBy
+ interface LoDashStatic {
+ /**
+ * This method is like _.difference except that it accepts iteratee which is invoked for each element of array
+ * and values to generate the criterion by which uniqueness is computed. The iteratee is invoked with one
+ * argument: (value).
+ *
+ * @param array The array to inspect.
+ * @param values The values to exclude.
+ * @param iteratee The iteratee invoked per element.
+ * @returns Returns the new array of filtered values.
+ */
+ differenceBy(
+ array: T[]|List,
+ values?: T[]|List,
+ iteratee?: ((value: T) => any)|string
+ ): T[];
+
+ /**
+ * @see _.differenceBy
+ */
+ differenceBy(
+ array: T[]|List,
+ values?: T[]|List,
+ iteratee?: W
+ ): T[];
+
+ /**
+ * @see _.differenceBy
+ */
+ differenceBy(
+ array: T[]|List,
+ values1?: T[]|List,
+ values2?: T[]|List,
+ iteratee?: ((value: T) => any)|string
+ ): T[];
+
+ /**
+ * @see _.differenceBy
+ */
+ differenceBy(
+ array: T[]|List,
+ values1?: T[]|List,
+ values2?: T[]|List,
+ iteratee?: W
+ ): T[];
+
+ /**
+ * @see _.differenceBy
+ */
+ differenceBy(
+ array: T[]|List,
+ values1?: T[]|List,
+ values2?: T[]|List,
+ values3?: T[]|List,
+ iteratee?: ((value: T) => any)|string
+ ): T[];
+
+ /**
+ * @see _.differenceBy
+ */
+ differenceBy(
+ array: T[]|List,
+ values1?: T[]|List,
+ values2?: T[]|List,
+ values3?: T[]|List,
+ iteratee?: W
+ ): T[];
+
+ /**
+ * @see _.differenceBy
+ */
+ differenceBy(
+ array: T[]|List,
+ values1?: T[]|List,
+ values2?: T[]|List,
+ values3?: T[]|List,
+ values4?: T[]|List,
+ iteratee?: W
+ ): T[];
+
+ /**
+ * @see _.differenceBy
+ */
+ differenceBy(
+ array: T[]|List,
+ values1?: T[]|List,
+ values2?: T[]|List,
+ values3?: T[]|List