<commit_before>
window.Talkfunnel = {};

if (Modernizr.localstorage) {
    window.Talkfunnel.Store = {};

    //Local storage can only save strings, so value is converted into strings and stored.
    window.Talkfunnel.Store.add = function(key, value) {
        return localStorage.setItem(key, JSON.stringify(value));
    };

    //Reads from LocalStorage.
    window.Talkfunnel.Store.read = function(key) {
        return JSON.parse(localStorage.getItem(key));
    };

    window.Talkfunnel.Queue = function(queueName) {
        this.queueName = queueName;

        //Adds a participant_id to queue
        this.enqueue = function(participant_id) {
            var participantList = window.Talkfunnel.Store.read(this.queueName) || [];
            if(participantList.indexOf(participant_id) === -1) {
                participantList.push(participant_id);
                return window.Talkfunnel.Store.add(this.queueName, participantList);
            }
        };

        //Reads and returns all items from queue
        //Returns undefined when queue is empty or not defined
        this.readAll = function() {
            var participantList = window.Talkfunnel.Store.read(this.queueName);
            if(participantList && participantList.length) {
                return participantList;
            }
        };

        //Removes item from queue and returns true
        //Returns undefined when item not present in queue
        this.dequeue = function(participant_id) {
            var participantList = window.Talkfunnel.Store.read(this.queueName);
            var index = participantList ? participantList.indexOf(participant_id) : -1;
            if(index !== -1) {
                //Remove item from queue and add updated queue to localStorage
                participantList.splice(index, 1);
                window.Talkfunnel.Store.add(this.queueName, participantList);
                return participant_id;
            }
        };
    }
}

function radioHighlight(radioName, highlightClass) {
    var selector = "input[name='" + radioName + "']";
    $(selector + ":checked").parent().addClass(highlightClass);
    var handler = function() {
        $(selector).parent().removeClass(highlightClass);
        $(selector + ":checked").parent().addClass(highlightClass);
    };
    $(selector).change(handler);
    $(selector).click(handler);
}

function commentsInit(pageURL) {
    $(".comments .collapse").click(function() {
        $(this).addClass('hidden');
        $(this).parent().find('.uncollapse').removeClass('hidden');
        $(this).parent().parent().find('.com-body').slideUp("fast");
        $(this).parent().parent().parent().find('.com-children').slideUp("fast");
        return false;
    });

    $(".comments .uncollapse").click(function() {
        $(this).addClass('hidden');
        $(this).parent().find('.collapse').removeClass('hidden');
        $(this).parent().parent().find('.com-body').slideDown("fast");
        $(this).parent().parent().parent().find('.com-children').slideDown("fast");
        return false;
    });

    $(".comments .comment-reply").click(function() {
        var cfooter = $(this).parent();
        $('#newcomment input[name="parent_id"]').val(cfooter.attr('data-id'));
        $('#newcomment input[name="comment_edit_id"]').val('');
        $("#toplevel-comment").removeClass('hidden');
        $("#comment-submit").val("Reply"); // i18n gotcha
        cfooter.after($("#newcomment"));
        $("#newcomment textarea").focus();
        return false;
    });

    $("#toplevel-comment a").click(function() {
        $('#newcomment input[name="parent_id"]').val('');
        $('#newcomment input[name="comment_edit_id"]').val('');
        $("#comment-submit").val("Post comment"); // i18n gotcha
        $(this).parent().after($("#newcomment"));
        $(this).parent().addClass('hidden');
        $("#newcomment textarea").focus();
        return false;
    });

    $(".comments .comment-delete").click(function() {
        var cfooter = $(this).parent();
        $('#delcomment input[name="comment_id"]').val(cfooter.attr('data-id'));
        $("#delcomment").removeClass('hidden').hide().insertAfter(cfooter).slideDown("fast");
        return false;
    });

    $("#comment-delete-cancel").click(function() {
        $("#delcomment").slideUp("fast");
        return false;
    });

    $(".comments .comment-edit").click(function() {
        var cfooter = $(this).parent();
        var cid = cfooter.attr('data-id');
        $("#newcomment textarea").val("Loading..."); // i18n gotcha
        $.getJSON(pageURL+'/comments/'+cid+'/json', function(data) {
            $("#newcomment textarea").val(data.message);
            });
        $('#newcomment input[name="parent_id"]').val('');
        $('#newcomment input[name="comment_edit_id"]').val(cid);
        $("#toplevel-comment").removeClass('hidden');
        $("#comment-submit").val("Save changes"); // i18n gotcha
        cfooter.after($("#newcomment"));
        $("#newcomment textarea").focus();
        return false;
    });
}

// ROT13 link handler
$(function() {
  $("a.rot13").each(function() {
    if ($(this).attr('data-href')) {
      var decoded = $(this).attr('data-href').replace(/[a-zA-Z]/g, function(c) {
        return String.fromCharCode((c<="Z"?90:122)>=(c=c.charCodeAt(0)+13)?c:c-26);
        });
      $(this).attr('href', decoded);
      $(this).removeAttr('data-href');
      $(this).removeClass('rot13');
    }
  });
});

window.TableSearch = function(tableId){
  // a little library that takes a table id
  // and provides a method to search the table's rows for a given query.
  // the row's td must contain the class 'js-searchable' to be considered
  // for searching.
  // Eg:
  // var tableSearch = new TableSearch('tableId');
  // var hits = tableSearch.searchRows('someQuery');
  // 'hits' is a list of ids of the table's rows which contained 'someQuery'
  this.tableId = tableId;
  this.rowData = [];
  this.allMatchedIds = [];
};

window.TableSearch.prototype.getRows = function(){
  return $('#' + this.tableId +' tbody tr');
};

window.TableSearch.prototype.setRowData = function(rowD){
  // Builds a list of objects and sets it the object's rowData
  var rowMap = [];
  $.each(this.getRows(), function(rowIndex, row){
    rowMap.push({
      'rid': '#' + $(row).attr('id'),
      'text': $(row).find('td.js-searchable').text().toLowerCase()
    });
  });
  this.rowData = rowMap;
};

window.TableSearch.prototype.setAllMatchedIds = function(ids) {
  this.allMatchedIds = ids;
};

window.TableSearch.prototype.searchRows = function(q){
  // Search the rows of the table for a supplied query.
  // reset data collection on first search or if table has changed
  if (this.rowData.length !== this.getRows().length) {
    this.setRowData();
  }
  // return cached matched ids if query is blank
  if (q === '' && this.allMatchedIds.length !== 0) {
    return this.allMatchedIds;
  }
  var matchedIds = [];
  for (var i = this.rowData.length - 1; i >= 0; i--) {
    if (this.rowData[i].text.indexOf(q.toLowerCase()) !== -1) {
      matchedIds.push(this.rowData[i]['rid']);
    }
  }
  // cache ids if query is blank
  if (q === '') {
    this.setAllMatchedIds(matchedIds);
  }
  return matchedIds;
};

//convert array of objects into hashmap
function tohashMap(objectArray, key) {
    var hashMap = {};
    objectArray.forEach(function(obj) {
        hashMap[obj[key]] = obj;
    });
    return hashMap;
}
<commit_msg>fixed indent<commit_after>
window.Talkfunnel = {};

if (Modernizr.localstorage) {
  window.Talkfunnel.Store = {};

  //Local storage can only save strings, so value is converted into strings and stored.
  window.Talkfunnel.Store.add = function(key, value) {
    return localStorage.setItem(key, JSON.stringify(value));
  };

  //Reads from LocalStorage.
  window.Talkfunnel.Store.read = function(key) {
    return JSON.parse(localStorage.getItem(key));
  };

  window.Talkfunnel.Queue = function(queueName) {
    this.queueName = queueName;

    //Adds a participant_id to queue
    this.enqueue = function(participant_id) {
      var participantList = window.Talkfunnel.Store.read(this.queueName) || [];
      if(participantList.indexOf(participant_id) === -1) {
        participantList.push(participant_id);
        return window.Talkfunnel.Store.add(this.queueName, participantList);
      }
    };

    //Reads and returns all items from queue
    //Returns undefined when queue is empty or not defined
    this.readAll = function() {
      var participantList = window.Talkfunnel.Store.read(this.queueName);
      if(participantList && participantList.length) {
        return participantList;
      }
    };

    //Removes item from queue and returns true
    //Returns undefined when item not present in queue
    this.dequeue = function(participant_id) {
      var participantList = window.Talkfunnel.Store.read(this.queueName);
      var index = participantList ? participantList.indexOf(participant_id) : -1;
      if(index !== -1) {
        //Remove item from queue and add updated queue to localStorage
        participantList.splice(index, 1);
        window.Talkfunnel.Store.add(this.queueName, participantList);
        return participant_id;
      }
    };
  }
}

function radioHighlight(radioName, highlightClass) {
  var selector = "input[name='" + radioName + "']";
  $(selector + ":checked").parent().addClass(highlightClass);
  var handler = function() {
    $(selector).parent().removeClass(highlightClass);
    $(selector + ":checked").parent().addClass(highlightClass);
  };
  $(selector).change(handler);
  $(selector).click(handler);
}

function commentsInit(pageURL) {
  $(".comments .collapse").click(function() {
    $(this).addClass('hidden');
    $(this).parent().find('.uncollapse').removeClass('hidden');
    $(this).parent().parent().find('.com-body').slideUp("fast");
    $(this).parent().parent().parent().find('.com-children').slideUp("fast");
    return false;
  });

  $(".comments .uncollapse").click(function() {
    $(this).addClass('hidden');
    $(this).parent().find('.collapse').removeClass('hidden');
    $(this).parent().parent().find('.com-body').slideDown("fast");
    $(this).parent().parent().parent().find('.com-children').slideDown("fast");
    return false;
  });

  $(".comments .comment-reply").click(function() {
    var cfooter = $(this).parent();
    $('#newcomment input[name="parent_id"]').val(cfooter.attr('data-id'));
    $('#newcomment input[name="comment_edit_id"]').val('');
    $("#toplevel-comment").removeClass('hidden');
    $("#comment-submit").val("Reply"); // i18n gotcha
    cfooter.after($("#newcomment"));
    $("#newcomment textarea").focus();
    return false;
  });

  $("#toplevel-comment a").click(function() {
    $('#newcomment input[name="parent_id"]').val('');
    $('#newcomment input[name="comment_edit_id"]').val('');
    $("#comment-submit").val("Post comment"); // i18n gotcha
    $(this).parent().after($("#newcomment"));
    $(this).parent().addClass('hidden');
    $("#newcomment textarea").focus();
    return false;
  });

  $(".comments .comment-delete").click(function() {
    var cfooter = $(this).parent();
    $('#delcomment input[name="comment_id"]').val(cfooter.attr('data-id'));
    $("#delcomment").removeClass('hidden').hide().insertAfter(cfooter).slideDown("fast");
    return false;
  });

  $("#comment-delete-cancel").click(function() {
    $("#delcomment").slideUp("fast");
    return false;
  });

  $(".comments .comment-edit").click(function() {
    var cfooter = $(this).parent();
    var cid = cfooter.attr('data-id');
    $("#newcomment textarea").val("Loading..."); // i18n gotcha
    $.getJSON(pageURL+'/comments/'+cid+'/json', function(data) {
      $("#newcomment textarea").val(data.message);
    });
    $('#newcomment input[name="parent_id"]').val('');
    $('#newcomment input[name="comment_edit_id"]').val(cid);
    $("#toplevel-comment").removeClass('hidden');
    $("#comment-submit").val("Save changes"); // i18n gotcha
    cfooter.after($("#newcomment"));
    $("#newcomment textarea").focus();
    return false;
  });
}

// ROT13 link handler
$(function() {
  $("a.rot13").each(function() {
    if ($(this).attr('data-href')) {
      var decoded = $(this).attr('data-href').replace(/[a-zA-Z]/g, function(c) {
        return String.fromCharCode((c<="Z"?90:122)>=(c=c.charCodeAt(0)+13)?c:c-26);
      });
      $(this).attr('href', decoded);
      $(this).removeAttr('data-href');
      $(this).removeClass('rot13');
    }
  });
});

window.TableSearch = function(tableId){
  // a little library that takes a table id
  // and provides a method to search the table's rows for a given query.
  // the row's td must contain the class 'js-searchable' to be considered
  // for searching.
  // Eg:
  // var tableSearch = new TableSearch('tableId');
  // var hits = tableSearch.searchRows('someQuery');
  // 'hits' is a list of ids of the table's rows which contained 'someQuery'
  this.tableId = tableId;
  this.rowData = [];
  this.allMatchedIds = [];
};

window.TableSearch.prototype.getRows = function(){
  return $('#' + this.tableId +' tbody tr');
};

window.TableSearch.prototype.setRowData = function(rowD){
  // Builds a list of objects and sets it the object's rowData
  var rowMap = [];
  $.each(this.getRows(), function(rowIndex, row){
    rowMap.push({
      'rid': '#' + $(row).attr('id'),
      'text': $(row).find('td.js-searchable').text().toLowerCase()
    });
  });
  this.rowData = rowMap;
};

window.TableSearch.prototype.setAllMatchedIds = function(ids) {
  this.allMatchedIds = ids;
};

window.TableSearch.prototype.searchRows = function(q){
  // Search the rows of the table for a supplied query.
  // reset data collection on first search or if table has changed
  if (this.rowData.length !== this.getRows().length) {
    this.setRowData();
  }
  // return cached matched ids if query is blank
  if (q === '' && this.allMatchedIds.length !== 0) {
    return this.allMatchedIds;
  }
  var matchedIds = [];
  for (var i = this.rowData.length - 1; i >= 0; i--) {
    if (this.rowData[i].text.indexOf(q.toLowerCase()) !== -1) {
      matchedIds.push(this.rowData[i]['rid']);
    }
  }
  // cache ids if query is blank
  if (q === '') {
    this.setAllMatchedIds(matchedIds);
  }
  return matchedIds;
};

//convert array of objects into hashmap
function tohashMap(objectArray, key) {
  var hashMap = {};
  objectArray.forEach(function(obj) {
    hashMap[obj[key]] = obj;
  });
  return hashMap;
}
<|endoftext|>


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

    angular
        .module('crowdsource.project.controllers')
        .controller('ProjectController', ProjectController);

    ProjectController.$inject = ['$location', '$scope', '$mdToast', 'Project', '$routeParams',
        'Upload', 'helpersService', '$timeout', '$mdDialog'];

    /**
     * @namespace ProjectController
     */
    function ProjectController($location, $scope, $mdToast, Project, $routeParams, Upload, helpersService, $timeout, $mdDialog) {
        var self = this;
        self.save = save;
        self.deleteProject = deleteProject;
        self.publish = publish;
        self.removeFile = removeFile;
        self.project = {
            "pk": null
        };
        self.upload = upload;
        self.doPrototype = doPrototype;
        self.didPrototype = false;
        self.showPrototypeDialog = showPrototypeDialog;
        self.isClicked=isClicked;
        self.isExpanded=0;
        self.deadlineisEmpty=1;
        self.timeoutisEmpty=1;
         function isClicked() {
            self.isExpanded=self.isExpanded^1;
        }
        activate();

        function activate() {
            self.project.pk = $routeParams.projectId;
            Project.retrieve(self.project.pk, 'project').then(
                function success(response) {
                    self.project = response[0];
                },
                function error(response) {
                    $mdToast.showSimple('Could not get project.');
                }
            ).finally(function () {
            });
        }

        function doPrototype() {
            self.didPrototype = true;
        }

        function publish(e){
            var fieldsFilled = self.project.price && self.project.repetition>0
                                && self.project.templates[0].template_items.length;
            if(self.project.is_prototype && !self.didPrototype && fieldsFilled) {
                if(self.project.batch_files[0]) {
                    self.num_rows = self.project.batch_files[0].number_of_rows;
                } else {
                    self.num_rows = 1;
                }
                showPrototypeDialog(e);
            } else if(fieldsFilled){
                if(self.project.batch_files.length > 0) {
                    var num_rows = self.project.batch_files[0].number_of_rows;
                } else {
                    var num_rows = 0;
                }
                var request_data = {'status': 2, 'num_rows': num_rows};
                Project.update(self.project.id, request_data, 'project').then(
                    function success(response) {
                        $location.path('/my-projects');
                    },
                    function error(response) {
                        $mdToast.showSimple('Could not update project status.');
                    }
                ).finally(function () {});
            } else {
                if(!self.project.price){
                    $mdToast.showSimple('Please enter task price ($/task).');
                }
                else if(!self.project.repetition){
                    $mdToast.showSimple('Please enter number of workers per task.');
                }
                else if(!self.project.templates[0].template_items.length){
                    $mdToast.showSimple('Please add at least one item to the template.');
                } else if(!self.didPrototype || self.num_rows) {
                    $mdToast.showSimple('Please enter the number of tasks');
                }
                return;
            }
        }
        var timeouts = {};
        var timeout;
        $scope.$watch('project.project', function (newValue, oldValue) {
            if (!angular.equals(newValue, oldValue) && self.project.id && oldValue.pk==undefined) {
                var request_data = {};
                var key = null;
                if(!angular.equals(newValue['name'], oldValue['name']) && newValue['name']){
                    request_data['name'] = newValue['name'];
                    key = 'name';
                }
                if(!angular.equals(newValue['price'], oldValue['price']) && newValue['price']){
                    request_data['price'] = newValue['price'];
                    key = 'price';
                }
                if(!angular.equals(newValue['repetition'], oldValue['repetition']) && oldValue['repetition']){
                    request_data['repetition'] = newValue['repetition'];
                    key = 'repetition';
                }
                if(!angular.equals(newValue['deadline'], oldValue['deadline']) && oldValue['deadline']){
                    request_data['deadline'] = newValue['deadline'];
                    key = 'deadline';
                    self.deadlineisEmpty=0;
                }
                if(!angular.equals(newValue['timeout'], oldValue['timeout']) && oldValue['timeout']){
                    request_data['timeout'] = newValue['timeout'];
                    key = 'timeout';

                   if (newValue['timeout']==null)
                        self.timeoutisEmpty=1;
                    else
                        self.timeoutisEmpty=0;
                }
                if (angular.equals(request_data, {})) return;
                if(timeouts[key]) $timeout.cancel(timeouts[key]);
                timeouts[key] = $timeout(function() {
		            Project.update(self.project.id, request_data, 'project').then(
                        function success(response) {

                        },
                        function error(response) {
                            $mdToast.showSimple('Could not update project data.');
                        }
                    ).finally(function () {
                    });
                }, 2048);
            }
        }, true);

        function save(){

        }

        function upload(files) {
            if (files && files.length) {
                for (var i = 0; i < files.length; i++) {
                    var file = files[i];
                    Upload.upload({
                        url: '/api/file/',
                        //fields: {'username': $scope.username},
                        file: file
                    }).progress(function (evt) {
                        var progressPercentage = parseInt(100.0 * evt.loaded / evt.total);
                        // console.log('progress: ' + progressPercentage + '% ' + evt.config.file.name);
                    }).success(function (data, status, headers, config) {
                        Project.attachFile(self.project.id, {"batch_file": data.id}).then(
                            function success(response) {
                                self.project.batch_files.push(data);
                            },
                            function error(response) {
                                $mdToast.showSimple('Could not upload file.');
                            }
                        ).finally(function () {
                        });

                    }).error(function (data, status, headers, config) {
                        $mdToast.showSimple('Error uploading spreadsheet.');
                    })
                }
            }
        }

        function deleteProject(){
            Project.deleteInstance(self.project.id).then(
                function success(response) {
                    $location.path('/my-projects');
                },
                function error(response) {
                    $mdToast.showSimple('Could not delete project.');
                }
            ).finally(function () {
            });
        }

        function removeFile(pk){
            Project.deleteFile(self.project.id, {"batch_file": pk}).then(
                function success(response) {
                    self.project.batch_files = []; // TODO in case we have multiple splice
                },
                function error(response) {
                    $mdToast.showSimple('Could not remove file.');
                }
            ).finally(function () {
            });
        }

        function showPrototypeDialog($event) {
            var parent = angular.element(document.body);
            $mdDialog.show({
                clickOutsideToClose: true,
                scope: $scope,
                preserveScope: true,
                parent: parent,
                targetEvent: $event,
                templateUrl: '/static/templates/project/prototype.html',
                locals: {
                    project: self.project,
                    num_rows: self.num_rows
                },
                controller: DialogController
            });
            function DialogController($scope, $mdDialog) {
                $scope.hide = function() {
                    $mdDialog.hide();
                };
                $scope.cancel = function() {
                    $mdDialog.cancel();
                };
            }
        }
    }
})();
<commit_msg>use defaults<commit_after>(function () {
    'use strict';

    angular
        .module('crowdsource.project.controllers')
        .controller('ProjectController', ProjectController);

    ProjectController.$inject = ['$location', '$scope', '$mdToast', 'Project', '$routeParams',
        'Upload', 'helpersService', '$timeout', '$mdDialog'];

    /**
     * @namespace ProjectController
     */
    function ProjectController($location, $scope, $mdToast, Project, $routeParams, Upload, helpersService, $timeout, $mdDialog) {
        var self = this;
        self.save = save;
        self.deleteProject = deleteProject;
        self.publish = publish;
        self.removeFile = removeFile;
        self.project = {
            "pk": null
        };
        self.upload = upload;
        self.doPrototype = doPrototype;
        self.didPrototype = false;
        self.showPrototypeDialog = showPrototypeDialog;

        activate();

        function activate() {
            var today = new Date();
            self.minDate= new Date(today.getFullYear(), today.getMonth(), today.getDate());

            self.project.pk = $routeParams.projectId;
            Project.retrieve(self.project.pk, 'project').then(
                function success(response) {
                    self.project = response[0];

                    if(self.project.deadline == null){
                        self.project.deadline = self.minDate;
                    }
                },
                function error(response) {
                    $mdToast.showSimple('Could not get project.');
                }
            ).finally(function () {
            });
        }

        function doPrototype() {
            self.didPrototype = true;
        }

        function publish(e){
            var fieldsFilled = self.project.price && self.project.repetition>0
                                && self.project.templates[0].template_items.length;
            if(self.project.is_prototype && !self.didPrototype && fieldsFilled) {
                if(self.project.batch_files[0]) {
                    self.num_rows = self.project.batch_files[0].number_of_rows;
                } else {
                    self.num_rows = 1;
                }
                showPrototypeDialog(e);
            } else if(fieldsFilled){
                if(self.project.batch_files.length > 0) {
                    var num_rows = self.project.batch_files[0].number_of_rows;
                } else {
                    var num_rows = 0;
                }
                var request_data = {'status': 2, 'num_rows': num_rows};
                Project.update(self.project.id, request_data, 'project').then(
                    function success(response) {
                        $location.path('/my-projects');
                    },
                    function error(response) {
                        $mdToast.showSimple('Could not update project status.');
                    }
                ).finally(function () {});
            } else {
                if(!self.project.price){
                    $mdToast.showSimple('Please enter task price ($/task).');
                }
                else if(!self.project.repetition){
                    $mdToast.showSimple('Please enter number of workers per task.');
                }
                else if(!self.project.templates[0].template_items.length){
                    $mdToast.showSimple('Please add at least one item to the template.');
                } else if(!self.didPrototype || self.num_rows) {
                    $mdToast.showSimple('Please enter the number of tasks');
                }
                return;
            }
        }
        var timeouts = {};
        var timeout;
        $scope.$watch('project.project', function (newValue, oldValue) {
            if (!angular.equals(newValue, oldValue) && self.project.id && oldValue.pk==undefined) {
                var request_data = {};
                var key = null;
                if(!angular.equals(newValue['name'], oldValue['name']) && newValue['name']){
                    request_data['name'] = newValue['name'];
                    key = 'name';
                }
                if(!angular.equals(newValue['price'], oldValue['price']) && newValue['price']){
                    request_data['price'] = newValue['price'];
                    key = 'price';
                }
                if(!angular.equals(newValue['repetition'], oldValue['repetition']) && oldValue['repetition']){
                    request_data['repetition'] = newValue['repetition'];
                    key = 'repetition';
                }
                if(!angular.equals(newValue['deadline'], oldValue['deadline']) && oldValue['deadline']){
                    request_data['deadline'] = newValue['deadline'];
                    key = 'deadline';
                }
                if(!angular.equals(newValue['timeout'], oldValue['timeout']) && oldValue['timeout']){
                    request_data['timeout'] = newValue['timeout'];
                    key = 'timeout';
                }
                if (angular.equals(request_data, {})) return;
                if(timeouts[key]) $timeout.cancel(timeouts[key]);
                timeouts[key] = $timeout(function() {
		            Project.update(self.project.id, request_data, 'project').then(
                        function success(response) {

                        },
                        function error(response) {
                            $mdToast.showSimple('Could not update project data.');
                        }
                    ).finally(function () {
                    });
                }, 2048);
            }
        }, true);

        function save(){

        }

        function upload(files) {
            if (files && files.length) {
                for (var i = 0; i < files.length; i++) {
                    var file = files[i];
                    Upload.upload({
                        url: '/api/file/',
                        //fields: {'username': $scope.username},
                        file: file
                    }).progress(function (evt) {
                        var progressPercentage = parseInt(100.0 * evt.loaded / evt.total);
                        // console.log('progress: ' + progressPercentage + '% ' + evt.config.file.name);
                    }).success(function (data, status, headers, config) {
                        Project.attachFile(self.project.id, {"batch_file": data.id}).then(
                            function success(response) {
                                self.project.batch_files.push(data);
                            },
                            function error(response) {
                                $mdToast.showSimple('Could not upload file.');
                            }
                        ).finally(function () {
                        });

                    }).error(function (data, status, headers, config) {
                        $mdToast.showSimple('Error uploading spreadsheet.');
                    })
                }
            }
        }

        function deleteProject(){
            Project.deleteInstance(self.project.id).then(
                function success(response) {
                    $location.path('/my-projects');
                },
                function error(response) {
                    $mdToast.showSimple('Could not delete project.');
                }
            ).finally(function () {
            });
        }

        function removeFile(pk){
            Project.deleteFile(self.project.id, {"batch_file": pk}).then(
                function success(response) {
                    self.project.batch_files = []; // TODO in case we have multiple splice
                },
                function error(response) {
                    $mdToast.showSimple('Could not remove file.');
                }
            ).finally(function () {
            });
        }

        function showPrototypeDialog($event) {
            var parent = angular.element(document.body);
            $mdDialog.show({
                clickOutsideToClose: true,
                scope: $scope,
                preserveScope: true,
                parent: parent,
                targetEvent: $event,
                templateUrl: '/static/templates/project/prototype.html',
                locals: {
                    project: self.project,
                    num_rows: self.num_rows
                },
                controller: DialogController
            });
            function DialogController($scope, $mdDialog) {
                $scope.hide = function() {
                    $mdDialog.hide();
                };
                $scope.cancel = function() {
                    $mdDialog.cancel();
                };
            }
        }
    }
})();
<|endoftext|>


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

  /**
   * Creates a balancer instance.
   *
   * Terminology:
   *
   *    master:
   *
   *       When the user begins to alter a slider, this slider is designated
   *       the master. A slider is only a master while the user is making a
   *       change.
   *
   *    subordinates:
   *
   *       When the user is altering a slider value, all of the other sliders,
   *       minus those which are disabled, are considered subordinates. The
   *       subordinates are the sliders whose values are changes to ensure
   *       that the group remains balanced.
   */
  function Balancer (options) {
    _.bindAll(this, 'onBegin', 'onChange', 'onCommit', 'onAbort');

    this.options   = _.clone(options || {});
    this.max       = this.__getMax();
    this.precision = 1;

    this.views      = [];
    this.quinns     = [];
    this.quinnOrder = [];

    this.oValues    = null;

    this.masterId     = null;
    this.subordinates = null;
  }

  // ## Class-Level Stuff ----------------------------------------------------

  // Balancer triggers Quinn-like begin, change, commit, and abort events when
  // the master slider is adjusted.
  _.extend(Balancer.prototype, Backbone.Events);

  // Holds balancer instances so that InputElements may automatically add
  // themselves to the correct balancer when initialzed.
  Balancer.balancers = {};

  // Gets the Balancer with the given name. If one does not exist, it
  // will be created with the given options.
  Balancer.get = function (name, options) {
    if (! Balancer.balancers.hasOwnProperty(name)) {
      Balancer.balancers[name] = new Balancer(options);
    }

    return Balancer.balancers[name];
  };

  // ## Instance-Level Stuff -------------------------------------------------

  /**
   * Adds a slider to be balanced. Note that `add` expects an
   * InputElementView, _not_ an InputElement.
   */
  Balancer.prototype.add = function (inputView) {
    var quinn = inputView.quinn;

    quinn.balanceId = _.uniqueId('balance_');

    quinn.bind('begin',  this.onBegin);
    quinn.bind('change', this.onChange);
    quinn.bind('commit', this.onCommit);
    quinn.bind('abort',  this.onAbort);

    this.views.push(inputView);
    this.quinns.push(inputView.quinn);
    this.quinnOrder.push(quinn.balanceId);

    this.max       = this.__getMax();
    this.precision = this.__getPrecision();

    return this;
  };

  /**
   * Triggered when the user alteres a slider; performs balancing of the
   * subordinates.
   */
  Balancer.prototype.doBalance = function (newValue, quinn) {
    var amountChanged = newValue - this.oValues.value(quinn),
        valuesBeforeBalancing, flex, sLength, slider, prevValue, i;

    // Return quickly: if the amount changed is larger than the balancer
    // allows as the change is impossible.
    if (amountChanged > this.max || amountChanged < -this.max) {
      return false;
    }

    if ((sLength = this.subordinates.length) === 0) {
      // Return quickly if all none of the subordinate sliders can be moved
      // any further.
      return false;
    }

    valuesBeforeBalancing = new OriginalValues(this.subordinates);

    // Flex is the amount of "value" which needs to be adjusted for. e.g.
    //
    //    max: 100
    //    slider 1: 0
    //    slider 2: 100
    //
    //  If slider 1 is moved to 25, the flex is -25 since in order to balance
    //  the sliders we need to subtract 25 from the subordinates.
    //
    flex = this.oValues.sumOf(this.subordinates) + newValue;
    flex = this.snapValue(this.max - flex);

    for (i = 0; i < sLength; i++) {
      // The balancer seeks to assign the full flex amount to one slider; if
      // this can't be done, it moves on to the next slider, and keeps going
      // until either all of the flex has been assigned, or we run out of
      // sliders.

      slider    = sliders[i];
      prevValue = this.oValues.value(slider);

      slider.__setValue(prevValue + flex);

      // Reduce the flex by the amount by which the slider was changed,
      // ready for the next slider.
      flex = this.snapValue(flex - (slider.value - prevValue));
    }

    if (flex !== 0) {
      valuesBeforeBalancing.revert();
      return false;
    }
  };

  /**
   * Given a float, "snaps" it to match the precision (i.e. if the smallest
   * step value of any of the balanced sliders is 0.1, it will round the
   * number to the nearest 0.1). Used heavily in doBalance to account for the
   * _vast_ number of floating point errors which occur when a group contains
   * three or more sliders.
   */
  Balancer.prototype.snapValue = function (value) {
    return parseFloat(value.toFixed(this.precision));
  };

  /**
   * Returns if the given Quinn instance is the current master slider.
   */
  Balancer.prototype.isMaster = function (quinn) {
    return (this.masterId !== null &&
            this.masterId === quinn.balanceId);
  };

  /**
   * Resetting a single slider in a group resets them all to their original
   * values.
   */
  Balancer.prototype.resetAll = function () {
    try {
      this.isDisabled = true;
      _.invoke(this.views, 'resetValue', false);
    } finally {
      this.isDisabled = false;
    }
  };

  // ## Event-Handling -------------------------------------------------------

  Balancer.prototype.onBegin = function (value, quinn) {
    if (this.isDisabled) {
      return true;
    }

    // If no slider is already being adjusted, then this is when the
    // user begins moving a slider.
    if (this.masterId === null) {
      this.masterId     = quinn.balanceId;
      this.subordinates = this.__getSubordinates();
      this.oValues      = new OriginalValues(this.quinns);

      this.__runOnSubordinates('__willChange');

      this.trigger('begin');
    }

    // Otherwise is is an onBegin event being fired when a subordinate
    // slider is being balanced; ignore it.
  };

  Balancer.prototype.onChange = function (value, quinn) {
    // Fired when a slider value is changed. We only care about changes to the
    // master slider, and subordinates are ignored.
    if (this.isMaster(quinn)) {
      if (this.doBalance(value, quinn) === false) {
        // Can't do the balance, so we prevent the slider movement.
        return false;
      }

      this.trigger('change');
    }
  };

  Balancer.prototype.onCommit = function (value, quinn) {
    if (this.isMaster(quinn)) {
      this.__sliderUsed(quinn);
      this.__finish('__hasChanged');
      this.trigger('commit');
    }
  };

  Balancer.prototype.onAbort = function (value, quinn) {
    if (this.isMaster(quinn)) {
      this.__finish('__abortChange');
      this.trigger('abort');
    }
  };

  // ## Pseudo-Private Methods -----------------------------------------------

  /**
   * Returns all the sliders except the one with which the user is
   * interacting and those which are disabled.
   */
  Balancer.prototype.__getSubordinates = function () {
    var self = this, subs;

    subs = _.select(this.quinns, function (quinn) {
      return (! self.isMaster(quinn) && ! quinn.isDisabled);
    });

    if (this.quinns.length <= 2) {
      return subs;
    }

    // The subs are now re-ordered so that the most recently used sliders are
    // at the end of the array. Otherwise doBalance is somewhat biased towards
    // the first slider.
    return _.sortBy(subs, function (quinn) {
      return _.indexOf(self.quinnOrder, quinn.balanceId);
    });
  };

  /**
   * Marks a slider as used, pushing it to the back of the quinnOrder array.
   * This prevents doBalance favouring balancing one slider over the others.
   */
  Balancer.prototype.__sliderUsed = function (quinn) {
    if (this.quinns.length <= 2) {
      return true;
    }

    var balanceId = quinn.balanceId;

    this.quinnOrder = _.without(this.quinnOrder, balanceId);
    this.quinnOrder.push(balanceId);
  };

  /**
   * Returns the maximum permitted cumulative value of the sliders which are
   * members of the group. This is cached as this.max.
   */
  Balancer.prototype.__getMax = function () {
    if (this.options.max) {
      return this.options.max;
    }

    // No explicit max, just use the total of all the sliders (no balancing).
    return _.reduce(this.quinns, function (sum, quinn) {
      return (sum + quinn.range[1]);
    }, 0) / this.quinns.length;
  };

  /**
   * Since many sliders use a fractional step value, and floating point
   * arithmetic is a nightmare, determine the number of decimal places used in
   * the smallest slider step value, so that we can do all balancing using
   * integers.
   */
  Balancer.prototype.__getPrecision = function () {
    return _.max(_.map(this.views, function (view) {
      return view.conversion.precision;
    })) || 0;
  };

  /**
   * Finishes editing slider values by resetting this.masterId and
   * this.subordinates, and calling 'method' on the subordinates.
   */
  Balancer.prototype.__finish = function (method) {
    this.__runOnSubordinates(method);

    this.masterId     = null;
    this.subordinates = null;
    this.oValues      = null;
  };

  /**
   * Runs a method on all the subordinates.
   */
  Balancer.prototype.__runOnSubordinates = function (method) {
    var subLength = this.subordinates.length, i;

    for (i = 0; i < subLength; i++) {
      this.subordinates[i][method]();
    }
  };

  // # OriginalValues --------------------------------------------------------

  /**
   * Given an array of Quinn instances, OriginalValues keeps track of the
   * value of each slider at the time the OriginalValues instance was created.
   */
  function OriginalValues (quinns) {
    var i;

    this.length = quinns.length;
    this.quinns = quinns;
    this.values = {};

    for (i = 0; i < this.length; i++) {
      this.values[quinns[i].balanceId] = quinns[i].value;
    }
  }

  /**
   * Given a Quinn instance, returns the value of that instance at the time
   * the OriginalValues was initialized.
   */
  OriginalValues.prototype.value = function (quinn) {
    return this.values[quinn.balanceId];
  };

  /**
   * Given an array of Quinns, returns the sum of their values at the time the
   * OriginalValues was initialized.
   */
  OriginalValues.prototype.sumOf = function (sliders) {
    var sLength = sliders.length, sum = 0, i;

    for (i = 0; i < sLength; i++) {
      sum += this.value(sliders[i]);
    }

    return sum;
  };

  /**
   * Reverts the Quinn instances back to their original value.
   */
  OriginalValues.prototype.revert = function () {
    var i;

    for (i = 0; i < this.length; i++) {
      this.quinns[i].__setValue(this.values[ this.quinns[i].balanceId ]);
    }
  };

  // # Globals ---------------------------------------------------------------

  window.InputElement.Balancer = Balancer;

})(window);
<commit_msg>slider balancer fix<commit_after>(function (window) {
  'use strict';

  /**
   * Creates a balancer instance.
   *
   * Terminology:
   *
   *    master:
   *
   *       When the user begins to alter a slider, this slider is designated
   *       the master. A slider is only a master while the user is making a
   *       change.
   *
   *    subordinates:
   *
   *       When the user is altering a slider value, all of the other sliders,
   *       minus those which are disabled, are considered subordinates. The
   *       subordinates are the sliders whose values are changes to ensure
   *       that the group remains balanced.
   */
  function Balancer (options) {
    _.bindAll(this, 'onBegin', 'onChange', 'onCommit', 'onAbort');

    this.options   = _.clone(options || {});
    this.max       = this.__getMax();
    this.precision = 1;

    this.views      = [];
    this.quinns     = [];
    this.quinnOrder = [];

    this.oValues    = null;

    this.masterId     = null;
    this.subordinates = null;
  }

  // ## Class-Level Stuff ----------------------------------------------------

  // Balancer triggers Quinn-like begin, change, commit, and abort events when
  // the master slider is adjusted.
  _.extend(Balancer.prototype, Backbone.Events);

  // Holds balancer instances so that InputElements may automatically add
  // themselves to the correct balancer when initialzed.
  Balancer.balancers = {};

  // Gets the Balancer with the given name. If one does not exist, it
  // will be created with the given options.
  Balancer.get = function (name, options) {
    if (! Balancer.balancers.hasOwnProperty(name)) {
      Balancer.balancers[name] = new Balancer(options);
    }

    return Balancer.balancers[name];
  };

  // ## Instance-Level Stuff -------------------------------------------------

  /**
   * Adds a slider to be balanced. Note that `add` expects an
   * InputElementView, _not_ an InputElement.
   */
  Balancer.prototype.add = function (inputView) {
    var quinn = inputView.quinn;

    quinn.balanceId = _.uniqueId('balance_');

    quinn.bind('begin',  this.onBegin);
    quinn.bind('change', this.onChange);
    quinn.bind('commit', this.onCommit);
    quinn.bind('abort',  this.onAbort);

    this.views.push(inputView);
    this.quinns.push(inputView.quinn);
    this.quinnOrder.push(quinn.balanceId);

    this.max       = this.__getMax();
    this.precision = this.__getPrecision();

    return this;
  };

  /**
   * Triggered when the user alteres a slider; performs balancing of the
   * subordinates.
   */
  Balancer.prototype.doBalance = function (newValue, quinn) {
    var amountChanged = newValue - this.oValues.value(quinn),
        valuesBeforeBalancing, flex, sLength, slider, prevValue, i;

    // Return quickly: if the amount changed is larger than the balancer
    // allows as the change is impossible.
    if (amountChanged > this.max || amountChanged < -this.max) {
      return false;
    }

    if ((sLength = this.subordinates.length) === 0) {
      // Return quickly if all none of the subordinate sliders can be moved
      // any further.
      return false;
    }

    valuesBeforeBalancing = new OriginalValues(this.subordinates);

    // Flex is the amount of "value" which needs to be adjusted for. e.g.
    //
    //    max: 100
    //    slider 1: 0
    //    slider 2: 100
    //
    //  If slider 1 is moved to 25, the flex is -25 since in order to balance
    //  the sliders we need to subtract 25 from the subordinates.
    //
    flex = this.oValues.sumOf(this.subordinates) + newValue;
    flex = this.snapValue(this.max - flex);

    for (i = 0; i < sLength; i++) {
      // The balancer seeks to assign the full flex amount to one slider; if
      // this can't be done, it moves on to the next slider, and keeps going
      // until either all of the flex has been assigned, or we run out of
      // sliders.

      slider    = this.subordinates[i];
      prevValue = this.oValues.value(slider);

      slider.__setValue(prevValue + flex);

      // Reduce the flex by the amount by which the slider was changed,
      // ready for the next slider.
      flex = this.snapValue(flex - (slider.value - prevValue));
    }

    if (flex !== 0) {
      valuesBeforeBalancing.revert();
      return false;
    }
  };

  /**
   * Given a float, "snaps" it to match the precision (i.e. if the smallest
   * step value of any of the balanced sliders is 0.1, it will round the
   * number to the nearest 0.1). Used heavily in doBalance to account for the
   * _vast_ number of floating point errors which occur when a group contains
   * three or more sliders.
   */
  Balancer.prototype.snapValue = function (value) {
    return parseFloat(value.toFixed(this.precision));
  };

  /**
   * Returns if the given Quinn instance is the current master slider.
   */
  Balancer.prototype.isMaster = function (quinn) {
    return (this.masterId !== null &&
            this.masterId === quinn.balanceId);
  };

  /**
   * Resetting a single slider in a group resets them all to their original
   * values.
   */
  Balancer.prototype.resetAll = function () {
    try {
      this.isDisabled = true;
      _.invoke(this.views, 'resetValue', false);
    } finally {
      this.isDisabled = false;
    }
  };

  // ## Event-Handling -------------------------------------------------------

  Balancer.prototype.onBegin = function (value, quinn) {
    if (this.isDisabled) {
      return true;
    }

    // If no slider is already being adjusted, then this is when the
    // user begins moving a slider.
    if (this.masterId === null) {
      this.masterId     = quinn.balanceId;
      this.subordinates = this.__getSubordinates();
      this.oValues      = new OriginalValues(this.quinns);

      this.__runOnSubordinates('__willChange');

      this.trigger('begin');
    }

    // Otherwise is is an onBegin event being fired when a subordinate
    // slider is being balanced; ignore it.
  };

  Balancer.prototype.onChange = function (value, quinn) {
    // Fired when a slider value is changed. We only care about changes to the
    // master slider, and subordinates are ignored.
    if (this.isMaster(quinn)) {
      if (this.doBalance(value, quinn) === false) {
        // Can't do the balance, so we prevent the slider movement.
        return false;
      }

      this.trigger('change');
    }
  };

  Balancer.prototype.onCommit = function (value, quinn) {
    if (this.isMaster(quinn)) {
      this.__sliderUsed(quinn);
      this.__finish('__hasChanged');
      this.trigger('commit');
    }
  };

  Balancer.prototype.onAbort = function (value, quinn) {
    if (this.isMaster(quinn)) {
      this.__finish('__abortChange');
      this.trigger('abort');
    }
  };

  // ## Pseudo-Private Methods -----------------------------------------------

  /**
   * Returns all the sliders except the one with which the user is
   * interacting and those which are disabled.
   */
  Balancer.prototype.__getSubordinates = function () {
    var self = this, subs;

    subs = _.select(this.quinns, function (quinn) {
      return (! self.isMaster(quinn) && ! quinn.isDisabled);
    });

    if (this.quinns.length <= 2) {
      return subs;
    }

    // The subs are now re-ordered so that the most recently used sliders are
    // at the end of the array. Otherwise doBalance is somewhat biased towards
    // the first slider.
    return _.sortBy(subs, function (quinn) {
      return _.indexOf(self.quinnOrder, quinn.balanceId);
    });
  };

  /**
   * Marks a slider as used, pushing it to the back of the quinnOrder array.
   * This prevents doBalance favouring balancing one slider over the others.
   */
  Balancer.prototype.__sliderUsed = function (quinn) {
    if (this.quinns.length <= 2) {
      return true;
    }

    var balanceId = quinn.balanceId;

    this.quinnOrder = _.without(this.quinnOrder, balanceId);
    this.quinnOrder.push(balanceId);
  };

  /**
   * Returns the maximum permitted cumulative value of the sliders which are
   * members of the group. This is cached as this.max.
   */
  Balancer.prototype.__getMax = function () {
    if (this.options.max) {
      return this.options.max;
    }

    // No explicit max, just use the total of all the sliders (no balancing).
    return _.reduce(this.quinns, function (sum, quinn) {
      return (sum + quinn.range[1]);
    }, 0) / this.quinns.length;
  };

  /**
   * Since many sliders use a fractional step value, and floating point
   * arithmetic is a nightmare, determine the number of decimal places used in
   * the smallest slider step value, so that we can do all balancing using
   * integers.
   */
  Balancer.prototype.__getPrecision = function () {
    return _.max(_.map(this.views, function (view) {
      return view.conversion.precision;
    })) || 0;
  };

  /**
   * Finishes editing slider values by resetting this.masterId and
   * this.subordinates, and calling 'method' on the subordinates.
   */
  Balancer.prototype.__finish = function (method) {
    this.__runOnSubordinates(method);

    this.masterId     = null;
    this.subordinates = null;
    this.oValues      = null;
  };

  /**
   * Runs a method on all the subordinates.
   */
  Balancer.prototype.__runOnSubordinates = function (method) {
    var subLength = this.subordinates.length, i;

    for (i = 0; i < subLength; i++) {
      this.subordinates[i][method]();
    }
  };

  // # OriginalValues --------------------------------------------------------

  /**
   * Given an array of Quinn instances, OriginalValues keeps track of the
   * value of each slider at the time the OriginalValues instance was created.
   */
  function OriginalValues (quinns) {
    var i;

    this.length = quinns.length;
    this.quinns = quinns;
    this.values = {};

    for (i = 0; i < this.length; i++) {
      this.values[quinns[i].balanceId] = quinns[i].value;
    }
  }

  /**
   * Given a Quinn instance, returns the value of that instance at the time
   * the OriginalValues was initialized.
   */
  OriginalValues.prototype.value = function (quinn) {
    return this.values[quinn.balanceId];
  };

  /**
   * Given an array of Quinns, returns the sum of their values at the time the
   * OriginalValues was initialized.
   */
  OriginalValues.prototype.sumOf = function (sliders) {
    var sLength = sliders.length, sum = 0, i;

    for (i = 0; i < sLength; i++) {
      sum += this.value(sliders[i]);
    }

    return sum;
  };

  /**
   * Reverts the Quinn instances back to their original value.
   */
  OriginalValues.prototype.revert = function () {
    var i;

    for (i = 0; i < this.length; i++) {
      this.quinns[i].__setValue(this.values[ this.quinns[i].balanceId ]);
    }
  };

  // # Globals ---------------------------------------------------------------

  window.InputElement.Balancer = Balancer;

})(window);
<|endoftext|>


<commit_before>import React from 'react'
import {connect} from 'store'
import Http from 'http-client'

class LandCover extends React.Component {
    createComposites() {
        this.props.asyncActionBuilder('CREATE_COMPOSITES',
            Http.postJson$('/api/tasks', {
                operation: 'sepal.landcover.create_composites',
                params: {
                    assetPath: 'land-cover-test/myanmar',
                    fromYear: 2015,
                    toYear: 2016,
                    aoiFusionTable: '15_cKgOA-AkdD6EiO-QW9JXM8_1-dPuuj1dqFr17F',
                    keyColumn: 'ISO',
                    keyValue: 'MMR',
                    sensors: ['L8', 'L7'],
                    scale: 3000
                }
            })
        ).dispatch()
    }

    classify() {
        this.props.asyncActionBuilder('CLASSIFY',
            Http.postJson$('/api/tasks', {
                operation: 'sepal.landcover.create_land_cover_map',
                params: {
                    assetPath: 'land-cover-test/myanmar',
                    scale: 3000,
                    years: {
                        // 2015: {
                        //     trainingDataFusionTables: {
                        //         primitiveA: '1kprIURiogZxAKo2Dmvnt5RVEiN0FuuPNUR4Z4COD',
                        //         primitiveB: '1kprIURiogZxAKo2Dmvnt5RVEiN0FuuPNUR4Z4COD',
                        //     }
                        // },
                        2016: {
                            trainingDataFusionTables: {
                                primitiveA: '1kprIURiogZxAKo2Dmvnt5RVEiN0FuuPNUR4Z4COD',
                                // primitiveB: '1kprIURiogZxAKo2Dmvnt5RVEiN0FuuPNUR4Z4COD',
                            }
                        }
                    }
                }
            })
        ).dispatch()
    }

    assessAccuracy() {
        this.props.asyncActionBuilder('ASSES_ACCURACY',
            Http.postJson$('/api/tasks', {
                operation: 'sepal.landcover.assess_land_cover_map_accuracy',
                params: {}
            })
        ).dispatch()
    }

    // Find out which step
    //      Start with a recipe step, then validate that expected assets and fusion tables are available

    // Get the task id, and use it to monitor state

    render() {
        return (

                <button onClick={this.createComposites.bind(this)}>Create composites</button>

                <button onClick={this.classify.bind(this)}>Classify</button>

                <button onClick={this.assessAccuracy.bind(this)}>Assess accuracy</button>

        )
    }
}

export default connect()(LandCover)<commit_msg>Enabled more years and primitives in land cover analysis test.<commit_after>import React from 'react'
import {connect} from 'store'
import Http from 'http-client'

class LandCover extends React.Component {
    createComposites() {
        this.props.asyncActionBuilder('CREATE_COMPOSITES',
            Http.postJson$('/api/tasks', {
                operation: 'sepal.landcover.create_composites',
                params: {
                    assetPath: 'land-cover-test/myanmar',
                    fromYear: 2015,
                    toYear: 2016,
                    aoiFusionTable: '15_cKgOA-AkdD6EiO-QW9JXM8_1-dPuuj1dqFr17F',
                    keyColumn: 'ISO',
                    keyValue: 'MMR',
                    sensors: ['L8', 'L7'],
                    scale: 3000
                }
            })
        ).dispatch()
    }

    classify() {
        this.props.asyncActionBuilder('CLASSIFY',
            Http.postJson$('/api/tasks', {
                operation: 'sepal.landcover.create_land_cover_map',
                params: {
                    assetPath: 'land-cover-test/myanmar',
                    scale: 3000,
                    years: {
                        2015: {
                            trainingDataFusionTables: {
                                primitiveA: '1kprIURiogZxAKo2Dmvnt5RVEiN0FuuPNUR4Z4COD',
                                primitiveB: '1kprIURiogZxAKo2Dmvnt5RVEiN0FuuPNUR4Z4COD',
                            }
                        },
                        2016: {
                            trainingDataFusionTables: {
                                primitiveA: '1kprIURiogZxAKo2Dmvnt5RVEiN0FuuPNUR4Z4COD',
                                primitiveB: '1kprIURiogZxAKo2Dmvnt5RVEiN0FuuPNUR4Z4COD',
                            }
                        }
                    }
                }
            })
        ).dispatch()
    }

    assessAccuracy() {
        this.props.asyncActionBuilder('ASSES_ACCURACY',
            Http.postJson$('/api/tasks', {
                operation: 'sepal.landcover.assess_land_cover_map_accuracy',
                params: {}
            })
        ).dispatch()
    }

    // Find out which step
    //      Start with a recipe step, then validate that expected assets and fusion tables are available

    // Get the task id, and use it to monitor state

    render() {
        return (

                <button onClick={this.createComposites.bind(this)}>Create composites</button>

                <button onClick={this.classify.bind(this)}>Classify</button>

                <button onClick={this.assessAccuracy.bind(this)}>Assess accuracy</button>

        )
    }
}

export default connect()(LandCover)<|endoftext|>


<commit_before>import React from 'react';
import {isCookiesDisabled} from '../../utils/helpers';

export const InputFieldStyles = `
    .gh-portal-input {
        -webkit-appearance: none;
        -moz-appearance: none;
        appearance: none;

        display: block;
        box-sizing: border-box;
        font-size: 1.5rem;
        color: inherit;
        background: transparent;
        outline: none;
        border: 1px solid var(--grey12);
        border-radius: 3px;
        width: 100%;
        height: 40px;
        padding: 0 12px;
        margin-bottom: 18px;
        letter-spacing: 0.2px;
        box-shadow: 0px 2px 4px 0px rgba(0, 0, 0, 0.07), 0px 1px 1.5px 0px rgba(0, 0, 0, 0.05);
        transition: all 0.25s ease-in-out;
    }

    .gh-portal-input-labelcontainer {
        display: flex;
        justify-content: space-between;
        width: 100%;
    }

    .gh-portal-input-labelcontainer p {
        color: var(--red);
        font-size: 1.3rem;
        letter-spacing: 0.35px;
        line-height: 1.6em;
        margin-bottom: 0;
    }

    .gh-portal-input-label.hidden {
        display: none;
    }

    .gh-portal-input:focus {
        border-color: #cdcdcd;
    }

    .gh-portal-input.error {
        border-color: var(--red);
    }

    .gh-portal-input::placeholder {
        color: var(--grey7);
    }

    .gh-portal-input:disabled {
        background: var(--grey13);
        color: var(--grey9);
        box-shadow: none;
    }

    .gh-portal-input:disabled::placeholder {
        color: var(--grey9);
    }
`;

function InputError({message, style}) {
    if (!message) {
        return null;
    }
    return (

            {message}

    );
}

function InputField({name, id, label, hideLabel, type, value, placeholder, disabled, onChange, onBlur, onKeyDown, errorMessage}) {
    id = id || `input-${name}`;
    onBlur = onBlur || function (){};
    const labelClasses = hideLabel ? 'gh-portal-input-label hidden' : 'gh-portal-input-label';
    const inputClasses = errorMessage ? 'gh-portal-input error' : 'gh-portal-input';
    if (isCookiesDisabled()) {
        disabled = true;
    }
    return (

                 {label}
                <InputError message={errorMessage} name={name} />

            <input
                id={id}
                className={inputClasses}
                type={type}
                name={name}
                value={value}
                placeholder={placeholder}
                onChange={e => onChange(e, name)}
                onKeyDown={e => onKeyDown(e, name)}
                onBlur={e => onBlur(e, name)}
                disabled={disabled}
                aria-label={label}
            />

    );
}

export default InputField;
<commit_msg>Added name and email input attributes<commit_after>import React from 'react';
import {isCookiesDisabled} from '../../utils/helpers';

export const InputFieldStyles = `
    .gh-portal-input {
        -webkit-appearance: none;
        -moz-appearance: none;
        appearance: none;

        display: block;
        box-sizing: border-box;
        font-size: 1.5rem;
        color: inherit;
        background: transparent;
        outline: none;
        border: 1px solid var(--grey12);
        border-radius: 3px;
        width: 100%;
        height: 40px;
        padding: 0 12px;
        margin-bottom: 18px;
        letter-spacing: 0.2px;
        box-shadow: 0px 2px 4px 0px rgba(0, 0, 0, 0.07), 0px 1px 1.5px 0px rgba(0, 0, 0, 0.05);
        transition: all 0.25s ease-in-out;
    }

    .gh-portal-input-labelcontainer {
        display: flex;
        justify-content: space-between;
        width: 100%;
    }

    .gh-portal-input-labelcontainer p {
        color: var(--red);
        font-size: 1.3rem;
        letter-spacing: 0.35px;
        line-height: 1.6em;
        margin-bottom: 0;
    }

    .gh-portal-input-label.hidden {
        display: none;
    }

    .gh-portal-input:focus {
        border-color: #cdcdcd;
    }

    .gh-portal-input.error {
        border-color: var(--red);
    }

    .gh-portal-input::placeholder {
        color: var(--grey7);
    }

    .gh-portal-input:disabled {
        background: var(--grey13);
        color: var(--grey9);
        box-shadow: none;
    }

    .gh-portal-input:disabled::placeholder {
        color: var(--grey9);
    }
`;

function InputError({message, style}) {
    if (!message) {
        return null;
    }
    return (

            {message}

    );
}

function InputField({name, id, label, hideLabel, type, value, placeholder, disabled, onChange, onBlur, onKeyDown, errorMessage}) {
    id = id || `input-${name}`;
    onBlur = onBlur || function (){};
    const labelClasses = hideLabel ? 'gh-portal-input-label hidden' : 'gh-portal-input-label';
    const inputClasses = errorMessage ? 'gh-portal-input error' : 'gh-portal-input';
    if (isCookiesDisabled()) {
        disabled = true;
    }
    let autocomplete = '';
    let autocorrect = '';
    let autocapitalize = '';
    switch (id) {
    case 'input-email':
        autocomplete = 'off';
        autocorrect = 'off';
        autocapitalize = 'off';
        break;
    case 'input-name':
        autocomplete = 'off';
        autocorrect = 'off';
        break;
    default:
        break;
    }
    return (

                 {label}
                <InputError message={errorMessage} name={name} />

            <input
                id={id}
                className={inputClasses}
                type={type}
                name={name}
                value={value}
                placeholder={placeholder}
                onChange={e => onChange(e, name)}
                onKeyDown={e => onKeyDown(e, name)}
                onBlur={e => onBlur(e, name)}
                disabled={disabled}
                autoComplete={autocomplete}
                autoCorrect={autocorrect}
                autoCapitalize={autocapitalize}
                aria-label={label}
            />

    );
}

export default InputField;
<|endoftext|>


<commit_before>'use strict';

const fs = require('original-fs');
const readdir = require('./readdir');
const co = require('co');

const path = require('path');

const matchFunc = (filePath, stats) => {
  const ext = path.extname(filePath).toLowerCase();
  if (stats.isDirectory())
    return true;
  return (ext === '.exe' || ext === '.lnk');
};

function injectEnvVariable(dirPath) {
  let _path = dirPath;
  for (const envVar in process.env) {
    const value = process.env[envVar];
    _path = _path.replace(`\${${envVar}}`, value);
  }
  return _path;
}

function injectEnvVariables(dirArr) {
  const newArr = [];
  for (let i = 0; i < dirArr.length; ++i) {
    const dirPath = dirArr[i];
    newArr.push(injectEnvVariable(dirPath));
  }
  return newArr;
}

module.exports = (context) => {
  const matchutil = context.matchutil;
  const logger = context.logger;
  const shell = context.shell;
  const app = context.app;
  const initialPref = context.preferences.get();

  const recursiveSearchDirs = injectEnvVariables(initialPref.recursiveFolders || []);
  const flatSearchDirs = injectEnvVariables(initialPref.flatFolders || []);

  const db = {};
  const lazyIndexingKeys = {};

  function* refreshIndex(dirs, recursive) {
    for (const dir of dirs) {
      logger.log(`refreshIndex ${dir}`);
      if (fs.existsSync(dir) === false) {
        logger.log(`can't find a dir: ${dir}`);
        continue;
      }
      const files = yield co(readdir(dir, recursive, matchFunc));
      logger.log(`index updated ${dir}`);
      db[dir] = files;
    }
  }

  function lazyRefreshIndex(dir, recursive) {
    const _lazyKey = lazyIndexingKeys[dir];
    if (_lazyKey !== undefined) {
      clearTimeout(_lazyKey);
    }

    lazyIndexingKeys[dir] = setTimeout(() => {
      co(refreshIndex([dir], recursive));
    }, 5000);
  }

  function* setupWatchers(dirs, recursive) {
    for (const dir of dirs) {
      const _dir = dir;
      fs.watch(_dir, {
        persistent: true,
        recursive: recursive
      }, (evt, filename) => {
        lazyRefreshIndex(_dir, recursive);
      });
    }
  }

  function startup() {
    co(function* () {
      yield* refreshIndex(recursiveSearchDirs, true);
      yield* refreshIndex(flatSearchDirs, false);
      yield* setupWatchers(recursiveSearchDirs, true);
      yield* setupWatchers(flatSearchDirs, false);
    }).catch((err) => {
      logger.log(err);
      logger.log(err.stack);
    });
  }

  function computeRatio(filePath) {
    let ratio = 1;
    const ext = path.extname(filePath).toLowerCase();
    const basename = path.basename(filePath).toLowerCase();
    if (ext !== '.lnk' && ext !== '.exe')
      ratio *= 0.5;
    if (basename.indexOf('uninstall') >= 0 || basename.indexOf('remove') >= 0)
      ratio *= 0.9;
    return ratio;
  }

  function search(query, res) {
    const query_trim = query.replace(' ', '');
    const searched = matchutil.fuzzy(db, query_trim, (x) => x);
    const result = searched.slice(0, 10).map((x) => {
      const filePath = x.elem;
      const filePath_bold = matchutil.makeStringBoldHtml(filePath, x.matches);
      const filePath_base64 = new Buffer(filePath).toString('base64');
      const score = x.score * computeRatio(filePath);
      return {
        id: filePath,
        title: path.basename(filePath, path.extname(filePath)),
        desc: filePath_bold,
        icon: `icon://${filePath_base64}`,
        group: 'Files & Folders',
        score
      };
    });
    res.add(result);
  }

  function execute(id, payload) {
    logger.log(`${id} executed`);
    shell.openItem(id);
    app.close();
  }

  return { startup, search, execute };
};
<commit_msg>Update priority by extension (hain-plugin-filesearch)<commit_after>'use strict';

const fs = require('original-fs');
const readdir = require('./readdir');
const co = require('co');

const path = require('path');

const matchFunc = (filePath, stats) => {
  const ext = path.extname(filePath).toLowerCase();
  if (stats.isDirectory())
    return true;
  return (ext === '.exe' || ext === '.lnk');
};

function injectEnvVariable(dirPath) {
  let _path = dirPath;
  for (const envVar in process.env) {
    const value = process.env[envVar];
    _path = _path.replace(`\${${envVar}}`, value);
  }
  return _path;
}

function injectEnvVariables(dirArr) {
  const newArr = [];
  for (let i = 0; i < dirArr.length; ++i) {
    const dirPath = dirArr[i];
    newArr.push(injectEnvVariable(dirPath));
  }
  return newArr;
}

module.exports = (context) => {
  const matchutil = context.matchutil;
  const logger = context.logger;
  const shell = context.shell;
  const app = context.app;
  const initialPref = context.preferences.get();

  const recursiveSearchDirs = injectEnvVariables(initialPref.recursiveFolders || []);
  const flatSearchDirs = injectEnvVariables(initialPref.flatFolders || []);

  const db = {};
  const lazyIndexingKeys = {};

  function* refreshIndex(dirs, recursive) {
    for (const dir of dirs) {
      logger.log(`refreshIndex ${dir}`);
      if (fs.existsSync(dir) === false) {
        logger.log(`can't find a dir: ${dir}`);
        continue;
      }
      const files = yield co(readdir(dir, recursive, matchFunc));
      logger.log(`index updated ${dir}`);
      db[dir] = files;
    }
  }

  function lazyRefreshIndex(dir, recursive) {
    const _lazyKey = lazyIndexingKeys[dir];
    if (_lazyKey !== undefined) {
      clearTimeout(_lazyKey);
    }

    lazyIndexingKeys[dir] = setTimeout(() => {
      co(refreshIndex([dir], recursive));
    }, 5000);
  }

  function* setupWatchers(dirs, recursive) {
    for (const dir of dirs) {
      const _dir = dir;
      fs.watch(_dir, {
        persistent: true,
        recursive: recursive
      }, (evt, filename) => {
        lazyRefreshIndex(_dir, recursive);
      });
    }
  }

  function startup() {
    co(function* () {
      yield* refreshIndex(recursiveSearchDirs, true);
      yield* refreshIndex(flatSearchDirs, false);
      yield* setupWatchers(recursiveSearchDirs, true);
      yield* setupWatchers(flatSearchDirs, false);
    }).catch((err) => {
      logger.log(err);
      logger.log(err.stack);
    });
  }

  function computeRatio(filePath) {
    let ratio = 1;
    const ext = path.extname(filePath).toLowerCase();
    const basename = path.basename(filePath).toLowerCase();
    if (ext !== '.lnk' && ext !== '.exe')
      ratio *= 0.5;
    if (ext === '.lnk')
      ratio *= 1.5;
    if (basename.indexOf('uninstall') >= 0 || basename.indexOf('remove') >= 0)
      ratio *= 0.9;
    return ratio;
  }

  function search(query, res) {
    const query_trim = query.replace(' ', '');
    const searched = matchutil.fuzzy(db, query_trim, (x) => x);
    const result = searched.slice(0, 10).map((x) => {
      const filePath = x.elem;
      const filePath_bold = matchutil.makeStringBoldHtml(filePath, x.matches);
      const filePath_base64 = new Buffer(filePath).toString('base64');
      const score = x.score * computeRatio(filePath);
      return {
        id: filePath,
        title: path.basename(filePath, path.extname(filePath)),
        desc: filePath_bold,
        icon: `icon://${filePath_base64}`,
        group: 'Files & Folders',
        score
      };
    });
    res.add(result);
  }

  function execute(id, payload) {
    logger.log(`${id} executed`);
    shell.openItem(id);
    app.close();
  }

  return { startup, search, execute };
};
<|endoftext|>