Creating Stores and using Observables

Change-Id: I214692e64df065beaddee0e0ec8759de540c269d
diff --git a/package.json b/package.json
index a42a6cc..bd5da85 100644
--- a/package.json
+++ b/package.json
@@ -5,6 +5,7 @@
     "angular-resource": "^1.6.0",
     "angular-ui-router": "1.0.0-beta.1",
     "lodash": "^4.17.2",
+    "rxjs": "^5.0.1",
     "socket.io-client": "^1.7.2"
   },
   "devDependencies": {
@@ -68,6 +69,7 @@
     "build": "gulp",
     "start": "gulp serve",
     "serve:dist": "gulp serve:dist",
+    "pretest": "npm run lint",
     "test": "gulp test",
     "test:auto": "gulp test:auto",
     "config": "gulp config",
diff --git a/src/app/config/app.config.ts b/src/app/config/app.config.ts
index 2357f77..7b6fa12 100644
--- a/src/app/config/app.config.ts
+++ b/src/app/config/app.config.ts
@@ -6,6 +6,6 @@
 }
 
 export const AppConfig: IAppConfig = {
-    apiEndpoint: 'http://xos-rest-gw:3000/api',
-    websocketClient: 'http://xos-rest-gw:3000'
+    apiEndpoint: 'http://xos.dev:3000/api',
+    websocketClient: 'http://xos.dev:3000'
 };
diff --git a/src/app/core/login/login.ts b/src/app/core/login/login.ts
index 51dc7c9..e5881dd 100644
--- a/src/app/core/login/login.ts
+++ b/src/app/core/login/login.ts
@@ -1,4 +1,4 @@
-import {AuthService} from '../../rest/auth.rest';
+import {AuthService} from '../../datasources/rest/auth.rest';
 
 class LoginCtrl {
   static $inject = ['AuthService', '$state'];
diff --git a/src/app/core/table/table.scss b/src/app/core/table/table.scss
new file mode 100644
index 0000000..fbf6ee7
--- /dev/null
+++ b/src/app/core/table/table.scss
@@ -0,0 +1,41 @@
+table {
+  width: 100%;
+  max-width: 100%;
+  margin-bottom: 20px;
+  border-collapse: collapse !important;
+  background: darken(grey, 20);
+  border: 1px solid darken(grey, 35);
+
+  td, th {
+  }
+  > tbody > tr > th,
+  > tfoot > tr > th,
+  > thead > tr > td,
+  > tbody > tr > td,
+  > tfoot > tr > td {
+    padding: 8px;
+    line-height: 1.42857143;
+    vertical-align: top;
+    border-top: 1px solid #ddd;
+  }
+  > thead > tr > th {
+    vertical-align: bottom;
+    border-bottom: 2px solid #ddd;
+    text-align: left;
+    padding: 8px;
+  }
+  > caption + thead > tr:first-child > th,
+  > colgroup + thead > tr:first-child > th,
+  > thead:first-child > tr:first-child > th,
+  > caption + thead > tr:first-child > td,
+  > colgroup + thead > tr:first-child > td,
+  > thead:first-child > tr:first-child > td {
+    border-top: 0;
+  }
+  > tbody + tbody {
+    border-top: 2px solid #ddd;
+  }
+  .table .table {
+    background-color: #fff;
+  }
+}
\ No newline at end of file
diff --git a/src/app/core/table/table.ts b/src/app/core/table/table.ts
index 43360c6..a837600 100644
--- a/src/app/core/table/table.ts
+++ b/src/app/core/table/table.ts
@@ -1,6 +1,7 @@
 // TODO fininsh to import all methods from https://github.com/opencord/ng-xos-lib/blob/master/src/ui_components/dumbComponents/table/table.component.js
 // TODO import tests
 
+import './table.scss';
 import * as _ from 'lodash';
 
 interface IXosTableCgfOrder {
@@ -19,8 +20,6 @@
   public columns: any[];
   public orderBy: string;
   public reverse: boolean;
-
-  private data: any[];
   private config: IXosTableCfg;
 
 
@@ -34,13 +33,13 @@
     }
 
     // handle default ordering
-    if (this.config.order && angular.isObject(this.config.order)){
+    if (this.config.order && angular.isObject(this.config.order)) {
       this.reverse = this.config.order.reverse || false;
       this.orderBy = this.config.order.field || 'id';
     }
 
     // if columns with type 'custom' are provided
-    // check that a custom formatte3 is provided too
+    // check that a custom formatter is provided too
     let customCols = _.filter(this.config.columns, {type: 'custom'});
     if (angular.isArray(customCols) && customCols.length > 0) {
       _.forEach(customCols, (col) => {
@@ -51,7 +50,7 @@
     }
 
     // if columns with type 'icon' are provided
-    // check that a custom formatte3 is provided too
+    // check that a custom formatter is provided too
     let iconCols = _.filter(this.config.columns, {type: 'icon'});
     if (angular.isArray(iconCols) && iconCols.length > 0) {
       _.forEach(iconCols, (col) => {
diff --git a/src/app/datasources/helpers/store.helpers.ts b/src/app/datasources/helpers/store.helpers.ts
new file mode 100644
index 0000000..dfb1e7a
--- /dev/null
+++ b/src/app/datasources/helpers/store.helpers.ts
@@ -0,0 +1,34 @@
+import {BehaviorSubject} from 'rxjs';
+import * as _ from 'lodash';
+import {IWSEvent} from '../websocket/global';
+
+export interface IStoreHelpersService {
+  updateCollection(event: IWSEvent, subject: BehaviorSubject<any>): BehaviorSubject<any>;
+}
+
+export class StoreHelpers {
+  public updateCollection(event: IWSEvent, subject: BehaviorSubject<any>): BehaviorSubject<any> {
+    const collection: any[] = subject.value;
+    const index: number = _.findIndex(collection, (i) => {
+      return i.id === event.msg.object.id;
+    });
+    const exist: boolean = index > -1;
+    const isDeleted: boolean = _.includes(event.msg.changed_fields, 'deleted');
+       // remove
+    if (exist && isDeleted) {
+       _.remove(collection, {id: event.msg.object.id});
+     }
+    // Replace item at index using native splice
+    else if (exist && !isDeleted) {
+       collection.splice(index, 1, event.msg.object);
+     }
+    // if the element is not deleted add it
+    else if (!exist && !isDeleted) {
+      collection.push(event.msg.object);
+     }
+
+    subject.next(collection);
+
+    return subject;
+    }
+}
diff --git a/src/app/datasources/index.ts b/src/app/datasources/index.ts
new file mode 100644
index 0000000..4473541
--- /dev/null
+++ b/src/app/datasources/index.ts
@@ -0,0 +1,20 @@
+import {CoreRest} from './rest/core.rest';
+import {SlicesRest} from './rest/slices.rest';
+import {AuthService} from './rest/auth.rest';
+import {WebSocketEvent} from './websocket/global';
+import {SliceStore} from './stores/slices.store';
+import {StoreHelpers} from './helpers/store.helpers';
+
+export const xosRest = 'xosDataSources';
+
+angular
+  .module('xosDataSources', ['ngCookies'])
+  .service('CoreRest', CoreRest)
+  .service('SlicesRest', SlicesRest)
+  .service('AuthService', AuthService)
+  .service('WebSocket', WebSocketEvent);
+
+angular
+  .module('xosDataSources')
+  .service('StoreHelpers', StoreHelpers)
+  .service('SlicesStore', SliceStore);
diff --git a/src/app/rest/auth.rest.ts b/src/app/datasources/rest/auth.rest.ts
similarity index 95%
rename from src/app/rest/auth.rest.ts
rename to src/app/datasources/rest/auth.rest.ts
index c72b51e..a94599a 100644
--- a/src/app/rest/auth.rest.ts
+++ b/src/app/datasources/rest/auth.rest.ts
@@ -1,4 +1,4 @@
-import {AppConfig} from '../config/app.config';
+import {AppConfig} from '../../config/app.config';
 import IHttpPromiseCallbackArg = angular.IHttpPromiseCallbackArg;
 export interface IAuthRequestData {
   username: string;
diff --git a/src/app/rest/core.rest.ts b/src/app/datasources/rest/core.rest.ts
similarity index 87%
rename from src/app/rest/core.rest.ts
rename to src/app/datasources/rest/core.rest.ts
index aace3aa..2c10e10 100644
--- a/src/app/rest/core.rest.ts
+++ b/src/app/datasources/rest/core.rest.ts
@@ -1,4 +1,4 @@
-import {AppConfig} from '../config/app.config';
+import {AppConfig} from '../../config/app.config';
 export class CoreRest {
 
   /** @ngInject */
diff --git a/src/app/datasources/rest/slices.rest.ts b/src/app/datasources/rest/slices.rest.ts
new file mode 100644
index 0000000..a5b7e5c
--- /dev/null
+++ b/src/app/datasources/rest/slices.rest.ts
@@ -0,0 +1,21 @@
+import {AppConfig} from '../../config/app.config';
+
+export interface IXosResourceService {
+  getResource(): ng.resource.IResourceClass<any>;
+}
+
+export class SlicesRest implements IXosResourceService {
+  static $inject = ['$resource'];
+  private resource: angular.resource.IResourceClass<any>;
+
+  /** @ngInject */
+  constructor(
+    private $resource: ng.resource.IResourceService
+  ) {
+    this.resource = this.$resource(`${AppConfig.apiEndpoint}/core/slices/`);
+  }
+
+  public getResource(): ng.resource.IResourceClass<ng.resource.IResource<any>> {
+    return this.resource;
+  }
+}
diff --git a/src/app/datasources/stores/slices.store.ts b/src/app/datasources/stores/slices.store.ts
new file mode 100644
index 0000000..9c3389f
--- /dev/null
+++ b/src/app/datasources/stores/slices.store.ts
@@ -0,0 +1,43 @@
+/// <reference path="../../../../typings/index.d.ts"/>
+
+import {BehaviorSubject, Observable} from 'rxjs/Rx';
+import {IWSEvent, IWSEventService} from '../websocket/global';
+import {IXosResourceService} from '../rest/slices.rest';
+import {IStoreHelpersService} from '../helpers/store.helpers';
+
+export interface  IStoreService {
+  query(): Observable<any>;
+}
+
+export class SliceStore {
+  static $inject = ['WebSocket', 'StoreHelpers', 'SlicesRest'];
+  private _slices: BehaviorSubject<any[]> = new BehaviorSubject([]);
+  constructor(
+    private webSocket: IWSEventService,
+    private storeHelpers: IStoreHelpersService,
+    private sliceService: IXosResourceService
+  ) {
+    this.loadInitialData();
+    this.webSocket.list()
+      .filter((e: IWSEvent) => e.model === 'Slice')
+      .subscribe(
+        (event: IWSEvent) => {
+          this.storeHelpers.updateCollection(event, this._slices);
+        }
+      );
+  }
+
+  query() {
+    return this._slices.asObservable();
+  }
+
+  private loadInitialData() {
+    this.sliceService.getResource().query().$promise
+      .then(
+        res => {
+          this._slices.next(res);
+        },
+        err => console.log('Error retrieving Slices', err)
+      );
+  }
+}
diff --git a/src/app/datasources/websocket/global.ts b/src/app/datasources/websocket/global.ts
new file mode 100644
index 0000000..aaf142a
--- /dev/null
+++ b/src/app/datasources/websocket/global.ts
@@ -0,0 +1,31 @@
+import * as io from 'socket.io-client';
+import {Subject, Observable} from 'rxjs/Rx';
+import {AppConfig} from '../../config/app.config';
+
+export interface IWSEvent {
+  model: string;
+  msg: {
+    changed_fields: string[],
+    object?: any,
+    pk?: number
+  };
+}
+
+export interface IWSEventService {
+  list(): Observable<IWSEvent>;
+}
+
+export class WebSocketEvent {
+  private _events: Subject<IWSEvent> = new Subject<IWSEvent>();
+    private socket;
+    constructor() {
+      console.log('socket.io');
+      this.socket = io(AppConfig.websocketClient);
+      this.socket.on('event', (data: IWSEvent): void => {
+          this._events.next(data);
+        });
+    }
+    list() {
+      return this._events.asObservable();
+    }
+}
diff --git a/src/app/rest/index.ts b/src/app/rest/index.ts
deleted file mode 100644
index d28084b..0000000
--- a/src/app/rest/index.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import {CoreRest} from './core.rest';
-import {SlicesRest} from './slices.rest';
-import {AuthService} from './auth.rest';
-
-export const xosRest = 'xosRest';
-
-angular
-  .module('xosRest', ['ngCookies'])
-  .service('CoreRest', CoreRest)
-  .service('SlicesRest', SlicesRest)
-  .service('AuthService', AuthService);
diff --git a/src/app/rest/slices.rest.ts b/src/app/rest/slices.rest.ts
deleted file mode 100644
index 0d1d8a1..0000000
--- a/src/app/rest/slices.rest.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-import {AppConfig} from '../config/app.config';
-
-export interface IXosResourceService {
-  getResource(): ng.resource.IResourceClass<any>;
-}
-
-export class SlicesRest implements IXosResourceService{
-  static $inject = ['$resource'];
-
-  /** @ngInject */
-  constructor(
-    private $resource: ng.resource.IResourceService
-  ) {
-
-  }
-
-  public getResource(): ng.resource.IResourceClass<ng.resource.IResource<any>> {
-    return this.$resource(`${AppConfig.apiEndpoint}/core/slices/`);
-  }
-}
diff --git a/src/app/views/crud/crud.ts b/src/app/views/crud/crud.ts
index b35c104..853669c 100644
--- a/src/app/views/crud/crud.ts
+++ b/src/app/views/crud/crud.ts
@@ -1,37 +1,42 @@
-import {IXosResourceService} from '../../rest/slices.rest';
 import {IXosTableCfg} from '../../core/table/table';
+import {IStoreService} from '../../datasources/stores/slices.store';
 export interface IXosCrudData {
   title: string;
-  resource: string;
+  store: string;
   xosTableCfg: IXosTableCfg;
 }
 
 class CrudController {
-  static $inject = ['$state', '$injector'];
+  // TODO dynamically inject store
+  static $inject = ['$state', '$injector', '$scope'];
 
   public data: IXosCrudData;
   public tableCfg: IXosTableCfg;
   public title: string;
-  public resourceName: string;
-  public resource: ng.resource.IResourceClass<ng.resource.IResource<any>>;
+  public storeName: string;
+  public store: IStoreService;
   public tableData: any[];
 
   constructor(
     private $state: angular.ui.IStateService,
-    private $injector: angular.Injectable<any>
+    private $injector: angular.Injectable<any>,
+    private $scope: angular.IScope
   ) {
     this.data = this.$state.current.data;
-    console.log('xosCrud', this.data);
     this.tableCfg = this.data.xosTableCfg;
     this.title = this.data.title;
-    this.resourceName = this.data.resource;
-    this.resource = this.$injector.get(this.resourceName).getResource();
+    this.storeName = this.data.store;
+    this.store = this.$injector.get(this.storeName);
 
-    this.resource
-      .query().$promise
-      .then(res => {
-        this.tableData = res;
-      });
+    this.store.query()
+      .subscribe(
+        (event) => {
+          // NOTE Observable mess with $digest cycles, we need to schedule the expression later
+          $scope.$evalAsync(() => {
+            this.tableData = event;
+          });
+        }
+      );
   }
 }
 
diff --git a/src/index.scss b/src/index.scss
index 2cbe173..3d155ca 100644
--- a/src/index.scss
+++ b/src/index.scss
@@ -36,6 +36,7 @@
     flex-basis: 90%;
     background: darken(grey, 25);
     padding: 20px;
+    color: #eee;
   }
 }
 
@@ -49,12 +50,6 @@
   font-size: 1.5rem;
   margin: 1rem;
 }
-.header-date {
-  flex: 1;
-  text-align: right;
-  margin: 1rem;
-  white: white;
-}
 
 .footer {
   padding: 0.5rem;
@@ -63,3 +58,7 @@
   text-align: center;
   color: white;
 }
+
+h1 {
+  color: #fff;
+}
\ No newline at end of file
diff --git a/src/index.ts b/src/index.ts
index 66a32f1..c654e52 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -11,7 +11,7 @@
 
 import './index.scss';
 import {xosCore} from './app/core/index';
-import {xosRest} from './app/rest/index';
+import {xosRest} from './app/datasources/index';
 import {xosViews} from './app/views/index';
 import {interceptorConfig, userStatusInterceptor, CredentialsInterceptor} from './interceptors';
 
diff --git a/src/routes.ts b/src/routes.ts
index 8290e9a..d5a0800 100644
--- a/src/routes.ts
+++ b/src/routes.ts
@@ -29,7 +29,7 @@
       component: `xosCrud`,
       data: {
         title: 'Slices',
-        resource: 'SlicesRest',
+        store: 'SlicesStore',
         xosTableCfg: {
           columns: [
             {
diff --git a/typings.json b/typings.json
index 700269c..ac768af 100644
--- a/typings.json
+++ b/typings.json
@@ -8,6 +8,7 @@
     "es6-shim": "registry:dt/es6-shim#0.31.2+20160602141504",
     "jasmine": "github:DefinitelyTyped/DefinitelyTyped/jasmine/jasmine.d.ts#dc9dabe74a5be62613b17a3605309783a12ff28a",
     "jquery": "github:DefinitelyTyped/DefinitelyTyped/jquery/jquery.d.ts#dc9dabe74a5be62613b17a3605309783a12ff28a",
-    "require": "registry:dt/require#2.1.20+20160316155526"
+    "require": "registry:dt/require#2.1.20+20160316155526",
+    "socket.io-client": "registry:dt/socket.io-client#1.4.4+20160317120654"
   }
 }
diff --git a/typings/globals/socket.io-client/index.d.ts b/typings/globals/socket.io-client/index.d.ts
new file mode 100644
index 0000000..db58959
--- /dev/null
+++ b/typings/globals/socket.io-client/index.d.ts
@@ -0,0 +1,663 @@
+// Generated by typings
+// Source: https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/7de6c3dd94feaeb21f20054b9f30d5dabc5efabd/socket.io-client/socket.io-client.d.ts
+declare var io: SocketIOClientStatic;
+
+declare module 'socket.io-client' {
+	export = io;
+}
+
+interface SocketIOClientStatic {
+
+	/**
+	 * Looks up an existing 'Manager' for multiplexing. If the user summons:
+	 * 	'io( 'http://localhost/a' );'
+	 * 	'io( 'http://localhost/b' );'
+	 *
+	 * We reuse the existing instance based on the same scheme/port/host, and
+	 * we initialize sockets for each namespace. If autoConnect isn't set to
+	 * false in the options, then we'll automatically connect
+	 * @param uri The uri that we'll connect to, including the namespace, where '/' is the default one (e.g. http://localhost:4000/somenamespace)
+	 * @opts Any connect options that we want to pass along
+	 * @return A Socket object
+	 */
+	( uri: string, opts?: SocketIOClient.ConnectOpts ): SocketIOClient.Socket;
+
+	/**
+	 * Auto-connects to the window location and defalt namespace.
+	 * E.g. window.protocol + '//' + window.host + ':80/'
+	 * @opts Any connect options that we want to pass along
+	 * @return A Socket object
+	 */
+	( opts?: SocketIOClient.ConnectOpts ): SocketIOClient.Socket;
+
+	/**
+	 * @see the default constructor (io(uri, opts))
+	 */
+	connect( uri: string, opts?: SocketIOClient.ConnectOpts ): SocketIOClient.Socket;
+
+	/**
+	 * @see the default constructor (io(opts))
+	 */
+	connect( opts?: SocketIOClient.ConnectOpts ): SocketIOClient.Socket;
+
+	/**
+	 * The socket.io protocol revision number this client works with
+	 * @default 4
+	 */
+	protocol: number;
+
+	/**
+	 * Socket constructor - exposed for the standalone build
+	 */
+	Socket: SocketIOClient.Socket;
+
+	/**
+	 * Manager constructor - exposed for the standalone build
+	 */
+	Manager: SocketIOClient.ManagerStatic;
+}
+
+declare namespace SocketIOClient {
+
+	/**
+	 * The base emiter class, used by Socket and Manager
+	 */
+	interface Emitter {
+		/**
+		 * Adds a listener for a particular event. Calling multiple times will add
+		 * multiple listeners
+		 * @param event The event that we're listening for
+		 * @param fn The function to call when we get the event. Parameters depend on the
+		 * event in question
+		 * @return This Emitter
+		 */
+		on( event: string, fn: Function ):Emitter;
+
+		/**
+		 * @see on( event, fn )
+		 */
+		addEventListener( event: string, fn: Function ):Emitter;
+
+		/**
+		 * Adds a listener for a particular event that will be invoked
+		 * a single time before being automatically removed
+		 * @param event The event that we're listening for
+		 * @param fn The function to call when we get the event. Parameters depend on
+		 * the event in question
+		 * @return This Emitter
+		 */
+		once( event: string, fn: Function ):Emitter;
+
+		/**
+		 * Removes a listener for a particular type of event. This will either
+		 * remove a specific listener, or all listeners for this type of event
+		 * @param event The event that we want to remove the listener of
+		 * @param fn The function to remove, or null if we want to remove all functions
+		 * @return This Emitter
+		 */
+		off( event: string, fn?: Function ):Emitter;
+
+		/**
+		 * @see off( event, fn )
+		 */
+		removeListener( event: string, fn?: Function ):Emitter;
+
+		/**
+		 * @see off( event, fn )
+		 */
+		removeEventListener( event: string, fn?: Function ):Emitter;
+
+		/**
+		 * Removes all event listeners on this object
+		 * @return This Emitter
+		 */
+		removeAllListeners():Emitter;
+
+		/**
+		 * Emits 'event' with the given args
+		 * @param event The event that we want to emit
+		 * @param args Optional arguments to emit with the event
+		 * @return Emitter
+		 */
+		emit( event: string, ...args: any[] ):Emitter;
+
+		/**
+		 * Returns all the callbacks for a particular event
+		 * @param event The event that we're looking for the callbacks of
+		 * @return An array of callback Functions, or an empty array if we don't have any
+		 */
+		listeners( event: string ):Function[];
+
+		/**
+		 * Returns if we have listeners for a particular event
+		 * @param event The event that we want to check if we've listeners for
+		 * @return True if we have listeners for this event, false otherwise
+		 */
+		hasListeners( event: string ):boolean;
+	}
+
+	/**
+	 * The Socket static interface
+	 */
+	interface SocketStatic {
+
+		/**
+		 * Creates a new Socket, used for communicating with a specific namespace
+		 * @param io The Manager that's controlling this socket
+		 * @param nsp The namespace that this socket is for (@default '/')
+		 * @return A new Socket
+		 */
+		( io: SocketIOClient.Manager, nsp: string ): Socket;
+
+		/**
+		 * Creates a new Socket, used for communicating with a specific namespace
+		 * @param io The Manager that's controlling this socket
+		 * @param nsp The namespace that this socket is for (@default '/')
+		 * @return A new Socket
+		 */
+		new ( url: string, opts: any ): SocketIOClient.Manager;
+	}
+
+	/**
+	 * The Socket that we use to connect to a Namespace on the server
+	 */
+	interface Socket extends Emitter {
+
+		/**
+		 * The Manager that's controller this socket
+		 */
+		io: SocketIOClient.Manager;
+
+		/**
+		 * The namespace that this socket is for
+		 * @default '/'
+		 */
+		nsp: string;
+
+		/**
+		 * The ID of the socket; matches the server ID and is set when we're connected, and cleared
+		 * when we're disconnected
+		 */
+		id: string;
+
+		/**
+		 * Are we currently connected?
+		 * @default false
+		 */
+		connected: boolean;
+
+		/**
+		 * Are we currently disconnected?
+		 * @default true
+		 */
+		disconnected: boolean;
+
+		/**
+		 * Opens our socket so that it connects. If the 'autoConnect' option for io is
+		 * true (default), then this is called automatically when the Socket is created
+		 */
+		open(): Socket;
+
+		/**
+		 * @see open();
+		 */
+		connect(): Socket;
+
+		/**
+		 * Sends a 'message' event
+		 * @param args Any optional arguments that we want to send
+		 * @see emit
+		 * @return This Socket
+		 */
+		send( ...args: any[] ):Socket;
+
+		/**
+		 * An override of the base emit. If the event is one of:
+		 * 	connect
+		 * 	connect_error
+		 * 	connect_timeout
+		 * 	connecting
+		 * 	disconnect
+		 * 	error
+		 * 	reconnect
+		 * 	reconnect_attempt
+		 * 	reconnect_failed
+		 * 	reconnect_error
+		 * 	reconnecting
+		 * 	ping
+		 * 	pong
+		 * then the event is emitted normally. Otherwise, if we're connected, the
+		 * event is sent. Otherwise, it's buffered.
+		 *
+		 * If the last argument is a function, then it will be called
+		 * as an 'ack' when the response is received. The parameter(s) of the
+		 * ack will be whatever data is returned from the event
+		 * @param event The event that we're emitting
+		 * @param args Optional arguments to send with the event
+		 * @return This Socket
+		 */
+		emit( event: string, ...args: any[] ):Socket;
+
+		/**
+		 * Disconnects the socket manually
+		 * @return This Socket
+		 */
+		close():Socket;
+
+		/**
+		 * @see close()
+		 */
+		disconnect():Socket;
+
+		/**
+		* Sets the compress flag.
+		* @param compress If `true`, compresses the sending data
+		* @return this Socket
+		*/
+		compress(compress: boolean):Socket;
+	}
+
+	/**
+	 * The Manager static interface
+	 */
+	interface ManagerStatic {
+		/**
+		 * Creates a new Manager
+		 * @param uri The URI that we're connecting to (e.g. http://localhost:4000)
+		 * @param opts Any connection options that we want to use (and pass to engine.io)
+		 * @return A Manager
+		 */
+		( uri: string, opts?: SocketIOClient.ConnectOpts ): SocketIOClient.Manager;
+
+		/**
+		 * Creates a new Manager with the default URI (window host)
+		 * @param opts Any connection options that we want to use (and pass to engine.io)
+		 */
+		( opts: SocketIOClient.ConnectOpts ):SocketIOClient.Manager;
+
+		/**
+		 * @see default constructor
+		 */
+		new ( uri: string, opts?: SocketIOClient.ConnectOpts ): SocketIOClient.Manager;
+
+		/**
+		 * @see default constructor
+		 */
+		new ( opts: SocketIOClient.ConnectOpts ):SocketIOClient.Manager;
+	}
+
+	/**
+	 * The Manager class handles all the Namespaces and Sockets that we're using
+	 */
+	interface Manager extends Emitter {
+
+		/**
+		 * All the namespaces currently controlled by this Manager, and the Sockets
+		 * that we're using to communicate with them
+		 */
+		nsps: { [namespace:string]: Socket };
+
+		/**
+		 * The connect options that we used when creating this Manager
+		 */
+		opts: SocketIOClient.ConnectOpts;
+
+		/**
+		 * The state of the Manager. Either 'closed', 'opening', or 'open'
+		 */
+		readyState: string;
+
+		/**
+		 * The URI that this manager is for (host + port), e.g. 'http://localhost:4000'
+		 */
+		uri: string;
+
+		/**
+		 * The currently connected sockets
+		 */
+		connecting: Socket[];
+
+		/**
+		 * If we should auto connect (also used when creating Sockets). Set via the
+		 * opts object
+		 */
+		autoConnect: boolean;
+
+		/**
+		 * Gets if we should reconnect automatically
+		 * @default true
+		 */
+		reconnection(): boolean;
+
+		/**
+		 * Sets if we should reconnect automatically
+		 * @param v True if we should reconnect automatically, false otherwise
+		 * @default true
+		 * @return This Manager
+		 */
+		reconnection( v: boolean ): Manager;
+
+		/**
+		 * Gets the number of reconnection attempts we should try before giving up
+		 * @default Infinity
+		 */
+		reconnectionAttempts(): number;
+
+		/**
+		 * Sets the number of reconnection attempts we should try before giving up
+		 * @param v The number of attempts we should do before giving up
+		 * @default Infinity
+		 * @return This Manager
+		 */
+		reconnectionAttempts( v: number ): Manager;
+
+		/**
+		 * Gets the delay in milliseconds between each reconnection attempt
+		 * @default 1000
+		 */
+		reconnectionDelay(): number;
+
+		/**
+		 * Sets the delay in milliseconds between each reconnection attempt
+		 * @param v The delay in milliseconds
+		 * @default 1000
+		 * @return This Manager
+		 */
+		reconnectionDelay( v: number ): Manager;
+
+		/**
+		 * Gets the max reconnection delay in milliseconds between each reconnection
+		 * attempt
+		 * @default 5000
+		 */
+		reconnectionDelayMax(): number;
+
+		/**
+		 * Sets the max reconnection delay in milliseconds between each reconnection
+		 * attempt
+		 * @param v The max reconnection dleay in milliseconds
+		 * @return This Manager
+		 */
+		reconnectionDelayMax( v: number ): Manager;
+
+		/**
+		 * Gets the randomisation factor used in the exponential backoff jitter
+		 * when reconnecting
+		 * @default 0.5
+		 */
+		randomizationFactor(): number;
+
+		/**
+		 * Sets the randomisation factor used in the exponential backoff jitter
+		 * when reconnecting
+		 * @param The reconnection randomisation factor
+		 * @default 0.5
+		 * @return This Manager
+		 */
+		randomizationFactor( v: number ): Manager;
+
+		/**
+		 * Gets the timeout in milliseconds for our connection attempts
+		 * @default 20000
+		 */
+		timeout(): number;
+
+		/**
+		 * Sets the timeout in milliseconds for our connection attempts
+		 * @param The connection timeout milliseconds
+		 * @return This Manager
+		 */
+		timeout(v: boolean): Manager;
+
+		/**
+		 * Sets the current transport socket and opens our connection
+		 * @param fn An optional callback to call when our socket has either opened, or
+		 * failed. It can take one optional parameter of type Error
+		 * @return This Manager
+		 */
+		open( fn?: (err?: any) => void ): Manager;
+
+		/**
+		 * @see open( fn );
+		 */
+		connect( fn?: (err?: any) => void ): Manager;
+
+		/**
+		 * Creates a new Socket for the given namespace
+		 * @param nsp The namespace that this Socket is for
+		 * @return A new Socket, or if one has already been created for this namespace,
+		 * an existing one
+		 */
+		socket( nsp: string ): Socket;
+	}
+
+	/**
+	 * Options we can pass to the socket when connecting
+	 */
+	interface ConnectOpts {
+
+		/**
+		 * Should we force a new Manager for this connection?
+		 * @default false
+		 */
+		forceNew?: boolean;
+
+		/**
+		 * Should we multiplex our connection (reuse existing Manager) ?
+		 * @default true
+		 */
+		multiplex?: boolean;
+
+		/**
+		 * The path to get our client file from, in the case of the server
+		 * serving it
+		 * @default '/socket.io'
+		 */
+		path?: string;
+
+		/**
+		 * Should we allow reconnections?
+		 * @default true
+		 */
+		reconnection?: boolean;
+
+		/**
+		 * How many reconnection attempts should we try?
+		 * @default Infinity
+		 */
+		reconnectionAttempts?: number;
+
+		/**
+		 * The time delay in milliseconds between reconnection attempts
+		 * @default 1000
+		 */
+		reconnectionDelay?: number;
+
+		/**
+		 * The max time delay in milliseconds between reconnection attempts
+		 * @default 5000
+		 */
+		reconnectionDelayMax?: number;
+
+		/**
+		 * Used in the exponential backoff jitter when reconnecting
+		 * @default 0.5
+		 */
+		randomizationFactor?: number;
+
+		/**
+		 * The timeout in milliseconds for our connection attempt
+		 * @default 20000
+		 */
+		timeout?: number;
+
+		/**
+		 * Should we automically connect?
+		 * @default true
+		 */
+		autoConnect?: boolean;
+
+		/**
+		 * The host that we're connecting to. Set from the URI passed when connecting
+		 */
+		host?: string;
+
+		/**
+		 * The hostname for our connection. Set from the URI passed when connecting
+		 */
+		hostname?: string;
+
+		/**
+		 * If this is a secure connection. Set from the URI passed when connecting
+		 */
+		secure?: boolean;
+
+		/**
+		 * The port for our connection. Set from the URI passed when connecting
+		 */
+		port?: string;
+
+		/**
+		 * Any query parameters in our uri. Set from the URI passed when connecting
+		 */
+		query?: Object;
+
+		/**
+		 * `http.Agent` to use, defaults to `false` (NodeJS only)
+		 */
+		agent?: string|boolean;
+
+		/**
+		 * Whether the client should try to upgrade the transport from
+		 * long-polling to something better.
+		 * @default true
+		 */
+		upgrade?: boolean;
+
+		/**
+		 * Forces JSONP for polling transport.
+		 */
+		forceJSONP?: boolean;
+
+		/**
+		 * Determines whether to use JSONP when necessary for polling. If
+		 * disabled (by settings to false) an error will be emitted (saying
+		 * "No transports available") if no other transports are available.
+		 * If another transport is available for opening a connection (e.g.
+		 * WebSocket) that transport will be used instead.
+		 * @default true
+		 */
+		jsonp?: boolean;
+
+		/**
+		 * Forces base 64 encoding for polling transport even when XHR2
+		 * responseType is available and WebSocket even if the used standard
+		 * supports binary.
+		 */
+		forceBase64?: boolean;
+
+		/**
+		 * Enables XDomainRequest for IE8 to avoid loading bar flashing with
+		 * click sound. default to `false` because XDomainRequest has a flaw
+		 * of not sending cookie.
+		 * @default false
+		 */
+		enablesXDR?: boolean;
+
+		/**
+		 * The param name to use as our timestamp key
+		 * @default 't'
+		 */
+		timestampParam?: string;
+
+		/**
+		 * Whether to add the timestamp with each transport request. Note: this
+		 * is ignored if the browser is IE or Android, in which case requests
+		 * are always stamped
+		 * @default false
+		 */
+		timestampRequests?: boolean;
+
+		/**
+		 * A list of transports to try (in order). Engine.io always attempts to
+		 * connect directly with the first one, provided the feature detection test
+		 * for it passes.
+		 * @default ['polling','websocket']
+		 */
+		transports?: string[];
+
+		/**
+		 * The port the policy server listens on
+		 * @default 843
+		 */
+		policyPost?: number;
+
+		/**
+		 * If true and if the previous websocket connection to the server succeeded,
+		 * the connection attempt will bypass the normal upgrade process and will
+		 * initially try websocket. A connection attempt following a transport error
+		 * will use the normal upgrade process. It is recommended you turn this on
+		 * only when using SSL/TLS connections, or if you know that your network does
+		 * not block websockets.
+		 * @default false
+		 */
+		rememberUpgrade?: boolean;
+
+		/**
+		 * Are we only interested in transports that support binary?
+		 */
+		onlyBinaryUpgrades?: boolean;
+
+		/**
+		 * (SSL) Certificate, Private key and CA certificates to use for SSL.
+		 * Can be used in Node.js client environment to manually specify
+		 * certificate information.
+		 */
+		pfx?: string;
+
+		/**
+		 * (SSL) Private key to use for SSL. Can be used in Node.js client
+		 * environment to manually specify certificate information.
+		 */
+		key?: string;
+
+		/**
+		 * (SSL) A string or passphrase for the private key or pfx. Can be
+		 * used in Node.js client environment to manually specify certificate
+		 * information.
+		 */
+		passphrase?: string
+
+		/**
+		 * (SSL) Public x509 certificate to use. Can be used in Node.js client
+		 * environment to manually specify certificate information.
+		 */
+		cert?: string;
+
+		/**
+		 * (SSL) An authority certificate or array of authority certificates to
+		 * check the remote host against.. Can be used in Node.js client
+		 * environment to manually specify certificate information.
+		 */
+		ca?: string|string[];
+
+		/**
+		 * (SSL) A string describing the ciphers to use or exclude. Consult the
+		 * [cipher format list]
+		 * (http://www.openssl.org/docs/apps/ciphers.html#CIPHER_LIST_FORMAT) for
+		 * details on the format.. Can be used in Node.js client environment to
+		 * manually specify certificate information.
+		 */
+		ciphers?: string;
+
+		/**
+		 * (SSL) If true, the server certificate is verified against the list of
+		 * supplied CAs. An 'error' event is emitted if verification fails.
+		 * Verification happens at the connection level, before the HTTP request
+		 * is sent. Can be used in Node.js client environment to manually specify
+		 * certificate information.
+		 */
+		rejectUnauthorized?: boolean;
+
+	}
+}
diff --git a/typings/globals/socket.io-client/typings.json b/typings/globals/socket.io-client/typings.json
new file mode 100644
index 0000000..f29e7a2
--- /dev/null
+++ b/typings/globals/socket.io-client/typings.json
@@ -0,0 +1,8 @@
+{
+  "resolution": "main",
+  "tree": {
+    "src": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/7de6c3dd94feaeb21f20054b9f30d5dabc5efabd/socket.io-client/socket.io-client.d.ts",
+    "raw": "registry:dt/socket.io-client#1.4.4+20160317120654",
+    "typings": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/7de6c3dd94feaeb21f20054b9f30d5dabc5efabd/socket.io-client/socket.io-client.d.ts"
+  }
+}
diff --git a/typings/index.d.ts b/typings/index.d.ts
index dfa460a..b0a5fb0 100644
--- a/typings/index.d.ts
+++ b/typings/index.d.ts
@@ -7,3 +7,4 @@
 /// <reference path="globals/jasmine/index.d.ts" />
 /// <reference path="globals/jquery/index.d.ts" />
 /// <reference path="globals/require/index.d.ts" />
+/// <reference path="globals/socket.io-client/index.d.ts" />