Hello community,

here is the log from the commit of package velum for openSUSE:Factory checked 
in at 2018-02-22 15:03:31
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/velum (Old)
 and      /work/SRC/openSUSE:Factory/.velum.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "velum"

Thu Feb 22 15:03:31 2018 rev:7 rq:578943 
version:3.0.0+dev+git_r650_4eb2d26dfbef4dd92b3b4685f1704ed8787d5732

Changes:
--------
--- /work/SRC/openSUSE:Factory/velum/velum.changes      2018-02-18 
11:42:51.856523989 +0100
+++ /work/SRC/openSUSE:Factory/.velum.new/velum.changes 2018-02-22 
15:03:34.463568486 +0100
@@ -1,0 +2,9 @@
+Thu Feb 22 09:58:32 UTC 2018 - containers-bugow...@suse.de
+
+- Commit 4eb2d26 by James Mason jma...@suse.com
+ Add user interface for public cloud bootstrapping
+ 
+ new file:   app/assets/stylesheets/pages/instance_type.scss
+
+
+-------------------------------------------------------------------

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ velum.spec ++++++
--- /var/tmp/diff_new_pack.RjePRA/_old  2018-02-22 15:03:35.919516113 +0100
+++ /var/tmp/diff_new_pack.RjePRA/_new  2018-02-22 15:03:35.923515970 +0100
@@ -23,7 +23,7 @@
 # Version:      1.0.0
 # %%define branch 1.0.0
 
-Version:        3.0.0+dev+git_r646_67806291a2f2903835f76b154b3e1b4811873011
+Version:        3.0.0+dev+git_r650_4eb2d26dfbef4dd92b3b4685f1704ed8787d5732
 Release:        0
 %define branch master
 Summary:        Dashboard for CaasP
@@ -96,7 +96,7 @@
 %description
 velum is the dashboard for CaasP to manage and deploy kubernetes clusters on 
top of MicroOS
 
-This package has been built with commit 
67806291a2f2903835f76b154b3e1b4811873011 from branch master on date Thu, 15 Feb 
2018 15:53:13 +0000
+This package has been built with commit 
4eb2d26dfbef4dd92b3b4685f1704ed8787d5732 from branch master on date Thu, 22 Feb 
2018 09:57:53 +0000
 
 %prep
 %setup -q -n velum-%{branch}

++++++ master.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/velum-master/app/assets/javascripts/application.js 
new/velum-master/app/assets/javascripts/application.js
--- old/velum-master/app/assets/javascripts/application.js      2018-02-15 
16:53:11.000000000 +0100
+++ new/velum-master/app/assets/javascripts/application.js      2018-02-22 
10:57:04.000000000 +0100
@@ -13,6 +13,7 @@
 //= require jquery
 //= require jquery_ujs
 //= require bootstrap.min
+//= require bootstrap-slider.min
 //
 //= require_tree ./dashboard
 //= require_tree ./setup
@@ -21,4 +22,4 @@
 
 $('body').on('click', '[disabled]', function(e) {
   e.preventDefault();
-});
\ No newline at end of file
+});
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/velum-master/app/assets/javascripts/cloud/bootstrap.js 
new/velum-master/app/assets/javascripts/cloud/bootstrap.js
--- old/velum-master/app/assets/javascripts/cloud/bootstrap.js  1970-01-01 
01:00:00.000000000 +0100
+++ new/velum-master/app/assets/javascripts/cloud/bootstrap.js  2018-02-22 
10:57:04.000000000 +0100
@@ -0,0 +1,65 @@
+$(function() {
+  // 
https://stackoverflow.com/questions/10420352/converting-file-size-in-bytes-to-human-readable-string
+  // https://creativecommons.org/licenses/by-sa/4.0/
+  function humanFileSize(bytes, si) {
+      var thresh = si ? 1000 : 1024;
+      if(Math.abs(bytes) < thresh) {
+          return bytes + ' B';
+      }
+      var units = si
+          ? ['kB','MB','GB','TB','PB','EB','ZB','YB']
+          : ['KiB','MiB','GiB','TiB','PiB','EiB','ZiB','YiB'];
+      var u = -1;
+      do {
+          bytes /= thresh;
+          ++u;
+      } while(Math.abs(bytes) >= thresh && u < units.length - 1);
+      return bytes.toFixed(1)+' '+units[u];
+  }
+
+  function calcClusterVcpus() {
+      vcpusPerVm = $('.instance-type-description .vcpu-count').data('vcpus');
+      vmCount = clusterSize.getValue();
+      $('#cluster-cpu-count').html(vcpusPerVm * vmCount);
+  }
+
+  function calcClusterRam() {
+      bytesPerVm = $('.instance-type-description .ram-size').data('bytes');
+      siUnits = $('.instance-type-description .ram-size').data('si');
+      vmCount = clusterSize.getValue();
+      totalBytes = bytesPerVm * vmCount;
+      $('#cluster-ram-size').attr('data-bytes', totalBytes);
+      $('#cluster-ram-size').html(humanFileSize(totalBytes, siUnits))
+  }
+
+  var updateClusterSize = function() {
+      calcClusterVcpus();
+      calcClusterRam();
+  }
+
+  var clusterSize = $('#cloud_cluster_instance_count').slider()
+    .on('slide change', updateClusterSize).data('slider');
+
+  $('input[name="cloud_cluster[instance_type]"]').click(function() {
+      definition = $(this).siblings('.definition').html();
+      $('.instance-type-description').html(definition);
+      ramSize = $('.instance-type-description .ram-size')
+      ramSize.html(
+          humanFileSize(ramSize.data('bytes'), ramSize.data('si'))
+      )
+
+      if (this.id === 'cloud_cluster_instance_type_custom') {
+        $('.cluster-cpu-count,.cluster-ram-size').hide();
+        $('input#cloud_cluster_instance_type_custom[type="text"]').
+            show().focus();
+      } else {
+        $('input#cloud_cluster_instance_type_custom[type="text"]').
+            val("").hide();
+        updateClusterSize();
+        $('.cluster-cpu-count,.cluster-ram-size').show();
+      }
+  });
+
+  // kick things off
+  $('input[name="cloud_cluster[instance_type]"][checked="checked"]').click();
+});
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/velum-master/app/assets/stylesheets/application.scss 
new/velum-master/app/assets/stylesheets/application.scss
--- old/velum-master/app/assets/stylesheets/application.scss    2018-02-15 
16:53:11.000000000 +0100
+++ new/velum-master/app/assets/stylesheets/application.scss    2018-02-22 
10:57:04.000000000 +0100
@@ -6,6 +6,7 @@
 @import 'bootstrap-sprockets';
 @import 'velum_bootstrap-variables';
 @import 'bootstrap';
+@import 'bootstrap-slider.min';
 
 @import 'components/**/*';
 @import 'velum_general';
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/velum-master/app/assets/stylesheets/pages/instance_type.scss 
new/velum-master/app/assets/stylesheets/pages/instance_type.scss
--- old/velum-master/app/assets/stylesheets/pages/instance_type.scss    
1970-01-01 01:00:00.000000000 +0100
+++ new/velum-master/app/assets/stylesheets/pages/instance_type.scss    
2018-02-22 10:57:04.000000000 +0100
@@ -0,0 +1,106 @@
+.instance-type-selector {
+    background-color: $panel-default-heading-bg;
+
+    .instance-types {
+        border-right: 1px solid $table-border-color;
+    }
+
+    label.instance-type {
+
+        input[type="radio"] {
+            display: none;
+
+            &:checked + .instance-type-box {
+                background-color: $brand-success;
+                color: $table-bg;
+                box-shadow: none;
+            }
+        }
+
+        .instance-type-box {
+            display: inline-block;
+            overflow: hidden;
+            width: 148px;
+            height: 148px;
+
+            border: 1px solid $table-border-color;
+            border-radius: 5px;
+            box-shadow: 1px 1px 6px 1px $table-border-color;
+
+            background: $table-bg;
+            color: $brand-success;
+
+            margin: 10px;
+            padding: 10px;
+
+            font-size: 14pt;
+            text-align: center;
+            font-weight: normal;
+            word-wrap: break-word;
+
+            &.double {
+                width: 316px;
+            }
+        }
+
+        .definition {
+            display: none;
+        }
+    }
+
+    .instance-type-description {
+        h1, h2, h3, h4, h5, h6 {
+            color: #3d4042;
+        }
+    }
+}
+
+.cluster-size-selector {
+    background-color: $panel-default-heading-bg;
+    min-height: 113px;
+
+    .slider {
+        &.slider-horizontal {
+            width: 100% !important;
+        }
+
+        .slider-handle {
+            background: $brand-success;
+            border: 1px solid $brand-success;
+            box-shadow: none;
+        }
+
+        .slider-track {
+            background: $table-bg;
+            border: 1px solid $table-border-color;
+        }
+
+        .slider-track-low, .slider-track-high {
+            background: $table-bg;
+        }
+
+        .slider-selection {
+            background: $brand-success; //#337ab7;
+        }
+
+        .slider-tick {
+            background: $table-bg;
+            border: 1px solid $table-border-color;
+            box-shadow: none;
+
+            &.in-selection {
+                background: $brand-success; //#337ab7;
+                border: 1px solid $brand-success; //#337ab7;
+            }
+        }
+    }
+
+    label {
+        display: block;
+
+        &.h3 {
+            margin-top: 0;
+            margin-bottom: 0;
+        }
+    }
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/velum-master/app/controllers/internal_api/v1/pillars_controller.rb 
new/velum-master/app/controllers/internal_api/v1/pillars_controller.rb
--- old/velum-master/app/controllers/internal_api/v1/pillars_controller.rb      
2018-02-15 16:53:11.000000000 +0100
+++ new/velum-master/app/controllers/internal_api/v1/pillars_controller.rb      
2018-02-22 10:57:04.000000000 +0100
@@ -1,14 +1,18 @@
 # Serve the pillar information
 class InternalApi::V1::PillarsController < InternalApiController
   def show
-    ok content: pillar_contents.merge(registry_contents)
+    ok content: pillar_contents.merge(
+      registry_contents
+    ).merge(
+      cloud_framework_contents
+    )
   end
 
   private
 
   def pillar_contents
     pillar_struct = {}.tap do |h|
-      Pillar.all_pillars.each do |k, v|
+      Pillar.simple_pillars.each do |k, v|
         h[v] = Pillar.value(pillar: k.to_sym) unless Pillar.value(pillar: 
k.to_sym).nil?
       end
     end
@@ -40,4 +44,34 @@
     end
     { registries: (registries + registry_mirrors) }
   end
+
+  def cloud_framework_contents
+    case Pillar.value(pillar: :cloud_framework)
+    when "ec2"
+      ec2_cloud_contents
+    else
+      {}
+    end
+  end
+
+  def ec2_cloud_contents
+    {
+      cloud: {
+        framework: "ec2",
+        profiles:  {
+          cluster_node: {
+            size:               Pillar.value(pillar: :cloud_worker_type),
+            network_interfaces: [
+              {
+                DeviceIndex:              0,
+                AssociatePublicIpAddress: false,
+                SubnetId:                 Pillar.value(pillar: 
:cloud_worker_subnet),
+                SecurityGroupId:          Pillar.value(pillar: 
:cloud_worker_security_group)
+              }
+            ]
+          }
+        }
+      }
+    }
+  end
 end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/velum-master/app/controllers/setup_controller.rb 
new/velum-master/app/controllers/setup_controller.rb
--- old/velum-master/app/controllers/setup_controller.rb        2018-02-15 
16:53:11.000000000 +0100
+++ new/velum-master/app/controllers/setup_controller.rb        2018-02-22 
10:57:04.000000000 +0100
@@ -1,4 +1,5 @@
 require "velum/salt"
+require "velum/instance_type"
 
 # SetupController is responsible for everything related to the bootstrapping
 # process:
@@ -52,6 +53,38 @@
 
   def worker_bootstrap
     @controller_node = Pillar.value pillar: :dashboard
+
+    return unless (cloud = Pillar.value(pillar: :cloud_framework))
+
+    @instance_types = Velum::InstanceType.for(cloud)
+    @cloud_cluster = CloudCluster.new(cloud_framework: cloud)
+    case cloud
+    when "ec2"
+      @cloud_cluster.instance_type = Pillar.value(
+        pillar: :cloud_worker_type
+      ) || @instance_types.first.key
+      @cloud_cluster.subnet_id = Pillar.value(
+        pillar: :cloud_worker_subnet
+      ) || "subnet-"
+      @cloud_cluster.security_group_id = Pillar.value(
+        pillar: :cloud_worker_security_group
+      ) || "sg-"
+    end
+    render "worker_bootstrap_#{cloud}".to_sym
+  end
+
+  def build_cloud_cluster
+    @cloud_cluster = CloudCluster.new(cloud_cluster_params)
+
+    if @cloud_cluster.save
+      Velum::Salt.build_cloud_cluster(@cloud_cluster.instance_count)
+      redirect_to setup_discovery_path,
+        notice: "Starting to build #{@cloud_cluster}..."
+    else
+      flash.keep
+      redirect_to setup_worker_bootstrap_path,
+        flash: { error: @cloud_cluster.errors.full_messages.to_sentence }
+    end
   end
 
   def set_roles
@@ -135,6 +168,21 @@
     [parameters]
   end
 
+  def cloud_cluster_params
+    cloud_cluster = params.require(:cloud_cluster).permit(
+      :instance_type,
+      :instance_type_custom,
+      :instance_count,
+      :vnet_id,
+      :subnet_id,
+      :security_group_id,
+      :publishsettings,
+      :media_link
+    )
+    cloud_cluster["cloud_framework"] = Pillar.value(pillar: :cloud_framework)
+    cloud_cluster
+  end
+
   def update_nodes_params
     params.require(:roles)
   end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/velum-master/app/models/cloud_cluster.rb 
new/velum-master/app/models/cloud_cluster.rb
--- old/velum-master/app/models/cloud_cluster.rb        1970-01-01 
01:00:00.000000000 +0100
+++ new/velum-master/app/models/cloud_cluster.rb        2018-02-22 
10:57:04.000000000 +0100
@@ -0,0 +1,55 @@
+# frozen_string_literal: true
+require "velum/salt"
+# CloudCluster represents user-configured attributes of a cloud deployment.
+class CloudCluster
+  include ActiveModel::Model
+  attr_accessor :cloud_framework,
+    :instance_count, :instance_type, :instance_type_custom,
+    :subnet_id, :security_group_id # EC2
+
+  def initialize(*args)
+    super
+    if @instance_type.blank? || @instance_type == "CUSTOM"
+      @instance_type = instance_type_custom
+    end
+    @instance_count = @instance_count.to_i
+  end
+
+  def to_s
+    parts = ["a cluster of #{@instance_count} #{@instance_type} instances"]
+    parts.push("in the #{@subnet_id} subnet") if @subnet_id
+    parts.push("in the #{@security_group_id} security group") if 
@security_group_id
+    case @cloud_framework
+    when "ec2"
+      parts.push("in EC2")
+    end
+    parts.join(" ")
+  end
+
+  def save!
+    case @cloud_framework
+    when "ec2"
+      persist_to_pillar!(:cloud_worker_type, @instance_type)
+      persist_to_pillar!(:cloud_worker_subnet, @subnet_id)
+      persist_to_pillar!(:cloud_worker_security_group, @security_group_id)
+      Velum::Salt.call(action: "saltutil.refresh_pillar")
+    end
+  end
+
+  def save
+    save!
+    return true
+  rescue ActiveRecord::ActiveRecordError,
+         Velum::SaltApi::SaltConnectionException => e
+    errors[:base] << e.message
+    return false
+  end
+
+  private
+
+  def persist_to_pillar!(pillar_key, value)
+    pillar = Pillar.find_or_initialize_by(pillar: 
Pillar.all_pillars[pillar_key])
+    pillar.value = value
+    pillar.save!
+  end
+end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/velum-master/app/models/pillar.rb 
new/velum-master/app/models/pillar.rb
--- old/velum-master/app/models/pillar.rb       2018-02-15 16:53:11.000000000 
+0100
+++ new/velum-master/app/models/pillar.rb       2018-02-22 10:57:04.000000000 
+0100
@@ -13,6 +13,10 @@
     end
 
     def all_pillars
+      simple_pillars.merge(cloud_worker_pillars)
+    end
+
+    def simple_pillars
       {
         dashboard:                     "dashboard",
         dashboard_external_fqdn:       "dashboard_external_fqdn",
@@ -47,6 +51,19 @@
       }
     end
 
+    # rubocop:disable Layout/AlignHash
+    def cloud_worker_pillars
+      {
+        cloud_worker_type:
+          "cloud:profiles:cluster_node:size",
+        cloud_worker_subnet:
+          "cloud:profiles:cluster_node:network_interfaces:SubnetId",
+        cloud_worker_security_group:
+          "cloud:profiles:cluster_node:network_interfaces:SecurityGroupId"
+      }
+    end
+    # rubocop:enable Layout/AlignHash
+
     # Apply the given pillars into the database. It returns an array with the
     # encountered errors.
     def apply(pillars, required_pillars: [], unprotected_pillars: [])
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/velum-master/app/views/setup/_cluster_size_panel.html.slim 
new/velum-master/app/views/setup/_cluster_size_panel.html.slim
--- old/velum-master/app/views/setup/_cluster_size_panel.html.slim      
1970-01-01 01:00:00.000000000 +0100
+++ new/velum-master/app/views/setup/_cluster_size_panel.html.slim      
2018-02-22 10:57:04.000000000 +0100
@@ -0,0 +1,16 @@
+.panel.panel-default
+  .panel-heading
+    h3.panel-title Cluster size
+  .panel-body.cluster-size-selector
+    .col-md-8
+      label for="cloud_cluster_instance_count" Number of instances
+      = form.text_field :instance_count, data: {slider_min: 3, slider_value: 
5, slider_max: 50, slider_scale: "logarithmic", slider_tooltip: "always", 
slider_tooltip_position: "bottom", slider_ticks: [3, 5, 10, 20, 50], 
slider_ticks_snap_bounds: 0.5}, class: 'h3'
+    .col-md-2.text-right.cluster-cpu-count
+      label Total vCPUs
+      label.h3#cluster-cpu-count = 0
+    .col-md-2.text-right.cluster-ram-size
+      label Total RAM
+      label.h3#cluster-ram-size data-bytes=0 = 0
+  .panel-footer
+    h4 Tip
+    p At least three nodes are required for a reliable cluster.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/velum-master/app/views/setup/_instance_type_panel.html.slim 
new/velum-master/app/views/setup/_instance_type_panel.html.slim
--- old/velum-master/app/views/setup/_instance_type_panel.html.slim     
1970-01-01 01:00:00.000000000 +0100
+++ new/velum-master/app/views/setup/_instance_type_panel.html.slim     
2018-02-22 10:57:04.000000000 +0100
@@ -0,0 +1,56 @@
+.panel.panel-default
+  .panel-heading
+    h3.panel-title Instance Type
+  .panel-body.instance-type-selector
+    .row
+      .col-md-8.instance-types
+        .form-group
+          - @instance_types.each do |instance_type|
+              label.instance-type
+                = form.radio_button :instance_type, instance_type.key
+                .instance-type-box
+                  = instance_type.category.name
+                  br
+                  small = instance_type.key
+                .definition
+                  h2 = instance_type.category.name
+                  h3 = instance_type.key
+                  p
+                    = instance_type.category.description
+                  p
+                    - instance_type.category.features.each do |feature|
+                      '
+                      span.label.label-default = feature
+
+                  dl
+                    dt vCPUs
+                    dd.vcpu-count(data-vcpus="#{instance_type.vcpu_count}")
+                      = pluralize(instance_type.vcpu_count, 'core')
+                    dt RAM
+                    dd.ram-size(data-bytes="#{instance_type.ram_bytes}"
+                                data-si="#{instance_type.ram_si_units}")
+                    - instance_type.details.each do |key, value|
+                      dt
+                        = key
+                      dd
+                        = value
+          label.instance-type
+            = form.radio_button :instance_type, 'CUSTOM'
+            .instance-type-box.double
+              ' Other types&hellip;
+              br
+              br
+              small = form.text_field :instance_type_custom, class: 
"form-control", style: "display: none;"
+            .definition
+              p
+                ' You may specify a preferred instance type with a minimum of
+                '  are 2 vCPUs and 8GB of RAM; 4 vCPUs are recommended.
+
+
+      .col-md-4.instance-type-description
+  .panel-footer
+    h4 Tip
+    p
+      ' Not sure which type of instance to use? Check the
+      = link_to "Instance Types", list_url
+      '  list.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/velum-master/app/views/setup/worker_bootstrap_ec2.html.slim 
new/velum-master/app/views/setup/worker_bootstrap_ec2.html.slim
--- old/velum-master/app/views/setup/worker_bootstrap_ec2.html.slim     
1970-01-01 01:00:00.000000000 +0100
+++ new/velum-master/app/views/setup/worker_bootstrap_ec2.html.slim     
2018-02-22 10:57:04.000000000 +0100
@@ -0,0 +1,38 @@
+= content_for :body_class, "worker_bootstrap"
+
+h1
+  ' Bootstrap your CaaS Platform
+  small in Amazon Web Services' Elastic Compute Cloud
+
+
+= form_for @cloud_cluster, url: setup_build_cloud_cluster_path do |form|
+  = form.hidden_field :cloud_framework
+  p
+    ' In order to complete the installation, it is necessary to bootstrap a few
+    ' additional nodes, those will be the Kubernetes Master and Workers.
+
+  = render "instance_type_panel",
+    form: form,
+    list_url: "https://aws.amazon.com/ec2/instance-types/";
+
+  = render "cluster_size_panel", form: form
+
+  .panel.panel-default
+    .panel-heading
+      h3.panel-title Networking
+    .panel-body
+      .col-md-4
+        .form-group
+          label for="cloud_cluster_subnet_id" Subnet ID
+          = form.text_field :subnet_id, class: "form-control"
+      .col-md-4
+        .form-group
+          label for="cloud_cluster_security_group_id" Security Group ID
+          = form.text_field :security_group_id, class: "form-control"
+
+  .clearfix.text-right.steps-container
+    = link_to "Back", setup_path, class: "btn btn-danger"
+    = form.submit "Next", class: "btn btn-primary"
+
+- content_for :page_javascript do
+  = javascript_include_tag 'cloud/bootstrap', defer: true
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/velum-master/config/initializers/assets.rb 
new/velum-master/config/initializers/assets.rb
--- old/velum-master/config/initializers/assets.rb      2018-02-15 
16:53:11.000000000 +0100
+++ new/velum-master/config/initializers/assets.rb      2018-02-22 
10:57:04.000000000 +0100
@@ -9,4 +9,7 @@
 # Precompile additional assets.
 # application.js, application.css, and all non-JS/CSS in app/assets folder are 
already added.
 # Rails.application.config.assets.precompile += %w( search.js )
-Rails.application.config.assets.precompile += ["authentication.css"]
+Rails.application.config.assets.precompile += [
+  "authentication.css",
+  "cloud/bootstrap.js"
+]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/velum-master/config/routes.rb 
new/velum-master/config/routes.rb
--- old/velum-master/config/routes.rb   2018-02-15 16:53:11.000000000 +0100
+++ new/velum-master/config/routes.rb   2018-02-22 10:57:04.000000000 +0100
@@ -37,7 +37,8 @@
   namespace :setup do
     get "/", action: :welcome
     match "/", action: :configure, via: [:put, :patch]
-    get :"worker-bootstrap"
+    get  "worker-bootstrap"
+    post :build_cloud_cluster
     get :discovery
     post :discovery, action: :set_roles
     get :bootstrap
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/velum-master/lib/velum/salt.rb 
new/velum-master/lib/velum/salt.rb
--- old/velum-master/lib/velum/salt.rb  2018-02-15 16:53:11.000000000 +0100
+++ new/velum-master/lib/velum/salt.rb  2018-02-22 10:57:04.000000000 +0100
@@ -1,4 +1,5 @@
 require "velum/salt_api"
+require "securerandom"
 
 module Velum
   # This class allows to interact with global salt actions
@@ -34,6 +35,23 @@
       [needed["return"], failed["return"]]
     end
 
+    # Trigger salt-cloud to construct a cluster
+    def self.build_cloud_cluster(count)
+      instance_names = (1..count).collect { "caasp-node-" + 
SecureRandom.hex(4) }
+      instance_names.collect do |instance_name|
+        perform_request(
+          endpoint: "/",
+          method:   "post",
+          data:     {
+            client: "local_async",
+            tgt:    "admin",
+            fun:    "cloud.profile",
+            arg:    ["cluster_node", instance_name]
+          }
+        )
+      end
+    end
+
     # Returns the minions as discovered by salt.
     def self.minions
       res = perform_request(endpoint: "/minions", method: "get")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/velum-master/spec/controllers/internal_api/v1/pillars_controller_spec.rb 
new/velum-master/spec/controllers/internal_api/v1/pillars_controller_spec.rb
--- 
old/velum-master/spec/controllers/internal_api/v1/pillars_controller_spec.rb    
    2018-02-15 16:53:11.000000000 +0100
+++ 
new/velum-master/spec/controllers/internal_api/v1/pillars_controller_spec.rb    
    2018-02-22 10:57:04.000000000 +0100
@@ -74,4 +74,56 @@
       expect(json).to match expected_registries_response
     end
   end
+
+  context "when in EC2 framework" do
+    let(:custom_instance_type) { "custom-instance-type" }
+    let(:subnet_id) { "subnet-9d4a7b6c" }
+    let(:security_group_id) { "sg-903004f8" }
+
+    let(:expected_response) do
+      {
+        registries: [],
+        cloud:      {
+          framework: "ec2",
+          profiles:  {
+            cluster_node: {
+              size:               custom_instance_type,
+              network_interfaces: [
+                {
+                  DeviceIndex:              0,
+                  AssociatePublicIpAddress: false,
+                  SubnetId:                 subnet_id,
+                  SecurityGroupId:          security_group_id
+                }
+              ]
+            }
+          }
+        }
+      }
+    end
+
+    before do
+      create(:ec2_pillar)
+      create(
+        :pillar,
+        pillar: "cloud:profiles:cluster_node:size",
+        value:  custom_instance_type
+      )
+      create(
+        :pillar,
+        pillar: "cloud:profiles:cluster_node:network_interfaces:SubnetId",
+        value:  subnet_id
+      )
+      create(
+        :pillar,
+        pillar: 
"cloud:profiles:cluster_node:network_interfaces:SecurityGroupId",
+        value:  security_group_id
+      )
+    end
+
+    it "has remote registries and respective mirrors" do
+      get :show
+      expect(json).to eq(expected_response)
+    end
+  end
 end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/velum-master/spec/controllers/setup_controller_spec.rb 
new/velum-master/spec/controllers/setup_controller_spec.rb
--- old/velum-master/spec/controllers/setup_controller_spec.rb  2018-02-15 
16:53:11.000000000 +0100
+++ new/velum-master/spec/controllers/setup_controller_spec.rb  2018-02-22 
10:57:04.000000000 +0100
@@ -88,6 +88,104 @@
       get :worker_bootstrap
       expect(assigns(:controller_node)).to eq("localhost")
     end
+
+    context "when in EC2 framework" do
+      before do
+        create(:ec2_pillar)
+        get :worker_bootstrap
+      end
+
+      it "assigns @instance_sizes" do
+        expect(assigns(:instance_types)).to all(be_a(Velum::InstanceType))
+      end
+
+      it "renders EC2 view" do
+        expect(response).to render_template(:worker_bootstrap_ec2)
+      end
+    end
+  end
+
+  describe "POST /setup/worker-boostrap via HTML in EC2" do
+    let(:instance_type) { "t2.xlarge" }
+    let(:instance_count) { 5 }
+    let(:subnet_id) { "subnet-9d4a7b6c" }
+    let(:security_group_id) { "sg-903004f8" }
+    let(:cloud_cluster_params) do
+      {
+        instance_type:     instance_type,
+        instance_count:    instance_count,
+        subnet_id:         subnet_id,
+        security_group_id: security_group_id
+      }
+    end
+
+    before do
+      sign_in user
+      create(:ec2_pillar)
+      Pillar.create pillar: "dashboard", value: "localhost"
+
+      allow(Velum::Salt).to receive(:build_cloud_cluster)
+    end
+
+    context "when saving succeeds" do
+      before do
+        ensure_pillar_refresh do
+          post :build_cloud_cluster, cloud_cluster: cloud_cluster_params
+        end
+      end
+
+      it "always uses the framework pillar" do
+        expect(assigns(:cloud_cluster).cloud_framework).to eq("ec2")
+      end
+
+      it "assigns the instance type" do
+        expect(assigns(:cloud_cluster).instance_type).to eq(instance_type)
+      end
+
+      it "assigns the quantity of workers" do
+        expect(assigns(:cloud_cluster).instance_count).to eq(instance_count)
+      end
+
+      it "assigns the EC2 subnet ID" do
+        expect(assigns(:cloud_cluster).subnet_id).to eq(subnet_id)
+      end
+
+      it "assigns the EC2 security group ID" do
+        expect(assigns(:cloud_cluster).security_group_id).to 
eq(security_group_id)
+      end
+
+      it "calls salt-cloud" do
+        expect(Velum::Salt).to 
have_received(:build_cloud_cluster).with(instance_count).once
+      end
+
+      it "uses a flash to provide confirmation" do
+        expect(flash[:notice]).to be_present
+      end
+    end
+
+    context "when saving fails" do
+      let(:error_message) { "Nope!" }
+      let(:mock_cloud_cluster) do
+        mock = CloudCluster.new(cloud_cluster_params)
+        allow(mock).to receive(:save!).and_raise(
+          ActiveRecord::ActiveRecordError.new(error_message)
+        )
+        mock
+      end
+
+      before do
+        allow(CloudCluster).to receive(:new).and_return(mock_cloud_cluster)
+        post :build_cloud_cluster, cloud_cluster: cloud_cluster_params
+      end
+
+      it "redirects back to bootstrap" do
+        expect(controller).to redirect_to(:setup_worker_bootstrap)
+      end
+
+      it "uses a flash to show error messages" do
+        expect(flash[:error]).to be_present
+      end
+    end
   end
 
   describe "POST /setup/discovery via HTML" do
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/velum-master/spec/factories/pillar_factory.rb 
new/velum-master/spec/factories/pillar_factory.rb
--- old/velum-master/spec/factories/pillar_factory.rb   2018-02-15 
16:53:11.000000000 +0100
+++ new/velum-master/spec/factories/pillar_factory.rb   2018-02-22 
10:57:04.000000000 +0100
@@ -7,4 +7,8 @@
     pillar { Pillar.all_pillars[:apiserver] }
     value  "myapiserver.example.com"
   end
+  factory :ec2_pillar, parent: :pillar do
+    pillar { Pillar.all_pillars[:cloud_framework] }
+    value  "ec2"
+  end
 end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/velum-master/spec/features/bootstrap_in_ec2_feature_spec.rb 
new/velum-master/spec/features/bootstrap_in_ec2_feature_spec.rb
--- old/velum-master/spec/features/bootstrap_in_ec2_feature_spec.rb     
1970-01-01 01:00:00.000000000 +0100
+++ new/velum-master/spec/features/bootstrap_in_ec2_feature_spec.rb     
2018-02-22 10:57:04.000000000 +0100
@@ -0,0 +1,70 @@
+require "rails_helper"
+require "velum/instance_type"
+
+describe "Feature: Bootstrap a cluster in EC2" do
+  let(:user) { create(:user) }
+  let(:instance_types) { Velum::InstanceType.for("ec2") }
+  let(:custom_instance_type) { OpenStruct.new(key: "CUSTOM") }
+
+  before do
+    login_as user, scope: :user
+    create(:ec2_pillar)
+    setup_stubbed_update_status!
+    visit setup_worker_bootstrap_path
+  end
+
+  it "refers to EC2 in the heading" do
+    expect(page).to have_css("h1", text: "Elastic Compute Cloud")
+  end
+
+  it "allows selection of an instance type" do
+    instance_types.each do |instance_type|
+      expect(page).to have_css(instance_type_radio_finder(instance_type))
+    end
+  end
+
+  it "displays the category of the selected instance type", js: true do
+    instance_types.each do |instance_type|
+      click_instance_type_radio(instance_type)
+      expect(page).to have_text(:visible, instance_type.category.name)
+      expect(page).to have_text(:visible, instance_type.category.description)
+    end
+  end
+
+  it "hides the custom instance type box by default", js: true do
+    expect(page).not_to 
have_css("input#cloud_cluster_instance_type_custom[type='text']")
+  end
+
+  it "shows the textbox when choosing a custom instance type", js: true do
+    click_instance_type_radio(custom_instance_type)
+    expect(page).to 
have_css("input#cloud_cluster_instance_type_custom[type='text']")
+  end
+
+  context "when sizing the cluster" do
+    let(:cluster_size) do
+      page.find("#cloud_cluster_instance_count", visible: 
:any)["data-slider-value"].to_i
+    end
+
+    it "calculates the total cluster vCPU count", js: true do
+      instance_types.each do |instance_type|
+        total = instance_type.vcpu_count * cluster_size
+        click_instance_type_radio(instance_type)
+        expect(page).to have_css("#cluster-cpu-count", text: total)
+      end
+    end
+
+    it "calculates the total cluster RAM size", js: true do
+      instance_types.each do |instance_type|
+        total = instance_type.ram_bytes * cluster_size
+        click_instance_type_radio(instance_type)
+        expect(page.find("#cluster-ram-size")["data-bytes"].to_i).to eq(total)
+      end
+    end
+
+    it "hides calculations for custom types", js: true do
+      click_instance_type_radio(custom_instance_type)
+      expect(page).not_to have_css("#cluster-cpu-count")
+      expect(page).not_to have_css("#cluster-ram-count")
+    end
+  end
+end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/velum-master/spec/lib/velum/salt_spec.rb 
new/velum-master/spec/lib/velum/salt_spec.rb
--- old/velum-master/spec/lib/velum/salt_spec.rb        2018-02-15 
16:53:11.000000000 +0100
+++ new/velum-master/spec/lib/velum/salt_spec.rb        2018-02-22 
10:57:04.000000000 +0100
@@ -76,4 +76,16 @@
       end
     end
   end
+
+  describe "#build_cloud_cluster" do
+    let(:count) { rand(49) + 1 } # 1..50
+
+    it "calls cloud.profile salt function the specified number of times" do
+      VCR.use_cassette("salt/cloud_profile", record: :none, 
allow_playback_repeats: true) do
+        responses = described_class.build_cloud_cluster(count)
+        expect(responses.length).to eq(count)
+        expect(responses).to all(be_a(Net::HTTPOK))
+      end
+    end
+  end
 end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/velum-master/spec/models/cloud_cluster_spec.rb 
new/velum-master/spec/models/cloud_cluster_spec.rb
--- old/velum-master/spec/models/cloud_cluster_spec.rb  1970-01-01 
01:00:00.000000000 +0100
+++ new/velum-master/spec/models/cloud_cluster_spec.rb  2018-02-22 
10:57:04.000000000 +0100
@@ -0,0 +1,116 @@
+require "rails_helper"
+require "velum/salt_api"
+
+describe CloudCluster do
+  let(:custom_instance_type) { "custom-instance-type" }
+  let(:subnet_id) { "subnet-9d4a7b6c" }
+  let(:security_group_id) { "sg-903004f8" }
+  let(:instance_count) { 5 }
+
+  it "can implicitly represent a custom instance type" do
+    cluster = described_class.new(instance_type_custom: custom_instance_type)
+    expect(cluster.instance_type).to be(custom_instance_type)
+  end
+
+  it "can explicity represent a custom instance type" do
+    cluster = described_class.new(
+      instance_type:        "CUSTOM",
+      instance_type_custom: custom_instance_type
+    )
+    expect(cluster.instance_type).to be(custom_instance_type)
+  end
+
+  context "when represented as a string" do
+    let(:cluster) do
+      described_class.new(
+        instance_type:     custom_instance_type,
+        instance_count:    instance_count,
+        subnet_id:         subnet_id,
+        security_group_id: security_group_id
+      )
+    end
+
+    it "counts out the instances" do
+      substring = "a cluster of #{instance_count} #{custom_instance_type} 
instances"
+      expect(cluster.to_s).to match(substring)
+    end
+
+    it "describes the subnet" do
+      substring = "in the #{subnet_id} subnet"
+      expect(cluster.to_s).to match(substring)
+    end
+
+    it "describes the security group" do
+      substring = "in the #{security_group_id} security group"
+      expect(cluster.to_s).to match(substring)
+    end
+  end
+
+  context "when saving, behave like ActiveRecord#save" do
+    let(:cluster) { described_class.new }
+    let(:handled_exceptions) do
+      [
+        ActiveRecord::ActiveRecordError.new("Didn't work!"),
+        Velum::SaltApi::SaltConnectionException.new("You're bad at this.")
+      ]
+    end
+
+    it "returns true" do
+      allow(cluster).to receive(:save!)
+      expect(cluster.save).to be(true)
+    end
+
+    it "returns false when there is an exception" do
+      handled_exceptions.each do |exception|
+        allow(cluster).to receive(:save!).and_raise(exception)
+        expect(cluster.save).to be(false)
+      end
+    end
+
+    it "captures downstream messages to the errors collection" do
+      handled_exceptions.each do |exception|
+        allow(cluster).to receive(:save!).and_raise(exception)
+        cluster.save
+        expect(cluster.errors[:base]).to include(exception.message)
+      end
+    end
+  end
+
+  context "when framework is EC2" do
+    let(:framework) { "ec2" }
+    let(:cluster) do
+      described_class.new(
+        cloud_framework:   framework,
+        instance_type:     custom_instance_type,
+        subnet_id:         subnet_id,
+        security_group_id: security_group_id
+      )
+    end
+
+    it "stores instance type as :cloud_worker_type Pillar and refreshes" do
+      ensure_pillar_refresh do
+        expect(cluster.save).to be(true)
+      end
+      expect(Pillar.value(pillar: :cloud_worker_type)).to 
eq(custom_instance_type)
+    end
+
+    it "stores subnet ID as :cloud_worker_subnet Pillar and refreshes" do
+      ensure_pillar_refresh do
+        expect(cluster.save).to be(true)
+      end
+      expect(Pillar.value(pillar: :cloud_worker_subnet)).to eq(subnet_id)
+    end
+
+    it "stores security group ID as :cloud_worker_security_group Pillar and 
refreshes" do
+      ensure_pillar_refresh do
+        expect(cluster.save).to be(true)
+      end
+      expect(Pillar.value(pillar: :cloud_worker_security_group)).to 
eq(security_group_id)
+    end
+
+    it "describes the framework in string representation" do
+      substring = "in EC2"
+      expect(cluster.to_s).to match(substring)
+    end
+  end
+end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/velum-master/spec/support/helpers.rb 
new/velum-master/spec/support/helpers.rb
--- old/velum-master/spec/support/helpers.rb    2018-02-15 16:53:11.000000000 
+0100
+++ new/velum-master/spec/support/helpers.rb    2018-02-22 10:57:04.000000000 
+0100
@@ -23,4 +23,16 @@
   end
 end
 
+def click_instance_type_radio(instance_type)
+  page.execute_script('$("' + instance_type_radio_finder(instance_type) + 
'").click()')
+end
+
+def instance_type_radio_finder(instance_type)
+  [
+    "input[type='radio']",
+    "[name='cloud_cluster[instance_type]']",
+    "[value='#{instance_type.key}']"
+  ].join
+end
+
 RSpec.configure { |config| config.include Helpers, type: :feature }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/velum-master/spec/support/utils.rb 
new/velum-master/spec/support/utils.rb
--- old/velum-master/spec/support/utils.rb      2018-02-15 16:53:11.000000000 
+0100
+++ new/velum-master/spec/support/utils.rb      2018-02-22 10:57:04.000000000 
+0100
@@ -19,6 +19,17 @@
   def setup_undone
     Pillar.delete_all
   end
+
+  def ensure_pillar_refresh
+    VCR.use_cassette(
+      "salt/refresh_pillar",
+      allow_unused_http_interactions: false,
+      allow_playback_repeats:         true,
+      record:                         :none
+    ) do
+      yield
+    end
+  end
 end
 
 RSpec.configure { |config| config.include Utils }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/velum-master/spec/vcr_cassettes/salt/cloud_profile.yml 
new/velum-master/spec/vcr_cassettes/salt/cloud_profile.yml
--- old/velum-master/spec/vcr_cassettes/salt/cloud_profile.yml  1970-01-01 
01:00:00.000000000 +0100
+++ new/velum-master/spec/vcr_cassettes/salt/cloud_profile.yml  2018-02-22 
10:57:04.000000000 +0100
@@ -0,0 +1,107 @@
+---
+http_interactions:
+- request:
+    method: post
+    uri: https://127.0.0.1:8000/login
+    body:
+      encoding: UTF-8
+      string: 
'{"username":"saltapi","password":"l+ZtDm9lG1DPdt/QyFfABgWtCN/IKwnmGTK8nCt++PiOVG9Y2NccIrozchvz7RtxREIZe5CshcO0","eauth":"pam"}'
+    headers:
+      Accept-Encoding:
+      - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
+      Accept:
+      - application/json; charset=utf-8
+      User-Agent:
+      - Ruby
+      Host:
+      - 127.0.0.1:8000
+      Content-Type:
+      - application/json; charset=utf-8
+  response:
+    status:
+      code: 200
+      message: OK
+    headers:
+      Content-Length:
+      - '217'
+      Access-Control-Expose-Headers:
+      - GET, POST
+      Vary:
+      - Accept-Encoding
+      Server:
+      - CherryPy/3.6.0
+      Allow:
+      - GET, HEAD, POST
+      Access-Control-Allow-Credentials:
+      - 'true'
+      Date:
+      - Mon, 05 Feb 2018 20:57:34 GMT
+      Access-Control-Allow-Origin:
+      - "*"
+      X-Auth-Token:
+      - 507fef45a35e7038c9a1cdb754acfc7539aac4a2
+      Content-Type:
+      - application/json
+      Set-Cookie:
+      - session_id=507fef45a35e7038c9a1cdb754acfc7539aac4a2; expires=Tue, 06 
Feb 2018
+        06:57:34 GMT; Path=/
+    body:
+      encoding: UTF-8
+      string: '{"return": [{"perms": [".*", "@wheel", "@runner", "@jobs", 
"@events"],
+        "start": 1517864254.835655, "token": 
"507fef45a35e7038c9a1cdb754acfc7539aac4a2",
+        "expire": 1517907454.835655, "user": "saltapi", "eauth": "pam"}]}'
+    http_version:
+  recorded_at: Mon, 05 Feb 2018 20:57:34 GMT
+- request:
+    method: post
+    uri: https://127.0.0.1:8000/
+    body:
+      encoding: UTF-8
+      string: 
'{"client":"local_async","tgt":"admin","fun":"cloud.profile","arg":["cluster_node","caasp-node-d43efb76"]}'
+    headers:
+      Accept-Encoding:
+      - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
+      Accept:
+      - application/json; charset=utf-8
+      User-Agent:
+      - Ruby
+      Host:
+      - 127.0.0.1:8000
+      Content-Type:
+      - application/json; charset=utf-8
+      X-Auth-Token:
+      - 507fef45a35e7038c9a1cdb754acfc7539aac4a2
+  response:
+    status:
+      code: 200
+      message: OK
+    headers:
+      Content-Length:
+      - '67'
+      Access-Control-Expose-Headers:
+      - GET, POST
+      Cache-Control:
+      - private
+      Vary:
+      - Accept-Encoding
+      Server:
+      - CherryPy/3.6.0
+      Allow:
+      - GET, HEAD, POST
+      Access-Control-Allow-Credentials:
+      - 'true'
+      Date:
+      - Mon, 05 Feb 2018 20:57:34 GMT
+      Access-Control-Allow-Origin:
+      - "*"
+      Content-Type:
+      - application/json
+      Set-Cookie:
+      - session_id=507fef45a35e7038c9a1cdb754acfc7539aac4a2; expires=Tue, 06 
Feb 2018
+        06:57:34 GMT; Path=/
+    body:
+      encoding: UTF-8
+      string: '{"return": [{"jid": "20180205205734878026", "minions": 
["admin"]}]}'
+    http_version:
+  recorded_at: Mon, 05 Feb 2018 20:57:34 GMT
+recorded_with: VCR 3.0.3
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/velum-master/spec/vcr_cassettes/salt/refresh_pillar.yml 
new/velum-master/spec/vcr_cassettes/salt/refresh_pillar.yml
--- old/velum-master/spec/vcr_cassettes/salt/refresh_pillar.yml 1970-01-01 
01:00:00.000000000 +0100
+++ new/velum-master/spec/vcr_cassettes/salt/refresh_pillar.yml 2018-02-22 
10:57:04.000000000 +0100
@@ -0,0 +1,107 @@
+---
+http_interactions:
+- request:
+    method: post
+    uri: https://127.0.0.1:8000/login
+    body:
+      encoding: UTF-8
+      string: 
'{"username":"saltapi","password":"x3NTblSaFzs2+SjtkW8zkUXL65L5AWbTPScpuzYkcDjmBMgvzixpuPTxDERT7Y1JEjqkMo7KG0+r","eauth":"pam"}'
+    headers:
+      Accept-Encoding:
+      - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
+      Accept:
+      - application/json; charset=utf-8
+      User-Agent:
+      - Ruby
+      Host:
+      - 127.0.0.1:8000
+      Content-Type:
+      - application/json; charset=utf-8
+  response:
+    status:
+      code: 200
+      message: OK
+    headers:
+      Content-Length:
+      - '216'
+      Access-Control-Expose-Headers:
+      - GET, POST
+      Vary:
+      - Accept-Encoding
+      Server:
+      - CherryPy/3.6.0
+      Allow:
+      - GET, HEAD, POST
+      Access-Control-Allow-Credentials:
+      - 'true'
+      Date:
+      - Sat, 27 Jan 2018 00:12:03 GMT
+      Access-Control-Allow-Origin:
+      - "*"
+      X-Auth-Token:
+      - cd96f194d3bb5a73ea6f5acd427abe4ff677cb27
+      Content-Type:
+      - application/json
+      Set-Cookie:
+      - session_id=cd96f194d3bb5a73ea6f5acd427abe4ff677cb27; expires=Sat, 27 
Jan 2018
+        10:12:03 GMT; Path=/
+    body:
+      encoding: UTF-8
+      string: '{"return": [{"perms": [".*", "@wheel", "@runner", "@jobs", 
"@events"],
+        "start": 1517011923.448009, "token": 
"cd96f194d3bb5a73ea6f5acd427abe4ff677cb27",
+        "expire": 1517055123.44801, "user": "saltapi", "eauth": "pam"}]}'
+    http_version:
+  recorded_at: Sat, 27 Jan 2018 00:12:03 GMT
+- request:
+    method: post
+    uri: https://127.0.0.1:8000/
+    body:
+      encoding: UTF-8
+      string: 
'{"tgt":"*","fun":"saltutil.refresh_pillar","expr_form":"glob","client":"local"}'
+    headers:
+      Accept-Encoding:
+      - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
+      Accept:
+      - application/json; charset=utf-8
+      User-Agent:
+      - Ruby
+      Host:
+      - 127.0.0.1:8000
+      Content-Type:
+      - application/json; charset=utf-8
+      X-Auth-Token:
+      - cd96f194d3bb5a73ea6f5acd427abe4ff677cb27
+  response:
+    status:
+      code: 200
+      message: OK
+    headers:
+      Content-Length:
+      - '41'
+      Access-Control-Expose-Headers:
+      - GET, POST
+      Cache-Control:
+      - private
+      Vary:
+      - Accept-Encoding
+      Server:
+      - CherryPy/3.6.0
+      Allow:
+      - GET, HEAD, POST
+      Access-Control-Allow-Credentials:
+      - 'true'
+      Date:
+      - Sat, 27 Jan 2018 00:12:03 GMT
+      Access-Control-Allow-Origin:
+      - "*"
+      Content-Type:
+      - application/json
+      Set-Cookie:
+      - session_id=cd96f194d3bb5a73ea6f5acd427abe4ff677cb27; expires=Sat, 27 
Jan 2018
+        10:12:03 GMT; Path=/
+    body:
+      encoding: UTF-8
+      string: '{"return": [{"admin": true, "ca": true}]}'
+    http_version:
+  recorded_at: Sat, 27 Jan 2018 00:12:04 GMT
+recorded_with: VCR 3.0.3
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/velum-master/vendor/assets/javascript/bootstrap-slider.min.js 
new/velum-master/vendor/assets/javascript/bootstrap-slider.min.js
--- old/velum-master/vendor/assets/javascript/bootstrap-slider.min.js   
1970-01-01 01:00:00.000000000 +0100
+++ new/velum-master/vendor/assets/javascript/bootstrap-slider.min.js   
2018-02-22 10:57:04.000000000 +0100
@@ -0,0 +1,5 @@
+/*! =======================================================
+                      VERSION  9.9.0              
+========================================================= */
+"use strict";var _typeof="function"==typeof Symbol&&"symbol"==typeof 
Symbol.iterator?function(a){return typeof a}:function(a){return 
a&&"function"==typeof 
Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?"symbol":typeof 
a},windowIsDefined="object"===("undefined"==typeof 
window?"undefined":_typeof(window));!function(a){if("function"==typeof 
define&&define.amd)define(["jquery"],a);else if("object"===("undefined"==typeof 
module?"undefined":_typeof(module))&&module.exports){var 
b;try{b=require("jquery")}catch(c){b=null}module.exports=a(b)}else 
window&&(window.Slider=a(window.jQuery))}(function(a){var 
b="slider",c="bootstrapSlider";windowIsDefined&&!window.console&&(window.console={}),windowIsDefined&&!window.console.log&&(window.console.log=function(){}),windowIsDefined&&!window.console.warn&&(window.console.warn=function(){});var
 d;return function(a){function b(){}function c(a){function 
c(b){b.prototype.option||(b.prototype.option=function(b){a.isPlainObject(b)&&(this.options=a.extend(!0,this.options,b))})}function
 e(b,c){a.fn[b]=function(e){if("string"==typeof e){for(var 
g=d.call(arguments,1),h=0,i=this.length;i>h;h++){var 
j=this[h],k=a.data(j,b);if(k)if(a.isFunction(k[e])&&"_"!==e.charAt(0)){var 
l=k[e].apply(k,g);if(void 0!==l&&l!==k)return l}else f("no such method '"+e+"' 
for "+b+" instance");else f("cannot call methods on "+b+" prior to 
initialization; attempted to call '"+e+"'")}return this}var 
m=this.map(function(){var d=a.data(this,b);return 
d?(d.option(e),d._init()):(d=new 
c(this,e),a.data(this,b,d)),a(this)});return!m||m.length>1?m:m[0]}}if(a){var 
f="undefined"==typeof console?b:function(a){console.error(a)};return 
a.bridget=function(a,b){c(b),e(a,b)},a.bridget}}var 
d=Array.prototype.slice;c(a)}(a),function(a){function e(b,c){function 
d(a,b){var c="data-slider-"+b.replace(/_/g,"-"),d=a.getAttribute(c);try{return 
JSON.parse(d)}catch(e){return 
d}}this._state={value:null,enabled:null,offset:null,size:null,percentage:null,inDrag:!1,over:!1},this.ticksCallbackMap={},this.handleCallbackMap={},"string"==typeof
 b?this.element=document.querySelector(b):b instanceof 
HTMLElement&&(this.element=b),c=c?c:{};for(var 
e=Object.keys(this.defaultOptions),f=0;f<e.length;f++){var 
h=e[f],i=c[h];i="undefined"!=typeof 
i?i:d(this.element,h),i=null!==i?i:this.defaultOptions[h],this.options||(this.options={}),this.options[h]=i}"auto"===this.options.rtl&&(this.options.rtl="rtl"===window.getComputedStyle(this.element).direction),"vertical"!==this.options.orientation||"top"!==this.options.tooltip_position&&"bottom"!==this.options.tooltip_position?"horizontal"!==this.options.orientation||"left"!==this.options.tooltip_position&&"right"!==this.options.tooltip_position||(this.options.tooltip_position="top"):this.options.rtl?this.options.tooltip_position="left":this.options.tooltip_position="right";var
 
j,k,l,m,n,o=this.element.style.width,p=!1,q=this.element.parentNode;if(this.sliderElem)p=!0;else{this.sliderElem=document.createElement("div"),this.sliderElem.className="slider";var
 
r=document.createElement("div");r.className="slider-track",k=document.createElement("div"),k.className="slider-track-low",j=document.createElement("div"),j.className="slider-selection",l=document.createElement("div"),l.className="slider-track-high",m=document.createElement("div"),m.className="slider-handle
 
min-slider-handle",m.setAttribute("role","slider"),m.setAttribute("aria-valuemin",this.options.min),m.setAttribute("aria-valuemax",this.options.max),n=document.createElement("div"),n.className="slider-handle
 
max-slider-handle",n.setAttribute("role","slider"),n.setAttribute("aria-valuemin",this.options.min),n.setAttribute("aria-valuemax",this.options.max),r.appendChild(k),r.appendChild(j),r.appendChild(l),this.rangeHighlightElements=[];var
 s=this.options.rangeHighlights;if(Array.isArray(s)&&s.length>0)for(var 
t=0;t<s.length;t++){var 
u=document.createElement("div"),v=s[t]["class"]||"";u.className="slider-rangeHighlight
 slider-selection "+v,this.rangeHighlightElements.push(u),r.appendChild(u)}var 
w=Array.isArray(this.options.labelledby);if(w&&this.options.labelledby[0]&&m.setAttribute("aria-labelledby",this.options.labelledby[0]),w&&this.options.labelledby[1]&&n.setAttribute("aria-labelledby",this.options.labelledby[1]),!w&&this.options.labelledby&&(m.setAttribute("aria-labelledby",this.options.labelledby),n.setAttribute("aria-labelledby",this.options.labelledby)),this.ticks=[],Array.isArray(this.options.ticks)&&this.options.ticks.length>0){for(this.ticksContainer=document.createElement("div"),this.ticksContainer.className="slider-tick-container",f=0;f<this.options.ticks.length;f++){var
 
x=document.createElement("div");if(x.className="slider-tick",this.options.ticks_tooltip){var
 
y=this._addTickListener(),z=y.addMouseEnter(this,x,f),A=y.addMouseLeave(this,x);this.ticksCallbackMap[f]={mouseEnter:z,mouseLeave:A}}this.ticks.push(x),this.ticksContainer.appendChild(x)}j.className+="
 
tick-slider-selection"}if(this.tickLabels=[],Array.isArray(this.options.ticks_labels)&&this.options.ticks_labels.length>0)for(this.tickLabelContainer=document.createElement("div"),this.tickLabelContainer.className="slider-tick-label-container",f=0;f<this.options.ticks_labels.length;f++){var
 
B=document.createElement("div"),C=0===this.options.ticks_positions.length,D=this.options.reversed&&C?this.options.ticks_labels.length-(f+1):f;B.className="slider-tick-label",B.innerHTML=this.options.ticks_labels[D],this.tickLabels.push(B),this.tickLabelContainer.appendChild(B)}var
 E=function(a){var 
b=document.createElement("div");b.className="tooltip-arrow";var 
c=document.createElement("div");c.className="tooltip-inner",a.appendChild(b),a.appendChild(c)},F=document.createElement("div");F.className="tooltip
 tooltip-main",F.setAttribute("role","presentation"),E(F);var 
G=document.createElement("div");G.className="tooltip 
tooltip-min",G.setAttribute("role","presentation"),E(G);var 
H=document.createElement("div");H.className="tooltip 
tooltip-max",H.setAttribute("role","presentation"),E(H),this.sliderElem.appendChild(r),this.sliderElem.appendChild(F),this.sliderElem.appendChild(G),this.sliderElem.appendChild(H),this.tickLabelContainer&&this.sliderElem.appendChild(this.tickLabelContainer),this.ticksContainer&&this.sliderElem.appendChild(this.ticksContainer),this.sliderElem.appendChild(m),this.sliderElem.appendChild(n),q.insertBefore(this.sliderElem,this.element),this.element.style.display="none"}if(a&&(this.$element=a(this.element),this.$sliderElem=a(this.sliderElem)),this.eventToCallbackMap={},this.sliderElem.id=this.options.id,this.touchCapable="ontouchstart"in
 window||window.DocumentTouch&&document instanceof 
window.DocumentTouch,this.touchX=0,this.touchY=0,this.tooltip=this.sliderElem.querySelector(".tooltip-main"),this.tooltipInner=this.tooltip.querySelector(".tooltip-inner"),this.tooltip_min=this.sliderElem.querySelector(".tooltip-min"),this.tooltipInner_min=this.tooltip_min.querySelector(".tooltip-inner"),this.tooltip_max=this.sliderElem.querySelector(".tooltip-max"),this.tooltipInner_max=this.tooltip_max.querySelector(".tooltip-inner"),g[this.options.scale]&&(this.options.scale=g[this.options.scale]),p===!0&&(this._removeClass(this.sliderElem,"slider-horizontal"),this._removeClass(this.sliderElem,"slider-vertical"),this._removeClass(this.sliderElem,"slider-rtl"),this._removeClass(this.tooltip,"hide"),this._removeClass(this.tooltip_min,"hide"),this._removeClass(this.tooltip_max,"hide"),["left","right","top","width","height"].forEach(function(a){this._removeProperty(this.trackLow,a),this._removeProperty(this.trackSelection,a),this._removeProperty(this.trackHigh,a)},this),[this.handle1,this.handle2].forEach(function(a){this._removeProperty(a,"left"),this._removeProperty(a,"right"),this._removeProperty(a,"top")},this),[this.tooltip,this.tooltip_min,this.tooltip_max].forEach(function(a){this._removeProperty(a,"left"),this._removeProperty(a,"right"),this._removeProperty(a,"top"),this._removeProperty(a,"margin-left"),this._removeProperty(a,"margin-right"),this._removeProperty(a,"margin-top"),this._removeClass(a,"right"),this._removeClass(a,"left"),this._removeClass(a,"top")},this)),"vertical"===this.options.orientation?(this._addClass(this.sliderElem,"slider-vertical"),this.stylePos="top",this.mousePos="pageY",this.sizePos="offsetHeight"):(this._addClass(this.sliderElem,"slider-horizontal"),this.sliderElem.style.width=o,this.options.orientation="horizontal",this.options.rtl?this.stylePos="right":this.stylePos="left",this.mousePos="pageX",this.sizePos="offsetWidth"),this.options.rtl&&this._addClass(this.sliderElem,"slider-rtl"),this._setTooltipPosition(),Array.isArray(this.options.ticks)&&this.options.ticks.length>0&&(this.options.max=Math.max.apply(Math,this.options.ticks),this.options.min=Math.min.apply(Math,this.options.ticks)),Array.isArray(this.options.value)?(this.options.range=!0,this._state.value=this.options.value):this.options.range?this._state.value=[this.options.value,this.options.max]:this._state.value=this.options.value,this.trackLow=k||this.trackLow,this.trackSelection=j||this.trackSelection,this.trackHigh=l||this.trackHigh,"none"===this.options.selection?(this._addClass(this.trackLow,"hide"),this._addClass(this.trackSelection,"hide"),this._addClass(this.trackHigh,"hide")):("after"===this.options.selection||"before"===this.options.selection)&&(this._removeClass(this.trackLow,"hide"),this._removeClass(this.trackSelection,"hide"),this._removeClass(this.trackHigh,"hide")),this.handle1=m||this.handle1,this.handle2=n||this.handle2,p===!0)for(this._removeClass(this.handle1,"round
 triangle"),this._removeClass(this.handle2,"round triangle 
hide"),f=0;f<this.ticks.length;f++)this._removeClass(this.ticks[f],"round 
triangle hide");var 
I=["round","triangle","custom"],J=-1!==I.indexOf(this.options.handle);if(J)for(this._addClass(this.handle1,this.options.handle),this._addClass(this.handle2,this.options.handle),f=0;f<this.ticks.length;f++)this._addClass(this.ticks[f],this.options.handle);if(this._state.offset=this._offset(this.sliderElem),this._state.size=this.sliderElem[this.sizePos],this.setValue(this._state.value),this.handle1Keydown=this._keydown.bind(this,0),this.handle1.addEventListener("keydown",this.handle1Keydown,!1),this.handle2Keydown=this._keydown.bind(this,1),this.handle2.addEventListener("keydown",this.handle2Keydown,!1),this.mousedown=this._mousedown.bind(this),this.touchstart=this._touchstart.bind(this),this.touchmove=this._touchmove.bind(this),this.touchCapable){var
 K=!1;try{var 
L=Object.defineProperty({},"passive",{get:function(){K=!0}});window.addEventListener("test",null,L)}catch(M){}var
 
N=K?{passive:!0}:!1;this.sliderElem.addEventListener("touchstart",this.touchstart,N),this.sliderElem.addEventListener("touchmove",this.touchmove,N)}if(this.sliderElem.addEventListener("mousedown",this.mousedown,!1),this.resize=this._resize.bind(this),window.addEventListener("resize",this.resize,!1),"hide"===this.options.tooltip)this._addClass(this.tooltip,"hide"),this._addClass(this.tooltip_min,"hide"),this._addClass(this.tooltip_max,"hide");else
 
if("always"===this.options.tooltip)this._showTooltip(),this._alwaysShowTooltip=!0;else{if(this.showTooltip=this._showTooltip.bind(this),this.hideTooltip=this._hideTooltip.bind(this),this.options.ticks_tooltip){var
 
O=this._addTickListener(),P=O.addMouseEnter(this,this.handle1),Q=O.addMouseLeave(this,this.handle1);this.handleCallbackMap.handle1={mouseEnter:P,mouseLeave:Q},P=O.addMouseEnter(this,this.handle2),Q=O.addMouseLeave(this,this.handle2),this.handleCallbackMap.handle2={mouseEnter:P,mouseLeave:Q}}else
 
this.sliderElem.addEventListener("mouseenter",this.showTooltip,!1),this.sliderElem.addEventListener("mouseleave",this.hideTooltip,!1);this.handle1.addEventListener("focus",this.showTooltip,!1),this.handle1.addEventListener("blur",this.hideTooltip,!1),this.handle2.addEventListener("focus",this.showTooltip,!1),this.handle2.addEventListener("blur",this.hideTooltip,!1)}this.options.enabled?this.enable():this.disable()}var
 f={formatInvalidInputErrorMsg:function(a){return"Invalid input value '"+a+"' 
passed in"},callingContextNotSliderInstance:"Calling context element does not 
have instance of Slider bound to it. Check your code to make sure the JQuery 
object returned from the call to the slider() initializer is calling the 
method"},g={linear:{toValue:function(a){var 
b=a/100*(this.options.max-this.options.min),c=!0;if(this.options.ticks_positions.length>0){for(var
 
d,e,f,g=0,h=1;h<this.options.ticks_positions.length;h++)if(a<=this.options.ticks_positions[h]){d=this.options.ticks[h-1],f=this.options.ticks_positions[h-1],e=this.options.ticks[h],g=this.options.ticks_positions[h];break}var
 i=(a-f)/(g-f);b=d+i*(e-d),c=!1}var 
j=c?this.options.min:0,k=j+Math.round(b/this.options.step)*this.options.step;return
 
k<this.options.min?this.options.min:k>this.options.max?this.options.max:k},toPercentage:function(a){if(this.options.max===this.options.min)return
 0;if(this.options.ticks_positions.length>0){for(var 
b,c,d,e=0,f=0;f<this.options.ticks.length;f++)if(a<=this.options.ticks[f]){b=f>0?this.options.ticks[f-1]:0,d=f>0?this.options.ticks_positions[f-1]:0,c=this.options.ticks[f],e=this.options.ticks_positions[f];break}if(f>0){var
 g=(a-b)/(c-b);return d+g*(e-d)}}return 
100*(a-this.options.min)/(this.options.max-this.options.min)}},logarithmic:{toValue:function(a){var
 
b=0===this.options.min?0:Math.log(this.options.min),c=Math.log(this.options.max),d=Math.exp(b+(c-b)*a/100);return
 
Math.round(d)===this.options.max?this.options.max:(d=this.options.min+Math.round((d-this.options.min)/this.options.step)*this.options.step,d<this.options.min?this.options.min:d>this.options.max?this.options.max:d)},toPercentage:function(a){if(this.options.max===this.options.min)return
 0;var 
b=Math.log(this.options.max),c=0===this.options.min?0:Math.log(this.options.min),d=0===a?0:Math.log(a);return
 100*(d-c)/(b-c)}}};if(d=function(a,b){return 
e.call(this,a,b),this},d.prototype={_init:function(){},constructor:d,defaultOptions:{id:"",min:0,max:10,step:1,precision:0,orientation:"horizontal",value:5,range:!1,selection:"before",tooltip:"show",tooltip_split:!1,handle:"round",reversed:!1,rtl:"auto",enabled:!0,formatter:function(a){return
 Array.isArray(a)?a[0]+" : 
"+a[1]:a},natural_arrow_keys:!1,ticks:[],ticks_positions:[],ticks_labels:[],ticks_snap_bounds:0,ticks_tooltip:!1,scale:"linear",focus:!1,tooltip_position:null,labelledby:null,rangeHighlights:[]},getElement:function(){return
 this.sliderElem},getValue:function(){return 
this.options.range?this._state.value:this._state.value[0]},setValue:function(a,b,c){a||(a=0);var
 d=this.getValue();this._state.value=this._validateInputValue(a);var 
e=this._applyPrecision.bind(this);this.options.range?(this._state.value[0]=e(this._state.value[0]),this._state.value[1]=e(this._state.value[1]),this._state.value[0]=Math.max(this.options.min,Math.min(this.options.max,this._state.value[0])),this._state.value[1]=Math.max(this.options.min,Math.min(this.options.max,this._state.value[1]))):(this._state.value=e(this._state.value),this._state.value=[Math.max(this.options.min,Math.min(this.options.max,this._state.value))],this._addClass(this.handle2,"hide"),"after"===this.options.selection?this._state.value[1]=this.options.max:this._state.value[1]=this.options.min),this.options.max>this.options.min?this._state.percentage=[this._toPercentage(this._state.value[0]),this._toPercentage(this._state.value[1]),100*this.options.step/(this.options.max-this.options.min)]:this._state.percentage=[0,0,100],this._layout();var
 f=this.options.range?this._state.value:this._state.value[0];return 
this._setDataVal(f),b===!0&&this._trigger("slide",f),d!==f&&c===!0&&this._trigger("change",{oldValue:d,newValue:f}),this},destroy:function(){this._removeSliderEventHandlers(),this.sliderElem.parentNode.removeChild(this.sliderElem),this.element.style.display="",this._cleanUpEventCallbacksMap(),this.element.removeAttribute("data"),a&&(this._unbindJQueryEventHandlers(),this.$element.removeData("slider"))},disable:function(){return
 
this._state.enabled=!1,this.handle1.removeAttribute("tabindex"),this.handle2.removeAttribute("tabindex"),this._addClass(this.sliderElem,"slider-disabled"),this._trigger("slideDisabled"),this},enable:function(){return
 
this._state.enabled=!0,this.handle1.setAttribute("tabindex",0),this.handle2.setAttribute("tabindex",0),this._removeClass(this.sliderElem,"slider-disabled"),this._trigger("slideEnabled"),this},toggle:function(){return
 
this._state.enabled?this.disable():this.enable(),this},isEnabled:function(){return
 this._state.enabled},on:function(a,b){return 
this._bindNonQueryEventHandler(a,b),this},off:function(b,c){a?(this.$element.off(b,c),this.$sliderElem.off(b,c)):this._unbindNonQueryEventHandler(b,c)},getAttribute:function(a){return
 a?this.options[a]:this.options},setAttribute:function(a,b){return 
this.options[a]=b,this},refresh:function(){return 
this._removeSliderEventHandlers(),e.call(this,this.element,this.options),a&&a.data(this.element,"slider",this),this},relayout:function(){return
 
this._resize(),this._layout(),this},_removeSliderEventHandlers:function(){if(this.handle1.removeEventListener("keydown",this.handle1Keydown,!1),this.handle2.removeEventListener("keydown",this.handle2Keydown,!1),this.options.ticks_tooltip){for(var
 
a=this.ticksContainer.getElementsByClassName("slider-tick"),b=0;b<a.length;b++)a[b].removeEventListener("mouseenter",this.ticksCallbackMap[b].mouseEnter,!1),a[b].removeEventListener("mouseleave",this.ticksCallbackMap[b].mouseLeave,!1);this.handle1.removeEventListener("mouseenter",this.handleCallbackMap.handle1.mouseEnter,!1),this.handle2.removeEventListener("mouseenter",this.handleCallbackMap.handle2.mouseEnter,!1),this.handle1.removeEventListener("mouseleave",this.handleCallbackMap.handle1.mouseLeave,!1),this.handle2.removeEventListener("mouseleave",this.handleCallbackMap.handle2.mouseLeave,!1)}this.handleCallbackMap=null,this.ticksCallbackMap=null,this.showTooltip&&(this.handle1.removeEventListener("focus",this.showTooltip,!1),this.handle2.removeEventListener("focus",this.showTooltip,!1)),this.hideTooltip&&(this.handle1.removeEventListener("blur",this.hideTooltip,!1),this.handle2.removeEventListener("blur",this.hideTooltip,!1)),this.showTooltip&&this.sliderElem.removeEventListener("mouseenter",this.showTooltip,!1),this.hideTooltip&&this.sliderElem.removeEventListener("mouseleave",this.hideTooltip,!1),this.sliderElem.removeEventListener("touchstart",this.touchstart,!1),this.sliderElem.removeEventListener("touchmove",this.touchmove,!1),this.sliderElem.removeEventListener("mousedown",this.mousedown,!1),window.removeEventListener("resize",this.resize,!1)},_bindNonQueryEventHandler:function(a,b){void
 
0===this.eventToCallbackMap[a]&&(this.eventToCallbackMap[a]=[]),this.eventToCallbackMap[a].push(b)},_unbindNonQueryEventHandler:function(a,b){var
 c=this.eventToCallbackMap[a];if(void 0!==c)for(var 
d=0;d<c.length;d++)if(c[d]===b){c.splice(d,1);break}},_cleanUpEventCallbacksMap:function(){for(var
 a=Object.keys(this.eventToCallbackMap),b=0;b<a.length;b++){var c=a[b];delete 
this.eventToCallbackMap[c]}},_showTooltip:function(){this.options.tooltip_split===!1?(this._addClass(this.tooltip,"in"),this.tooltip_min.style.display="none",this.tooltip_max.style.display="none"):(this._addClass(this.tooltip_min,"in"),this._addClass(this.tooltip_max,"in"),this.tooltip.style.display="none"),this._state.over=!0},_hideTooltip:function(){this._state.inDrag===!1&&this.alwaysShowTooltip!==!0&&(this._removeClass(this.tooltip,"in"),this._removeClass(this.tooltip_min,"in"),this._removeClass(this.tooltip_max,"in")),this._state.over=!1},_setToolTipOnMouseOver:function(a){function
 b(a,b){return 
b?[100-a.percentage[0],this.options.range?100-a.percentage[1]:a.percentage[1]]:[a.percentage[0],a.percentage[1]]}var
 
c=this.options.formatter(a?a.value[0]:this._state.value[0]),d=a?b(a,this.options.reversed):b(this._state,this.options.reversed);this._setText(this.tooltipInner,c),this.tooltip.style[this.stylePos]=d[0]+"%","vertical"===this.options.orientation?this._css(this.tooltip,"margin-"+this.stylePos,-this.tooltip.offsetHeight/2+"px"):this._css(this.tooltip,"margin-"+this.stylePos,-this.tooltip.offsetWidth/2+"px")},_addTickListener:function(){return{addMouseEnter:function(a,b,c){var
 d=function(){var 
b=a._state,d=c>=0?c:this.attributes["aria-valuenow"].value,e=parseInt(d,10);b.value[0]=e,b.percentage[0]=a.options.ticks_positions[e],a._setToolTipOnMouseOver(b),a._showTooltip()};return
 b.addEventListener("mouseenter",d,!1),d},addMouseLeave:function(a,b){var 
c=function(){a._hideTooltip()};return 
b.addEventListener("mouseleave",c,!1),c}}},_layout:function(){var 
a;if(a=this.options.reversed?[100-this._state.percentage[0],this.options.range?100-this._state.percentage[1]:this._state.percentage[1]]:[this._state.percentage[0],this._state.percentage[1]],this.handle1.style[this.stylePos]=a[0]+"%",this.handle1.setAttribute("aria-valuenow",this._state.value[0]),isNaN(this.options.formatter(this._state.value[0]))&&this.handle1.setAttribute("aria-valuetext",this.options.formatter(this._state.value[0])),this.handle2.style[this.stylePos]=a[1]+"%",this.handle2.setAttribute("aria-valuenow",this._state.value[1]),isNaN(this.options.formatter(this._state.value[1]))&&this.handle2.setAttribute("aria-valuetext",this.options.formatter(this._state.value[1])),this.rangeHighlightElements.length>0&&Array.isArray(this.options.rangeHighlights)&&this.options.rangeHighlights.length>0)for(var
 b=0;b<this.options.rangeHighlights.length;b++){var 
c=this._toPercentage(this.options.rangeHighlights[b].start),d=this._toPercentage(this.options.rangeHighlights[b].end);if(this.options.reversed){var
 e=100-d;d=100-c,c=e}var 
f=this._createHighlightRange(c,d);f?"vertical"===this.options.orientation?(this.rangeHighlightElements[b].style.top=f.start+"%",this.rangeHighlightElements[b].style.height=f.size+"%"):(this.options.rtl?this.rangeHighlightElements[b].style.right=f.start+"%":this.rangeHighlightElements[b].style.left=f.start+"%",this.rangeHighlightElements[b].style.width=f.size+"%"):this.rangeHighlightElements[b].style.display="none"}if(Array.isArray(this.options.ticks)&&this.options.ticks.length>0){var
 
g,h="vertical"===this.options.orientation?"height":"width";g="vertical"===this.options.orientation?"marginTop":this.options.rtl?"marginRight":"marginLeft";var
 
i=this._state.size/(this.options.ticks.length-1);if(this.tickLabelContainer){var
 
j=0;if(0===this.options.ticks_positions.length)"vertical"!==this.options.orientation&&(this.tickLabelContainer.style[g]=-i/2+"px"),j=this.tickLabelContainer.offsetHeight;else
 
for(k=0;k<this.tickLabelContainer.childNodes.length;k++)this.tickLabelContainer.childNodes[k].offsetHeight>j&&(j=this.tickLabelContainer.childNodes[k].offsetHeight);"horizontal"===this.options.orientation&&(this.sliderElem.style.marginBottom=j+"px")}for(var
 k=0;k<this.options.ticks.length;k++){var 
l=this.options.ticks_positions[k]||this._toPercentage(this.options.ticks[k]);this.options.reversed&&(l=100-l),this.ticks[k].style[this.stylePos]=l+"%",this._removeClass(this.ticks[k],"in-selection"),this.options.range?l>=a[0]&&l<=a[1]&&this._addClass(this.ticks[k],"in-selection"):"after"===this.options.selection&&l>=a[0]?this._addClass(this.ticks[k],"in-selection"):"before"===this.options.selection&&l<=a[0]&&this._addClass(this.ticks[k],"in-selection"),this.tickLabels[k]&&(this.tickLabels[k].style[h]=i+"px","vertical"!==this.options.orientation&&void
 
0!==this.options.ticks_positions[k]?(this.tickLabels[k].style.position="absolute",this.tickLabels[k].style[this.stylePos]=l+"%",this.tickLabels[k].style[g]=-i/2+"px"):"vertical"===this.options.orientation&&(this.options.rtl?this.tickLabels[k].style.marginRight=this.sliderElem.offsetWidth+"px":this.tickLabels[k].style.marginLeft=this.sliderElem.offsetWidth+"px",this.tickLabelContainer.style[g]=this.sliderElem.offsetWidth/2*-1+"px"))}}var
 
m;if(this.options.range){m=this.options.formatter(this._state.value),this._setText(this.tooltipInner,m),this.tooltip.style[this.stylePos]=(a[1]+a[0])/2+"%","vertical"===this.options.orientation?this._css(this.tooltip,"margin-"+this.stylePos,-this.tooltip.offsetHeight/2+"px"):this._css(this.tooltip,"margin-"+this.stylePos,-this.tooltip.offsetWidth/2+"px");var
 
n=this.options.formatter(this._state.value[0]);this._setText(this.tooltipInner_min,n);var
 
o=this.options.formatter(this._state.value[1]);this._setText(this.tooltipInner_max,o),this.tooltip_min.style[this.stylePos]=a[0]+"%","vertical"===this.options.orientation?this._css(this.tooltip_min,"margin-"+this.stylePos,-this.tooltip_min.offsetHeight/2+"px"):this._css(this.tooltip_min,"margin-"+this.stylePos,-this.tooltip_min.offsetWidth/2+"px"),this.tooltip_max.style[this.stylePos]=a[1]+"%","vertical"===this.options.orientation?this._css(this.tooltip_max,"margin-"+this.stylePos,-this.tooltip_max.offsetHeight/2+"px"):this._css(this.tooltip_max,"margin-"+this.stylePos,-this.tooltip_max.offsetWidth/2+"px")}else
 
m=this.options.formatter(this._state.value[0]),this._setText(this.tooltipInner,m),this.tooltip.style[this.stylePos]=a[0]+"%","vertical"===this.options.orientation?this._css(this.tooltip,"margin-"+this.stylePos,-this.tooltip.offsetHeight/2+"px"):this._css(this.tooltip,"margin-"+this.stylePos,-this.tooltip.offsetWidth/2+"px");if("vertical"===this.options.orientation)this.trackLow.style.top="0",this.trackLow.style.height=Math.min(a[0],a[1])+"%",this.trackSelection.style.top=Math.min(a[0],a[1])+"%",this.trackSelection.style.height=Math.abs(a[0]-a[1])+"%",this.trackHigh.style.bottom="0",this.trackHigh.style.height=100-Math.min(a[0],a[1])-Math.abs(a[0]-a[1])+"%";else{"right"===this.stylePos?this.trackLow.style.right="0":this.trackLow.style.left="0",this.trackLow.style.width=Math.min(a[0],a[1])+"%","right"===this.stylePos?this.trackSelection.style.right=Math.min(a[0],a[1])+"%":this.trackSelection.style.left=Math.min(a[0],a[1])+"%",this.trackSelection.style.width=Math.abs(a[0]-a[1])+"%","right"===this.stylePos?this.trackHigh.style.left="0":this.trackHigh.style.right="0",this.trackHigh.style.width=100-Math.min(a[0],a[1])-Math.abs(a[0]-a[1])+"%";var
 
p=this.tooltip_min.getBoundingClientRect(),q=this.tooltip_max.getBoundingClientRect();"bottom"===this.options.tooltip_position?p.right>q.left?(this._removeClass(this.tooltip_max,"bottom"),this._addClass(this.tooltip_max,"top"),this.tooltip_max.style.top="",this.tooltip_max.style.bottom="22px"):(this._removeClass(this.tooltip_max,"top"),this._addClass(this.tooltip_max,"bottom"),this.tooltip_max.style.top=this.tooltip_min.style.top,this.tooltip_max.style.bottom=""):p.right>q.left?(this._removeClass(this.tooltip_max,"top"),this._addClass(this.tooltip_max,"bottom"),this.tooltip_max.style.top="18px"):(this._removeClass(this.tooltip_max,"bottom"),this._addClass(this.tooltip_max,"top"),this.tooltip_max.style.top=this.tooltip_min.style.top)}},_createHighlightRange:function(a,b){return
 
this._isHighlightRange(a,b)?a>b?{start:b,size:a-b}:{start:a,size:b-a}:null},_isHighlightRange:function(a,b){return
 
a>=0&&100>=a&&b>=0&&100>=b?!0:!1},_resize:function(a){this._state.offset=this._offset(this.sliderElem),this._state.size=this.sliderElem[this.sizePos],this._layout()},_removeProperty:function(a,b){a.style.removeProperty?a.style.removeProperty(b):a.style.removeAttribute(b)},_mousedown:function(a){if(!this._state.enabled)return!1;this._state.offset=this._offset(this.sliderElem),this._state.size=this.sliderElem[this.sizePos];var
 b=this._getPercentage(a);if(this.options.range){var 
c=Math.abs(this._state.percentage[0]-b),d=Math.abs(this._state.percentage[1]-b);this._state.dragged=d>c?0:1,this._adjustPercentageForRangeSliders(b)}else
 
this._state.dragged=0;this._state.percentage[this._state.dragged]=b,this._layout(),this.touchCapable&&(document.removeEventListener("touchmove",this.mousemove,!1),document.removeEventListener("touchend",this.mouseup,!1)),this.mousemove&&document.removeEventListener("mousemove",this.mousemove,!1),this.mouseup&&document.removeEventListener("mouseup",this.mouseup,!1),this.mousemove=this._mousemove.bind(this),this.mouseup=this._mouseup.bind(this),this.touchCapable&&(document.addEventListener("touchmove",this.mousemove,!1),document.addEventListener("touchend",this.mouseup,!1)),document.addEventListener("mousemove",this.mousemove,!1),document.addEventListener("mouseup",this.mouseup,!1),this._state.inDrag=!0;var
 e=this._calculateValue();return 
this._trigger("slideStart",e),this._setDataVal(e),this.setValue(e,!1,!0),a.returnValue=!1,this.options.focus&&this._triggerFocusOnHandle(this._state.dragged),!0},_touchstart:function(a){if(void
 0===a.changedTouches)return void this._mousedown(a);var 
b=a.changedTouches[0];this.touchX=b.pageX,this.touchY=b.pageY},_triggerFocusOnHandle:function(a){0===a&&this.handle1.focus(),1===a&&this.handle2.focus()},_keydown:function(a,b){if(!this._state.enabled)return!1;var
 c;switch(b.keyCode){case 37:case 40:c=-1;break;case 39:case 
38:c=1}if(c){if(this.options.natural_arrow_keys){var 
d="vertical"===this.options.orientation&&!this.options.reversed,e="horizontal"===this.options.orientation&&this.options.reversed;(d||e)&&(c=-c)}var
 
f=this._state.value[a]+c*this.options.step,g=f/this.options.max*100;if(this._state.keyCtrl=a,this.options.range){this._adjustPercentageForRangeSliders(g);var
 
h=this._state.keyCtrl?this._state.value[0]:f,i=this._state.keyCtrl?f:this._state.value[1];f=[h,i]}return
 
this._trigger("slideStart",f),this._setDataVal(f),this.setValue(f,!0,!0),this._setDataVal(f),this._trigger("slideStop",f),this._layout(),this._pauseEvent(b),delete
 
this._state.keyCtrl,!1}},_pauseEvent:function(a){a.stopPropagation&&a.stopPropagation(),a.preventDefault&&a.preventDefault(),a.cancelBubble=!0,a.returnValue=!1},_mousemove:function(a){if(!this._state.enabled)return!1;var
 
b=this._getPercentage(a);this._adjustPercentageForRangeSliders(b),this._state.percentage[this._state.dragged]=b,this._layout();var
 c=this._calculateValue(!0);return 
this.setValue(c,!0,!0),!1},_touchmove:function(a){if(void 
0!==a.changedTouches){var 
b=a.changedTouches[0],c=b.pageX-this.touchX,d=b.pageY-this.touchY;this._state.inDrag||("vertical"===this.options.orientation&&5>=c&&c>=-5&&(d>=15||-15>=d)?this._mousedown(a):5>=d&&d>=-5&&(c>=15||-15>=c)&&this._mousedown(a))}},_adjustPercentageForRangeSliders:function(a){if(this.options.range){var
 b=this._getNumDigitsAfterDecimalPlace(a);b=b?b-1:0;var 
c=this._applyToFixedAndParseFloat(a,b);0===this._state.dragged&&this._applyToFixedAndParseFloat(this._state.percentage[1],b)<c?(this._state.percentage[0]=this._state.percentage[1],this._state.dragged=1):1===this._state.dragged&&this._applyToFixedAndParseFloat(this._state.percentage[0],b)>c?(this._state.percentage[1]=this._state.percentage[0],this._state.dragged=0):0===this._state.keyCtrl&&this._state.value[1]/this.options.max*100<a?(this._state.percentage[0]=this._state.percentage[1],this._state.keyCtrl=1,this.handle2.focus()):1===this._state.keyCtrl&&this._state.value[0]/this.options.max*100>a&&(this._state.percentage[1]=this._state.percentage[0],this._state.keyCtrl=0,this.handle1.focus())}},_mouseup:function(){if(!this._state.enabled)return!1;this.touchCapable&&(document.removeEventListener("touchmove",this.mousemove,!1),document.removeEventListener("touchend",this.mouseup,!1)),document.removeEventListener("mousemove",this.mousemove,!1),document.removeEventListener("mouseup",this.mouseup,!1),this._state.inDrag=!1,this._state.over===!1&&this._hideTooltip();var
 a=this._calculateValue(!0);return 
this._layout(),this._setDataVal(a),this._trigger("slideStop",a),!1},_calculateValue:function(a){var
 
b;if(this.options.range?(b=[this.options.min,this.options.max],0!==this._state.percentage[0]&&(b[0]=this._toValue(this._state.percentage[0]),b[0]=this._applyPrecision(b[0])),100!==this._state.percentage[1]&&(b[1]=this._toValue(this._state.percentage[1]),b[1]=this._applyPrecision(b[1]))):(b=this._toValue(this._state.percentage[0]),b=parseFloat(b),b=this._applyPrecision(b)),a){for(var
 c=[b,1/0],d=0;d<this.options.ticks.length;d++){
+var 
e=Math.abs(this.options.ticks[d]-b);e<=c[1]&&(c=[this.options.ticks[d],e])}if(c[1]<=this.options.ticks_snap_bounds)return
 c[0]}return b},_applyPrecision:function(a){var 
b=this.options.precision||this._getNumDigitsAfterDecimalPlace(this.options.step);return
 
this._applyToFixedAndParseFloat(a,b)},_getNumDigitsAfterDecimalPlace:function(a){var
 b=(""+a).match(/(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/);return 
b?Math.max(0,(b[1]?b[1].length:0)-(b[2]?+b[2]:0)):0},_applyToFixedAndParseFloat:function(a,b){var
 c=a.toFixed(b);return 
parseFloat(c)},_getPercentage:function(a){!this.touchCapable||"touchstart"!==a.type&&"touchmove"!==a.type||(a=a.touches[0]);var
 
b=a[this.mousePos],c=this._state.offset[this.stylePos],d=b-c;"right"===this.stylePos&&(d=-d);var
 e=d/this._state.size*100;return 
e=Math.round(e/this._state.percentage[2])*this._state.percentage[2],this.options.reversed&&(e=100-e),Math.max(0,Math.min(100,e))},_validateInputValue:function(a){if(isNaN(+a)){if(Array.isArray(a))return
 this._validateArray(a),a;throw new 
Error(f.formatInvalidInputErrorMsg(a))}return+a},_validateArray:function(a){for(var
 b=0;b<a.length;b++){var c=a[b];if("number"!=typeof c)throw new 
Error(f.formatInvalidInputErrorMsg(c))}},_setDataVal:function(a){this.element.setAttribute("data-value",a),this.element.setAttribute("value",a),this.element.value=a},_trigger:function(b,c){c=c||0===c?c:void
 0;var d=this.eventToCallbackMap[b];if(d&&d.length)for(var 
e=0;e<d.length;e++){var 
f=d[e];f(c)}a&&this._triggerJQueryEvent(b,c)},_triggerJQueryEvent:function(a,b){var
 
c={type:a,value:b};this.$element.trigger(c),this.$sliderElem.trigger(c)},_unbindJQueryEventHandlers:function(){this.$element.off(),this.$sliderElem.off()},_setText:function(a,b){"undefined"!=typeof
 a.textContent?a.textContent=b:"undefined"!=typeof 
a.innerText&&(a.innerText=b)},_removeClass:function(a,b){for(var c=b.split(" 
"),d=a.className,e=0;e<c.length;e++){var f=c[e],g=new 
RegExp("(?:\\s|^)"+f+"(?:\\s|$)");d=d.replace(g," 
")}a.className=d.trim()},_addClass:function(a,b){for(var c=b.split(" 
"),d=a.className,e=0;e<c.length;e++){var f=c[e],g=new 
RegExp("(?:\\s|^)"+f+"(?:\\s|$)"),h=g.test(d);h||(d+=" 
"+f)}a.className=d.trim()},_offsetLeft:function(a){return 
a.getBoundingClientRect().left},_offsetRight:function(a){return 
a.getBoundingClientRect().right},_offsetTop:function(a){for(var 
b=a.offsetTop;(a=a.offsetParent)&&!isNaN(a.offsetTop);)b+=a.offsetTop,"BODY"!==a.tagName&&(b-=a.scrollTop);return
 
b},_offset:function(a){return{left:this._offsetLeft(a),right:this._offsetRight(a),top:this._offsetTop(a)}},_css:function(b,c,d){if(a)a.style(b,c,d);else{var
 e=c.replace(/^-ms-/,"ms-").replace(/-([\da-z])/gi,function(a,b){return 
b.toUpperCase()});b.style[e]=d}},_toValue:function(a){return 
this.options.scale.toValue.apply(this,[a])},_toPercentage:function(a){return 
this.options.scale.toPercentage.apply(this,[a])},_setTooltipPosition:function(){var
 
a=[this.tooltip,this.tooltip_min,this.tooltip_max];if("vertical"===this.options.orientation){var
 
b;b=this.options.tooltip_position?this.options.tooltip_position:this.options.rtl?"left":"right";var
 
c="left"===b?"right":"left";a.forEach(function(a){this._addClass(a,b),a.style[c]="100%"}.bind(this))}else"bottom"===this.options.tooltip_position?a.forEach(function(a){this._addClass(a,"bottom"),a.style.top="22px"}.bind(this)):a.forEach(function(a){this._addClass(a,"top"),a.style.top=-this.tooltip.outerHeight-14+"px"}.bind(this))}},a&&a.fn){var
 h=void 
0;a.fn.slider?(windowIsDefined&&window.console.warn("bootstrap-slider.js - 
WARNING: $.fn.slider namespace is already bound. Use the $.fn.bootstrapSlider 
namespace 
instead."),h=c):(a.bridget(b,d),h=b),a.bridget(c,d),a(function(){a("input[data-provide=slider]")[h]()})}}(a),d});
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/velum-master/vendor/assets/stylesheets/bootstrap-slider.min.css 
new/velum-master/vendor/assets/stylesheets/bootstrap-slider.min.css
--- old/velum-master/vendor/assets/stylesheets/bootstrap-slider.min.css 
1970-01-01 01:00:00.000000000 +0100
+++ new/velum-master/vendor/assets/stylesheets/bootstrap-slider.min.css 
2018-02-22 10:57:04.000000000 +0100
@@ -0,0 +1,41 @@
+/*! =======================================================
+                      VERSION  9.9.0              
+========================================================= */
+/*! =========================================================
+ * bootstrap-slider.js
+ *
+ * Maintainers:
+ *             Kyle Kemp
+ *                     - Twitter: @seiyria
+ *                     - Github:  seiyria
+ *             Rohit Kalkur
+ *                     - Twitter: @Rovolutionary
+ *                     - Github:  rovolution
+ *
+ * =========================================================
+  *
+ * bootstrap-slider is released under the MIT License
+ * Copyright (c) 2017 Kyle Kemp, Rohit Kalkur, and contributors
+ * 
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ * 
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * ========================================================= 
*/.slider{display:inline-block;vertical-align:middle;position:relative}.slider.slider-horizontal{width:210px;height:20px}.slider.slider-horizontal
 
.slider-track{height:10px;width:100%;margin-top:-5px;top:50%;left:0}.slider.slider-horizontal
 .slider-selection,.slider.slider-horizontal 
.slider-track-low,.slider.slider-horizontal 
.slider-track-high{height:100%;top:0;bottom:0}.slider.slider-horizontal 
.slider-tick,.slider.slider-horizontal 
.slider-handle{margin-left:-10px}.slider.slider-horizontal 
.slider-tick.triangle,.slider.slider-horizontal 
.slider-handle.triangle{position:relative;top:50%;transform:translateY(-50%);border-width:0
 10px 10px 
10px;width:0;height:0;border-bottom-color:#2e6da4;margin-top:0}.slider.slider-horizontal
 
.slider-tick-container{white-space:nowrap;position:absolute;top:0;left:0;width:100%}.slider.slider-horizontal
 
.slider-tick-label-container{white-space:nowrap;margin-top:20px}.slider.slider-horizontal
 .slider-tick-label-container 
.slider-tick-label{padding-top:4px;display:inline-block;text-align:center}.slider.slider-horizontal.slider-rtl
 .slider-track{left:initial;right:0}.slider.slider-horizontal.slider-rtl 
.slider-tick,.slider.slider-horizontal.slider-rtl 
.slider-handle{margin-left:initial;margin-right:-10px}.slider.slider-horizontal.slider-rtl
 
.slider-tick-container{left:initial;right:0}.slider.slider-vertical{height:210px;width:20px}.slider.slider-vertical
 .slider-track{width:10px;height:100%;left:25%;top:0}.slider.slider-vertical 
.slider-selection{width:100%;left:0;top:0;bottom:0}.slider.slider-vertical 
.slider-track-low,.slider.slider-vertical 
.slider-track-high{width:100%;left:0;right:0}.slider.slider-vertical 
.slider-tick,.slider.slider-vertical 
.slider-handle{margin-top:-10px}.slider.slider-vertical 
.slider-tick.triangle,.slider.slider-vertical 
.slider-handle.triangle{border-width:10px 0 10px 
10px;width:1px;height:1px;border-left-color:#2e6da4;border-right-color:#2e6da4;margin-left:0;margin-right:0}.slider.slider-vertical
 .slider-tick-label-container{white-space:nowrap}.slider.slider-vertical 
.slider-tick-label-container 
.slider-tick-label{padding-left:4px}.slider.slider-vertical.slider-rtl 
.slider-track{left:initial;right:25%}.slider.slider-vertical.slider-rtl 
.slider-selection{left:initial;right:0}.slider.slider-vertical.slider-rtl 
.slider-tick.triangle,.slider.slider-vertical.slider-rtl 
.slider-handle.triangle{border-width:10px 10px 10px 
0}.slider.slider-vertical.slider-rtl .slider-tick-label-container 
.slider-tick-label{padding-left:initial;padding-right:4px}.slider.slider-disabled
 .slider-handle{background-image:-webkit-linear-gradient(top,#dfdfdf 0,#bebebe 
100%);background-image:-o-linear-gradient(top,#dfdfdf 0,#bebebe 
100%);background-image:linear-gradient(to bottom,#dfdfdf 0,#bebebe 
100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdfdfdf',endColorstr='#ffbebebe',GradientType=0)}.slider.slider-disabled
 .slider-track{background-image:-webkit-linear-gradient(top,#e5e5e5 0,#e9e9e9 
100%);background-image:-o-linear-gradient(top,#e5e5e5 0,#e9e9e9 
100%);background-image:linear-gradient(to bottom,#e5e5e5 0,#e9e9e9 
100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe5e5e5',endColorstr='#ffe9e9e9',GradientType=0);cursor:not-allowed}.slider
 input{display:none}.slider .tooltip.top{margin-top:-36px}.slider 
.tooltip-inner{white-space:nowrap;max-width:none}.slider 
.hide{display:none}.slider-track{position:absolute;cursor:pointer;background-image:-webkit-linear-gradient(top,#f5f5f5
 0,#f9f9f9 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#f9f9f9 
100%);background-image:linear-gradient(to bottom,#f5f5f5 0,#f9f9f9 
100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5',endColorstr='#fff9f9f9',GradientType=0);-webkit-box-shadow:inset
 0 1px 2px rgba(0,0,0,0.1);box-shadow:inset 0 1px 2px 
rgba(0,0,0,0.1);border-radius:4px}.slider-selection{position:absolute;background-image:-webkit-linear-gradient(top,#f9f9f9
 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#f9f9f9 0,#f5f5f5 
100%);background-image:linear-gradient(to bottom,#f9f9f9 0,#f5f5f5 
100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff9f9f9',endColorstr='#fff5f5f5',GradientType=0);-webkit-box-shadow:inset
 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 0 -1px 0 
rgba(0,0,0,0.15);-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;border-radius:4px}.slider-selection.tick-slider-selection{background-image:-webkit-linear-gradient(top,#8ac1ef
 0,#82b3de 100%);background-image:-o-linear-gradient(top,#8ac1ef 0,#82b3de 
100%);background-image:linear-gradient(to bottom,#8ac1ef 0,#82b3de 
100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff8ac1ef',endColorstr='#ff82b3de',GradientType=0)}.slider-track-low,.slider-track-high{position:absolute;background:transparent;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;border-radius:4px}.slider-handle{position:absolute;top:0;width:20px;height:20px;background-color:#337ab7;background-image:-webkit-linear-gradient(top,#337ab7
 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 
100%);background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 
100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7',endColorstr='#ff2e6da4',GradientType=0);filter:none;-webkit-box-shadow:inset
 0 1px 0 rgba(255,255,255,.2),0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 
0 rgba(255,255,255,.2),0 1px 2px rgba(0,0,0,.05);border:0 solid 
transparent}.slider-handle.round{border-radius:50%}.slider-handle.triangle{background:transparent
 none}.slider-handle.custom{background:transparent 
none}.slider-handle.custom::before{line-height:20px;font-size:20px;content:'\2605';color:#726204}.slider-tick{position:absolute;width:20px;height:20px;background-image:-webkit-linear-gradient(top,#f9f9f9
 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#f9f9f9 0,#f5f5f5 
100%);background-image:linear-gradient(to bottom,#f9f9f9 0,#f5f5f5 
100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff9f9f9',endColorstr='#fff5f5f5',GradientType=0);-webkit-box-shadow:inset
 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 0 -1px 0 
rgba(0,0,0,0.15);-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;filter:none;opacity:.8;border:0
 solid 
transparent}.slider-tick.round{border-radius:50%}.slider-tick.triangle{background:transparent
 none}.slider-tick.custom{background:transparent 
none}.slider-tick.custom::before{line-height:20px;font-size:20px;content:'\2605';color:#726204}.slider-tick.in-selection{background-image:-webkit-linear-gradient(top,#8ac1ef
 0,#82b3de 100%);background-image:-o-linear-gradient(top,#8ac1ef 0,#82b3de 
100%);background-image:linear-gradient(to bottom,#8ac1ef 0,#82b3de 
100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff8ac1ef',endColorstr='#ff82b3de',GradientType=0);opacity:1}
\ No newline at end of file


Reply via email to