Preparation to bower release
diff --git a/.bowerrc b/.bowerrc
new file mode 100644
index 0000000..637d54e
--- /dev/null
+++ b/.bowerrc
@@ -0,0 +1,3 @@
+{
+  "directory": "./bower_components"
+}
\ No newline at end of file
diff --git a/.eslintrc b/.eslintrc
new file mode 100644
index 0000000..ba3aaee
--- /dev/null
+++ b/.eslintrc
@@ -0,0 +1,45 @@
+{
+    "ecmaFeatures": {
+        "blockBindings": true,
+        "forOf": true,
+        "destructuring": true,
+        "arrowFunctions": true,
+        "templateStrings": true
+    },
+    "env": { 
+        "browser": true,
+        "es6": true
+    },
+    "plugins": [
+        "angular"
+    ],
+    "rules": {
+        "quotes": [2, "single"],
+        "camelcase": [0, {"properties": "always"}],
+        "no-underscore-dangle": 0,
+        "no-undef": [2],
+        "no-var": [2],
+        "eqeqeq": [2, "smart"],
+        "no-alert": 1,
+        "key-spacing": [1, { "beforeColon": false, "afterColon": true }],
+        "indent": [2, 2],
+        "no-irregular-whitespace": 1,
+        "eol-last": 0,
+        "comma-spacing": [1, {"before": false, "after": true}],
+        "no-trailing-spaces": [1, { skipBlankLines: true }],
+        "no-unused-vars": [1, {"vars": "all", "args": "after-used"}],
+        "new-cap": 0,
+        "no-multiple-empty-lines": 2,
+
+        "angular/ng_module_name": [2, '/^xos\.*[a-z]*$/'],
+        "angular/ng_controller_name": [2, '/^[[[a-z].*]*Ctrl$/'],
+        "angular/ng_directive_name": [2, '/^[xos[[A-Z].*]*$/'],
+        "angular/ng_di": [0, "function or array"],
+        "angular/ng_angularelement": 0,
+        "angular/ng_on_watch": 1,
+        "angular/ng_controller_as_vm": 0
+    },
+    "globals" :{
+        "angular": true
+    } 
+}
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..fcbc2bf
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,6 @@
+node_modules/
+bower_components/
+dist/
+docs/
+test-result/
+.tmp/
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..e916c15
--- /dev/null
+++ b/README.md
@@ -0,0 +1,10 @@
+# ngXosLib
+
+Please see the full documentation here:
+http://ngxoslib.wiki.opencord.org/
+
+## Quick Notes
+
+This library has been developer to be used along with the [CORD Project](http://opencord.org/) and in particular to be integrated in [XOS](http://guide.xosproject.org/).
+
+During the process we have developed a set of common bootstrap based UI Component and we decided to release them in the community, that's why you'll find more generated files than you'll need to include also if only the `xosUiComponents.js` is listed in the `bower.json` main section.
\ No newline at end of file
diff --git a/bower.json b/bower.json
new file mode 100644
index 0000000..e137a15
--- /dev/null
+++ b/bower.json
@@ -0,0 +1,49 @@
+{
+  "name": "ngXosLib",
+  "version": "1.0.0",
+  "authors": [
+    "Open Networking Laboratory"
+  ],
+  "description": "A collection of API $resources, Heplers Services and UI Component to work on the XOS UI",
+  "license": "Apache 2.0",
+  "ignore": [
+    "**/.*",
+    "node_modules",
+    "bower_components",
+    "test",
+    "tests",
+    "./bower_components"
+  ],
+  "dependencies": {
+    "angular": "1.4.7",
+    "angular-ui-router": "0.2.15",
+    "angular-resource": "1.4.7",
+    "angular-cookies": "1.4.7",
+    "angular-animate": "1.4.7",
+    "lodash": "~4.11.1",
+    "angular-chart.js": "~0.10.2",
+    "d3": "~3.5.17",
+    "angular-recursion": "~1.0.5"
+  },
+  "devDependencies": {
+    "angular-mocks": "1.4.7",
+    "jasmine-jquery": "~2.1.1",
+    "jquery": "~3.0.0",
+    "bootstrap-sass": "~3.3.6"
+  },
+  "resolutions": {
+    "angular": "1.4.7"
+  },
+  "main": [
+    "./dist/xosUiComponent.js"
+  ],
+  "moduleType": [],
+  "keywords": [
+    "XOS",
+    "CORD",
+    "OPENCORD",
+    "ANGULARJS",
+    "UI-COMPONENTS"
+  ],
+  "homepage": "http://ngxoslib.wiki.opencord.org/#/ngXosLib"
+}
diff --git a/dev/index.html b/dev/index.html
new file mode 100644
index 0000000..8d580ac
--- /dev/null
+++ b/dev/index.html
@@ -0,0 +1,81 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="UTF-8">
+  <title>ngXosLib development environment</title>
+  <!-- bower:css -->
+  <link rel="stylesheet" href="../bower_components/angular-chart.js/dist/angular-chart.css" />
+  <!-- endbower -->
+  <!-- inject:css -->
+  <link rel="stylesheet" href="/xosNgLib.css">
+  <!-- endinject -->
+  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
+</head>
+<body style="padding-top: 50px">
+  <div ng-app="ngXosLib" class="container">
+    <div class="row" ng-controller="testCtrl as vm">
+      <div class="col-xs-12">
+        <xos-table config="vm.config" data="vm.data"></xos-table>
+      </div>
+    </div>
+  </div>
+  <!-- bower:js -->
+  <script src="../bower_components/angular/angular.js"></script>
+  <script src="../bower_components/angular-ui-router/release/angular-ui-router.js"></script>
+  <script src="../bower_components/angular-resource/angular-resource.js"></script>
+  <script src="../bower_components/angular-cookies/angular-cookies.js"></script>
+  <script src="../bower_components/angular-animate/angular-animate.js"></script>
+  <script src="../bower_components/lodash/lodash.js"></script>
+  <script src="../bower_components/Chart.js/Chart.js"></script>
+  <script src="../bower_components/angular-chart.js/dist/angular-chart.js"></script>
+  <script src="../bower_components/d3/d3.js"></script>
+  <script src="../bower_components/angular-recursion/angular-recursion.js"></script>
+  <!-- endbower -->
+  <!-- inject:js -->
+  <script src="/ui_components/ui-components.module.js"></script>
+  <script src="/ui_components/smartComponents/smartPie/smartPie.component.js"></script>
+  <script src="/ui_components/smartComponents/smartTable/smartTable.component.js"></script>
+  <script src="/ui_components/dumbComponents/table/table.component.js"></script>
+  <script src="/ui_components/dumbComponents/validation/validation.component.js"></script>
+  <script src="/ui_components/dumbComponents/pagination/pagination.component.js"></script>
+  <script src="/ui_components/dumbComponents/form/form.component.js"></script>
+  <script src="/ui_components/dumbComponents/field/field.component.js"></script>
+  <script src="/ui_components/dumbComponents/alert/alert.component.js"></script>
+  <script src="/services/helpers/ui/label_formatter.service.js"></script>
+  <script src="/services/helpers/ui/form.helpers.js"></script>
+  <script src="/services/helpers/ui/comparator.service.js"></script>
+  <script src="/xosHelpers.module.js"></script>
+  <script src="/services/rest/vSG.js"></script>
+  <script src="/services/rest/vOLT.js"></script>
+  <script src="/services/rest/Utility.js"></script>
+  <script src="/services/rest/Users.js"></script>
+  <script src="/services/rest/Truckroll.js"></script>
+  <script src="/services/rest/Tenant.js"></script>
+  <script src="/services/rest/Subscribers.js"></script>
+  <script src="/services/rest/Slices_plus.js"></script>
+  <script src="/services/rest/Slices.js"></script>
+  <script src="/services/rest/Sites.js"></script>
+  <script src="/services/rest/Services.js"></script>
+  <script src="/services/rest/ONOS-Services.js"></script>
+  <script src="/services/rest/ONOS-Apps.js"></script>
+  <script src="/services/rest/Nodes.js"></script>
+  <script src="/services/rest/Networkstemplates.js"></script>
+  <script src="/services/rest/Networks.js"></script>
+  <script src="/services/rest/Me.js"></script>
+  <script src="/services/rest/Instances.js"></script>
+  <script src="/services/rest/Images.js"></script>
+  <script src="/services/rest/Flavors.js"></script>
+  <script src="/services/rest/Example.js"></script>
+  <script src="/services/rest/Deployments.js"></script>
+  <script src="/services/rest/Dashboards.js"></script>
+  <script src="/services/helpers/user-prefs.service.js"></script>
+  <script src="/services/service_graph.service.js"></script>
+  <script src="/services/notification.service.js"></script>
+  <script src="/services/noHyperlinks.interceptor.js"></script>
+  <script src="/services/log.decorator.js"></script>
+  <script src="/services/csrfToken.interceptor.js"></script>
+  <script src="/index.ngdoc.js"></script>
+  <!-- endinject -->
+  <script src="main.js"></script>
+</body>
+</html>
\ No newline at end of file
diff --git a/dev/main.js b/dev/main.js
new file mode 100644
index 0000000..e858499
--- /dev/null
+++ b/dev/main.js
@@ -0,0 +1,30 @@
+/* eslint-disable angular/ng_module_name */
+(function () {
+  'use strict';
+  console.log('hello!');
+  angular.module('ngXosLib', ['xos.helpers'])
+  .run(function(){
+    console.info('Dev Environment ready!')
+  })
+  .controller('testCtrl', function(){
+
+    // TODO add styles
+
+    this.config = {
+      columns: [
+        {
+          label: '#',
+          prop: 'id',
+        },
+        {
+          label: 'Name:',
+          prop: 'name',
+        }
+      ]
+    };
+
+    this.data = [
+      {id: 1, name: 'Jhon'}
+    ];
+  });
+})();
\ No newline at end of file
diff --git a/gulp/dev.js b/gulp/dev.js
new file mode 100644
index 0000000..ee51e3f
--- /dev/null
+++ b/gulp/dev.js
@@ -0,0 +1,84 @@
+/*eslint-env node */
+(function () {
+  'use strict';
+
+  const gulp = require('gulp');
+  const inject = require('gulp-inject');
+  const angularFilesort = require('gulp-angular-filesort');
+  const wiredep = require('wiredep').stream;
+  const path = require('path');
+  const babel = require('gulp-babel');
+  const sourcemaps = require('gulp-sourcemaps');
+  const browserSync = require('browser-sync').create();
+  module.exports = function(options){
+
+    console.log(options.xosHelperTmp, path.join(__dirname, `../${options.xosHelperTmp}`));
+
+    gulp.task('serveDevEnv', ['babelDev', 'wiredep', 'inject', 'injectStyle'], function(){
+      browserSync.init({
+        server: {
+          baseDir: ['./dev', './.tmp', './dist'],
+          // directory: true,
+          routes: {
+            '/bower_components': 'bower_components'
+          },
+        }
+      });
+
+      gulp.watch([
+        './src/**/*.js'
+      ], ['babelDev']);
+
+      gulp.watch([
+        './src/**/*.scss'
+      ], ['style']);
+
+      gulp.watch([
+        './dev/*.html',
+        './dev/*.js',
+        './.tmp/**/*.js'
+      ], function(){
+        browserSync.reload();
+      });
+    });
+
+    gulp.task('babelDev', function(){
+      return gulp.src(options.xosHelperSource + '**/*.js')
+        .pipe(sourcemaps.init())
+        .pipe(babel({
+          presets: ['es2015']
+        }))
+        .pipe(sourcemaps.write('./maps'))
+        .pipe(gulp.dest(options.xosHelperTmp));
+    });
+
+    gulp.task('inject', function(){
+      const files = gulp.src([
+        `${options.xosHelperTmp}**/*.js`
+      ])
+      .pipe(angularFilesort())
+
+      return gulp.src('./dev/index.html')
+        .pipe(inject(files, {ignorePath: ['.tmp/']}))
+        .pipe(gulp.dest('./dev/'));
+    });
+
+    gulp.task('injectStyle', function(){
+      const files = gulp.src([
+        `${options.ngXosStyles}*.css`
+      ])
+
+      return gulp.src('./dev/index.html')
+        .pipe(inject(files, {ignorePath: ['dist/']}))
+        .pipe(gulp.dest('./dev/'));
+    });
+    
+
+    // inject bower dependencies with wiredep
+    gulp.task('wiredep', function () {
+      return gulp.src('./dev/index.html')
+        .pipe(wiredep({devDependencies: false}))
+        .pipe(gulp.dest('./dev'));
+    });
+  };
+})();
\ No newline at end of file
diff --git a/gulp/docs.js b/gulp/docs.js
new file mode 100644
index 0000000..ab77e1a
--- /dev/null
+++ b/gulp/docs.js
@@ -0,0 +1,74 @@
+/*eslint-env node */
+
+const gulp = require('gulp');
+const gulpDocs = require('gulp-ngdocs');
+const del = require('del');
+const browserSync = require('browser-sync').create();
+
+module.exports = function(options){
+
+  gulp.task('cleanDocs', function(){
+    return del([options.docs + '**/*']);
+  });
+
+  gulp.task('makeDocs', ['cleanDocs'], function(){
+
+    const ngOptions = {
+      scripts: [].concat([
+        `./${options.ngXosVendor}ngXosVendor.min.js`,
+        `./${options.ngXosVendor}ngXosHelpers.min.js`,
+        'https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.7/angular-mocks.js',
+      ]),
+      styles: [
+        `./${options.ngXosStyles}xosNgLib.css`,
+        'https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/css/bootstrap.css',
+      ],
+      html5Mode: false,
+      title: 'XOS Helpers documentation',
+      startPage: '/ngXosLib',
+    }
+
+    return gulpDocs.sections({
+      ngXosLib: {
+        glob: [
+          options.xosHelperSource + '*.js',
+          options.xosHelperSource + 'services/helpers/**/*.js',
+          options.xosHelperSource + 'services/*.js',
+          options.xosHelperSource + 'ui_components/**/*.js'
+        ],
+        title: 'Module Documentation',
+      },
+      'rest-api': {
+        glob: [
+          options.xosHelperSource + 'services/rest/*.js'
+        ],
+        api: true,
+        title: 'API Documentation',
+      }
+    }).pipe(gulpDocs.process(ngOptions)).pipe(gulp.dest('./docs'));
+  });
+
+  gulp.task('serveDocs', function(){
+    browserSync.init({
+      server: {
+        baseDir: './docs',
+      }
+    });
+  });
+
+  gulp.task('docs', ['makeDocs', 'serveDocs'], function(){
+    
+    const files = [
+      options.xosHelperSource + '**/*.js',
+    ];
+
+    gulp.watch(files, ['makeDocs']);
+
+    // uncomment to enable autoreload, now it is broken (reload a wrong page)
+    // https://github.com/nikhilmodak/gulp-ngdocs/issues/81
+
+    // gulp.watch(files, function(){
+    //   browserSync.reload();
+    // });
+  });
+};
\ No newline at end of file
diff --git a/gulp/ngXosHelpers.js b/gulp/ngXosHelpers.js
new file mode 100644
index 0000000..4888bdf
--- /dev/null
+++ b/gulp/ngXosHelpers.js
@@ -0,0 +1,85 @@
+/*eslint-env node */
+
+(function () {
+  'use strict';
+
+  const gulp = require('gulp');
+  const uglify = require('gulp-uglify');
+  const concat = require('gulp-concat');
+  const ngAnnotate = require('gulp-ng-annotate');
+  const angularFilesort = require('gulp-angular-filesort');
+  const del = require('del');
+  const babel = require('gulp-babel');
+  const sourcemaps = require('gulp-sourcemaps');
+  const rename = require('gulp-rename');
+  const sass = require('gulp-sass');
+
+  module.exports = function(options){
+
+    // delete previous builded file
+    gulp.task('cleanLib', function(){
+      return del(
+        [
+          `${options.ngXosVendor}/ngXosHelpers.min.js`,
+          `${options.ngXosVendor}/xosUiComponents.js`,
+          `${options.ngXosVendor}/ngXos.css`
+        ],
+        {force: true}
+      );
+    });
+
+    gulp.task('style', function(){
+      return gulp.src(`${options.xosHelperSource}styles/main.scss`)
+        .pipe(sourcemaps.init())
+        .pipe(sass().on('error', sass.logError))
+        .pipe(rename('xosNgLib.css'))
+        .pipe(sourcemaps.write())
+        .pipe(gulp.dest(options.ngXosStyles));
+    });
+
+    // transpile js with sourceMaps
+    gulp.task('babel', function(){
+      return gulp.src(options.xosHelperSource + '**/*.js')
+        .pipe(babel({
+          presets: ['es2015']
+        }))
+        .pipe(gulp.dest(options.xosHelperTmp));
+    });
+
+    // build
+    gulp.task('helpers', ['cleanLib', 'babel', 'style'], function(){
+      return gulp.src([options.xosHelperTmp + '**/*.js'])
+        .pipe(angularFilesort())
+        .pipe(concat('ngXosHelpers.min.js'))
+        .pipe(ngAnnotate())
+        .pipe(uglify())
+        .pipe(gulp.dest(options.ngXosVendor));
+    });
+
+    // build Dev (no minify, sourcemaps), for development purposes
+    // gulp.task('helpersDev', ['babelDev'], function(){
+    //   return gulp.src([options.xosHelperTmp + '**/*.js'])
+    //     .pipe(angularFilesort())
+    //     .pipe(concat('ngXosHelpers.js'))
+    //     .pipe(ngAnnotate())
+    //     .pipe(gulp.dest(options.ngXosVendor));
+    // });
+
+    // concat only UI Components (for free use)
+    gulp.task('uiLibrary', function(){
+      return gulp.src([
+        options.xosHelperTmp + '**/*.js',
+        !options.xosHelperTmp + 'services/rest/*.js'
+      ])
+        .pipe(angularFilesort())
+        .pipe(concat('xosUiComponents.js'))
+        .pipe(ngAnnotate())
+        .pipe(gulp.dest(options.ngXosVendor));
+    });
+
+    gulp.task('dev', function(){
+      gulp.watch(`${options.xosHelperSource}**/*.scss`, ['style']);
+      gulp.watch(options.xosHelperSource + '**/*.js', ['helpersDev']);
+    });
+  };
+})();
\ No newline at end of file
diff --git a/gulp/ngXosVendor.js b/gulp/ngXosVendor.js
new file mode 100644
index 0000000..9e82c23
--- /dev/null
+++ b/gulp/ngXosVendor.js
@@ -0,0 +1,30 @@
+/*eslint-env node */
+(function () {
+  
+  'use strict';
+  const gulp = require('gulp');
+  const uglify = require('gulp-uglify');
+  const concat = require('gulp-concat');
+  const wiredep = require('wiredep');
+  const del = require('del');
+
+  module.exports = function(options){
+
+    gulp.task('cleanVendor', function(){
+      return del(
+        [
+          `${options.ngXosVendor}/ngXosVendor.min.js`
+        ],
+        {force: true}
+      );
+    });
+
+    gulp.task('vendor', ['cleanVendor'], function(){
+      const bowerDeps = wiredep().js;
+      return gulp.src(bowerDeps)
+        .pipe(concat('ngXosVendor.min.js'))
+        .pipe(uglify())
+        .pipe(gulp.dest(options.ngXosVendor));
+    });
+  };
+})();
\ No newline at end of file
diff --git a/gulpfile.js b/gulpfile.js
new file mode 100644
index 0000000..e25e936
--- /dev/null
+++ b/gulpfile.js
@@ -0,0 +1,28 @@
+/*eslint-env node */
+(function () {
+  'use strict';
+
+  const gulp = require('gulp');
+  const wrench = require('wrench');
+  const path = require('path');
+
+  const options = {
+    ngXosVendor: './dist/',
+    ngXosStyles: './dist/',
+    xosHelperSource: './src/',
+    xosHelperTmp: './.tmp/',
+    docs: './docs'
+  };
+
+  wrench.readdirSyncRecursive(path.join(__dirname, './gulp'))
+  .map(function(file) {
+    require(path.join(__dirname, './gulp/' + file))(options);
+  });
+
+  gulp.task('default', function () {
+    gulp.start('build');
+  });
+
+  gulp.task('build', ['vendor', 'helpers', 'uiLibrary']);
+
+})(); 
\ No newline at end of file
diff --git a/karma.conf.ci.js b/karma.conf.ci.js
new file mode 100644
index 0000000..399cdfd
--- /dev/null
+++ b/karma.conf.ci.js
@@ -0,0 +1,123 @@
+/*eslint-env node */
+(function () {
+  
+  'use strict';
+
+  // Karma configuration
+  // Generated on Tue Oct 06 2015 09:27:10 GMT+0000 (UTC)
+
+  const babelPreset = require('babel-preset-es2015');
+
+  /*eslint-disable*/
+
+  var files = [
+    'node_modules/babel-polyfill/dist/polyfill.js',
+
+
+    // loading jquery (it's used in tests)
+    `./bower_components/jquery/dist/jquery.js`,
+    `./bower_components/jasmine-jquery/lib/jasmine-jquery.js`,
+
+    // loading helpers and vendors
+    `./dist/ngXosVendor.min.js`,
+    `./dist/ngXosHelpers.min.js`,
+
+    // loading ngMock
+    `./bower_components/angular-mocks/angular-mocks.js`,
+  ]
+  .concat([
+    // loading tests
+    `spec/test_helpers.js`,
+    'spec/**/*.test.js'
+  ]);
+
+  module.exports = function(config) {
+  /*eslint-enable*/
+    config.set({
+
+      // base path that will be used to resolve all patterns (eg. files, exclude)
+      basePath: '',
+
+
+      // frameworks to use
+      // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
+      frameworks: ['jasmine'],
+
+
+      // list of files / patterns to load in the browser
+      files: files,
+
+
+      // list of files to exclude
+      exclude: [
+      ],
+
+
+      // preprocess matching files before serving them to the browser
+      // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
+      preprocessors: {
+        './spec/**/*.test.js': ['babel'],
+        './spec/test_helpers.js': ['babel'],
+      },
+
+      babelPreprocessor: {
+        options: {
+          presets: [babelPreset],
+          sourceMap: 'inline'
+        }
+      },
+
+      //ngHtml2JsPreprocessor: {
+      //  stripPrefix: 'src/', //strip the src path from template url (http://stackoverflow.com/questions/22869668/karma-unexpected-request-when-testing-angular-directive-even-with-ng-html2js)
+      //  moduleName: 'templates' // define the template module name
+      //},
+
+      // test results reporter to use
+      // possible values: 'dots', 'progress'
+      // available reporters: https://npmjs.org/browse/keyword/karma-reporter
+      reporters: ['dots', 'junit', 'coverage'],
+
+      junitReporter: {
+        outputDir: 'test-result',
+        useBrowserName: false,
+        outputFile: 'test-results.xml'
+      },
+
+      coverageReporter: {
+        type: 'cobertura',
+        subdir: '.',
+        dir: 'test-result/'
+      },
+
+      // web server port
+      port: 9876,
+
+
+      // enable / disable colors in the output (reporters and logs)
+      colors: true,
+
+
+      // level of logging
+      // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
+      logLevel: config.LOG_INFO,
+
+
+      // enable / disable watching file and executing tests whenever any file changes
+      autoWatch: false,
+
+
+      // start these browsers
+      // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
+      browsers: [
+        'PhantomJS',
+        // 'Chrome'
+      ],
+
+
+      // Continuous Integration mode
+      // if true, Karma captures browsers, runs the tests and exits
+      singleRun: true
+    });
+  };
+
+})();
\ No newline at end of file
diff --git a/karma.conf.js b/karma.conf.js
new file mode 100644
index 0000000..76d232c
--- /dev/null
+++ b/karma.conf.js
@@ -0,0 +1,115 @@
+/*eslint-env node */
+(function () {
+  'use strict';
+  // Karma configuration
+  // Generated on Tue Oct 06 2015 09:27:10 GMT+0000 (UTC)
+
+  /* eslint indent: [2,2], quotes: [2, "single"]*/
+
+  // this is to load a different suite of test while developing
+  const testFiles = '*';
+  if(process.argv[4]){
+    testFiles = process.argv[4];
+  }
+
+  /*eslint-disable*/
+  const wiredep = require('wiredep');
+  const path = require('path');
+
+  const bowerComponents = wiredep({
+    devDependencies: true,
+    exclude: [ /bootstrap-sass/],
+  })[ 'js' ]
+  .map(function( file ){
+    return path.relative(process.cwd(), file);
+  });
+
+  const files = bowerComponents.concat([
+    'node_modules/babel-polyfill/dist/polyfill.js',
+    'src/**/*.module.js',
+    'src/**/*.js',
+    `spec/test_helpers.js`,
+    `spec/**/${testFiles}.test.js`
+  ]);
+
+  module.exports = function(config) {
+  /*eslint-enable*/
+    config.set({
+
+      // base path that will be used to resolve all patterns (eg. files, exclude)
+      basePath: '',
+
+
+      // frameworks to use
+      // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
+      frameworks: ['jasmine'],
+
+
+      // list of files / patterns to load in the browser
+      files: files,
+
+
+      // list of files to exclude
+      exclude: [
+      ],
+
+
+      // preprocess matching files before serving them to the browser
+      // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
+      preprocessors: {
+        'src/**/*.js': ['babel'],
+        'spec/**/*.js': ['babel'],
+      },
+
+      babelPreprocessor: {
+        options: {
+          presets: ['es2015'],
+          sourceMap: 'both'
+        },
+        filename: function (file) {
+          return file.originalPath;
+        },
+      },
+
+      //ngHtml2JsPreprocessor: {
+      //  stripPrefix: 'src/', //strip the src path from template url (http://stackoverflow.com/questions/22869668/karma-unexpected-request-when-testing-angular-directive-even-with-ng-html2js)
+      //  moduleName: 'templates' // define the template module name
+      //},
+
+      // test results reporter to use
+      // possible values: 'dots', 'progress'
+      // available reporters: https://npmjs.org/browse/keyword/karma-reporter
+      reporters: ['mocha'],
+
+
+      // web server port
+      port: 9876,
+
+
+      // enable / disable colors in the output (reporters and logs)
+      colors: true,
+
+
+      // level of logging
+      // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
+      logLevel: config.LOG_INFO,
+
+
+      // enable / disable watching file and executing tests whenever any file changes
+      autoWatch: true,
+
+
+      // start these browsers
+      // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
+      browsers: [
+        'PhantomJS',
+         //'Chrome'
+      ],
+
+
+      // Continuous Integration mode
+      // if true, Karma captures browsers, runs the tests and exits
+      singleRun: false
+    });
+  };
+})();
\ No newline at end of file
diff --git a/karma.conf.ui.js b/karma.conf.ui.js
new file mode 100644
index 0000000..5869924
--- /dev/null
+++ b/karma.conf.ui.js
@@ -0,0 +1,125 @@
+/*eslint-env node */
+(function () {
+  
+  'use strict';
+
+  // Karma configuration
+  // Generated on Tue Oct 06 2015 09:27:10 GMT+0000 (UTC)
+
+  const babelPreset = require('babel-preset-es2015');
+
+  /*eslint-disable*/
+
+  var files = [
+    'node_modules/babel-polyfill/dist/polyfill.js',
+
+
+    // loading jquery (it's used in tests)
+    `./bower_components/jquery/dist/jquery.js`,
+    `./bower_components/jasmine-jquery/lib/jasmine-jquery.js`,
+
+    // loading helpers and vendors
+    `./dist/ngXosVendor.min.js`,
+    `./dist/xosUiComponents.js`,
+
+    // loading ngMock
+    `./bower_components/angular-mocks/angular-mocks.js`,
+  ]
+  .concat([
+    // loading tests
+    `spec/test_helpers.js`,
+    `spec/ui/xos.helpers.mock.js`,
+    'spec/ui/**/*.test.js'
+  ]);
+
+  module.exports = function(config) {
+  /*eslint-enable*/
+    config.set({
+
+      // base path that will be used to resolve all patterns (eg. files, exclude)
+      basePath: '',
+
+
+      // frameworks to use
+      // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
+      frameworks: ['jasmine'],
+
+
+      // list of files / patterns to load in the browser
+      files: files,
+
+
+      // list of files to exclude
+      exclude: [
+      ],
+
+
+      // preprocess matching files before serving them to the browser
+      // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
+      preprocessors: {
+        './spec/ui/**/*.test.js': ['babel'],
+        './spec/test_helpers.js': ['babel'],
+        './spec/ui/xos.helpers.mock.js': ['babel']
+      },
+
+      babelPreprocessor: {
+        options: {
+          presets: [babelPreset],
+          sourceMap: 'inline'
+        }
+      },
+
+      //ngHtml2JsPreprocessor: {
+      //  stripPrefix: 'src/', //strip the src path from template url (http://stackoverflow.com/questions/22869668/karma-unexpected-request-when-testing-angular-directive-even-with-ng-html2js)
+      //  moduleName: 'templates' // define the template module name
+      //},
+
+      // test results reporter to use
+      // possible values: 'dots', 'progress'
+      // available reporters: https://npmjs.org/browse/keyword/karma-reporter
+      reporters: ['dots', 'junit', 'coverage'],
+
+      junitReporter: {
+        outputDir: 'test-result',
+        useBrowserName: false,
+        outputFile: 'test-results.xml'
+      },
+
+      coverageReporter: {
+        type: 'cobertura',
+        subdir: '.',
+        dir: 'test-result/'
+      },
+
+      // web server port
+      port: 9876,
+
+
+      // enable / disable colors in the output (reporters and logs)
+      colors: true,
+
+
+      // level of logging
+      // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
+      logLevel: config.LOG_INFO,
+
+
+      // enable / disable watching file and executing tests whenever any file changes
+      autoWatch: false,
+
+
+      // start these browsers
+      // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
+      browsers: [
+        'PhantomJS',
+        // 'Chrome'
+      ],
+
+
+      // Continuous Integration mode
+      // if true, Karma captures browsers, runs the tests and exits
+      singleRun: true
+    });
+  };
+
+})();
\ No newline at end of file
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..f123fad
--- /dev/null
+++ b/package.json
@@ -0,0 +1,62 @@
+{
+  "name": "ng-xos-lib",
+  "version": "1.0.0",
+  "description": "Angular Version of XosLib, containing Helpers and ngResources",
+  "main": "index.js",
+  "scripts": {
+    "test": "karma start karma.conf.js",
+    "test:ci": "karma start karma.conf.ci.js",
+    "test:ui": "karma start karma.conf.ui.js",
+    "docs": "gulp docs; cd ./docs",
+    "docs:ci": "gulp makeDocs;",
+    "build": "gulp build",
+    "dev": "gulp serveDevEnv",
+    "lint:src": "eslint src/",
+    "lint:spec": "eslint spec/",
+    "lint": "npm run lint:src && npm run lint:spec",
+    "postinstall": "cd node_modules/gulp-ngdocs/; npm install"
+  },
+  "author": "Open Networking Laboratory",
+  "license": "Apache 2.0",
+  "dependencies": {
+    "bluebird": "^3.0.5",
+    "chalk": "^1.1.1",
+    "concat": "^2.0.0",
+    "eslint": "^1.8.0",
+    "eslint-plugin-angular": "linkmesrl/eslint-plugin-angular"
+  },
+  "bugs": {
+    "url": "https://jira.opencord.org"
+  },
+  "devDependencies": {
+    "babel-polyfill": "^6.7.4",
+    "babel-preset-es2015": "^6.6.0",
+    "browser-sync": "^2.12.3",
+    "concat": "^2.0.0",
+    "del": "^2.2.0",
+    "gulp": "^3.9.0",
+    "gulp-angular-filesort": "^1.1.1",
+    "gulp-babel": "^6.1.2",
+    "gulp-concat": "^2.6.0",
+    "gulp-inject": "^4.1.0",
+    "gulp-ng-annotate": "^1.1.0",
+    "gulp-ngdocs": "^0.2.13",
+    "gulp-rename": "^1.2.2",
+    "gulp-sass": "^2.3.1",
+    "gulp-sourcemaps": "^1.6.0",
+    "gulp-uglify": "^1.4.2",
+    "jasmine-core": "^2.4.1",
+    "karma": "^0.13.22",
+    "karma-babel-preprocessor": "^6.0.1",
+    "karma-chrome-launcher": "^0.2.3",
+    "karma-coverage": "^0.5.5",
+    "karma-jasmine": "^0.3.6",
+    "karma-junit-reporter": "^0.4.2",
+    "karma-mocha-reporter": "^1.1.3",
+    "karma-ng-html2js-preprocessor": "^0.2.0",
+    "karma-phantomjs-launcher": "^0.2.1",
+    "phantomjs": "^2.1.3",
+    "wiredep": "^3.0.0-beta",
+    "wrench": "^1.5.8"
+  }
+}
diff --git a/spec/.eslintrc b/spec/.eslintrc
new file mode 100644
index 0000000..493c9e2
--- /dev/null
+++ b/spec/.eslintrc
@@ -0,0 +1,24 @@
+{
+  "rules": {
+    "angular/ng_angularelement": 0,
+    "angular/ng_no_digest": 0,
+    "angular/ng_json_functions": 0
+  },
+  "globals" :{
+    "module": true,
+    "describe": true,
+    "xdescribe": true,
+    "it": true,
+    "xit": true,
+    "before": true,
+    "beforeEach": true,
+    "after": true,
+    "afterEach": true,
+    "expect": true,
+    "jasmine": true,
+    "inject": true,
+    "spyOn": true,
+    "$": true,
+    "clickElement": true
+  } 
+}
\ No newline at end of file
diff --git a/spec/csrftoken.test.js b/spec/csrftoken.test.js
new file mode 100644
index 0000000..fd00181
--- /dev/null
+++ b/spec/csrftoken.test.js
@@ -0,0 +1,53 @@
+(function () {
+  'use strict';
+  describe('The xos.helper module', function(){
+    let SetCSRFToken, httpProviderObj, httpBackend, http, cookies;
+
+    const fakeToken = 'aiuhsnds98234ndASd';
+
+    beforeEach(function() {
+      module(
+        'xos.helpers',
+        function ($httpProvider) {
+          //save our interceptor
+          httpProviderObj = $httpProvider;
+        }
+      );
+
+      inject(function (_SetCSRFToken_, _$httpBackend_, _$http_, _$cookies_) {
+        SetCSRFToken = _SetCSRFToken_;
+        httpBackend = _$httpBackend_;
+        http = _$http_;
+        cookies = _$cookies_
+
+        // mocking $cookie service
+        spyOn(cookies, 'get').and.returnValue(fakeToken);
+      });
+
+    });
+
+    describe('the SetCSRFToken', () => {
+      it('should exist', () => {
+        expect(SetCSRFToken).toBeDefined();
+      });
+
+      it('should attach token the request', (done) => {
+        httpBackend.when('POST', 'http://example.com', null, function(headers) {
+          expect(headers['X-CSRFToken']).toBe(fakeToken);
+          done();
+          return headers;
+        }).respond(200, {name: 'example' });
+
+        http.post('http://example.com');
+
+        httpBackend.flush();
+      });
+    });
+    
+    it('should set SetCSRFToken interceptor', () => {
+      expect(httpProviderObj).toBeDefined();
+      expect(httpProviderObj.interceptors).toContain('SetCSRFToken');
+    });
+
+  });
+})();
diff --git a/spec/label_formatter.test.js b/spec/label_formatter.test.js
new file mode 100644
index 0000000..119f4ce
--- /dev/null
+++ b/spec/label_formatter.test.js
@@ -0,0 +1,42 @@
+(function () {
+  'use strict';
+
+  describe('The xos.helper module', function(){
+    describe('The label formatter service', () => {
+
+      let service;
+
+      // load the application module
+      beforeEach(module('xos.helpers'));
+
+      // inject the cartService
+      beforeEach(inject(function (_LabelFormatter_) {
+        // The injector unwraps the underscores (_) from around the parameter names when matching
+        service = _LabelFormatter_;
+      }));
+
+      it('should replace underscores in a string', () => {
+        expect(service._formatByUnderscore('my_test')).toEqual('my test');
+        expect(service._formatByUnderscore('_test')).toEqual('test');
+      });
+
+      it('should split a camel case string', () => {
+        expect(service._formatByUppercase('myTest')).toEqual('my test');
+      });
+
+      it('should capitalize a string', () => {
+        expect(service._capitalize('my test')).toEqual('My test');
+      });
+
+      it('should format an object property to a label', () => {
+        expect(service.format('myWeird_String')).toEqual('My weird string:');
+      });
+
+      it('should not add column if already present', () => {
+        expect(service.format('myWeird_String:')).toEqual('My weird string:');
+      });
+
+    });
+  });
+
+})();
\ No newline at end of file
diff --git a/spec/log.test.js b/spec/log.test.js
new file mode 100644
index 0000000..21085c6
--- /dev/null
+++ b/spec/log.test.js
@@ -0,0 +1,57 @@
+/**
+ * © OpenCORD
+ *
+ * Created by teone on 4/18/16.
+ */
+/* eslint-disable angular/ng_window_service*/
+
+// TODO write tests for log
+// NODE Actually the code is working, the tests are not.
+
+(function () {
+  'use strict';
+
+  xdescribe('The xos.helper module', function(){
+
+    let log, window;
+
+    let mockLog;
+
+    beforeEach(function() {
+      mockLog = jasmine.createSpyObj('logMock', ['info']);
+    });
+
+    beforeEach(function() {
+      angular.mock.module('xos.helpers', function($injector, $provide) {
+        // console.log('$injector',$injector.get('logDecorator'));
+        $provide.value('$log', mockLog);
+        // $provide.decorator('$log', $injector.get('logDecorator'));
+      });
+    });
+
+    beforeEach(inject(($log, $window) => {
+      log = $log;
+      window = $window;
+      // log.reset();
+    }));
+
+    describe('The log decorator', () => {
+      it('should not print anything', inject(($log) => {
+        // spyOn(log, 'info');
+        $log.info('test');
+        expect(mockLog.info).not.toHaveBeenCalled();
+      }));
+
+    });
+    describe('if logging is enabled', () => {
+      beforeEach(() => {
+        window.location.href += '?debug=true'
+      });
+
+      it('should should log', () => {
+        log.info('test');
+        console.log(log.info.logs);
+      });
+    });
+  });
+})();
diff --git a/spec/noHyperlinks.test.js b/spec/noHyperlinks.test.js
new file mode 100644
index 0000000..7b6e9d0
--- /dev/null
+++ b/spec/noHyperlinks.test.js
@@ -0,0 +1,51 @@
+/**
+ * © OpenCORD
+ *
+ * Visit http://guide.xosproject.org/devguide/addview/ for more information
+ *
+ * Created by teone on 3/24/16.
+ */
+
+(function () {
+  'use strict';
+
+  describe('The xos.helper module', function(){
+    describe('The NoHyperlinks factory', () => {
+
+      let httpProviderObj, noHyperlinks;
+
+      beforeEach(() => {
+        module(
+          'xos.helpers',
+          ($httpProvider) => {
+            //save our interceptor
+            httpProviderObj = $httpProvider;
+          }
+        );
+
+        inject(function (_NoHyperlinks_) {
+          noHyperlinks = _NoHyperlinks_
+        });
+
+        httpProviderObj.interceptors.push('NoHyperlinks');
+
+      });
+
+      it('should set NoHyperlinks interceptor', () => {
+        expect(httpProviderObj.interceptors).toContain('NoHyperlinks');
+      });
+
+      it('should attach ?no_hyperlinks=1 to the request url', () => {
+        let result = noHyperlinks.request({url: 'sample.url'});
+        expect(result.url).toEqual('sample.url?no_hyperlinks=1');
+      });
+
+      it('should NOT attach ?no_hyperlinks=1 to the request url if is HTML', () => {
+        let result = noHyperlinks.request({url: 'sample.html'});
+        expect(result.url).toEqual('sample.html');
+      });
+
+    });
+  });
+})();
+
diff --git a/spec/notification.test.js b/spec/notification.test.js
new file mode 100644
index 0000000..cbc1e56
--- /dev/null
+++ b/spec/notification.test.js
@@ -0,0 +1,63 @@
+(function () {
+  'use strict';
+
+  describe('The xos.helper module', function(){
+    describe('The xosNotification service', () => {
+
+      let service, scope;
+
+      const options = {icon: 'icon', body: 'message'};
+
+      let notificationMock = {
+        requestPermission: () => {
+          return {
+            then: cb => cb('granted')
+          }
+        },
+        permission: 'granted'
+      }
+
+
+      // load the application module
+      beforeEach(module('xos.helpers', ($provide) => {
+        $provide.value('Notification', notificationMock);
+      }));
+
+      // inject the cartService
+      beforeEach(inject(function (_xosNotification_, $rootScope) {
+        // The injector unwraps the underscores (_) from around the parameter names when matching
+        service = _xosNotification_;
+        scope = $rootScope;
+        spyOn(service, 'sendNotification');
+        spyOn(service, 'checkPermission').and.callThrough();
+        spyOn(notificationMock, 'requestPermission').and.callThrough();
+      }));
+
+      it('should exist', () => {
+        expect(service).toBeDefined();
+      });
+
+      describe('when permission are granted', () => {
+        it('should send the notification', () => {
+          service.notify('Test', options);
+          expect(service.sendNotification).toHaveBeenCalledWith('Test', options);
+        });
+      });
+
+      describe('when permission are not granted', () => {
+        beforeEach(() => {
+          notificationMock.permission = false;
+        });
+
+        it('should request permission', () => {
+          service.notify('Test', options);
+          expect(service.checkPermission).toHaveBeenCalled();
+          scope.$apply(); // this resolve the promise
+          expect(service.sendNotification).toHaveBeenCalledWith('Test', options);
+        });
+      });
+
+    });
+  });
+
+})();
\ No newline at end of file
diff --git a/spec/services/helpers/comparator.test.js b/spec/services/helpers/comparator.test.js
new file mode 100644
index 0000000..66e26d3
--- /dev/null
+++ b/spec/services/helpers/comparator.test.js
@@ -0,0 +1,60 @@
+(function () {
+  'use strict';
+
+  describe('The xos.helper module', function(){
+    describe('The Comparator service', () => {
+
+      let service;
+
+      // load the application module
+      beforeEach(module('xos.helpers'));
+
+      // inject the cartService
+      beforeEach(inject(function (_Comparator_) {
+        // The injector unwraps the underscores (_) from around the parameter names when matching
+        service = _Comparator_;
+      }));
+
+      describe('given a string', () => {
+        it('should return true if expected is substring of actual', () => {
+          const res = service('test', 'te');
+          expect(res).toBeTruthy();
+        });
+
+        it('should return false if expected is not substring of actual', () => {
+          const res = service('test', 'ab');
+          expect(res).toBeFalsy();
+        });
+      });
+
+      describe('given a boolean', () => {
+        it('should return true if values match', () => {
+          expect(service(false, false)).toBeTruthy();
+          expect(service(true, true)).toBeTruthy();
+          expect(service(0, false)).toBeTruthy();
+          expect(service(1, true)).toBeTruthy();
+        });
+
+        it('should return false if values doesn\'t match', () => {
+          expect(service(false, true)).toBeFalsy();
+          expect(service(true, false)).toBeFalsy();
+          expect(service(1, false)).toBeFalsy();
+          expect(service(0, true)).toBeFalsy();
+        });
+      });
+
+      describe('given a number', () => {
+        // NOTE if numbers should we compare with === ??
+        it('should return true if expected is substring of actual', () => {
+          expect(service(12, 1)).toBeTruthy();
+        });
+
+        it('should return false if expected is not substring of actual', () => {
+          expect(service(12, 3)).toBeFalsy();
+        });
+      });
+
+    });
+  });
+
+})();
\ No newline at end of file
diff --git a/spec/services/helpers/form.helpers.test.js b/spec/services/helpers/form.helpers.test.js
new file mode 100644
index 0000000..a126db5
--- /dev/null
+++ b/spec/services/helpers/form.helpers.test.js
@@ -0,0 +1,335 @@
+/**
+ * © OpenCORD
+ *
+ * Created by teone on 5/25/16.
+ */
+
+(function () {
+  'use strict';
+
+  describe('The xos.helper module', function(){
+
+    describe('The XosFormHelper service', () => {
+      let service;
+
+      let fields = [
+        'id',
+        'name',
+        'mail',
+        'active',
+        'created'
+      ];
+
+      let modelField = {
+        id: {},
+        name: {},
+        mail: {},
+        active: {},
+        created: {}
+      };
+
+      let model = {
+        id: 1,
+        name: 'test',
+        mail: 'test@onlab.us',
+        active: true,
+        created: '2016-04-18T23:44:16.883181Z',
+        custom: 'MyCustomValue'
+      };
+
+      let customField = {
+        id: {
+          label: 'Id',
+          type: 'number',
+          validators: {
+            required: true
+          },
+          hint: ''
+        },
+        custom: {
+          label: 'Custom Label',
+          type: 'number',
+          validators: {},
+          hint: 'Test Hint'
+        }
+      };
+
+      let formObject = {
+        id: {
+          label: 'Id:',
+          type: 'number',
+          validators: {
+            required: true
+          },
+          hint: ''
+        },
+        name: {
+          label: 'Name:',
+          type: 'text',
+          validators: {},
+          hint: ''
+        },
+        mail: {
+          label: 'Mail:',
+          type: 'email',
+          validators: {},
+          hint: ''
+        },
+        active: {
+          label: 'Active:',
+          type: 'boolean',
+          validators: {},
+          hint: ''
+        },
+        created: {
+          label: 'Created:',
+          type: 'date',
+          validators: {},
+          hint: ''
+        },
+        custom: {
+          label: 'Custom Label:',
+          type: 'number',
+          validators: {},
+          hint: 'Test Hint'
+        }
+      };
+
+      // load the application module
+      beforeEach(module('xos.helpers'));
+
+      // inject the cartService
+      beforeEach(inject(function (_XosFormHelpers_) {
+        // The injector unwraps the underscores (_) from around the parameter names when matching
+        service = _XosFormHelpers_;
+      }));
+
+      describe('the _isEmail method', () => {
+        it('should return true', () => {
+          expect(service._isEmail('test@onlab.us')).toEqual(true);
+        });
+        it('should return false', () => {
+          expect(service._isEmail('testonlab.us')).toEqual(false);
+          expect(service._isEmail('test@onlab')).toEqual(false);
+        });
+      });
+
+      describe('the _getFieldFormat method', () => {
+        it('should return text', () => {
+          expect(service._getFieldFormat('a random text')).toEqual('text');
+          expect(service._getFieldFormat(null)).toEqual('text');
+          expect(service._getFieldFormat('1')).toEqual('text');
+        });
+        it('should return mail', () => {
+          expect(service._getFieldFormat('test@onlab.us')).toEqual('email');
+        });
+        it('should return number', () => {
+          expect(service._getFieldFormat(1)).toEqual('number');
+        });
+        it('should return boolean', () => {
+          expect(service._getFieldFormat(false)).toEqual('boolean');
+          expect(service._getFieldFormat(true)).toEqual('boolean');
+        });
+
+        it('should return date', () => {
+          expect(service._getFieldFormat('2016-04-19T23:09:1092Z')).toEqual('text');
+          expect(service._getFieldFormat(new Date())).toEqual('date');
+          expect(service._getFieldFormat('2016-04-19T23:09:10.208092Z')).toEqual('date');
+        });
+
+        it('should return array', () => {
+          expect(service._getFieldFormat([])).toEqual('array');
+          expect(service._getFieldFormat(['a', 'b'])).toEqual('array');
+        });
+
+        it('should return object', () => {
+          expect(service._getFieldFormat({})).toEqual('object');
+          expect(service._getFieldFormat({foo: 'bar'})).toEqual('object');
+        });
+      });
+
+      describe('the parseModelField mehtod', () => {
+        it('should convert the fields array in an empty form object', () => {
+          expect(service.parseModelField(fields)).toEqual(modelField);
+        });
+
+        xit('should handle nested config', () => {
+          
+        });
+      });
+
+      describe('when modelField are provided', () => {
+        it('should combine modelField and customField in a form object', () => {
+          const form = service.buildFormStructure(modelField, customField, model);
+          expect(form).toEqual(formObject);
+        });
+
+        it('should override modelField properties whith customField properties', () => {
+          const customFieldOverride = {
+            id: {
+              hint: 'something',
+              type: 'select',
+              options: [
+                {id: 1, label: 'one'},
+                {id: 2, label: 'two'}
+              ],
+              validators: {
+                required: true
+              }
+            }
+          };
+          const form = service.buildFormStructure({id: {}}, customFieldOverride, model);
+          
+          expect(form).toEqual({
+            id: {
+              label: 'Id:',
+              validators: {required: true},
+              hint: customFieldOverride.id.hint,
+              type: customFieldOverride.id.type,
+              options: customFieldOverride.id.options
+            }
+          });
+        });
+      });
+
+      describe('when model field is an empty array', () => {
+        let empty_modelField = {
+          // 5: {}
+        };
+        let empty_customFields = {
+          id: {
+            label: 'Id',
+            type: 'number'
+          },
+          name: {
+            label: 'Name',
+            type: 'text'
+          },
+          mail: {
+            label: 'Mail',
+            type: 'email'
+          },
+          active: {
+            label: 'Active',
+            type: 'boolean'
+          },
+          created: {
+            label: 'Created',
+            type: 'date'
+          },
+          custom: {
+            label: 'Custom Label',
+            type: 'number',
+            hint: 'Test Hint'
+          },
+          select: {
+            label: 'Select Label',
+            type: 'select',
+            hint: 'Select Hint',
+            options: [
+              {id: 1, label: 'something'}
+            ]
+          },
+          object: {
+            label: 'Object Label',
+            type: 'object',
+            hint: 'Object Hint',
+            properties: {
+              foo: {
+                type: 'string',
+                label: 'FooLabel',
+                validators: {
+                  required: true
+                }
+              },
+              bar: {
+                type: 'number'
+              }
+            }
+          }
+        };
+
+        let empty_formObject = {
+          id: {
+            label: 'Id:',
+            type: 'number',
+            validators: {},
+            hint: ''
+          },
+          name: {
+            label: 'Name:',
+            type: 'text',
+            validators: {},
+            hint: ''
+          },
+          mail: {
+            label: 'Mail:',
+            type: 'email',
+            validators: {},
+            hint: ''
+          },
+          active: {
+            label: 'Active:',
+            type: 'boolean',
+            validators: {},
+            hint: ''
+          },
+          created: {
+            label: 'Created:',
+            type: 'date',
+            validators: {},
+            hint: ''
+          },
+          custom: {
+            label: 'Custom Label:',
+            type: 'number',
+            validators: {},
+            hint: 'Test Hint'
+          },
+          select: {
+            label: 'Select Label:',
+            type: 'select',
+            hint: 'Select Hint',
+            validators: {},
+            options: [
+              {id: 1, label: 'something'}
+            ]
+          },
+          object: {
+            label: 'Object Label:',
+            type: 'object',
+            hint: 'Object Hint',
+            validators: {},
+            properties: {
+              foo: {
+                type: 'string',
+                label: 'FooLabel',
+                validators: {
+                  required: true
+                }
+              },
+              bar: {
+                type: 'number'
+              }
+            }
+          }
+        };
+
+        let empty_model = {5: 'Nan'}
+
+        it('should create a form object', () => {
+          let res = service.buildFormStructure(empty_modelField, empty_customFields, empty_model);
+          expect(res.id).toEqual(empty_formObject.id);
+          expect(res.name).toEqual(empty_formObject.name);
+          expect(res.mail).toEqual(empty_formObject.mail);
+          expect(res.active).toEqual(empty_formObject.active);
+          expect(res.created).toEqual(empty_formObject.created);
+          expect(res.custom).toEqual(empty_formObject.custom);
+          expect(res.select).toEqual(empty_formObject.select);
+          expect(res.object).toEqual(empty_formObject.object);
+          expect(res).toEqual(empty_formObject);
+        });
+      });
+    });
+  });
+})();
\ No newline at end of file
diff --git a/spec/services/helpers/user-prefs.test.js b/spec/services/helpers/user-prefs.test.js
new file mode 100644
index 0000000..63b55c9
--- /dev/null
+++ b/spec/services/helpers/user-prefs.test.js
@@ -0,0 +1,183 @@
+/**
+ * © OpenCORD
+ *
+ * Created by teone on 5/25/16.
+ */
+
+(function () {
+  'use strict';
+
+  let cookies = {
+    xosUserPrefs: JSON.stringify({test: true})
+  };
+
+  const cookieMock = {
+    get: (name) => {
+      return cookies[name]
+    },
+    put: (name, value) => {
+      cookies[name] = value
+    }
+  };
+
+  describe('The xos.helper module', function(){
+
+    describe('The XosUserPrefs service', () => {
+      let service, deffered, rootScope;
+
+      // load the application module
+      beforeEach(module('xos.helpers', ($provide) => {
+        $provide.value('$cookies', cookieMock);
+      }));
+
+      // inject the cartService
+      beforeEach(inject(function (_XosUserPrefs_) {
+        // The injector unwraps the underscores (_) from around the parameter names when matching
+        service = _XosUserPrefs_;
+        spyOn(cookieMock, 'put').and.callThrough();
+      }));
+
+      beforeEach(inject(($q, $rootScope) => {
+        rootScope = $rootScope;
+      }));
+      it('should exists and have methods', () => {
+        expect(service).toBeDefined();
+        expect(service.getAll).toBeDefined();
+        expect(service.setAll).toBeDefined();
+        expect(service.getSynchronizerNotificationStatus).toBeDefined();
+        expect(service.setSynchronizerNotificationStatus).toBeDefined();
+        expect(service.setUserDetailsCookie).toBeDefined();
+        expect(service.getUserDetailsCookie).toBeDefined();
+      });
+
+      describe('the getAll method', () => {
+        it('should return all the stored prefs', () => {
+          let prefs = service.getAll();
+          expect(prefs).toEqual(JSON.parse(cookies.xosUserPrefs));
+        });
+      });
+
+      describe('the setAll method', () => {
+        it('should override all preferences', () => {
+          service.setAll({test: true, updated: true});
+          expect(JSON.parse(cookies.xosUserPrefs)).toEqual({test: true, updated: true});
+        });
+      });
+
+      describe('the synchronizers status', () => {
+        let syncNotification;
+        beforeEach(() => {
+          syncNotification = {
+            synchronizers: {
+              notification: {
+                first: true,
+                second: false
+              }
+            },
+            userData: {
+              userId: 1
+            }
+          }
+          cookies.xosUserPrefs = JSON.stringify(syncNotification);
+        });
+
+        describe('the getSynchronizerNotificationStatus method', () => {
+          it('should return notification status for all synchronizers', () => {
+            expect(service.getSynchronizerNotificationStatus()).toEqual(syncNotification.synchronizers.notification);
+          });
+
+          it('should return notification status for a single synchronizers', () => {
+            expect(service.getSynchronizerNotificationStatus('first')).toEqual(syncNotification.synchronizers.notification.first);
+            expect(service.getSynchronizerNotificationStatus('second')).toEqual(syncNotification.synchronizers.notification.second);
+          });
+        });
+
+        describe('the setSynchronizerNotificationStatus', () => {
+          
+          it('should throw an error if called without synchronizer name', () => {
+            function wrapper (){
+              service.setSynchronizerNotificationStatus();
+            }
+            expect(wrapper).toThrowError('[XosUserPrefs] When updating a synchronizer is mandatory to provide a name.');
+          });
+
+          it('should update a synchronizer notification status', () => {
+            service.setSynchronizerNotificationStatus('second', true);
+            expect(service.getSynchronizerNotificationStatus('second')).toEqual(true);
+            expect(service.getSynchronizerNotificationStatus('first')).toEqual(true);
+
+            // should persist the change
+            expect(cookieMock.put).toHaveBeenCalledWith('xosUserPrefs', '{"synchronizers":{"notification":{"first":true,"second":true}},"userData":{"userId":1}}');
+          });
+
+          it('should handle empty cookies', () => {
+            cookies.xosUserPrefs = '';
+            service.setSynchronizerNotificationStatus('second', true);
+            expect(service.getSynchronizerNotificationStatus('second')).toEqual(true);
+          });
+        });
+      });
+
+      describe('the userdetails status', () => {
+        let userdata, meMock;
+        const userData = {
+          current_user_id: 2
+        };
+        beforeEach(inject(($q, Me) => {
+          userdata = {
+            userData: {
+              current_user_id: 1
+            }
+          }
+          cookies.xosUserPrefs = JSON.stringify(userdata);
+          deffered= $q.defer();
+          meMock = Me;
+          spyOn(meMock, 'get').and.callFake(function(){
+            return deffered.promise;
+          });
+        }));
+        describe('Get user data method', ()=>{
+          it('it should return the stored data', (done) => {
+            service.getUserDetailsCookie().$promise.then((data) => {
+              expect(data).toEqual(userdata.userData);
+              done();
+            });
+            rootScope.$apply();
+          });
+
+          it('Should call the Api to return the data', (done) => {
+            cookies.xosUserPrefs = JSON.stringify();
+            service.getUserDetailsCookie().$promise.then((res) => {
+              expect(res.userId).toEqual(userData.userId);
+              expect(meMock.get).toHaveBeenCalled();
+              done();
+            });
+            deffered.resolve(userData);
+            rootScope.$apply();
+          });
+
+        });
+        describe('Set user data method', ()=>{
+          it('it should save the provided data', (done) => {
+            service.setUserDetailsCookie(userData).$promise.then(data => {
+              expect(data).toEqual(userData);
+              expect(cookieMock.put).toHaveBeenCalledWith('xosUserPrefs',  '{"userData":{"current_user_id":2}}');
+              done();
+            });
+            rootScope.$apply();
+          });
+          it('Should call the Api to save the data', (done)=>{
+            service.setUserDetailsCookie().$promise.then(data => {
+              expect(meMock.get).toHaveBeenCalled();
+              expect(data).toEqual(userData);
+              expect(cookieMock.put).toHaveBeenCalledWith('xosUserPrefs',  '{"userData":{"current_user_id":2}}');
+              done();
+            });
+            deffered.resolve(userData);
+            rootScope.$apply();
+          });
+        });
+      });
+    });
+  });
+})();
\ No newline at end of file
diff --git a/spec/test_helpers.js b/spec/test_helpers.js
new file mode 100644
index 0000000..c373c5e
--- /dev/null
+++ b/spec/test_helpers.js
@@ -0,0 +1,50 @@
+/**
+ * Collection of helpers for xos tests
+ */
+
+/* exported clickElement */
+/* eslint-disable angular/ng_document_service */
+
+const clickElement = function (el){
+  const ev = document.createEvent('MouseEvent');
+  ev.initMouseEvent(
+    'click',
+    true /* bubble */, true /* cancelable */,
+    window, null,
+    0, 0, 0, 0, /* coordinates */
+    false, false, false, false, /* modifier keys */
+    0 /*left*/, null
+  );
+  el.dispatchEvent(ev);
+};
+
+describe('Matchers inclusion', () => {
+  beforeEach(function(){
+    jasmine.addMatchers({
+      toBeInstanceOf: function() {
+
+        return {
+          compare: (actual, expected) => {
+            // const actual = actual;
+            const result = {};
+            result.pass = actual instanceof expected.constructor;
+
+            result.message = 'Expected ' + actual + ' to be instance of ' + expected;
+
+            return result;
+          },
+          negativeCompare: (actual, expected) => {
+            // const actual = actual;
+            const result = {};
+            result.pass = actual instanceof expected.constructor === false;
+
+            result.message = 'Expected ' + actual + ' to be instance of ' + expected;
+
+            return result;
+          }
+        }
+      }
+    });
+  });
+});
+console.log('---------------------- Test Helpers Loaded!! -----------------------');
diff --git a/spec/ui/alert.test.js b/spec/ui/alert.test.js
new file mode 100644
index 0000000..c67d03a
--- /dev/null
+++ b/spec/ui/alert.test.js
@@ -0,0 +1,131 @@
+/**
+ * © OpenCORD
+ *
+ * Created by teone on 4/15/16.
+ */
+
+(function () {
+  'use strict';
+
+  describe('The xos.helper module', function(){
+    describe('The xos-alert component', () => {
+
+      let element, scope, isolatedScope;
+
+      let message = 'Test Error Message';
+
+      beforeEach(module('xos.helpers'));
+
+      it('should throw an error if no config is specified', inject(($compile, $rootScope) => {
+        function errorFunctionWrapper(){
+          $compile(angular.element('<xos-alert></xos-alert>'))($rootScope);
+          $rootScope.$digest();
+        }
+        expect(errorFunctionWrapper).toThrow(new Error('[xosAlert] Please provide a configuration via the "config" attribute'));
+      }));
+
+      describe('when correctly configured', () => {
+        beforeEach(inject(($compile, $rootScope) => {
+
+          scope = $rootScope.$new();
+
+          scope.config = {
+            type: 'danger',
+            closeBtn: true
+          };
+
+          element = angular.element(`<xos-alert config="config">${message}</xos-alert>`);
+          $compile(element)(scope);
+          scope.$digest();
+          isolatedScope = element.isolateScope().vm;
+        }));
+
+        it('should transclude the message', () => {
+          let textContainer = element[0].getElementsByTagName('p')[0];
+          let text = angular.element(textContainer).text();
+          expect(text).toEqual(message)
+        });
+
+        it('should have a close button', () => {
+          let btn = element[0].getElementsByTagName('button');
+          expect(btn.length).toEqual(1);
+        });
+
+        describe('when the close button is clicked', () => {
+          it('should hide the alert', () => {
+            let btn = element[0].getElementsByTagName('button')[0];
+            btn.click();
+            let alert = angular.element(element[0].querySelectorAll('.alert')[0]);
+            expect(alert.hasClass('ng-hide')).toBeTruthy();
+          });
+        });
+
+        describe('when autoHide is set', () => {
+
+          let to;
+
+          beforeEach(inject(($compile, $rootScope, $timeout) => {
+            scope = $rootScope.$new();
+
+            scope.config = {
+              type: 'danger',
+              closeBtn: true,
+              autoHide: 500
+            };
+
+            to = $timeout;
+
+            element = angular.element(`<xos-alert config="config">${message}</xos-alert>`);
+            $compile(element)(scope);
+            scope.$digest();
+            isolatedScope = element.isolateScope().vm;
+          }));
+
+          it('should hide the alert', () => {
+            to.flush();
+            expect(isolatedScope.show).toBeFalsy();
+            let alert = angular.element(element[0].querySelectorAll('.alert')[0]);
+            expect(alert.hasClass('ng-hide')).toBeTruthy();
+          });
+        });
+
+        describe('when show is set to false', () => {
+
+          beforeEach(inject(($compile, $rootScope) => {
+            scope = $rootScope.$new();
+
+            scope.config = {
+              type: 'danger',
+              closeBtn: true
+            };
+
+            scope.show = false;
+
+            element = angular.element(`<xos-alert config="config" show="show">${message}</xos-alert>`);
+            $compile(element)(scope);
+            scope.$digest();
+            isolatedScope = element.isolateScope().vm;
+          }));
+
+          it('should hide the alert', () => {
+            let alert = angular.element(element[0].querySelectorAll('.alert')[0]);
+            expect(alert.hasClass('ng-hide')).toBeTruthy();
+          });
+
+          describe('when show is changed to true', () => {
+            beforeEach(() => {
+              scope.show = true;
+              scope.$digest();
+            });
+
+            it('should show the alert', () => {
+              let alert = angular.element(element[0].querySelectorAll('.alert')[0]);
+              expect(alert.hasClass('ng-hide')).toBeFalsy();
+            });
+          });
+        });
+
+      });
+    });
+  });
+})();
\ No newline at end of file
diff --git a/spec/ui/custom-validator.test.js b/spec/ui/custom-validator.test.js
new file mode 100644
index 0000000..c85c934
--- /dev/null
+++ b/spec/ui/custom-validator.test.js
@@ -0,0 +1,107 @@
+/**
+ * © OpenCORD
+ *
+ * Created by teone on 5/25/16.
+ */
+
+(function () {
+  'use strict';
+
+  describe('The xos.helper module', function () {
+    describe('The xosCustomValidator directive', () => {
+      let element, scope, isolatedScope, rootScope, compile, form, input;
+      const compileElement = (el) => {
+        element = el;
+
+        if(!scope){
+          scope = rootScope.$new();
+        }
+        if(angular.isUndefined(element)){
+          element = angular.element(`
+            <form name="form">
+              <input name="testInput" type="text" ng-model="value" xos-custom-validator custom-validator="validator"/>
+            </form>
+          `);
+        }
+        compile(element)(scope);
+        scope.$digest();
+        input = $(element).find('input');
+        isolatedScope = angular.element(input).isolateScope();
+        form = scope.form;
+      };
+
+      beforeEach(module('xos.helpers'));
+
+      beforeEach(inject(function ($compile, $rootScope) {
+        compile = $compile;
+        rootScope = $rootScope;
+      }));
+
+      beforeEach(() => {
+        scope = rootScope.$new();
+        scope.validator = 'validator';
+        scope.value = '';
+        compileElement();
+      });
+
+      it('should bind the validator', () => {
+        expect(isolatedScope.fn).toEqual('validator');
+      });
+
+      describe('given a validator function', () => {
+
+        beforeEach(() => {
+          scope = rootScope.$new();
+          scope.value = '';
+          scope.validator = (model) => angular.equals(model, 'test');
+          spyOn(scope, 'validator').and.callThrough();
+          compileElement();
+        });
+
+        it('should call the validator function on value change', () => {
+          form.testInput.$setViewValue('something');
+          scope.$digest();
+          expect(scope.validator).toHaveBeenCalledWith('something');
+          expect(scope.value).toEqual('something');
+        });
+
+        it('should set the field invalid', () => {
+          form.testInput.$setViewValue('something');
+          scope.$digest();
+          expect(scope.validator).toHaveBeenCalledWith('something');
+          expect(input).toHaveClass('ng-invalid');
+          expect(input).toHaveClass('ng-invalid-custom');
+        });
+
+        it('should set the field valid', () => {
+          form.testInput.$setViewValue('test');
+          scope.$digest();
+          expect(scope.validator).toHaveBeenCalledWith('test');
+          expect(input).not.toHaveClass('ng-invalid');
+          expect(input).not.toHaveClass('ng-invalid-custom');
+        });
+
+        describe('if the validation function return an array', () => {
+
+          beforeEach(() => {
+            scope = rootScope.$new();
+            scope.value = '';
+            scope.validator = (model) => {
+              return ['randomTest', angular.equals(model, 'test')];
+            };
+            spyOn(scope, 'validator').and.callThrough();
+            compileElement();
+          });
+
+          it('should set the field invalid', () => {
+            form.testInput.$setViewValue('something');
+            scope.$digest();
+            expect(scope.validator).toHaveBeenCalledWith('something');
+            expect(input).toHaveClass('ng-invalid');
+            expect(input).toHaveClass('ng-invalid-random-test');
+          });
+        });
+      });
+    });
+  });
+})();
\ No newline at end of file
diff --git a/spec/ui/field.test.js b/spec/ui/field.test.js
new file mode 100644
index 0000000..bfb36a3
--- /dev/null
+++ b/spec/ui/field.test.js
@@ -0,0 +1,330 @@
+/**
+ * © OpenCORD
+ *
+ * Created by teone on 5/25/16.
+ */
+
+(function () {
+  'use strict';
+
+  describe('The xos.helper module', function(){
+
+    describe('The xosField component', () => {
+      let element, scope, isolatedScope, rootScope, compile;
+      const compileElement = (el) => {
+        element = el;
+
+        if(!scope){
+          scope = rootScope.$new();
+        }
+        if(angular.isUndefined(element)){
+          element = angular.element('<xos-field name="name" field="field" ng-model="ngModel"></xos-field>');
+        }
+        compile(element)(scope);
+        scope.$digest();
+        isolatedScope = element.isolateScope().vm;
+      };
+
+      beforeEach(module('xos.helpers'));
+
+      beforeEach(inject(function ($compile, $rootScope) {
+        compile = $compile;
+        rootScope = $rootScope;
+      }));
+
+      it('should throw an error if no name is passed', inject(($compile, $rootScope) => {
+        function errorFunctionWrapper(){
+          // setup the parent scope
+          scope = $rootScope.$new();
+          scope.field = {
+            label: 'Label',
+            type: 'number',
+            validators: {}
+          };
+          scope.ngModel = 1;
+          compileElement();
+        }
+        expect(errorFunctionWrapper).toThrow(new Error('[xosField] Please provide a field name'));
+      }));
+
+      it('should throw an error if no field definition is passed', inject(($compile, $rootScope) => {
+        function errorFunctionWrapper(){
+          // setup the parent scope
+          scope = $rootScope.$new();
+          scope.name = 'label';
+          scope.ngModel = 1;
+          compileElement();
+        }
+        expect(errorFunctionWrapper).toThrow(new Error('[xosField] Please provide a field definition'));
+      }));
+
+      it('should throw an error if no field type is passed', inject(($compile, $rootScope) => {
+        function errorFunctionWrapper(){
+          // setup the parent scope
+          scope = $rootScope.$new();
+          scope.name = 'label';
+          scope.ngModel = 1;
+          scope.field = {label: 'Label:'}
+          compileElement();
+        }
+        expect(errorFunctionWrapper).toThrow(new Error('[xosField] Please provide a type in the field definition'));
+      }));
+
+      it('should throw an error if no field model is passed', inject(($compile, $rootScope) => {
+        function errorFunctionWrapper(){
+          // setup the parent scope
+          scope = $rootScope.$new();
+          scope.name = 'label';
+          scope.field = {
+            label: 'Label',
+            type: 'number',
+            validators: {}
+          };
+          compileElement(angular.element('<xos-field name="name" field="field"></xos-field>'));
+        }
+        expect(errorFunctionWrapper).toThrow(new Error('[xosField] Please provide an ng-model'));
+      }));
+
+      describe('when a text input is passed', () => {
+        beforeEach(() => {
+          scope = rootScope.$new();
+          scope.name = 'label';
+          scope.field = {
+            label: 'Label',
+            type: 'text',
+            validators: {
+              custom: 'fake'
+            }
+          };
+          scope.ngModel = 'label';
+          compileElement();
+        });
+
+        it('should print a text field', () => {
+          expect($(element).find('[name="label"]')).toHaveAttr('type', 'text');
+        });
+
+        it('should attach the custom validator directive', () => {
+          let input = $(element).find('[name="label"]');
+          expect(input).toHaveAttr('xos-custom-validator');
+          expect(input).toHaveAttr('custom-validator', 'vm.field.validators.custom || null');
+        });
+      });
+
+      describe('when a option is selected in dropdown', () => {
+        beforeEach(() => {
+          scope = rootScope.$new();
+          scope.name = 'label';
+          scope.field = {
+            label: 'Label',
+            type: 'select',
+            validators: {},
+            options: [
+              {
+                id: 0,
+                label: '---Site---'
+              },
+              {
+                id: 1,
+                label: '---Site1---'
+              }
+            ]
+          };
+          scope.ngModel = 0;
+          compileElement();
+        });
+
+        it('No of select elements', () => {
+          expect($(element).find('select').children('option').length).toEqual(2);
+        });
+
+        it('should show the selected value', () => {
+          const elem =  angular.element($(element).find('select').children('option')[0]);
+          expect(elem.text()).toEqual('---Site---');
+          expect(elem).toHaveAttr('selected');
+        });
+      });
+
+      describe('when a number input is passed', () => {
+        beforeEach(() => {
+          scope = rootScope.$new();
+          scope.name = 'label';
+          scope.field = {
+            label: 'Label',
+            type: 'number',
+            validators: {}
+          };
+          scope.ngModel = 10;
+          compileElement();
+        });
+
+        it('should print a number field', () => {
+          expect($(element).find('[name="label"]')).toHaveAttr('type', 'number');
+        });
+      });
+
+      describe('when a boolean input is passed', () => {
+        beforeEach(() => {
+          scope = rootScope.$new();
+          scope.name = 'label';
+          scope.field = {
+            label: 'Label',
+            type: 'boolean',
+            validators: {}
+          };
+          scope.ngModel = true;
+          compileElement();
+        });
+
+        let setFalse, setTrue;
+
+        beforeEach(() => {
+          setFalse= $(element).find('.boolean-field > a:first-child');
+          setTrue = $(element).find('.boolean-field > a:last-child');
+        });
+
+        it('should print two buttons', () => {
+          expect($(element).find('.boolean-field > a').length).toEqual(2)
+        });
+
+        it('should change value to false', () => {
+          expect(isolatedScope.ngModel).toEqual(true);
+          clickElement(setFalse[0]);
+          expect(isolatedScope.ngModel).toEqual(false);
+        });
+
+        it('should change value to true', () => {
+          isolatedScope.ngModel = false;
+          scope.$apply();
+          expect(isolatedScope.ngModel).toEqual(false);
+          clickElement(setTrue[0]);
+          expect(isolatedScope.ngModel).toEqual(true);
+        });
+      });
+
+      describe('when an object input is passed', () => {
+        beforeEach(() => {
+          scope = rootScope.$new();
+          scope.name = 'label';
+          scope.field = {
+            label: 'Label',
+            type: 'object',
+            validators: {}
+          };
+          scope.ngModel = {
+            baz: true,
+            foo: 'bar',
+            foz: 1,
+          };
+          compileElement();
+        });
+
+        it('should print a panel to contain object property field', () => {
+          expect($(element).find('.panel.object-field')).toExist()
+        });
+
+        it('should print the right input type for each property', () => {
+          expect($(element).find('input').length).toBe(2);
+          expect($(element).find('.boolean-field > a').length).toEqual(2);
+        });
+
+        it('should format labels', () => {
+          expect($(element).find('input[name="foo"]').parent().find('label').text()).toBe('Foo:');
+        });
+
+        describe('and the model is empty', () => {
+          beforeEach(() => {
+            scope.ngModel = {
+            };
+            compileElement();
+          });
+
+          it('should not print the panel', () => {
+            expect($(element).find('.panel.object-field')).not.toExist()
+          });
+
+          describe('but field is configured', () => {
+            beforeEach(() => {
+              scope.field.properties = {
+                foo: {
+                  label: 'FooLabel:',
+                  type: 'string',
+                  validators: {
+                    required: true
+                  }
+                },
+                bar: {
+                  type: 'number'
+                }
+              };
+              compileElement();
+            });
+            it('should render panel and configured fields', () => {
+              expect($(element).find('.panel.object-field')).toExist();
+              expect($(element).find('input[name="foo"]').parent().find('label').text()).toBe('FooLabel:');
+              expect($(element).find('input[name="foo"]')).toHaveAttr('type', 'string');
+              expect($(element).find('input[name="foo"]')).toHaveAttr('required');
+
+              expect($(element).find('input[name="bar"]').parent().find('label').text()).toBe('Bar:');
+              expect($(element).find('input[name="bar"]')).toHaveAttr('type', 'number');
+
+            });
+          });
+        });
+      });
+
+      describe('when validation options are passed', () => {
+        let input;
+        describe('given a a text field', () => {
+          beforeEach(() => {
+            scope.field = {
+              label: 'Label',
+              type: 'text',
+              validators: {
+                minlength: 10,
+                maxlength: 15,
+                required: true
+              }
+            };
+
+            scope.$digest();
+            input = $(element).find('input');
+          });
+
+          it('should validate required', () => {
+            scope.ngModel= null;
+            scope.$digest();
+            expect(input).toHaveClass('ng-invalid-required');
+
+            scope.ngModel= 'not too short';
+            scope.$digest();
+            expect(input).not.toHaveClass('ng-invalid-required');
+            expect(input).not.toHaveClass('ng-invalid');
+          });
+
+          it('should validate minlength', () => {
+            scope.ngModel= 'short';
+            scope.$digest();
+            expect(input).toHaveClass('ng-invalid-minlength');
+
+            scope.ngModel= 'not too short';
+            scope.$digest();
+            expect(input).not.toHaveClass('ng-invalid-minlength');
+            expect(input).not.toHaveClass('ng-invalid');
+          });
+
+          it('should validate maxlength', () => {
+            scope.ngModel= 'this is definitely too long!!';
+            scope.$digest();
+            expect(input).toHaveClass('ng-invalid-maxlength');
+
+            scope.ngModel= 'not too short';
+            scope.$digest();
+            expect(input).not.toHaveClass('ng-invalid-maxlength');
+            expect(input).not.toHaveClass('ng-invalid');
+          });
+        });
+      });
+    });
+  });
+})();
\ No newline at end of file
diff --git a/spec/ui/form.test.js b/spec/ui/form.test.js
new file mode 100644
index 0000000..e92d31a
--- /dev/null
+++ b/spec/ui/form.test.js
@@ -0,0 +1,269 @@
+/**
+ * © OpenCORD
+ *
+ * Created by teone on 4/18/16.
+ */
+
+(function () {
+  'use strict';
+
+  let element, scope, isolatedScope, rootScope, compile;
+
+  const compileElement = () => {
+
+    if(!scope){
+      scope = rootScope.$new();
+    }
+
+    element = angular.element(`<xos-form config="config" ng-model="model"></xos-form>`);
+    compile(element)(scope);
+    scope.$digest();
+    isolatedScope = element.isolateScope().vm;
+  }
+
+  describe('The xos.helper module', function(){
+
+    describe('The xos-form component', () => {
+
+
+      beforeEach(module('xos.helpers'));
+
+      beforeEach(inject(($compile, $rootScope) => {
+        rootScope = $rootScope;
+        compile = $compile;
+      }));
+
+      it('should throw an error if no config is specified', () => {
+        function errorFunctionWrapper(){
+          compileElement();
+        }
+        expect(errorFunctionWrapper).toThrow(new Error('[xosForm] Please provide a configuration via the "config" attribute'));
+      });
+
+      it('should throw an error if no actions is specified', () => {
+        function errorFunctionWrapper(){
+          scope = rootScope.$new();
+          scope.config = 'green';
+          compileElement();
+        }
+        expect(errorFunctionWrapper).toThrow(new Error('[xosForm] Please provide an action list in the configuration'));
+      });
+
+      describe('when correctly configured', () => {
+        
+        let cb = jasmine.createSpy('callback');
+
+        beforeEach(inject(($rootScope) => {
+
+          scope = $rootScope.$new();
+
+          scope.config = {
+            exclude: ['excludedField'],
+            formName: 'testForm',
+            actions: [
+              {
+                label: 'Save',
+                icon: 'ok', // refers to bootstraps glyphicon
+                cb: cb,
+                class: 'success'
+              }
+            ],
+            fields: {
+              first_name: {
+                label: 'Custom Label'
+              }
+            }
+          };
+
+          scope.model = {
+            id: 1,
+            first_name: 'Jhon',
+            last_name: 'Snow',
+            age: 25,
+            email: 'test@onlab.us',
+            birthDate: '2016-04-18T23:44:16.883181Z',
+            enabled: true,
+            role: 'user', //select
+            a_permissions: [
+            ],
+            object_field: {
+              string: 'bar',
+              number: 1,
+              email: 'teo@onlab.us'
+            }
+          };
+
+          compileElement();
+        }));
+
+        it('should add excluded properties to the list', () => {
+          let expected = ['id', 'validators', 'created', 'updated', 'deleted', 'backend_status', 'excludedField'];
+          expect(isolatedScope.excludedField).toEqual(expected);
+        });
+
+        it('should render 10 input field', () => {
+          // boolean are in the form model, but are not input
+          expect(Object.keys(isolatedScope.formField).length).toEqual(9);
+          const field = element[0].getElementsByTagName('input');
+          expect(field.length).toEqual(10);
+        });
+
+        it('should render 1 boolean field', () => {
+          expect($(element).find('.boolean-field > a').length).toEqual(2)
+        });
+
+        it('when clicking on action should invoke callback', () => {
+          const link = $(element).find('[role="button"]');
+          //console.log(link);
+          link.click();
+          // TODO : Check correct parameters
+          expect(cb).toHaveBeenCalled();
+
+        });
+
+        it('should set a custom label', () => {
+          let nameField = element[0].getElementsByClassName('form-group')[0];
+          let label = angular.element(nameField.getElementsByTagName('label')[0]).text()
+          expect(label).toEqual('Custom Label:');
+        });
+
+        it('should use the correct input type', () => {
+          expect($(element).find('[name="age"]')).toHaveAttr('type', 'number');
+          expect($(element).find('[name="birthDate"]')).toHaveAttr('type', 'date');
+          expect($(element).find('[name="email"]')).toHaveAttr('type', 'email');
+        });
+
+        xdescribe('the boolean field test', () => {
+
+          let setFalse, setTrue;
+
+          beforeEach(() => {
+            setFalse= $(element).find('.boolean-field > button:first-child');
+            setTrue = $(element).find('.boolean-field > button:last-child');
+          });
+
+          it('should change value to false', () => {
+            expect(isolatedScope.ngModel.enabled).toEqual(true);
+            setFalse.click();
+            expect(isolatedScope.ngModel.enabled).toEqual(false);
+          });
+
+          it('should change value to true', () => {
+            isolatedScope.ngModel.enabled = false;
+            scope.$apply();
+            expect(isolatedScope.ngModel.enabled).toEqual(false);
+            setTrue.click()
+            expect(isolatedScope.ngModel.enabled).toEqual(true);
+          });
+        });
+
+        describe('when a deep model is passed', () => {
+
+          beforeEach(inject(($rootScope) => {
+
+            scope = $rootScope.$new();
+
+            scope.config = {
+              exclude: ['excludedField'],
+              formName: 'testForm',
+              actions: [
+                {
+                  label: 'Save',
+                  icon: 'ok', // refers to bootstraps glyphicon
+                  cb: cb,
+                  class: 'success'
+                }
+              ],
+              fields: {
+                object_field: {
+                  field_one: {
+                    label: 'Custom Label'
+                  }
+                }
+              }
+            };
+
+            scope.model = {
+              object_field: {
+                field_one: 'bar',
+                number: 1,
+                email: 'teo@onlab.us'
+              }
+            };
+
+            compileElement();
+          }));
+
+          it('should print nested field', () => {
+            expect($(element).find('input').length).toBe(3);
+          });
+
+          xit('should configure nested fields', () => {
+            let custom_label = $(element).find('input[name=field_one]').parent().find('label');
+            expect(custom_label.text()).toBe('Custom Label');
+          });
+        });
+      });
+      describe('when correctly configured for feedback', () => {
+
+        let fb = jasmine.createSpy('feedback').and.callFake(function(statusFlag) {
+          if(statusFlag){
+            scope.config.feedback.show = true;
+            scope.config.feedback.message = 'Form Submitted';
+            scope.config.feedback.type = 'success';
+          }
+          else {
+            scope.config.feedback.show = true;
+            scope.config.feedback.message = 'Error';
+            scope.config.feedback.type = 'danger';
+
+          }
+        });
+
+        beforeEach(()=> {
+          scope = rootScope.$new();
+          scope.config =
+          {
+
+            feedback: {
+              show: false,
+              message: 'Form submitted successfully !!!',
+              type: 'success'
+            },
+            actions: [
+              {
+                label: 'Save',
+                icon: 'ok', // refers to bootstraps glyphicon
+                cb: () => {},
+                class: 'success'
+              }
+            ]
+          };
+          scope.model={};
+          compileElement();
+        });
+
+        it('should not show feedback when loaded', () => {
+          expect($(element).find('xos-alert > div')).toHaveClass('alert alert-success ng-hide');
+        });
+
+        it('should show a success feedback', () => {
+          fb(true);
+          scope.$digest();
+          expect(isolatedScope.config.feedback.type).toEqual('success');
+          expect(fb).toHaveBeenCalledWith(true);
+          expect($(element).find('xos-alert > div')).toHaveClass('alert alert-success');
+        });
+
+        it('should show an error feedback', function() {
+          fb(false);
+          scope.$digest();
+          expect(isolatedScope.config.feedback.type).toEqual('danger');
+          expect(fb).toHaveBeenCalledWith(false);
+          expect($(element).find('xos-alert > div')).toHaveClass('alert alert-danger');
+        });
+      });
+
+    });
+  });
+})();
diff --git a/spec/ui/pagination.test.js b/spec/ui/pagination.test.js
new file mode 100644
index 0000000..03f1045
--- /dev/null
+++ b/spec/ui/pagination.test.js
@@ -0,0 +1,53 @@
+(function () {
+  'use strict';
+
+  describe('The xos.helper module', function(){
+    describe('The xos-pagination component', () => {
+
+      let scope, element, isolatedScope;
+      let cb = jasmine.createSpy('callback')
+
+      beforeEach(module('xos.helpers'));
+
+      beforeEach(inject(function ($compile, $rootScope) {
+        scope = $rootScope.$new();
+
+        scope.pageSize = 2;
+
+        scope.totalElements = 5;
+
+        scope.change = cb;
+
+        element = angular.element('<xos-pagination page-size="pageSize" total-elements="totalElements" change="change"></xos-table>');
+        $compile(element)(scope);
+        scope.$digest();
+        isolatedScope = element.isolateScope().vm;
+      }));
+
+      it('should contain 3 pages', function() {
+        const li = element[0].getElementsByTagName('li');
+        expect(li.length).toEqual(5);
+      });
+
+      it('should call the change function', () => {
+        const li = element[0].getElementsByTagName('li')[3];
+        let link = li.getElementsByTagName('a')[0];
+        link.click();
+        expect(cb).toHaveBeenCalledWith(2);
+      });
+
+      describe('when elements number is less than page size', () => {
+        beforeEach(() => {
+          isolatedScope.pageSize = 10;
+          isolatedScope.totalElements = 9;
+          scope.$digest();
+        });
+
+        it('should not be rendered', () => {
+          const pagination = element[0].getElementsByClassName('pagination');
+          expect(pagination.length).toEqual(0);
+        });
+      });
+    });
+  });
+})();
\ No newline at end of file
diff --git a/spec/ui/smart-pie.test.js b/spec/ui/smart-pie.test.js
new file mode 100644
index 0000000..d5a9cfe
--- /dev/null
+++ b/spec/ui/smart-pie.test.js
@@ -0,0 +1,210 @@
+/**
+ * © OpenCORD
+ *
+ * Created by teone on 3/24/16.
+ */
+
+(function () {
+  'use strict';
+
+  let mockData, compile, rootScope, spy, scope, isolatedScope, element, interval;
+
+  const compileElement = () => {
+
+    if(!scope){
+      scope = rootScope.$new();
+    }
+
+    element = angular.element('<xos-smart-pie config="config"></xos-smart-pie>');
+    compile(element)(scope);
+    scope.$digest();
+    isolatedScope = element.isolateScope().vm;
+  }
+
+  describe('The xos.helper module', function(){
+    describe('The xos-smart-pie component', () => {
+      
+      beforeEach(module('xos.helpers'));
+
+      beforeEach(function(){
+        module(function($provide){
+          $provide.service('MockResource', function(){
+            return {
+              query: ''
+            }
+          });
+        });
+      });
+
+      beforeEach(inject(function ($compile, $rootScope) {
+
+        // set mockData
+        mockData = [
+          {
+            id: 1,
+            first_name: 'Jon',
+            last_name: 'Snow',
+            category: 1
+          },
+          {
+            id: 2,
+            first_name: 'Danaerys',
+            last_name: 'Targaryen',
+            category: 2
+          },
+          {
+            id: 3,
+            first_name: 'Aria',
+            last_name: 'Stark',
+            category: 1
+          }
+        ]
+
+        compile = $compile;
+        rootScope = $rootScope;
+      }));
+
+      it('should throw an error if no resource and no data are passed in the config', inject(($compile, $rootScope) => {
+        function errorFunctionWrapper(){
+          // setup the parent scope
+          scope = $rootScope.$new();
+          scope.config = {};
+          compileElement();
+        }
+        expect(errorFunctionWrapper).toThrow(new Error('[xosSmartPie] Please provide a resource or an array of data in the configuration'));
+      }));
+
+      describe('when data are passed in the configuration', () => {
+        beforeEach(inject(function ($compile, $rootScope) {
+          scope = $rootScope.$new();
+
+          scope.config = {
+            data: mockData,
+            groupBy: 'category',
+            classes: 'my-test-class'
+          };
+
+          compileElement();
+        }));
+        
+
+        it('should attach provided classes', () => {
+          expect($(element).find('canvas')).toHaveClass('my-test-class');
+        });
+
+        it('should group elements', () => {
+          let groupedData = [2, 1];
+          expect(isolatedScope.data).toEqual(groupedData);
+        });
+
+        describe('when a labelFormatter function is provided', () => {
+          beforeEach(() => {
+            scope.config.labelFormatter = (labels) => {
+              return labels.map(l => l === '1' ? 'First' : 'Second');
+            };
+            compileElement();
+          });
+          it('should format labels', () => {
+            expect(isolatedScope.labels).toEqual(['First', 'Second'])
+          });
+        });
+
+        describe('when provided data changes', () => {
+          beforeEach(() => {
+            scope.config.data.push({
+              id: 2,
+              first_name: 'Danaerys',
+              last_name: 'Targaryen',
+              category: 1
+            });
+            scope.$digest();
+          });
+          it('should calculate again the data', () => {
+            expect(isolatedScope.data).toEqual([3, 1]);
+          });
+        });
+      });
+
+      
+      describe('when a resource is specified in the configuration', () => {
+
+        beforeEach(inject(function ($compile, $rootScope, $q, MockResource) {
+          scope = $rootScope.$new();
+
+          scope.config = {
+            resource: 'MockResource',
+            groupBy: 'category',
+            classes: 'my-test-class'
+          };
+
+          spy = MockResource;
+
+          spyOn(MockResource, 'query').and.callFake(function() {
+            const deferred = $q.defer();
+            deferred.resolve(mockData);
+            return {$promise: deferred.promise};
+          });
+
+          compileElement();
+        }));
+
+
+        it('should call the server and group elements', () => {
+          let groupedData = [2, 1];
+          expect(spy.query).toHaveBeenCalled();
+          expect(isolatedScope.data).toEqual(groupedData);
+        });
+
+        describe('when a labelFormatter function is provided', () => {
+          beforeEach(inject(function ($compile, $rootScope){
+            scope = $rootScope.$new();
+            scope.config = {
+              resource: 'MockResource',
+              groupBy: 'category',
+              classes: 'label-formatter-test',
+              labelFormatter: (labels) => {
+                return labels.map(l => l === '1' ? 'First' : 'Second');
+              }
+            };
+            compileElement();
+          }));
+
+          it('should format labels', () => {
+            expect(isolatedScope.labels).toEqual(['First', 'Second'])
+          });
+        });
+
+        describe('when polling is enabled', () => {
+          beforeEach(inject(function ($compile, $rootScope, $interval){
+
+            //mocked $interval (by ngMock)
+            interval = $interval;
+
+            // cleaning the spy
+            spy.query.calls.reset()
+
+            scope = $rootScope.$new();
+            scope.config = {
+              resource: 'MockResource',
+              groupBy: 'category',
+              classes: 'label-formatter-test',
+              poll: 2
+            };
+            compileElement();
+          }));
+
+          it('should call the backend every 2 second', () => {
+            expect(spy.query).toHaveBeenCalled();
+            expect(spy.query.calls.count()).toEqual(1);
+            interval.flush(2000);
+            expect(spy.query.calls.count()).toEqual(2);
+            interval.flush(2000);
+            expect(spy.query.calls.count()).toEqual(3)
+          });
+        });
+      });
+
+
+    });
+  });
+})();
\ No newline at end of file
diff --git a/spec/ui/smart-table.test.js b/spec/ui/smart-table.test.js
new file mode 100644
index 0000000..e87e807
--- /dev/null
+++ b/spec/ui/smart-table.test.js
@@ -0,0 +1,198 @@
+/**
+ * © OpenCORD
+ *
+ * Created by teone on 3/24/16.
+ */
+
+(function () {
+  'use strict';
+
+  let mockData;
+
+  describe('The xos.helper module', function(){
+    describe('The xos-smart-table component', () => {
+
+      let spy, emptySpy, scope, isolatedScope, element;
+
+      beforeEach(module('xos.helpers'));
+
+      beforeEach(function() {
+
+        // set mockData
+        mockData = [
+          {
+            id: 1,
+            first_name: 'Jon',
+            last_name: 'Snow',
+            hidden_field: 'hidden'
+          }
+        ];
+      });
+
+      // mock the service
+      beforeEach(function(){
+        module(function($provide){
+          $provide.service('MockResource', function(){
+            return {
+              query: '',
+              delete: ''
+            }
+          });
+
+          $provide.service('EmptyResource', function(){
+            return {
+              query: ''
+            }
+          });
+        });
+      })
+
+      beforeEach(inject(function ($compile, $rootScope, $q, MockResource) {
+        scope = $rootScope.$new();
+
+        scope.config = {
+          resource: 'MockResource',
+          hiddenFields: ['hidden_field']
+        };
+
+        spy = MockResource;
+
+        spyOn(MockResource, 'query').and.callFake(function() {
+          const deferred = $q.defer();
+          deferred.resolve(mockData);
+          return {$promise: deferred.promise};
+        });
+
+        spyOn(MockResource, 'delete').and.callFake(function() {
+          const deferred = $q.defer();
+          deferred.resolve();
+          return {$promise: deferred.promise};
+        });
+
+        element = angular.element('<xos-smart-table config="config"></xos-smart-table>');
+        $compile(element)(scope);
+        scope.$digest();
+        isolatedScope = element.isolateScope().vm;
+      }));
+
+      it('should query elements', () => {
+        expect(spy.query).toHaveBeenCalled();
+        expect($(element).find('.alert').parent().parent()).toHaveClass('ng-hide');
+      });
+
+      it('should hide hidden fields', () => {
+        // the 4th field is the mocked save method
+        expect($(element).find('thead th').length).toEqual(3);
+        expect($(element).find('thead th')[0]).toContainText('First name:');
+        expect($(element).find('thead th')[1]).toContainText('Last name:');
+        expect($(element).find('thead th')[2]).toContainText('Actions:');
+      });
+
+      it('should delete a model', () => {
+        // saving mockData (they are going to be deleted)
+        let mock = angular.copy(mockData);
+        $(element).find('a[title="delete"]')[0].click();
+        expect(spy.delete).toHaveBeenCalledWith({id: mock[0].id});
+        expect($(element).find('.alert')).toContainText(`MockResource with id ${mock[0].id} successfully deleted`);
+      });
+
+      it('should show the form', () => {
+        expect($(element).find('.panel')[0]).toHaveClass('ng-hide');
+        $(element).find('a[title="details"]')[0].click();
+        expect($(element).find('.panel')).not.toHaveClass('ng-hide');
+      });
+
+      it('should hide the form', () => {
+        isolatedScope.detailedItem = {
+          some: 'model'
+        };
+        scope.$apply();
+        expect($(element).find('.panel')).not.toHaveClass('ng-hide');
+        $(element).find('.panel .col-xs-1 a')[0].click();
+        expect($(element).find('.panel')[0]).toHaveClass('ng-hide');
+      });
+
+      it('should save an item', inject(($q) => {
+
+        let model = {
+          id: 1,
+          first_name: 'Jon',
+          last_name: 'Snow',
+          hidden_field: 'hidden',
+          $save: '',
+          $update: ''
+        };
+
+        spyOn(model, '$save').and.callFake(function() {
+          const deferred = $q.defer();
+          deferred.resolve();
+          return deferred.promise;
+        });
+
+        spyOn(model, '$update').and.callFake(function() {
+          const deferred = $q.defer();
+          deferred.resolve();
+          return deferred.promise;
+        });
+
+        isolatedScope.detailedItem = model;
+        scope.$apply();
+        $(element).find('xos-form .btn.btn-success').click();
+        expect(model.$update).toHaveBeenCalled();
+      }));
+
+      it('should have an add button', () => {
+        let addBtn = $(element).find('.row .btn.btn-success');
+        expect(addBtn.parent().parent()).not.toHaveClass('ng-hide');
+      });
+
+      describe('when the add button is clicked', () => {
+        beforeEach(() => {
+          let btn = $(element).find('.row .btn.btn-success')
+          btn[0].click();
+        });
+
+        xit('should create a new model', () => {
+          expect(isolatedScope.detailedItem).toBeDefined();
+          expect(isolatedScope.detailedItem).toBeInstanceOf('Resource');
+        });
+      });
+
+      describe('when fetching an empty collection', () => {
+        beforeEach(inject(function ($compile, $rootScope, $q, EmptyResource) {
+          scope = $rootScope.$new();
+
+          scope.config = {
+            resource: 'EmptyResource'
+          };
+
+          emptySpy = EmptyResource;
+
+          spyOn(EmptyResource, 'query').and.callFake(function() {
+            const deferred = $q.defer();
+            deferred.resolve([]);
+            return {$promise: deferred.promise};
+          });
+
+          element = angular.element('<xos-smart-table config="config"></xos-smart-table>');
+          $compile(element)(scope);
+          scope.$digest();
+          isolatedScope = element.isolateScope().vm;
+        }));
+
+        it('should display an alert', () => {
+          expect(emptySpy.query).toHaveBeenCalled();
+          expect($(element).find('.alert').parent().parent()).not.toHaveClass('ng-hide');
+          expect($(element).find('.alert')).toContainText('No data to show');
+        });
+
+        it('should not have an add button', () => {
+          let addBtn = $(element).find('.row .btn.btn-success');
+          expect(addBtn.parent().parent()).toHaveClass('ng-hide');
+        });
+      });
+
+
+    });
+  });
+})();
\ No newline at end of file
diff --git a/spec/ui/table.test.js b/spec/ui/table.test.js
new file mode 100644
index 0000000..0b6ea87
--- /dev/null
+++ b/spec/ui/table.test.js
@@ -0,0 +1,576 @@
+/**
+ * © OpenCORD
+ *
+ * Created by teone on 3/24/16.
+ */
+
+(function () {
+  'use strict';
+
+  let scope, element, isolatedScope, rootScope, compile, filter;
+  const compileElement = () => {
+
+    if(!scope){
+      scope = rootScope.$new();
+    }
+
+    element = angular.element('<xos-table config="config" data="data"></xos-table>');
+    compile(element)(scope);
+    scope.$digest();
+    isolatedScope = element.isolateScope().vm;
+  };
+
+
+  describe('The xos.helper module', function(){
+    describe('The xos-table component', () => {
+
+      beforeEach(module('xos.helpers'));
+
+      beforeEach(inject(function ($compile, $rootScope, $filter) {
+        compile = $compile;
+        rootScope = $rootScope;
+        filter = $filter;
+      }));
+
+      it('should throw an error if no config is specified', () => {
+        function errorFunctionWrapper(){
+          compileElement();
+        }
+        expect(errorFunctionWrapper).toThrow(new Error('[xosTable] Please provide a configuration via the "config" attribute'));
+      });
+
+      it('should throw an error if no config columns are specified', () => {
+        function errorFunctionWrapper(){
+          // setup the parent scope
+          scope = rootScope.$new();
+          scope.config = 'green';
+          compileElement();
+        }
+        expect(errorFunctionWrapper).toThrow(new Error('[xosTable] Please provide a columns list in the configuration'));
+      });
+
+      describe('when basically configured', function() {
+
+        beforeEach(inject(function ($compile, $rootScope) {
+
+          scope = $rootScope.$new();
+
+          scope.config = {
+            columns: [
+              {
+                label: 'Label 1',
+                prop: 'label-1'
+              },
+              {
+                label: 'Label 2',
+                prop: 'label-2'
+              }
+            ]
+          };
+
+          scope.data = [
+            {
+              'label-1': 'Sample 1.1',
+              'label-2': 'Sample 1.2'
+            },
+            {
+              'label-1': 'Sample 2.1',
+              'label-2': 'Sample 2.2'
+            }
+          ]
+
+          element = angular.element('<xos-table config="config" data="data"></xos-table>');
+          $compile(element)(scope);
+          scope.$digest();
+          isolatedScope = element.isolateScope().vm;
+        }));
+
+        it('should contain 2 columns', function() {
+          const th = element[0].getElementsByTagName('th');
+          expect(th.length).toEqual(2);
+          expect(isolatedScope.columns.length).toEqual(2);
+        });
+
+        it('should contain 3 rows', function() {
+          const tr = element[0].getElementsByTagName('tr');
+          expect(tr.length).toEqual(3);
+        });
+
+        it('should render labels', () => {
+          let label1 = $(element).find('thead tr th')[0]
+          let label2 = $(element).find('thead tr th')[1]
+          expect($(label1).text().trim()).toEqual('Label 1');
+          expect($(label2).text().trim()).toEqual('Label 2');
+        });
+
+        describe('when no data are provided', () => {
+          beforeEach(() => {
+            isolatedScope.data = [];
+            scope.$digest();
+          });
+          it('should render an alert', () => {
+            let alert = element[0].getElementsByClassName('alert');
+            let table = element[0].getElementsByTagName('table');
+            expect(alert.length).toEqual(1);
+            expect(table.length).toEqual(1);
+          });
+        });
+
+        describe('when a field type is provided', () => {
+          describe('and is boolean', () => {
+            beforeEach(() => {
+              scope.config = {
+                columns: [
+                  {
+                    label: 'Label 1',
+                    prop: 'label-1',
+                    type: 'boolean'
+                  },
+                  {
+                    label: 'Label 2',
+                    prop: 'label-2',
+                    type: 'boolean'
+                  }
+                ]
+              };
+              scope.data = [
+                {
+                  'label-1': true,
+                  'label-2': 1
+                },
+                {
+                  'label-1': false,
+                  'label-2': 0
+                }
+              ];
+              compileElement();
+            });
+
+            it('should render an incon', () => {
+              let td1 = $(element).find('tbody tr:first-child td')[0];
+              let td2 = $(element).find('tbody tr:last-child td')[0];
+              expect($(td1).find('i')).toHaveClass('glyphicon-ok');
+              expect($(td2).find('i')).toHaveClass('glyphicon-remove');
+            });
+
+            describe('with field filters', () => {
+              beforeEach(() => {
+                scope.config.filter = 'field';
+                compileElement();
+              });
+
+              it('should render a dropdown for filtering', () => {
+                let td1 = $(element).find('table tbody tr td')[0];
+                expect(td1).toContainElement('select');
+                expect(td1).not.toContainElement('input');
+              });
+
+              it('should correctly filter results', () => {
+                isolatedScope.query = {
+                  'label-1': false
+                };
+                scope.$digest();
+                expect(isolatedScope.query['label-1']).toBeFalsy();
+                const tr = $(element).find('tbody:last-child > tr');
+                const icon = $(tr[0]).find('td i');
+                expect(tr.length).toEqual(1);
+                expect(icon).toHaveClass('glyphicon-remove');
+              });
+
+              it('should correctly filter results if the field is in the form of 0|1', () => {
+                isolatedScope.query = {
+                  'label-2': false
+                };
+                scope.$digest();
+                expect(isolatedScope.query['label-1']).toBeFalsy();
+                const tr = $(element).find('tbody:last-child > tr');
+                const icon = $(tr[0]).find('td i');
+                expect(tr.length).toEqual(1);
+                expect(icon).toHaveClass('glyphicon-remove');
+              });
+            });
+          });
+
+          describe('and is date', () => {
+            beforeEach(() => {
+              scope.config = {
+                columns: [
+                  {
+                    label: 'Label 1',
+                    prop: 'label-1',
+                    type: 'date'
+                  }
+                ]
+              };
+              scope.data = [
+                {
+                  'label-1': '2015-02-17T22:06:38.059000Z'
+                }
+              ];
+              compileElement();
+            });
+
+            it('should render an formatted date', () => {
+              let td1 = $(element).find('tbody tr:first-child td')[0];
+              const expectedDate = filter('date')(scope.data[0]['label-1'], 'H:mm MMM d, yyyy');
+              expect($(td1).text().trim()).toEqual(expectedDate);
+            });
+          });
+
+          describe('and is array', () => {
+            beforeEach(() => {
+              scope.data = [
+                {categories: ['Film', 'Music']}
+              ];
+              scope.config = {
+                filter: 'field',
+                columns: [
+                  {
+                    label: 'Categories',
+                    prop: 'categories',
+                    type: 'array'
+                  }
+                ]
+              }
+              compileElement();
+            });
+            it('should render a comma separated list', () => {
+              let td1 = $(element).find('tbody:last-child tr:first-child')[0];
+              expect($(td1).text().trim()).toEqual('Film, Music');
+            });
+
+            it('should not render the filter field', () => {
+              let filter = $(element).find('tbody tr td')[0];
+              expect($(filter)).not.toContainElement('input');
+            });
+          });
+
+          describe('and is object', () => {
+            beforeEach(() => {
+              scope.data = [
+                {
+                  attributes: {
+                    age: 20,
+                    height: 50
+                  }
+                }
+              ];
+              scope.config = {
+                filter: 'field',
+                columns: [
+                  {
+                    label: 'Categories',
+                    prop: 'attributes',
+                    type: 'object'
+                  }
+                ]
+              }
+              compileElement();
+            });
+            it('should render a list of key-values', () => {
+              let td = $(element).find('tbody:last-child tr:first-child')[0];
+              let ageLabel = $(td).find('dl dt')[0];
+              let ageValue = $(td).find('dl dd')[0];
+              let heightLabel = $(td).find('dl dt')[1];
+              let heightValue = $(td).find('dl dd')[1];
+              expect($(ageLabel).text().trim()).toEqual('age');
+              expect($(ageValue).text().trim()).toEqual('20');
+              expect($(heightLabel).text().trim()).toEqual('height');
+              expect($(heightValue).text().trim()).toEqual('50');
+            });
+
+            it('should not render the filter field', () => {
+              let filter = $(element).find('tbody tr td')[0];
+              expect($(filter)).not.toContainElement('input');
+            });
+          });
+
+          describe('and is custom', () => {
+
+            let formatterFn = jasmine.createSpy('formatter').and.returnValue('Formatted Content');
+
+            beforeEach(() => {
+              scope.data = [
+                {categories: ['Film', 'Music']}
+              ];
+              scope.config = {
+                filter: 'field',
+                columns: [
+                  {
+                    label: 'Categories',
+                    prop: 'categories',
+                    type: 'custom',
+                    formatter: formatterFn
+                  }
+                ]
+              }
+              compileElement();
+            });
+
+            it('should check for a formatter property', () => {
+              function errorFunctionWrapper(){
+                // setup the parent scope
+                scope = rootScope.$new();
+                scope.config = {
+                  columns: [
+                    {
+                      label: 'Categories',
+                      prop: 'categories',
+                      type: 'custom'
+                    }
+                  ]
+                };
+                compileElement();
+              }
+              expect(errorFunctionWrapper).toThrow(new Error('[xosTable] You have provided a custom field type, a formatter function should provided too.'));
+            });
+
+            it('should check that the formatter property is a function', () => {
+              function errorFunctionWrapper(){
+                // setup the parent scope
+                scope = rootScope.$new();
+                scope.config = {
+                  columns: [
+                    {
+                      label: 'Categories',
+                      prop: 'categories',
+                      type: 'custom',
+                      formatter: 'formatter'
+                    }
+                  ]
+                };
+                compileElement();
+              }
+              expect(errorFunctionWrapper).toThrow(new Error('[xosTable] You have provided a custom field type, a formatter function should provided too.'));
+            });
+
+            it('should format data using the formatter property', () => {
+              let td1 = $(element).find('tbody:last-child tr:first-child')[0];
+              expect($(td1).text().trim()).toEqual('Formatted Content');
+              // the custom formatted should receive the entire object, otherwise is not so custom
+              expect(formatterFn).toHaveBeenCalledWith({categories: ['Film', 'Music']});
+            });
+
+            it('should not render the filter field', () => {
+              // displayed value is different from model val, filter would not work
+              let filter = $(element).find('tbody tr td')[0];
+              expect($(filter)).not.toContainElement('input');
+            });
+          });
+
+          describe('and is icon', () => {
+
+            beforeEach(() => {
+              scope.config = {
+                columns: [
+                  {
+                    label: 'Label 1',
+                    prop: 'label-1',
+                    type: 'icon',
+                    formatter: item => {
+                      switch (item['label-1']){
+                      case 1:
+                        return 'ok';
+                      case 2:
+                        return 'remove';
+                      case 3:
+                        return 'plus'
+                      }
+                    }
+                  }
+                ]
+              };
+              scope.data = [
+                {
+                  'label-1': 1
+                },
+                {
+                  'label-1': 2
+                },
+                {
+                  'label-1': 3
+                }
+              ];
+              compileElement();
+            });
+
+            it('should render a custom icon', () => {
+              let td1 = $(element).find('tbody tr:first-child td')[0];
+              let td2 = $(element).find('tbody tr:nth-child(2) td')[0];
+              let td3 = $(element).find('tbody tr:last-child td')[0];
+              expect($(td1).find('i')).toHaveClass('glyphicon-ok');
+              expect($(td2).find('i')).toHaveClass('glyphicon-remove');
+              expect($(td3).find('i')).toHaveClass('glyphicon-plus');
+            });
+          });
+        });
+
+        describe('when a link property is provided', () => {
+          beforeEach(() => {
+            scope.data = [
+              {
+                id: 1}
+            ];
+            scope.config = {
+              columns: [
+                {
+                  label: 'Id',
+                  prop: 'id',
+                  link: (item) => {
+                    return `/link/${item.id}`;
+                  }
+                }
+              ]
+            }
+            compileElement();
+          });
+
+          it('should check that the link property is a function', () => {
+            function errorFunctionWrapper(){
+              // setup the parent scope
+              scope = rootScope.$new();
+              scope.config = {
+                columns: [
+                  {
+                    label: 'Categories',
+                    prop: 'categories',
+                    link: 'custom'
+                  }
+                ]
+              };
+              compileElement();
+            }
+            expect(errorFunctionWrapper).toThrow(new Error('[xosTable] The link property should be a function.'));
+          });
+
+          it('should render a link with the correct url', () => {
+            let link = $(element).find('tbody tr:first-child td a')[0];
+            expect($(link).attr('href')).toEqual('/link/1');
+          });
+        });
+
+        describe('when actions are passed', () => {
+
+          let cb = jasmine.createSpy('callback')
+
+          beforeEach(() => {
+            isolatedScope.config.actions = [
+              {
+                label: 'delete',
+                icon: 'remove',
+                cb: cb,
+                color: 'red'
+              }
+            ];
+            scope.$digest();
+          });
+
+          it('should have 3 columns', () => {
+            const th = element[0].getElementsByTagName('th');
+            expect(th.length).toEqual(3);
+            expect(isolatedScope.columns.length).toEqual(2);
+          });
+
+          it('when clicking on action should invoke callback', () => {
+            const link = element[0].getElementsByTagName('a')[0];
+            link.click();
+            expect(cb).toHaveBeenCalledWith(scope.data[0]);
+          });
+        });
+
+        describe('when filter is fulltext', () => {
+          beforeEach(() => {
+            isolatedScope.config.filter = 'fulltext';
+            scope.$digest();
+          });
+
+          it('should render a text field', () => {
+            const textField = element[0].getElementsByTagName('input');
+            expect(textField.length).toEqual(1);
+          });
+
+          describe('and a value is enterd', () => {
+            beforeEach(() => {
+              isolatedScope.query = '2.2';
+              scope.$digest();
+            });
+
+            it('should contain 2 rows', function() {
+              const tr = element[0].getElementsByTagName('tr');
+              expect(tr.length).toEqual(2);
+            });
+          });
+        });
+
+        describe('when filter is field', () => {
+          beforeEach(() => {
+            isolatedScope.config.filter = 'field';
+            scope.$digest();
+          });
+
+          it('should render a text field for each column', () => {
+            const textField = element[0].getElementsByTagName('input');
+            expect(textField.length).toEqual(2);
+          });
+
+          describe('and a value is enterd', () => {
+            beforeEach(() => {
+              isolatedScope.query = {'label-1': '2.1'};
+              scope.$digest();
+            });
+
+            it('should contain 3 rows', function() {
+              const tr = element[0].getElementsByTagName('tr');
+              expect(tr.length).toEqual(3);
+            });
+          });
+        });
+
+        describe('when order is true', () => {
+          beforeEach(() => {
+            isolatedScope.config.order = true;
+            scope.$digest();
+          });
+
+          it('should render a arrows beside', () => {
+            const arrows = element[0].getElementsByTagName('i');
+            expect(arrows.length).toEqual(4);
+          });
+
+          describe('and a default ordering is passed', () => {
+
+            beforeEach(() => {
+              scope.config.order = {
+                field: 'label-1',
+                reverse: true
+              };
+              compileElement();
+            });
+
+            it('should orderBy the default order', () => {
+              const tr = $(element).find('tr');
+              expect($(tr[1]).text()).toContain('Sample 2.2');
+              expect($(tr[2]).text()).toContain('Sample 1.1');
+            });
+          });
+
+          describe('and an order is set', () => {
+            beforeEach(() => {
+              isolatedScope.orderBy = 'label-1';
+              isolatedScope.reverse = true;
+              scope.$digest();
+            });
+
+            it('should orderBy', function() {
+              // console.log($(element).find('table'));
+              const tr = $(element).find('tr');
+              expect($(tr[1]).text()).toContain('Sample 2.2');
+              expect($(tr[2]).text()).toContain('Sample 1.1');
+            });
+          });
+        });
+      });
+    });
+  });
+})();
+
diff --git a/spec/ui/validation.test.js b/spec/ui/validation.test.js
new file mode 100644
index 0000000..44d9f96
--- /dev/null
+++ b/spec/ui/validation.test.js
@@ -0,0 +1,86 @@
+/**
+ * © OpenCORD
+ *
+ * Created by teone on 4/15/16.
+ */
+
+(function () {
+  'use strict';
+
+  let compile, element, scope, rootScope;
+
+  const compileElement = (el) => {
+    element = el;
+
+    if(!scope){
+      scope = rootScope.$new();
+    }
+    if(angular.isUndefined(element)){
+      element = angular.element('<xos-validation field="field" form="form"></xos-validation>');
+    }
+    compile(element)(scope);
+    scope.$digest();
+  }
+
+  describe('The xos.helper module', function(){
+    describe('The xos-validation component', () => {
+
+      beforeEach(module('xos.helpers'));
+
+      describe('when the form has no errors', () => {
+        beforeEach(inject(($compile, $rootScope) => {
+          compile = $compile;
+          scope = $rootScope.$new();
+
+          scope.field = {
+            $error: {}
+          };
+
+          scope.form = {
+            $submitted: true
+          }
+
+          compileElement();
+        }));
+
+        it('should not show an alert by default', () => {
+          expect($(element).find('xos-alert > .alert')[0]).toHaveClass('ng-hide');
+        });
+      });
+
+      let availableErrors = [
+        {
+          type: 'required',
+          message: 'Field required'
+        },
+        {
+          type: 'email',
+          message: 'This is not a valid email'
+        },
+        {
+          type: 'minlength',
+          message: 'Too short'
+        },
+        {
+          type: 'maxlength',
+          message: 'Too long'
+        },
+        {
+          type: 'custom',
+          message: 'Field invalid'
+        },
+      ];
+
+      // use a loop to generate similar test
+      availableErrors.forEach((e, i) => {
+        it(`should show an alert for ${e.type} errors`, () => {
+          scope.field.$error[e.type] = true;
+          compileElement();
+          let alert = $(element).find('xos-alert > .alert')[i];
+          expect(alert).not.toHaveClass('ng-hide');
+          expect(alert).toHaveText(e.message);
+        });
+      });
+    });
+  });
+})();
\ No newline at end of file
diff --git a/spec/ui/xos.helpers.mock.js b/spec/ui/xos.helpers.mock.js
new file mode 100644
index 0000000..bf0f0f5
--- /dev/null
+++ b/spec/ui/xos.helpers.mock.js
@@ -0,0 +1,5 @@
+(function () {
+  'use strict';
+  angular.module('xos.helpers', ['xos.uiComponents'])
+  .factory('_', $window => $window._ );
+})();
\ No newline at end of file
diff --git a/src/index.ngdoc.js b/src/index.ngdoc.js
new file mode 100644
index 0000000..6f6a77c
--- /dev/null
+++ b/src/index.ngdoc.js
@@ -0,0 +1,13 @@
+/**
+* @ngdoc overview
+* @name ngXosLib
+* @id index
+* @description
+* # Welcome to the ngXosLib documentation! <br/>
+* This is the module that group all the helpers service and UI components for XOS.
+* <br/><br/>
+* You can find all the documentation related to the UI Component Library here: <a href="#/module/xos.uiComponents"> xos.uiComponents</a> <br/>
+* and the documentation related to all the other helpers here: <a href="#/module/xos.helpers"> xos.helpers</a> <br/>
+* ## Issues
+* Please report issues at https://jira.opencord.org
+**/
\ No newline at end of file
diff --git a/src/services/csrfToken.interceptor.js b/src/services/csrfToken.interceptor.js
new file mode 100644
index 0000000..5f87de5
--- /dev/null
+++ b/src/services/csrfToken.interceptor.js
@@ -0,0 +1,24 @@
+(function() {
+  'use strict';
+
+  /**
+  * @ngdoc service
+  * @name xos.helpers.SetCSRFToken
+  * @description This factory is automatically loaded trough xos.helpers and will add an $http interceptor that will the CSRF-Token to your request headers
+  **/
+
+  angular
+      .module('xos.helpers')
+      .factory('SetCSRFToken', setCSRFToken);
+
+  function setCSRFToken($cookies) {
+    return {
+      request: function(request){
+        if(request.method !== 'GET'){
+          request.headers['X-CSRFToken'] = $cookies.get('xoscsrftoken');
+        }
+        return request;
+      }
+    };
+  }
+})();
diff --git a/src/services/helpers/ui/comparator.service.js b/src/services/helpers/ui/comparator.service.js
new file mode 100644
index 0000000..24bf9f9
--- /dev/null
+++ b/src/services/helpers/ui/comparator.service.js
@@ -0,0 +1,96 @@
+(function() {
+  'use strict';
+
+  /**
+   * @ngdoc service
+   * @name xos.uiComponents.Comparator
+   * @description
+   * This factory define a function that replace the native angular.filter comparator.
+   *
+   * It is done to allow the comparation between (0|1) values with booleans.
+   * >Note that this factory return a single function, not an object.
+   *
+   * The tipical usage of this factory is inside an `ng-repeat`
+   * @example
+   * <example module="comparator">
+   *   <file name="index.html">
+   *     <div ng-controller="sample as vm">
+   *       <div class="row">
+   *         <div class="col-xs-6">
+   *           <label>Filter by name:</label>
+   *           <input class="form-control" type="text" ng-model="vm.query.name"/>
+   *         </div>
+   *         <div class="col-xs-6">
+   *           <label>Filter by status:</label>
+   *           <select
+   *            ng-model="vm.query.status"
+   *            ng-options="i for i in [true, false]">
+   *           </select>
+   *         </div>
+   *       </div>
+   *       <div ng-repeat="item in vm.data | filter:vm.query:vm.comparator">
+   *         <div class="row">
+   *           <div class="col-xs-6">{{item.name}}</div>
+   *           <div class="col-xs-6">{{item.status}}</div>
+   *         </div>
+   *       </div>
+   *     </div>
+   *   </file>
+   *   <file name="script.js">
+   *     angular.module('comparator', ['xos.uiComponents'])
+   *     .controller('sample', function(Comparator){
+   *       this.comparator = Comparator;
+   *       this.data = [
+   *         {name: 'Jhon', status: 1},
+   *         {name: 'Jack', status: 0},
+   *         {name: 'Mike', status: 1},
+   *         {name: 'Scott', status: 0}
+   *       ];
+   *     });
+   *   </file>
+   * </example>
+   **/
+
+  angular
+    .module('xos.uiComponents')
+    .factory('Comparator', comparator);
+
+  function comparator(_) {
+
+    return function(actual, expected){
+
+      if (angular.isUndefined(actual)) {
+        // No substring matching against `undefined`
+        return false;
+      }
+      if ((actual === null) || (expected === null)) {
+        // No substring matching against `null`; only match against `null`
+        return actual === expected;
+      }
+      if (angular.isObject(expected) || (angular.isObject(actual))){
+        return angular.equals(expected, actual);
+      }
+
+      if(_.isBoolean(actual) || _.isBoolean(expected)){
+        if(actual === 0 || actual === 1){
+          actual = !!actual;
+        }
+        return angular.equals(expected, actual);
+      }
+
+      if(!angular.isString(actual) || !angular.isString(expected)){
+        if(angular.isDefined(actual.toString) && angular.isDefined(expected.toString)){
+          actual = actual.toString();
+          expected = expected.toString();
+        }
+        else {
+          return actual === expected;
+        }
+      }
+
+      actual = actual.toLowerCase() + '';
+      expected = expected.toLowerCase() + '';
+      return actual.indexOf(expected) !== -1;
+    };
+  }
+})();
diff --git a/src/services/helpers/ui/form.helpers.js b/src/services/helpers/ui/form.helpers.js
new file mode 100644
index 0000000..582cb8a
--- /dev/null
+++ b/src/services/helpers/ui/form.helpers.js
@@ -0,0 +1,152 @@
+(function () {
+  
+  angular.module('xos.uiComponents')
+
+  /**
+  * @ngdoc service
+  * @name xos.uiComponents.XosFormHelpers
+  * @requires xos.uiComponents.LabelFormatter
+  * @requires xos.helpers._
+  **/
+
+  .service('XosFormHelpers', function(_, LabelFormatter){
+
+    /**
+    * @ngdoc method
+    * @name xos.uiComponents.XosFormHelpers#_isEmail
+    * @methodOf xos.uiComponents.XosFormHelpers
+    * @description
+    * Return true if the string is an email address
+    * @param {string} text The string to be evaluated
+    * @returns {boolean} If the string match an email format
+    **/
+
+    this._isEmail = (text) => {
+      const re = /(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))/;
+      return re.test(text);
+    };
+
+    /**
+    * @ngdoc method
+    * @name xos.uiComponents.XosFormHelpers#_getFieldFormat
+    * @methodOf xos.uiComponents.XosFormHelpers
+    * @description
+    * Return the type of the input
+    * @param {mixed} value The data to be evaluated
+    * @returns {string} The type of the input
+    **/
+
+    this._getFieldFormat = (value) => {
+
+      if(angular.isArray(value)){
+        return 'array';
+      }
+
+      // check if is date
+      if (_.isDate(value) || (!Number.isNaN(Date.parse(value)) && new Date(value).getTime() > 631180800000)){
+        return 'date';
+      }
+
+      // check if is boolean
+      // isNaN(false) = false, false is a number (0), true is a number (1)
+      if(typeof value  === 'boolean'){
+        return 'boolean';
+      }
+
+      // check if a string is an email
+      if(this._isEmail(value)){
+        return 'email';
+      }
+
+      // if null return string
+      if(angular.isString(value) || value === null){
+        return 'text';
+      }
+
+      return typeof value;
+    };
+
+    /**
+    * @ngdoc method
+    * @name xos.uiComponents.XosFormHelpers#buildFormStructure
+    * @methodOf xos.uiComponents.XosFormHelpers
+    * @description
+    * Return the type of the input
+    * @param {object} modelField An object containing one property for each field of the model
+    * @param {object} customField An object containing one property for each field custom field
+    * @param {object} model The actual model on wich build the form structure (it is used to determine the type of the input)
+    * @returns {object} An object describing the form structure in the form of:
+    * ```
+    * {
+    *   'field-name': {
+    *     label: 'Label',
+    *     type: 'number', //typeof field
+    *     validators: {}, // see xosForm for more details
+    *     hint: 'A Custom hint for the field'
+    *   }
+    * }
+    * ```
+    **/
+
+    this.buildFormStructure = (modelField, customField, model) => {
+
+      modelField = angular.extend(modelField, customField);
+      customField = customField || {};
+
+      return _.reduce(Object.keys(modelField), (form, f) => {
+
+        form[f] = {
+          label: (customField[f] && customField[f].label) ? `${customField[f].label}:` : LabelFormatter.format(f),
+          type: (customField[f] && customField[f].type) ? customField[f].type : this._getFieldFormat(model[f]),
+          validators: (customField[f] && customField[f].validators) ? customField[f].validators : {},
+          hint: (customField[f] && customField[f].hint)? customField[f].hint : '',
+        };
+
+        if(customField[f] && customField[f].options){
+          form[f].options = customField[f].options;
+        }
+        if(customField[f] && customField[f].properties){
+          form[f].properties = customField[f].properties;
+        }
+        if(form[f].type === 'date'){
+          model[f] = new Date(model[f]);
+        }
+
+        if(form[f].type === 'number'){
+          model[f] = parseInt(model[f], 10);
+        }
+
+        return form;
+      }, {});
+    };
+
+    /**
+    * @ngdoc method
+    * @name xos.uiComponents.XosFormHelpers#parseModelField
+    * @methodOf xos.uiComponents.XosFormHelpers
+    * @description
+    * Helpers for buildFormStructure, convert a list of model properties in an object used to build the form structure, eg:
+    * ```
+    * // input:
+    * ['id', 'name'm 'mail']
+    *
+    * // output
+    * {
+    *   id: {},
+    *   name: {},
+    *   mail: {}
+    * }
+    * ```
+    * @param {array} fields An array of fields representing the model properties
+    * @returns {object} An object containing one property for each field of the model
+    **/
+
+    this.parseModelField = (fields) => {
+      return _.reduce(fields, (form, f) => {
+        form[f] = {};
+        return form;
+      }, {});
+    }
+
+  });
+})();
\ No newline at end of file
diff --git a/src/services/helpers/ui/label_formatter.service.js b/src/services/helpers/ui/label_formatter.service.js
new file mode 100644
index 0000000..f23fea4
--- /dev/null
+++ b/src/services/helpers/ui/label_formatter.service.js
@@ -0,0 +1,90 @@
+(function() {
+  'use strict';
+
+  /**
+  * @ngdoc service
+  * @name xos.uiComponents.LabelFormatter
+  * @description This factory define a set of helper function to format label started from an object property
+  **/
+
+  angular
+      .module('xos.uiComponents')
+      .factory('LabelFormatter', labelFormatter);
+
+  function labelFormatter() {
+
+    /**
+    * @ngdoc method
+    * @name xos.uiComponents.LabelFormatter#_formatByUnderscore
+    * @methodOf xos.uiComponents.LabelFormatter
+    * @description
+    * Convert a `snake_case` string to readable string.<br/>
+    * Eg: `this_string` will became `this string`
+    * @param {string} string The string to be converted
+    * @returns {string} The converten string
+    **/
+
+    const _formatByUnderscore = string => string.split('_').join(' ').trim();
+
+    /**
+    * @ngdoc method
+    * @name xos.uiComponents.LabelFormatter#_formatByUppercase
+    * @methodOf xos.uiComponents.LabelFormatter
+    * @description
+    * Convert a `camelCase` string to readable string.<br/>
+    * Eg: `thisString` will became `this string`
+    * @param {string} string The string to be converted
+    * @returns {string} The converten string
+    **/
+
+    const _formatByUppercase = string => string.split(/(?=[A-Z])/).map(w => w.toLowerCase()).join(' ');
+
+    /**
+    * @ngdoc method
+    * @name xos.uiComponents.LabelFormatter#_capitalize
+    * @methodOf xos.uiComponents.LabelFormatter
+    * @description
+    * Capitalize the first letter of a string.<br/>
+    * Eg: `this string` will became `This string`
+    * @param {string} string The string to be converted
+    * @returns {string} The converten string
+    **/
+
+    const _capitalize = string => string.slice(0, 1).toUpperCase() + string.slice(1);
+
+    /**
+    * @ngdoc method
+    * @name xos.uiComponents.LabelFormatter#format
+    * @methodOf xos.uiComponents.LabelFormatter
+    * @description
+    * Apply in order:
+    * - _formatByUnderscore
+    * - _formatByUppercase
+    * - _capitalize
+    * - replace multiple space with a single one
+    * - append `:` at the end 
+    * <br/>
+    * Eg: `this_string` will became `This string:`<br/>
+    * Eg: `thisString` will became `This string:`
+    * @param {string} string The string to be converted
+    * @returns {string} The converten string
+    **/
+
+    const format = (string) => {
+      string = _formatByUnderscore(string);
+      string = _formatByUppercase(string);
+
+      string = _capitalize(string).replace(/\s\s+/g, ' ') + ':';
+      return string.replace('::', ':');
+    };
+
+    return {
+      // test export
+      _formatByUnderscore: _formatByUnderscore,
+      _formatByUppercase: _formatByUppercase,
+      _capitalize: _capitalize,
+      // export to use
+      format: format
+    };
+  }
+})();
diff --git a/src/services/helpers/user-prefs.service.js b/src/services/helpers/user-prefs.service.js
new file mode 100644
index 0000000..f3f1f19
--- /dev/null
+++ b/src/services/helpers/user-prefs.service.js
@@ -0,0 +1,154 @@
+(function () {

+  

+  angular.module('xos.helpers')

+

+  /**

+  * @ngdoc service

+  * @name xos.helpers.XosUserPrefs

+  * @description

+  * This service is used to store the user preferences in cookies, so that they survive to page changes.

+  * The structure of the user preference is:

+  * ```

+  * {

+  *   synchronizers: {

+  *     notification: {

+  *       'volt': boolean,

+  *       'openstack': boolean,

+  *       ...

+  *     }

+  *   }

+  *   userData: {

+  *     current_user_site_id: Number,

+  *     current_user_site_user_names: Array[1],

+  *     ...

+  *     }

+  * }

+  * ```

+  **/

+

+  .service('XosUserPrefs', function($cookies, Me, $q){

+

+    let userPrefs = $cookies.get('xosUserPrefs') ? angular.fromJson($cookies.get('xosUserPrefs')) : {};

+

+    /**

+    * @ngdoc method

+    * @name xos.helpers.XosUserPrefs#getAll

+    * @methodOf xos.helpers.XosUserPrefs

+    * @description

+    * Return all the user preferences stored in cookies

+    * @returns {object} The user preferences

+    **/

+    this.getAll = () => {

+      userPrefs = $cookies.get('xosUserPrefs') ? angular.fromJson($cookies.get('xosUserPrefs')) : {};

+      return userPrefs;

+    };

+

+    /**

+    * @ngdoc method

+    * @name xos.helpers.XosUserPrefs#setAll

+    * @methodOf xos.helpers.XosUserPrefs

+    * @description

+    * Override all user preferences

+    * @param {object} prefs The user preferences

+    **/

+    this.setAll = (prefs) => {

+      $cookies.put('xosUserPrefs', angular.toJson(prefs));

+    };

+

+    /**

+    * @ngdoc method

+    * @name xos.helpers.XosUserPrefs#getSynchronizerNotificationStatus

+    * @methodOf xos.helpers.XosUserPrefs

+    * @description

+    * Return the synchronizer notification status, if name is not provided return the status for all synchronizers

+    * @param {string=} prefs The synchronizer name

+    * @returns {object | string} The synchronizer status

+    **/

+    this.getSynchronizerNotificationStatus = (name = false) => {

+      if(name){

+        return this.getAll().synchronizers.notification[name];

+      }

+      return this.getAll().synchronizers.notification;

+    };

+

+

+    /**

+    * @ngdoc method

+    * @name xos.helpers.XosUserPrefs#getUserDetailsCookie

+    * @methodOf xos.helpers.XosUserPrefs

+    * @description

+    * Return all the user details stored in cookies or call the service

+    * @returns {object} The user details

+    **/

+    this.getUserDetailsCookie = () => {

+      const defer = $q.defer();

+      let localPref  = this.getAll();

+      if(!localPref.userData){

+        this.setUserDetailsCookie().$promise.then((data)=>{

+          defer.resolve(data);

+        });

+      }

+      else{

+        defer.resolve(localPref.userData);

+      }

+      return {$promise: defer.promise};

+    };

+

+    /**

+    * @ngdoc method

+    * @name xos.helpers.XosUserPrefs#setUserDetailsCookie

+    * @methodOf xos.helpers.XosUserPrefs

+    * @description

+    * Save the user details in the cookie

+    * @param {object} details stored in cookie

+    * @param {objects} returns the user details as a promise

+    **/

+    this.setUserDetailsCookie = (userData = null)=> {

+

+      const defer = $q.defer();

+      let cookies = this.getAll();

+      if (!userData){

+        Me.get().then((user)=> {

+          cookies.userData = user;

+          this.setAll(cookies);

+          defer.resolve(user);

+        })

+        .catch ((e) => {

+          defer.reject(e);

+        });

+      }

+      else {

+        cookies.userData = userData;

+        this.setAll(cookies);

+        defer.resolve(userData);

+      }

+      return {$promise: defer.promise};

+    }

+

+     /**

+    * @ngdoc method

+    * @name xos.helpers.XosUserPrefs#setSynchronizerNotificationStatus

+    * @methodOf xos.helpers.XosUserPrefs

+    * @description

+    * Update the notification status for a single synchronizer

+    * @param {string} name The synchronizer name

+    * @param {boolean} value The notification status (true means that it has been sent)

+    **/

+

+    this.setSynchronizerNotificationStatus = (name = false, value) => {

+      if(!name){

+        throw new Error('[XosUserPrefs] When updating a synchronizer is mandatory to provide a name.')

+      }

+

+      let cookies = this.getAll();

+

+      if(!cookies.synchronizers){

+        cookies.synchronizers = {

+          notification: {}

+        }

+      }

+      cookies.synchronizers.notification[name] = value;

+      this.setAll(cookies);

+    }

+  });

+})();
\ No newline at end of file
diff --git a/src/services/log.decorator.js b/src/services/log.decorator.js
new file mode 100644
index 0000000..37d36f9
--- /dev/null
+++ b/src/services/log.decorator.js
@@ -0,0 +1,60 @@
+// TODO write tests for log
+
+/* eslint-disable  angular/ng_window_service*/
+
+angular.module('xos.helpers')
+.config([ '$provide', function( $provide )
+{
+  // Use the `decorator` solution to substitute or attach behaviors to
+  // original service instance; @see angular-mocks for more examples....
+
+  $provide.decorator( '$log', [ '$delegate', function( $delegate )
+  {
+
+    const isLogEnabled = () => {
+      return window.location.href.indexOf('debug=true') >= 0;
+    };
+    // Save the original $log.debug()
+    let logFn = $delegate.log;
+    let infoFn = $delegate.info;
+    let warnFn = $delegate.warn;
+    //let errorFn = $delegate.error;
+    let debugFn = $delegate.debug;
+
+    // create the replacement function
+    const replacement = (fn) => {
+      return function(){
+         //console.log(`Is Log Enabled: ${isLogEnabled()}`)
+        if(!isLogEnabled()){
+          // console.log('logging is disabled');
+          return;
+        }
+
+        let args    = [].slice.call(arguments);
+        let now     = new Date();
+
+        // Prepend timestamp
+        args[0] = `[${now.getHours()}:${now.getMinutes()}:${now.getSeconds()}] ${args[0]}`;
+
+        // HACK awfull fix for angular mock implementation whithin jasmine test failing issue
+        if (angular.isFunction($delegate.reset) && !($delegate.debug.logs instanceof Array)) {
+          // if we are within the mock and did not reset yet, we call it to avoid issue
+          // console.log('mock log impl fix to avoid logs array not existing...');
+          $delegate.reset();
+        }
+
+        // Call the original with the output prepended with formatted timestamp
+
+        return fn.apply(null, args)
+      };
+    };
+
+    $delegate.info = replacement(infoFn);
+    $delegate.log = replacement(logFn);
+    $delegate.warn = replacement(warnFn);
+    //$delegate.error = replacement(errorFn); // note this will prevent errors to be printed
+    $delegate.debug = replacement(debugFn);
+
+    return $delegate;
+  }]);
+}]);
\ No newline at end of file
diff --git a/src/services/noHyperlinks.interceptor.js b/src/services/noHyperlinks.interceptor.js
new file mode 100644
index 0000000..af3dd63
--- /dev/null
+++ b/src/services/noHyperlinks.interceptor.js
@@ -0,0 +1,24 @@
+(function() {
+  'use strict';
+
+  /**
+  * @ngdoc service
+  * @name xos.helpers.NoHyperlinks
+  * @description This factory is automatically loaded trough xos.helpers and will add an $http interceptor that will add ?no_hyperlinks=1 to your api request, that is required by django
+  **/
+
+  angular
+      .module('xos.helpers')
+      .factory('NoHyperlinks', noHyperlinks);
+
+  function noHyperlinks() {
+    return {
+      request: function(request){
+        if(request.url.indexOf('.html') === -1){
+          request.url += '?no_hyperlinks=1';
+        }
+        return request;
+      }
+    };
+  }
+})();
\ No newline at end of file
diff --git a/src/services/notification.service.js b/src/services/notification.service.js
new file mode 100644
index 0000000..9a1598e
--- /dev/null
+++ b/src/services/notification.service.js
@@ -0,0 +1,62 @@
+/* eslint-disable  angular/ng_window_service*/
+(function() {
+  'use strict';
+
+  angular
+  .module('xos.helpers')
+  .factory('Notification', function(){
+    return window.Notification;
+  })
+  /**
+  * @ngdoc service
+  * @name xos.helpers.xosNotification
+  * @description This factory define a set of helper function to trigger desktop notification
+  **/
+  .service('xosNotification', function($q, $log, Notification) {
+
+    this.checkPermission = () => {
+      const deferred = $q.defer();
+      Notification.requestPermission()
+      .then(permission => {
+        if (permission === 'granted') {
+          deferred.resolve(permission);
+        }
+        else {
+          deferred.reject(permission);
+        }
+      });
+      return deferred.promise;
+    };
+
+    this.sendNotification = (title, options) => {
+      const notification = new Notification(title, options);
+      notification.onerror = function(err){
+        $log.error(err);
+      };
+    };
+
+    /**
+    * @ngdoc method
+    * @name xos.helpers.xosNotification#notify
+    * @methodOf xos.helpers.xosNotification
+    * @description
+    * This method will check for user permission and if granted will send a browser notification.
+    * @param {string} title The notification title
+    * @param {object} options The notification options: `{icon: 'url', body: 'Notification body'}`
+    **/
+
+    this.notify = (title, options) => {
+      if (!('Notification' in window)) {
+        $log.info('This browser does not support desktop notification');
+      }
+      else if (Notification.permission !== 'granted') {
+        this.checkPermission()
+        .then(() => this.sendNotification(title, options));
+      }
+      else if (Notification.permission === 'granted') {
+        this.sendNotification(title, options);
+      }
+    }
+
+  })
+})();
diff --git a/src/services/rest/Dashboards.js b/src/services/rest/Dashboards.js
new file mode 100644
index 0000000..42af90b
--- /dev/null
+++ b/src/services/rest/Dashboards.js
@@ -0,0 +1,31 @@
+(function() {
+  'use strict';
+
+  angular.module('xos.helpers')
+  /**
+  * @ngdoc service
+  * @name xos.helpers.Dashboards
+  * @description Angular resource to fetch /api/core/dashboardviews/:id/
+  **/
+  .service('Dashboards', function($resource, $q, $http){
+    const r = $resource('/api/core/dashboardviews/:id/', { id: '@id' }, {
+      update: { method: 'PUT' }
+    });
+
+    r.prototype.$save = function(){
+      const d = $q.defer();
+
+      $http.put(`/api/core/dashboardviews/${this.id}/`, this)
+      .then((res) => {
+        d.resolve(res.data);
+      })
+      .catch(e => {
+        d.reject(e.data);
+      });
+
+      return d.promise;
+    }
+
+    return r;
+  })
+})();
\ No newline at end of file
diff --git a/src/services/rest/Deployments.js b/src/services/rest/Deployments.js
new file mode 100644
index 0000000..4fecbc2
--- /dev/null
+++ b/src/services/rest/Deployments.js
@@ -0,0 +1,15 @@
+(function() {
+  'use strict';
+
+  angular.module('xos.helpers')
+  /**
+  * @ngdoc service
+  * @name xos.helpers.Deployments
+  * @description Angular resource to fetch /api/core/deployments/:id/
+  **/
+  .service('Deployments', function($resource){
+    return $resource('/api/core/deployments/:id/', { id: '@id' }, {
+      update: { method: 'PUT' }
+    });
+  })
+})();
\ No newline at end of file
diff --git a/src/services/rest/Example.js b/src/services/rest/Example.js
new file mode 100644
index 0000000..b13ccda
--- /dev/null
+++ b/src/services/rest/Example.js
@@ -0,0 +1,13 @@
+(function() {
+  'use strict';
+
+  angular.module('xos.helpers')
+  /**
+  * @ngdoc service
+  * @name xos.helpers.Example-Services-Collection
+  * @description Angular resource to fetch /api/service/exampleservice/
+  **/
+  .service('Example-Services-Collection', function($resource){
+    return $resource('/api/service/exampleservice/');
+  })
+})();
\ No newline at end of file
diff --git a/src/services/rest/Flavors.js b/src/services/rest/Flavors.js
new file mode 100644
index 0000000..348b770
--- /dev/null
+++ b/src/services/rest/Flavors.js
@@ -0,0 +1,15 @@
+(function() {
+  'use strict';
+
+  angular.module('xos.helpers')
+  /**
+  * @ngdoc service
+  * @name xos.helpers.Flavors
+  * @description Angular resource to fetch /api/core/flavors/:id/
+  **/
+  .service('Flavors', function($resource){
+    return $resource('/api/core/flavors/:id/', { id: '@id' }, {
+      update: { method: 'PUT' }
+    });
+  })
+})();
\ No newline at end of file
diff --git a/src/services/rest/Images.js b/src/services/rest/Images.js
new file mode 100644
index 0000000..4fe9cb3
--- /dev/null
+++ b/src/services/rest/Images.js
@@ -0,0 +1,15 @@
+(function() {
+  'use strict';
+
+  angular.module('xos.helpers')
+  /**
+  * @ngdoc service
+  * @name xos.helpers.Images
+  * @description Angular resource to fetch /api/core/images/
+  **/
+  .service('Images', function($resource){
+    return $resource('/api/core/images/:id/', { id: '@id' }, {
+      update: { method: 'PUT' }
+    });
+  })
+})();
\ No newline at end of file
diff --git a/src/services/rest/Instances.js b/src/services/rest/Instances.js
new file mode 100644
index 0000000..f1e8521
--- /dev/null
+++ b/src/services/rest/Instances.js
@@ -0,0 +1,15 @@
+(function() {
+  'use strict';
+
+  angular.module('xos.helpers')
+  /**
+  * @ngdoc service
+  * @name xos.helpers.Instances
+  * @description Angular resource to fetch /api/core/instances/:id/
+  **/
+  .service('Instances', function($resource){
+    return $resource('/api/core/instances/:id/', { id: '@id' }, {
+      update: { method: 'PUT' }
+    });
+  })
+})();
\ No newline at end of file
diff --git a/src/services/rest/Me.js b/src/services/rest/Me.js
new file mode 100644
index 0000000..5dd1043
--- /dev/null
+++ b/src/services/rest/Me.js
@@ -0,0 +1,26 @@
+(function() {

+  'use strict';

+

+  angular.module('xos.helpers')

+  /**

+  * @ngdoc service

+  * @name xos.helpers.Me

+  * @description Http read-only api to fetch /api/utility/me/

+  **/

+  .service('Me', function($q,$http){

+

+    this.get = () => {

+      let deferred = $q.defer();

+

+      $http.get('/api/utility/me/')

+      .then(res => {

+        deferred.resolve(res.data);

+      })

+      .catch(e => {

+        deferred.reject(e);

+      });

+      return deferred.promise;

+

+    };

+  })

+})();
\ No newline at end of file
diff --git a/src/services/rest/Networks.js b/src/services/rest/Networks.js
new file mode 100644
index 0000000..74b73b6
--- /dev/null
+++ b/src/services/rest/Networks.js
@@ -0,0 +1,15 @@
+(function() {
+  'use strict';
+
+  angular.module('xos.helpers')
+  /**
+  * @ngdoc service
+  * @name xos.helpers.Networks
+  * @description Angular resource to fetch /api/core/networks/:id/
+  **/
+  .service('Networks', function($resource){
+    return $resource('/api/core/networks/:id/', { id: '@id' }, {
+      update: { method: 'PUT' }
+    });
+  })
+})();
diff --git a/src/services/rest/Networkstemplates.js b/src/services/rest/Networkstemplates.js
new file mode 100644
index 0000000..961d5d8
--- /dev/null
+++ b/src/services/rest/Networkstemplates.js
@@ -0,0 +1,15 @@
+(function() {
+  'use strict';
+
+  angular.module('xos.helpers')
+  /**
+  * @ngdoc service
+  * @name xos.helpers.Networkstemplates
+  * @description Angular resource to fetch /api/core/networktemplates/:id/
+  **/
+  .service('Networkstemplates', function($resource){
+    return $resource('/api/core/networktemplates/:id/', { id: '@id' }, {
+      update: { method: 'PUT' }
+    });
+  })
+})();
diff --git a/src/services/rest/Nodes.js b/src/services/rest/Nodes.js
new file mode 100644
index 0000000..bf2e387
--- /dev/null
+++ b/src/services/rest/Nodes.js
@@ -0,0 +1,15 @@
+(function() {
+  'use strict';
+
+  angular.module('xos.helpers')
+  /**
+  * @ngdoc service
+  * @name xos.helpers.Nodes
+  * @description Angular resource to fetch /api/core/nodes/:id/
+  **/
+  .service('Nodes', function($resource){
+    return $resource('/api/core/nodes/:id/', { id: '@id' }, {
+      update: { method: 'PUT' }
+    });
+  })
+})();
\ No newline at end of file
diff --git a/src/services/rest/ONOS-Apps.js b/src/services/rest/ONOS-Apps.js
new file mode 100644
index 0000000..8d4c104
--- /dev/null
+++ b/src/services/rest/ONOS-Apps.js
@@ -0,0 +1,13 @@
+(function() {
+  'use strict';
+
+  angular.module('xos.helpers')
+  /**
+  * @ngdoc service
+  * @name xos.helpers.ONOS-App-Collection
+  * @description Angular resource to fetch /api/tenant/onos/app/
+  **/
+  .service('ONOS-App-Collection', function($resource){
+    return $resource('/api/tenant/onos/app/');
+  })
+})();
\ No newline at end of file
diff --git a/src/services/rest/ONOS-Services.js b/src/services/rest/ONOS-Services.js
new file mode 100644
index 0000000..19270e1
--- /dev/null
+++ b/src/services/rest/ONOS-Services.js
@@ -0,0 +1,13 @@
+(function() {
+  'use strict';
+
+  angular.module('xos.helpers')
+  /**
+  * @ngdoc service
+  * @name xos.helpers.ONOS-Services-Collection
+  * @description Angular resource to fetch /api/service/onos/
+  **/
+  .service('ONOS-Services-Collection', function($resource){
+    return $resource('/api/service/onos/');
+  })
+})();
\ No newline at end of file
diff --git a/src/services/rest/Services.js b/src/services/rest/Services.js
new file mode 100644
index 0000000..eda57e4
--- /dev/null
+++ b/src/services/rest/Services.js
@@ -0,0 +1,15 @@
+(function() {
+  'use strict';
+
+  angular.module('xos.helpers')
+  /**
+  * @ngdoc service
+  * @name xos.helpers.Services
+  * @description Angular resource to fetch /api/core/services/:id/
+  **/
+  .service('Services', function($resource){
+    return $resource('/api/core/services/:id/', { id: '@id' }, {
+      update: { method: 'PUT' }
+    });
+  })
+})();
\ No newline at end of file
diff --git a/src/services/rest/Sites.js b/src/services/rest/Sites.js
new file mode 100644
index 0000000..818d741
--- /dev/null
+++ b/src/services/rest/Sites.js
@@ -0,0 +1,15 @@
+(function() {
+  'use strict';
+
+  angular.module('xos.helpers')
+  /**
+  * @ngdoc service
+  * @name xos.helpers.Sites
+  * @description Angular resource to fetch /api/core/sites/:id/
+  **/
+  .service('Sites', function($resource){
+    return $resource('/api/core/sites/:id/', { id: '@id' }, {
+      update: { method: 'PUT' }
+    });
+  })
+})();
\ No newline at end of file
diff --git a/src/services/rest/Slices.js b/src/services/rest/Slices.js
new file mode 100644
index 0000000..5a0da11
--- /dev/null
+++ b/src/services/rest/Slices.js
@@ -0,0 +1,15 @@
+(function() {
+  'use strict';
+
+  angular.module('xos.helpers')
+  /**
+  * @ngdoc service
+  * @name xos.helpers.Slices
+  * @description Angular resource to fetch /api/core/slices/:id/
+  **/
+  .service('Slices', function($resource){
+    return $resource('/api/core/slices/:id/', { id: '@id' }, {
+      update: { method: 'PUT' }
+    });
+  })
+})();
\ No newline at end of file
diff --git a/src/services/rest/Slices_plus.js b/src/services/rest/Slices_plus.js
new file mode 100644
index 0000000..8213b11
--- /dev/null
+++ b/src/services/rest/Slices_plus.js
@@ -0,0 +1,40 @@
+(function() {
+  'use strict';
+
+  angular.module('xos.helpers')
+  /**
+  * @ngdoc service
+  * @name xos.helpers.SlicesPlus
+  * @description Angular resource to fetch /api/utility/slicesplus/
+  * This is a read-only API and only the `query` method is currently supported.
+  **/
+  .service('SlicesPlus', function($http, $q){
+    this.query = (params) => {
+      let deferred = $q.defer();
+
+      $http.get('/api/utility/slicesplus/', {params: params})
+      .then(res => {
+        deferred.resolve(res.data);
+      })
+      .catch(res => {
+        deferred.reject(res.data);
+      });
+
+      return {$promise: deferred.promise};
+    }
+
+    this.get = (id, params) => {
+      let deferred = $q.defer();
+
+      $http.get(`/api/utility/slicesplus/${id}`, {params: params})
+      .then(res => {
+        deferred.resolve(res.data);
+      })
+      .catch(res => {
+        deferred.reject(res.data);
+      });
+      return {$promise: deferred.promise};
+      
+    }
+  })
+})();
diff --git a/src/services/rest/Subscribers.js b/src/services/rest/Subscribers.js
new file mode 100644
index 0000000..945e1e8
--- /dev/null
+++ b/src/services/rest/Subscribers.js
@@ -0,0 +1,147 @@
+(function() {
+  'use strict';
+
+  angular.module('xos.helpers')
+  /**
+  * @ngdoc service
+  * @name xos.helpers.Subscribers
+  * @description Angular resource to fetch Subscribers
+  **/
+  .service('Subscribers', function($resource){
+    return $resource('/api/tenant/cord/subscriber/:id/', { id: '@id' }, {
+      update: { method: 'PUT' },
+      /**
+      * @ngdoc method
+      * @name xos.helpers.Subscribers#View-a-Subscriber-Features-Detail
+      * @methodOf xos.helpers.Subscribers
+      * @description
+      * View-a-Subscriber-Features-Detail
+      **/
+      'View-a-Subscriber-Features-Detail': {
+        method: 'GET',
+        isArray: false,
+        url: '/api/tenant/cord/subscriber/:id/features/'
+      },
+      /**
+      * @ngdoc method
+      * @name xos.helpers.Subscribers#Read-Subscriber-uplink_speed
+      * @methodOf xos.helpers.Subscribers
+      * @description
+      * Read-Subscriber-uplink_speed
+      **/
+      'Read-Subscriber-uplink_speed': {
+        method: 'GET',
+        isArray: false,
+        url: '/api/tenant/cord/subscriber/:id/features/uplink_speed/'
+      },
+      /**
+      * @ngdoc method
+      * @name xos.helpers.Subscribers#Update-Subscriber-uplink_speed
+      * @methodOf xos.helpers.Subscribers
+      * @description
+      * Update-Subscriber-uplink_speed
+      **/
+      'Update-Subscriber-uplink_speed': {
+        method: 'PUT',
+        isArray: false,
+        url: '/api/tenant/cord/subscriber/:id/features/uplink_speed/'
+      },
+      /**
+      * @ngdoc method
+      * @name xos.helpers.Subscribers#Read-Subscriber-downlink_speed
+      * @methodOf xos.helpers.Subscribers
+      * @description
+      * Read-Subscriber-downlink_speed
+      **/
+      'Read-Subscriber-downlink_speed': {
+        method: 'GET',
+        isArray: false,
+        url: '/api/tenant/cord/subscriber/:id/features/downlink_speed/'
+      },
+      /**
+      * @ngdoc method
+      * @name xos.helpers.Subscribers#Update-Subscriber-downlink_speed
+      * @methodOf xos.helpers.Subscribers
+      * @description
+      * Update-Subscriber-downlink_speed
+      **/
+      'Update-Subscriber-downlink_speed': {
+        method: 'PUT',
+        isArray: false,
+        url: '/api/tenant/cord/subscriber/:id/features/downlink_speed/'
+      },
+      /**
+      * @ngdoc method
+      * @name xos.helpers.Subscribers#Read-Subscriber-cdn
+      * @methodOf xos.helpers.Subscribers
+      * @description
+      * Read-Subscriber-cdn
+      **/
+      'Read-Subscriber-cdn': {
+        method: 'GET',
+        isArray: false,
+        url: '/api/tenant/cord/subscriber/:id/features/cdn/'
+      },
+      /**
+      * @ngdoc method
+      * @name xos.helpers.Subscribers#Update-Subscriber-cdn
+      * @methodOf xos.helpers.Subscribers
+      * @description
+      * Update-Subscriber-cdn
+      **/
+      'Update-Subscriber-cdn': {
+        method: 'PUT',
+        isArray: false,
+        url: '/api/tenant/cord/subscriber/:id/features/cdn/'
+      },
+      /**
+      * @ngdoc method
+      * @name xos.helpers.Subscribers#Read-Subscriber-uverse
+      * @methodOf xos.helpers.Subscribers
+      * @description
+      * Read-Subscriber-uverse
+      **/
+      'Read-Subscriber-uverse': {
+        method: 'GET',
+        isArray: false,
+        url: '/api/tenant/cord/subscriber/:id/features/uverse/'
+      },
+      /**
+      * @ngdoc method
+      * @name xos.helpers.Subscribers#Update-Subscriber-uverse
+      * @methodOf xos.helpers.Subscribers
+      * @description
+      * Update-Subscriber-uverse
+      **/
+      'Update-Subscriber-uverse': {
+        method: 'PUT',
+        isArray: false,
+        url: '/api/tenant/cord/subscriber/:id/features/uverse/'
+      },
+      /**
+      * @ngdoc method
+      * @name xos.helpers.Subscribers#Read-Subscriber-status
+      * @methodOf xos.helpers.Subscribers
+      * @description
+      * Read-Subscriber-status
+      **/
+      'Read-Subscriber-status': {
+        method: 'GET',
+        isArray: false,
+        url: '/api/tenant/cord/subscriber/:id/features/status/'
+      },
+      /**
+      * @ngdoc method
+      * @name xos.helpers.Subscribers#Update-Subscriber-status
+      * @methodOf xos.helpers.Subscribers
+      * @description
+      * Update-Subscriber-status
+      **/
+      'Update-Subscriber-status': {
+        method: 'PUT',
+        isArray: false,
+        url: '/api/tenant/cord/subscriber/:id/features/status/'
+      }
+    })
+  })
+})();
\ No newline at end of file
diff --git a/src/services/rest/Tenant.js b/src/services/rest/Tenant.js
new file mode 100644
index 0000000..8feb102
--- /dev/null
+++ b/src/services/rest/Tenant.js
@@ -0,0 +1,15 @@
+(function() {
+  'use strict';
+
+  angular.module('xos.helpers')
+  /**
+  * @ngdoc service
+  * @name xos.helpers.Tenant
+  * @description Angular resource to fetch /api/core/tenant/:id/
+  **/
+  .service('Tenants', function($resource){
+    return $resource('/api/core/tenants/:id/', { id: '@id' }, {
+      update: { method: 'PUT' }
+    });
+  })
+})();
\ No newline at end of file
diff --git a/src/services/rest/Truckroll.js b/src/services/rest/Truckroll.js
new file mode 100644
index 0000000..7af9016
--- /dev/null
+++ b/src/services/rest/Truckroll.js
@@ -0,0 +1,15 @@
+(function() {
+  'use strict';
+
+  angular.module('xos.helpers')
+  /**
+  * @ngdoc service
+  * @name xos.helpers.Truckroll
+  * @description Angular resource to fetch /api/tenant/truckroll/:id/
+  **/
+  .service('Truckroll', function($resource){
+    return $resource('/api/tenant/truckroll/:id/', { id: '@id' }, {
+      update: { method: 'PUT' }
+    });
+  })
+})();
diff --git a/src/services/rest/Users.js b/src/services/rest/Users.js
new file mode 100644
index 0000000..8be0fdd
--- /dev/null
+++ b/src/services/rest/Users.js
@@ -0,0 +1,15 @@
+(function() {
+  'use strict';
+
+  angular.module('xos.helpers')
+  /**
+  * @ngdoc service
+  * @name xos.helpers.Users
+  * @description Angular resource to fetch /api/core/users/:id/
+  **/
+  .service('Users', function($resource){
+    return $resource('/api/core/users/:id/', { id: '@id' }, {
+      update: { method: 'PUT' }
+    });
+  })
+})();
\ No newline at end of file
diff --git a/src/services/rest/Utility.js b/src/services/rest/Utility.js
new file mode 100644
index 0000000..a735c46
--- /dev/null
+++ b/src/services/rest/Utility.js
@@ -0,0 +1,21 @@
+(function() {
+  'use strict';
+
+  angular.module('xos.helpers')
+  /**
+  * @ngdoc service
+  * @name xos.helpers.Login
+  * @description Angular resource to fetch /api/utility/login/
+  **/
+  .service('Login', function($resource){
+    return $resource('/api/utility/login/');
+  })
+  /**
+  * @ngdoc service
+  * @name xos.helpers.Logout
+  * @description Angular resource to fetch /api/utility/logout/
+  **/
+  .service('Logout', function($resource){
+    return $resource('/api/utility/logout/');
+  })
+})();
\ No newline at end of file
diff --git a/src/services/rest/vOLT.js b/src/services/rest/vOLT.js
new file mode 100644
index 0000000..424c48d
--- /dev/null
+++ b/src/services/rest/vOLT.js
@@ -0,0 +1,15 @@
+(function() {
+  'use strict';
+
+  angular.module('xos.helpers')
+  /**
+  * @ngdoc service
+  * @name xos.helpers.vOLT-Collection
+  * @description Angular resource to fetch /api/tenant/cord/volt/:volt_id/
+  **/
+  .service('vOLT-Collection', function($resource){
+    return $resource('/api/tenant/cord/volt/:volt_id/', { volt_id: '@id' }, {
+      update: { method: 'PUT' }
+    });
+  })
+})();
\ No newline at end of file
diff --git a/src/services/rest/vSG.js b/src/services/rest/vSG.js
new file mode 100644
index 0000000..121b5a3
--- /dev/null
+++ b/src/services/rest/vSG.js
@@ -0,0 +1,13 @@
+(function() {
+  'use strict';
+
+  angular.module('xos.helpers')
+  /**
+  * @ngdoc service
+  * @name xos.helpers.vSG-Collection
+  * @description Angular resource to fetch /api/service/vsg/
+  **/
+  .service('vSG-Collection', function($resource){
+    return $resource('/api/service/vsg/');
+  })
+})();
\ No newline at end of file
diff --git a/src/services/service_graph.service.js b/src/services/service_graph.service.js
new file mode 100644
index 0000000..8a732a2
--- /dev/null
+++ b/src/services/service_graph.service.js
@@ -0,0 +1,44 @@
+(function() {
+  'use strict';
+
+  /**
+  * @ngdoc service
+  * @name xos.helpers.ServiceGraph
+  * @description This factory define a set of helper function to query the service tenancy graph
+  **/
+
+  angular
+  .module('xos.helpers')
+  .service('GraphService', function($q, Tenants, Services) {
+
+    this.loadCoarseData = () => {
+
+      let services;
+
+      let deferred = $q.defer();
+
+      Services.query().$promise
+      .then((res) => {
+        services = res;
+        return Tenants.query({kind: 'coarse'}).$promise;
+      })
+      .then((tenants) => {
+        deferred.resolve({
+          tenants: tenants,
+          services: services
+        });
+      })
+
+      return deferred.promise;
+    }
+
+    this.getCoarseGraph = () => {
+      this.loadCoarseData()
+      .then((res) => {
+        console.log(res);
+      })
+      return 'ciao';
+    };
+
+  })
+})();
diff --git a/src/styles/animations.scss b/src/styles/animations.scss
new file mode 100644
index 0000000..f565ff7
--- /dev/null
+++ b/src/styles/animations.scss
@@ -0,0 +1,44 @@
+@keyframes slideInRight {
+  from {
+    transform: translate3d(100%, 0, 0);
+    visibility: visible;
+  }
+
+  to {
+    transform: translate3d(0, 0, 0);
+  }
+}
+
+@keyframes slideOutRight {
+  from {
+    transform: translate3d(0, 0, 0);
+  }
+
+  to {
+    visibility: hidden;
+    transform: translate3d(100%, 0, 0);
+  }
+}
+
+@keyframes fadeInUp {
+  from {
+    opacity: 0;
+    transform: translate3d(0, 100%, 0);
+  }
+
+  to {
+    opacity: 1;
+    transform: none;
+  }
+}
+
+@keyframes fadeOutDown {
+  from {
+    opacity: 1;
+  }
+
+  to {
+    opacity: 0;
+    transform: translate3d(0, 100%, 0);
+  }
+}
\ No newline at end of file
diff --git a/src/styles/loader.scss b/src/styles/loader.scss
new file mode 100644
index 0000000..66297df
--- /dev/null
+++ b/src/styles/loader.scss
@@ -0,0 +1,51 @@
+.loader {
+  font-size: 10px;
+  margin: 0 auto;
+  text-indent: -9999em;
+  width: 11em;
+  height: 11em;
+  border-radius: 50%;
+  background: #ffffff;
+  background: -moz-linear-gradient(left, #ffffff 10%, rgba(255, 255, 255, 0) 42%);
+  background: -webkit-linear-gradient(left, #ffffff 10%, rgba(255, 255, 255, 0) 42%);
+  background: -o-linear-gradient(left, #ffffff 10%, rgba(255, 255, 255, 0) 42%);
+  background: -ms-linear-gradient(left, #ffffff 10%, rgba(255, 255, 255, 0) 42%);
+  background: linear-gradient(to right, #ffffff 10%, rgba(255, 255, 255, 0) 42%);
+  position: relative;
+  animation: loaderSpinner 1.4s infinite linear;
+  transform: translateZ(0);
+}
+.loader:before {
+  width: 50%;
+  height: 50%;
+  background: $brand-primary;
+  border-radius: 100% 0 0 0;
+  position: absolute;
+  top: 0;
+  left: 0;
+  content: '';
+}
+.loader:after {
+  background: #fff;
+  width: 75%;
+  height: 75%;
+  border-radius: 50%;
+  content: '';
+  margin: auto;
+  position: absolute;
+  top: 0;
+  left: 0;
+  bottom: 0;
+  right: 0;
+}
+
+@keyframes loaderSpinner {
+  0% {
+    -webkit-transform: rotate(0deg);
+    transform: rotate(0deg);
+  }
+  100% {
+    -webkit-transform: rotate(360deg);
+    transform: rotate(360deg);
+  }
+}
\ No newline at end of file
diff --git a/src/styles/main.scss b/src/styles/main.scss
new file mode 100644
index 0000000..3dbdc24
--- /dev/null
+++ b/src/styles/main.scss
@@ -0,0 +1,20 @@
+@import './animations.scss';
+@import '../../bower_components/bootstrap-sass/assets/stylesheets/bootstrap/_variables.scss';
+@import './loader.scss';
+
+@import '../ui_components/dumbComponents/table/table.scss';
+@import '../ui_components/dumbComponents/alert/alert.scss';
+@import '../ui_components/dumbComponents/validation/validation.scss';
+@import '../ui_components/dumbComponents/field/field.scss';
+@import '../ui_components/dumbComponents/form/form.scss';
+
+@import '../ui_components/smartComponents/smartTable/smartTable.scss';
+
+[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
+  display: none !important;
+}
+
+.row + .row {
+  /* TODO move in xos.scss*/ 
+  margin-top: $form-group-margin-bottom;
+}
\ No newline at end of file
diff --git a/src/ui_components/dumbComponents/alert/alert.component.js b/src/ui_components/dumbComponents/alert/alert.component.js
new file mode 100644
index 0000000..9b60def
--- /dev/null
+++ b/src/ui_components/dumbComponents/alert/alert.component.js
@@ -0,0 +1,145 @@
+/**
+ * © OpenCORD
+ *
+ * Visit http://guide.xosproject.org/devguide/addview/ for more information
+ *
+ * Created by teone on 4/15/16.
+ */
+
+(function () {
+  'use strict';
+
+  angular.module('xos.uiComponents')
+
+  /**
+    * @ngdoc directive
+    * @name xos.uiComponents.directive:xosAlert
+    * @restrict E
+    * @description The xos-alert directive
+    * @param {Object} config The configuration object
+    * ```
+    * {
+    *   type: 'danger', //info, success, warning
+    *   closeBtn: true, //default false
+    *   autoHide: 3000 //delay to automatically hide the alert
+    * }
+    * ```
+    * @param {Boolean=} show Binding to show and hide the alert, default to true
+    * @element ANY
+    * @scope
+    * @example
+  <example module="sampleAlert1">
+    <file name="index.html">
+      <div ng-controller="SampleCtrl1 as vm">
+        <xos-alert config="vm.config1">
+          A sample alert message
+        </xos-alert>
+        <xos-alert config="vm.config2">
+          A sample alert message (with close button)
+        </xos-alert>
+        <xos-alert config="vm.config3">
+          A sample info message
+        </xos-alert>
+        <xos-alert config="vm.config4">
+          A sample success message
+        </xos-alert>
+        <xos-alert config="vm.config5">
+          A sample warning message
+        </xos-alert>
+      </div>
+    </file>
+    <file name="script.js">
+      angular.module('sampleAlert1', ['xos.uiComponents'])
+      .controller('SampleCtrl1', function(){
+        this.config1 = {
+          type: 'danger'
+        };
+
+        this.config2 = {
+          type: 'danger',
+          closeBtn: true
+        };
+
+        this.config3 = {
+          type: 'info'
+        };
+
+        this.config4 = {
+          type: 'success'
+        };
+
+        this.config5 = {
+          type: 'warning'
+        };
+      });
+    </file>
+  </example>
+
+  <example module="sampleAlert2" animations="true">
+    <file name="index.html">
+      <div ng-controller="SampleCtrl as vm" class="row">
+        <div class="col-sm-4">
+          <a class="btn btn-default btn-block" ng-show="!vm.show" ng-click="vm.show = true">Show Alert</a>
+          <a class="btn btn-default btn-block" ng-show="vm.show" ng-click="vm.show = false">Hide Alert</a>
+        </div>
+        <div class="col-sm-8">
+          <xos-alert config="vm.config1" show="vm.show">
+            A sample alert message, not displayed by default.
+          </xos-alert>
+        </div>
+      </div>
+    </file>
+    <file name="script.js">
+      angular.module('sampleAlert2', ['xos.uiComponents', 'ngAnimate'])
+      .controller('SampleCtrl', function(){
+        this.config1 = {
+          type: 'success'
+        };
+
+        this.show = false;
+      });
+    </file>
+  </example>
+  **/
+
+  .directive('xosAlert', function(){
+    return {
+      restrict: 'E',
+      scope: {
+        config: '=',
+        show: '=?'
+      },
+      template: `
+        <div ng-cloak class="alert alert-{{vm.config.type}}" ng-hide="!vm.show">
+          <button type="button" class="close" ng-if="vm.config.closeBtn" ng-click="vm.dismiss()">
+            <span aria-hidden="true">&times;</span>
+          </button>
+          <p ng-transclude></p>
+        </div>
+      `,
+      transclude: true,
+      bindToController: true,
+      controllerAs: 'vm',
+      controller: function($timeout){
+
+        if(!this.config){
+          throw new Error('[xosAlert] Please provide a configuration via the "config" attribute');
+        }
+
+        // default the value to true
+        this.show = this.show !== false;
+        
+        this.dismiss = () => {
+          this.show = false;
+        }
+
+        if(this.config.autoHide){
+          let to = $timeout(() => {
+            this.dismiss();
+            $timeout.cancel(to);
+          }, this.config.autoHide);
+        }
+      }
+    }
+  })
+})();
diff --git a/src/ui_components/dumbComponents/alert/alert.scss b/src/ui_components/dumbComponents/alert/alert.scss
new file mode 100644
index 0000000..f031ba6
--- /dev/null
+++ b/src/ui_components/dumbComponents/alert/alert.scss
@@ -0,0 +1,12 @@
+@import '../../../styles/animations.scss';
+
+xos-alert {
+  margin-top: $form-group-margin-bottom;
+  display: block;
+
+  /* when hiding */
+  .ng-hide-add         { animation:0.5s fadeOutDown ease-in-out; }
+
+  /* when showing */
+  .ng-hide-remove      { animation:0.5s fadeInUp ease-in-out; }
+}
\ No newline at end of file
diff --git a/src/ui_components/dumbComponents/field/field.component.js b/src/ui_components/dumbComponents/field/field.component.js
new file mode 100644
index 0000000..21b2f4e
--- /dev/null
+++ b/src/ui_components/dumbComponents/field/field.component.js
@@ -0,0 +1,279 @@
+/**
+ * © OpenCORD
+ *
+ * Visit http://guide.xosproject.org/devguide/addview/ for more information
+ *
+ * Created by teone on 5/25/16.
+ */
+
+(function () {
+  'use strict';
+
+  angular.module('xos.uiComponents')
+  /**
+    * @ngdoc directive
+    * @name xos.uiComponents.directive:xosField
+    * @restrict E
+    * @description The xos-field directive.
+    * This component decide, give a field wich kind of input it need to print.
+    * @param {string} name The field name
+    * @param {object} field The field configuration:
+    * ```
+    * {
+    *   label: 'Label',
+    *   type: 'number', //typeof field
+    *   validators: {} // see xosForm for more details
+    * }
+    * ```
+    * @param {mixed} ngModel The field value
+    *
+    * @example
+    
+    # Basic Example
+    
+      <example module="sampleField1">
+        <file name="script.js">
+          angular.module('sampleField1', ['xos.uiComponents'])
+          .factory('_', function($window){
+            return $window._;
+          })
+          .controller('SampleCtrl', function(){
+            this.name = 'input-name';
+            this.field = {label: 'My String Value:', type: 'string'};
+            this.model = 'my string';
+          });
+        </file>
+        <file name="index.html">
+          <div ng-controller="SampleCtrl as vm">
+            <xos-field ng-model="vm.model" name="vm.name" field="vm.field"></xos-field>
+          </div>
+        </file>
+      </example>
+      
+      # Possible Values
+
+      <example module="sampleField2">
+        <file name="script.js">
+          angular.module('sampleField2', ['xos.uiComponents'])
+          .factory('_', function($window){
+            return $window._;
+          })
+          .controller('SampleCtrl', function(){
+            this.field1 = {
+              name: 'number-field',
+              field: {label: 'My Number Value:', type: 'number'},
+              model: 2
+            };
+
+            this.field2 = {
+              name: 'date-field',
+              field: {label: 'My Date Value:', type: 'date'},
+              model: new Date()
+            };
+
+            this.field3 = {
+              name: 'boolean-field',
+              field: {label: 'My Boolean Value:', type: 'boolean'},
+              model: true
+            };
+
+            this.field4 = {
+              name: 'email-field',
+              field: {label: 'My Email Value:', type: 'email'},
+              model: 'sample@domain.us'
+            };
+          });
+        </file>
+        <file name="index.html">
+          <div ng-controller="SampleCtrl as vm">
+            <xos-field ng-model="vm.field1.model" name="vm.field1.name" field="vm.field1.field"></xos-field>
+            <xos-field ng-model="vm.field2.model" name="vm.field2.name" field="vm.field2.field"></xos-field>
+            <xos-field ng-model="vm.field3.model" name="vm.field3.name" field="vm.field3.field"></xos-field>
+            <xos-field ng-model="vm.field4.model" name="vm.field4.name" field="vm.field4.field"></xos-field>
+          </div>
+        </file>
+      </example>
+
+      # This element is recursive
+
+      <example module="sampleField3">
+        <file name="script.js">
+          angular.module('sampleField3', ['xos.uiComponents'])
+          .factory('_', function($window){
+            return $window._;
+          })
+          .controller('SampleCtrl', function(){
+            this.name1 = 'input-name';
+            this.field1 = {label: 'My Object Field:', type: 'object'};
+            this.model1 = {
+              name: 'Jhon',
+              age: '25',
+              email: 'jhon@thewall.ru',
+              active: true
+            };
+
+            this.name2 = 'another-name';
+            this.field2 = {
+              label: 'Empty Object Field',
+              type: 'object',
+              properties: {
+                foo: {
+                  label: 'FooLabel:',
+                  type: 'string',
+                  validators: {
+                    required: true
+                  }
+                },
+                bar: {
+                  type: 'number'
+                }
+              }
+            }
+          });
+        </file>
+        <file name="index.html">
+          <div ng-controller="SampleCtrl as vm">
+            <h4>Autogenerated object field</h4>
+            <xos-field ng-model="vm.model1" name="vm.name1" field="vm.field1"></xos-field>
+
+            <h4>Configured object field</h4>
+            <xos-field ng-model="vm.model2" name="vm.name2" field="vm.field2"></xos-field>
+          </div>
+        </file>
+      </example>
+    */
+  .directive('xosField', function(RecursionHelper){
+    return {
+      restrict: 'E',
+      scope: {
+        name: '=',
+        field: '=',
+        ngModel: '='
+      },
+      template: `
+        <label ng-if="vm.field.type !== 'object'">{{vm.field.label}}</label>
+            <input
+              xos-custom-validator custom-validator="vm.field.validators.custom || null"
+              ng-if="vm.field.type !== 'boolean' && vm.field.type !== 'object' && vm.field.type !== 'select'"
+              type="{{vm.field.type}}"
+              name="{{vm.name}}"
+              class="form-control"
+              ng-model="vm.ngModel"
+              ng-minlength="vm.field.validators.minlength || 0"
+              ng-maxlength="vm.field.validators.maxlength || 2000"
+              ng-required="vm.field.validators.required || false" />
+              <select class="form-control" ng-if ="vm.field.type === 'select'"
+                name = "{{vm.name}}"
+                ng-options="item.id as item.label for item in vm.field.options"
+                ng-model="vm.ngModel"
+                ng-required="vm.field.validators.required || false">
+                </select>
+            <span class="boolean-field" ng-if="vm.field.type === 'boolean'">
+              <a href="#"
+                class="btn btn-success"
+                ng-show="vm.ngModel"
+                ng-click="vm.ngModel = false">
+                <i class="glyphicon glyphicon-ok"></i>
+              </a>
+              <a href="#"
+                class="btn btn-danger"
+                ng-show="!vm.ngModel"
+                ng-click="vm.ngModel = true">
+                <i class="glyphicon glyphicon-remove"></i>
+              </a>
+            </span>
+            <div
+              class="panel panel-default object-field"
+              ng-if="vm.field.type == 'object' && (!vm.isEmptyObject(vm.ngModel) || !vm.isEmptyObject(vm.field.properties))"
+              >
+              <div class="panel-heading">{{vm.field.label}}</div>
+              <div class="panel-body">
+                <div ng-if="!vm.field.properties" ng-repeat="(k, v) in vm.ngModel">
+                  <xos-field
+                    name="k"
+                    field="{label: vm.formatLabel(k), type: vm.getType(v)}"
+                    ng-model="v">
+                  </xos-field>
+                </div>
+                <div ng-if="vm.field.properties" ng-repeat="(k, v) in vm.field.properties">
+                  <xos-field
+                    name="k"
+                    field="{
+                      label: v.label || vm.formatLabel(k),
+                      type: v.type,
+                      validators: v.validators
+                    }"
+                    ng-model="vm.ngModel[k]">
+                  </xos-field>
+                </div>
+              </div>
+            </div>
+      `,
+      bindToController: true,
+      controllerAs: 'vm',
+      // the compile cicle is needed to support recursion
+      compile: function (element) {
+        return RecursionHelper.compile(element);
+      },
+      controller: function($attrs, XosFormHelpers, LabelFormatter){
+
+        if(!this.name){
+          throw new Error('[xosField] Please provide a field name');
+        }
+        if(!this.field){
+          throw new Error('[xosField] Please provide a field definition');
+        }
+        if(!this.field.type){
+          throw new Error('[xosField] Please provide a type in the field definition');
+        }
+        if(!$attrs.ngModel){
+          throw new Error('[xosField] Please provide an ng-model');
+        }
+        this.getType = XosFormHelpers._getFieldFormat;
+        this.formatLabel = LabelFormatter.format;
+
+        this.isEmptyObject = o => o ? Object.keys(o).length === 0 : true;
+      }
+    }
+  })
+
+/**
+ * @ngdoc directive
+ * @name xos.uiComponents.directive:xosCustomValidator
+ * @restrict A
+ * @description The xosCustomValidator directive.
+ * This component apply a custom validation function
+ * @param {function} customValidator The function that execute the validation.
+ *
+ * You should do your validation here and return true | false,
+ * or alternatively you can return an array [errorName, true|false]
+ */
+  .directive('xosCustomValidator', function(){
+    return {
+      restrict: 'A',
+      scope: {
+        fn: '=customValidator'
+      },
+      require: 'ngModel',
+      link: function(scope, element, attr, ctrl){
+        if(!angular.isFunction(scope.fn)){
+          return;
+        }
+
+        function customValidatorWrapper(ngModelValue) {
+          const valid = scope.fn(ngModelValue);
+          if(angular.isArray(valid)){
+            // ES6 spread rocks over fn.apply()
+            ctrl.$setValidity(...valid);
+          }
+          else{
+            ctrl.$setValidity('custom', valid);
+          }
+          return ngModelValue;
+        }
+
+        ctrl.$parsers.push(customValidatorWrapper);
+      }
+    };
+  });
+})();
\ No newline at end of file
diff --git a/src/ui_components/dumbComponents/field/field.scss b/src/ui_components/dumbComponents/field/field.scss
new file mode 100644
index 0000000..8dd7ca4
--- /dev/null
+++ b/src/ui_components/dumbComponents/field/field.scss
@@ -0,0 +1,3 @@
+xos-field {
+  display: block;
+}
\ No newline at end of file
diff --git a/src/ui_components/dumbComponents/form/form.component.js b/src/ui_components/dumbComponents/form/form.component.js
new file mode 100644
index 0000000..4d9169b
--- /dev/null
+++ b/src/ui_components/dumbComponents/form/form.component.js
@@ -0,0 +1,285 @@
+/**
+ * © OpenCORD
+ *
+ * Visit http://guide.xosproject.org/devguide/addview/ for more information
+ *
+ * Created by teone on 4/18/16.
+ */
+
+(function () {
+  'use strict';
+
+
+  angular.module('xos.uiComponents')
+
+  /**
+    * @ngdoc directive
+    * @name xos.uiComponents.directive:xosForm
+    * @restrict E
+    * @description The xos-form directive.
+    * This components have two usage, given a model it is able to autogenerate a form or it can be configured to create a custom form.
+    * @param {Object} config The configuration object
+    * ```
+    * {
+    *   exclude: ['id', 'validators', 'created', 'updated', 'deleted'], //field to be skipped in the form, the provide values are concatenated
+    *   actions: [ // define the form buttons with related callback
+    *     {
+            label: 'save',
+            icon: 'ok', // refers to bootstraps glyphicon
+            cb: (user) => { // receive the model
+              console.log(user);
+            },
+            class: 'success'
+          }
+    *   ],
+    *   feedback: {
+          show: false,
+          message: 'Form submitted successfully !!!',
+          type: 'success'  //refers to bootstrap class
+        },
+    *   fields: {
+    *     field_name: {
+    *       label: 'Field Label',
+    *       type: 'string' // options are: [date, boolean, number, email, string, select],
+    *       validators: {
+    *         minlength: number,
+              maxlength: number,
+              required: boolean,
+              min: number,
+              max: number,
+              custom: (value) => {
+                // do your validation here and return true | false
+                // alternatively you can return an array [errorName, true|false]
+              }
+    *       }
+    *     }
+    *   }
+    * }
+    * ```
+    * @element ANY
+    * @scope
+    * @requires xos.uiComponents.directive:xosField
+    * @requires xos.uiComponents.XosFormHelpers
+    * @requires xos.helpers._
+    * @example
+    
+    Autogenerated form
+
+  <example module="sampleForm">
+    <file name="script.js">
+      angular.module('sampleForm', ['xos.uiComponents'])
+      .factory('_', function($window){
+        return $window._;
+      })
+      .controller('SampleCtrl', function(){
+        this.model = {
+          first_name: 'Jhon',
+          last_name: 'Doe',
+          email: 'jhon.doe@sample.com',
+          active: true,
+          birthDate: '2015-02-17T22:06:38.059000Z'
+        }
+        this.config = {
+          exclude: ['password', 'last_login'],
+          formName: 'sampleForm',
+          actions: [
+            {
+              label: 'Save',
+              icon: 'ok', // refers to bootstraps glyphicon
+              cb: (user) => { // receive the model
+                console.log(user);
+              },
+              class: 'success'
+            }
+          ]
+        };
+      });
+    </file>
+    <file name="index.html">
+      <div ng-controller="SampleCtrl as vm">
+        <xos-form ng-model="vm.model" config="vm.config"></xos-form>
+      </div>
+    </file>
+  </example>
+
+  Configuration defined form
+
+  <example module="sampleForm1">
+    <file name="script.js">
+      angular.module('sampleForm1', ['xos.uiComponents','ngResource', 'ngMockE2E'])
+      .factory('_', function($window){
+        return $window._;
+      })
+      .controller('SampleCtrl1', function(SampleResource){
+
+
+        this.model = {
+        };
+
+        this.config = {
+          exclude: ['password', 'last_login'],
+          formName: 'sampleForm1',
+          feedback: {
+            show: false,
+            message: 'Form submitted successfully !!!',
+            type: 'success'
+          },
+          actions: [
+            {
+              label: 'Save',
+              icon: 'ok', // refers to bootstraps glyphicon
+              cb: (user) => { // receive the model
+                console.log(user);
+                this.config.feedback.show = true;
+                this.config.feedback.type='success';
+              },
+              class: 'success'
+            }
+          ],
+          fields: {
+            first_name: {
+              type: 'string',
+              validators: {
+                required: true
+              }
+            },
+            last_name: {
+              label: 'Surname',
+              type: 'string',
+              validators: {
+                required: true,
+                minlength: 10
+              }
+            },
+            age: {
+              type: 'number',
+              validators: {
+                required: true,
+                min: 21
+              }
+            },
+
+            site: {
+            label: 'Site',
+            type: 'select',
+            validators: { required: true},
+            hint: 'The Site this Slice belongs to',
+            options: []
+            },
+         }
+        };
+        SampleResource.query().$promise
+          .then((users) => {
+          //this.users_site = users;
+        //console.log(users);
+          this.optionVal = users;
+          this.config.fields['site'].options = this.optionVal;
+        //= this.optionVal;
+
+      })
+      .catch((e) => {
+        throw new Error(e);
+      });
+
+      });
+    </file>
+   <file name="backend.js">
+     angular.module('sampleForm1')
+     .run(function($httpBackend, _){
+        let datas = [{id: 1, label: 'site1'},{id: 4, label: 'site4'},{id: 3, label: 'site3'}];
+        let paramsUrl = new RegExp(/\/test\/(.+)/);
+        $httpBackend.whenGET('/test').respond(200, datas)
+      })
+      .service('SampleResource', function($resource){
+        return $resource('/test/:id', {id: '@id'});
+      });
+
+    </file>
+    <file name="index.html">
+      <div ng-controller="SampleCtrl1 as vm">
+        <xos-form ng-model="vm.model" config="vm.config"></xos-form>
+      </div>
+    </file>
+  </example>
+
+  **/
+
+  .directive('xosForm', function(){
+    return {
+      restrict: 'E',
+      scope: {
+        config: '=',
+        ngModel: '='
+      },
+      template: `
+        <form name="vm.{{vm.config.formName || 'form'}}" novalidate>
+          <div class="form-group" ng-repeat="(name, field) in vm.formField">
+            <xos-field name="name" field="field" ng-model="vm.ngModel[name]"></xos-field>
+            <xos-validation field="vm[vm.config.formName || 'form'][name]" form = "vm[vm.config.formName || 'form']"></xos-validation>
+            <div class="alert alert-info" ng-show="(field.hint).length >0" role="alert">{{field.hint}}</div>
+          </div>
+          <div class="form-group" ng-if="vm.config.actions">
+          <xos-alert config="vm.config.feedback" show="vm.config.feedback.show">{{vm.config.feedback.message}}</xos-alert>
+
+            <button role="button" href=""
+              ng-repeat="action in vm.config.actions"
+              ng-click="action.cb(vm.ngModel, vm[vm.config.formName || 'form'])"
+              class="btn btn-{{action.class}}"
+              title="{{action.label}}">
+              <i class="glyphicon glyphicon-{{action.icon}}"></i>
+              {{action.label}}
+            </button>
+          </div>
+        </form>
+      `,
+      bindToController: true,
+      controllerAs: 'vm',
+      controller: function($scope, $log, _, XosFormHelpers){
+
+        if(!this.config){
+          throw new Error('[xosForm] Please provide a configuration via the "config" attribute');
+        }
+
+        if(!this.config.actions){
+          throw new Error('[xosForm] Please provide an action list in the configuration');
+        }
+
+        if(!this.config.feedback){
+          this.config.feedback =  {
+            show: false,
+            message: 'Form submitted successfully !!!',
+            type: 'success'
+          }
+        }
+
+        this.excludedField = ['id', 'validators', 'created', 'updated', 'deleted', 'backend_status'];
+        if(this.config && this.config.exclude){
+          this.excludedField = this.excludedField.concat(this.config.exclude);
+        }
+
+        this.formField = [];
+
+        $scope.$watch(() => this.config, ()=> {
+          if(!this.ngModel){
+            return;
+          }
+          let diff = _.difference(Object.keys(this.ngModel), this.excludedField);
+          let modelField = XosFormHelpers.parseModelField(diff);
+          this.formField = XosFormHelpers.buildFormStructure(modelField, this.config.fields, this.ngModel);
+        }, true);
+
+        $scope.$watch(() => this.ngModel, (model) => {
+          // empty from old stuff
+          this.formField = {};
+          if(!model){
+            return;
+          }
+          let diff = _.difference(Object.keys(model), this.excludedField);
+          let modelField = XosFormHelpers.parseModelField(diff);
+          this.formField = XosFormHelpers.buildFormStructure(modelField, this.config.fields, model);
+        });
+
+      }
+    }
+  });
+})();
diff --git a/src/ui_components/dumbComponents/form/form.scss b/src/ui_components/dumbComponents/form/form.scss
new file mode 100644
index 0000000..cf977af
--- /dev/null
+++ b/src/ui_components/dumbComponents/form/form.scss
@@ -0,0 +1,12 @@
+@import '../../../styles/animations.scss';
+@import '../../../../bower_components/bootstrap-sass/assets/stylesheets/bootstrap/_variables.scss';
+
+xos-form {
+  button {
+    margin-bottom: $form-group-margin-bottom;
+  }
+
+  button + button {
+   margin-left: $form-group-margin-bottom; 
+  }
+}
\ No newline at end of file
diff --git a/src/ui_components/dumbComponents/pagination/pagination.component.js b/src/ui_components/dumbComponents/pagination/pagination.component.js
new file mode 100644
index 0000000..ddb1eb9
--- /dev/null
+++ b/src/ui_components/dumbComponents/pagination/pagination.component.js
@@ -0,0 +1,122 @@
+/**
+ * © OpenCORD
+ *
+ * Visit http://guide.xosproject.org/devguide/addview/ for more information
+ *
+ * Created by teone on 4/15/16.
+ */
+
+(function () {
+  'use strict';
+
+  angular.module('xos.uiComponents')
+
+  /**
+    * @ngdoc directive
+    * @name xos.uiComponents.directive:xosPagination
+    * @restrict E
+    * @description The xos-table directive
+    * @param {Number} pageSize Number of elements per page
+    * @param {Number} totalElements Number of total elements in the collection
+    * @param {Function} change The callback to be triggered on page change.
+    * * @element ANY
+    * @scope
+    * @example
+  <example module="samplePagination">
+    <file name="index.html">
+      <div ng-controller="SampleCtrl1 as vm">
+        <xos-pagination
+          page-size="vm.pageSize"
+          total-elements="vm.totalElements"
+          change="vm.change">
+        </xos-pagination>
+      </div>
+    </file>
+    <file name="script.js">
+      angular.module('samplePagination', ['xos.uiComponents'])
+      .controller('SampleCtrl1', function(){
+        this.pageSize = 10;
+        this.totalElements = 35;
+        this.change = (pageNumber) => {
+          console.log(pageNumber);
+        }
+      });
+    </file>
+  </example>
+  **/
+
+  .directive('xosPagination', function(){
+    return {
+      restrict: 'E',
+      scope: {
+        pageSize: '=',
+        totalElements: '=',
+        change: '='
+      },
+      template: `
+        <div class="row" ng-if="vm.pageList.length > 1">
+          <div class="col-xs-12 text-center">
+            <ul class="pagination">
+              <li
+                ng-click="vm.goToPage(vm.currentPage - 1)"
+                ng-class="{disabled: vm.currentPage == 0}">
+                <a href="" aria-label="Previous">
+                    <span aria-hidden="true">&laquo;</span>
+                </a>
+              </li>
+              <li ng-repeat="i in vm.pageList" ng-class="{active: i === vm.currentPage}">
+                <a href="" ng-click="vm.goToPage(i)">{{i + 1}}</a>
+              </li>
+              <li
+                ng-click="vm.goToPage(vm.currentPage + 1)"
+                ng-class="{disabled: vm.currentPage == vm.pages - 1}">
+                <a href="" aria-label="Next">
+                    <span aria-hidden="true">&raquo;</span>
+                </a>
+              </li>
+            </ul>
+          </div>
+        </div>
+      `,
+      bindToController: true,
+      controllerAs: 'vm',
+      controller: function($scope){
+        
+        this.currentPage = 0;
+
+        this.goToPage = (n) => {
+          if(n < 0 || n === this.pages){
+            return;
+          }
+          this.currentPage = n;
+          this.change(n);
+        }
+
+        this.createPages = (pages) => {
+          let arr = [];
+          for(let i = 0; i < pages; i++){
+            arr.push(i);
+          }
+          return arr;
+        }
+
+        // watch for data changes
+        $scope.$watch(() => this.totalElements, () => {
+          if(this.totalElements){
+            this.pages = Math.ceil(this.totalElements / this.pageSize);
+            this.pageList = this.createPages(this.pages);
+          }
+        });
+      }
+    }
+  })
+  .filter('pagination', function(){
+    return function(input, start) {
+      if(!input || !angular.isArray(input)){
+        return input;
+      }
+      start = parseInt(start, 10);
+      return input.slice(start);
+    };
+  });
+})();
diff --git a/src/ui_components/dumbComponents/table/table.component.js b/src/ui_components/dumbComponents/table/table.component.js
new file mode 100644
index 0000000..1e60458
--- /dev/null
+++ b/src/ui_components/dumbComponents/table/table.component.js
@@ -0,0 +1,549 @@
+/**
+ * © OpenCORD
+ *
+ * Visit http://guide.xosproject.org/devguide/addview/ for more information
+ *
+ * Created by teone on 3/24/16.
+ */
+
+(function () {
+  'use strict';
+
+  angular.module('xos.uiComponents')
+
+    /**
+    * @ngdoc directive
+    * @name xos.uiComponents.directive:xosTable
+    * @restrict E
+    * @description The xos-table directive
+    * @param {Object} config The configuration for the component.
+    * ```
+    * {
+    *   columns: [
+    *     {
+    *       label: 'Human readable name',
+    *       prop: 'Property to read in the model object',
+    *       type: 'boolean'| 'array'| 'object'| 'custom'| 'date' | 'icon' // see examples for more details
+            formatter: fn(), // receive the whole item if tipe is custom and return a string
+            link: fn() // receive the whole item and return an url
+    *     }
+    *   ],
+    *   classes: 'table table-striped table-bordered',
+    *   actions: [ // if defined add an action column
+          {
+            label: 'delete',
+            icon: 'remove', // refers to bootstraps glyphicon
+            cb: (user) => { // receive the model
+              console.log(user);
+            },
+            color: 'red'
+          }
+        ],
+        filter: 'field', // can be by `field` or `fulltext`
+        order: true | {field: 'property name', reverse: true | false} // whether to show ordering arrows, or a configuration for a default ordering
+    * }
+    * ```
+    * @param {Array} data The data that should be rendered
+    * @element ANY
+    * @scope
+    * @example
+  
+  # Basic usage
+  <example module="sampleTable1">
+    <file name="index.html">
+      <div ng-controller="SampleCtrl1 as vm">
+        <xos-table data="vm.data" config="vm.config"></xos-table>
+      </div>
+    </file>
+    <file name="script.js">
+      angular.module('sampleTable1', ['xos.uiComponents'])
+      .factory('_', function($window){
+        return $window._;
+      })
+      .controller('SampleCtrl1', function(){
+        this.config = {
+          columns: [
+            {
+              label: 'First Name', // column title
+              prop: 'name' // property to read in the data array
+            },
+            {
+              label: 'Last Name',
+              prop: 'lastname'
+            }
+          ]
+        };
+
+        this.data = [
+          {
+            name: 'John',
+            lastname: 'Doe'
+          },
+          {
+            name: 'Gili',
+            lastname: 'Fereydoun'
+          }
+        ]
+      });
+    </file>
+  </example>
+  
+  # Filtering
+  <example module="sampleTable2" animations="true">
+    <file name="index.html">
+      <div ng-controller="SampleCtrl2 as vm">
+        <xos-table data="vm.data" config="vm.config"></xos-table>
+      </div>
+    </file>
+    <file name="script.js">
+      angular.module('sampleTable2', ['xos.uiComponents', 'ngAnimate'])
+      .factory('_', function($window){
+        return $window._;
+      })
+      .controller('SampleCtrl2', function(){
+        this.config = {
+          columns: [
+            {
+              label: 'First Name', // column title
+              prop: 'name' // property to read in the data array
+            },
+            {
+              label: 'Last Name',
+              prop: 'lastname'
+            }
+          ],
+          classes: 'table table-striped table-condensed', // table classes, default to `table table-striped table-bordered`
+          actions: [ // if defined add an action column
+            {
+              label: 'delete', // label
+              icon: 'remove', // icons, refers to bootstraps glyphicon
+              cb: (user) => { // callback, get feeded with the full object
+                console.log(user);
+              },
+              color: 'red' // icon color
+            }
+          ],
+          filter: 'field', // can be by `field` or `fulltext`
+          order: true
+        };
+
+        this.data = [
+          {
+            name: 'John',
+            lastname: 'Doe'
+          },
+          {
+            name: 'Gili',
+            lastname: 'Fereydoun'
+          }
+        ]
+      });
+    </file>
+  </example>
+  
+  # Pagination
+  <example module="sampleTable3">
+    <file name="index.html">
+      <div ng-controller="SampleCtrl3 as vm">
+        <xos-table data="vm.data" config="vm.config"></xos-table>
+      </div>
+    </file>
+    <file name="script.js">
+      angular.module('sampleTable3', ['xos.uiComponents'])
+      .factory('_', function($window){
+        return $window._;
+      })
+      .controller('SampleCtrl3', function(){
+        this.config = {
+          columns: [
+            {
+              label: 'First Name', // column title
+              prop: 'name' // property to read in the data array
+            },
+            {
+              label: 'Last Name',
+              prop: 'lastname'
+            }
+          ],
+          pagination: {
+            pageSize: 2
+          }
+        };
+
+        this.data = [
+          {
+            name: 'John',
+            lastname: 'Doe'
+          },
+          {
+            name: 'Gili',
+            lastname: 'Fereydoun'
+          },
+          {
+            name: 'Lucky',
+            lastname: 'Clarkson'
+          },
+          {
+            name: 'Tate',
+            lastname: 'Spalding'
+          }
+        ]
+      });
+    </file>
+  </example>
+  
+  # Field formatter
+  <example module="sampleTable4">
+    <file name="index.html">
+      <div ng-controller="SampleCtrl as vm">
+        <xos-table data="vm.data" config="vm.config"></xos-table>
+      </div>
+    </file>
+    <file name="script.js">
+      angular.module('sampleTable4', ['xos.uiComponents'])
+      .factory('_', function($window){
+        return $window._;
+      })
+      .controller('SampleCtrl', function(){
+        this.config = {
+          columns: [
+            {
+              label: 'First Name',
+              prop: 'name',
+              link: item => `https://www.google.it/#q=${item.name}`
+            },
+            {
+              label: 'Enabled',
+              prop: 'enabled',
+              type: 'boolean'
+            },
+            {
+              label: 'Services',
+              prop: 'services',
+              type: 'array'
+            },
+            {
+              label: 'Details',
+              prop: 'details',
+              type: 'object'
+            },
+            {
+              label: 'Created',
+              prop: 'created',
+              type: 'date'
+            },
+            {
+              label: 'Icon',
+              type: 'icon',
+              formatter: item => item.icon //note that this refer to [Bootstrap Glyphicon](http://getbootstrap.com/components/#glyphicons)
+            }
+          ]
+        };
+
+        this.data = [
+          {
+            name: 'John',
+            enabled: true,
+            services: ['Cdn', 'IpTv'],
+            details: {
+              c_tag: '243',
+              s_tag: '444'
+            },
+            created: new Date('December 17, 1995 03:24:00'),
+            icon: 'music'
+          },
+          {
+            name: 'Gili',
+            enabled: false,
+            services: ['Cdn', 'IpTv', 'Cache'],
+            details: {
+              c_tag: '675',
+              s_tag: '893'
+            },
+            created: new Date(),
+            icon: 'camera'
+          }
+        ]
+      });
+    </file>
+  </example>
+
+  # Custom formatter
+  <example module="sampleTable5">
+    <file name="index.html">
+      <div ng-controller="SampleCtrl as vm">
+        <xos-table data="vm.data" config="vm.config"></xos-table>
+      </div>
+    </file>
+    <file name="script.js">
+      angular.module('sampleTable5', ['xos.uiComponents'])
+      .factory('_', function($window){
+        return $window._;
+      })
+      .controller('SampleCtrl', function(){
+        this.config = {
+          columns: [
+            {
+              label: 'Username',
+              prop: 'username'
+            },
+            {
+              label: 'Features',
+              type: 'custom',
+              formatter: (val) => {
+                
+                let cdnEnabled = val.features.cdn ? 'enabled' : 'disabled';
+                return `
+                  Cdn is ${cdnEnabled},
+                  uplink speed is ${val.features.uplink_speed}
+                  and downlink speed is ${val.features.downlink_speed}
+                `;
+              }
+            }
+          ]
+        };
+
+        this.data = [
+          {
+            username: 'John',
+            features: {
+              "cdn": false,
+              "uplink_speed": 1000000000,
+              "downlink_speed": 1000000000,
+              "uverse": true,
+              "status": "enabled"
+            }
+          },
+          {
+            username: 'Gili',
+            features: {
+              "cdn": true,
+              "uplink_speed": 3000000000,
+              "downlink_speed": 2000000000,
+              "uverse": true,
+              "status": "enabled"
+            }
+          }
+        ]
+      });
+    </file>
+  </example>
+    **/
+
+    .directive('xosTable', function(){
+      return {
+        restrict: 'E',
+        scope: {
+          data: '=',
+          config: '='
+        },
+        template: `
+          <div ng-show="vm.data.length > 0 && vm.loader == false">
+            <div class="row" ng-if="vm.config.filter == 'fulltext'">
+              <div class="col-xs-12">
+                <input
+                  class="form-control"
+                  placeholder="Type to search.."
+                  type="text"
+                  ng-model="vm.query"/>
+              </div>
+            </div>
+            <table ng-class="vm.classes" ng-hide="vm.data.length == 0">
+              <thead>
+                <tr>
+                  <th ng-repeat="col in vm.columns">
+                    {{col.label}}
+                    <span ng-if="vm.config.order">
+                      <a href="" ng-click="vm.orderBy = col.prop; vm.reverse = false">
+                        <i class="glyphicon glyphicon-chevron-up"></i>
+                      </a>
+                      <a href="" ng-click="vm.orderBy = col.prop; vm.reverse = true">
+                        <i class="glyphicon glyphicon-chevron-down"></i>
+                      </a>
+                    </span>
+                  </th>
+                  <th ng-if="vm.config.actions">Actions:</th>
+                </tr>
+              </thead>
+              <tbody ng-if="vm.config.filter == 'field'">
+                <tr>
+                  <td ng-repeat="col in vm.columns">
+                    <input
+                      ng-if="col.type !== 'boolean' && col.type !== 'array' && col.type !== 'object' && col.type !== 'custom'"
+                      class="form-control"
+                      placeholder="Type to search by {{col.label}}"
+                      type="text"
+                      ng-model="vm.query[col.prop]"/>
+                    <select
+                      ng-if="col.type === 'boolean'"
+                      class="form-control"
+                      ng-model="vm.query[col.prop]">
+                      <option value="">-</option>
+                      <option value="true">True</option>
+                      <option value="false">False</option>
+                    </select>
+                  </td>
+                  <td ng-if="vm.config.actions"></td>
+                </tr>
+              </tbody>
+              <tbody>
+                <tr ng-repeat="item in vm.data | filter:vm.query:vm.comparator | orderBy:vm.orderBy:vm.reverse | pagination:vm.currentPage * vm.config.pagination.pageSize | limitTo: (vm.config.pagination.pageSize || vm.data.length) track by $index">
+                  <td ng-repeat="col in vm.columns" xos-link-wrapper>
+                    <span ng-if="!col.type">{{item[col.prop]}}</span>
+                    <span ng-if="col.type === 'boolean'">
+                      <i class="glyphicon"
+                        ng-class="{'glyphicon-ok': item[col.prop], 'glyphicon-remove': !item[col.prop]}">
+                      </i>
+                    </span>
+                    <span ng-if="col.type === 'date'">
+                      {{item[col.prop] | date:'H:mm MMM d, yyyy'}}
+                    </span>
+                    <span ng-if="col.type === 'array'">
+                      {{item[col.prop] | arrayToList}}
+                    </span>
+                    <span ng-if="col.type === 'object'">
+                      <dl class="dl-horizontal">
+                        <span ng-repeat="(k,v) in item[col.prop]">
+                          <dt>{{k}}</dt>
+                          <dd>{{v}}</dd>
+                        </span>
+                      </dl>
+                    </span>
+                    <span ng-if="col.type === 'custom'">
+                      {{col.formatter(item)}}
+                    </span>
+                    <span ng-if="col.type === 'icon'">
+                      <i class="glyphicon glyphicon-{{col.formatter(item)}}">
+                      </i>
+                    </span>
+                  </td>
+                  <td ng-if="vm.config.actions">
+                    <a href=""
+                      ng-repeat="action in vm.config.actions"
+                      ng-click="action.cb(item)"
+                      title="{{action.label}}">
+                      <i
+                        class="glyphicon glyphicon-{{action.icon}}"
+                        style="color: {{action.color}};"></i>
+                    </a>
+                  </td>
+                </tr>
+              </tbody>
+            </table>
+            <xos-pagination
+              ng-if="vm.config.pagination"
+              page-size="vm.config.pagination.pageSize"
+              total-elements="vm.data.length"
+              change="vm.goToPage">
+              </xos-pagination>
+          </div>
+          <div ng-show="(vm.data.length == 0 || !vm.data) && vm.loader == false">
+             <xos-alert config="{type: 'info'}">
+              No data to show.
+            </xos-alert>
+          </div>
+          <div ng-show="vm.loader == true">
+            <div class="loader"></div>
+          </div>
+        `,
+        bindToController: true,
+        controllerAs: 'vm',
+        controller: function(_, $scope, Comparator){
+
+          this.comparator = Comparator;
+
+          this.loader = true;
+
+          $scope.$watch(() => this.data, data => {
+            if(angular.isDefined(data)){
+              this.loader = false;
+            }
+          });
+
+          if(!this.config){
+            throw new Error('[xosTable] Please provide a configuration via the "config" attribute');
+          }
+
+          if(!this.config.columns){
+            throw new Error('[xosTable] Please provide a columns list in the configuration');
+          }
+
+          // handle default ordering
+          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
+          let customCols = _.filter(this.config.columns, {type: 'custom'});
+          if(angular.isArray(customCols) && customCols.length > 0){
+            _.forEach(customCols, (col) => {
+              if(!col.formatter || !angular.isFunction(col.formatter)){
+                throw new Error('[xosTable] You have provided a custom field type, a formatter function should provided too.');
+              }
+            })
+          }
+
+          // if columns with type 'icon' are provided
+          // check that a custom formatte3 is provided too
+          let iconCols = _.filter(this.config.columns, {type: 'icon'});
+          if(angular.isArray(iconCols) && iconCols.length > 0){
+            _.forEach(iconCols, (col) => {
+              if(!col.formatter || !angular.isFunction(col.formatter)){
+                throw new Error('[xosTable] You have provided an icon field type, a formatter function should provided too.');
+              }
+            })
+          }
+
+          // if a link property is passed,
+          // it should be a function
+          let linkedColumns = _.filter(this.config.columns, col => angular.isDefined(col.link));
+          if(angular.isArray(linkedColumns) && linkedColumns.length > 0){
+            _.forEach(linkedColumns, (col) => {
+              if(!angular.isFunction(col.link)){
+                throw new Error('[xosTable] The link property should be a function.');
+              }
+            })
+          }
+
+          this.columns = this.config.columns;
+          this.classes = this.config.classes || 'table table-striped table-bordered';
+
+          if(this.config.actions){
+            // TODO validate action format
+          }
+          if(this.config.pagination){
+            this.currentPage = 0;
+            this.goToPage = (n) => {
+              this.currentPage = n;
+            };
+          }
+
+        }
+      }
+    })
+    // TODO move in separate files
+    // TODO test
+    .filter('arrayToList', function(){
+      return (input) => {
+        if(!angular.isArray(input)){
+          return input;
+        }
+        return input.join(', ');
+      }
+    })
+    // TODO test
+    .directive('xosLinkWrapper', function() {
+      return {
+        restrict: 'A',
+        transclude: true,
+        template: `
+          <a ng-if="col.link" href="{{col.link(item)}}">
+            <div ng-transclude></div>
+          </a>
+          <div ng-transclude ng-if="!col.link"></div>
+        `
+      };
+    });
+})();
diff --git a/src/ui_components/dumbComponents/table/table.scss b/src/ui_components/dumbComponents/table/table.scss
new file mode 100644
index 0000000..d9830d8
--- /dev/null
+++ b/src/ui_components/dumbComponents/table/table.scss
@@ -0,0 +1,44 @@
+@import '../../../styles/animations.scss';
+
+xos-table {
+
+  display: block;
+
+  tr.ng-move,
+  tr.ng-enter,
+  tr.ng-leave {
+    transition:all linear 0.5s;
+  }
+
+  tr.ng-leave.ng-leave-active,
+  tr.ng-move,
+  tr.ng-enter {
+    opacity:0;
+    animation: 0.5s slideOutRight ease-in-out;
+  }
+
+  tr.ng-leave,
+  tr.ng-move.ng-move-active,
+  tr.ng-enter.ng-enter-active {
+    opacity:1;
+    animation: 0.5s slideInRight ease-in-out;
+  }
+
+  td dl {
+    margin-bottom: 0;
+
+    dt {
+      width: auto !important;
+      margin-right: 10px;
+    }
+    
+    dt:after {
+      /*display: block;*/
+      content: ':';
+    }
+
+    dd {
+      margin-left: 0 !important;
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/ui_components/dumbComponents/validation/validation.component.js b/src/ui_components/dumbComponents/validation/validation.component.js
new file mode 100644
index 0000000..91610e1
--- /dev/null
+++ b/src/ui_components/dumbComponents/validation/validation.component.js
@@ -0,0 +1,112 @@
+/**
+ * © OpenCORD
+ *
+ * Visit http://guide.xosproject.org/devguide/addview/ for more information
+ *
+ * Created by teone on 4/15/16.
+ */
+
+(function () {
+  'use strict';
+
+  angular.module('xos.uiComponents')
+
+  /**
+    * @ngdoc directive
+    * @name xos.uiComponents.directive:xosValidation
+    * @restrict E
+    * @description The xos-validation directive
+    * @param {Object} errors The error object
+    * @element ANY
+    * @scope
+  * @example
+  <example module="sampleValidation">
+    <file name="index.html">
+      <div ng-controller="SampleCtrl as vm">
+        <div class="row">
+          <div class="col-xs-12">
+            <label>Set an error type:</label>
+          </div>
+          <div class="col-xs-2">
+            <a class="btn"
+              ng-click="vm.field.$error.required = !vm.field.$error.required"
+              ng-class="{'btn-default': !vm.field.$error.required, 'btn-success': vm.field.$error.required}">
+              Required
+            </a>
+          </div>
+          <div class="col-xs-2">
+            <a class="btn"
+              ng-click="vm.field.$error.email = !vm.field.$error.email"
+              ng-class="{'btn-default': !vm.field.$error.email, 'btn-success': vm.field.$error.email}">
+              Email
+            </a>
+          </div>
+          <div class="col-xs-2">
+            <a class="btn"
+              ng-click="vm.field.$error.minlength = !vm.field.$error.minlength"
+              ng-class="{'btn-default': !vm.field.$error.minlength, 'btn-success': vm.field.$error.minlength}">
+              Min Length
+            </a>
+          </div>
+          <div class="col-xs-2">
+            <a class="btn"
+              ng-click="vm.field.$error.maxlength = !vm.field.$error.maxlength"
+              ng-class="{'btn-default': !vm.field.$error.maxlength, 'btn-success': vm.field.$error.maxlength}">
+              Max Length
+            </a>
+          </div>
+        </div>
+        <xos-validation field ="vm.field" form = "vm.form"></xos-validation>
+      </div>
+    </file>
+    <file name="script.js">
+      angular.module('sampleValidation', ['xos.uiComponents'])
+      .controller('SampleCtrl', function(){
+        this.field = {
+          $error: {}
+        };
+        this.form= {
+        $submitted:true
+        }
+      });
+    </file>
+  </example>
+    */
+
+  .directive('xosValidation', function(){
+    return {
+      restrict: 'E',
+      scope: {
+        field: '=',
+        form: '='
+      },
+      template: `
+        <div ng-cloak>
+          <xos-alert config="vm.config" show="vm.field.$error.required !== undefined && vm.field.$error.required !== false  && (vm.field.$touched || vm.form.$submitted)">
+            Field required
+          </xos-alert>
+          <xos-alert config="vm.config" show="vm.field.$error.email !== undefined && vm.field.$error.email !== false && (vm.field.$touched || vm.form.$submitted)">
+            This is not a valid email
+          </xos-alert>
+          <xos-alert config="vm.config" show="vm.field.$error.minlength !== undefined && vm.field.$error.minlength !== false && (vm.field.$touched || vm.form.$submitted)">
+            Too short
+          </xos-alert>
+          <xos-alert config="vm.config" show="vm.field.$error.maxlength !== undefined && vm.field.$error.maxlength !== false && (vm.field.$touched || vm.form.$submitted)">
+            Too long
+          </xos-alert>
+          <xos-alert config="vm.config" show="vm.field.$error.custom !== undefined && vm.field.$error.custom !== false && (vm.field.$touched || vm.form.$submitted)">
+            Field invalid
+          </xos-alert>
+        </div>
+      `,
+      transclude: true,
+      bindToController: true,
+      controllerAs: 'vm',
+      controller: function(){
+        this.config = {
+          type: 'danger'
+        }
+      }
+    }
+  })
+})();
diff --git a/src/ui_components/dumbComponents/validation/validation.scss b/src/ui_components/dumbComponents/validation/validation.scss
new file mode 100644
index 0000000..588853f
--- /dev/null
+++ b/src/ui_components/dumbComponents/validation/validation.scss
@@ -0,0 +1,7 @@
+@import '../../../styles/animations.scss';
+@import '../../../../bower_components/bootstrap-sass/assets/stylesheets/bootstrap/_variables.scss';
+
+input + xos-validation {
+  margin-top: $form-group-margin-bottom;
+  display: block;
+}
\ No newline at end of file
diff --git a/src/ui_components/smartComponents/smartPie/smartPie.component.js b/src/ui_components/smartComponents/smartPie/smartPie.component.js
new file mode 100644
index 0000000..f8a3985
--- /dev/null
+++ b/src/ui_components/smartComponents/smartPie/smartPie.component.js
@@ -0,0 +1,248 @@
+/**
+ * © OpenCORD
+ *
+ * Visit http://guide.xosproject.org/devguide/addview/ for more information
+ *
+ * Created by teone on 3/24/16.
+ */
+
+(function () {
+  'use strict';
+
+  angular.module('xos.uiComponents')
+  /**
+    * @ngdoc directive
+    * @name xos.uiComponents.directive:xosSmartPie
+    * @restrict E
+    * @description The xos-table directive
+    * @param {Object} config The configuration for the component,
+    * it is composed by the name of an angular [$resource](https://docs.angularjs.org/api/ngResource/service/$resource)
+    * and a field name that is used to group the data.
+    * ```
+    * {
+        resource: 'Users',
+        groupBy: 'fieldName',
+        classes: 'my-custom-class',
+        labelFormatter: (labels) => {
+          // here you can format your label,
+          // you should return an array with the same order
+          return labels;
+        }
+      }
+    * ```
+    * @scope
+    * @example
+    
+    Displaying Local data
+
+    <example module="sampleSmartPieLocal">
+      <file name="index.html">
+        <div ng-controller="SampleCtrlLocal as vm">
+          <xos-smart-pie config="vm.configLocal"></xos-smart-pie>
+        </div>
+      </file>
+      <file name="script.js">
+        angular.module('sampleSmartPieLocal', ['xos.uiComponents'])
+        .factory('_', function($window){
+          return $window._;
+        })
+        .controller('SampleCtrlLocal', function($timeout){
+          
+          this.datas = [
+            {id: 1, first_name: 'Jon', last_name: 'aaa', category: 2},
+            {id: 2, first_name: 'Danaerys', last_name: 'Targaryen', category: 1},
+            {id: 3, first_name: 'Aria', last_name: 'Stark', category: 2}
+          ];
+
+          this.configLocal = {
+            data: [],
+            groupBy: 'category',
+            classes: 'local',
+            labelFormatter: (labels) => {
+              return labels.map(l => l === '1' ? 'North' : 'Dragon');
+            }
+          };
+          
+          $timeout(() => {
+            // this need to be triggered in this way just because of ngDoc,
+            // otherwise you can assign data directly in the config
+            this.configLocal.data = this.datas;
+          }, 1)
+        });
+      </file>
+    </example>
+
+    Fetching data from API
+
+    <example module="sampleSmartPieResource">
+      <file name="index.html">
+        <div ng-controller="SampleCtrl as vm">
+          <xos-smart-pie config="vm.config"></xos-smart-pie>
+        </div>
+      </file>
+      <file name="script.js">
+        angular.module('sampleSmartPieResource', ['xos.uiComponents', 'ngResource', 'ngMockE2E'])
+        .controller('SampleCtrl', function(){
+          this.config = {
+            resource: 'SampleResource',
+            groupBy: 'category',
+            classes: 'resource',
+            labelFormatter: (labels) => {
+              return labels.map(l => l === '1' ? 'North' : 'Dragon');
+            }
+          };
+        });
+      </file>
+      <file name="backendPoll.js">
+        angular.module('sampleSmartPieResource')
+        .run(function($httpBackend, _){
+          let datas = [
+            {id: 1, first_name: 'Jon', last_name: 'Snow', category: 1},
+            {id: 2, first_name: 'Danaerys', last_name: 'Targaryen', category: 2},
+            {id: 3, first_name: 'Aria', last_name: 'Stark', category: 1}
+          ];
+
+          $httpBackend.whenGET('/test').respond(200, datas)
+        })
+        .factory('_', function($window){
+          return $window._;
+        })
+        .service('SampleResource', function($resource){
+          return $resource('/test/:id', {id: '@id'});
+        })
+      </file>
+    </example>
+
+    Polling data from API
+
+    <example module="sampleSmartPiePoll">
+      <file name="index.html">
+        <div ng-controller="SampleCtrl as vm">
+          <xos-smart-pie config="vm.config"></xos-smart-pie>
+        </div>
+      </file>
+      <file name="script.js">
+        angular.module('sampleSmartPiePoll', ['xos.uiComponents', 'ngResource', 'ngMockE2E'])
+        .controller('SampleCtrl', function(){
+          this.config = {
+            resource: 'SampleResource',
+            groupBy: 'category',
+            poll: 2,
+            labelFormatter: (labels) => {
+              return labels.map(l => l === '1' ? 'Active' : 'Banned');
+            }
+          };
+        });
+      </file>
+      <file name="backend.js">
+        angular.module('sampleSmartPiePoll')
+        .run(function($httpBackend, _){
+          let mock = [
+            [
+              {id: 1, first_name: 'Jon', last_name: 'Snow', category: 1},
+              {id: 2, first_name: 'Danaerys', last_name: 'Targaryen', category: 2},
+              {id: 3, first_name: 'Aria', last_name: 'Stark', category: 1},
+              {id: 3, first_name: 'Tyrion', last_name: 'Lannister', category: 1}
+            ],
+
+            [
+              {id: 1, first_name: 'Jon', last_name: 'Snow', category: 1},
+              {id: 2, first_name: 'Danaerys', last_name: 'Targaryen', category: 2},
+              {id: 3, first_name: 'Aria', last_name: 'Stark', category: 2},
+              {id: 3, first_name: 'Tyrion', last_name: 'Lannister', category: 2}
+            ],
+
+            [
+              {id: 1, first_name: 'Jon', last_name: 'Snow', category: 1},
+              {id: 2, first_name: 'Danaerys', last_name: 'Targaryen', category: 2},
+              {id: 3, first_name: 'Aria', last_name: 'Stark', category: 1},
+              {id: 3, first_name: 'Tyrion', last_name: 'Lannister', category: 2}
+            ]
+          ];
+          $httpBackend.whenGET('/test').respond(function(method, url, data, headers, params) {
+            return [200, mock[Math.round(Math.random() * 3)]];
+          });
+        })
+        .factory('_', function($window){
+          return $window._;
+        })
+        .service('SampleResource', function($resource){
+          return $resource('/test/:id', {id: '@id'});
+        })
+      </file>
+    </example>
+    */
+  .directive('xosSmartPie', function(){
+    return {
+      restrict: 'E',
+      scope: {
+        config: '='
+      },
+      template: `
+        <canvas
+          class="chart chart-pie {{vm.config.classes}}"
+          chart-data="vm.data" chart-labels="vm.labels"
+          chart-legend="{{vm.config.legend}}">
+        </canvas>
+      `,
+      bindToController: true,
+      controllerAs: 'vm',
+      controller: function($injector, $interval, $scope, $timeout, _){
+
+        if(!this.config.resource && !this.config.data){
+          throw new Error('[xosSmartPie] Please provide a resource or an array of data in the configuration');
+        }
+
+        const groupData = (data) => _.groupBy(data, this.config.groupBy);
+        const formatData = (data) => _.reduce(Object.keys(data), (list, group) => list.concat(data[group].length), []);
+        const formatLabels = (data) => angular.isFunction(this.config.labelFormatter) ? this.config.labelFormatter(Object.keys(data)) : Object.keys(data);
+
+        const prepareData = (data) => {
+          // group data
+          let grouped = groupData(data);
+          this.data = formatData(grouped);
+          // create labels
+          this.labels = formatLabels(grouped);
+        }
+
+        if(this.config.resource){
+
+          this.Resource = $injector.get(this.config.resource);
+          const getData = () => {
+            this.Resource.query().$promise
+            .then((res) => {
+
+              if(!res[0]){
+                return;
+              }
+
+              prepareData(res);
+            });
+          }
+
+          getData();
+
+          if(this.config.poll){
+            $interval(() => {getData()}, this.config.poll * 1000)
+          }
+        }
+        else {
+          $scope.$watch(() => this.config.data, (data) => {
+            if(data){
+              prepareData(this.config.data);
+            }
+          }, true);
+        }
+
+        $scope.$on('create', function (event, chart) {
+          console.log(`create: ${chart.id}`);
+        });
+
+        $scope.$on('destroy', function (event, chart) {
+          console.log(`destroy: ${chart.id}`);
+        });
+
+      }
+    };
+  });
+})();
diff --git a/src/ui_components/smartComponents/smartTable/smartTable.component.js b/src/ui_components/smartComponents/smartTable/smartTable.component.js
new file mode 100644
index 0000000..622952f
--- /dev/null
+++ b/src/ui_components/smartComponents/smartTable/smartTable.component.js
@@ -0,0 +1,269 @@
+/**
+ * © OpenCORD
+ *
+ * Visit http://guide.xosproject.org/devguide/addview/ for more information
+ *
+ * Created by teone on 3/24/16.
+ */
+
+(function () {
+  'use strict';
+
+  angular.module('xos.uiComponents')
+
+    /**
+    * @ngdoc directive
+    * @name xos.uiComponents.directive:xosSmartTable
+    * @link xos.uiComponents.directive:xosTable xosTable
+    * @link xos.uiComponents.directive:xosForm xosForm
+    * @restrict E
+    * @description The xos-table directive
+    * @param {Object} config The configuration for the component,
+    * it is composed by the name of an angular [$resource](https://docs.angularjs.org/api/ngResource/service/$resource)
+    * and an array of fields that shouldn't be printed.
+    * ```
+    * {
+        resource: 'Users',
+        hiddenFields: []
+      }
+    * ```
+    * @scope
+    * @example
+
+    <example module="sampleSmartTable">
+      <file name="index.html">
+        <div ng-controller="SampleCtrl as vm">
+          <xos-smart-table config="vm.config"></xos-smart-table>
+        </div>
+      </file>
+      <file name="script.js">
+        angular.module('sampleSmartTable', ['xos.uiComponents', 'ngResource', 'ngMockE2E'])
+        // This is only for documentation purpose
+        .run(function($httpBackend, _){
+          let datas = [{id: 1, name: 'Jhon', surname: 'Doe'}];
+          let count = 1;
+
+          let paramsUrl = new RegExp(/\/test\/(.+)/);
+
+          $httpBackend.whenDELETE(paramsUrl, undefined, ['id']).respond((method, url, data, headers, params) => {
+            data = angular.fromJson(data);
+            let id = url.match(paramsUrl)[1];
+            _.remove(datas, (d) => {
+              return d.id === parseInt(id);
+            })
+            return [204];
+          });
+
+          $httpBackend.whenGET('/test').respond(200, datas)
+          $httpBackend.whenPOST('/test').respond((method, url, data) => {
+            data = angular.fromJson(data);
+            data.id = ++count;
+            datas.push(data);
+            return [201, data, {}];
+          });
+        })
+        .factory('_', function($window){
+          return $window._;
+        })
+        .service('SampleResource', function($resource){
+          return $resource('/test/:id', {id: '@id'});
+        })
+        // End of documentation purpose, example start
+        .controller('SampleCtrl', function(){
+          this.config = {
+            resource: 'SampleResource'
+          };
+        });
+      </file>
+    </example>
+    */
+   
+  .directive('xosSmartTable', function(){
+    return {
+      restrict: 'E',
+      scope: {
+        config: '='
+      },
+      template: `
+        <div class="row" ng-show="vm.data.length > 0">
+          <div class="col-xs-12 text-right">
+            <a href="" class="btn btn-success" ng-click="vm.createItem()">
+              Add
+            </a>
+          </div>
+        </div>
+        <div class="row">
+          <div class="col-xs-12 table-responsive">
+            <xos-table config="vm.tableConfig" data="vm.data"></xos-table>
+          </div>
+        </div>
+        <div class="panel panel-default" ng-show="vm.detailedItem">
+          <div class="panel-heading">
+            <div class="row">
+              <div class="col-xs-11">
+                <h3 class="panel-title" ng-show="vm.detailedItem.id">Update {{vm.config.resource}} {{vm.detailedItem.id}}</h3>
+                <h3 class="panel-title" ng-show="!vm.detailedItem.id">Create {{vm.config.resource}} item</h3>
+              </div>
+              <div class="col-xs-1">
+                <a href="" ng-click="vm.cleanForm()">
+                  <i class="glyphicon glyphicon-remove pull-right"></i>
+                </a>
+              </div>
+            </div>
+          </div>
+          <div class="panel-body">
+            <xos-form config="vm.formConfig" ng-model="vm.detailedItem"></xos-form>
+          </div>
+        </div>
+        <xos-alert config="{type: 'success', closeBtn: true}" show="vm.responseMsg">{{vm.responseMsg}}</xos-alert>
+        <xos-alert config="{type: 'danger', closeBtn: true}" show="vm.responseErr">{{vm.responseErr}}</xos-alert>
+      `,
+      bindToController: true,
+      controllerAs: 'vm',
+      controller: function($injector, LabelFormatter, _, XosFormHelpers){
+        
+        // TODO
+        // - Validate the config (what if resource does not exist?)
+
+        // NOTE
+        // Corner case
+        // - if response is empty, how can we generate a form ?
+
+        this.responseMsg = false;
+        this.responseErr = false;
+
+        this.tableConfig = {
+          columns: [
+          ],
+          actions: [
+            {
+              label: 'delete',
+              icon: 'remove',
+              cb: (item) => {
+                this.Resource.delete({id: item.id}).$promise
+                .then(() => {
+                  _.remove(this.data, (d) => d.id === item.id);
+                  this.responseMsg = `${this.config.resource} with id ${item.id} successfully deleted`;
+                })
+                .catch(err => {
+                  this.responseErr = err.data.detail || `Error while deleting ${this.config.resource} with id ${item.id}`;
+                });
+              },
+              color: 'red'
+            },
+            {
+              label: 'details',
+              icon: 'search',
+              cb: (item) => {
+                this.detailedItem = item;
+              }
+            }
+          ],
+          classes: 'table table-striped table-bordered table-responsive',
+          filter: 'field',
+          order: true,
+          pagination: {
+            pageSize: 10
+          }
+        };
+
+        this.formConfig = {
+          exclude: this.config.hiddenFields,
+          fields: {},
+          formName: `${this.config.resource}Form`,
+          actions: [
+            {
+              label: 'Save',
+              icon: 'ok',
+              cb: (item) => {
+                let p;
+                let isNew = true;
+
+                if(item.id){
+                  p = item.$update();
+                  isNew = false;
+                }
+                else {
+                  p = item.$save();
+                }
+
+                p.then((res) => {
+                  if(isNew){
+                    this.data.push(angular.copy(res));
+                  }
+                  delete this.detailedItem;
+                  this.responseMsg = `${this.config.resource} with id ${item.id} successfully saved`;
+                })
+                .catch((err) => {
+                  this.responseErr = err.data.detail || `Error while saving ${this.config.resource} with id ${item.id}`;
+                })
+              },
+              class: 'success'
+            }
+          ]
+        };
+
+        this.cleanForm = () => {
+          delete this.detailedItem;
+        };
+
+        this.createItem = () => {
+          this.detailedItem = new this.Resource();
+        };
+
+        this.Resource = $injector.get(this.config.resource);
+
+        const getData = () => {
+          this.Resource.query().$promise
+          .then((res) => {
+
+            if(!res[0]){
+              this.data = res;
+              return;
+            }
+
+            let item = res[0];
+            let props = Object.keys(item);
+
+            _.remove(props, p => {
+              return p === 'id' || p === 'validators'
+            });
+
+            // TODO move out cb,  non sense triggering a lot of times
+            if(angular.isArray(this.config.hiddenFields)){
+              props = _.difference(props, this.config.hiddenFields)
+            }
+
+            let labels = props.map(p => LabelFormatter.format(p));
+
+            props.forEach((p, i) => {
+              let fieldConfig = {
+                label: labels[i],
+                prop: p
+              };
+
+              if(angular.isString(item[p]) && typeof item[p] !== 'undefined'){
+                fieldConfig.type = typeof item[p];
+              }
+
+              this.tableConfig.columns.push(fieldConfig);
+            });
+
+            // build form structure
+            // TODO move in a pure function for testing purposes
+            props.forEach((p, i) => {
+              this.formConfig.fields[p] = {
+                label: LabelFormatter.format(labels[i]).replace(':', ''),
+                type: XosFormHelpers._getFieldFormat(item[p])
+              };
+            });
+
+            this.data = res;
+          });
+        }
+
+        getData();
+      }
+    };
+  });
+})();
\ No newline at end of file
diff --git a/src/ui_components/smartComponents/smartTable/smartTable.scss b/src/ui_components/smartComponents/smartTable/smartTable.scss
new file mode 100644
index 0000000..fc63fdf
--- /dev/null
+++ b/src/ui_components/smartComponents/smartTable/smartTable.scss
@@ -0,0 +1,3 @@
+xos-smart-table{
+  
+}
\ No newline at end of file
diff --git a/src/ui_components/ui-components.module.js b/src/ui_components/ui-components.module.js
new file mode 100644
index 0000000..f8bc222
--- /dev/null
+++ b/src/ui_components/ui-components.module.js
@@ -0,0 +1,31 @@
+/**
+ * © OpenCORD
+ *
+ * Visit http://guide.xosproject.org/devguide/addview/ for more information
+ *
+ * Created by teone on 3/24/16.
+ */
+
+(function () {
+  'use strict';
+
+  /**
+  * @ngdoc overview
+  * @name xos.uiComponents
+  * @description
+  * # xos.uiComponents
+  * A collection of UI components useful for Dashboard development. <br/>
+  * Currently available components are:
+  * - [xosAlert](/#/module/xos.uiComponents.directive:xosAlert)
+  * - [xosForm](/#/module/xos.uiComponents.directive:xosForm)
+  * - [xosPagination](/#/module/xos.uiComponents.directive:xosPagination)
+  * - [xosSmartTable](/#/module/xos.uiComponents.directive:xosSmartTable)
+  * - [xosTable](/#/module/xos.uiComponents.directive:xosTable)
+  * - [xosValidation](/#/module/xos.uiComponents.directive:xosValidation)
+  **/
+
+  angular.module('xos.uiComponents', [
+    'chart.js',
+    'RecursionHelper'
+  ])
+})();
diff --git a/src/xosHelpers.module.js b/src/xosHelpers.module.js
new file mode 100644
index 0000000..25c8354
--- /dev/null
+++ b/src/xosHelpers.module.js
@@ -0,0 +1,43 @@
+(function() {
+  'use strict';
+
+  /**
+  * @ngdoc overview
+  * @name xos.helpers
+  * @description
+  * # xos.Helpers
+  * A collection of helpers to work with XOS <br/>
+  * Currently available components are:
+  * - [NoHyperlinks](/#/module/xos.helpers.NoHyperlinks)
+  * - [SetCSRFToken](/#/module/xos.helpers.SetCSRFToken)
+  * - [xosNotification](/#/module/xos.helpers.xosNotification)
+  * - [XosUserPrefs](/#/module/xos.helpers.XosUserPrefs)
+  * <br/><br/>
+  * A set of angular [$resource](https://docs.angularjs.org/api/ngResource/service/$resource) is provided to work with the API.<br>
+  * You can find the documentation [here](#/rest-api)
+  **/
+
+  angular
+      .module('xos.helpers', [
+        'ngCookies',
+        'ngResource',
+        'ngAnimate',
+        'xos.uiComponents'
+      ])
+      .config(config)
+
+      /**
+      * @ngdoc service
+      * @name xos.helpers._
+      * @description Wrap [lodash](https://lodash.com/docs) in an Angular Service
+      **/
+
+      .factory('_', $window => $window._ );
+
+  function config($httpProvider, $interpolateProvider, $resourceProvider) {
+    $httpProvider.interceptors.push('SetCSRFToken');
+
+    // NOTE http://www.masnun.com/2013/09/18/django-rest-framework-angularjs-resource-trailing-slash-problem.html
+    $resourceProvider.defaults.stripTrailingSlashes = false;
+  }
+})();
\ No newline at end of file