<commit_before>(function () {
  'use strict';

  angular
      .module('protractorRec')
      .controller('MainController', MainController);

  /** @ngInject */
  function MainController($scope, $http, $log, $filter, $timeout, $mdToast, $location, $mdDialog, socket) {

    var vm = this;

    /*-------------------------------------------------------------------
     * 		 				 	ATTRIBUTES
     *-------------------------------------------------------------------*/

    vm.isLoadingSession    = false;
    vm.showConf            = $location.path() == '/conf' ? true : false;
    vm.isSnippet           = false;
    vm.showSelectedOptions = false;
    vm.index = false;

    /* If first run set examples or get from local storage */
    vm.url       = localStorage.getItem('url') ? localStorage.getItem('url') : 'http://www.protractortest.org';
    vm.describes = localStorage.getItem('describes') ? angular.fromJson(localStorage.getItem('describes')) : [];
    vm.conf      = localStorage.getItem('conf') ? angular.fromJson(localStorage.getItem('conf')) : false;

    /* Javascript snippet to inject on session */
    vm.snippet = 'var b=document.getElementsByTagName("body")[0];' +
        'var i = document.createElement("iframe");' +
        'i.id="recorder-iframe";' +
        'i.setAttribute("style", "display:none");' +
        'b.appendChild(i);' +
        'var i = document.getElementById("recorder-iframe");' +
        'var s = i.contentWindow.document.createElement("script");' +
        's.src = "http://localhost:9000/socket.io-1.3.7.js";' +
        'i.contentWindow.document.body.appendChild(s);' +
        'var s = i.contentWindow.document.createElement("script");' +
        's.src = "http://localhost:9000/snippet.js";' +
        'i.contentWindow.document.body.appendChild(s);';

    vm.session       = {};
    vm.lines         = [];
    vm.describe      = {};
    vm.spec          = [];
    vm.dataBind      = [];
    vm.capabilities  = [];
    vm.selectedItems = 0;

    /* Configuration example */
    if(!vm.conf) {
      vm.conf = {
        isRecording: false,
        string: 'Conf.js',
        seleniumAddress: 'http://localhost:4444/wd/hub',
        capabilities: ['chromedriver'],
        spec: {
          actions: [
            {"type": "link", "value": vm.url, "action": "get"}
          ]
        }

      };
    }

    /* Spec example */
    vm.sample = {
      string: 'Describe Protractor Example',
      specs: [
        {
          string: 'Should navigate to protractortest.org',
          actions: [
            {"type": "link", "value": "http://www.protractortest.org", "action": "get"}
          ]
        }
      ]
    };

    /* Base options for new spec */
    vm.blankSpec = {
      string: '',
      actions: []
    };

    vm.hidden = false;
    vm.isOpen = false;
    vm.hover = false;

    // On opening, add a delayed property which shows tooltips after the speed dial has opened
    // so that they have the proper position; if closing, immediately hide the tooltips
    $scope.$watch('main.isOpen', function (isOpen) {
      if (isOpen) {
        $timeout(function () {
          vm.tooltipVisible = vm.isOpen;
        }, 600);
      } else {
        vm.tooltipVisible = vm.isOpen;
      }
    });

    /*-------------------------------------------------------------------
     * 		 				  SOCKET ON
     *-------------------------------------------------------------------*/
    /**
     * Messages: onsnippet, click, change, keyup, assertion, session-disconnect, protractor-log
     */

    socket.on('onsnippet', function(data){
      vm.isSnippet = true;
    });

    socket.on('click', function (data) {
      $log.debug('onclick');
      $log.debug(data);

      vm.setElement(data);

    });

    socket.on('change', function (data) {
      $log.debug('onchange');
      $log.debug(data);

      vm.setElement(data);

    });

    socket.on('keyup', function (data) {
      $log.debug('onkeyup');
      $log.debug(data);

      if(vm.conf.isRecording) {
        var lastAction = vm.spec.actions[vm.spec.actions.length - 1];
        lastAction.action = 'sendKeys';
        lastAction.value = data;
      }

    });

    socket.on('assertion', function (data) {
      $log.debug('onassertion');
      $log.debug(data);

      if(vm.conf.isRecording) {
        var lastAction = vm.spec.actions[vm.spec.actions.length - 1];

        lastAction.action = 'assertion';
        lastAction.value = data;

        vm.dataBind.forEach(function (data) {

          lastAction.locators.push(data);

        });
      }

    });

    socket.on('session-disconnect', function (data) {

      vm.isSnippet = false;
      vm.isLoadingSession = true;

      $log.debug('on-session-disconnect');
      $log.debug(data);

      vm.getSessionSource();

    });

    socket.on('protractor-log', function (data) {
      $log.debug('protractor-log');
      $log.debug(data);
    });

    vm.setCapabilities = function(capability) {
      if(capability.checked){
        vm.conf.capabilities.push(capability.driver);
      } else {
        var index = vm.conf.capabilities.indexOf(capability.driver);
        vm.conf.capabilities.splice(index, 1);
      }
    };

    vm.openConf = function() {
      vm.showConf = true;
      vm.setSpec(vm.conf.spec, vm.showConf);
    };

    vm.setExample = function () {

      if (!vm.describes.length) {

        vm.describes.push(angular.copy(vm.sample));

        vm.setDescribe(vm.describes[0]);
        vm.setSpec(vm.describe.specs[0]);

        vm.createSession();
      } else {
        vm.setDescribe(vm.describes[0]);
        vm.setSpec(vm.describe.specs[0]);
      }

    };

    vm.newDescribe = function () {
      $log.debug('newDescribe');

    };

    vm.addSpec = function () {
      $log.debug('addSpec');

      vm.describe.specs.push(angular.copy(vm.blankSpec));
      vm.setSpec(vm.describe.specs[vm.describe.specs.length - 1]);
    };

    vm.setDescribe = function (describe) {
      vm.describe = describe;
    };

    vm.setSpec = function (spec, conf) {
      $log.debug('setSpec');
      if(vm.showConf && conf == undefined || conf == true) {
        vm.showConf = true;
        vm.spec = vm.conf.spec;
        $location.path('/conf');
      } else {
        vm.spec = spec;
        vm.showConf = false;
        $location.path('/');
      }

      angular.forEach(vm.spec.actions, function(action) {
        action.checked = false;
      });
    };

    vm.setElementOnChange = function (element) {

      if (vm.conf.isRecording) {

        var target = angular.element(element.outerHTML);

        if (target[0].tagName.match(/^select/i) && element.value) {

          vm.addElement(target, 'select', 'click', element.value, element.xPath);
        }
      }
    };

    vm.setElement = function (element) {

      if(vm.conf.isRecording) {
        var target = angular.element(element.outerHTML);
        var parent = !element.offsetParent.outerHTML ? [] : angular.element(element.offsetParent.outerHTML);

        var value = '';

        if (target[0].tagName.match(/^button/i) || (parent[0].tagName && parent[0].tagName.match(/^button/i)) && !target[0].tagName.match(/^input/i)) {

          vm.addElement(parent, 'button', 'click', target.text().trim(), element.xPath);

        } else if (target[0].tagName.match(/^input/i)) {
          vm.addElement(target, 'input', 'click', false, element.xPath);
        } else if (target[0].tagName.match(/^a/i)) {
          vm.addElement(target, 'a', 'click', target.text().trim(), element.xPath);
        } else if (element.ngRepeat) {

          value = target.text() ? target.text() : false

          //if(value)
          vm.addElement(target, target[0].tagName.toLowerCase(), 'wait', value, element.xPath);

          vm.addElement(target, 'row', 'click', element.ngRepeat.rowIndex, element.xPath, element.ngRepeat.value);

          vm.addElement(target, target[0].tagName.toLowerCase(), 'click', value, element.xPath);

        } else {
          value = target.text() ? target.text() : false;
          vm.addElement(target, target[0].tagName.toLowerCase(), 'click', value, element.xPath);
        }
      }
    };

    vm.addElement = function (element, type, actionType, value, xPath, repeater) {

      var locators = [];

      if(type == 'select' && vm.getAttr('ng-model', element))
        locators.push({type: 'model', value: vm.getAttr('ng-model', element)});

      if(type == 'row')
        locators.push({type: 'repeater', value: repeater});

      if (type == 'button' && value)
        locators.push({type: 'buttonText', value: value});

      if (type == 'input' && vm.getAttr('ng-model', element))
        locators.push({type: 'model', value: vm.getAttr('ng-model', element)});

      if (type == 'input' && vm.getAttr('name', element))
        locators.push({type: 'css', value: '[name="' + vm.getAttr('name', element) + '"]'});

      /*if (type == 'input' && vm.getAttr('type', element) == 'button') {
        locators.push({type: 'id', value: vm.getAttr('id', element)});
      }*/

      if (type == 'input' && vm.getAttr('type', element) == 'submit') {
        locators.push({type: 'css', value: '[value="' + element.val() + '"]'});
      }

      if (vm.getAttr('href', element)) {
        locators.push({type: 'linkText', value: value});
        locators.push({type: 'get', value: vm.getAttr('href', element)});
      }

      if (vm.getAttr('id', element))
        locators.push({type: 'id', value: vm.getAttr('id', element)});

      if (vm.getAttr('class', element) || actionType == 'wait') {

        if (value)
          locators.push({type: 'xpath', value: '//' + type + '[.="' + value + '"]'});
        if (xPath && !vm.getAttr('ng-click', element) && !vm.getAttr('class', element))
          locators.push({type: 'xpath', value: xPath});
        if (vm.getAttr('ng-click', element)) {
          //element(by.css("[ng-click='changeToRemove(row.entity)']")).click();
          locators.push({type: 'css', value: '[ng-click="' + vm.getAttr('ng-click', element) + '"]'})
        }

        if(vm.getAttr('class', element)) {
          locators.push({type: 'css', value: '.' + vm.getAttr('class', element).replace(/\s/g, '.')});
        }

        if (xPath)
          locators.push({type: 'xpath', value: xPath});
      }

      var action = {
        //element: element.html(),
        type: type,
        value: value,
        action: actionType,
        locators: locators,
        locator: locators ? {type: locators[0].type, value: locators[0].value} : null
      };

      vm.spec.actions.push(action);

      var mainContent = angular.element( document.querySelector('#main') );
      mainContent[0].scrollTop = mainContent[0].scrollHeight;

      vm.getSessionUrl();

      //localStorage.setItem('actions', angular.toJson(vm.actions));

      //vm.getSessionUrl();

    };

    /**
     * Get all data bind to suggest on assertions
     */
    vm.getAllDataBind = function () {

      $log.debug('getAllDataBind');

      var dataBind = vm.session.source.match(/\{{2}(.*?)\}{2}|ng-bind=["|'](.*?)["|']/igm);

      angular.forEach(dataBind, function (data) {

        data = data.replace(/\"|\'|ng-bind=|{{|}}/g, '').trim();

        if (!$filter('filter')(vm.dataBind, data).length) {

          vm.dataBind.push({type: 'bind', value: data});

        }

      });

      $log.debug(dataBind);
      $log.debug(vm.dataBind);

    };

    vm.runTest = function () {

      $log.debug('runTest');

      $http({
        method: 'GET',
        url: 'http://localhost:9000/run'
      }).then(function successCallback(response) {

        $log.debug('Test finished');
        $log.debug(response);

      });
    };

    vm.removeSpec = function (index) {
      vm.describe.specs.splice(index, 1);
    };

    vm.exportProtractor = function () {

      $log.debug('exportProtractor');

      /* Get line export to actions in conf.js */
      vm.conf.spec.lines = [];

      angular.forEach(vm.conf.spec.actions, function (action) {

        vm.conf.spec.lines.push(vm.getLine(action));

      });

      /* Get line exported to actions in spec.js */
      vm.spec.lines = [];

      if($filter('filter')(vm.spec.actions, {action: 'wait'}).length != 0)
        vm.spec.lines.push('var EC = protractor.ExpectedConditions;');

      angular.forEach(vm.spec.actions, function (action) {

        vm.spec.lines.push(vm.getLine(action));

      });

      $http({
        method: 'POST',
        url: 'http://localhost:9000/export',
        data: {baseUrl: vm.url, conf: angular.toJson(vm.conf), describe: angular.toJson(vm.describes)}
      }).then(function successCallback(response) {

        $log.debug('Exported');
        $log.debug(response);

        $mdToast.show(
            $mdToast.simple()
                .content('File exported!')
                .position('bottom left')
                .hideDelay(3000)
        );

      });

    };

    vm.getLine = function(action) {

      var line = '';

      if(action.action == 'wait'){

        var elm = '';

        if(action.locator.type == 'xpath')
          elm = "element(by.xpath('" + action.locator.value + "'))";

        if(action.locator.type == 'css')
          elm = "element(by.css('" + action.locator.value + "');";

        line = "browser.wait(EC.presenceOf(" + elm + "), 10000);";

      }

      if(action.type == 'select' && action.action == 'click' && action.locator.type == 'model')
        line = "element(by.model('" + action.locator.value + "')).$('[value=\"" + action.value + "\"]').click();";

      if(action.action == 'click' && action.locator.type == 'repeater')
        line = "element(by.repeater('" + action.locator.value + "').row(" + action.value + ")).";

      if(action.action == 'sendKeys' && action.locator.type == 'model') {
        line = "element(by.model('" + action.locator.value + "')).sendKeys('" + action.value + "');";
      }

      if(action.action == 'sendKeys' && action.locator.type == 'css') {
        line = "element(by.css('" + action.locator.value + "')).sendKeys('" + action.value + "');";
      }

      if(action.action == 'click' && action.type == 'button' && action.value) {
        line = "element(by.buttonText('" + action.value + "')).click();";
      }

      if(action.action == 'click' && action.type == 'a' && action.locator.type == 'linkText') {
        line = "element(by.linkText('" + action.value + "')).click();";
      }

      if(action.action == 'click' && action.type == 'a' && action.locator.type == 'get') {
        line = "browser.get('" + action.locator.value + "');";
      }

      if(action.action == 'click' && action.locator.type == 'xpath') {
        line = "element(by.xpath('" + action.locator.value + "')).click();";
      }

      if(action.action == 'click' && action.locator.type == 'id') {
        line = "element(by.id('" + action.locator.value + "')).click();";
      }

      if(action.action == 'click' && action.locator.type == 'css') {
        line = "element(by.css('" + action.locator.value + "')).click();";
      }

      if(action.action == 'assertion' && action.locator.type == 'bind')
        line = "expect(element(by.binding('" + action.locator.value + "')).getText()).toBe('" + action.value + "');";

      if(action.action == 'assertion' && action.locator.type == 'id')
        line = "expect(element(by.id('" + action.locator.value + "')).getText()).toBe('" + action.value + "');";

      if(action.action == 'assertion' && action.locator.type == 'xpath')
        line = "expect(element(by.xpath('" + action.locator.value + "')).getText()).toBe('" + action.value + "');";

      if(action.action == 'assertion' && action.locator.type == 'css')
        line = "expect(element(by.css('" + action.locator.value + "')).getText()).toBe('" + action.value + "');";

      return line;
    };

    vm.runFromHere = function(index) {

      vm.index = index;
      var element = vm.getElementAction(vm.spec.actions[index]);
      vm.getSessionElementId(element);

    };

    vm.setActionLocator = function(action){
      $log.debug(action);
    };

    vm.getAttr = function (attr, elem) {
      if (elem.attr(attr))
        return elem.attr(attr);
      return false;
    };

    vm.createSession = function () {

      if(!vm.session.id) {

        vm.isLoadingSession = true;

        $http({
          method: 'POST',
          url: 'http://localhost:4444/wd/hub/session',
          data: {'desiredCapabilities': {'browserName': 'chrome'}}
        }).then(function successCallback(response) {

          $log.debug('Session Created');

          vm.session.id = response.data.sessionId;

          vm.conf.isRecording = true;

          vm.setSessionUrl();

        });
      } else {
        vm.conf.isRecording = true;
      }
    };

    vm.getSession = function () {

      $http({
        method: 'GET',
        url: 'http://localhost:4444/wd/hub/sessions'
      }).then(function successCallback(response) {

        $log.debug('Get Session');

        if (response.data.value.length) {
          vm.session = response.data.value[0];

          vm.getSessionSource();
        }

      });

    };

    vm.setSessionUrl = function () {

      $http({
        method: 'POST',
        url: 'http://localhost:4444/wd/hub/session/' + vm.session.id + '/url',
        data: {'url': vm.url}
      }).then(function successCallback() {

        $log.debug('setSessionUrl');

        vm.getSessionUrl();
        vm.getSessionSource();

      });

    };

    vm.getSessionUrl = function () {

      $http({
        method: 'GET',
        url: 'http://localhost:4444/wd/hub/session/' + vm.session.id + '/url'
      }).then(function successCallback(response) {

        $log.debug('getSessionUrl');

        vm.session.url = response.data.value;

      });

    };

    $scope.$watch('main.conf', function () {
      $log.debug('watch conf');
      localStorage.setItem('conf', angular.toJson(vm.conf));
    }, true);

    $scope.$watch('main.describe', function () {
      $log.debug('watch describe');
      localStorage.setItem('describes', angular.toJson(vm.describes));

      vm.selectedItems = $filter('filter')(vm.spec.actions, {checked: true}).length;

      if(vm.selectedItems){
        vm.showSelectedOptions = true
      } else {
        vm.showSelectedOptions = false;
      }

    }, true);

    $scope.$watchCollection('main.describes', function () {
      $log.debug('watch describes');
      localStorage.setItem('describes', angular.toJson(vm.describes));
    });

    $scope.$watch('main.url', function (newVal) {
      $log.debug('watch Url');

      if(newVal.match(/^https/)){

        $mdToast.show(
            $mdToast.simple()
                .content('Do not use https on Base Url!')
                .position('bottom left')
                .hideDelay(3000)
        );

        vm.url = '';

      } else {

        localStorage.setItem('url', vm.url);
      }

    });

    vm.toggleAll = function(){

      angular.forEach(vm.spec.actions, function(action){

        action.checked = !vm.selectAll;

      });

      if(vm.selectAll)
        vm.showSelectedOptions = false;

    };

    vm.toggleAction = function(action){
      if(!action.checked){
        //vm.showSelectedOptions = true;
      }
    };

    vm.removeActions = function(index){

      if(index){
        vm.spec.actions.splice(index, 1);
      } else {
        var i = vm.spec.actions.length;
        while (i--) {
          var action = vm.spec.actions[i];
          if (action.checked)
            vm.spec.actions.splice(i, 1);
        }
      }
    };

    vm.duplicateActions = function(index){

      if(index){
        var newAction = angular.copy(vm.spec.actions[index]);
        vm.spec.actions.push(newAction);
      }
    };

    vm.sessionExecute = function () {

      $http({
        method: 'POST',
        url: 'http://localhost:4444/wd/hub/session/' + vm.session.id + '/execute',
        data: {'script': vm.snippet, 'args': [{'f': ''}]}
      }).then(function successCallback() {

        $log.debug('Session Executed');

        vm.isLoadingSession = false;
        vm.isSnippet = true;

        vm.getSessionUrl();

        $mdToast.show(
            $mdToast.simple()
                .content('Session ready to record!')
                .position('bottom left')
                .hideDelay(3000)
        );

      });

    };

    vm.getSessionSource = function () {

      if (vm.session.id) {
        $http({
          method: 'GET',
          url: 'http://localhost:4444/wd/hub/session/' + vm.session.id + '/source'
        }).then(function successCallback(response) {

          vm.session.source = response.data.value;

          if(response.data.value) {
            vm.getNgIncludes();
            vm.verifySnippet();
          }

        }, function errorCallback(response) {
          $log.debug(response);
          $log.debug('Error session source');
          vm.deleteSession();

        });
      } else {
        vm.isLoadingSession = false;
        vm.conf.isRecording = false;
      }

    };

    /**
     * Get all html from ng-includes and concatenate with main source
     */
    vm.getNgIncludes = function () {

      $log.debug('getNgIncludes');

      var ngIncludes = vm.session.source.match(/ngInclude:\s?["|'](.*?)["|']/igm);

      $log.debug(ngIncludes);

      var includes = [];

      angular.forEach(ngIncludes, function (include) {

        include = include.replace(/:\s|\"|\'|ngInclude|{{|}}/g, '').trim();

        if (!$filter('filter')(includes, include).length) {

          $http({
            method: 'POST',
            url: 'http://localhost:9000/html',
            data: {url: vm.url, include: include}
          }).then(function successCallback(response) {

            vm.session.source += response.data;
            vm.getAllDataBind();

          });
        }
        includes.push(include);
      });
    };

    vm.verifySnippet = function(){

      if (!vm.isSnippet && !vm.session.source.match(/recorder-iframe/)) {
        vm.sessionExecute();
      } else {
        vm.isLoadingSession = false;
      }
    };

    vm.deleteSession = function(){

      $http({
        method: 'DELETE',
        url: 'http://localhost:4444/wd/hub/session/' + vm.session.id
      }).then(function successCallback(response) {

        $log.debug('Session Deleted');
        $log.debug(response);

        vm.session = {};

        vm.isLoadingSession = false;
        vm.conf.isRecording = false;

      });

    };

    vm.getCapabilities = function(){
<commit_msg>Fix #12 - Verify iframe snippet presence<commit_after>(function () {
  'use strict';

  angular
      .module('protractorRec')
      .controller('MainController', MainController);

  /** @ngInject */
  function MainController($scope, $http, $log, $filter, $timeout, $mdToast, $location, $mdDialog, socket) {

    var vm = this;

    /*-------------------------------------------------------------------
     * 		 				 	ATTRIBUTES
     *-------------------------------------------------------------------*/

    vm.isLoadingSession    = false;
    vm.showConf            = $location.path() == '/conf' ? true : false;
    vm.isSnippet           = false;
    vm.showSelectedOptions = false;
    vm.index = false;

    /* If first run set examples or get from local storage */
    vm.url       = localStorage.getItem('url') ? localStorage.getItem('url') : 'http://www.protractortest.org';
    vm.describes = localStorage.getItem('describes') ? angular.fromJson(localStorage.getItem('describes')) : [];
    vm.conf      = localStorage.getItem('conf') ? angular.fromJson(localStorage.getItem('conf')) : false;

    /* Javascript snippet to inject on session */
    vm.snippet = 'var b=document.getElementsByTagName("body")[0];' +
        'var i = document.createElement("iframe");' +
        'i.id="recorder-iframe";' +
        'i.setAttribute("style", "display:none");' +
        'b.appendChild(i);' +
        'var i = document.getElementById("recorder-iframe");' +
        'var s = i.contentWindow.document.createElement("script");' +
        's.src = "http://localhost:9000/socket.io-1.3.7.js";' +
        'i.contentWindow.document.body.appendChild(s);' +
        'var s = i.contentWindow.document.createElement("script");' +
        's.src = "http://localhost:9000/snippet.js";' +
        'i.contentWindow.document.body.appendChild(s);';

    vm.session       = {};
    vm.lines         = [];
    vm.describe      = {};
    vm.spec          = [];
    vm.dataBind      = [];
    vm.capabilities  = [];
    vm.selectedItems = 0;

    /* Configuration example */
    if(!vm.conf) {
      vm.conf = {
        isRecording: false,
        string: 'Conf.js',
        seleniumAddress: 'http://localhost:4444/wd/hub',
        capabilities: ['chromedriver'],
        spec: {
          actions: [
            {"type": "link", "value": vm.url, "action": "get"}
          ]
        }

      };
    }

    /* Spec example */
    vm.sample = {
      string: 'Describe Protractor Example',
      specs: [
        {
          string: 'Should navigate to protractortest.org',
          actions: [
            {"type": "link", "value": "http://www.protractortest.org", "action": "get"}
          ]
        }
      ]
    };

    /* Base options for new spec */
    vm.blankSpec = {
      string: '',
      actions: []
    };

    vm.hidden = false;
    vm.isOpen = false;
    vm.hover = false;

    // On opening, add a delayed property which shows tooltips after the speed dial has opened
    // so that they have the proper position; if closing, immediately hide the tooltips
    $scope.$watch('main.isOpen', function (isOpen) {
      if (isOpen) {
        $timeout(function () {
          vm.tooltipVisible = vm.isOpen;
        }, 600);
      } else {
        vm.tooltipVisible = vm.isOpen;
      }
    });

    /*-------------------------------------------------------------------
     * 		 				  SOCKET ON
     *-------------------------------------------------------------------*/
    /**
     * Messages: onsnippet, click, change, keyup, assertion, session-disconnect, protractor-log
     */

    socket.on('onsnippet', function(data){
       vm.isSnippet = true;
    });

    socket.on('click', function (data) {
      $log.debug('onclick');
      $log.debug(data);

      vm.setElement(data);

    });

    socket.on('change', function (data) {
      $log.debug('onchange');
      $log.debug(data);

      vm.setElement(data);

    });

    socket.on('keyup', function (data) {
      $log.debug('onkeyup');
      $log.debug(data);

      if(vm.conf.isRecording) {
        var lastAction = vm.spec.actions[vm.spec.actions.length - 1];
        lastAction.action = 'sendKeys';
        lastAction.value = data;
      }

    });

    socket.on('assertion', function (data) {
      $log.debug('onassertion');
      $log.debug(data);

      if(vm.conf.isRecording) {
        var lastAction = vm.spec.actions[vm.spec.actions.length - 1];

        lastAction.action = 'assertion';
        lastAction.value = data;

        vm.dataBind.forEach(function (data) {

          lastAction.locators.push(data);

        });
      }

    });

    socket.on('session-disconnect', function (data) {

      vm.isSnippet = false;
      vm.isLoadingSession = true;

      $log.debug('on-session-disconnect');
      $log.debug(data);

      vm.getSessionSource();

    });

    socket.on('protractor-log', function (data) {
      $log.debug('protractor-log');
      $log.debug(data);
    });

    vm.setCapabilities = function(capability) {
      if(capability.checked){
        vm.conf.capabilities.push(capability.driver);
      } else {
        var index = vm.conf.capabilities.indexOf(capability.driver);
        vm.conf.capabilities.splice(index, 1);
      }
    };

    vm.openConf = function() {
      vm.showConf = true;
      vm.setSpec(vm.conf.spec, vm.showConf);
    };

    vm.setExample = function () {

      if (!vm.describes.length) {

        vm.describes.push(angular.copy(vm.sample));

        vm.setDescribe(vm.describes[0]);
        vm.setSpec(vm.describe.specs[0]);

        vm.createSession();
      } else {
        vm.setDescribe(vm.describes[0]);
        vm.setSpec(vm.describe.specs[0]);
      }

    };

    vm.newDescribe = function () {
      $log.debug('newDescribe');

    };

    vm.addSpec = function () {
      $log.debug('addSpec');

      vm.describe.specs.push(angular.copy(vm.blankSpec));
      vm.setSpec(vm.describe.specs[vm.describe.specs.length - 1]);
    };

    vm.setDescribe = function (describe) {
      vm.describe = describe;
    };

    vm.setSpec = function (spec, conf) {
      $log.debug('setSpec');
      if(vm.showConf && conf == undefined || conf == true) {
        vm.showConf = true;
        vm.spec = vm.conf.spec;
        $location.path('/conf');
      } else {
        vm.spec = spec;
        vm.showConf = false;
        $location.path('/');
      }

      angular.forEach(vm.spec.actions, function(action) {
        action.checked = false;
      });
    };

    vm.setElementOnChange = function (element) {

      if (vm.conf.isRecording) {

        var target = angular.element(element.outerHTML);

        if (target[0].tagName.match(/^select/i) && element.value) {

          vm.addElement(target, 'select', 'click', element.value, element.xPath);
        }
      }
    };

    vm.setElement = function (element) {

      if(vm.conf.isRecording) {
        var target = angular.element(element.outerHTML);
        var parent = !element.offsetParent.outerHTML ? [] : angular.element(element.offsetParent.outerHTML);

        var value = '';

        if (target[0].tagName.match(/^button/i) || (parent[0].tagName && parent[0].tagName.match(/^button/i)) && !target[0].tagName.match(/^input/i)) {

          vm.addElement(parent, 'button', 'click', target.text().trim(), element.xPath);

        } else if (target[0].tagName.match(/^input/i)) {
          vm.addElement(target, 'input', 'click', false, element.xPath);
        } else if (target[0].tagName.match(/^a/i)) {
          vm.addElement(target, 'a', 'click', target.text().trim(), element.xPath);
        } else if (element.ngRepeat) {

          value = target.text() ? target.text() : false

          //if(value)
          vm.addElement(target, target[0].tagName.toLowerCase(), 'wait', value, element.xPath);

          vm.addElement(target, 'row', 'click', element.ngRepeat.rowIndex, element.xPath, element.ngRepeat.value);

          vm.addElement(target, target[0].tagName.toLowerCase(), 'click', value, element.xPath);

        } else {
          value = target.text() ? target.text() : false;
          vm.addElement(target, target[0].tagName.toLowerCase(), 'click', value, element.xPath);
        }
      }
    };

    vm.addElement = function (element, type, actionType, value, xPath, repeater) {

      var locators = [];

      if(type == 'select' && vm.getAttr('ng-model', element))
        locators.push({type: 'model', value: vm.getAttr('ng-model', element)});

      if(type == 'row')
        locators.push({type: 'repeater', value: repeater});

      if (type == 'button' && value)
        locators.push({type: 'buttonText', value: value});

      if (type == 'input' && vm.getAttr('ng-model', element))
        locators.push({type: 'model', value: vm.getAttr('ng-model', element)});

      if (type == 'input' && vm.getAttr('name', element))
        locators.push({type: 'css', value: '[name="' + vm.getAttr('name', element) + '"]'});

      /*if (type == 'input' && vm.getAttr('type', element) == 'button') {
        locators.push({type: 'id', value: vm.getAttr('id', element)});
      }*/

      if (type == 'input' && vm.getAttr('type', element) == 'submit') {
        locators.push({type: 'css', value: '[value="' + element.val() + '"]'});
      }

      if (vm.getAttr('href', element)) {
        locators.push({type: 'linkText', value: value});
        locators.push({type: 'get', value: vm.getAttr('href', element)});
      }

      if (vm.getAttr('id', element))
        locators.push({type: 'id', value: vm.getAttr('id', element)});

      if (vm.getAttr('class', element) || actionType == 'wait') {

        if (value)
          locators.push({type: 'xpath', value: '//' + type + '[.="' + value + '"]'});
        if (xPath && !vm.getAttr('ng-click', element) && !vm.getAttr('class', element))
          locators.push({type: 'xpath', value: xPath});
        if (vm.getAttr('ng-click', element)) {
          //element(by.css("[ng-click='changeToRemove(row.entity)']")).click();
          locators.push({type: 'css', value: '[ng-click="' + vm.getAttr('ng-click', element) + '"]'})
        }

        if(vm.getAttr('class', element)) {
          locators.push({type: 'css', value: '.' + vm.getAttr('class', element).replace(/\s/g, '.')});
        }

        if (xPath)
          locators.push({type: 'xpath', value: xPath});
      }

      var action = {
        //element: element.html(),
        type: type,
        value: value,
        action: actionType,
        locators: locators,
        locator: locators ? {type: locators[0].type, value: locators[0].value} : null
      };

      vm.spec.actions.push(action);

      var mainContent = angular.element( document.querySelector('#main') );
      mainContent[0].scrollTop = mainContent[0].scrollHeight;

      vm.getSessionUrl();

      //localStorage.setItem('actions', angular.toJson(vm.actions));

      //vm.getSessionUrl();

    };

    /**
     * Get all data bind to suggest on assertions
     */
    vm.getAllDataBind = function () {

      $log.debug('getAllDataBind');

      var dataBind = vm.session.source.match(/\{{2}(.*?)\}{2}|ng-bind=["|'](.*?)["|']/igm);

      angular.forEach(dataBind, function (data) {

        data = data.replace(/\"|\'|ng-bind=|{{|}}/g, '').trim();

        if (!$filter('filter')(vm.dataBind, data).length) {

          vm.dataBind.push({type: 'bind', value: data});

        }

      });

      $log.debug(dataBind);
      $log.debug(vm.dataBind);

    };

    vm.runTest = function () {

      $log.debug('runTest');

      $http({
        method: 'GET',
        url: 'http://localhost:9000/run'
      }).then(function successCallback(response) {

        $log.debug('Test finished');
        $log.debug(response);

      });
    };

    vm.removeSpec = function (index) {
      vm.describe.specs.splice(index, 1);
    };

    vm.exportProtractor = function () {

      $log.debug('exportProtractor');

      /* Get line export to actions in conf.js */
      vm.conf.spec.lines = [];

      angular.forEach(vm.conf.spec.actions, function (action) {

        vm.conf.spec.lines.push(vm.getLine(action));

      });

      /* Get line exported to actions in spec.js */
      vm.spec.lines = [];

      if($filter('filter')(vm.spec.actions, {action: 'wait'}).length != 0)
        vm.spec.lines.push('var EC = protractor.ExpectedConditions;');

      angular.forEach(vm.spec.actions, function (action) {

        vm.spec.lines.push(vm.getLine(action));

      });

      $http({
        method: 'POST',
        url: 'http://localhost:9000/export',
        data: {baseUrl: vm.url, conf: angular.toJson(vm.conf), describe: angular.toJson(vm.describes)}
      }).then(function successCallback(response) {

        $log.debug('Exported');
        $log.debug(response);

        $mdToast.show(
            $mdToast.simple()
                .content('File exported!')
                .position('bottom left')
                .hideDelay(3000)
        );

      });

    };

    vm.getLine = function(action) {

      var line = '';

      if(action.action == 'wait'){

        var elm = '';

        if(action.locator.type == 'xpath')
          elm = "element(by.xpath('" + action.locator.value + "'))";

        if(action.locator.type == 'css')
          elm = "element(by.css('" + action.locator.value + "');";

        line = "browser.wait(EC.presenceOf(" + elm + "), 10000);";

      }

      if(action.type == 'select' && action.action == 'click' && action.locator.type == 'model')
        line = "element(by.model('" + action.locator.value + "')).$('[value=\"" + action.value + "\"]').click();";

      if(action.action == 'click' && action.locator.type == 'repeater')
        line = "element(by.repeater('" + action.locator.value + "').row(" + action.value + ")).";

      if(action.action == 'sendKeys' && action.locator.type == 'model') {
        line = "element(by.model('" + action.locator.value + "')).sendKeys('" + action.value + "');";
      }

      if(action.action == 'sendKeys' && action.locator.type == 'css') {
        line = "element(by.css('" + action.locator.value + "')).sendKeys('" + action.value + "');";
      }

      if(action.action == 'click' && action.type == 'button' && action.value) {
        line = "element(by.buttonText('" + action.value + "')).click();";
      }

      if(action.action == 'click' && action.type == 'a' && action.locator.type == 'linkText') {
        line = "element(by.linkText('" + action.value + "')).click();";
      }

      if(action.action == 'click' && action.type == 'a' && action.locator.type == 'get') {
        line = "browser.get('" + action.locator.value + "');";
      }

      if(action.action == 'click' && action.locator.type == 'xpath') {
        line = "element(by.xpath('" + action.locator.value + "')).click();";
      }

      if(action.action == 'click' && action.locator.type == 'id') {
        line = "element(by.id('" + action.locator.value + "')).click();";
      }

      if(action.action == 'click' && action.locator.type == 'css') {
        line = "element(by.css('" + action.locator.value + "')).click();";
      }

      if(action.action == 'assertion' && action.locator.type == 'bind')
        line = "expect(element(by.binding('" + action.locator.value + "')).getText()).toBe('" + action.value + "');";

      if(action.action == 'assertion' && action.locator.type == 'id')
        line = "expect(element(by.id('" + action.locator.value + "')).getText()).toBe('" + action.value + "');";

      if(action.action == 'assertion' && action.locator.type == 'xpath')
        line = "expect(element(by.xpath('" + action.locator.value + "')).getText()).toBe('" + action.value + "');";

      if(action.action == 'assertion' && action.locator.type == 'css')
        line = "expect(element(by.css('" + action.locator.value + "')).getText()).toBe('" + action.value + "');";

      return line;
    };

    vm.runFromHere = function(index) {

      vm.index = index;
      var element = vm.getElementAction(vm.spec.actions[index]);
      vm.getSessionElementId(element);

    };

    vm.setActionLocator = function(action){
      $log.debug(action);
    };

    vm.getAttr = function (attr, elem) {
      if (elem.attr(attr))
        return elem.attr(attr);
      return false;
    };

    vm.createSession = function () {

      if(!vm.session.id) {

        vm.isLoadingSession = true;

        $http({
          method: 'POST',
          url: 'http://localhost:4444/wd/hub/session',
          data: {'desiredCapabilities': {'browserName': 'chrome'}}
        }).then(function successCallback(response) {

          $log.debug('Session Created');

          vm.session.id = response.data.sessionId;

          vm.conf.isRecording = true;

          vm.setSessionUrl();

        });
      } else {
        vm.conf.isRecording = true;
      }
    };

    vm.getSession = function () {

      $http({
        method: 'GET',
        url: 'http://localhost:4444/wd/hub/sessions'
      }).then(function successCallback(response) {

        $log.debug('Get Session');

        if (response.data.value.length) {
          vm.session = response.data.value[0];

          vm.getSessionSource();
        }

      });

    };

    vm.setSessionUrl = function () {

      $http({
        method: 'POST',
        url: 'http://localhost:4444/wd/hub/session/' + vm.session.id + '/url',
        data: {'url': vm.url}
      }).then(function successCallback() {

        $log.debug('setSessionUrl');

        vm.getSessionUrl();
        vm.getSessionSource();

      });

    };

    vm.getSessionUrl = function () {

      $http({
        method: 'GET',
        url: 'http://localhost:4444/wd/hub/session/' + vm.session.id + '/url'
      }).then(function successCallback(response) {

        $log.debug('getSessionUrl');

        vm.session.url = response.data.value;

      });

    };

    $scope.$watch('main.conf', function () {
      $log.debug('watch conf');
      localStorage.setItem('conf', angular.toJson(vm.conf));
    }, true);

    $scope.$watch('main.describe', function () {
      $log.debug('watch describe');
      localStorage.setItem('describes', angular.toJson(vm.describes));

      vm.selectedItems = $filter('filter')(vm.spec.actions, {checked: true}).length;

      if(vm.selectedItems){
        vm.showSelectedOptions = true
      } else {
        vm.showSelectedOptions = false;
      }

    }, true);

    $scope.$watchCollection('main.describes', function () {
      $log.debug('watch describes');
      localStorage.setItem('describes', angular.toJson(vm.describes));
    });

    $scope.$watch('main.url', function (newVal) {
      $log.debug('watch Url');

      if(newVal.match(/^https/)){

        $mdToast.show(
            $mdToast.simple()
                .content('Do not use https on Base Url!')
                .position('bottom left')
                .hideDelay(3000)
        );

        vm.url = '';

      } else {

        localStorage.setItem('url', vm.url);
      }

    });

    vm.toggleAll = function(){

      angular.forEach(vm.spec.actions, function(action){

        action.checked = !vm.selectAll;

      });

      if(vm.selectAll)
        vm.showSelectedOptions = false;

    };

    vm.toggleAction = function(action){
      if(!action.checked){
        //vm.showSelectedOptions = true;
      }
    };

    vm.removeActions = function(index){

      if(index){
        vm.spec.actions.splice(index, 1);
      } else {
        var i = vm.spec.actions.length;
        while (i--) {
          var action = vm.spec.actions[i];
          if (action.checked)
            vm.spec.actions.splice(i, 1);
        }
      }
    };

    vm.duplicateActions = function(index){

      if(index){
        var newAction = angular.copy(vm.spec.actions[index]);
        vm.spec.actions.push(newAction);
      }
    };

    vm.sessionExecute = function () {

      $http({
        method: 'POST',
        url: 'http://localhost:4444/wd/hub/session/' + vm.session.id + '/execute',
        data: {'script': vm.snippet, 'args': [{'f': ''}]}
      }).then(function successCallback() {

        $log.debug('Session Executed');

        vm.isLoadingSession = false;
        vm.isSnippet = true;

        vm.getSessionUrl();

        $mdToast.show(
            $mdToast.simple()
                .content('Session ready to record!')
                .position('bottom left')
                .hideDelay(3000)
        );

      });

    };

    vm.getSessionSource = function () {

      if (vm.session.id) {
        $http({
          method: 'GET',
          url: 'http://localhost:4444/wd/hub/session/' + vm.session.id + '/source'
        }).then(function successCallback(response) {

          vm.session.source = response.data.value;

          if(response.data.value) {
            vm.getNgIncludes();
            vm.verifySnippet();
          }

        }, function errorCallback(response) {
          $log.debug(response);
          $log.debug('Error session source');
          vm.deleteSession();

        });
      } else {
        vm.isLoadingSession = false;
        vm.conf.isRecording = false;
      }

    };

    /**
     * Get all html from ng-includes and concatenate with main source
     */
    vm.getNgIncludes = function () {

      $log.debug('getNgIncludes');

      var ngIncludes = vm.session.source.match(/ngInclude:\s?["|'](.*?)["|']/igm);

      $log.debug(ngIncludes);

      var includes = [];

      angular.forEach(ngIncludes, function (include) {

        include = include.replace(/:\s|\"|\'|ngInclude|{{|}}/g, '').trim();

        if (!$filter('filter')(includes, include).length) {

          $http({
            method: 'POST',
            url: 'http://localhost:9000/html',
            data: {url: vm.url, include: include}
          }).then(function successCallback(response) {

            vm.session.source += response.data;
            vm.getAllDataBind();

          });
        }
        includes.push(include);
      });
    };

    vm.verifySnippet = function(){

      var countIframe = vm.session.source.match(/recorder-iframe/);
      countIframe != null ? countIframe.length : countIframe = 0;

      if (!vm.isSnippet && countIframe == 0) {
        vm.sessionExecute();
      } else {
        vm.isLoadingSession = false;
      }
    };

    vm.deleteSession = function(){

      $http({
        method: 'DELETE',
        url: 'http://localhost:4444/wd/hub/session/' + vm.session.id
      }).then(function successCallback(response) {

        $log.debug('Session Deleted');
        $log.debug(response);

        vm.session = {};

        vm.isLoadingSession = false;
        vm.conf.isRecording = false;

      });

    };

    vm.getCapabilities = function(){

{'fraction_non_alphanumeric': 0.1926646045072912, 'fraction_numerical': 0.004772425983208131, 'mean_word_length': 2.1248964374482187, 'pattern_counts': {'":': 12, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 4, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '948715', 'n_tokens_mistral': 14607, 'n_tokens_neox': 13957, 'n_words': 2338}