diff --git a/joData/joData-tests.ts b/joData/joData-tests.ts
new file mode 100644
index 0000000000..62dd1569ce
--- /dev/null
+++ b/joData/joData-tests.ts
@@ -0,0 +1,192 @@
+///
+
+var query = new jo('http://test.com');
+
+// Base URI
+query.baseUri;
+
+// To string
+query.toString();
+
+// Order by
+query.orderBy('PropertyName');
+query.orderBy('PropertyName').asc();
+query.orderBy('PropertyName').desc();
+query.orderBy('PropertyName').asc().desc();
+query.resetOrderBy();
+query.setOrderByDefault('PropertyName');
+query.toggleOrderBy('CustomerId'); // TODO Example with callback.
+
+query
+ .setOrderByDefault('p1', 'desc')
+ .orderBy('p2')
+ .asc();
+
+// Top
+query.top(10);
+query.resetTop();
+query.setTopDefault(5);
+query
+ .setTopDefault(5)
+ .top(10);
+
+// Skip
+query.skip(5);
+query.resetSkip();
+query.setSkipDefault(5);
+query
+ .setSkipDefault(5)
+ .skip(10);
+
+// Select
+query.select(['Property1', 'Property2']);
+query.resetSelect();
+query.setSelectDefault(['CustomerId', 'CustomerName']);
+query
+ .setSelectDefault(['CustomerId', 'CustomerName'])
+ .select(['CustomerId', 'CustomerName', 'Address']);
+
+// Expand
+query.expand('Customer');
+query.resetExpand();
+query.setExpandDefault('Customer');
+query
+ .setExpandDefault('Customer')
+ .expand('Product');
+
+// Format
+query.format().atom();
+query.format().xml();
+query.format().json();
+query.format().custom('text/csv');
+
+query.formatDefault().atom();
+
+query
+ .formatDefault()
+ .atom()
+ .format()
+ .json();
+
+query.resetFormat();
+
+// Inlinecount
+query.inlineCount().allPages();
+query.inlineCount().none();
+
+query.inlineCountDefault().allPages();
+
+query
+ .inlineCountDefault()
+ .allPages()
+ .inlineCount()
+ .none();
+
+query.resetInlineCount();
+
+// Filter
+var clause = new jo.FilterClause('PropertyName');
+clause.eq(5);
+query.filter(clause);
+
+query
+ .andFilter(new jo.FilterClause('Property1').eq(5))
+ .andFilter(new jo.FilterClause('Property2').eq(10));
+
+query
+ .orFilter(new jo.FilterClause('Property1').eq(5))
+ .orFilter(new jo.FilterClause('Property2').eq(10));
+
+query
+ .filter(new jo.FilterClause('p1').eq(1))
+ .andFilter(new jo.FilterClause('p2').eq(5))
+ .orFilter(new jo.FilterClause('p3').eq(10));
+
+query.removeFilter('CustomerName');
+
+var clause = new jo.FilterClause('CustomerId');
+clause.isEmpty();
+
+var clause = new jo.FilterClause('CustomerId').eq(1);
+clause.isEmpty();
+
+query.andFilter(new jo.FilterClause('Status').eq('Pending'));
+query.captureFilter();
+query.resetToCapturedFilter();
+query.resetFilter();
+
+// Casts
+query.filter(new jo.FilterClause('DateAdded').eq(jo.datetime('2013-03-01')));
+query.filter(new jo.FilterClause('CustomerId').eq(jo.guid('3F2504E0-4F89-11D3-9A0C-0305E82C3301')));
+query.filter(new jo.FilterClause('Price').eq(jo.decimal(24.97)));
+query.filter(new jo.FilterClause('Price').eq(jo.single(24.97)));
+query.filter(new jo.FilterClause('Price').eq(jo.double(24.97)));
+
+// Logical Operators
+query.filter(new jo.FilterClause('PropertyName').eq('test'));
+query.filter(new jo.FilterClause('PropertyName').eq(10));
+query.filter(new jo.FilterClause('CustomerName').not().eq('bob'));
+query.filter(new jo.FilterClause('CustomerName').not().endswith('bob'));
+
+// Precedence Groups
+var group = new jo.PrecedenceGroup(new jo.FilterClause('Name').eq('Bob'));
+query.filter(group);
+
+var group2 = new jo.PrecedenceGroup(new jo.FilterClause('Name').eq('Bob')).orFilter(new jo.FilterClause('Name').eq('George'));
+query.filter(group2);
+
+query
+ .filter(new jo.FilterClause('Id').eq(1))
+ .andFilter(new jo.PrecedenceGroup(new jo.FilterClause('Name').startswith('a').eq(true))
+ .orFilter(new jo.FilterClause('Name').startswith('b').eq(true)));
+
+// Setting filter defaults
+query.defaultFilter(new jo.FilterClause('Id').eq(1));
+query
+ .defaultFilter(new jo.FilterClause('Id').eq(1))
+ .filter(new jo.FilterClause('Name').eq('bob'));
+query
+ .defaultFilter(new jo.FilterClause('Id').eq(1))
+ .filter(new jo.FilterClause('Name').eq('bob'));
+query.resetFilter();
+
+// Arithmetic Methods
+query.filter(new jo.FilterClause('PropertyName').add(5).eq(10));
+
+// String Functions
+query.filter(new jo.FilterClause('PropertyName').substringof('test').eq(true));
+query.filter(new jo.FilterClause('PropertyName').toLower().substringof('test').eq(true));
+query.filter(new jo.FilterClause('PropertyName').endswith('test').eq(true));
+query.filter(new jo.FilterClause('PropertyName').startswith('test').eq(true));
+query.filter(new jo.FilterClause('PropertyName').length().eq(10));
+query.filter(new jo.FilterClause('PropertyName').indexof('test').eq(1));
+query.filter(new jo.FilterClause('PropertyName').replace('test', 'bob').eq('bob'));
+query.filter(new jo.FilterClause('PropertyName').substring(1).eq('test'));
+query.filter(new jo.FilterClause('PropertyName').substring(1,2).eq('test'));
+query.filter(new jo.FilterClause('PropertyName').toLower().eq('test'));
+query.filter(new jo.FilterClause('PropertyName').toUpper().eq('TEST'));
+query.filter(new jo.FilterClause('PropertyName').trim().eq('test'));
+
+// Concat
+query.filter(new jo.FilterClause().Concat(new jo.Concat('FirstName', 'LastName')).eq('BobSmith'));
+query.filter(new jo.FilterClause().Concat(new jo.Concat(new jo.Concat('City', jo.literal(', ')), 'State')).eq('Birmingham, Alabama'));
+
+// Date Functions
+query.filter(new jo.FilterClause('Birthday').day().eq(2));
+query.filter(new jo.FilterClause('Birthday').hour().eq(2));
+query.filter(new jo.FilterClause('Birthday').minute().eq(2));
+query.filter(new jo.FilterClause('Birthday').month().eq(2));
+query.filter(new jo.FilterClause('Birthday').second().eq(2));
+query.filter(new jo.FilterClause('Birthday').year().eq(2));
+
+// Math Functions
+query.filter(new jo.FilterClause('Price').round().eq(2));
+query.filter(new jo.FilterClause('Price').floor().eq(2));
+query.filter(new jo.FilterClause('Price').ceiling().eq(2));
+
+// Saving Local
+query.saveLocal();
+jo.loadLocal();
+
+query.saveLocal("key");
+jo.loadLocal("key");
\ No newline at end of file
diff --git a/joData/joData.d.ts b/joData/joData.d.ts
new file mode 100644
index 0000000000..f2d6ce4120
--- /dev/null
+++ b/joData/joData.d.ts
@@ -0,0 +1,229 @@
+// Type definitions for joData v1.1
+// Project: https://github.com/mccow002/joData
+// Definitions by: Chris Wrench
+// Definitions: https://github.com/borisyankov/DefinitelyTyped
+
+declare class jo
+{
+ constructor(baseUri: string);
+
+ baseUri: string;
+ ExpandSettings: jo.ExpandSettings;
+ FilterSettings: jo.InlineCountSettings;
+ FormatSettings: jo.FormatSettings;
+ InlineCountSettings: jo.InlineCountSettings;
+ OrderBySettings: jo.OrderBySettings;
+ SelectSettings: jo.SelectSettings;
+ SkipSettings: jo.SkipSettings;
+ TopSettings: jo.TopSettings;
+
+ currentHashRoute: string;
+ updateHashRoute: (hashRoute: string) => void;
+
+ // Order by
+ setOrderByDefault(property: string, order?: string): jo;
+ toggleOrderBy(property: string, callback?: Function): jo;
+ orderBy(property: string): jo;
+ desc(): jo;
+ asc(): jo;
+ resetOrderBy(): jo;
+
+ // Top
+ setTopDefault(top: number): jo;
+ top(top: number): jo;
+ resetTop(): jo;
+
+ // Skip
+ setSkipDefault(skip: number): jo;
+ skip(skip: number): jo;
+ resetSkip(): jo;
+
+ // Select
+ setSelectDefault(select: string[]): jo;
+ select(select: string[]): jo;
+ resetSelect(): jo;
+
+ // Expand
+ setExpandDefault(expand: string): jo;
+ expand(expand: string): jo;
+ resetExpand(): jo;
+
+ // Format
+ format(): jo.FormatOptions;
+ formatDefault(): jo.FormatOptions;
+ resetFormat(): void;
+
+ // Inline count
+ inlineCount(): jo.InlineCountOptions;
+ inlineCountDefault(): jo.InlineCountOptions;
+ resetInlineCount(): void;
+
+ // Filter
+ filter(filterClause: jo.FilterClause|jo.PrecedenceGroup): jo;
+ andFilter(filterClause: jo.FilterClause|jo.PrecedenceGroup): jo;
+ orFilter(filterClause: jo.FilterClause|jo.PrecedenceGroup): jo;
+ removeFilter(property: string): jo;
+ captureFilter(): void;
+ resetFilter(): jo;
+ resetToCapturedFilter(): jo;
+ defaultFilter(filterClause: jo.FilterClause): jo;
+ defaultAndFilter(filterClause: jo.FilterClause): jo;
+ defaultOrFilter(filterClause: jo.FilterClause): jo;
+
+ // Casts
+ static literal: (stringLiteral: string) => string;
+ static datetime: (stringLiteral: string) => string;
+ static guid: (stringLiteral: string) => string;
+ static decimal: (stringLiteral: number) => string;
+ static double: (stringLiteral: number) => string;
+ static single: (stringLiteral: number) => string;
+
+ toString: () => string;
+ toJson: () => string;
+ saveLocal: (key?: string) => void;
+
+ static loadLocal: (key?: string) => jo;
+}
+
+declare module jo {
+ interface FormatOptions {
+ atom(): jo;
+ custom(value: string): jo;
+ json(): jo;
+ xml(): jo;
+ }
+
+ interface InlineCountOptions {
+ allPages(): jo;
+ none(): jo;
+ }
+
+ export class FilterClause {
+ constructor();
+ constructor(property: string);
+
+ toString(): string;
+ isEmpty(): Boolean;
+
+ Property: string;
+ Components: string[];
+ IsClauseEmpty: Boolean;
+ PropertyIncluded: Boolean;
+ UsingNot: Boolean;
+ Value: any;
+ FuncReturnType: any;
+ transformFunc: Function;
+
+ // Logical operators
+ eq(value: string|number|boolean): jo.FilterClause;
+ ne(value: string|number|boolean): jo.FilterClause;
+ gt(value: string|number|boolean): jo.FilterClause;
+ ge(value: string|number|boolean): jo.FilterClause;
+ lt(value: string|number|boolean): jo.FilterClause;
+ le(value: string|number|boolean): jo.FilterClause;
+ not(): jo.FilterClause;
+
+ // Arithmetic methods
+ add(amount: number): jo.FilterClause;
+ sub(amount: number): jo.FilterClause;
+ mul(amount: number): jo.FilterClause;
+ div(amount: number): jo.FilterClause;
+ mod(amount: number): jo.FilterClause;
+
+ // String functions
+ substringof(value: string): jo.FilterClause;
+ substring(position: number, length?: number): jo.FilterClause;
+ toLower(): jo.FilterClause;
+ toUpper(): jo.FilterClause;
+ trim(): jo.FilterClause;
+ endswith(value: string): jo.FilterClause;
+ startswith(value: string): jo.FilterClause;
+ length(): jo.FilterClause;
+ indexof(value: string): jo.FilterClause;
+ replace(find: string, replace: string): jo.FilterClause;
+
+ // Concat
+ Concat(concat: jo.Concat): jo.FilterClause;
+
+ // Date functions
+ day(): jo.FilterClause;
+ hour(): jo.FilterClause;
+ minute(): jo.FilterClause;
+ month(): jo.FilterClause;
+ second(): jo.FilterClause;
+ year(): jo.FilterClause;
+
+ // Math functions
+ round(): jo.FilterClause;
+ floor(): jo.FilterClause;
+ ceiling() : jo.FilterClause;
+ }
+
+ // Precedence groups
+ export class PrecedenceGroup {
+ constructor(filterClause: jo.FilterClause)
+ andFilter(filterClause: jo.FilterClause): jo.FilterClause;
+ orFilter(filterClause: jo.FilterClause): jo.FilterClause;
+ }
+
+ // Concat
+ export class Concat {
+ constructor(value1: string|jo.Concat, value2: string|jo.Concat)
+ LeftSide: string|jo.Concat;
+ RightSide: string|jo.Concat;
+ toString(): string;
+ }
+
+ // TODO What is the most appropriate place for these interfaces?
+ // They are only required by the `jo` class.
+ interface ISettings {
+ toString: () => string;
+ reset: () => void;
+ isSet: () => Boolean;
+ }
+
+ interface OrderBySettings extends ISettings {
+ Property: string;
+ Order: string;
+ DefaultProperty:string;
+ DefaultOrder: string;
+ }
+
+ interface TopSettings extends ISettings {
+ Top: number;
+ DefaultTop: number;
+ }
+
+ interface SkipSettings extends ISettings {
+ Skip: number;
+ DefaultSkip: number;
+ }
+
+ interface SelectSettings extends ISettings {
+ Select: string[];
+ DefaultSelect: string[];
+ }
+
+ interface ExpandSettings extends ISettings {
+ Expand: string;
+ DefaultExpand: string;
+ }
+
+ interface FormatSettings extends ISettings {
+ Format: string;
+ DefaultFormat: string;
+ }
+
+ interface InlineCountSettings extends ISettings {
+ InlineCount: string;
+ DefaultInlineCount: string;
+ }
+
+ interface FilterSettings extends ISettings {
+ Filters: FilterClause[];
+ DefaultFilters: FilterClause[];
+ CapturedFilter: FilterClause[];
+ fullReset: () => void;
+ loadFromJson: (filterSettings: any) => void;
+ }
+}