-
-
-
-
-
-
-
diff --git a/app/views/ontologies/browser/_ontologies.html.haml b/app/views/ontologies/browser/_ontologies.html.haml
new file mode 100644
index 000000000..3e4d3c130
--- /dev/null
+++ b/app/views/ontologies/browser/_ontologies.html.haml
@@ -0,0 +1,13 @@
+= render InfiniteScrollComponent.new(id: 'ontologies_list',
+ collection: @ontologies,
+ next_url: ontologies_filter_url(@filters, page: @page.nextPage),
+ current_page: @page.page, next_page: @page.nextPage) do |c|
+ - ontologies = c.collection
+ - ontologies.each do |ontology|
+ = render OntologyBrowseCardComponent.new(ontology: ontology)
+ - c.loader do
+ - ontologies_browse_skeleton
+ - c.error do
+ .browse-empty-illustration
+ %img{:src => "#{asset_path("empty-box.svg")}"}
+ %p No result was found
\ No newline at end of file
diff --git a/app/views/ontologies/browser/browse.html.haml b/app/views/ontologies/browser/browse.html.haml
new file mode 100644
index 000000000..2ef7337f4
--- /dev/null
+++ b/app/views/ontologies/browser/browse.html.haml
@@ -0,0 +1,96 @@
+.browse-center
+ .browse-container
+
+ .browse-submit-new-ontology-and-you-are-admin-container
+ - if session[:user]&.admin?
+ %div
+ %div.browse-you-are-admin
+ %h3 Welcome admin
+ %div
+ %svg{:fill => "none", :height => "11", :viewbox => "0 0 11 11", :width => "11", :xmlns => "http://www.w3.org/2000/svg"}
+ %circle{:cx => "5.5", :cy => "5.5", :fill => 'var(--admin-color)', :r => "5.5"}
+ %p This coloring indicates admin-only features
+
+ %a#back_top_btn.btn.btn-primary.btn-floating.btn-lg
+ %i.fas.fa-arrow-up.text-white
+
+ :javascript
+ const btn = document.getElementById("back_top_btn");
+ window.addEventListener("scroll", function() {
+ if (window.scrollY > 300) {
+ btn.classList.add("show");
+ } else {
+ btn.classList.remove("show");
+ }
+ });
+
+ btn.addEventListener("click", function(e) {
+ e.preventDefault();
+ window.scrollTo({
+ top: 0,
+ behavior: "smooth"
+ });
+ });
+
+ %div{data: { controller: "turbo-frame history browse-filters" , "turbo-frame-url-value": "/ontologies_filter", action: "change->browse-filters#dispatchFilterEvent changed->history#updateURL changed->turbo-frame#updateFrame"}}
+
+ .browse-sub-container
+ .browse-first-row{data:{controller: "browse-filters", action: "change->browse-filters#dispatchFilterEvent changed->history#updateURL"}}
+ %div.d-flex.p-2{style: "height: 67px"}
+ = upload_ontology_button
+ %div{style:'margin-top: 27px'}
+ %p.browse-filters-title Filters
+ - if session[:user]&.admin?
+ %div.browse-filter.admin-border
+ = render SwitchInputComponent.new(id:'filter-private', name:'private_only', checked: @show_private_only) do
+ Show private ontology only
+ %div.browse-filter{style:'border: none'}
+ = render SwitchInputComponent.new(id:'filter-views', name:'views', checked: @show_views) do
+ Show ontology views
+ = render SwitchInputComponent.new(id:'filter-retired', name:'retired',checked: @show_retired) do
+ Show retired ontologies
+
+ - @filters.each do |key, values|
+ - if session[:user]&.admin? || key != :missingStatus
+ .browse-filter{data:{controller: "show-filter-count browse-filters", action: "change->show-filter-count#updateCount change->browse-filters#dispatchFilterEvent"}, id: "#{key}_filter_container", style: "#{"border-color: var(--admin-color);" if key == :missingStatus}"}
+ .browse-filter-title-bar{"data-target" => "#browse-#{key}-filter", "data-toggle" => "collapse"}
+ %p
+ = browse_filter_section_label(key)
+ %span.badge.badge-primary{"data-show-filter-count-target":"countSpan", style: "#{values[2] && values[2].positive? ? '' : 'display: none;'}"}
+ = values[2]
+ %img{:src => "#{asset_path("arrow-down.svg")}"}/
+ .collapse{id: "browse-#{key}-filter", class: "#{values[2].positive? ? 'show': ''}"}
+ .browse-filter-checks-container
+ - values.first.each do |object|
+ - title = (key.eql?(:categories) || key.eql?(:groups) ? object["name"] : '')
+ - value = (object["value"] || object["acronym"] || object["id"])
+ %div{data: {controller: 'tooltip'}, title: title}
+ = render ChipsComponent.new(id: value, name: key, value: value,
+ label: object["acronym"].humanize,
+ checked: values[1]&.include?(object["id"])) do |c|
+ - c.count do
+ %span.badge.badge-light.ml-1
+ = turbo_frame_tag "count_#{key}_#{object["id"]}", busy: true
+ %span.show-if-loading
+ = render LoaderComponent.new(small:true)
+
+ .browse-second-row
+ .browse-search-bar
+ .browse-search-container
+ %input{:name => "search", :placeholder => "Start typing to filter ontologies, e.g AGROVOC...", :type => "text", :value => @search, data: {action: "input->browse-filters#dispatchInputEvent"}}
+ .browse-search-filters
+ %select#format.browse-format-filter{:name => "format"}
+ = options_for_select(@formats, @selected_format)
+ %select#Sort_by.browse-sort-by-filter{:name => "Sort_by"}
+ = options_for_select(@sorts_options, '')
+ .browse-ontologies
+ = render TurboFrameComponent.new(id:"ontologies_list_container", data:{"turbo-frame-target":"frame", "turbo-frame-url-value": "/ontologies_filter"}) do |container|
+ = turbo_frame_tag "ontologies_filter_count_request", src: "/ontologies_filter?count=true{request.original_url.split('?').last}" do
+ = browser_counter_loader
+ = render TurboFrameComponent.new(id: "ontologies_list_view-page-1" , src: "/ontologies_filter?page=1{request.original_url.split('?').last}") do |list|
+ - list.loader do
+ - ontologies_browse_skeleton
+ - container.loader do
+ = browser_counter_loader
+ - ontologies_browse_skeleton
+
diff --git a/app/views/ontologies/sections/_additional_metadata.html.haml b/app/views/ontologies/sections/_additional_metadata.html.haml
new file mode 100644
index 000000000..0054b4c76
--- /dev/null
+++ b/app/views/ontologies/sections/_additional_metadata.html.haml
@@ -0,0 +1,18 @@
+= turbo_frame_tag 'application_modal_content' do
+ - sub_hash = @submission_latest.to_hash.except(:context, :links, :ontology)
+ %div.card.overflow-hidden{style: 'border-radius: 20px;'}
+ %div
+ = render Display::AlertComponent.new(closable: false) do
+ %div.d-flex.align-items-center
+ %div{style:'width: 50px; height: 50px'}
+ - sub_values = sub_hash.values
+ - count = sub_values.count{|x| !(x.nil? || x.to_s.empty?)}
+ = render CircleProgressBarComponent.new(count: count , max: sub_values.size )
+ %div.mx-1
+ of the metadata attributes were filled
+ %section.px-4{style:'height: 70vh; overflow-y: scroll'}
+ = render SubmissionMetadataComponent.new(submission: @submission_latest, submission_metadata: submission_metadata) unless @submission_latest.nil?
+ %div.scroll-message.text-center.py-3.bg-light.text-primary
+ %p.scroll-text.mb-0
+ Scroll down to see more
+ %i.scroll-icon.fa.fa-chevron-down
diff --git a/app/views/ontologies/sections/_licenses.html.haml b/app/views/ontologies/sections/_licenses.html.haml
new file mode 100644
index 000000000..e966e7608
--- /dev/null
+++ b/app/views/ontologies/sections/_licenses.html.haml
@@ -0,0 +1,3 @@
+= render_in_modal do
+ = render Layout::ListComponent.new do |l|
+ = properties_list_component(l, @licenses.map { |x| [x.to_s, @submission_latest.send(x.to_s)] }.to_h)
diff --git a/app/views/ontologies/sections/_metadata.html.haml b/app/views/ontologies/sections/_metadata.html.haml
old mode 100644
new mode 100755
index 46c942e61..3b575d5b5
--- a/app/views/ontologies/sections/_metadata.html.haml
+++ b/app/views/ontologies/sections/_metadata.html.haml
@@ -1,189 +1,66 @@
= turbo_frame_tag 'summary', target:"_top" do
- %div.ont-metadata
- -# Details pane
- %section.ont-metadata-card.ont-details-card
- %header.pb-2.font-weight-bold Details
- %table.table.table-sm
- %tr
- %td Acronym
- %td= @ontology.acronym
- %tr
- %td Visibility
- %td= strip_links(visibility_link(@ontology))
- - if @ontology.viewing_restricted?
- %tr
- %td Viewing restriction
- %td= @ontology.viewingRestriction.capitalize
- - unless @ontology.viewOf.nil?
- %tr
- %td View of ontology
- %td
- - ont_parent_acronym = @ontology.viewOf.split('/').last
- - if $PURL_ENABLED
- - ont_url = @ontology.purl.sub(@ontology.acronym, ont_parent_acronym)
- - else
- - ont_url = @ontology.links['ui'].sub(@ontology.acronym, ont_parent_acronym)
- = link_to(ont_parent_acronym, ont_url)
- - unless @submission_latest.nil?
- %tr
- %td Description
- %td= sanitize(@submission_latest.description)
- %tr
- %td Status
- %td= @submission_latest.status.capitalize unless @submission_latest.status.nil?
- %tr
- %td Format
- %td= @submission_latest.hasOntologyLanguage
- %tr
- %td Contact
- %td= raw @submission_latest.contact.map {|c| [c.name, c.email].join(", ") if c.member?(:name) && c.member?(:email)}.join(" ")
- - categories_hash = LinkedData::Client::Models::Category.all_to_hash
- - categories = @ontology.hasDomain
- - unless categories.empty?
- %tr
- %td Categories
- %td= categories.map {|c| categories_hash[c].name}.sort.join(", ")
- - groups_hash = LinkedData::Client::Models::Group.all_to_hash
- - groups = @ontology.group
- - unless groups.empty?
- %tr
- %td Groups
- %td= groups.map {|g| groups_hash[g].name}.sort.join(", ")
- - if @ontology.admin?(session[:user])
- %tr
- %td Pull URL
- %td
- = link_to @submission_latest.pullLocation, @submission_latest.pullLocation
- = raw additional_details
+ .summary-page-center
+ .summary-page-first-row
+ = render partial: 'ontologies/sections/metadata/ontology_description_section'
+ = render partial: 'ontologies/sections/metadata/ontology_fairness_section'
+ = render partial: 'ontologies/sections/metadata/ontology_relations_network'
+ = render partial: 'ontologies/sections/metadata/ontology_submissions_section'
+ = render partial: 'ontologies/sections/metadata/ontology_metrics_section'
+ .summary-page-second-row
+ = ontology_depiction_card
+ = properties_card('Identifiers','Principal identifiers of the ontology', @identifiers) do |values|
+ = horizontal_list_container(values) do |v|
+ = render LinkFieldComponent.new(value: v)
- = render partial: 'additional_metadata'
+ = properties_dropdown('dates','Dates','', @dates_properties) do |values|
+ = horizontal_list_container(values) do |v|
+ = render DateTimeFieldComponent.new(value: v)
- -# Submissions pane
- %section.ont-metadata-card.ont-subs-card
- %div.ont-section-toolbar
- %header.pb-2.font-weight-bold Submissions
- - if @ontology.admin?(session[:user])
- = link_to(new_ontology_submission_path(@ontology.acronym), "aria-label": "Add submission", title: "Add submission") do
- %i.fas.fa-lg.fa-plus-circle{"aria-hidden": "true", style: "margin-left: 0.75rem;"}
- - unless (@submission_latest.nil? || (@submission_latest.respond_to?(:status) && @submission_latest.status == 404))
- = link_to(edit_ontology_submission_path(@ontology.acronym, @submission_latest.submissionId), "aria-label": "Edit latest submission", title: "Edit latest submission") do
- %i.fas.fa-user-edit{"aria-hidden": "true", style: "margin-left: 0.5rem;"}
- = render TurboFrameComponent.new(id: 'ontology_submissions', src: ontology_submissions_path(@ontology.acronym))
+ = properties_dropdown('person_and_organization','Persons and organizations','', @agents_properties) do |values|
+ = horizontal_list_container(values) do |v|
+ = render ChipButtonComponent.new(type: "static",'data-controller':' tooltip', title: '', class: 'text-truncate', style: 'max-width: 280px; display:block; line-height: unset') do
+ = display_agent(v, link: false)
+ = properties_dropdown('link','Links','Metadata properties that highlight the links enabling access to datasets, downloading semantic resources, etc', @links_properties)
- -# Views pane (don't show if the ontology is a view - we don't allow views of views).
- - unless @ontology.view?
- %section.ont-metadata-card.ont-views-card
- %div.ont-section-toolbar
- %header.pb-2.font-weight-bold= "Views of #{@ontology.acronym}"
- - ont_id_esc = CGI.escape(@ontology.id)
- -# TODO: I don't think we should have brackets in the URL parameters.
- - if session[:user].nil?
- %a{href: "/login?redirect=#{escape("/ontologies/new?ontology[viewOf]=#{ont_id_esc}")}", "aria-label": "Create new view", title: "Create new view"}
- %i.fas.fa-lg.fa-plus-circle{"aria-hidden": "true", style: "margin-left: 0.5rem;"}
- - else
- %a{href: "/ontologies/new?ontology[viewOf]=#{ont_id_esc}"}
- %i.fas.fa-lg.fa-plus-circle{"aria-hidden": "true", style: "margin-left: 0.5rem;"}
- - if @views.empty?
- %p.font-italic= "No views of #{@ontology.acronym} available"
- - else
- %div.border-top
- %dl
- - @view_decorators.each do |view_decorator|
- %dt= view_decorator.linked_name
- %dd= view_decorator.description
+ = properties_dropdown('projects_section','Projects and usage information','Details pertaining to the utilization of the ontology.', nil) do |c|
+ - c.row do
+ = render FieldContainerComponent.new do |f|
+ - f.label do
+ Projects using #{@ontology.acronym}
+ = new_element_link('Create new project', new_project_path)
- %div.right-hand-content
+ - if @projects.empty?
+ = empty_state_message("No projects using #{@ontology.acronym}")
+ - else
+ = horizontal_list_container(@projects) do |project|
+ = render ChipButtonComponent.new(url: project_path(project.acronym), text: project.name, type: "clickable")
+ - properties_list_component(c, @projects_properties)
- -# Misc links pane
- %section.ont-metadata-card.ont-links-card
- %div.ont-section-toolbar
- %header.pb-2.font-weight-bold Links
- %a{:href => "#{(@submission_latest || @ontology).id}?display=all", :target => '_blank', :class => "btn btn-primary"} Go to the REST API JSON entry
+ = properties_dropdown('methodology','Methodology', 'Metadata properties primarily encompass the design, methods, and actions to create the ontology. This includes elements such as the tools and software employed by the creator of the ontology during its configuration', @methodology_properties)
- -# Metadata links pane
- %section.ont-metadata-card.ont-metadatalinks-card
- %div.ont-section-toolbar
- %header.pb-2.font-weight-bold Get my metadata back
- %div
- - unless @submission_latest.nil?
- %div{data:{controller: 'metadata-downloader'}}
- =javascript_include_tag "jsonld"
- %button{:id => "getMetadataBackNquadsBtn", :class => "btn btn-primary", 'data-action': 'metadata-downloader#downloadNQuads'} N-Triple
- %button{:id => "getMetadataBackJsonldBtn", :class => "btn btn-primary", 'data-action': 'metadata-downloader#downloadJsonLd'} Json-LD
- %button{:id => "getMetadataBackXmlBtn", :class => "btn btn-primary", 'data-action': 'metadata-downloader#downloadXML'} RDF/XML
- -# Listener in bp_ontology_viewer.js.erb
- -# Fair score pane
- -# TODO temporary hide fairness_service for AGROVOC after there demand
- - if fairness_service_enabled? && @ontology.acronym != 'AGROVOC'
- %section.ont-metadata-card.ont-fair-score-card#fair-summary
- %div.ont-section-toolbar
- %header.pb-2.font-weight-bold
- = render partial: "fair_score/fair_service_header"
- %div#fair-score-charts-container
- = render partial: "fairs_score"
+ = render Layout::CardComponent.new do |c|
+ - c.header do |h|
+ - h.text do
+ Visits
+ - if visits_data(@ontology)
+ = link_to(@ontology.links["analytics"] + "?apikey=#{get_apikey}&format=csv", title: "Download as CSV") do
+ = inline_svg("summary/download.svg", width: '30px', height: '20px')
- -# Metrics pane
- %section.ont-metadata-card.ont-metrics-card
- %div.ont-section-toolbar
- %header.pb-2.font-weight-bold Metrics
- = link_to(Rails.configuration.settings.links[:metrics], target: "_blank", "aria-label": "View individual metrics definitions", title: "View individual metrics definitions") do
- %i.fas.fa-lg.fa-question-circle{"aria-hidden": "true", style: "margin-left: 0.5rem"}
- - if @metrics.nil? || (@metrics.is_a?(Array) && @metrics.empty?) || (@metrics.respond_to?(:status) && @metrics.status == 404)
- %p.font-italic= "We have not yet calculated metrics for #{@ontology.acronym}"
- - else
- %table.table.table-sm
- %tr
- %td Classes
- %td{style: "text-align: right"}= number_with_delimiter(@metrics.classes)
- %tr
- %td Individuals
- %td= number_with_delimiter(@metrics.individuals)
- %tr
- %td Properties
- %td= number_with_delimiter(@metrics.properties)
- %tr
- %td Maximum depth
- %td= number_with_delimiter(@metrics.maxDepth)
- %tr
- %td Maximum number of children
- %td= number_with_delimiter(@metrics.maxChildCount)
- %tr
- %td Average number of children
- %td= number_with_delimiter(@metrics.averageChildCount)
- %tr
- %td Classes with a single child
- %td= number_with_delimiter(@metrics.classesWithOneChild)
- %tr
- %td Classes with more than 25 children
- %td= number_with_delimiter(@metrics.classesWithMoreThan25Children)
- %tr
- %td Classes with no definition
- %td= number_with_delimiter(@metrics.classesWithNoDefinition)
- -# Visits pane
- %section.ont-metadata-card.ont-analytics-card
- %div.ont-section-toolbar
- %header.pb-2.font-weight-bold Visits
- - if visits_data(@ontology)
- = link_to(@ontology.links["analytics"] + "?apikey=#{get_apikey}&format=csv", "aria-label": "Download as CSV", title: "Download as CSV") do
- %i.fas.fa-lg.fa-download{"aria-hidden": "true", style: "margin-left: 0.5rem"}
- = render partial: "visits"
+ = render Layout::ListComponent.new do |l|
+ - l.row do
+ = render partial: "visits"
- -# Included in data catalog pane
- = raw display_data_catalog(@submission_latest) unless @submission_latest.nil?
- -# Logo & depiction
- = raw display_logo(@submission_latest) unless @submission_latest.nil?
-
- -# Projects pane
- %section.ont-metadata-card.ont-projects-card
- %div.ont-section-toolbar
- %header.pb-2.font-weight-bold= "Projects using #{@ontology.acronym}"
- = link_to(new_project_path(), "aria-label": "Create new project", title: "Create new project") do
- %i.fas.fa-lg.fa-plus-circle{"aria-hidden": "true", style: "margin-left: 0.5rem"}
- - if @projects.empty?
- %p.font-italic= "No projects using #{@ontology.acronym}"
- - else
- %div.border-top
- - for project in @projects
- %p= link_to(project.name, project_path(project.acronym))
+ - unless @ontology.view?
+ = render Layout::CardComponent.new do |d|
+ - d.header do |h|
+ - h.text do
+ Views of #{@ontology.acronym}
+ = new_element_link('Create new view', new_view_path(@ontology.id))
+ = render Layout::ListComponent.new do |l|
+ - l.row do
+ = render partial: 'ontology_views'
+ - unless @submission_latest.nil?
+ = javascript_include_tag("jsonld")
+ = metadata_formats_buttons
\ No newline at end of file
diff --git a/app/views/ontologies/sections/metadata/_metrics_evolution_graph.html.haml b/app/views/ontologies/sections/metadata/_metrics_evolution_graph.html.haml
new file mode 100644
index 000000000..a8791f2da
--- /dev/null
+++ b/app/views/ontologies/sections/metadata/_metrics_evolution_graph.html.haml
@@ -0,0 +1,26 @@
+= turbo_frame_tag 'application_modal_content' do
+ %canvas#metrics_evolution_chart
+ :javascript
+
+ var metrics = #{raw data.to_json};
+ var key = Object.entries(metrics)[0][0]
+ var numbers = Object.entries(metrics)[0][1]
+
+ // Create a line chart
+ var ctx = document.getElementById('metrics_evolution_chart').getContext('2d');
+ console.log(key, numbers)
+ var metricsChart = new Chart(ctx, {
+ type: 'line',
+ data: {
+ labels: numbers.map((_, index) => `Submission ${index + 1}`),
+ datasets: [
+ {
+ label: key,
+ data: numbers,
+ borderColor: 'rgba(75, 192, 192, 1)',
+ backgroundColor: 'rgba(75, 192, 192, 0.2)',
+ }
+ ]
+ },
+ options: {}
+ })
\ No newline at end of file
diff --git a/app/views/ontologies/sections/metadata/_ontology_description_section.html.haml b/app/views/ontologies/sections/metadata/_ontology_description_section.html.haml
new file mode 100644
index 000000000..4fc4c21c7
--- /dev/null
+++ b/app/views/ontologies/sections/metadata/_ontology_description_section.html.haml
@@ -0,0 +1,53 @@
+= render Layout::CardComponent.new do |c|
+ - c.header(text: 'General information')
+ = render Layout::ListComponent.new do |l|
+ - l.row do
+ .d-flex.align-items-center
+ .description_text
+ = render TextAreaFieldComponent.new(value: @submission_latest&.description)
+ - unless @submission_latest&.logo.nil?
+ = image_tag(@submission_latest&.logo, class: 'description_img')
+ - l.row do
+ %span.creation_text
+ - if @submission_latest&.released
+ Initial release occurred on
+ %span.date_creation_text= l(Date.parse(@submission_latest.released), format: :monthfull_day_year) + '.'
+ - if @submission_latest&.contact
+ For additional information, reach out
+ %span.creator_text
+ = display_contact(@submission_latest.contact)
+
+ - unless Array(@submission_latest&.naturalLanguage).empty?
+ - l.row do
+ = render FieldContainerComponent.new(label: 'Languages') do
+ = horizontal_list_container(Array(@submission_latest&.naturalLanguage)) do |v|
+ = render LanguageFieldComponent.new(value: v)
+
+ - if @ontology.admin?(session[:user]) && @submission_latest&.pullLocation
+ - l.row do
+ = render FieldContainerComponent.new(label: 'Pull location') do
+ = horizontal_list_container([@submission_latest&.pullLocation]) do |v|
+ = render LinkFieldComponent.new(value: v)
+ - unless Array(@submission_latest&.keywords).empty? && Array(@submission_latest&.keyClasses).empty?
+ - l.row do
+ = render FieldContainerComponent.new(label: 'Keywords and classes') do
+ - values = (Array(@submission_latest&.keywords) + Array(@submission_latest&.keyClasses))
+ - values = values.map{|x| x.split(',')}.flatten
+ = horizontal_list_container(values) do |v|
+ - if link?(v)
+ = raw get_link_for_cls_ajax(v, @ontology.acronym, '_blank')
+ - else
+ = render ChipButtonComponent.new(text: v, type: "static")
+
+ - unless Array(@ontology.hasDomain).empty?
+ - l.row do
+ = render FieldContainerComponent.new(label: 'Categories and subjects') do
+ = horizontal_list_container(@ontology.hasDomain) do |v|
+ = render ChipButtonComponent.new(text: show_category_name(v), type: "static")
+
+ %hr.w-100.my-3
+ .icons_container
+ = ontology_icon_links(@ontology_icon_links, @submission_latest)
+ %hr.w-100.my-3
+ %div.text-center.pb-3
+ = link_to_modal('See all metadata...', "/ajax/submission/show_additional_metadata/#{@ontology.acronym}",data: { show_modal_title_value: "All metadata properties", show_modal_size_value: 'modal-xl' })
\ No newline at end of file
diff --git a/app/views/ontologies/sections/metadata/_ontology_fairness_section.html.haml b/app/views/ontologies/sections/metadata/_ontology_fairness_section.html.haml
new file mode 100644
index 000000000..550776961
--- /dev/null
+++ b/app/views/ontologies/sections/metadata/_ontology_fairness_section.html.haml
@@ -0,0 +1,15 @@
+- if fairness_service_enabled? && @ontology.acronym != 'AGROVOC' && @fair_scores_data
+ = render SummarySectionComponent.new(title: 'FAIR score') do |s|
+ - s.action_link do
+ = render partial: "fair_score/fair_service_header"
+
+ %div.p-2
+ %section.ont-metadata-card.ont-fair-score-card#fair-summary
+ %div.ont-section-toolbar.justify-content-between.flex-row-reverse
+ %div.align-items-start
+ .btn.btn-primary.rounded-pill.right-button
+ .span Total score : #{@fair_scores_data[:score]} ( #{@fair_scores_data[:normalizedScore]}% )
+
+ %div#fair-score-charts-container
+ = render partial: "fairs_score"
+ .account-page-card-sub-container
\ No newline at end of file
diff --git a/app/views/ontologies/sections/metadata/_ontology_metrics_section.html.haml b/app/views/ontologies/sections/metadata/_ontology_metrics_section.html.haml
new file mode 100644
index 000000000..ffe69f38d
--- /dev/null
+++ b/app/views/ontologies/sections/metadata/_ontology_metrics_section.html.haml
@@ -0,0 +1,15 @@
+= render SummarySectionComponent.new(title: "Metrics" , link: Rails.configuration.settings.links[:metrics], link_title: "Metadata properties that provide information about measurements of the ontology, such as the number of classes, individuals, etc.", show_card: false) do
+ - if @metrics.nil? || (@metrics.is_a?(Array) && @metrics.empty?) || (@metrics.respond_to?(:status) && @metrics.status == 404)
+ = empty_state_message("We have not yet calculated metrics for #{@ontology.acronym}")
+ - else
+ .metrics-container.metrics
+ - %w[classes individuals properties].each do |metric|
+ = link_to_modal nil, ontology_path(@ontology.acronym) + "/metrics_evolution?metrics_key=#{metric}",
+ class: "metrics-item", data: { show_modal_title_value: "Metrics evolution of #{@ontology.acronym}"} do
+ %hr
+ %div
+ %h4
+ = @metrics.send(metric)
+ %p
+ = render PopupLinkTextComponent.new(text: metric.humanize)
+
diff --git a/app/views/ontologies/sections/metadata/_ontology_relations_network.html.haml b/app/views/ontologies/sections/metadata/_ontology_relations_network.html.haml
new file mode 100644
index 000000000..3064d1a8d
--- /dev/null
+++ b/app/views/ontologies/sections/metadata/_ontology_relations_network.html.haml
@@ -0,0 +1,13 @@
+- unless @ontology_relations_data.nil? || @ontology_relations_data.empty?
+ = render SummarySectionComponent.new(title: 'Ontology relations network') do
+ %div.d-flex.flex-column.justify-content-center{data: {controller: "ontology-relations-network", "ontology-relations-network-data-value": @ontology_relations_data.to_json.html_safe }}
+ %button.btn.btn-link.m-2{'data-toggle': "collapse",'data-target': "#ontologyRelations"}
+ %span= t("landscape.filter_network")
+ %i.fas.fa-chevron-down
+ %div#ontologyRelations.collapse.flex-row.flex-wrap.px-2.my-1.fade{'data-action': "change->ontology-relations-network#build"}
+ - values = @relations_array.map{|relation| ["#{attr_label(relation.split(':').last)}(#{relation})", relation]}
+ = render SelectInputComponent.new(id:'relation-network', name: 'selectedRelations[]', values: values, selected:@relations_array , multiple: true)
+
+ %div{:style => "width: 100%;"}
+ %div#networkContainer{:style => "height: 465px; width: 100%;", "data-ontology-relations-network-target": "container" }
+ %div#ontologyNetwork
\ No newline at end of file
diff --git a/app/views/ontologies/sections/metadata/_ontology_submissions_section.html.haml b/app/views/ontologies/sections/metadata/_ontology_submissions_section.html.haml
new file mode 100644
index 000000000..1f90304f5
--- /dev/null
+++ b/app/views/ontologies/sections/metadata/_ontology_submissions_section.html.haml
@@ -0,0 +1,10 @@
+= render SummarySectionComponent.new(title: 'Submissions') do |s|
+ - if @ontology.admin?(session[:user])
+ - s.action_link do
+ = link_to(new_ontology_submission_path(@ontology.acronym), "aria-label": "Add submission", title: "Add submission") do
+ %i.fas.fa-plus-circle
+ - unless @submission_latest.nil? || (@submission_latest.respond_to?(:status) && @submission_latest.status == 404)
+ - s.action_link do
+ = link_to(edit_ontology_submission_path(@ontology.acronym, @submission_latest.submissionId), "aria-label": "Edit latest submission", title: "Edit latest submission") do
+ %i.fas.fa-user-edit
+ = render TurboFrameComponent.new(id: 'ontology_submissions', src: ontology_submissions_path(@ontology.acronym))
\ No newline at end of file
diff --git a/app/views/ontologies/sections/visualize.html.haml b/app/views/ontologies/sections/visualize.html.haml
index 14dee3422..b13130877 100644
--- a/app/views/ontologies/sections/visualize.html.haml
+++ b/app/views/ontologies/sections/visualize.html.haml
@@ -5,9 +5,9 @@
- @enable_ontolobridge = !$NEW_TERM_REQUEST_ONTOLOGIES.nil? && $NEW_TERM_REQUEST_ONTOLOGIES.include?(@ontology.acronym)
%div.tooltip
%div#bd_content.bd_content.explore{data:{controller: 'container-splitter'}}
- %div.sidebar.d-flex.flex-column.mr-2.card{data:{'container-splitter-target': 'container'}}
+ %div.sidebar{data:{'container-splitter-target': 'container'}}
= render partial: 'ontologies/concepts_browsers/concepts_browser'
- %div#concept_content.d-flex.flex-column.card.p-1.ml-2{data:{'container-splitter-target': 'container'}}
+ %div#concept_content.d-flex.flex-column{data:{'container-splitter-target': 'container'}}
= render partial: 'concepts/show'
- form_for(:search, :url => {:controller =>'search',:action=>'fetch_results'},:html=>{:id=>'search_form'}) do |f|
diff --git a/app/views/recommender/index.html.haml b/app/views/recommender/index.html.haml
index 7abac68a6..f5ff17276 100644
--- a/app/views/recommender/index.html.haml
+++ b/app/views/recommender/index.html.haml
@@ -30,7 +30,7 @@
-# Input text or keywords
%div.form-group.mt-4
- = text_area_tag("inputText", nil, rows: 10, class: "form-control default", placeholder: "Paste a paragraph of text or some keywords to use in calculating ontology recommendations", aria: {describedby: "inputTextHelpBlock"})
+ = text_area_tag("inputText", @text, rows: 10, class: "form-control default", placeholder: "Paste a paragraph of text or some keywords to use in calculating ontology recommendations", aria: {describedby: "inputTextHelpBlock"})
%div.card#inputTextHighlighted
%div.card-body
%small#inputTextHelpBlock.form-text
@@ -106,3 +106,14 @@
%div.col
%h5#resultsHeader
%div#recommender-results.mb-5
+
+:javascript
+ window.addEventListener("load", function() {
+ const value = document.getElementById("inputText").value
+ document.getElementById("inputText").click();
+ document.getElementById("inputText").value = value
+ if(document.getElementById("inputText").value != ''){
+ document.getElementById("recommenderButton").click()
+ window.scrollBy(0, 1080);
+ }
+ });
\ No newline at end of file
diff --git a/app/views/submissions/_form_content.html.haml b/app/views/submissions/_form_content.html.haml
index 5b55e4ec9..dc5109f9e 100644
--- a/app/views/submissions/_form_content.html.haml
+++ b/app/views/submissions/_form_content.html.haml
@@ -71,7 +71,7 @@
- data.each do |d|
= metadata_section(d[0], d[1], parent_id: "description-card") do
- - for attr in @metadata.select { |m| m['display'] == d[2] }
+ - for attr in submission_metadata.select { |m| m['category'] == d[2] }
= form_group_attribute(attr["attribute"])
%div#ontology-dates-card.mt-4
@@ -79,7 +79,7 @@
= form_group_attribute("released", default: Date.today, required: true)
= form_group_attribute("modificationDate")
= metadata_section('more-dates', 'More dates', parent_id: "ontology-dates-card") do
- - for attr in @metadata.select { |m| m['display'] == 'dates' }
+ - for attr in submission_metadata.select { |m| m['category'] == 'dates' }
= form_group_attribute(attr["attribute"])
%div#licenses-card.mt-4
@@ -94,7 +94,7 @@
to choose your license
= metadata_section('more-licensing-info', 'More licensing information', parent_id: "licenses-card") do
- - for attr in @metadata.select { |m| m['display'] == 'license' }
+ - for attr in submission_metadata.select { |m| m['category'] == 'license' }
= form_group_attribute(attr["attribute"])
%div#community.mt-4
@@ -113,11 +113,11 @@
= form_group_attribute("hasCreator")
= metadata_section('more-community-info', 'More community information', parent_id: "community") do
- - for attr in @metadata.select { |m| m['display'] == 'community' }
+ - for attr in submission_metadata.select { |m| m['category'] == 'community' }
= form_group_attribute(attr["attribute"])
= metadata_section('more-people-info', 'More people information', parent_id: "community") do
- - for attr in @metadata.select { |m| m['display'] == 'people' }
+ - for attr in submission_metadata.select { |m| m['category'] == 'people' }
= form_group_attribute(attr["attribute"])
%div#ontology-relations-more.mt-4
@@ -127,9 +127,10 @@
= form_group_attribute("isAlignedTo")
= form_group_attribute("ontologyRelatedTo")
+
= metadata_section('more-relations', 'More relations', parent_id: "ontology-relations-more") do
- - for attr in @metadata
- - if attr["display"].eql?("relations")
+ - for attr in submission_metadata
+ - if attr["category"].eql?("relations")
= form_group_attribute(attr["attribute"])
%div#ontology-content-metrics.mt-4
@@ -137,10 +138,11 @@
= form_group_attribute("preferredNamespacePrefix")
= form_group_attribute("preferredNamespaceUri")
- = metadata_section('more-informations', 'More content informations', parent_id: "ontology-content-metrics") do
- - for attr in @metadata.select { |m| m['display'] == 'content' }
+ %div#ontology-more-informations.mt-4
+ = metadata_section('more-informations', 'More content informations', parent_id: "ontology-more-informations") do
+ - for attr in submission_metadata.select { |m| m['category'] == 'content' }
= form_group_attribute(attr["attribute"])
= metadata_section('more-metrics-informations', 'More metrics informations', parent_id: "ontology-content-metrics") do
- - for attr in @metadata.select { |m| m['display'] == 'metrics' }
+ - for attr in submission_metadata.select { |m| m['category'] == 'metrics' }
= form_group_attribute(attr["attribute"])
\ No newline at end of file
diff --git a/app/views/submissions/_submissions.html.haml b/app/views/submissions/_submissions.html.haml
index 6a666118f..8c74959a3 100644
--- a/app/views/submissions/_submissions.html.haml
+++ b/app/views/submissions/_submissions.html.haml
@@ -4,24 +4,29 @@
- more_colspan = 7
- more_colspan = 6 if @ont_restricted
- %div.click_versions_collapse
+ %div.click_versions_collapse.p-1
= render_alerts_container(AdminController)
- %table#ontology_versions.table.table-sm.table-striped
- %thead
- %tr
- - if @ontology.admin?(session[:user])
- %th.align-middle ID
- %th.align-middle Version
- %th
- = generate_attribute_text("released", "Released")
- %th
- = generate_attribute_text("modificationDate", "Modified")
- %th
- = generate_attribute_text("creationDate", "Uploaded")
- - unless @ont_restricted
- %th.align-middle Downloads
- - if @ontology.admin?(session[:user])
- %th.align-middle Actions
+ = render TableComponent.new(id: 'ontology_versions', stripped: false, borderless: true) do |t|
+ - t.header do |header|
+ - if @ontology.admin?(session[:user])
+ - header.th do
+ %div.align-middle
+ ID
+ - header.th do
+ %div.align-middle
+ Version
+ - header.th do
+ = generate_attribute_text("modificationDate", "Modified", tooltip: false)
+ - header.th do
+ = generate_attribute_text("creationDate", "Uploaded", tooltip: false)
+ - unless @ont_restricted
+ - header.th do
+ %div.align-middle
+ Downloads
+ - if @ontology.admin?(session[:user])
+ - header.th do
+ %div.align-middle
+ Actions
- begin
- submission_ready = @ontology.explore.latest_submission({:include_status => 'ready', display: 'submissionId'})
@@ -30,23 +35,29 @@
- submission_readyId = -1
- @submissions.each_with_index do |sub, index|
- hidden_row_class = index >= 5 ? "hidden_ont hidden_select" : ""
- %tr{class: "#{hidden_row_class}", id: "submission_#{sub.submissionId}"}
+ - t.row(id:"submission_#{sub.submissionId}" , class_css: hidden_row_class) do |r|
+
- if @ontology.admin?(session[:user])
- %td
- = sub.submissionId
- %td
- = raw status_link(sub, sub.submissionId==submission_readyId)
- %td
- = xmldatetime_to_date(sub.released) unless sub.released.nil?
- %td
- = xmldatetime_to_date(sub.modificationDate) unless sub.modificationDate.nil?
- %td
- = xmldatetime_to_date(sub.creationDate) unless sub.creationDate.nil?
+ - r.td { raw sub.submissionId }
+ - r.td { raw status_link(sub, sub.submissionId==submission_readyId)}
+ - r.td { xmldatetime_to_date(sub.modificationDate) unless sub.modificationDate.nil? }
+ - r.td { xmldatetime_to_date(sub.creationDate) unless sub.creationDate.nil? }
+
- unless @ont_restricted
- %td
- = raw download_link(sub, @ontology)
+ - r.td do
+ %div.dropdown
+ %button.btn.btn-outline-primary.rounded-pill.dropdown-toggle{type:"button", 'data-toggle':"dropdown", 'aria-expanded': "false", style:'white-space: nowrap'}
+ Download
+ %span.sr-only Toggle Dropdown
+ .dropdown-menu
+ - links = download_link(sub,@ontology)
+ - links.each do |value|
+ - link,label = value.values
+ %a.dropdown-item{ href: link }= label
+
+ -# = raw download_link(sub, @ontology)
- if @ontology.admin?(session[:user])
- %td
+ - r.td do
%div.d-flex
%a.btn.btn-sm.btn-link{:href => "/ontologies/#{@ontology.acronym}/submissions/#{sub.submissionId}/edit"}
%span Edit
@@ -55,8 +66,8 @@
= button_to "Delete", "/admin/ontologies/#{@ontology.acronym}/submissions/#{sub.submissionId}?turbo_stream=true", method: :delete, class:'btn btn-sm btn-link', form: {data: { turbo: true, turbo_confirm: alert_text, turbo_frame: '_top'}}
- if @submissions.length > 5
- %tr
- %td{colspan: more_colspan, class: "show_more_subs"}
+ - t.row(class_css: "show_more_subs") do |r|
+ - r.td(colspan: more_colspan) do
%a#version_toggle{:href => ""} more...
:javascript
diff --git a/config/bioportal_config_env.rb.sample b/config/bioportal_config_env.rb.sample
index 4c83979d0..0f747779c 100644
--- a/config/bioportal_config_env.rb.sample
+++ b/config/bioportal_config_env.rb.sample
@@ -61,6 +61,34 @@ $ANNOUNCE_LIST||= "users-list@test"
# Where "ncbo" is the namespace used as key in the interportal_hash
$INTERPORTAL_HASH = {}
+# OAuth2 authentication
+$OMNIAUTH_PROVIDERS = {
+ github: {
+ client_id: 'CLIENT_ID',
+ client_secret: 'CLIENT_SECRET',
+ icon: 'icons/github.svg',
+ },
+ google: {
+ strategy: :google_oauth2,
+ client_id: 'CLIENT_ID',
+ client_secret: 'CLIENT_SECRET',
+ icon: 'icons/google.svg',
+ },
+ orcid: {
+ client_id: 'CLIENT_SECRET',
+ client_secret: 'CLIENT_SECRET',
+ icon: 'icons/orcid.svg'
+ },
+ keycloak: {
+ strategy: :keycloak_openid,
+ client_id: 'YOUR_KEYCLOAK_CLIENT_ID',
+ client_secret: 'YOUR_KEYCLOAK_CLIENT_SECRET',
+ client_options: { site: 'KEYCLOAK_SITE', realm: 'KEYCLOAK_REALM' },
+ name: 'keycloak',
+ icon: 'icons/keycloak.svg'
+ }
+}.freeze
+
# Don't load and don't display recent mappings if false, in case of too many mappings (take longer to load homepage)
$DISPLAY_RECENT = false
diff --git a/config/initializers/omniauth.rb b/config/initializers/omniauth.rb
new file mode 100644
index 000000000..af53788f9
--- /dev/null
+++ b/config/initializers/omniauth.rb
@@ -0,0 +1,5 @@
+Rails.application.config.middleware.use OmniAuth::Builder do
+ $OMNIAUTH_PROVIDERS.each do |provider, config|
+ provider config[:strategy] || provider, config[:client_id], config[:client_secret], client_options: {}.merge(config[:client_options].to_h)
+ end
+end
\ No newline at end of file
diff --git a/config/routes.rb b/config/routes.rb
index 057297ac7..2f4465c34 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -2,6 +2,8 @@
root to: 'home#index'
+ get 'auth/:provider/callback', to: 'login#create_omniauth'
+
get '/notes/new_comment', to: 'notes#new_comment'
get '/notes/new_proposal', to: 'notes#new_proposal'
get '/notes/new_reply', to: 'notes#new_reply'
@@ -42,6 +44,7 @@
get 'instances/:instance_id', to: 'instances#show', constraints: { instance_id: /[^\/?]+/ }
get 'schemes/show_scheme', to: 'schemes#show'
get 'collections/show'
+ get 'metrics_evolution'
end
resources :login
@@ -85,6 +88,7 @@
get '/about' => 'home#about'
get '/site_config' => 'home#site_config'
get '/validate_ontology_file' => 'home#validate_ontology_file_show'
+ post '/annotator_recommender_form' => 'home#annotator_recommender_form'
match '/validate_ontology_file' => 'home#validate_ontology_file', via: [:get, :post]
get '/layout_partial/:partial' => 'home#render_layout_partial'
match '/visits', to: 'visits#index', via: :get
@@ -113,6 +117,7 @@
get '/ontologies/:acronym/classes/:purl_conceptid', to: 'ontologies#show', constraints: { purl_conceptid: /[^\/]+/ }
get '/ontologies/:acronym/: f', to: 'ontologies#show', constraints: { purl_conceptid: /[^\/]+/ }
match '/ontologies/:acronym/submissions/:id/edit_metadata' => 'submissions#edit_metadata', via: [:get, :post]
+ get '/ontologies_filter', to: 'ontologies#ontologies_filter'
# Analytics
get '/analytics/:action' => 'analytics#(?-mix:search_result_clicked|user_intention_surveys)'
@@ -144,6 +149,8 @@
get 'ajax/label_xl', to: "label_xl#show"
get '/ajax/biomixer' => 'concepts#biomixer'
get '/ajax/fair_score/html' => 'fair_score#details_html'
+ get '/ajax/submission/show_additional_metadata/:id' => 'ontologies#show_additional_metadata'
+ get '/ajax/submission/show_licenses/:id' => 'ontologies#show_licenses'
get '/ajax/fair_score/json' => 'fair_score#details_json'
get '/ajax/:ontology/instances' => 'instances#index_by_ontology'
get '/ajax/:ontology/classes/:conceptid/instances' => 'instances#index_by_class', :constraints => { conceptid: /[^\/?]+/ }
diff --git a/package.json b/package.json
index d112843e7..62dabf435 100644
--- a/package.json
+++ b/package.json
@@ -4,11 +4,18 @@
"dependencies": {
"@hotwired/stimulus": "^3.0.1",
"@hotwired/turbo-rails": "^7.1.1",
+ "debounce": "^1.2.1",
"esbuild": "^0.14.41",
"flatpickr": "^4.6.13",
"split.js": "^1.6.5",
"stimulus-flatpickr": "^3.0.0-0",
- "stimulus-rails-nested-form": "^4.0.0"
+ "stimulus-read-more": "^4.1.0",
+ "stimulus-rails-nested-form": "^4.0.0",
+ "stimulus-timeago": "^4.1.0",
+ "vis-data": "^7.1.6",
+ "vis-network": "^9.1.6",
+ "vis-util": "^5.0.3",
+ "tom-select": "^2.2.2"
},
"scripts": {
"build": "esbuild app/javascript/*.* --bundle --sourcemap --outdir=app/assets/builds"
diff --git a/public/browse/.bowerrc b/public/browse/.bowerrc
deleted file mode 100755
index 7dcff4cd0..000000000
--- a/public/browse/.bowerrc
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "directory" : "lib"
-}
\ No newline at end of file
diff --git a/public/browse/.gitignore b/public/browse/.gitignore
deleted file mode 100755
index b702acc68..000000000
--- a/public/browse/.gitignore
+++ /dev/null
@@ -1,7 +0,0 @@
-logs/*
-!.gitkeep
-node_modules/
-bower_components/
-tmp
-.DS_Store
-.idea
\ No newline at end of file
diff --git a/public/browse/.jshintrc b/public/browse/.jshintrc
deleted file mode 100755
index 6f00218e3..000000000
--- a/public/browse/.jshintrc
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "globalstrict": true,
- "globals": {
- "angular": false,
- "describe": false,
- "it": false,
- "expect": false,
- "beforeEach": false,
- "afterEach": false,
- "module": false,
- "inject": false
- }
-}
\ No newline at end of file
diff --git a/public/browse/app.css b/public/browse/app.css
deleted file mode 100755
index 4cc86735e..000000000
--- a/public/browse/app.css
+++ /dev/null
@@ -1,184 +0,0 @@
-.grid-container {
- max-width: 1400px;
-}
-[ng-cloak].splash {
- display: block !important;
-}
-.splash {
- display: none;
- width: 25%;
- height: 4em;
- padding: 2em;
- text-align: center;
- margin: 2em auto;
- background-color: #ECECEC;
- border-radius: 3px;
-}
-[ng-cloak] {
- display: none;
-}
-.admin {
- background-color: #EFFFEF !important;
-}
-.welcome_admin {
- width: 33%;
- padding: 7px 10px 5px;
- border-radius: 3px;
- text-align: center;
- top: -5em;
- position: relative;
- float: right;
- left: -33%;
-}
-.search {
- float: left;
- width: 150px;
- padding: 2px 4px 1px;
- margin-top: -5px;
- width: 200px;
-}
-.smaller {
- color: gray;
- font-size: .8em;
- padding-bottom: 2px;
-}
-#facets {
- margin-top: 1em;
-}
-.new_ontology_button {
- display: inline-block;
- width: 100%;
- padding-left: 0px !important;
- padding-right: 0px !important;
- margin-top: 1em;
-}
-.facet {
- margin: 1em 0;
- border: thin lightGray solid;
- padding: 5px;
- border-radius: 3px;
-}
-.facet_disabled {
- color: gray;
-}
-.checkbox_list {
- max-height: 200px;
- overflow: auto;
- padding-left: 1px;
-}
-.checkbox_list > span {
- overflow-x: hidden;
- white-space: nowrap;
- text-overflow: ellipsis;
- width: 200px;
- display: block;
-}
-#sorting {
-}
-#sorting_float {
- float: right;
- margin-bottom: .5em;
-}
-@keyframes highlight {
- 0% {
- background: yellow;
- }
- 100% {
- background: none;
- }
-}
-@-webkit-keyframes highlight {
- 0% {
- background: yellow;
- }
- 100% {
- background: none;
- }
-}
-.trigger_highlight-add, .trigger_highlight-remove {
- -webkit-animation: highlight 1s;
- animation: highlight 1s;
-}
-#ontologies {
-}
-.clear {
- clear: both;
-}
-.ontology {
- border: thin gray solid;
- border-radius: 5px;
- padding: .5em 1em .5em;
- margin: 1em 0;
-}
-.ontology_view_badge {
- float: left;
- padding: 5px;
- text-align: center;
- margin-right: 5px;
- border-radius: 3px;
- color: white;
- background-color: #234979;
- font-size: 1em;
- font-weight: bold;
-}
-.ontology_view_badge a {
- color: white;
- text-decoration: none;
-}
-.locked_ont {
- font-size: .65em;
- padding-left: .2em;
- color: gray;
- cursor: help;
- /* Make the lock appear in the upper left corner */
- /*
- background-color: #234979;
- padding: 2.5px 4px;
- font-size: 1em;
- color: white;
- position: relative;
- left: -10px;
- top: -8px;
- border-radius: 5px 0px;
- float: left;
- */
-}
-.ont-info {
- margin: 5px 5px 0 0;
- display: inline-block;
- padding: 5px 10px 3px;
- border-radius: 3px;
- background-color: #ECECEC;
- font-size: 11px;
-}
-.badge_grid {
- padding-bottom: 10px;
- float: right !important;
-}
-.ontology_badge {
- border-radius: 5px;
- text-align: center;
- max-width: 120px;
- height: 45px;
- max-height: 45px;
- border: solid #234979 thin;
-}
-.ontology_badge:hover {
- cursor: pointer;
-}
-.badge_title {
- border-radius: 4px 4px 0 0;
- font-size: 12px;
- color: white;
- background-color: #234979;
-}
-.badge_count {
- border-radius: 0 0 4px 4px;
- height: 22px;
- font-size: 1.1em;
- font-weight: bold;
- color: #234979;
-}
-.ontology_badge:hover .badge_count {
- background-color: rgba(220, 235, 255, 0.79);
-}
\ No newline at end of file
diff --git a/public/browse/app.js b/public/browse/app.js
deleted file mode 100755
index fe18ca0d9..000000000
--- a/public/browse/app.js
+++ /dev/null
@@ -1,417 +0,0 @@
-'use strict';
-
-// Declare app level module which depends on views, and components
-angular.module('FacetedBrowsing', [
- 'ngRoute',
- 'FacetedBrowsing.OntologyList'
-]).
-config( ['$locationProvider', function ($locationProvider) {
- $locationProvider.html5Mode(true);
-}])
-;
-
-var app = angular.module('FacetedBrowsing.OntologyList', ['checklist-model', 'ngAnimate', 'pasvaz.bindonce'])
-
-.controller('OntologyList', ['$scope', '$animate', '$timeout', function($scope, $animate, $timeout) {
- // Default values
- $scope.visible_ont_count = 0;
- $scope.ontology_sort_order = "-popularity";
- $scope.previous_sort_order = "-popularity";
- $scope.show_highlight = false;
-
- // Data transfer from Rails
- $scope.debug = jQuery(document).data().bp.development;
- $scope.admin = jQuery(document).data().bp.admin;
- $scope.ontologies = jQuery(document).data().bp.ontologies;
- $scope.formats = jQuery(document).data().bp.formats.sort();
- $scope.categories = jQuery(document).data().bp.categories.sort(function(a, b){
- if (a.name < b.name) return -1;
- if (a.name > b.name) return 1;
- return 0;
- });
- $scope.categories_hash = jQuery(document).data().bp.categories_hash;
- $scope.groups = jQuery(document).data().bp.groups.sort(function(a, b){
- if (a.acronym < b.acronym) return -1;
- if (a.acronym > b.acronym) return 1;
- return 0;
- });
- $scope.groups_hash = jQuery(document).data().bp.groups_hash;
-
- $scope.formality_levels = jQuery(document).data().bp.formality_levels;
- $scope.natural_languages = jQuery(document).data().bp.natural_languages;
- $scope.is_of_type = jQuery(document).data().bp.is_of_type;
-
- // Search setup
- $scope.searchText = null;
- $scope.ontIndex = lunr(function() {
- this.field('acronym', 100);
- this.field('name', 50);
- this.field('description');
- this.ref('id');
- });
- $scope.ontIndex.pipeline.reset();
-
- // Default setup for facets
- $scope.facets = {
- types: {
- active: ["ontology"],
- ont_property: "type",
- filter: function(ontology) {
- if ($scope.facets.types.active.length == 0)
- return true;
- if ($scope.facets.types.active.indexOf(ontology.type) === -1)
- return false;
- return true;
- },
- },
- formats: {
- active: [],
- ont_property: "format",
- filter: function(ontology) {
- if ($scope.facets.formats.active.length == 0)
- return true;
- if ($scope.facets.formats.active.indexOf(ontology.format) === -1)
- return false;
- return true;
- },
- },
- groups: {
- active: [],
- ont_property: "groups",
- filter: function(ontology) {
- if ($scope.facets.groups.active.length == 0)
- return true;
- if (intersection($scope.facets.groups.active, ontology.groups).length === 0)
- return false;
- return true;
- },
- },
- categories: {
- active: [],
- ont_property: "categories",
- filter: function(ontology) {
- if ($scope.facets.categories.active.length == 0)
- return true;
- if (intersection($scope.facets.categories.active, ontology.categories).length === 0)
- return false;
- return true;
- },
- },
- artifacts: {
- active: [],
- ont_property: "artifacts",
- filter: function(ontology) {
- if ($scope.facets.artifacts.active.length == 0)
- return true;
- if (intersection($scope.facets.artifacts.active, ontology.artifacts).length === 0)
- return false;
- return true;
- },
- },
- missing_status: {
- active: "",
- ont_property: "submissionStatus",
- values: ["None", "RDF", "OBSOLETE", "METRICS", "RDF_LABELS", "UPLOADED", "INDEXED", "ANNOTATOR", "DIFF"],
- filter: function(ontology) {
- if ($scope.facets.missing_status.active == "")
- return true;
- if (ontology.submissionStatus.indexOf($scope.facets.missing_status.active) !== -1)
- return false;
- return true;
- }
- },
- upload_date: {
- active: "",
- ont_property: "creationDate",
- values: {day: 1, week: 7, month: 30, three_months: 90, six_months: 180, year: 365, all: "all"},
- day_text: ["day", "week", "month", "three_months", "six_months", "year", "all"],
- filter: function(ontology) {
- var active = $scope.facets.upload_date.active;
- if (active == "")
- return true;
- if (!ontology.submission)
- return false;
- var ontDate = new Date(ontology.creationDate);
- var compareDate = new Date();
- compareDate.setDate(compareDate.getDate() - active);
- if (ontDate >= compareDate)
- return true;
- return false;
- }
- },
- formality_levels: {
- active: [],
- ont_property: "hasFormalityLevel",
- filter: function(ontology) {
- if ($scope.facets.formality_levels.active.length == 0)
- return true;
- if ($scope.facets.formality_levels.active.indexOf(ontology.hasFormalityLevel) === -1)
- return false;
- return true;
- }
- },
- natural_languages: {
- active: [],
- ont_property: "naturalLanguage",
- filter: function(ontology) {
- if ($scope.facets.natural_languages.active.length == 0)
- return true;
- if ( !ontology.naturalLanguage )
- return false;
- for (var i = 0; i < ontology.naturalLanguage.length; i++) {
- if ($scope.facets.natural_languages.active.indexOf(ontology.naturalLanguage[i]) !== -1)
- return true;
- }
- return false;
- }
- },
- is_of_type: {
- active: [],
- ont_property: "isOfType",
- filter: function(ontology) {
- if ($scope.facets.is_of_type.active.length == 0)
- return true;
- if ($scope.facets.is_of_type.active.indexOf(ontology.isOfType) === -1)
- return false;
- return true;
- }
- }
- }
-
- // Instantiate object counts
- // This doesn't happen on the facet itself because
- // there is a $watch directive and updating counts
- // on the facets causes an infinite loop.
- $scope.facet_counts = {};
- Object.keys($scope.facets).forEach(function(facet) {$scope.facet_counts[facet] = {}});
-
- // Default values for facets that aren't definied on the ontologies
- $scope.types = {
- ontology: {sort: 1, id: "ontology"},
- ontology_view: {sort: 2, id: "ontology_view"}
- };
- $scope.artifacts = ["notes", "reviews", "projects", "summary_only"];
-
- $scope.groupAcronyms = function(groups) {
- var groupNames = [];
- angular.forEach(groups, function(group) {
- groupNames.push($scope.groups_hash[group].acronym);
- });
- return groupNames;
- };
-
- $scope.categoryNames = function(categories) {
- var catNames = [];
- angular.forEach(categories, function(category) {
- catNames.push($scope.categories_hash[category].name)
- })
- return catNames;
- }
-
- $scope.adminUsernames = function(admins) {
- return admins.map(function(a){return a.split('/').slice(-1)[0]});
- }
-
- $scope.ontologySortOrder = function(newOrder) {
- $scope.ontology_sort_order = newOrder;
- }
-
- // This watches the facets and updates the list depending on which facets are selected
- // All facets are basically ANDed together and return true if no options under the facet are selected.
- $scope.$watch('facets', function() {
- filterOntologies();
- }, true);
-
- $scope.$watch('searchText', function() {
- filterOntologies();
- });
-
- var filterOntologies = function() {
- var key, i, ontology, facet, facet_count, show, other_facets, count = 0;
- $scope.show_highlight = false;
- $scope.show_highlight = true;
-
- // Reset facet counts
- Object.keys($scope.facet_counts).forEach(function(key) {
- $scope.facet_counts[key] = {};
- });
-
- // First, filter by search. Do this first because the facets
- // will apply on top of the search results (EX: for hiding views)
- filterSearch();
-
- // Filter ontologies based on facet + count for facets
- for (i = 0; i < $scope.ontologies.length; i++) {
- ontology = $scope.ontologies[i];
-
- if (searchActive() && ontology.show === false) continue;
-
- // Filter out ontologies based on their facet filter functions
- ontology.show = Object.keys($scope.facets).map(function(key) {
- return $scope.facets[key].filter(ontology);
- }).every(Boolean);
-
- // Check each facet entry to calculate counts
- // Counts are calculated by looking at whether or not ontologies match OTHER facets
- // IE, counts show what will be available for a given facet entry if that entry
- // were to be selected relative to what is already selected in other facets.
- Object.keys($scope.facets).forEach(function(key) {
- facet = $scope.facets[key];
- other_facets = Object.keys($scope.facets).filter(function(f){return key != f});
- show = other_facets.map(function(other_facet){return $scope.facets[other_facet].filter(ontology)}).every(Boolean);
- if (show) {
- facet_count = $scope.facet_counts[key];
- if (angular.isArray(ontology[facet.ont_property])) {
- ontology[facet.ont_property].forEach(function(val) {
- facet_count[val] = (facet_count[val] || 0) + 1;
- });
- } else {
- facet_count[ontology[facet.ont_property]] = (facet_count[ontology[facet.ont_property]] || 0) + 1;
- }
- }
- });
- }
-
- $scope.visible_ont_count = $scope.ontologies.filter(function(ont) {return ont.show}).length;
-
- // Highlight the count
- count = $("#visible_ont_count");
- if (count.hasClass("trigger_highlight")) {
- $animate.removeClass(count, "trigger_highlight");
- } else {
- $animate.addClass(count, "trigger_highlight");
- }
- }
-
- var filterSearch = function() {
- var i, results, ontology, found = {};
- if (!searchActive()) {
- $scope.ontologySortOrder($scope.previous_sort_order);
- return;
- }
- if ($scope.ontology_sort_order !== "-search_rank") {
- $scope.previous_sort_order = $scope.ontology_sort_order;
- }
- $scope.ontologySortOrder("-search_rank");
- results = $scope.ontIndex.search($scope.searchText);
-
- angular.forEach(results, function(r){found[r.ref] = r});
- for (i = 0; i < $scope.ontologies.length; i++) {
- ontology = $scope.ontologies[i];
- ontology.show = false;
- ontology.search_rank = 0;
- if (found[ontology.id]) {
- ontology.show = true;
- ontology.search_rank = found[ontology.id].score;
- }
- }
- }
-
- var searchActive = function() {
- return !($scope.searchText === null || $scope.searchText === "");
- }
-
- var countAllInFacet = function(facet) {
- var active_facets = Object.keys($scope.facets).filter(function(facet) {return $scope.facets[facet].active.length > 0});
- if (active_facets.length == 0 || (active_facets.length == 1 && active_facets[0] == facet)) {
- return true;
- }
- return false;
- }
-
- var intersection = function(x, y) {
- if (typeof x === 'undefined' || typeof y === 'undefined') {return [];}
- var ret = [];
- for (var i = 0; i < x.length; i++) {
- for (var z = 0; z < y.length; z++) {
- if (x[i] == y[z]) {
- ret.push(i);
- break;
- }
- }
- }
- return ret;
- }
-
-
- $scope.init = function() {
- $scope.ontologies = jQuery(document).data().bp.fullOntologies;
- if (BP_queryString().filter) {
- angular.forEach($scope.groups, function(group) {
- if (group.acronym == BP_queryString().filter)
- $scope.facets.groups.active.push(group.id);
- });
- }
- filterOntologies();
- angular.forEach($scope.ontologies, function(ont) {
- $scope.ontIndex.add({
- id: ont.id,
- acronym: ont.acronym,
- name: ont.name,
- description: ont.description
- })
- });
- }
- $timeout($scope.init);
-
-}])
-
-.filter('idToTitle', function() {
- return function(input) {
- if (input) {
- var splitInput = input.replace(/_/g, " ").split(" ");
- var newInput = [];
- var word;
- for (word in splitInput) {
- word = splitInput[word];
- if (word[0].toUpperCase() == word[0]) {
- newInput.push(word);
- } else {
- newInput.push(word[0].toUpperCase() + word.slice(1));
- }
-
- }
- return newInput.join(" ");
- }
- };
-})
-
-.filter('humanShortNum', function() {
- return function(input) {
- if (input) {
- var num = parseInt(input);
- if (num < 10000) {return num;}
- if (num > 10000 && num < 1000000) {
- return String(+(Math.round(num / 1000 + "e+1") + "e-1")) + "k"
- }
- if (num > 1000000) {
- return String(+(Math.round(num / 100000 + "e+1") + "e-1")) + "M"
- }
- return newInput.join(" ");
- }
- };
-})
-
-.filter("toArray", function() {
- return function(obj) {
- var result = [];
- angular.forEach(obj, function(val, key) {
- result.push(val);
- });
- return result;
- };
-})
-
-.filter('htmlToText', function() {
- return function(text) {
- return String(text).replace(/<[^>]+>/gm, '');
- }
-})
-
-.filter('descriptionToText', function() {
- return function(text) {
- text = String(text).replace(/<[^>]+>/gm, '');
- return text.split(/\.\W/)[0];
- }
-})
-;
\ No newline at end of file
diff --git a/public/browse/bower.json b/public/browse/bower.json
deleted file mode 100755
index ed30585ec..000000000
--- a/public/browse/bower.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "angular-seed",
- "description": "A starter project for AngularJS",
- "version": "0.0.0",
- "homepage": "https://github.com/angular/angular-seed",
- "license": "MIT",
- "private": true,
- "dependencies": {
- "angular": "1.3.x",
- "angular-route": "1.3.x",
- "angular-loader": "1.3.x",
- "angular-mocks": "~1.3.x",
- "angular-animate": "1.3.x",
- "html5-boilerplate": "~4.3.0",
- "lunr.js": "~0.5.6",
- "angular-bindonce": "~0.3.3"
- }
-}
diff --git a/public/browse/checklist-model.js b/public/browse/checklist-model.js
deleted file mode 100644
index 228f0c5a0..000000000
--- a/public/browse/checklist-model.js
+++ /dev/null
@@ -1,99 +0,0 @@
-/**
- * Checklist-model
- * AngularJS directive for list of checkboxes
- */
-
-angular.module('checklist-model', [])
-.directive('checklistModel', ['$parse', '$compile', function($parse, $compile) {
- // contains
- function contains(arr, item) {
- if (angular.isArray(arr)) {
- for (var i = 0; i < arr.length; i++) {
- if (angular.equals(arr[i], item)) {
- return true;
- }
- }
- }
- return false;
- }
-
- // add
- function add(arr, item) {
- arr = angular.isArray(arr) ? arr : [];
- for (var i = 0; i < arr.length; i++) {
- if (angular.equals(arr[i], item)) {
- return arr;
- }
- }
- arr.push(item);
- return arr;
- }
-
- // remove
- function remove(arr, item) {
- if (angular.isArray(arr)) {
- for (var i = 0; i < arr.length; i++) {
- if (angular.equals(arr[i], item)) {
- arr.splice(i, 1);
- break;
- }
- }
- }
- return arr;
- }
-
- // http://stackoverflow.com/a/19228302/1458162
- function postLinkFn(scope, elem, attrs) {
- // compile with `ng-model` pointing to `checked`
- $compile(elem)(scope);
-
- // getter / setter for original model
- var getter = $parse(attrs.checklistModel);
- var setter = getter.assign;
-
- // value added to list
- var value = $parse(attrs.checklistValue)(scope.$parent);
-
- // watch UI checked change
- scope.$watch('checked', function(newValue, oldValue) {
- if (newValue === oldValue) {
- return;
- }
- var current = getter(scope.$parent);
- if (newValue === true) {
- setter(scope.$parent, add(current, value));
- } else {
- setter(scope.$parent, remove(current, value));
- }
- });
-
- // watch original model change
- scope.$parent.$watch(attrs.checklistModel, function(newArr, oldArr) {
- scope.checked = contains(newArr, value);
- }, true);
- }
-
- return {
- restrict: 'A',
- priority: 1000,
- terminal: true,
- scope: true,
- compile: function(tElement, tAttrs) {
- if (tElement[0].tagName !== 'INPUT' || tElement[0].getAttribute('type') !== 'checkbox') {
- throw 'checklist-model should be applied to `input[type="checkbox"]`.';
- }
-
- if (!tAttrs.checklistValue) {
- throw 'You should provide `checklist-value`.';
- }
-
- // exclude recursion
- tElement.removeAttr('checklist-model');
-
- // local scope var storing individual checkbox model
- tElement.attr('ng-model', 'checked');
-
- return postLinkFn;
- }
- };
-}]);
diff --git a/public/browse/e2e-tests/protractor.conf.js b/public/browse/e2e-tests/protractor.conf.js
deleted file mode 100755
index b45a117aa..000000000
--- a/public/browse/e2e-tests/protractor.conf.js
+++ /dev/null
@@ -1,19 +0,0 @@
-exports.config = {
- allScriptsTimeout: 11000,
-
- specs: [
- '*.js'
- ],
-
- capabilities: {
- 'browserName': 'chrome'
- },
-
- baseUrl: 'http://localhost:8000/app/',
-
- framework: 'jasmine',
-
- jasmineNodeOpts: {
- defaultTimeoutInterval: 30000
- }
-};
diff --git a/public/browse/e2e-tests/scenarios.js b/public/browse/e2e-tests/scenarios.js
deleted file mode 100755
index 59d816fc1..000000000
--- a/public/browse/e2e-tests/scenarios.js
+++ /dev/null
@@ -1,42 +0,0 @@
-'use strict';
-
-/* https://github.com/angular/protractor/blob/master/docs/toc.md */
-
-describe('faceted browsing', function() {
-
- browser.get('index.html');
-
- it('should automatically redirect to /view1 when location hash/fragment is empty', function() {
- expect(browser.getLocationAbsUrl()).toMatch("/view1");
- });
-
-
- describe('view1', function() {
-
- beforeEach(function() {
- browser.get('index.html#/view1');
- });
-
-
- it('should render view1 when user navigates to /view1', function() {
- expect(element.all(by.css('[ng-view] p')).first().getText()).
- toMatch(/partial for view 1/);
- });
-
- });
-
-
- describe('view2', function() {
-
- beforeEach(function() {
- browser.get('index.html#/view2');
- });
-
-
- it('should render view2 when user navigates to /view2', function() {
- expect(element.all(by.css('[ng-view] p')).first().getText()).
- toMatch(/partial for view 2/);
- });
-
- });
-});
diff --git a/public/browse/font/webhostinghub-glyphs.eot b/public/browse/font/webhostinghub-glyphs.eot
deleted file mode 100755
index 7e9248cee..000000000
Binary files a/public/browse/font/webhostinghub-glyphs.eot and /dev/null differ
diff --git a/public/browse/font/webhostinghub-glyphs.svg b/public/browse/font/webhostinghub-glyphs.svg
deleted file mode 100755
index b54ba7923..000000000
--- a/public/browse/font/webhostinghub-glyphs.svg
+++ /dev/null
@@ -1,7835 +0,0 @@
-
-
-
diff --git a/public/browse/font/webhostinghub-glyphs.ttf b/public/browse/font/webhostinghub-glyphs.ttf
deleted file mode 100755
index 6ad706c63..000000000
Binary files a/public/browse/font/webhostinghub-glyphs.ttf and /dev/null differ
diff --git a/public/browse/font/whhg.css b/public/browse/font/whhg.css
deleted file mode 100755
index 9423e9914..000000000
--- a/public/browse/font/whhg.css
+++ /dev/null
@@ -1,2085 +0,0 @@
-@font-face {
- font-family: 'WebHostingHub-Glyphs';
- src: url('webhostinghub-glyphs.eot');
- src: url('webhostinghub-glyphs.eot?#iefix') format('embedded-opentype'),
- url('webhostinghub-glyphs.ttf') format('truetype');
- font-weight: normal;
- font-style: normal;
- -moz-font-feature-settings: "calt=0,liga=0";
-}
-[class^="icon-"], [class*=" icon-"] {font-family:'WebHostingHub-Glyphs';background:none;width:auto;height:auto;font-style:normal}
-.icon-aaabattery:before{content:'\f413'}
-.icon-abacus:before{content:'\f261'}
-.icon-accountfilter:before{content:'\f05e'}
-.icon-acsource:before{content:'\f3ea'}
-.icon-addfriend:before{content:'\f3da'}
-.icon-address:before{content:'\f08f'}
-.icon-addshape:before{content:'\f1fd'}
-.icon-addtocart:before{content:'\f394'}
-.icon-addtolist:before{content:'\f2ac'}
-.icon-adjust:before{content:'\f484'}
-.icon-adobe:before{content:'\f1c9'}
-.icon-ads-bilboard:before{content:'\f082'}
-.icon-affiliate:before{content:'\f01e'}
-.icon-ajax:before{content:'\f06f'}
-.icon-alarm:before{content:'\f233'}
-.icon-alarmalt:before{content:'\f23d'}
-.icon-album-cover:before{content:'\f19f'}
-.icon-alertalt:before{content:'\f2b4'}
-.icon-alertpay:before{content:'\f269'}
-.icon-algorhythm:before{content:'\f0b8'}
-.icon-alienship:before{content:'\f41f'}
-.icon-alienware:before{content:'\f3be'}
-.icon-align-center:before{content:'\f1d9'}
-.icon-align-justify:before{content:'\f1da'}
-.icon-align-left:before{content:'\f1d7'}
-.icon-align-right:before{content:'\f1d8'}
-.icon-alignbottomedge:before{content:'\f1d3'}
-.icon-alignhorizontalcenter:before{content:'\f1d2'}
-.icon-alignleftedge:before{content:'\f1d6'}
-.icon-alignrightedge:before{content:'\f1d5'}
-.icon-aligntopedge:before{content:'\f1d4'}
-.icon-alignverticalcenter:before{content:'\f1d1'}
-.icon-amd:before{content:'\f020'}
-.icon-analogdown:before{content:'\f2cb'}
-.icon-analogleft:before{content:'\f2c8'}
-.icon-analogright:before{content:'\f2c9'}
-.icon-analogup:before{content:'\f2ca'}
-.icon-analytics-piechart:before{content:'\f000'}
-.icon-analyticsalt-piechartalt:before{content:'\f001'}
-.icon-anchor-port:before{content:'\f21d'}
-.icon-android:before{content:'\f12a'}
-.icon-angrybirds:before{content:'\f3c1'}
-.icon-antenna:before{content:'\f3ec'}
-.icon-apache-feather:before{content:'\f056'}
-.icon-aperture:before{content:'\f356'}
-.icon-appointment-agenda:before{content:'\f26c'}
-.icon-archive:before{content:'\f171'}
-.icon-arrow-down:before{content:'\f2fe'}
-.icon-arrow-left:before{content:'\f305'}
-.icon-arrow-right:before{content:'\f304'}
-.icon-arrow-up:before{content:'\f301'}
-.icon-asterisk:before{content:'\f317'}
-.icon-asteriskalt:before{content:'\002a'}
-.icon-at:before{content:'\40'}
-.icon-atari:before{content:'\f3b9'}
-.icon-authentication-keyalt:before{content:'\f051'}
-.icon-automobile-car:before{content:'\f239'}
-.icon-autorespond:before{content:'\f08e'}
-.icon-avatar:before{content:'\f15a'}
-.icon-avataralt:before{content:'\f161'}
-.icon-avengers:before{content:'\f342'}
-.icon-awstats:before{content:'\f04c'}
-.icon-axe:before{content:'\f2ef'}
-.icon-backup-vault:before{content:'\f004'}
-.icon-backupalt-vaultalt:before{content:'\f005'}
-.icon-backupwizard:before{content:'\f05f'}
-.icon-backward:before{content:'\f183'}
-.icon-bag:before{content:'\f234'}
-.icon-baloon:before{content:'\f405'}
-.icon-ban-circle:before{content:'\f313'}
-.icon-banana:before{content:'\f3f4'}
-.icon-bandwidth:before{content:'\f006'}
-.icon-bank:before{content:'\f262'}
-.icon-barchart:before{content:'\f02f'}
-.icon-barchartalt:before{content:'\f07d'}
-.icon-barcode:before{content:'\f276'}
-.icon-basecamp:before{content:'\f160'}
-.icon-basketball:before{content:'\f2e9'}
-.icon-bat:before{content:'\f3d3'}
-.icon-batman:before{content:'\f348'}
-.icon-batteryaltcharging:before{content:'\f104'}
-.icon-batteryaltfull:before{content:'\f101'}
-.icon-batteryaltsixty:before{content:'\f102'}
-.icon-batteryaltthird:before{content:'\f103'}
-.icon-batterycharged:before{content:'\f0f4'}
-.icon-batterycharging:before{content:'\f0f3'}
-.icon-batteryeighty:before{content:'\f0f9'}
-.icon-batteryempty:before{content:'\f0f5'}
-.icon-batteryforty:before{content:'\f0f7'}
-.icon-batteryfull:before{content:'\f0fa'}
-.icon-batterysixty:before{content:'\f0f8'}
-.icon-batterytwenty:before{content:'\f0f6'}
-.icon-bed:before{content:'\f2b9'}
-.icon-beer:before{content:'\f244'}
-.icon-bell:before{content:'\2407'}
-.icon-bigger:before{content:'\f30a'}
-.icon-bill:before{content:'\f278'}
-.icon-binary:before{content:'\f087'}
-.icon-binoculars-searchalt:before{content:'\f2a0'}
-.icon-birdhouse:before{content:'\f390'}
-.icon-birthday:before{content:'\f36b'}
-.icon-bishop:before{content:'\f2f9'}
-.icon-blackberry:before{content:'\f421'}
-.icon-blankstare:before{content:'\f13e'}
-.icon-blogger-blog:before{content:'\f167'}
-.icon-bluetooth:before{content:'\f12b'}
-.icon-bluetoothconnected:before{content:'\f386'}
-.icon-boardgame:before{content:'\f2d9'}
-.icon-boat:before{content:'\f21a'}
-.icon-bold:before{content:'\f1f4'}
-.icon-bomb:before{content:'\f2dc'}
-.icon-bone:before{content:'\f35f'}
-.icon-book:before{content:'\f1ba'}
-.icon-bookmark:before{content:'\f143'}
-.icon-boombox:before{content:'\f195'}
-.icon-bottle:before{content:'\f361'}
-.icon-bow:before{content:'\f2ee'}
-.icon-bowling:before{content:'\f2f3'}
-.icon-bowlingpins:before{content:'\f3d2'}
-.icon-bowtie:before{content:'\f37f'}
-.icon-boxtrapper-mousetrap:before{content:'\f046'}
-.icon-braces:before{content:'\f0b4'}
-.icon-braille0:before{content:'\f44b'}
-.icon-braille1:before{content:'\f44c'}
-.icon-braille2:before{content:'\f44d'}
-.icon-braille3:before{content:'\f44e'}
-.icon-braille4:before{content:'\f44f'}
-.icon-braille5:before{content:'\f450'}
-.icon-braille6:before{content:'\f451'}
-.icon-braille7:before{content:'\f452'}
-.icon-braille8:before{content:'\f453'}
-.icon-braille9:before{content:'\f454'}
-.icon-braillea:before{content:'\f431'}
-.icon-brailleb:before{content:'\f432'}
-.icon-braillec:before{content:'\f433'}
-.icon-brailled:before{content:'\f434'}
-.icon-braillee:before{content:'\f435'}
-.icon-braillef:before{content:'\f436'}
-.icon-brailleg:before{content:'\f437'}
-.icon-brailleh:before{content:'\f438'}
-.icon-braillei:before{content:'\f439'}
-.icon-braillej:before{content:'\f43a'}
-.icon-braillek:before{content:'\f43b'}
-.icon-braillel:before{content:'\f43c'}
-.icon-braillem:before{content:'\f43d'}
-.icon-braillen:before{content:'\f43e'}
-.icon-brailleo:before{content:'\f43f'}
-.icon-braillep:before{content:'\f440'}
-.icon-brailleq:before{content:'\f441'}
-.icon-brailler:before{content:'\f442'}
-.icon-brailles:before{content:'\f443'}
-.icon-braillespace:before{content:'\f455'}
-.icon-braillet:before{content:'\f444'}
-.icon-brailleu:before{content:'\f445'}
-.icon-braillev:before{content:'\f446'}
-.icon-braillew:before{content:'\f447'}
-.icon-braillex:before{content:'\f448'}
-.icon-brailley:before{content:'\f449'}
-.icon-braillez:before{content:'\f44a'}
-.icon-brain:before{content:'\f3e3'}
-.icon-bread:before{content:'\f42f'}
-.icon-breakable:before{content:'\f41c'}
-.icon-briefcase:before{content:'\f25e'}
-.icon-briefcasethree:before{content:'\f25f'}
-.icon-briefcasetwo:before{content:'\f0a2'}
-.icon-brightness:before{content:'\f10a'}
-.icon-brightnessfull:before{content:'\f10b'}
-.icon-brightnesshalf:before{content:'\f10c'}
-.icon-broom:before{content:'\f40a'}
-.icon-browser:before{content:'\f159'}
-.icon-brush:before{content:'\f1b8'}
-.icon-bucket:before{content:'\f1b5'}
-.icon-bug:before{content:'\f0a7'}
-.icon-bullhorn:before{content:'\f287'}
-.icon-bus:before{content:'\f241'}
-.icon-businesscardalt:before{content:'\f137'}
-.icon-buttona:before{content:'\f2bf'}
-.icon-buttonb:before{content:'\f2c0'}
-.icon-buttonx:before{content:'\f2c1'}
-.icon-buttony:before{content:'\f2c2'}
-.icon-cactus-desert:before{content:'\f22c'}
-.icon-calculator:before{content:'\f258'}
-.icon-calculatoralt:before{content:'\f265'}
-.icon-calendar:before{content:'\f20f'}
-.icon-calendaralt-cronjobs:before{content:'\f0a1'}
-.icon-camera:before{content:'\f19b'}
-.icon-candle:before{content:'\f29a'}
-.icon-candy:before{content:'\f42d'}
-.icon-candycane:before{content:'\f37d'}
-.icon-cannon:before{content:'\f401'}
-.icon-canvas:before{content:'\f1c8'}
-.icon-canvasrulers:before{content:'\f205'}
-.icon-capacitator:before{content:'\f3e8'}
-.icon-capslock:before{content:'\21ea'}
-.icon-captainamerica:before{content:'\f341'}
-.icon-carrot:before{content:'\f3f2'}
-.icon-cashregister:before{content:'\f26e'}
-.icon-cassette:before{content:'\f377'}
-.icon-cd-dvd:before{content:'\f0cd'}
-.icon-certificate:before{content:'\f277'}
-.icon-certificatealt:before{content:'\f058'}
-.icon-certificatethree:before{content:'\f059'}
-.icon-cgi:before{content:'\f086'}
-.icon-cgicenter:before{content:'\f079'}
-.icon-chair:before{content:'\2441'}
-.icon-chat:before{content:'\f162'}
-.icon-check:before{content:'\f310'}
-.icon-checkboxalt:before{content:'\f311'}
-.icon-checkin:before{content:'\f223'}
-.icon-checkinalt:before{content:'\f227'}
-.icon-chef:before{content:'\f3ce'}
-.icon-cherry:before{content:'\f35d'}
-.icon-chevron-down:before{content:'\f48b'}
-.icon-chevron-left:before{content:'\f489'}
-.icon-chevron-right:before{content:'\f488'}
-.icon-chevron-up:before{content:'\f48a'}
-.icon-chevrons:before{content:'\f0b5'}
-.icon-chicken:before{content:'\f359'}
-.icon-chocolate:before{content:'\f367'}
-.icon-christiancross:before{content:'\f40f'}
-.icon-christmastree:before{content:'\f37b'}
-.icon-chrome:before{content:'\f14e'}
-.icon-cigarette:before{content:'\f229'}
-.icon-circle-arrow-down:before{content:'\f475'}
-.icon-circle-arrow-left:before{content:'\f472'}
-.icon-circle-arrow-right:before{content:'\f473'}
-.icon-circle-arrow-up:before{content:'\f474'}
-.icon-circleadd:before{content:'\f0d1'}
-.icon-circledelete:before{content:'\f0d2'}
-.icon-circledown:before{content:'\f3c7'}
-.icon-circleleft:before{content:'\f3c6'}
-.icon-circleright:before{content:'\f3c9'}
-.icon-circleselect:before{content:'\f0d3'}
-.icon-circleselection:before{content:'\f1b1'}
-.icon-circleup:before{content:'\f3c8'}
-.icon-clearformatting:before{content:'\f1e7'}
-.icon-clipboard-paste:before{content:'\f0cb'}
-.icon-clockalt-timealt:before{content:'\f22b'}
-.icon-closetab:before{content:'\f170'}
-.icon-closewindow:before{content:'\f16e'}
-.icon-cloud:before{content:'\f0b9'}
-.icon-clouddownload:before{content:'\f0bb'}
-.icon-cloudhosting:before{content:'\f007'}
-.icon-cloudsync:before{content:'\f0bc'}
-.icon-cloudupload:before{content:'\f0ba'}
-.icon-clubs:before{content:'\f2f6'}
-.icon-cmd:before{content:'\f33a'}
-.icon-cms:before{content:'\f036'}
-.icon-cmsmadesimple:before{content:'\f0b0'}
-.icon-codeigniter:before{content:'\f077'}
-.icon-coffee:before{content:'\f235'}
-.icon-coffeebean:before{content:'\f366'}
-.icon-cog:before{content:'\f00f'}
-.icon-colocation:before{content:'\f024'}
-.icon-colocationalt:before{content:'\f023'}
-.icon-colors:before{content:'\f1e6'}
-.icon-comment:before{content:'\f12c'}
-.icon-commentout:before{content:'\f080'}
-.icon-commentround:before{content:'\f155'}
-.icon-commentroundempty:before{content:'\f156'}
-.icon-commentroundtyping:before{content:'\f157'}
-.icon-commentroundtypingempty:before{content:'\f158'}
-.icon-commenttyping:before{content:'\f12d'}
-.icon-compass:before{content:'\263c'}
-.icon-concretefive:before{content:'\f0af'}
-.icon-contact-businesscard:before{content:'\f040'}
-.icon-controllernes:before{content:'\f2d2'}
-.icon-controllerps:before{content:'\f2d1'}
-.icon-controllersnes:before{content:'\f2d3'}
-.icon-controlpanel:before{content:'\f008'}
-.icon-controlpanelalt:before{content:'\f009'}
-.icon-cooling:before{content:'\f00a'}
-.icon-coppermine:before{content:'\f0a4'}
-.icon-copy:before{content:'\f0c9'}
-.icon-copyright:before{content:'\00a9'}
-.icon-coupon:before{content:'\f254'}
-.icon-cpanel:before{content:'\f072'}
-.icon-cplusplus:before{content:'\f0b1'}
-.icon-cpu-processor:before{content:'\f002'}
-.icon-cpualt-processoralt:before{content:'\f003'}
-.icon-crayon:before{content:'\f383'}
-.icon-createfile:before{content:'\f0c6'}
-.icon-createfolder:before{content:'\f0da'}
-.icon-creativecommons:before{content:'\f1fc'}
-.icon-creditcard:before{content:'\f279'}
-.icon-cricket:before{content:'\f418'}
-.icon-croisant:before{content:'\f29f'}
-.icon-crop:before{content:'\f1af'}
-.icon-crown:before{content:'\f28f'}
-.icon-csharp:before{content:'\f0b2'}
-.icon-cssthree:before{content:'\f06a'}
-.icon-cup-coffeealt:before{content:'\f24b'}
-.icon-cupcake:before{content:'\f35b'}
-.icon-curling:before{content:'\f3d7'}
-.icon-cursor:before{content:'\f0dc'}
-.icon-cut-scissors:before{content:'\f0ca'}
-.icon-dagger:before{content:'\2020'}
-.icon-danger:before{content:'\f415'}
-.icon-dart:before{content:'\f3d4'}
-.icon-darthvader:before{content:'\f34a'}
-.icon-database:before{content:'\f00b'}
-.icon-databaseadd:before{content:'\f00c'}
-.icon-databasedelete:before{content:'\f00d'}
-.icon-davidstar:before{content:'\f40e'}
-.icon-dcsource:before{content:'\f3e9'}
-.icon-dedicatedserver:before{content:'\f00e'}
-.icon-deletefile:before{content:'\f0c7'}
-.icon-deletefolder:before{content:'\f0db'}
-.icon-delicious:before{content:'\f152'}
-.icon-designcontest:before{content:'\f351'}
-.icon-desklamp:before{content:'\f412'}
-.icon-dialpad:before{content:'\f399'}
-.icon-diamond:before{content:'\2666'}
-.icon-diamonds:before{content:'\f2f7'}
-.icon-die-dice:before{content:'\f2d8'}
-.icon-diefive:before{content:'\f3fb'}
-.icon-diefour:before{content:'\f3fa'}
-.icon-dieone:before{content:'\f3f7'}
-.icon-diesix:before{content:'\f3fc'}
-.icon-diethree:before{content:'\f3f9'}
-.icon-dietwo:before{content:'\f3f8'}
-.icon-diode:before{content:'\f3e7'}
-.icon-director:before{content:'\f2ae'}
-.icon-diskspace:before{content:'\f096'}
-.icon-distributehorizontalcenters:before{content:'\f1dc'}
-.icon-distributeverticalcenters:before{content:'\f1db'}
-.icon-divide:before{content:'\00f7'}
-.icon-dna:before{content:'\f409'}
-.icon-dnszone:before{content:'\f07f'}
-.icon-document:before{content:'\f0c2'}
-.icon-doghouse:before{content:'\f38f'}
-.icon-dollar:before{content:'\24'}
-.icon-dollaralt:before{content:'\f259'}
-.icon-dolphinsoftware:before{content:'\f064'}
-.icon-domain:before{content:'\f01d'}
-.icon-domainaddon:before{content:'\f053'}
-.icon-domino:before{content:'\f3d5'}
-.icon-donut:before{content:'\f3ca'}
-.icon-downleft:before{content:'\f2ff'}
-.icon-download:before{content:'\f47b'}
-.icon-download-alt:before{content:'\f11a'}
-.icon-downright:before{content:'\f300'}
-.icon-draft:before{content:'\f172'}
-.icon-dreamweaver:before{content:'\f1d0'}
-.icon-dribbble:before{content:'\f14c'}
-.icon-dropmenu:before{content:'\f0a5'}
-.icon-drupal:before{content:'\f075'}
-.icon-drwho:before{content:'\f3c0'}
-.icon-edit:before{content:'\f47c'}
-.icon-editalt:before{content:'\f0f2'}
-.icon-egg:before{content:'\f407'}
-.icon-eightball:before{content:'\f36e'}
-.icon-eject:before{content:'\f199'}
-.icon-elipse:before{content:'\f1bc'}
-.icon-emailalt:before{content:'\f136'}
-.icon-emailexport:before{content:'\f176'}
-.icon-emailforward:before{content:'\f175'}
-.icon-emailforwarders:before{content:'\f049'}
-.icon-emailimport:before{content:'\f177'}
-.icon-emailrefresh:before{content:'\f174'}
-.icon-emailtrace:before{content:'\f091'}
-.icon-emergency:before{content:'\f246'}
-.icon-emptycart:before{content:'\f395'}
-.icon-enter:before{content:'\f323'}
-.icon-envelope:before{content:'\f028'}
-.icon-equalizer:before{content:'\f18e'}
-.icon-equalizeralt:before{content:'\f18f'}
-.icon-equals:before{content:'\f30c'}
-.icon-eraser:before{content:'\f1f1'}
-.icon-erroralt:before{content:'\f05a'}
-.icon-euro:before{content:'\20ac'}
-.icon-euroalt:before{content:'\f25a'}
-.icon-evernote:before{content:'\f17c'}
-.icon-exchange-currency:before{content:'\f26b'}
-.icon-exclamation-sign:before{content:'\f04a'}
-.icon-excludeshape:before{content:'\f200'}
-.icon-exit:before{content:'\f324'}
-.icon-explorerwindow:before{content:'\f0d9'}
-.icon-exportfile:before{content:'\f32f'}
-.icon-exposure:before{content:'\f1de'}
-.icon-extinguisher:before{content:'\f2b7'}
-.icon-eye-close:before{content:'\f481'}
-.icon-eye-open:before{content:'\f2b5'}
-.icon-eye-view:before{content:'\f280'}
-.icon-eyedropper:before{content:'\f1ad'}
-.icon-facebook:before{content:'\f140'}
-.icon-facebookalt:before{content:'\f14b'}
-.icon-facetime-video:before{content:'\f19c'}
-.icon-factory:before{content:'\f27a'}
-.icon-fantastico:before{content:'\f0ae'}
-.icon-faq:before{content:'\f099'}
-.icon-fast-backward:before{content:'\f47e'}
-.icon-fast-forward:before{content:'\f47f'}
-.icon-fastdown:before{content:'\f31d'}
-.icon-fastleft:before{content:'\f31a'}
-.icon-fastright:before{content:'\f31b'}
-.icon-fastup:before{content:'\f31c'}
-.icon-favoritefile:before{content:'\f381'}
-.icon-favoritefolder:before{content:'\f382'}
-.icon-featheralt-write:before{content:'\f1c5'}
-.icon-fedora:before{content:'\f3f1'}
-.icon-fence:before{content:'\f2af'}
-.icon-file:before{content:'\f0d6'}
-.icon-film:before{content:'\f19d'}
-.icon-filmstrip:before{content:'\f3ed'}
-.icon-filter:before{content:'\f05c'}
-.icon-finder:before{content:'\f398'}
-.icon-fire:before{content:'\f27f'}
-.icon-firefox:before{content:'\f420'}
-.icon-firewall:before{content:'\f021'}
-.icon-firewire:before{content:'\f0fc'}
-.icon-firstaid:before{content:'\f2ba'}
-.icon-fish:before{content:'\f35a'}
-.icon-fishbone:before{content:'\f42b'}
-.icon-flag:before{content:'\f487'}
-.icon-flagalt:before{content:'\f232'}
-.icon-flagtriangle:before{content:'\f20b'}
-.icon-flash:before{content:'\f1cf'}
-.icon-flashlight:before{content:'\f299'}
-.icon-flashplayer:before{content:'\f070'}
-.icon-flaskfull:before{content:'\f27e'}
-.icon-flickr:before{content:'\f146'}
-.icon-flower:before{content:'\f2a5'}
-.icon-flowernew:before{content:'\f3a8'}
-.icon-folder-close:before{content:'\f094'}
-.icon-folder-open:before{content:'\f483'}
-.icon-foldertree:before{content:'\f0f0'}
-.icon-font:before{content:'\f1ae'}
-.icon-foodtray:before{content:'\f3d0'}
-.icon-football-soccer:before{content:'\f2eb'}
-.icon-forbiddenalt:before{content:'\f314'}
-.icon-forest-tree:before{content:'\f217'}
-.icon-forestalt-treealt:before{content:'\f21c'}
-.icon-fork:before{content:'\22d4'}
-.icon-forklift:before{content:'\f29b'}
-.icon-form:before{content:'\f08c'}
-.icon-forrst:before{content:'\f14d'}
-.icon-fort:before{content:'\f400'}
-.icon-forward:before{content:'\f182'}
-.icon-fourohfour:before{content:'\f09d'}
-.icon-foursquare:before{content:'\f42a'}
-.icon-freeway:before{content:'\f24a'}
-.icon-fridge:before{content:'\f40d'}
-.icon-fries:before{content:'\f36a'}
-.icon-ftp:before{content:'\f029'}
-.icon-ftpaccounts:before{content:'\f07b'}
-.icon-ftpsession:before{content:'\f07c'}
-.icon-fullscreen:before{content:'\f485'}
-.icon-gameboy:before{content:'\f403'}
-.icon-gamecursor:before{content:'\f2d0'}
-.icon-gasstation:before{content:'\f216'}
-.icon-gearfour:before{content:'\f3a7'}
-.icon-ghost:before{content:'\f2da'}
-.icon-gift:before{content:'\f260'}
-.icon-github:before{content:'\f081'}
-.icon-glass:before{content:'\f236'}
-.icon-glasses:before{content:'\f295'}
-.icon-glassesalt:before{content:'\f39d'}
-.icon-globe:before{content:'\f01b'}
-.icon-globealt:before{content:'\f36c'}
-.icon-glue:before{content:'\f36d'}
-.icon-gmail:before{content:'\f150'}
-.icon-golf:before{content:'\f2f1'}
-.icon-googledrive:before{content:'\f163'}
-.icon-googleplus:before{content:'\f165'}
-.icon-googlewallet:before{content:'\f270'}
-.icon-gpsoff-gps:before{content:'\f21e'}
-.icon-gpson:before{content:'\f21f'}
-.icon-gpu-graphicscard:before{content:'\f108'}
-.icon-gradient:before{content:'\2207'}
-.icon-grails:before{content:'\f085'}
-.icon-greenlantern:before{content:'\f340'}
-.icon-greenlightbulb:before{content:'\f406'}
-.icon-grooveshark:before{content:'\f3a2'}
-.icon-groups-friends:before{content:'\f134'}
-.icon-guitar:before{content:'\f19a'}
-.icon-halflife:before{content:'\f3ba'}
-.icon-halo:before{content:'\f3bb'}
-.icon-hamburger:before{content:'\f2b3'}
-.icon-hammer:before{content:'\f291'}
-.icon-hand-down:before{content:'\f387'}
-.icon-hand-left:before{content:'\f389'}
-.icon-hand-right:before{content:'\f388'}
-.icon-hand-up:before{content:'\f0dd'}
-.icon-handcuffs:before{content:'\f393'}
-.icon-handdrag:before{content:'\f0de'}
-.icon-handtwofingers:before{content:'\f0df'}
-.icon-hanger:before{content:'\f2ab'}
-.icon-happy:before{content:'\f13c'}
-.icon-harrypotter:before{content:'\f38b'}
-.icon-hdd:before{content:'\f02a'}
-.icon-hdtv:before{content:'\f1a0'}
-.icon-headphones:before{content:'\f180'}
-.icon-headphonesalt:before{content:'\f1a3'}
-.icon-heart:before{content:'\f131'}
-.icon-heartempty-love:before{content:'\f132'}
-.icon-hearts:before{content:'\f2f4'}
-.icon-helicopter:before{content:'\f3e4'}
-.icon-hexagon-polygon:before{content:'\f1be'}
-.icon-hockey:before{content:'\f3d9'}
-.icon-home:before{content:'\21b8'}
-.icon-homealt:before{content:'\f02b'}
-.icon-hospital:before{content:'\f247'}
-.icon-hotdog:before{content:'\f3cc'}
-.icon-hotlinkprotection:before{content:'\f050'}
-.icon-hourglassalt:before{content:'\f122'}
-.icon-html:before{content:'\f068'}
-.icon-htmlfive:before{content:'\f069'}
-.icon-hydrant:before{content:'\f3ff'}
-.icon-icecream:before{content:'\f2a4'}
-.icon-icecreamalt:before{content:'\f289'}
-.icon-illustrator:before{content:'\f1ce'}
-.icon-imac:before{content:'\f0fb'}
-.icon-images-gallery:before{content:'\f09f'}
-.icon-importcontacts:before{content:'\f092'}
-.icon-importfile:before{content:'\f32e'}
-.icon-inbox:before{content:'\f17a'}
-.icon-inboxalt:before{content:'\f178'}
-.icon-incomingcall:before{content:'\f15d'}
-.icon-indent-left:before{content:'\f1f2'}
-.icon-indent-right:before{content:'\f1f3'}
-.icon-indexmanager:before{content:'\f09e'}
-.icon-infinity:before{content:'\221e'}
-.icon-info-sign:before{content:'\f315'}
-.icon-infographic:before{content:'\f336'}
-.icon-ink:before{content:'\f3f6'}
-.icon-inkpen:before{content:'\f1ac'}
-.icon-insertbarchart:before{content:'\f1e5'}
-.icon-insertpicture:before{content:'\f1e0'}
-.icon-insertpicturecenter:before{content:'\f1e3'}
-.icon-insertpictureleft:before{content:'\f1e1'}
-.icon-insertpictureright:before{content:'\f1e2'}
-.icon-insertpiechart:before{content:'\f1e4'}
-.icon-instagram:before{content:'\f14a'}
-.icon-install:before{content:'\f128'}
-.icon-intel:before{content:'\f01f'}
-.icon-intersection:before{content:'\2229'}
-.icon-intersectshape:before{content:'\f1ff'}
-.icon-invert:before{content:'\f1df'}
-.icon-invoice:before{content:'\f3e5'}
-.icon-ipcontrol:before{content:'\f08b'}
-.icon-iphone:before{content:'\f0e6'}
-.icon-ipod:before{content:'\f190'}
-.icon-ironman:before{content:'\f349'}
-.icon-islam:before{content:'\f410'}
-.icon-island:before{content:'\f392'}
-.icon-italic:before{content:'\f1f5'}
-.icon-jar:before{content:'\f2b6'}
-.icon-jason:before{content:'\f38c'}
-.icon-java:before{content:'\f083'}
-.icon-joomla:before{content:'\f073'}
-.icon-joystickarcade:before{content:'\f2d4'}
-.icon-joystickatari:before{content:'\f2d5'}
-.icon-jquery:before{content:'\f06b'}
-.icon-jqueryui:before{content:'\f06c'}
-.icon-kerning:before{content:'\f1e9'}
-.icon-key:before{content:'\f093'}
-.icon-keyboard:before{content:'\f119'}
-.icon-keyboardalt:before{content:'\f105'}
-.icon-keyboarddelete:before{content:'\f3a6'}
-.icon-kidney:before{content:'\f3e0'}
-.icon-king:before{content:'\f2fc'}
-.icon-knife:before{content:'\f214'}
-.icon-knight:before{content:'\f2fb'}
-.icon-knob:before{content:'\f376'}
-.icon-lab-flask:before{content:'\f27d'}
-.icon-lamp:before{content:'\f2b1'}
-.icon-lan:before{content:'\f0ee'}
-.icon-language:before{content:'\f042'}
-.icon-laptop:before{content:'\f0d8'}
-.icon-lasso:before{content:'\f396'}
-.icon-lastfm:before{content:'\f3a3'}
-.icon-laugh:before{content:'\f13f'}
-.icon-law:before{content:'\f263'}
-.icon-layers:before{content:'\f1ca'}
-.icon-layersalt:before{content:'\f1cb'}
-.icon-leaf:before{content:'\f039'}
-.icon-leechprotect:before{content:'\f07e'}
-.icon-legacyfilemanager:before{content:'\f095'}
-.icon-lego:before{content:'\f370'}
-.icon-lifeempty:before{content:'\f2e1'}
-.icon-lifefull:before{content:'\f2e3'}
-.icon-lifehacker:before{content:'\f380'}
-.icon-lifehalf:before{content:'\f2e2'}
-.icon-lifepreserver:before{content:'\f015'}
-.icon-lightbulb-idea:before{content:'\f338'}
-.icon-lighthouse:before{content:'\f3e6'}
-.icon-lightning:before{content:'\f231'}
-.icon-lightningalt:before{content:'\f2a8'}
-.icon-line:before{content:'\f1bf'}
-.icon-lineheight:before{content:'\f1c0'}
-.icon-link:before{content:'\f022'}
-.icon-linkalt:before{content:'\f333'}
-.icon-linkedin:before{content:'\f166'}
-.icon-linux:before{content:'\f01a'}
-.icon-list:before{content:'\f111'}
-.icon-list-alt:before{content:'\f480'}
-.icon-liver:before{content:'\f3e2'}
-.icon-loading-hourglass:before{content:'\f123'}
-.icon-loadingalt:before{content:'\f339'}
-.icon-lock:before{content:'\f0be'}
-.icon-lockalt-keyhole:before{content:'\f0eb'}
-.icon-lollypop:before{content:'\f3ee'}
-.icon-lungs:before{content:'\f3df'}
-.icon-macpro:before{content:'\f3a5'}
-.icon-macro-plant:before{content:'\f1c6'}
-.icon-magazine:before{content:'\f1ec'}
-.icon-magento:before{content:'\f06e'}
-.icon-magnet:before{content:'\f281'}
-.icon-mailbox:before{content:'\f044'}
-.icon-mailinglists:before{content:'\f090'}
-.icon-man-male:before{content:'\f2a1'}
-.icon-managedhosting:before{content:'\f038'}
-.icon-map:before{content:'\f209'}
-.icon-map-marker:before{content:'\f220'}
-.icon-marker:before{content:'\f204'}
-.icon-marvin:before{content:'\f3dd'}
-.icon-mastercard:before{content:'\f266'}
-.icon-maximize:before{content:'\f30f'}
-.icon-medal:before{content:'\f2e5'}
-.icon-medalbronze:before{content:'\f2e8'}
-.icon-medalgold:before{content:'\f2e6'}
-.icon-medalsilver:before{content:'\f2e7'}
-.icon-mediarepeat:before{content:'\f187'}
-.icon-men:before{content:'\f24c'}
-.icon-menu:before{content:'\f127'}
-.icon-merge:before{content:'\f334'}
-.icon-mergecells:before{content:'\f327'}
-.icon-mergeshapes:before{content:'\f201'}
-.icon-metro-subway:before{content:'\f24f'}
-.icon-metronome:before{content:'\f374'}
-.icon-mickeymouse:before{content:'\f37a'}
-.icon-microphone:before{content:'\f191'}
-.icon-microscope:before{content:'\f283'}
-.icon-microsd:before{content:'\f107'}
-.icon-microwave:before{content:'\f42e'}
-.icon-mimetype:before{content:'\f057'}
-.icon-minimize:before{content:'\f30e'}
-.icon-minus:before{content:'\2212'}
-.icon-minus-sign:before{content:'\f477'}
-.icon-missedcall:before{content:'\f15c'}
-.icon-mobile:before{content:'\f0e8'}
-.icon-moleskine:before{content:'\f1f0'}
-.icon-money-cash:before{content:'\f27b'}
-.icon-moneybag:before{content:'\f271'}
-.icon-monitor:before{content:'\f0d5'}
-.icon-monstersinc:before{content:'\f3bd'}
-.icon-moon-night:before{content:'\f207'}
-.icon-mouse:before{content:'\f0d4'}
-.icon-mousealt:before{content:'\f126'}
-.icon-move:before{content:'\f322'}
-.icon-movieclapper:before{content:'\f193'}
-.icon-moviereel:before{content:'\f17f'}
-.icon-muffin:before{content:'\f363'}
-.icon-mug:before{content:'\f24e'}
-.icon-mushroom:before{content:'\f35e'}
-.icon-music:before{content:'\f181'}
-.icon-musicalt:before{content:'\f18d'}
-.icon-mutealt:before{content:'\f0e5'}
-.icon-mxentry:before{content:'\f07a'}
-.icon-mybb:before{content:'\f065'}
-.icon-myspace:before{content:'\f153'}
-.icon-mysql-dolphin:before{content:'\f076'}
-.icon-nail:before{content:'\f428'}
-.icon-navigation:before{content:'\f23a'}
-.icon-network:before{content:'\f0a6'}
-.icon-networksignal:before{content:'\f3a9'}
-.icon-news:before{content:'\f256'}
-.icon-newtab:before{content:'\f16f'}
-.icon-newwindow:before{content:'\f16d'}
-.icon-next:before{content:'\f18a'}
-.icon-nexus:before{content:'\f0e7'}
-.icon-nintendods:before{content:'\f404'}
-.icon-nodejs:before{content:'\f084'}
-.icon-notes:before{content:'\f0d7'}
-.icon-notificationbottom:before{content:'\f144'}
-.icon-notificationtop:before{content:'\f145'}
-.icon-nut:before{content:'\f427'}
-.icon-off:before{content:'\f11d'}
-.icon-office-building:before{content:'\f245'}
-.icon-officechair:before{content:'\f26d'}
-.icon-ok:before{content:'\2713'}
-.icon-ok-circle:before{content:'\f471'}
-.icon-ok-sign:before{content:'\f479'}
-.icon-oneup:before{content:'\f3b7'}
-.icon-oneupalt:before{content:'\f3b6'}
-.icon-opencart:before{content:'\f060'}
-.icon-opennewwindow:before{content:'\f332'}
-.icon-orange:before{content:'\f29e'}
-.icon-outbox:before{content:'\f179'}
-.icon-outgoingcall:before{content:'\f15e'}
-.icon-oxwall:before{content:'\f06d'}
-.icon-pacman:before{content:'\f2db'}
-.icon-pageback:before{content:'\f31e'}
-.icon-pagebreak:before{content:'\f1cc'}
-.icon-pageforward:before{content:'\f31f'}
-.icon-pagesetup:before{content:'\f331'}
-.icon-paintbrush:before{content:'\f1e8'}
-.icon-paintroll:before{content:'\f1fa'}
-.icon-palette-painting:before{content:'\f1b9'}
-.icon-paperclip:before{content:'\f284'}
-.icon-paperclipalt:before{content:'\f285'}
-.icon-paperclipvertical:before{content:'\f286'}
-.icon-paperplane:before{content:'\f296'}
-.icon-parentheses:before{content:'\f3c4'}
-.icon-parkeddomain:before{content:'\f055'}
-.icon-password:before{content:'\f03e'}
-.icon-passwordalt:before{content:'\f03f'}
-.icon-pasta:before{content:'\f408'}
-.icon-patch:before{content:'\f2a3'}
-.icon-path:before{content:'\f169'}
-.icon-pause:before{content:'\f186'}
-.icon-paw-pet:before{content:'\f29d'}
-.icon-pawn:before{content:'\f2f8'}
-.icon-paypal:before{content:'\f267'}
-.icon-peace:before{content:'\f2a7'}
-.icon-pen:before{content:'\f1ee'}
-.icon-pencil:before{content:'\f1b7'}
-.icon-pepperoni:before{content:'\f364'}
-.icon-percent:before{content:'\25'}
-.icon-perl-camel:before{content:'\f0b6'}
-.icon-perlalt:before{content:'\f0b7'}
-.icon-phone-call:before{content:'\f14f'}
-.icon-phonealt:before{content:'\f15b'}
-.icon-phonebook:before{content:'\f149'}
-.icon-phonebookalt:before{content:'\f135'}
-.icon-phonemic:before{content:'\f391'}
-.icon-phoneold:before{content:'\f148'}
-.icon-photoshop:before{content:'\f1cd'}
-.icon-php:before{content:'\f09c'}
-.icon-phpbb:before{content:'\f063'}
-.icon-phppear:before{content:'\f09b'}
-.icon-piano:before{content:'\f19e'}
-.icon-picture:before{content:'\22b7'}
-.icon-pictureframe:before{content:'\f41e'}
-.icon-piggybank:before{content:'\f257'}
-.icon-pigpena:before{content:'\f456'}
-.icon-pigpenb:before{content:'\f457'}
-.icon-pigpenc:before{content:'\f458'}
-.icon-pigpend:before{content:'\f459'}
-.icon-pigpene:before{content:'\f45a'}
-.icon-pigpenf:before{content:'\f45b'}
-.icon-pigpeng:before{content:'\f45c'}
-.icon-pigpenh:before{content:'\f45d'}
-.icon-pigpeni:before{content:'\f45e'}
-.icon-pigpenj:before{content:'\f45f'}
-.icon-pigpenk:before{content:'\f460'}
-.icon-pigpenl:before{content:'\f461'}
-.icon-pigpenm:before{content:'\f462'}
-.icon-pigpenn:before{content:'\f463'}
-.icon-pigpeno:before{content:'\f464'}
-.icon-pigpenp:before{content:'\f465'}
-.icon-pigpenq:before{content:'\f466'}
-.icon-pigpenr:before{content:'\f467'}
-.icon-pigpens:before{content:'\f468'}
-.icon-pigpent:before{content:'\f469'}
-.icon-pigpenu:before{content:'\f46a'}
-.icon-pigpenv:before{content:'\f46b'}
-.icon-pigpenw:before{content:'\f46c'}
-.icon-pigpenx:before{content:'\f46d'}
-.icon-pigpeny:before{content:'\f46e'}
-.icon-pigpenz:before{content:'\f46f'}
-.icon-pilcrow:before{content:'\00b6'}
-.icon-pill-antivirusalt:before{content:'\f0aa'}
-.icon-pin:before{content:'\f20a'}
-.icon-pipe:before{content:'\01c0'}
-.icon-piwigo:before{content:'\f0ad'}
-.icon-pizza:before{content:'\f35c'}
-.icon-placeadd:before{content:'\f221'}
-.icon-placealt:before{content:'\f224'}
-.icon-placealtadd:before{content:'\f225'}
-.icon-placealtdelete:before{content:'\f226'}
-.icon-placedelete:before{content:'\f222'}
-.icon-placeios:before{content:'\f20c'}
-.icon-plane:before{content:'\f23e'}
-.icon-plaque:before{content:'\f2b8'}
-.icon-play:before{content:'\f184'}
-.icon-play-circle:before{content:'\f17e'}
-.icon-playstore:before{content:'\f255'}
-.icon-playvideo:before{content:'\f03d'}
-.icon-plug:before{content:'\f0ea'}
-.icon-pluginalt:before{content:'\f098'}
-.icon-plus:before{content:'\002b'}
-.icon-plus-sign:before{content:'\f476'}
-.icon-pocket:before{content:'\f16b'}
-.icon-podcast:before{content:'\f1a2'}
-.icon-podium-winner:before{content:'\f2d6'}
-.icon-pokemon:before{content:'\f354'}
-.icon-police:before{content:'\f2aa'}
-.icon-polygonlasso:before{content:'\f397'}
-.icon-post:before{content:'\f12e'}
-.icon-postalt:before{content:'\f130'}
-.icon-pound:before{content:'\f25b'}
-.icon-poundalt:before{content:'\f25c'}
-.icon-powerjack:before{content:'\f0fd'}
-.icon-powerplug:before{content:'\f0ed'}
-.icon-powerplugeu:before{content:'\f28b'}
-.icon-powerplugus:before{content:'\f28c'}
-.icon-presentation:before{content:'\f0c4'}
-.icon-prestashop:before{content:'\f061'}
-.icon-pretzel:before{content:'\f3cf'}
-.icon-preview:before{content:'\f330'}
-.icon-previous:before{content:'\f18b'}
-.icon-print:before{content:'\f125'}
-.icon-protecteddirectory:before{content:'\f04d'}
-.icon-pscircle:before{content:'\f2bb'}
-.icon-pscursor:before{content:'\f2c3'}
-.icon-psdown:before{content:'\f2c6'}
-.icon-psleft:before{content:'\f2c7'}
-.icon-pslone:before{content:'\f2cc'}
-.icon-psltwo:before{content:'\f2cd'}
-.icon-psright:before{content:'\f2c5'}
-.icon-psrone:before{content:'\f2ce'}
-.icon-psrtwo:before{content:'\f2cf'}
-.icon-pssquare:before{content:'\f2bc'}
-.icon-pstriangle:before{content:'\f2bd'}
-.icon-psup:before{content:'\f2c4'}
-.icon-psx:before{content:'\f2be'}
-.icon-pull:before{content:'\f089'}
-.icon-punisher:before{content:'\f343'}
-.icon-push:before{content:'\f088'}
-.icon-puzzle-plugin:before{content:'\f0a0'}
-.icon-python:before{content:'\f071'}
-.icon-qrcode:before{content:'\f275'}
-.icon-quake:before{content:'\f355'}
-.icon-queen:before{content:'\f2fd'}
-.icon-query:before{content:'\f08a'}
-.icon-question-sign:before{content:'\f0a3'}
-.icon-quote:before{content:'\f12f'}
-.icon-quotedown:before{content:'\f329'}
-.icon-quoteup:before{content:'\f328'}
-.icon-raceflag:before{content:'\f38e'}
-.icon-racquet:before{content:'\f2f2'}
-.icon-radio:before{content:'\f1a1'}
-.icon-radioactive:before{content:'\f282'}
-.icon-radiobutton:before{content:'\f312'}
-.icon-railroad:before{content:'\f248'}
-.icon-rain:before{content:'\f22f'}
-.icon-ram:before{content:'\f02c'}
-.icon-random:before{content:'\f188'}
-.icon-rar:before{content:'\f117'}
-.icon-raspberry:before{content:'\f368'}
-.icon-raspberrypi:before{content:'\f369'}
-.icon-rawaccesslogs:before{content:'\f0c1'}
-.icon-razor:before{content:'\f416'}
-.icon-reademail:before{content:'\f173'}
-.icon-record:before{content:'\f189'}
-.icon-rectangle:before{content:'\25ad'}
-.icon-recycle:before{content:'\f297'}
-.icon-reddit:before{content:'\f154'}
-.icon-redirect:before{content:'\f054'}
-.icon-refresh:before{content:'\f078'}
-.icon-reliability:before{content:'\f016'}
-.icon-remote:before{content:'\f298'}
-.icon-remove:before{content:'\00d7'}
-.icon-remove-circle:before{content:'\f470'}
-.icon-remove-sign:before{content:'\f478'}
-.icon-removefriend:before{content:'\f3db'}
-.icon-repeat:before{content:'\f32b'}
-.icon-repeatone:before{content:'\f196'}
-.icon-resellerhosting:before{content:'\f03a'}
-.icon-residentevil:before{content:'\f350'}
-.icon-resistor:before{content:'\f3eb'}
-.icon-resize:before{content:'\f1ed'}
-.icon-resize-full:before{content:'\f325'}
-.icon-resize-horizontal:before{content:'\f318'}
-.icon-resize-small:before{content:'\f326'}
-.icon-resize-vertical:before{content:'\f319'}
-.icon-restart:before{content:'\f11f'}
-.icon-restaurantmenu:before{content:'\f362'}
-.icon-restore:before{content:'\f30d'}
-.icon-restricted:before{content:'\f0ab'}
-.icon-retweet:before{content:'\f486'}
-.icon-rim:before{content:'\f36f'}
-.icon-ring:before{content:'\02da'}
-.icon-road:before{content:'\f249'}
-.icon-roadsign-roadsignright:before{content:'\f21b'}
-.icon-roadsignleft:before{content:'\f240'}
-.icon-robocop:before{content:'\f357'}
-.icon-rocket-launch:before{content:'\f29c'}
-.icon-rook:before{content:'\f2fa'}
-.icon-root:before{content:'\f33c'}
-.icon-rorschach:before{content:'\f358'}
-.icon-rotateclockwise:before{content:'\f202'}
-.icon-rotatecounterclockwise:before{content:'\f203'}
-.icon-roundrectangle:before{content:'\f1bd'}
-.icon-route:before{content:'\f402'}
-.icon-router:before{content:'\f0e9'}
-.icon-rss:before{content:'\f17b'}
-.icon-rubberstamp:before{content:'\f274'}
-.icon-ruby:before{content:'\f067'}
-.icon-ruler:before{content:'\f1ef'}
-.icon-sad:before{content:'\f13d'}
-.icon-safetypin:before{content:'\f417'}
-.icon-satellite:before{content:'\f38a'}
-.icon-satellitedish-remotemysql:before{content:'\f0c0'}
-.icon-save-floppy:before{content:'\f0c8'}
-.icon-scales:before{content:'\f3fd'}
-.icon-science-atom:before{content:'\f2b0'}
-.icon-scope-scan:before{content:'\f212'}
-.icon-scopealt:before{content:'\f237'}
-.icon-screenshot:before{content:'\f109'}
-.icon-screw:before{content:'\f426'}
-.icon-screwdriver:before{content:'\f292'}
-.icon-screwdriveralt:before{content:'\f293'}
-.icon-script:before{content:'\f08d'}
-.icon-sd:before{content:'\f106'}
-.icon-search:before{content:'\f0c5'}
-.icon-searchdocument:before{content:'\f419'}
-.icon-searchfolder:before{content:'\f41a'}
-.icon-security-shield:before{content:'\f02d'}
-.icon-securityalt-shieldalt:before{content:'\f02e'}
-.icon-selection-rectangleselection:before{content:'\f1b0'}
-.icon-selectionadd:before{content:'\f1b2'}
-.icon-selectionintersect:before{content:'\f1b4'}
-.icon-selectionremove:before{content:'\f1b3'}
-.icon-seo:before{content:'\f030'}
-.icon-server:before{content:'\f026'}
-.icon-servers:before{content:'\f027'}
-.icon-settingsandroid:before{content:'\f309'}
-.icon-settingsfour-gearsalt:before{content:'\f306'}
-.icon-settingsthree-gears:before{content:'\f307'}
-.icon-settingstwo-gearalt:before{content:'\f308'}
-.icon-shades-sunglasses:before{content:'\f294'}
-.icon-shapes:before{content:'\f1dd'}
-.icon-share:before{content:'\f47d'}
-.icon-share-alt:before{content:'\f16c'}
-.icon-sharealt:before{content:'\f147'}
-.icon-sharedfile:before{content:'\f0ef'}
-.icon-sharedhosting:before{content:'\f037'}
-.icon-sharethree:before{content:'\f414'}
-.icon-sheriff:before{content:'\f2a9'}
-.icon-shipping:before{content:'\f23f'}
-.icon-shopping:before{content:'\f010'}
-.icon-shopping-cart:before{content:'\f035'}
-.icon-shoppingbag:before{content:'\f273'}
-.icon-shortcut:before{content:'\f043'}
-.icon-shovel:before{content:'\f290'}
-.icon-shredder:before{content:'\f27c'}
-.icon-shutdown:before{content:'\f11e'}
-.icon-sidebar:before{content:'\f124'}
-.icon-signal:before{content:'\f100'}
-.icon-sim:before{content:'\f0e1'}
-.icon-simalt:before{content:'\f121'}
-.icon-skrill:before{content:'\f268'}
-.icon-skull:before{content:'\f38d'}
-.icon-skype:before{content:'\f141'}
-.icon-skypeaway:before{content:'\f39f'}
-.icon-skypebusy:before{content:'\f3a0'}
-.icon-skypeoffline:before{content:'\f3a1'}
-.icon-skypeonline:before{content:'\f39e'}
-.icon-smaller:before{content:'\f30b'}
-.icon-smf:before{content:'\f062'}
-.icon-smile:before{content:'\263a'}
-.icon-snow:before{content:'\f22e'}
-.icon-snowman:before{content:'\f37c'}
-.icon-socialnetwork:before{content:'\f03b'}
-.icon-software:before{content:'\f09a'}
-.icon-sortbynameascending-atoz:before{content:'\f1c2'}
-.icon-sortbynamedescending-ztoa:before{content:'\f1c1'}
-.icon-sortbysizeascending:before{content:'\f1c3'}
-.icon-sortbysizedescending:before{content:'\f1c4'}
-.icon-soundwave:before{content:'\f194'}
-.icon-soup:before{content:'\f3d1'}
-.icon-spaceinvaders:before{content:'\f352'}
-.icon-spades:before{content:'\f2f5'}
-.icon-spam:before{content:'\f047'}
-.icon-spamalt:before{content:'\f048'}
-.icon-spawn:before{content:'\f344'}
-.icon-speaker:before{content:'\f372'}
-.icon-speed:before{content:'\f40b'}
-.icon-spider:before{content:'\f346'}
-.icon-spiderman:before{content:'\f347'}
-.icon-split:before{content:'\f335'}
-.icon-spoon:before{content:'\f213'}
-.icon-spray:before{content:'\f1c7'}
-.icon-spreadsheet:before{content:'\f0c3'}
-.icon-squareapp:before{content:'\f26f'}
-.icon-squarebrackets:before{content:'\f0b3'}
-.icon-ssh:before{content:'\f04e'}
-.icon-sslmanager:before{content:'\f04f'}
-.icon-stadium:before{content:'\f3d6'}
-.icon-stamp:before{content:'\f242'}
-.icon-stampalt:before{content:'\f243'}
-.icon-star:before{content:'\f13a'}
-.icon-star-empty:before{content:'\f13b'}
-.icon-starempty:before{content:'\f2de'}
-.icon-starfull:before{content:'\f2e0'}
-.icon-starhalf:before{content:'\f2df'}
-.icon-steak:before{content:'\f360'}
-.icon-steam:before{content:'\f2dd'}
-.icon-step-backward:before{content:'\f198'}
-.icon-step-forward:before{content:'\f197'}
-.icon-sticker:before{content:'\f3f5'}
-.icon-stiletto:before{content:'\f429'}
-.icon-stockdown:before{content:'\f252'}
-.icon-stocks:before{content:'\f250'}
-.icon-stockup:before{content:'\f251'}
-.icon-stomach:before{content:'\f3e1'}
-.icon-stop:before{content:'\f185'}
-.icon-stopwatch:before{content:'\f219'}
-.icon-storage-box:before{content:'\f011'}
-.icon-storagealt-drawer:before{content:'\f012'}
-.icon-store:before{content:'\f272'}
-.icon-storm:before{content:'\f230'}
-.icon-stove:before{content:'\f371'}
-.icon-strawberry:before{content:'\f3f3'}
-.icon-strikethrough:before{content:'\f1f7'}
-.icon-student-school:before{content:'\f288'}
-.icon-stumbleupon:before{content:'\f40c'}
-.icon-subdomain:before{content:'\f052'}
-.icon-submarine:before{content:'\f373'}
-.icon-subscript:before{content:'\f1ea'}
-.icon-subtractshape:before{content:'\f1fe'}
-.icon-sum:before{content:'\f33b'}
-.icon-sun-day:before{content:'\f206'}
-.icon-sunnysideup:before{content:'\f365'}
-.icon-superman:before{content:'\f33f'}
-.icon-superscript:before{content:'\f1eb'}
-.icon-support:before{content:'\f013'}
-.icon-supportalt:before{content:'\f014'}
-.icon-switch:before{content:'\f28a'}
-.icon-switchoff:before{content:'\f32d'}
-.icon-switchoffalt:before{content:'\f28e'}
-.icon-switchon:before{content:'\f32c'}
-.icon-switchonalt:before{content:'\f28d'}
-.icon-sword:before{content:'\f2ed'}
-.icon-sync:before{content:'\f0bd'}
-.icon-syncalt:before{content:'\f11c'}
-.icon-synckeeplocal:before{content:'\f33e'}
-.icon-synckeepserver:before{content:'\f33d'}
-.icon-syringe-antivirus:before{content:'\f0a9'}
-.icon-tablet:before{content:'\f118'}
-.icon-tabletennis-pingpong:before{content:'\f2f0'}
-.icon-taco:before{content:'\f3cd'}
-.icon-tag:before{content:'\f032'}
-.icon-tagalt-pricealt:before{content:'\f264'}
-.icon-tags:before{content:'\f482'}
-.icon-tagvertical:before{content:'\f15f'}
-.icon-tank:before{content:'\f423'}
-.icon-target:before{content:'\f2a6'}
-.icon-taskmanager-logprograms:before{content:'\f04b'}
-.icon-tasks:before{content:'\f0e0'}
-.icon-taxi:before{content:'\f3a4'}
-.icon-tea:before{content:'\f3cb'}
-.icon-teapot:before{content:'\f42c'}
-.icon-telescope:before{content:'\f3ef'}
-.icon-temperature-thermometer:before{content:'\f20d'}
-.icon-temperaturealt-thermometeralt:before{content:'\f20e'}
-.icon-tennis:before{content:'\f2ea'}
-.icon-tent-camping:before{content:'\f215'}
-.icon-terminal:before{content:'\f114'}
-.icon-tethering:before{content:'\f0f1'}
-.icon-tetrisone:before{content:'\f34b'}
-.icon-tetristhree:before{content:'\f34d'}
-.icon-tetristwo:before{content:'\f34c'}
-.icon-text-height:before{content:'\f1f8'}
-.icon-text-width:before{content:'\f1f9'}
-.icon-th:before{content:'\f110'}
-.icon-th-large:before{content:'\f112'}
-.icon-th-list:before{content:'\f113'}
-.icon-theather:before{content:'\f39c'}
-.icon-theme-style:before{content:'\f041'}
-.icon-thissideup:before{content:'\f41d'}
-.icon-threecolumns:before{content:'\f1ab'}
-.icon-thumbs-down:before{content:'\f139'}
-.icon-thumbs-up:before{content:'\f138'}
-.icon-ticket:before{content:'\f3dc'}
-.icon-tictactoe:before{content:'\f39a'}
-.icon-tie-business:before{content:'\2040'}
-.icon-time:before{content:'\f210'}
-.icon-timeline:before{content:'\f253'}
-.icon-tint:before{content:'\f208'}
-.icon-toast:before{content:'\f2ad'}
-.icon-toiletpaper:before{content:'\f384'}
-.icon-tooth:before{content:'\f3de'}
-.icon-toothbrush:before{content:'\f385'}
-.icon-tophat:before{content:'\f3f0'}
-.icon-torigate:before{content:'\f411'}
-.icon-touchpad:before{content:'\f115'}
-.icon-trafficlight:before{content:'\f22a'}
-.icon-transform:before{content:'\f1a6'}
-.icon-trash:before{content:'\f0ce'}
-.icon-trashempty:before{content:'\f0cf'}
-.icon-trashfull:before{content:'\f0d0'}
-.icon-travel:before{content:'\f422'}
-.icon-treediagram:before{content:'\f0ec'}
-.icon-treeornament:before{content:'\f37e'}
-.icon-triangle:before{content:'\25b3'}
-.icon-tron:before{content:'\f34f'}
-.icon-trophy:before{content:'\f2d7'}
-.icon-truck:before{content:'\f211'}
-.icon-trumpet:before{content:'\f375'}
-.icon-tumblr:before{content:'\f164'}
-.icon-tv:before{content:'\f1a4'}
-.icon-twitter:before{content:'\f16a'}
-.icon-twocolumnsleft:before{content:'\f1a9'}
-.icon-twocolumnsleftalt:before{content:'\f1aa'}
-.icon-twocolumnsright:before{content:'\f1a7'}
-.icon-twocolumnsrightalt:before{content:'\f1a8'}
-.icon-ubuntu:before{content:'\f120'}
-.icon-umbrella:before{content:'\f218'}
-.icon-underline:before{content:'\f1f6'}
-.icon-undo:before{content:'\f32a'}
-.icon-unlock:before{content:'\f0bf'}
-.icon-upleft:before{content:'\f302'}
-.icon-upload:before{content:'\f47a'}
-.icon-uploadalt:before{content:'\f11b'}
-.icon-upright:before{content:'\f303'}
-.icon-uptime:before{content:'\f017'}
-.icon-usb:before{content:'\f10d'}
-.icon-usbalt:before{content:'\f10e'}
-.icon-usbplug:before{content:'\f10f'}
-.icon-user:before{content:'\f133'}
-.icon-userfilter:before{content:'\f05d'}
-.icon-usfootball:before{content:'\f2ec'}
-.icon-value-coins:before{content:'\f018'}
-.icon-vector:before{content:'\f1b6'}
-.icon-vendetta:before{content:'\f3c5'}
-.icon-video:before{content:'\f17d'}
-.icon-viking:before{content:'\f379'}
-.icon-vimeo:before{content:'\f168'}
-.icon-vinyl:before{content:'\f0cc'}
-.icon-violin:before{content:'\f1a5'}
-.icon-virus:before{content:'\f0a8'}
-.icon-visa:before{content:'\f3c2'}
-.icon-visitor:before{content:'\f097'}
-.icon-vlc-cone:before{content:'\f192'}
-.icon-voice:before{content:'\f18c'}
-.icon-volume-down:before{content:'\f0e3'}
-.icon-volume-off:before{content:'\f0e4'}
-.icon-volume-up:before{content:'\f0e2'}
-.icon-vps:before{content:'\f025'}
-.icon-wacom:before{content:'\f1bb'}
-.icon-walle:before{content:'\f3bc'}
-.icon-wallet:before{content:'\e000'}
-.icon-warcraft:before{content:'\f3bf'}
-.icon-warmedal:before{content:'\f2e4'}
-.icon-warning-sign:before{content:'\f316'}
-.icon-washer:before{content:'\f39b'}
-.icon-watch:before{content:'\f378'}
-.icon-watertap-plumbing:before{content:'\f22d'}
-.icon-wave-sea:before{content:'\f23c'}
-.icon-wavealt-seaalt:before{content:'\f23b'}
-.icon-webcam:before{content:'\f0fe'}
-.icon-webcamalt:before{content:'\f129'}
-.icon-webhostinghub:before{content:'\f031'}
-.icon-webmail:before{content:'\f045'}
-.icon-webpage:before{content:'\f033'}
-.icon-webplatform:before{content:'\f3c3'}
-.icon-websitealt:before{content:'\f01c'}
-.icon-websitebuilder:before{content:'\f034'}
-.icon-weight:before{content:'\f430'}
-.icon-westernunion:before{content:'\f26a'}
-.icon-wheel:before{content:'\f228'}
-.icon-wheelchair:before{content:'\f3fe'}
-.icon-whistle:before{content:'\f3d8'}
-.icon-whmcs:before{content:'\f066'}
-.icon-wifi:before{content:'\f0ff'}
-.icon-wind:before{content:'\f41b'}
-.icon-windleft:before{content:'\f424'}
-.icon-windows:before{content:'\f019'}
-.icon-windright:before{content:'\f425'}
-.icon-wine:before{content:'\f238'}
-.icon-wizard:before{content:'\f03c'}
-.icon-wizardalt:before{content:'\f1fb'}
-.icon-wizardhat:before{content:'\f337'}
-.icon-woman-female:before{content:'\f2a2'}
-.icon-women:before{content:'\f24d'}
-.icon-wordpress:before{content:'\f074'}
-.icon-wrench:before{content:'\f05b'}
-.icon-wrenchalt:before{content:'\f2b2'}
-.icon-xbox:before{content:'\f353'}
-.icon-xmen:before{content:'\f345'}
-.icon-yahoo:before{content:'\f151'}
-.icon-yen:before{content:'\00a5'}
-.icon-yenalt:before{content:'\f25d'}
-.icon-yinyang:before{content:'\262f'}
-.icon-youtube:before{content:'\f142'}
-.icon-zelda:before{content:'\f3b8'}
-.icon-zikula:before{content:'\f0ac'}
-.icon-zip:before{content:'\f116'}
-.icon-zodiac-aquarius:before{content:'\f3b4'}
-.icon-zodiac-aries:before{content:'\f3aa'}
-.icon-zodiac-cancer:before{content:'\f3ad'}
-.icon-zodiac-capricorn:before{content:'\f3b3'}
-.icon-zodiac-gemini:before{content:'\f3ac'}
-.icon-zodiac-leo:before{content:'\f3ae'}
-.icon-zodiac-libra:before{content:'\f3b0'}
-.icon-zodiac-pisces:before{content:'\f3b5'}
-.icon-zodiac-sagitarius:before{content:'\f3b2'}
-.icon-zodiac-scorpio:before{content:'\f3b1'}
-.icon-zodiac-taurus:before{content:'\f3ab'}
-.icon-zodiac-virgo:before{content:'\f3af'}
-.icon-zoom-in:before{content:'\f320'}
-.icon-zoom-out:before{content:'\f321'}
-.icon-vk:before{content:'\f34e'}
-.icon-bitcoin:before{content:'\f584'}
-.icon-rouble:before{content:'\f4ca'}
-.icon-phpnuke:before{content:'\f48c'}
-.icon-modx:before{content:'\f48d'}
-.icon-eoneohseven:before{content:'\f48e'}
-.icon-subrion:before{content:'\f48f'}
-.icon-typothree:before{content:'\f490'}
-.icon-tikiwiki:before{content:'\f491'}
-.icon-pligg:before{content:'\f492'}
-.icon-pyrocms:before{content:'\f493'}
-.icon-mambo:before{content:'\f494'}
-.icon-contao:before{content:'\f495'}
-.icon-crackedegg:before{content:'\f496'}
-.icon-coffeecupalt:before{content:'\f497'}
-.icon-reademailalt:before{content:'\f498'}
-.icon-train:before{content:'\f499'}
-.icon-shoebox:before{content:'\f49a'}
-.icon-bathtub:before{content:'\f49b'}
-.icon-ninegag:before{content:'\f49c'}
-.icon-pebble:before{content:'\f49d'}
-.icon-musicthree:before{content:'\f49e'}
-.icon-stairsup:before{content:'\f49f'}
-.icon-stairsdown:before{content:'\f4a0'}
-.icon-bookalt:before{content:'\f4a1'}
-.icon-programclose:before{content:'\f4a2'}
-.icon-programok:before{content:'\f4a3'}
-.icon-splitalt:before{content:'\f4a4'}
-.icon-solarsystem:before{content:'\f4a5'}
-.icon-honeycomb:before{content:'\f4a6'}
-.icon-tools:before{content:'\f4a7'}
-.icon-xoops:before{content:'\f4a8'}
-.icon-pixie:before{content:'\f4a9'}
-.icon-dotclear:before{content:'\f4aa'}
-.icon-impresscms:before{content:'\f4ab'}
-.icon-saurus:before{content:'\f4ac'}
-.icon-impresspages:before{content:'\f4ad'}
-.icon-monstra:before{content:'\f4ae'}
-.icon-snews:before{content:'\f4af'}
-.icon-jcore:before{content:'\f4b0'}
-.icon-silverstripe:before{content:'\f4b1'}
-.icon-btwoevolution:before{content:'\f4b2'}
-.icon-nucleus:before{content:'\f4b3'}
-.icon-symphony:before{content:'\f4b5'}
-.icon-vanillacms:before{content:'\f4b6'}
-.icon-bbpress:before{content:'\f4b7'}
-.icon-phpbbalt:before{content:'\f4b8'}
-.icon-chyrp:before{content:'\f4b9'}
-.icon-pivotx:before{content:'\f4ba'}
-.icon-pagecookery:before{content:'\f4bb'}
-.icon-moviereelalt:before{content:'\f4bc'}
-.icon-cassettealt:before{content:'\f4bd'}
-.icon-photobucket:before{content:'\f4be'}
-.icon-technorati:before{content:'\f4bf'}
-.icon-theverge:before{content:'\f4c0'}
-.icon-stacks:before{content:'\f4c1'}
-.icon-dotlist:before{content:'\f4c2'}
-.icon-numberlist:before{content:'\f4c3'}
-.icon-indentleft:before{content:'\f4c4'}
-.icon-indentright:before{content:'\f4c5'}
-.icon-fblike:before{content:'\f4c6'}
-.icon-fbdislike:before{content:'\f4c7'}
-.icon-sale:before{content:'\f4c8'}
-.icon-sharetronix:before{content:'\f4c9'}
-.icon-markerdown:before{content:'\f4cb'}
-.icon-markerup:before{content:'\f4cc'}
-.icon-markerleft:before{content:'\f4cd'}
-.icon-markerright:before{content:'\f4ce'}
-.icon-bookmarkalt:before{content:'\f4cf'}
-.icon-calendarthree:before{content:'\f4d0'}
-.icon-wineglass:before{content:'\f4d1'}
-.icon-slidersoff:before{content:'\f4d2'}
-.icon-slidersmiddle:before{content:'\f4d3'}
-.icon-slidersfull:before{content:'\f4d4'}
-.icon-slidersdesc:before{content:'\f4d5'}
-.icon-slidersasc:before{content:'\f4d6'}
-.icon-slideronefull:before{content:'\f4d7'}
-.icon-slidertwofull:before{content:'\f4d8'}
-.icon-sliderthreefull:before{content:'\f4d9'}
-.icon-noborders:before{content:'\f4da'}
-.icon-bottomborder:before{content:'\f4db'}
-.icon-topborder:before{content:'\f4dc'}
-.icon-leftborder:before{content:'\f4dd'}
-.icon-rightborder:before{content:'\f4de'}
-.icon-horizontalborder:before{content:'\f4df'}
-.icon-verticalborder:before{content:'\f4e0'}
-.icon-outerborders:before{content:'\f4e1'}
-.icon-innerborders:before{content:'\f4e2'}
-.icon-fullborders:before{content:'\f4e3'}
-.icon-networksignalalt:before{content:'\f4e4'}
-.icon-resizeverticalalt:before{content:'\f4e5'}
-.icon-resizehorizontalalt:before{content:'\f4e6'}
-.icon-moneyalt:before{content:'\f4e7'}
-.icon-fontcase:before{content:'\f4e8'}
-.icon-playstation:before{content:'\f4e9'}
-.icon-cube:before{content:'\f4ea'}
-.icon-sphere:before{content:'\f4eb'}
-.icon-ceilinglight:before{content:'\f4ec'}
-.icon-chandelier:before{content:'\f4ed'}
-.icon-details:before{content:'\f4ee'}
-.icon-detailsalt:before{content:'\f4ef'}
-.icon-bullet:before{content:'\f4f0'}
-.icon-gun:before{content:'\f4f1'}
-.icon-processorthree:before{content:'\f4f2'}
-.icon-world:before{content:'\f4f3'}
-.icon-statistics:before{content:'\f4f4'}
-.icon-shoppingcartalt:before{content:'\f4f5'}
-.icon-microphonealt:before{content:'\f4f6'}
-.icon-routeralt:before{content:'\f4f7'}
-.icon-shell:before{content:'\f4f8'}
-.icon-squareplay:before{content:'\f4f9'}
-.icon-squarestop:before{content:'\f4fa'}
-.icon-squarepause:before{content:'\f4fb'}
-.icon-squarerecord:before{content:'\f4fc'}
-.icon-squareforward:before{content:'\f4fd'}
-.icon-squareback:before{content:'\f4fe'}
-.icon-squarenext:before{content:'\f4ff'}
-.icon-squareprevious:before{content:'\f500'}
-.icon-mega:before{content:'\f501'}
-.icon-charliechaplin:before{content:'\f502'}
-.icon-popcorn:before{content:'\f503'}
-.icon-fatarrowright:before{content:'\f504'}
-.icon-fatarrowleft:before{content:'\f505'}
-.icon-fatarrowdown:before{content:'\f506'}
-.icon-fatarrowup:before{content:'\f507'}
-.icon-shirtbutton:before{content:'\f508'}
-.icon-shirtbuttonalt:before{content:'\f509'}
-.icon-cuckooclock:before{content:'\f50a'}
-.icon-lens:before{content:'\f50b'}
-.icon-voltage:before{content:'\f50c'}
-.icon-planealt:before{content:'\f50d'}
-.icon-busalt:before{content:'\f50e'}
-.icon-lipstick:before{content:'\f50f'}
-.icon-plantalt:before{content:'\f510'}
-.icon-paperboat:before{content:'\f511'}
-.icon-texture:before{content:'\f512'}
-.icon-dominoone:before{content:'\f513'}
-.icon-dominotwo:before{content:'\f514'}
-.icon-dominothree:before{content:'\f515'}
-.icon-dominofour:before{content:'\f516'}
-.icon-dominofive:before{content:'\f517'}
-.icon-dominosix:before{content:'\f518'}
-.icon-dominoseven:before{content:'\f519'}
-.icon-dominoeight:before{content:'\f51a'}
-.icon-dominonine:before{content:'\f51b'}
-.icon-connected:before{content:'\f51c'}
-.icon-connectedpc:before{content:'\f51d'}
-.icon-musicsheet:before{content:'\f51e'}
-.icon-rdio:before{content:'\f51f'}
-.icon-spotify:before{content:'\f520'}
-.icon-deviantart:before{content:'\f521'}
-.icon-yelp:before{content:'\f522'}
-.icon-behance:before{content:'\f523'}
-.icon-nfc:before{content:'\f524'}
-.icon-earbudsalt:before{content:'\f525'}
-.icon-earbuds:before{content:'\f526'}
-.icon-amazon:before{content:'\f527'}
-.icon-openid:before{content:'\f528'}
-.icon-digg:before{content:'\f529'}
-.icon-retweet:before{content:'\f52a'}
-.icon-moonnew:before{content:'\f52b'}
-.icon-moonwaxingcrescent:before{content:'\f52c'}
-.icon-moonfirstquarter:before{content:'\f52d'}
-.icon-moonwaxinggibbous:before{content:'\f52e'}
-.icon-moonfull:before{content:'\f52f'}
-.icon-moonwaninggibbous:before{content:'\f530'}
-.icon-moonthirdquarter:before{content:'\f531'}
-.icon-moonwaningcrescent:before{content:'\f532'}
-.icon-planet:before{content:'\f533'}
-.icon-sodacup:before{content:'\f534'}
-.icon-cocktail:before{content:'\f535'}
-.icon-church:before{content:'\f536'}
-.icon-mosque:before{content:'\f537'}
-.icon-comedy:before{content:'\f538'}
-.icon-tragedy:before{content:'\f539'}
-.icon-bacon:before{content:'\f53a'}
-.icon-trailor:before{content:'\f53b'}
-.icon-tshirt:before{content:'\f53c'}
-.icon-design:before{content:'\f53d'}
-.icon-spiderweb:before{content:'\f53e'}
-.icon-fireplace:before{content:'\f53f'}
-.icon-tallglass:before{content:'\f540'}
-.icon-grapes:before{content:'\f541'}
-.icon-biohazard:before{content:'\f542'}
-.icon-directions:before{content:'\f543'}
-.icon-equalizerthree:before{content:'\f544'}
-.icon-mountains:before{content:'\f545'}
-.icon-bing:before{content:'\f546'}
-.icon-windowseight:before{content:'\f547'}
-.icon-microsoftoffice:before{content:'\f548'}
-.icon-salealt:before{content:'\f549'}
-.icon-purse:before{content:'\f54a'}
-.icon-chickenalt:before{content:'\f54b'}
-.icon-podium:before{content:'\f54c'}
-.icon-findfriends:before{content:'\f54d'}
-.icon-microphonethree:before{content:'\f54e'}
-.icon-workshirt:before{content:'\f54f'}
-.icon-donotdisturb:before{content:'\f550'}
-.icon-addtags:before{content:'\f551'}
-.icon-removetags:before{content:'\f556'}
-.icon-carbattery:before{content:'\f553'}
-.icon-debug:before{content:'\f554'}
-.icon-trojan:before{content:'\f555'}
-.icon-molecule:before{content:'\f556'}
-.icon-safetygoggles:before{content:'\f557'}
-.icon-leather:before{content:'\f558'}
-.icon-teddybear:before{content:'\f559'}
-.icon-stroller:before{content:'\f55a'}
-.icon-circleplay:before{content:'\f55b'}
-.icon-circlestop:before{content:'\f55c'}
-.icon-circlepause:before{content:'\f55d'}
-.icon-circlerecord:before{content:'\f55e'}
-.icon-circleforward:before{content:'\f55f'}
-.icon-circlebackward:before{content:'\f560'}
-.icon-circlenext:before{content:'\f561'}
-.icon-circleprevious:before{content:'\f562'}
-.icon-circleplayempty:before{content:'\f563'}
-.icon-circlestopempty:before{content:'\f564'}
-.icon-circlepauseempty:before{content:'\f565'}
-.icon-circlerecordempty:before{content:'\f566'}
-.icon-circleforwardempty:before{content:'\f567'}
-.icon-circlebackwardempty:before{content:'\f568'}
-.icon-circlenextempty:before{content:'\f569'}
-.icon-circlepreviousempty:before{content:'\f56a'}
-.icon-belt:before{content:'\f56b'}
-.icon-bait:before{content:'\f56c'}
-.icon-manalt:before{content:'\f56d'}
-.icon-womanalt:before{content:'\f56e'}
-.icon-clover:before{content:'\f56f'}
-.icon-pacifier:before{content:'\f570'}
-.icon-calcplus:before{content:'\f571'}
-.icon-calcminus:before{content:'\f572'}
-.icon-calcmultiply:before{content:'\f573'}
-.icon-calcdivide:before{content:'\f574'}
-.icon-calcequals:before{content:'\f575'}
-.icon-city:before{content:'\f576'}
-.icon-hdvideo:before{content:'\f577'}
-.icon-horizontalexpand:before{content:'\f578'}
-.icon-horizontalcontract:before{content:'\f579'}
-.icon-radar:before{content:'\f57a'}
-.icon-threed:before{content:'\f57b'}
-.icon-flickralt:before{content:'\f57c'}
-.icon-pattern:before{content:'\f57d'}
-.icon-elevator:before{content:'\f57e'}
-.icon-escalator:before{content:'\f57f'}
-.icon-portrait:before{content:'\f580'}
-.icon-cigar:before{content:'\f581'}
-.icon-dropbox:before{content:'\f582'}
-.icon-origami:before{content:'\f583'}
-.icon-opensource:before{content:'\f585'}
-.icon-redaxscript:before{content:'\f586'}
-.icon-mahara:before{content:'\f587'}
-.icon-forkcms:before{content:'\f588'}
-.icon-pimcore:before{content:'\f589'}
-.icon-bigace:before{content:'\f58a'}
-.icon-aef:before{content:'\f58b'}
-.icon-punbb:before{content:'\f58c'}
-.icon-phorum:before{content:'\f58d'}
-.icon-fluxbb:before{content:'\f58e'}
-.icon-minibb:before{content:'\f58f'}
-.icon-zenphoto:before{content:'\f590'}
-.icon-fourimages:before{content:'\f591'}
-.icon-plogger:before{content:'\f592'}
-.icon-jcow:before{content:'\f593'}
-.icon-elgg:before{content:'\f594'}
-.icon-etano:before{content:'\f595'}
-.icon-openclassifieds:before{content:'\f596'}
-.icon-osclass:before{content:'\f597'}
-.icon-openx:before{content:'\f598'}
-.icon-phplist:before{content:'\f599'}
-.icon-roundcube:before{content:'\f59a'}
-.icon-pommo:before{content:'\f59b'}
-.icon-webinsta:before{content:'\f59c'}
-.icon-limesurvey:before{content:'\f59d'}
-.icon-fengoffice:before{content:'\f59e'}
-.icon-eyeos:before{content:'\f59f'}
-.icon-dotproject:before{content:'\f5a0'}
-.icon-collabtive:before{content:'\f5a1'}
-.icon-projectpier:before{content:'\f5a2'}
-.icon-taskfreak:before{content:'\f5a3'}
-.icon-eventum:before{content:'\f5a4'}
-.icon-traq:before{content:'\f5a5'}
-.icon-mantisbugtracker:before{content:'\f5a6'}
-.icon-oscommerce:before{content:'\f5a7'}
-.icon-zencart:before{content:'\f5a8'}
-.icon-tomatocart:before{content:'\f5a9'}
-.icon-boxbilling:before{content:'\f5aa'}
-.icon-zurmo:before{content:'\f5ab'}
-.icon-orangehrm:before{content:'\f5ac'}
-.icon-vtiger:before{content:'\f5ad'}
-.icon-mibew:before{content:'\f5ae'}
-.icon-phpmyfaq:before{content:'\f5af'}
-.icon-yiiframework:before{content:'\f5b0'}
-.icon-zendframework:before{content:'\f5b1'}
-.icon-fuelphp:before{content:'\f5b2'}
-.icon-kohana:before{content:'\f5b3'}
-.icon-smarty:before{content:'\f5b4'}
-.icon-sidu:before{content:'\f5b5'}
-.icon-simplepie:before{content:'\f5b6'}
-.icon-projectsend:before{content:'\f5b7'}
-.icon-extjs:before{content:'\f5b8'}
-.icon-raphael:before{content:'\f5b9'}
-.icon-sizzle:before{content:'\f5ba'}
-.icon-yui:before{content:'\f5bb'}
-.icon-scissorsalt:before{content:'\f5bc'}
-.icon-cuthere:before{content:'\f5bd'}
-.icon-coinsalt:before{content:'\f5be'}
-.icon-parkingmeter:before{content:'\f5bf'}
-.icon-treethree:before{content:'\f5c0'}
-.icon-packarchive:before{content:'\f5c1'}
-.icon-unpackarchive:before{content:'\f5c2'}
-.icon-terminalalt:before{content:'\f5c3'}
-.icon-jersey:before{content:'\f5c4'}
-.icon-vial:before{content:'\f5c5'}
-.icon-noteslist:before{content:'\f5c6'}
-.icon-notestasks:before{content:'\f5c7'}
-.icon-notesdate:before{content:'\f5c8'}
-.icon-noteslocation:before{content:'\f5c9'}
-.icon-noteslistalt:before{content:'\f5ca'}
-.icon-notestasksalt:before{content:'\f5cb'}
-.icon-notesdatealt:before{content:'\f5cc'}
-.icon-noteslocationalt:before{content:'\f5cd'}
-.icon-useralt:before{content:'\f5ce'}
-.icon-adduseralt:before{content:'\f5cf'}
-.icon-removeuseralt:before{content:'\f5d0'}
-.icon-banuseralt:before{content:'\f5d1'}
-.icon-banuser:before{content:'\f5d2'}
-.icon-paintrollalt:before{content:'\f5d3'}
-.icon-textcursor:before{content:'\f5d4'}
-.icon-textfield:before{content:'\f5d5'}
-.icon-precisecursor:before{content:'\f5d6'}
-.icon-brokenlink:before{content:'\f5d7'}
-.icon-bookmarkthree:before{content:'\f5d8'}
-.icon-bookmarkfour:before{content:'\f5d9'}
-.icon-warmedalalt:before{content:'\f5da'}
-.icon-thinking:before{content:'\f5db'}
-.icon-commentlove:before{content:'\f5dc'}
-.icon-commentsmiley:before{content:'\f5dd'}
-.icon-sharetwo:before{content:'\f147'}
-.icon-emptystar:before{content:'\f2de'}
-.icon-halfstar:before{content:'\f2df'}
-.icon-fullstar:before{content:'\f2e0'}
-.icon-forbidden:before{content:'\f314'}
-.icon-indentleftalt:before{content:'\f4c4'}
-.icon-indentrightalt:before{content:'\f4c5'}
-.icon-modxalt:before{content:'\f5de'}
-.icon-apple:before{content:'\f5df'}
-.icon-greekcolumn:before{content:'\f5e0'}
-.icon-walletalt:before{content:'\f5e1'}
-.icon-dollarsquare:before{content:'\f5e2'}
-.icon-poundsquare:before{content:'\f5e3'}
-.icon-yensquare:before{content:'\f5e4'}
-.icon-eurosquare:before{content:'\f5e5'}
-.icon-bitcoinsquare:before{content:'\f5e6'}
-.icon-roublesquare:before{content:'\f5e7'}
-.icon-roublealt:before{content:'\f5e8'}
-.icon-bitcoinalt:before{content:'\f5e9'}
-.icon-gavel:before{content:'\f5ea'}
-.icon-barchartasc:before{content:'\f5eb'}
-.icon-barchartdesc:before{content:'\f5ec'}
-.icon-house:before{content:'\f5ed'}
-.icon-garage:before{content:'\f5ee'}
-.icon-milk:before{content:'\f5ef'}
-.icon-hryvnia:before{content:'\f5f0'}
-.icon-hryvniasquare:before{content:'\f5f1'}
-.icon-hryvniaalt:before{content:'\f5f2'}
-.icon-beeralt:before{content:'\f5f3'}
-.icon-trolleyfull:before{content:'\f5f4'}
-.icon-trolleyload:before{content:'\f5f5'}
-.icon-trolleyunload:before{content:'\f5f6'}
-.icon-trolleyempty:before{content:'\f5f7'}
-.icon-mootools:before{content:'\f5f8'}
-.icon-mootoolstwo:before{content:'\f5f9'}
-.icon-mootoolsthree:before{content:'\f5fa'}
-.icon-mysqlthree:before{content:'\f5fb'}
-.icon-mysqlalt:before{content:'\f5fc'}
-.icon-pgsql:before{content:'\f5fd'}
-.icon-mongodb:before{content:'\f5fe'}
-.icon-neofourj:before{content:'\f5ff'}
-.icon-nosql:before{content:'\f600'}
-.icon-catface:before{content:'\f601'}
-.icon-polaroid:before{content:'\f602'}
-.icon-clouderror:before{content:'\f603'}
-.icon-camcorder:before{content:'\f604'}
-.icon-projector:before{content:'\f605'}
-.icon-sdvideo:before{content:'\f606'}
-.icon-fx:before{content:'\f607'}
-.icon-gramophone:before{content:'\f608'}
-.icon-speakeralt:before{content:'\f609'}
-.icon-hddalt:before{content:'\f60a'}
-.icon-usbflash:before{content:'\f60b'}
-.icon-manillaenvelope:before{content:'\f60c'}
-.icon-stickynote:before{content:'\f60d'}
-.icon-stickynotealt:before{content:'\f60e'}
-.icon-torch:before{content:'\f60f'}
-.icon-flashlightalt:before{content:'\f610'}
-.icon-campfire:before{content:'\f611'}
-.icon-cctv:before{content:'\f612'}
-.icon-drill:before{content:'\f613'}
-.icon-lampalt:before{content:'\f614'}
-.icon-flowerpot:before{content:'\f615'}
-.icon-defragment:before{content:'\f616'}
-.icon-panoramio:before{content:'\f617'}
-.icon-panorama:before{content:'\f618'}
-.icon-photosphere:before{content:'\f619'}
-.icon-panoramaalt:before{content:'\f61a'}
-.icon-timer:before{content:'\f61b'}
-.icon-burstmode:before{content:'\f61c'}
-.icon-cameraflash:before{content:'\f61d'}
-.icon-autoflash:before{content:'\f61e'}
-.icon-noflash:before{content:'\f61f'}
-.icon-threetofour:before{content:'\f620'}
-.icon-sixteentonine:before{content:'\f621'}
-.icon-cat:before{content:'\f622'}
-.icon-dog:before{content:'\f623'}
-.icon-rabbit:before{content:'\f624'}
-.icon-koala:before{content:'\f625'}
-.icon-butterflyalt:before{content:'\f626'}
-.icon-butterfly:before{content:'\f627'}
-.icon-wwf:before{content:'\f628'}
-.icon-poop:before{content:'\f629'}
-.icon-poopalt:before{content:'\f62a'}
-.icon-kiwi:before{content:'\f62b'}
-.icon-kiwifruit:before{content:'\f62c'}
-.icon-lemon:before{content:'\f62d'}
-.icon-pear:before{content:'\f62e'}
-.icon-watermelon:before{content:'\f62f'}
-.icon-onion:before{content:'\f630'}
-.icon-turnip:before{content:'\f631'}
-.icon-eggplant:before{content:'\f632'}
-.icon-avocado:before{content:'\f633'}
-.icon-perfume:before{content:'\f634'}
-.icon-arch:before{content:'\f635'}
-.icon-pluspages:before{content:'\f636'}
-.icon-community:before{content:'\f637'}
-.icon-pluscircles:before{content:'\f638'}
-.icon-googleplusold:before{content:'\f639'}
-.icon-plusgames:before{content:'\f63a'}
-.icon-event:before{content:'\f63b'}
-.icon-miui:before{content:'\f63c'}
-.icon-hot:before{content:'\f63d'}
-.icon-flowup:before{content:'\f63e'}
-.icon-flowdown:before{content:'\f63f'}
-.icon-moustache:before{content:'\f640'}
-.icon-angle:before{content:'\f641'}
-.icon-sleep:before{content:'\f642'}
-.icon-acorn:before{content:'\f643'}
-.icon-steamalt:before{content:'\f644'}
-.icon-resizeupleft:before{content:'\f645'}
-.icon-resizeupright:before{content:'\f646'}
-.icon-resizedownright:before{content:'\f647'}
-.icon-resizedownleft:before{content:'\f648'}
-.icon-hammeralt:before{content:'\f649'}
-.icon-bamboo:before{content:'\f64a'}
-.icon-mypictures:before{content:'\f64b'}
-.icon-mymusic:before{content:'\f64c'}
-.icon-myvideos:before{content:'\f64d'}
-.icon-systemfolder:before{content:'\f64e'}
-.icon-bookthree:before{content:'\f64f'}
-.icon-compile:before{content:'\f650'}
-.icon-report:before{content:'\f651'}
-.icon-fliphorizontal:before{content:'\f652'}
-.icon-flipvertical:before{content:'\f653'}
-.icon-construction:before{content:'\f654'}
-.icon-counteralt:before{content:'\f655'}
-.icon-counter:before{content:'\f656'}
-.icon-papercutter:before{content:'\f657'}
-.icon-snaptodot:before{content:'\f658'}
-.icon-snaptogrid:before{content:'\f659'}
-.icon-caligraphy:before{content:'\f65a'}
-.icon-icecreamthree:before{content:'\f65b'}
-.icon-skitch:before{content:'\f65c'}
-.icon-archlinux:before{content:'\f65d'}
-.icon-elementaryos:before{content:'\f65e'}
-.icon-loadingone:before{content:'\f65f'}
-.icon-loadingtwo:before{content:'\f660'}
-.icon-loadingthree:before{content:'\f661'}
-.icon-loadingfour:before{content:'\f662'}
-.icon-loadingfive:before{content:'\f663'}
-.icon-loadingsix:before{content:'\f664'}
-.icon-loadingseven:before{content:'\f665'}
-.icon-loadingeight:before{content:'\f666'}
-.icon-brokenheart:before{content:'\f667'}
-.icon-heartarrow:before{content:'\f668'}
-.icon-heartsparkle:before{content:'\f669'}
-.icon-cell:before{content:'\f66a'}
-.icon-panda:before{content:'\f66b'}
-.icon-refreshalt:before{content:'\f66c'}
-.icon-mirror:before{content:'\f66d'}
-.icon-headphonesthree:before{content:'\f66e'}
-.icon-fan:before{content:'\f66f'}
-.icon-tornado:before{content:'\f670'}
-.icon-hangout:before{content:'\f671'}
-.icon-beaker:before{content:'\f672'}
-.icon-beakeralt:before{content:'\f673'}
-.icon-phonescreensize:before{content:'\f674'}
-.icon-tabletscreensize:before{content:'\f675'}
-.icon-notification:before{content:'\f676'}
-.icon-googleglass:before{content:'\f677'}
-.icon-pinterest:before{content:'\f678'}
-.icon-soundcloud:before{content:'\f679'}
-.icon-alarmclock:before{content:'\f67a'}
-.icon-addalarm:before{content:'\f67b'}
-.icon-deletealarm:before{content:'\f67c'}
-.icon-turnoffalarm:before{content:'\f67d'}
-.icon-snooze:before{content:'\f67e'}
-.icon-bringforward:before{content:'\f67f'}
-.icon-sendbackward:before{content:'\f680'}
-.icon-bringtofront:before{content:'\f681'}
-.icon-sendtoback:before{content:'\f682'}
-.icon-tectile:before{content:'\f683'}
-.icon-grave:before{content:'\f684'}
-.icon-gravetwo:before{content:'\f685'}
-.icon-gravethree:before{content:'\f686'}
-.icon-gravefour:before{content:'\f687'}
-.icon-textlayer:before{content:'\f688'}
-.icon-vectoralt:before{content:'\f689'}
-.icon-drmanhattan:before{content:'\f68a'}
-.icon-foursquarealt:before{content:'\f68b'}
-.icon-hashtag:before{content:'\f68c'}
-.icon-enteralt:before{content:'\f68d'}
-.icon-exitalt:before{content:'\f68e'}
-.icon-cartalt:before{content:'\f68f'}
-.icon-vaultthree:before{content:'\f690'}
-.icon-fatundo:before{content:'\f691'}
-.icon-fatredo:before{content:'\f692'}
-.icon-feedly:before{content:'\f693'}
-.icon-feedlyalt:before{content:'\f694'}
-.icon-squareheart:before{content:'\f695'}
-.icon-squarestar:before{content:'\f696'}
-.icon-squarecomment:before{content:'\f697'}
-.icon-squarelike:before{content:'\f698'}
-.icon-squarebookmark:before{content:'\f699'}
-.icon-squaresearch:before{content:'\f69a'}
-.icon-squaresettings:before{content:'\f69b'}
-.icon-squarevoice:before{content:'\f69c'}
-.icon-google:before{content:'\f69d'}
-.icon-emojigrinalt:before{content:'\f69e'}
-.icon-emojigrin:before{content:'\f69f'}
-.icon-constellation:before{content:'\f6a0'}
-.icon-emojisurprise:before{content:'\f6a1'}
-.icon-emojidead:before{content:'\f6a2'}
-.icon-emojiangry:before{content:'\f6a3'}
-.icon-emojidevil:before{content:'\f6a4'}
-.icon-emojiwink:before{content:'\f6a5'}
-.icon-moonorbit:before{content:'\f6a6'}
-.icon-emojismile:before{content:'\f6a7'}
-.icon-emojisorry:before{content:'\f6a8'}
-.icon-emojiconfused:before{content:'\f6a9'}
-.icon-emojisleep:before{content:'\f6aa'}
-.icon-emojicry:before{content:'\f6ab'}
-.icon-circlefork:before{content:'\f6ac'}
-.icon-circlespoon:before{content:'\f6ad'}
-.icon-circleknife:before{content:'\f6ae'}
-.icon-circlepencil:before{content:'\f6af'}
-.icon-circlehammer:before{content:'\f6b0'}
-.icon-circlescrewdriver:before{content:'\f6b1'}
-.icon-middlefinger:before{content:'\f6b2'}
-.icon-heavymetal:before{content:'\f6b3'}
-.icon-turnright:before{content:'\f6b4'}
-.icon-turnleft:before{content:'\f6b5'}
-.icon-vineapp:before{content:'\f6b6'}
-.icon-vineappalt:before{content:'\f6b7'}
-.icon-finance:before{content:'\f6b8'}
-.icon-survey:before{content:'\f6b9'}
-.icon-hangouts:before{content:'\f6ba'}
-.icon-square0:before{content:'\f6bb'}
-.icon-square1:before{content:'\f6bc'}
-.icon-square2:before{content:'\f6bd'}
-.icon-square3:before{content:'\f6be'}
-.icon-square4:before{content:'\f6bf'}
-.icon-square5:before{content:'\f6c0'}
-.icon-square6:before{content:'\f6c1'}
-.icon-square7:before{content:'\f6c2'}
-.icon-square8:before{content:'\f6c3'}
-.icon-square9:before{content:'\f6c4'}
-.icon-squarea:before{content:'\f6c5'}
-.icon-squareb:before{content:'\f6c6'}
-.icon-squarec:before{content:'\f6c7'}
-.icon-squared:before{content:'\f6c8'}
-.icon-squaree:before{content:'\f6c9'}
-.icon-squaref:before{content:'\f6ca'}
-.icon-squareg:before{content:'\f6cb'}
-.icon-squareh:before{content:'\f6cc'}
-.icon-squarei:before{content:'\f6cd'}
-.icon-squarej:before{content:'\f6ce'}
-.icon-squarek:before{content:'\f6cf'}
-.icon-squarel:before{content:'\f6d0'}
-.icon-squarem:before{content:'\f6d1'}
-.icon-squaren:before{content:'\f6d2'}
-.icon-squareo:before{content:'\f6d3'}
-.icon-squarep:before{content:'\f6d4'}
-.icon-squareq:before{content:'\f6d5'}
-.icon-squarer:before{content:'\f6d6'}
-.icon-squares:before{content:'\f6d7'}
-.icon-squaret:before{content:'\f6d8'}
-.icon-squareu:before{content:'\f6d9'}
-.icon-squarev:before{content:'\f6da'}
-.icon-squarew:before{content:'\f6db'}
-.icon-squarex:before{content:'\f6dc'}
-.icon-squarey:before{content:'\f6dd'}
-.icon-squarez:before{content:'\f6de'}
-.icon-shuttle:before{content:'\f6df'}
-.icon-meteor:before{content:'\f6e0'}
-.icon-galaxy:before{content:'\f6e1'}
-.icon-observatory:before{content:'\f6e2'}
-.icon-astronaut:before{content:'\f6e3'}
-.icon-asteroid:before{content:'\f6e4'}
-.icon-sunrise:before{content:'\f6e5'}
-.icon-sunset:before{content:'\f6e6'}
-.icon-tiderise:before{content:'\f6e7'}
-.icon-tidefall:before{content:'\f6e8'}
-.icon-mushroomcloud:before{content:'\f6e9'}
-.icon-galaxyalt:before{content:'\f6ea'}
-.icon-sputnik:before{content:'\f6eb'}
-.icon-sextant:before{content:'\f6ec'}
-.icon-spock:before{content:'\f6ed'}
-.icon-meteorite:before{content:'\f6ee'}
-.icon-deathstar:before{content:'\f6ef'}
-.icon-deathstarbulding:before{content:'\f6f0'}
-.icon-fallingstar:before{content:'\f6f1'}
-.icon-windmill:before{content:'\f6f2'}
-.icon-windmillalt:before{content:'\f6f3'}
-.icon-pumpjack:before{content:'\f6f4'}
-.icon-nuclearplant:before{content:'\f6f5'}
-.icon-solarpanel:before{content:'\f6f6'}
-.icon-barrel:before{content:'\f6f7'}
-.icon-canister:before{content:'\f6f8'}
-.icon-railtunnel:before{content:'\f6f9'}
-.icon-roadtunnel:before{content:'\f6fa'}
-.icon-pickaxe:before{content:'\f6fb'}
-.icon-cow:before{content:'\f6fc'}
-.icon-sheep:before{content:'\f6fd'}
-.icon-fountain:before{content:'\f6fe'}
-.icon-circlezero:before{content:'\f6ff'}
-.icon-circleone:before{content:'\f700'}
-.icon-circletwo:before{content:'\f701'}
-.icon-circlethree:before{content:'\f702'}
-.icon-circlefour:before{content:'\f703'}
-.icon-circlefive:before{content:'\f704'}
-.icon-circlesix:before{content:'\f705'}
-.icon-circleseven:before{content:'\f706'}
-.icon-circleeight:before{content:'\f707'}
-.icon-circlenine:before{content:'\f708'}
-.icon-circlea:before{content:'\f709'}
-.icon-circleb:before{content:'\f70a'}
-.icon-circlec:before{content:'\f70b'}
-.icon-circled:before{content:'\f70c'}
-.icon-circlee:before{content:'\f70d'}
-.icon-circlef:before{content:'\f70e'}
-.icon-circleg:before{content:'\f70f'}
-.icon-circleh:before{content:'\f710'}
-.icon-circlei:before{content:'\f711'}
-.icon-circlej:before{content:'\f712'}
-.icon-circlek:before{content:'\f713'}
-.icon-circlel:before{content:'\f714'}
-.icon-circlem:before{content:'\f715'}
-.icon-circlen:before{content:'\f716'}
-.icon-circleo:before{content:'\f717'}
-.icon-circlep:before{content:'\f718'}
-.icon-circleq:before{content:'\f719'}
-.icon-circler:before{content:'\f71a'}
-.icon-circles:before{content:'\f71b'}
-.icon-circlet:before{content:'\f71c'}
-.icon-circleu:before{content:'\f71d'}
-.icon-circlev:before{content:'\f71e'}
-.icon-circlew:before{content:'\f71f'}
-.icon-circlex:before{content:'\f720'}
-.icon-circley:before{content:'\f721'}
-.icon-circlez:before{content:'\f722'}
-.icon-creeper:before{content:'\f723'}
-.icon-minecraft:before{content:'\f724'}
-.icon-minecraftalt:before{content:'\f725'}
-.icon-pixelsword:before{content:'\f726'}
-.icon-pixelbroadsword:before{content:'\f727'}
-.icon-pixelwand:before{content:'\f728'}
-.icon-pixelpotion:before{content:'\f729'}
-.icon-pixelpotionalt:before{content:'\f72a'}
-.icon-pixelpickaxe:before{content:'\f72b'}
-.icon-pixelbow:before{content:'\f72c'}
-.icon-pixelarrow:before{content:'\f72d'}
-.icon-pixelaxe:before{content:'\f72e'}
-.icon-pixeldagger:before{content:'\f72f'}
-.icon-pixelbastardsword:before{content:'\f730'}
-.icon-pixellance:before{content:'\f731'}
-.icon-pixelbattleaxe:before{content:'\f732'}
-.icon-pixelshovel:before{content:'\f733'}
-.icon-pixelsphere:before{content:'\f734'}
-.icon-pixelelixir:before{content:'\f735'}
-.icon-pixelchest:before{content:'\f736'}
-.icon-pixelshield:before{content:'\f737'}
-.icon-pixelheart:before{content:'\f738'}
-.icon-rudder:before{content:'\f739'}
-.icon-folderalt:before{content:'\f73a'}
-.icon-removefolderalt:before{content:'\f73b'}
-.icon-addfolderalt:before{content:'\f73c'}
-.icon-deletefolderalt:before{content:'\f73d'}
-.icon-openfolderalt:before{content:'\f73e'}
-.icon-clipboardalt:before{content:'\f73f'}
-.icon-pastealt:before{content:'\f740'}
-.icon-loadingflowccw:before{content:'\f741'}
-.icon-loadingflowcw:before{content:'\f742'}
-.icon-code:before{content:'\f743'}
-.icon-cloveralt:before{content:'\f744'}
-.icon-lips:before{content:'\f745'}
-.icon-kiss:before{content:'\f746'}
-.icon-manualshift:before{content:'\f747'}
-.icon-simcardthree:before{content:'\f748'}
-.icon-parthenon:before{content:'\f749'}
-.icon-addcomment:before{content:'\f74a'}
-.icon-deletecomment:before{content:'\f74b'}
-.icon-gender:before{content:'\f74c'}
-.icon-callalt:before{content:'\f74d'}
-.icon-outgoingcallalt:before{content:'\f74e'}
-.icon-incomingcallalt:before{content:'\f74f'}
-.icon-missedcallalt:before{content:'\f750'}
-.icon-export:before{content:'\f751'}
-.icon-import:before{content:'\f752'}
-.icon-cherryalt:before{content:'\f753'}
-.icon-panties:before{content:'\f754'}
-.icon-kimai:before{content:'\f755'}
-.icon-livejournal:before{content:'\f756'}
-.icon-livejournalalt:before{content:'\f757'}
-.icon-tagged:before{content:'\f758'}
-.icon-temple:before{content:'\f759'}
-.icon-mayanpyramid:before{content:'\f75a'}
-.icon-egyptpyramid:before{content:'\f75b'}
-.icon-tampermonkey:before{content:'\f75c'}
-.icon-pushbullet:before{content:'\f75d'}
-.icon-currents:before{content:'\f75e'}
-.icon-communitysmall:before{content:'\f75f'}
-.icon-squaregithub:before{content:'\f760'}
-.icon-projectfork:before{content:'\f761'}
-.icon-projectmerge:before{content:'\f762'}
-.icon-projectcompare:before{content:'\f763'}
-.icon-history:before{content:'\f764'}
-.icon-notebook:before{content:'\f765'}
-.icon-issue:before{content:'\f766'}
-.icon-issueclosed:before{content:'\f767'}
-.icon-issuereopened:before{content:'\f768'}
-.icon-rubyalt:before{content:'\f769'}
-.icon-lighton:before{content:'\f76a'}
-.icon-lightoff:before{content:'\f76b'}
-.icon-bellalt:before{content:'\f76c'}
-.icon-versions:before{content:'\f777'}
-.icon-twog:before{content:'\f76e'}
-.icon-threeg:before{content:'\f76f'}
-.icon-fourg:before{content:'\f770'}
-.icon-gpsalt:before{content:'\f771'}
-.icon-circleloaderfull:before{content:'\f772'}
-.icon-circleloaderseven:before{content:'\f773'}
-.icon-circleloadersix:before{content:'\f774'}
-.icon-circleloaderfive:before{content:'\f775'}
-.icon-circleloaderfour:before{content:'\f776'}
-.icon-circleloaderthree:before{content:'\f777'}
-.icon-circleloadertwo:before{content:'\f778'}
-.icon-circleloaderone:before{content:'\f779'}
-.icon-circleloaderempty:before{content:'\f77a'}
-.icon-whatsapp:before{content:'\f77b'}
-.icon-whatsappalt:before{content:'\f77c'}
-.icon-viber:before{content:'\f77d'}
-.icon-squareviber:before{content:'\f77e'}
-.icon-teamviewer:before{content:'\f77f'}
-.icon-tunein:before{content:'\f780'}
-.icon-tuneinalt:before{content:'\f781'}
-.icon-weightscale:before{content:'\f782'}
-.icon-boxing:before{content:'\f783'}
-.icon-speedalt:before{content:'\f784'}
-.icon-scriptalt:before{content:'\f785'}
-.icon-splitthree:before{content:'\f786'}
-.icon-mergethree:before{content:'\f787'}
-.icon-layersthree:before{content:'\f788'}
-.icon-mutemic:before{content:'\f789'}
-.icon-zerply:before{content:'\f78a'}
-.icon-circlegoogleplus:before{content:'\f78b'}
-.icon-circletwitter:before{content:'\f78c'}
-.icon-circlefacebook:before{content:'\f78d'}
-.icon-circleyahoo:before{content:'\f78e'}
-.icon-circlegithub:before{content:'\f78f'}
-.icon-forumsalt:before{content:'\f790'}
-.icon-circlepath:before{content:'\f791'}
-.icon-circlevimeo:before{content:'\f792'}
-.icon-circlevine:before{content:'\f793'}
-.icon-instagramtwo:before{content:'\f794'}
-.icon-instagramthree:before{content:'\f795'}
-.icon-flickrthree:before{content:'\f796'}
-.icon-quora:before{content:'\f797'}
-.icon-squarequora:before{content:'\f798'}
-.icon-circlequora:before{content:'\f799'}
-.icon-picasa:before{content:'\f79a'}
-.icon-branch:before{content:'\f79b'}
-.icon-ingress:before{content:'\f79c'}
-.icon-squarezerply:before{content:'\f79d'}
-.icon-circlezerply:before{content:'\f79e'}
-.icon-squarevimeo:before{content:'\f79f'}
-.icon-squaretwitter:before{content:'\f7a0'}
-.icon-brightnessalt:before{content:'\f7a1'}
-.icon-brightnessalthalf:before{content:'\f7a2'}
-.icon-brightnessaltfull:before{content:'\f7a3'}
-.icon-brightnessaltauto:before{content:'\f7a4'}
-.icon-shirtbuttonthree:before{content:'\f7a5'}
-.icon-openshare:before{content:'\f7a6'}
-.icon-copyapp:before{content:'\f7a7'}
-.icon-bowl:before{content:'\f7a8'}
-.icon-cloudalt:before{content:'\f7a9'}
-.icon-cloudaltdownload:before{content:'\f7aa'}
-.icon-cloudaltupload:before{content:'\f7ab'}
-.icon-cloudaltsync:before{content:'\f7ac'}
-.icon-cloudaltprivate:before{content:'\f7ad'}
-.icon-flipboard:before{content:'\f7ae'}
-.icon-octoloaderempty:before{content:'\f7af'}
-.icon-octoloaderone:before{content:'\f7b0'}
-.icon-octoloadertwo:before{content:'\f7b1'}
-.icon-octoloaderthree:before{content:'\f7b2'}
-.icon-octoloaderfour:before{content:'\f7b3'}
-.icon-octoloaderfive:before{content:'\f7b4'}
-.icon-octoloadersix:before{content:'\f7b5'}
-.icon-octoloaderseven:before{content:'\f7b6'}
-.icon-octoloaderfull:before{content:'\f7b7'}
-.icon-selectionsymbol:before{content:'\f7b8'}
-.icon-infinityalt:before{content:'\f7b9'}
-.icon-pullrequest:before{content:'\f7ba'}
-.icon-projectforkdelete:before{content:'\f7bb'}
-.icon-projectforkprivate:before{content:'\f7bc'}
-.icon-commit:before{content:'\f7bd'}
-.icon-htmlfile:before{content:'\f7be'}
-.icon-pushalt:before{content:'\f7bf'}
-.icon-pullalt:before{content:'\f7c0'}
-.icon-photonineframes:before{content:'\f7c1'}
-.icon-wetfloor:before{content:'\f7c2'}
-.icon-instagramfour:before{content:'\f7c3'}
-.icon-circleinstagram:before{content:'\f7c4'}
-.icon-videocamerathree:before{content:'\f7c5'}
-.icon-subtitles:before{content:'\f7c6'}
-.icon-subtitlesoff:before{content:'\f7c7'}
-.icon-compress:before{content:'\f7c8'}
-.icon-baby:before{content:'\f7c9'}
-.icon-ducky:before{content:'\f7ca'}
-.icon-handswipe:before{content:'\f7cb'}
-.icon-swipeup:before{content:'\f7cc'}
-.icon-swipedown:before{content:'\f7cd'}
-.icon-twofingerswipedown:before{content:'\f7ce'}
-.icon-twofingerswipeup:before{content:'\f7cf'}
-.icon-doubletap:before{content:'\f7d0'}
-.icon-dribbblealt:before{content:'\f7d1'}
-.icon-circlecallmissed:before{content:'\f7d2'}
-.icon-circlecallincoming:before{content:'\f7d3'}
-.icon-circlecalloutgoing:before{content:'\f7d4'}
-.icon-circledownload:before{content:'\f7d5'}
-.icon-circleupload:before{content:'\f7d6'}
-.icon-minismile:before{content:'\f7d7'}
-.icon-minisad:before{content:'\f7d8'}
-.icon-minilaugh:before{content:'\f7d9'}
-.icon-minigrin:before{content:'\f7da'}
-.icon-miniangry:before{content:'\f7db'}
-.icon-minitongue:before{content:'\f7dc'}
-.icon-minitonguealt:before{content:'\f7dd'}
-.icon-miniwink:before{content:'\f7de'}
-.icon-minitonguewink:before{content:'\f7df'}
-.icon-miniconfused:before{content:'\f7e0'}
-.icon-soundright:before{content:'\f7e1'}
-.icon-soundleft:before{content:'\f7e2'}
-.icon-savetodrive:before{content:'\f7e3'}
-.icon-layerorderup:before{content:'\f7e4'}
-.icon-layerorderdown:before{content:'\f7e5'}
-.icon-layerorder:before{content:'\f7e6'}
-.icon-circledribbble:before{content:'\f7e7'}
-.icon-squaredribbble:before{content:'\f7e8'}
-.icon-handexpand:before{content:'\f7e9'}
-.icon-handpinch:before{content:'\f7ea'}
-.icon-fontserif:before{content:'\f7eb'}
-.icon-fontsansserif:before{content:'\f7ec'}
-.icon-fontrounded:before{content:'\f7ed'}
-.icon-fonthandwriting:before{content:'\f7ee'}
-.icon-fonttypewriter:before{content:'\f7ef'}
-.icon-fontcomic:before{content:'\f7f0'}
-.icon-fontcaligraphy:before{content:'\f7f1'}
-.icon-fontgothic:before{content:'\f7f2'}
-.icon-fontstencil:before{content:'\f7f3'}
diff --git a/public/browse/karma.conf.js b/public/browse/karma.conf.js
deleted file mode 100755
index 44bb29f1a..000000000
--- a/public/browse/karma.conf.js
+++ /dev/null
@@ -1,33 +0,0 @@
-module.exports = function(config){
- config.set({
-
- basePath : './',
-
- files : [
- 'app/bower_components/angular/angular.js',
- 'app/bower_components/angular-route/angular-route.js',
- 'app/bower_components/angular-mocks/angular-mocks.js',
- 'app/components/**/*.js',
- 'app/view*/**/*.js'
- ],
-
- autoWatch : true,
-
- frameworks: ['jasmine'],
-
- browsers : ['Chrome'],
-
- plugins : [
- 'karma-chrome-launcher',
- 'karma-firefox-launcher',
- 'karma-jasmine',
- 'karma-junit-reporter'
- ],
-
- junitReporter : {
- outputFile: 'test_out/unit.xml',
- suite: 'unit'
- }
-
- });
-};
diff --git a/public/browse/lib/angular-animate/.bower.json b/public/browse/lib/angular-animate/.bower.json
deleted file mode 100644
index 493bf5609..000000000
--- a/public/browse/lib/angular-animate/.bower.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "name": "angular-animate",
- "version": "1.3.5",
- "main": "./angular-animate.js",
- "ignore": [],
- "dependencies": {
- "angular": "1.3.5"
- },
- "homepage": "https://github.com/angular/bower-angular-animate",
- "_release": "1.3.5",
- "_resolution": {
- "type": "version",
- "tag": "v1.3.5",
- "commit": "f1ce791ecb58c64af1caac6253f93ecf3e2bf203"
- },
- "_source": "git://github.com/angular/bower-angular-animate.git",
- "_target": "1.3.x",
- "_originalSource": "angular-animate"
-}
\ No newline at end of file
diff --git a/public/browse/lib/angular-animate/README.md b/public/browse/lib/angular-animate/README.md
deleted file mode 100644
index 930b5dcc5..000000000
--- a/public/browse/lib/angular-animate/README.md
+++ /dev/null
@@ -1,77 +0,0 @@
-# packaged angular-animate
-
-This repo is for distribution on `npm` and `bower`. The source for this module is in the
-[main AngularJS repo](https://github.com/angular/angular.js/tree/master/src/ngAnimate).
-Please file issues and pull requests against that repo.
-
-## Install
-
-You can install this package either with `npm` or with `bower`.
-
-### npm
-
-```shell
-npm install angular-animate
-```
-
-Add a `
-```
-
-Then add `ngAnimate` as a dependency for your app:
-
-```javascript
-angular.module('myApp', ['ngAnimate']);
-```
-
-Note that this package is not in CommonJS format, so doing `require('angular-animate')` will
-return `undefined`.
-
-### bower
-
-```shell
-bower install angular-animate
-```
-
-Then add a `
-```
-
-Then add `ngAnimate` as a dependency for your app:
-
-```javascript
-angular.module('myApp', ['ngAnimate']);
-```
-
-## Documentation
-
-Documentation is available on the
-[AngularJS docs site](http://docs.angularjs.org/api/ngAnimate).
-
-## License
-
-The MIT License
-
-Copyright (c) 2010-2012 Google, Inc. http://angularjs.org
-
-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.
diff --git a/public/browse/lib/angular-animate/angular-animate.js b/public/browse/lib/angular-animate/angular-animate.js
deleted file mode 100644
index 761d622ea..000000000
--- a/public/browse/lib/angular-animate/angular-animate.js
+++ /dev/null
@@ -1,2136 +0,0 @@
-/**
- * @license AngularJS v1.3.5
- * (c) 2010-2014 Google, Inc. http://angularjs.org
- * License: MIT
- */
-(function(window, angular, undefined) {'use strict';
-
-/* jshint maxlen: false */
-
-/**
- * @ngdoc module
- * @name ngAnimate
- * @description
- *
- * The `ngAnimate` module provides support for JavaScript, CSS3 transition and CSS3 keyframe animation hooks within existing core and custom directives.
- *
- *
- *
- * # Usage
- *
- * To see animations in action, all that is required is to define the appropriate CSS classes
- * or to register a JavaScript animation via the myModule.animation() function. The directives that support animation automatically are:
- * `ngRepeat`, `ngInclude`, `ngIf`, `ngSwitch`, `ngShow`, `ngHide`, `ngView` and `ngClass`. Custom directives can take advantage of animation
- * by using the `$animate` service.
- *
- * Below is a more detailed breakdown of the supported animation events provided by pre-existing ng directives:
- *
- * | Directive | Supported Animations |
- * |----------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------|
- * | {@link ng.directive:ngRepeat#animations ngRepeat} | enter, leave and move |
- * | {@link ngRoute.directive:ngView#animations ngView} | enter and leave |
- * | {@link ng.directive:ngInclude#animations ngInclude} | enter and leave |
- * | {@link ng.directive:ngSwitch#animations ngSwitch} | enter and leave |
- * | {@link ng.directive:ngIf#animations ngIf} | enter and leave |
- * | {@link ng.directive:ngClass#animations ngClass} | add and remove (the CSS class(es) present) |
- * | {@link ng.directive:ngShow#animations ngShow} & {@link ng.directive:ngHide#animations ngHide} | add and remove (the ng-hide class value) |
- * | {@link ng.directive:form#animation-hooks form} & {@link ng.directive:ngModel#animation-hooks ngModel} | add and remove (dirty, pristine, valid, invalid & all other validations) |
- * | {@link module:ngMessages#animations ngMessages} | add and remove (ng-active & ng-inactive) |
- * | {@link module:ngMessages#animations ngMessage} | enter and leave |
- *
- * You can find out more information about animations upon visiting each directive page.
- *
- * Below is an example of how to apply animations to a directive that supports animation hooks:
- *
- * ```html
- *
- *
- *
- *
- * ```
- *
- * Keep in mind that, by default, if an animation is running, any child elements cannot be animated
- * until the parent element's animation has completed. This blocking feature can be overridden by
- * placing the `ng-animate-children` attribute on a parent container tag.
- *
- * ```html
- *
- *
- *
- * ...
- *
- *
- *
- * ```
- *
- * When the `on` expression value changes and an animation is triggered then each of the elements within
- * will all animate without the block being applied to child elements.
- *
- * ## Are animations run when the application starts?
- * No they are not. When an application is bootstrapped Angular will disable animations from running to avoid
- * a frenzy of animations from being triggered as soon as the browser has rendered the screen. For this to work,
- * Angular will wait for two digest cycles until enabling animations. From there on, any animation-triggering
- * layout changes in the application will trigger animations as normal.
- *
- * In addition, upon bootstrap, if the routing system or any directives or load remote data (via $http) then Angular
- * will automatically extend the wait time to enable animations once **all** of the outbound HTTP requests
- * are complete.
- *
- * ## CSS-defined Animations
- * The animate service will automatically apply two CSS classes to the animated element and these two CSS classes
- * are designed to contain the start and end CSS styling. Both CSS transitions and keyframe animations are supported
- * and can be used to play along with this naming structure.
- *
- * The following code below demonstrates how to perform animations using **CSS transitions** with Angular:
- *
- * ```html
- *
- *
- *
- *
- *
- * ```
- *
- * The following code below demonstrates how to perform animations using **CSS animations** with Angular:
- *
- * ```html
- *
- *
- *
- *
- *
- * ```
- *
- * Both CSS3 animations and transitions can be used together and the animate service will figure out the correct duration and delay timing.
- *
- * Upon DOM mutation, the event class is added first (something like `ng-enter`), then the browser prepares itself to add
- * the active class (in this case `ng-enter-active`) which then triggers the animation. The animation module will automatically
- * detect the CSS code to determine when the animation ends. Once the animation is over then both CSS classes will be
- * removed from the DOM. If a browser does not support CSS transitions or CSS animations then the animation will start and end
- * immediately resulting in a DOM element that is at its final state. This final state is when the DOM element
- * has no CSS transition/animation classes applied to it.
- *
- * ### Structural transition animations
- *
- * Structural transitions (such as enter, leave and move) will always apply a `0s none` transition
- * value to force the browser into rendering the styles defined in the setup (.ng-enter, .ng-leave
- * or .ng-move) class. This means that any active transition animations operating on the element
- * will be cut off to make way for the enter, leave or move animation.
- *
- * ### Class-based transition animations
- *
- * Class-based transitions refer to transition animations that are triggered when a CSS class is
- * added to or removed from the element (via `$animate.addClass`, `$animate.removeClass`,
- * `$animate.setClass`, or by directives such as `ngClass`, `ngModel` and `form`).
- * They are different when compared to structural animations since they **do not cancel existing
- * animations** nor do they **block successive transitions** from rendering on the same element.
- * This distinction allows for **multiple class-based transitions** to be performed on the same element.
- *
- * In addition to ngAnimate supporting the default (natural) functionality of class-based transition
- * animations, ngAnimate also decorates the element with starting and ending CSS classes to aid the
- * developer in further styling the element throughout the transition animation. Earlier versions
- * of ngAnimate may have caused natural CSS transitions to break and not render properly due to
- * $animate temporarily blocking transitions using `0s none` in order to allow the setup CSS class
- * (the `-add` or `-remove` class) to be applied without triggering an animation. However, as of
- * **version 1.3**, this workaround has been removed with ngAnimate and all non-ngAnimate CSS
- * class transitions are compatible with ngAnimate.
- *
- * There is, however, one special case when dealing with class-based transitions in ngAnimate.
- * When rendering class-based transitions that make use of the setup and active CSS classes
- * (e.g. `.fade-add` and `.fade-add-active` for when `.fade` is added) be sure to define
- * the transition value **on the active CSS class** and not the setup class.
- *
- * ```css
- * .fade-add {
- * /* remember to place a 0s transition here
- * to ensure that the styles are applied instantly
- * even if the element already has a transition style */
- * transition:0s linear all;
- *
- * /* starting CSS styles */
- * opacity:1;
- * }
- * .fade-add.fade-add-active {
- * /* this will be the length of the animation */
- * transition:1s linear all;
- * opacity:0;
- * }
- * ```
- *
- * The setup CSS class (in this case `.fade-add`) also has a transition style property, however, it
- * has a duration of zero. This may not be required, however, incase the browser is unable to render
- * the styling present in this CSS class instantly then it could be that the browser is attempting
- * to perform an unnecessary transition.
- *
- * This workaround, however, does not apply to standard class-based transitions that are rendered
- * when a CSS class containing a transition is applied to an element:
- *
- * ```css
- * /* this works as expected */
- * .fade {
- * transition:1s linear all;
- * opacity:0;
- * }
- * ```
- *
- * Please keep this in mind when coding the CSS markup that will be used within class-based transitions.
- * Also, try not to mix the two class-based animation flavors together since the CSS code may become
- * overly complex.
- *
- *
- * ### Preventing Collisions With Third Party Libraries
- *
- * Some third-party frameworks place animation duration defaults across many element or className
- * selectors in order to make their code small and reuseable. This can lead to issues with ngAnimate, which
- * is expecting actual animations on these elements and has to wait for their completion.
- *
- * You can prevent this unwanted behavior by using a prefix on all your animation classes:
- *
- * ```css
- * /* prefixed with animate- */
- * .animate-fade-add.animate-fade-add-active {
- * transition:1s linear all;
- * opacity:0;
- * }
- * ```
- *
- * You then configure `$animate` to enforce this prefix:
- *
- * ```js
- * $animateProvider.classNameFilter(/animate-/);
- * ```
- *
- *
- * ### CSS Staggering Animations
- * A Staggering animation is a collection of animations that are issued with a slight delay in between each successive operation resulting in a
- * curtain-like effect. The ngAnimate module (versions >=1.2) supports staggering animations and the stagger effect can be
- * performed by creating a **ng-EVENT-stagger** CSS class and attaching that class to the base CSS class used for
- * the animation. The style property expected within the stagger class can either be a **transition-delay** or an
- * **animation-delay** property (or both if your animation contains both transitions and keyframe animations).
- *
- * ```css
- * .my-animation.ng-enter {
- * /* standard transition code */
- * -webkit-transition: 1s linear all;
- * transition: 1s linear all;
- * opacity:0;
- * }
- * .my-animation.ng-enter-stagger {
- * /* this will have a 100ms delay between each successive leave animation */
- * -webkit-transition-delay: 0.1s;
- * transition-delay: 0.1s;
- *
- * /* in case the stagger doesn't work then these two values
- * must be set to 0 to avoid an accidental CSS inheritance */
- * -webkit-transition-duration: 0s;
- * transition-duration: 0s;
- * }
- * .my-animation.ng-enter.ng-enter-active {
- * /* standard transition styles */
- * opacity:1;
- * }
- * ```
- *
- * Staggering animations work by default in ngRepeat (so long as the CSS class is defined). Outside of ngRepeat, to use staggering animations
- * on your own, they can be triggered by firing multiple calls to the same event on $animate. However, the restrictions surrounding this
- * are that each of the elements must have the same CSS className value as well as the same parent element. A stagger operation
- * will also be reset if more than 10ms has passed after the last animation has been fired.
- *
- * The following code will issue the **ng-leave-stagger** event on the element provided:
- *
- * ```js
- * var kids = parent.children();
- *
- * $animate.leave(kids[0]); //stagger index=0
- * $animate.leave(kids[1]); //stagger index=1
- * $animate.leave(kids[2]); //stagger index=2
- * $animate.leave(kids[3]); //stagger index=3
- * $animate.leave(kids[4]); //stagger index=4
- *
- * $timeout(function() {
- * //stagger has reset itself
- * $animate.leave(kids[5]); //stagger index=0
- * $animate.leave(kids[6]); //stagger index=1
- * }, 100, false);
- * ```
- *
- * Stagger animations are currently only supported within CSS-defined animations.
- *
- * ## JavaScript-defined Animations
- * In the event that you do not want to use CSS3 transitions or CSS3 animations or if you wish to offer animations on browsers that do not
- * yet support CSS transitions/animations, then you can make use of JavaScript animations defined inside of your AngularJS module.
- *
- * ```js
- * //!annotate="YourApp" Your AngularJS Module|Replace this or ngModule with the module that you used to define your application.
- * var ngModule = angular.module('YourApp', ['ngAnimate']);
- * ngModule.animation('.my-crazy-animation', function() {
- * return {
- * enter: function(element, done) {
- * //run the animation here and call done when the animation is complete
- * return function(cancelled) {
- * //this (optional) function will be called when the animation
- * //completes or when the animation is cancelled (the cancelled
- * //flag will be set to true if cancelled).
- * };
- * },
- * leave: function(element, done) { },
- * move: function(element, done) { },
- *
- * //animation that can be triggered before the class is added
- * beforeAddClass: function(element, className, done) { },
- *
- * //animation that can be triggered after the class is added
- * addClass: function(element, className, done) { },
- *
- * //animation that can be triggered before the class is removed
- * beforeRemoveClass: function(element, className, done) { },
- *
- * //animation that can be triggered after the class is removed
- * removeClass: function(element, className, done) { }
- * };
- * });
- * ```
- *
- * JavaScript-defined animations are created with a CSS-like class selector and a collection of events which are set to run
- * a javascript callback function. When an animation is triggered, $animate will look for a matching animation which fits
- * the element's CSS class attribute value and then run the matching animation event function (if found).
- * In other words, if the CSS classes present on the animated element match any of the JavaScript animations then the callback function will
- * be executed. It should be also noted that only simple, single class selectors are allowed (compound class selectors are not supported).
- *
- * Within a JavaScript animation, an object containing various event callback animation functions is expected to be returned.
- * As explained above, these callbacks are triggered based on the animation event. Therefore if an enter animation is run,
- * and the JavaScript animation is found, then the enter callback will handle that animation (in addition to the CSS keyframe animation
- * or transition code that is defined via a stylesheet).
- *
- *
- * ### Applying Directive-specific Styles to an Animation
- * In some cases a directive or service may want to provide `$animate` with extra details that the animation will
- * include into its animation. Let's say for example we wanted to render an animation that animates an element
- * towards the mouse coordinates as to where the user clicked last. By collecting the X/Y coordinates of the click
- * (via the event parameter) we can set the `top` and `left` styles into an object and pass that into our function
- * call to `$animate.addClass`.
- *
- * ```js
- * canvas.on('click', function(e) {
- * $animate.addClass(element, 'on', {
- * to: {
- * left : e.client.x + 'px',
- * top : e.client.y + 'px'
- * }
- * }):
- * });
- * ```
- *
- * Now when the animation runs, and a transition or keyframe animation is picked up, then the animation itself will
- * also include and transition the styling of the `left` and `top` properties into its running animation. If we want
- * to provide some starting animation values then we can do so by placing the starting animations styles into an object
- * called `from` in the same object as the `to` animations.
- *
- * ```js
- * canvas.on('click', function(e) {
- * $animate.addClass(element, 'on', {
- * from: {
- * position: 'absolute',
- * left: '0px',
- * top: '0px'
- * },
- * to: {
- * left : e.client.x + 'px',
- * top : e.client.y + 'px'
- * }
- * }):
- * });
- * ```
- *
- * Once the animation is complete or cancelled then the union of both the before and after styles are applied to the
- * element. If `ngAnimate` is not present then the styles will be applied immediately.
- *
- */
-
-angular.module('ngAnimate', ['ng'])
-
- /**
- * @ngdoc provider
- * @name $animateProvider
- * @description
- *
- * The `$animateProvider` allows developers to register JavaScript animation event handlers directly inside of a module.
- * When an animation is triggered, the $animate service will query the $animate service to find any animations that match
- * the provided name value.
- *
- * Requires the {@link ngAnimate `ngAnimate`} module to be installed.
- *
- * Please visit the {@link ngAnimate `ngAnimate`} module overview page learn more about how to use animations in your application.
- *
- */
- .directive('ngAnimateChildren', function() {
- var NG_ANIMATE_CHILDREN = '$$ngAnimateChildren';
- return function(scope, element, attrs) {
- var val = attrs.ngAnimateChildren;
- if (angular.isString(val) && val.length === 0) { //empty attribute
- element.data(NG_ANIMATE_CHILDREN, true);
- } else {
- scope.$watch(val, function(value) {
- element.data(NG_ANIMATE_CHILDREN, !!value);
- });
- }
- };
- })
-
- //this private service is only used within CSS-enabled animations
- //IE8 + IE9 do not support rAF natively, but that is fine since they
- //also don't support transitions and keyframes which means that the code
- //below will never be used by the two browsers.
- .factory('$$animateReflow', ['$$rAF', '$document', function($$rAF, $document) {
- var bod = $document[0].body;
- return function(fn) {
- //the returned function acts as the cancellation function
- return $$rAF(function() {
- //the line below will force the browser to perform a repaint
- //so that all the animated elements within the animation frame
- //will be properly updated and drawn on screen. This is
- //required to perform multi-class CSS based animations with
- //Firefox. DO NOT REMOVE THIS LINE.
- var a = bod.offsetWidth + 1;
- fn();
- });
- };
- }])
-
- .config(['$provide', '$animateProvider', function($provide, $animateProvider) {
- var noop = angular.noop;
- var forEach = angular.forEach;
- var selectors = $animateProvider.$$selectors;
- var isArray = angular.isArray;
- var isString = angular.isString;
- var isObject = angular.isObject;
-
- var ELEMENT_NODE = 1;
- var NG_ANIMATE_STATE = '$$ngAnimateState';
- var NG_ANIMATE_CHILDREN = '$$ngAnimateChildren';
- var NG_ANIMATE_CLASS_NAME = 'ng-animate';
- var rootAnimateState = {running: true};
-
- function extractElementNode(element) {
- for (var i = 0; i < element.length; i++) {
- var elm = element[i];
- if (elm.nodeType == ELEMENT_NODE) {
- return elm;
- }
- }
- }
-
- function prepareElement(element) {
- return element && angular.element(element);
- }
-
- function stripCommentsFromElement(element) {
- return angular.element(extractElementNode(element));
- }
-
- function isMatchingElement(elm1, elm2) {
- return extractElementNode(elm1) == extractElementNode(elm2);
- }
-
- $provide.decorator('$animate',
- ['$delegate', '$$q', '$injector', '$sniffer', '$rootElement', '$$asyncCallback', '$rootScope', '$document', '$templateRequest',
- function($delegate, $$q, $injector, $sniffer, $rootElement, $$asyncCallback, $rootScope, $document, $templateRequest) {
-
- $rootElement.data(NG_ANIMATE_STATE, rootAnimateState);
-
- // Wait until all directive and route-related templates are downloaded and
- // compiled. The $templateRequest.totalPendingRequests variable keeps track of
- // all of the remote templates being currently downloaded. If there are no
- // templates currently downloading then the watcher will still fire anyway.
- var deregisterWatch = $rootScope.$watch(
- function() { return $templateRequest.totalPendingRequests; },
- function(val, oldVal) {
- if (val !== 0) return;
- deregisterWatch();
-
- // Now that all templates have been downloaded, $animate will wait until
- // the post digest queue is empty before enabling animations. By having two
- // calls to $postDigest calls we can ensure that the flag is enabled at the
- // very end of the post digest queue. Since all of the animations in $animate
- // use $postDigest, it's important that the code below executes at the end.
- // This basically means that the page is fully downloaded and compiled before
- // any animations are triggered.
- $rootScope.$$postDigest(function() {
- $rootScope.$$postDigest(function() {
- rootAnimateState.running = false;
- });
- });
- }
- );
-
- var globalAnimationCounter = 0;
- var classNameFilter = $animateProvider.classNameFilter();
- var isAnimatableClassName = !classNameFilter
- ? function() { return true; }
- : function(className) {
- return classNameFilter.test(className);
- };
-
- function classBasedAnimationsBlocked(element, setter) {
- var data = element.data(NG_ANIMATE_STATE) || {};
- if (setter) {
- data.running = true;
- data.structural = true;
- element.data(NG_ANIMATE_STATE, data);
- }
- return data.disabled || (data.running && data.structural);
- }
-
- function runAnimationPostDigest(fn) {
- var cancelFn, defer = $$q.defer();
- defer.promise.$$cancelFn = function() {
- cancelFn && cancelFn();
- };
- $rootScope.$$postDigest(function() {
- cancelFn = fn(function() {
- defer.resolve();
- });
- });
- return defer.promise;
- }
-
- function parseAnimateOptions(options) {
- // some plugin code may still be passing in the callback
- // function as the last param for the $animate methods so
- // it's best to only allow string or array values for now
- if (isObject(options)) {
- if (options.tempClasses && isString(options.tempClasses)) {
- options.tempClasses = options.tempClasses.split(/\s+/);
- }
- return options;
- }
- }
-
- function resolveElementClasses(element, cache, runningAnimations) {
- runningAnimations = runningAnimations || {};
-
- var lookup = {};
- forEach(runningAnimations, function(data, selector) {
- forEach(selector.split(' '), function(s) {
- lookup[s]=data;
- });
- });
-
- var hasClasses = Object.create(null);
- forEach((element.attr('class') || '').split(/\s+/), function(className) {
- hasClasses[className] = true;
- });
-
- var toAdd = [], toRemove = [];
- forEach((cache && cache.classes) || [], function(status, className) {
- var hasClass = hasClasses[className];
- var matchingAnimation = lookup[className] || {};
-
- // When addClass and removeClass is called then $animate will check to
- // see if addClass and removeClass cancel each other out. When there are
- // more calls to removeClass than addClass then the count falls below 0
- // and then the removeClass animation will be allowed. Otherwise if the
- // count is above 0 then that means an addClass animation will commence.
- // Once an animation is allowed then the code will also check to see if
- // there exists any on-going animation that is already adding or remvoing
- // the matching CSS class.
- if (status === false) {
- //does it have the class or will it have the class
- if (hasClass || matchingAnimation.event == 'addClass') {
- toRemove.push(className);
- }
- } else if (status === true) {
- //is the class missing or will it be removed?
- if (!hasClass || matchingAnimation.event == 'removeClass') {
- toAdd.push(className);
- }
- }
- });
-
- return (toAdd.length + toRemove.length) > 0 && [toAdd.join(' '), toRemove.join(' ')];
- }
-
- function lookup(name) {
- if (name) {
- var matches = [],
- flagMap = {},
- classes = name.substr(1).split('.');
-
- //the empty string value is the default animation
- //operation which performs CSS transition and keyframe
- //animations sniffing. This is always included for each
- //element animation procedure if the browser supports
- //transitions and/or keyframe animations. The default
- //animation is added to the top of the list to prevent
- //any previous animations from affecting the element styling
- //prior to the element being animated.
- if ($sniffer.transitions || $sniffer.animations) {
- matches.push($injector.get(selectors['']));
- }
-
- for (var i=0; i < classes.length; i++) {
- var klass = classes[i],
- selectorFactoryName = selectors[klass];
- if (selectorFactoryName && !flagMap[klass]) {
- matches.push($injector.get(selectorFactoryName));
- flagMap[klass] = true;
- }
- }
- return matches;
- }
- }
-
- function animationRunner(element, animationEvent, className, options) {
- //transcluded directives may sometimes fire an animation using only comment nodes
- //best to catch this early on to prevent any animation operations from occurring
- var node = element[0];
- if (!node) {
- return;
- }
-
- if (options) {
- options.to = options.to || {};
- options.from = options.from || {};
- }
-
- var classNameAdd;
- var classNameRemove;
- if (isArray(className)) {
- classNameAdd = className[0];
- classNameRemove = className[1];
- if (!classNameAdd) {
- className = classNameRemove;
- animationEvent = 'removeClass';
- } else if (!classNameRemove) {
- className = classNameAdd;
- animationEvent = 'addClass';
- } else {
- className = classNameAdd + ' ' + classNameRemove;
- }
- }
-
- var isSetClassOperation = animationEvent == 'setClass';
- var isClassBased = isSetClassOperation
- || animationEvent == 'addClass'
- || animationEvent == 'removeClass'
- || animationEvent == 'animate';
-
- var currentClassName = element.attr('class');
- var classes = currentClassName + ' ' + className;
- if (!isAnimatableClassName(classes)) {
- return;
- }
-
- var beforeComplete = noop,
- beforeCancel = [],
- before = [],
- afterComplete = noop,
- afterCancel = [],
- after = [];
-
- var animationLookup = (' ' + classes).replace(/\s+/g,'.');
- forEach(lookup(animationLookup), function(animationFactory) {
- var created = registerAnimation(animationFactory, animationEvent);
- if (!created && isSetClassOperation) {
- registerAnimation(animationFactory, 'addClass');
- registerAnimation(animationFactory, 'removeClass');
- }
- });
-
- function registerAnimation(animationFactory, event) {
- var afterFn = animationFactory[event];
- var beforeFn = animationFactory['before' + event.charAt(0).toUpperCase() + event.substr(1)];
- if (afterFn || beforeFn) {
- if (event == 'leave') {
- beforeFn = afterFn;
- //when set as null then animation knows to skip this phase
- afterFn = null;
- }
- after.push({
- event: event, fn: afterFn
- });
- before.push({
- event: event, fn: beforeFn
- });
- return true;
- }
- }
-
- function run(fns, cancellations, allCompleteFn) {
- var animations = [];
- forEach(fns, function(animation) {
- animation.fn && animations.push(animation);
- });
-
- var count = 0;
- function afterAnimationComplete(index) {
- if (cancellations) {
- (cancellations[index] || noop)();
- if (++count < animations.length) return;
- cancellations = null;
- }
- allCompleteFn();
- }
-
- //The code below adds directly to the array in order to work with
- //both sync and async animations. Sync animations are when the done()
- //operation is called right away. DO NOT REFACTOR!
- forEach(animations, function(animation, index) {
- var progress = function() {
- afterAnimationComplete(index);
- };
- switch (animation.event) {
- case 'setClass':
- cancellations.push(animation.fn(element, classNameAdd, classNameRemove, progress, options));
- break;
- case 'animate':
- cancellations.push(animation.fn(element, className, options.from, options.to, progress));
- break;
- case 'addClass':
- cancellations.push(animation.fn(element, classNameAdd || className, progress, options));
- break;
- case 'removeClass':
- cancellations.push(animation.fn(element, classNameRemove || className, progress, options));
- break;
- default:
- cancellations.push(animation.fn(element, progress, options));
- break;
- }
- });
-
- if (cancellations && cancellations.length === 0) {
- allCompleteFn();
- }
- }
-
- return {
- node: node,
- event: animationEvent,
- className: className,
- isClassBased: isClassBased,
- isSetClassOperation: isSetClassOperation,
- applyStyles: function() {
- if (options) {
- element.css(angular.extend(options.from || {}, options.to || {}));
- }
- },
- before: function(allCompleteFn) {
- beforeComplete = allCompleteFn;
- run(before, beforeCancel, function() {
- beforeComplete = noop;
- allCompleteFn();
- });
- },
- after: function(allCompleteFn) {
- afterComplete = allCompleteFn;
- run(after, afterCancel, function() {
- afterComplete = noop;
- allCompleteFn();
- });
- },
- cancel: function() {
- if (beforeCancel) {
- forEach(beforeCancel, function(cancelFn) {
- (cancelFn || noop)(true);
- });
- beforeComplete(true);
- }
- if (afterCancel) {
- forEach(afterCancel, function(cancelFn) {
- (cancelFn || noop)(true);
- });
- afterComplete(true);
- }
- }
- };
- }
-
- /**
- * @ngdoc service
- * @name $animate
- * @kind object
- *
- * @description
- * The `$animate` service provides animation detection support while performing DOM operations (enter, leave and move) as well as during addClass and removeClass operations.
- * When any of these operations are run, the $animate service
- * will examine any JavaScript-defined animations (which are defined by using the $animateProvider provider object)
- * as well as any CSS-defined animations against the CSS classes present on the element once the DOM operation is run.
- *
- * The `$animate` service is used behind the scenes with pre-existing directives and animation with these directives
- * will work out of the box without any extra configuration.
- *
- * Requires the {@link ngAnimate `ngAnimate`} module to be installed.
- *
- * Please visit the {@link ngAnimate `ngAnimate`} module overview page learn more about how to use animations in your application.
- * ## Callback Promises
- * With AngularJS 1.3, each of the animation methods, on the `$animate` service, return a promise when called. The
- * promise itself is then resolved once the animation has completed itself, has been cancelled or has been
- * skipped due to animations being disabled. (Note that even if the animation is cancelled it will still
- * call the resolve function of the animation.)
- *
- * ```js
- * $animate.enter(element, container).then(function() {
- * //...this is called once the animation is complete...
- * });
- * ```
- *
- * Also note that, due to the nature of the callback promise, if any Angular-specific code (like changing the scope,
- * location of the page, etc...) is executed within the callback promise then be sure to wrap the code using
- * `$scope.$apply(...)`;
- *
- * ```js
- * $animate.leave(element).then(function() {
- * $scope.$apply(function() {
- * $location.path('/new-page');
- * });
- * });
- * ```
- *
- * An animation can also be cancelled by calling the `$animate.cancel(promise)` method with the provided
- * promise that was returned when the animation was started.
- *
- * ```js
- * var promise = $animate.addClass(element, 'super-long-animation').then(function() {
- * //this will still be called even if cancelled
- * });
- *
- * element.on('click', function() {
- * //tooo lazy to wait for the animation to end
- * $animate.cancel(promise);
- * });
- * ```
- *
- * (Keep in mind that the promise cancellation is unique to `$animate` since promises in
- * general cannot be cancelled.)
- *
- */
- return {
- /**
- * @ngdoc method
- * @name $animate#animate
- * @kind function
- *
- * @description
- * Performs an inline animation on the element which applies the provided `to` and `from` CSS styles to the element.
- * If any detected CSS transition, keyframe or JavaScript matches the provided `className` value then the animation
- * will take on the provided styles. For example, if a transition animation is set for the given className then the
- * provided `from` and `to` styles will be applied alongside the given transition. If a JavaScript animation is
- * detected then the provided styles will be given in as function paramters.
- *
- * ```js
- * ngModule.animation('.my-inline-animation', function() {
- * return {
- * animate : function(element, className, from, to, done) {
- * //styles
- * }
- * }
- * });
- * ```
- *
- * Below is a breakdown of each step that occurs during the `animate` animation:
- *
- * | Animation Step | What the element class attribute looks like |
- * |-------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------|
- * | 1. $animate.animate(...) is called | class="my-animation" |
- * | 2. $animate waits for the next digest to start the animation | class="my-animation ng-animate" |
- * | 3. $animate runs the JavaScript-defined animations detected on the element | class="my-animation ng-animate" |
- * | 4. the className class value is added to the element | class="my-animation ng-animate className" |
- * | 5. $animate scans the element styles to get the CSS transition/animation duration and delay | class="my-animation ng-animate className" |
- * | 6. $animate blocks all CSS transitions on the element to ensure the .className class styling is applied right away| class="my-animation ng-animate className" |
- * | 7. $animate applies the provided collection of `from` CSS styles to the element | class="my-animation ng-animate className" |
- * | 8. $animate waits for a single animation frame (this performs a reflow) | class="my-animation ng-animate className" |
- * | 9. $animate removes the CSS transition block placed on the element | class="my-animation ng-animate className" |
- * | 10. the className-active class is added (this triggers the CSS transition/animation) | class="my-animation ng-animate className className-active" |
- * | 11. $animate applies the collection of `to` CSS styles to the element which are then handled by the transition | class="my-animation ng-animate className className-active" |
- * | 12. $animate waits for the animation to complete (via events and timeout) | class="my-animation ng-animate className className-active" |
- * | 13. The animation ends and all generated CSS classes are removed from the element | class="my-animation" |
- * | 14. The returned promise is resolved. | class="my-animation" |
- *
- * @param {DOMElement} element the element that will be the focus of the enter animation
- * @param {object} from a collection of CSS styles that will be applied to the element at the start of the animation
- * @param {object} to a collection of CSS styles that the element will animate towards
- * @param {string=} className an optional CSS class that will be added to the element for the duration of the animation (the default class is `ng-inline-animate`)
- * @param {object=} options an optional collection of options that will be picked up by the CSS transition/animation
- * @return {Promise} the animation callback promise
- */
- animate: function(element, from, to, className, options) {
- className = className || 'ng-inline-animate';
- options = parseAnimateOptions(options) || {};
- options.from = to ? from : null;
- options.to = to ? to : from;
-
- return runAnimationPostDigest(function(done) {
- return performAnimation('animate', className, stripCommentsFromElement(element), null, null, noop, options, done);
- });
- },
-
- /**
- * @ngdoc method
- * @name $animate#enter
- * @kind function
- *
- * @description
- * Appends the element to the parentElement element that resides in the document and then runs the enter animation. Once
- * the animation is started, the following CSS classes will be present on the element for the duration of the animation:
- *
- * Below is a breakdown of each step that occurs during enter animation:
- *
- * | Animation Step | What the element class attribute looks like |
- * |-------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------|
- * | 1. $animate.enter(...) is called | class="my-animation" |
- * | 2. element is inserted into the parentElement element or beside the afterElement element | class="my-animation" |
- * | 3. $animate waits for the next digest to start the animation | class="my-animation ng-animate" |
- * | 4. $animate runs the JavaScript-defined animations detected on the element | class="my-animation ng-animate" |
- * | 5. the .ng-enter class is added to the element | class="my-animation ng-animate ng-enter" |
- * | 6. $animate scans the element styles to get the CSS transition/animation duration and delay | class="my-animation ng-animate ng-enter" |
- * | 7. $animate blocks all CSS transitions on the element to ensure the .ng-enter class styling is applied right away | class="my-animation ng-animate ng-enter" |
- * | 8. $animate waits for a single animation frame (this performs a reflow) | class="my-animation ng-animate ng-enter" |
- * | 9. $animate removes the CSS transition block placed on the element | class="my-animation ng-animate ng-enter" |
- * | 10. the .ng-enter-active class is added (this triggers the CSS transition/animation) | class="my-animation ng-animate ng-enter ng-enter-active" |
- * | 11. $animate waits for the animation to complete (via events and timeout) | class="my-animation ng-animate ng-enter ng-enter-active" |
- * | 12. The animation ends and all generated CSS classes are removed from the element | class="my-animation" |
- * | 13. The returned promise is resolved. | class="my-animation" |
- *
- * @param {DOMElement} element the element that will be the focus of the enter animation
- * @param {DOMElement} parentElement the parent element of the element that will be the focus of the enter animation
- * @param {DOMElement} afterElement the sibling element (which is the previous element) of the element that will be the focus of the enter animation
- * @param {object=} options an optional collection of options that will be picked up by the CSS transition/animation
- * @return {Promise} the animation callback promise
- */
- enter: function(element, parentElement, afterElement, options) {
- options = parseAnimateOptions(options);
- element = angular.element(element);
- parentElement = prepareElement(parentElement);
- afterElement = prepareElement(afterElement);
-
- classBasedAnimationsBlocked(element, true);
- $delegate.enter(element, parentElement, afterElement);
- return runAnimationPostDigest(function(done) {
- return performAnimation('enter', 'ng-enter', stripCommentsFromElement(element), parentElement, afterElement, noop, options, done);
- });
- },
-
- /**
- * @ngdoc method
- * @name $animate#leave
- * @kind function
- *
- * @description
- * Runs the leave animation operation and, upon completion, removes the element from the DOM. Once
- * the animation is started, the following CSS classes will be added for the duration of the animation:
- *
- * Below is a breakdown of each step that occurs during leave animation:
- *
- * | Animation Step | What the element class attribute looks like |
- * |-------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------|
- * | 1. $animate.leave(...) is called | class="my-animation" |
- * | 2. $animate runs the JavaScript-defined animations detected on the element | class="my-animation ng-animate" |
- * | 3. $animate waits for the next digest to start the animation | class="my-animation ng-animate" |
- * | 4. the .ng-leave class is added to the element | class="my-animation ng-animate ng-leave" |
- * | 5. $animate scans the element styles to get the CSS transition/animation duration and delay | class="my-animation ng-animate ng-leave" |
- * | 6. $animate blocks all CSS transitions on the element to ensure the .ng-leave class styling is applied right away | class="my-animation ng-animate ng-leave" |
- * | 7. $animate waits for a single animation frame (this performs a reflow) | class="my-animation ng-animate ng-leave" |
- * | 8. $animate removes the CSS transition block placed on the element | class="my-animation ng-animate ng-leave" |
- * | 9. the .ng-leave-active class is added (this triggers the CSS transition/animation) | class="my-animation ng-animate ng-leave ng-leave-active" |
- * | 10. $animate waits for the animation to complete (via events and timeout) | class="my-animation ng-animate ng-leave ng-leave-active" |
- * | 11. The animation ends and all generated CSS classes are removed from the element | class="my-animation" |
- * | 12. The element is removed from the DOM | ... |
- * | 13. The returned promise is resolved. | ... |
- *
- * @param {DOMElement} element the element that will be the focus of the leave animation
- * @param {object=} options an optional collection of styles that will be picked up by the CSS transition/animation
- * @return {Promise} the animation callback promise
- */
- leave: function(element, options) {
- options = parseAnimateOptions(options);
- element = angular.element(element);
-
- cancelChildAnimations(element);
- classBasedAnimationsBlocked(element, true);
- return runAnimationPostDigest(function(done) {
- return performAnimation('leave', 'ng-leave', stripCommentsFromElement(element), null, null, function() {
- $delegate.leave(element);
- }, options, done);
- });
- },
-
- /**
- * @ngdoc method
- * @name $animate#move
- * @kind function
- *
- * @description
- * Fires the move DOM operation. Just before the animation starts, the animate service will either append it into the parentElement container or
- * add the element directly after the afterElement element if present. Then the move animation will be run. Once
- * the animation is started, the following CSS classes will be added for the duration of the animation:
- *
- * Below is a breakdown of each step that occurs during move animation:
- *
- * | Animation Step | What the element class attribute looks like |
- * |------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------|
- * | 1. $animate.move(...) is called | class="my-animation" |
- * | 2. element is moved into the parentElement element or beside the afterElement element | class="my-animation" |
- * | 3. $animate waits for the next digest to start the animation | class="my-animation ng-animate" |
- * | 4. $animate runs the JavaScript-defined animations detected on the element | class="my-animation ng-animate" |
- * | 5. the .ng-move class is added to the element | class="my-animation ng-animate ng-move" |
- * | 6. $animate scans the element styles to get the CSS transition/animation duration and delay | class="my-animation ng-animate ng-move" |
- * | 7. $animate blocks all CSS transitions on the element to ensure the .ng-move class styling is applied right away | class="my-animation ng-animate ng-move" |
- * | 8. $animate waits for a single animation frame (this performs a reflow) | class="my-animation ng-animate ng-move" |
- * | 9. $animate removes the CSS transition block placed on the element | class="my-animation ng-animate ng-move" |
- * | 10. the .ng-move-active class is added (this triggers the CSS transition/animation) | class="my-animation ng-animate ng-move ng-move-active" |
- * | 11. $animate waits for the animation to complete (via events and timeout) | class="my-animation ng-animate ng-move ng-move-active" |
- * | 12. The animation ends and all generated CSS classes are removed from the element | class="my-animation" |
- * | 13. The returned promise is resolved. | class="my-animation" |
- *
- * @param {DOMElement} element the element that will be the focus of the move animation
- * @param {DOMElement} parentElement the parentElement element of the element that will be the focus of the move animation
- * @param {DOMElement} afterElement the sibling element (which is the previous element) of the element that will be the focus of the move animation
- * @param {object=} options an optional collection of styles that will be picked up by the CSS transition/animation
- * @return {Promise} the animation callback promise
- */
- move: function(element, parentElement, afterElement, options) {
- options = parseAnimateOptions(options);
- element = angular.element(element);
- parentElement = prepareElement(parentElement);
- afterElement = prepareElement(afterElement);
-
- cancelChildAnimations(element);
- classBasedAnimationsBlocked(element, true);
- $delegate.move(element, parentElement, afterElement);
- return runAnimationPostDigest(function(done) {
- return performAnimation('move', 'ng-move', stripCommentsFromElement(element), parentElement, afterElement, noop, options, done);
- });
- },
-
- /**
- * @ngdoc method
- * @name $animate#addClass
- *
- * @description
- * Triggers a custom animation event based off the className variable and then attaches the className value to the element as a CSS class.
- * Unlike the other animation methods, the animate service will suffix the className value with {@type -add} in order to provide
- * the animate service the setup and active CSS classes in order to trigger the animation (this will be skipped if no CSS transitions
- * or keyframes are defined on the -add-active or base CSS class).
- *
- * Below is a breakdown of each step that occurs during addClass animation:
- *
- * | Animation Step | What the element class attribute looks like |
- * |----------------------------------------------------------------------------------------------------|------------------------------------------------------------------|
- * | 1. $animate.addClass(element, 'super') is called | class="my-animation" |
- * | 2. $animate runs the JavaScript-defined animations detected on the element | class="my-animation ng-animate" |
- * | 3. the .super-add class is added to the element | class="my-animation ng-animate super-add" |
- * | 4. $animate waits for a single animation frame (this performs a reflow) | class="my-animation ng-animate super-add" |
- * | 5. the .super and .super-add-active classes are added (this triggers the CSS transition/animation) | class="my-animation ng-animate super super-add super-add-active" |
- * | 6. $animate scans the element styles to get the CSS transition/animation duration and delay | class="my-animation ng-animate super super-add super-add-active" |
- * | 7. $animate waits for the animation to complete (via events and timeout) | class="my-animation ng-animate super super-add super-add-active" |
- * | 8. The animation ends and all generated CSS classes are removed from the element | class="my-animation super" |
- * | 9. The super class is kept on the element | class="my-animation super" |
- * | 10. The returned promise is resolved. | class="my-animation super" |
- *
- * @param {DOMElement} element the element that will be animated
- * @param {string} className the CSS class that will be added to the element and then animated
- * @param {object=} options an optional collection of styles that will be picked up by the CSS transition/animation
- * @return {Promise} the animation callback promise
- */
- addClass: function(element, className, options) {
- return this.setClass(element, className, [], options);
- },
-
- /**
- * @ngdoc method
- * @name $animate#removeClass
- *
- * @description
- * Triggers a custom animation event based off the className variable and then removes the CSS class provided by the className value
- * from the element. Unlike the other animation methods, the animate service will suffix the className value with {@type -remove} in
- * order to provide the animate service the setup and active CSS classes in order to trigger the animation (this will be skipped if
- * no CSS transitions or keyframes are defined on the -remove or base CSS classes).
- *
- * Below is a breakdown of each step that occurs during removeClass animation:
- *
- * | Animation Step | What the element class attribute looks like |
- * |------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------|
- * | 1. $animate.removeClass(element, 'super') is called | class="my-animation super" |
- * | 2. $animate runs the JavaScript-defined animations detected on the element | class="my-animation super ng-animate" |
- * | 3. the .super-remove class is added to the element | class="my-animation super ng-animate super-remove" |
- * | 4. $animate waits for a single animation frame (this performs a reflow) | class="my-animation super ng-animate super-remove" |
- * | 5. the .super-remove-active classes are added and .super is removed (this triggers the CSS transition/animation) | class="my-animation ng-animate super-remove super-remove-active" |
- * | 6. $animate scans the element styles to get the CSS transition/animation duration and delay | class="my-animation ng-animate super-remove super-remove-active" |
- * | 7. $animate waits for the animation to complete (via events and timeout) | class="my-animation ng-animate super-remove super-remove-active" |
- * | 8. The animation ends and all generated CSS classes are removed from the element | class="my-animation" |
- * | 9. The returned promise is resolved. | class="my-animation" |
- *
- *
- * @param {DOMElement} element the element that will be animated
- * @param {string} className the CSS class that will be animated and then removed from the element
- * @param {object=} options an optional collection of styles that will be picked up by the CSS transition/animation
- * @return {Promise} the animation callback promise
- */
- removeClass: function(element, className, options) {
- return this.setClass(element, [], className, options);
- },
-
- /**
- *
- * @ngdoc method
- * @name $animate#setClass
- *
- * @description Adds and/or removes the given CSS classes to and from the element.
- * Once complete, the done() callback will be fired (if provided).
- *
- * | Animation Step | What the element class attribute looks like |
- * |--------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------|
- * | 1. $animate.setClass(element, 'on', 'off') is called | class="my-animation off" |
- * | 2. $animate runs the JavaScript-defined animations detected on the element | class="my-animation ng-animate off" |
- * | 3. the .on-add and .off-remove classes are added to the element | class="my-animation ng-animate on-add off-remove off" |
- * | 4. $animate waits for a single animation frame (this performs a reflow) | class="my-animation ng-animate on-add off-remove off" |
- * | 5. the .on, .on-add-active and .off-remove-active classes are added and .off is removed (this triggers the CSS transition/animation) | class="my-animation ng-animate on on-add on-add-active off-remove off-remove-active" |
- * | 6. $animate scans the element styles to get the CSS transition/animation duration and delay | class="my-animation ng-animate on on-add on-add-active off-remove off-remove-active" |
- * | 7. $animate waits for the animation to complete (via events and timeout) | class="my-animation ng-animate on on-add on-add-active off-remove off-remove-active" |
- * | 8. The animation ends and all generated CSS classes are removed from the element | class="my-animation on" |
- * | 9. The returned promise is resolved. | class="my-animation on" |
- *
- * @param {DOMElement} element the element which will have its CSS classes changed
- * removed from it
- * @param {string} add the CSS classes which will be added to the element
- * @param {string} remove the CSS class which will be removed from the element
- * CSS classes have been set on the element
- * @param {object=} options an optional collection of styles that will be picked up by the CSS transition/animation
- * @return {Promise} the animation callback promise
- */
- setClass: function(element, add, remove, options) {
- options = parseAnimateOptions(options);
-
- var STORAGE_KEY = '$$animateClasses';
- element = angular.element(element);
- element = stripCommentsFromElement(element);
-
- if (classBasedAnimationsBlocked(element)) {
- return $delegate.$$setClassImmediately(element, add, remove, options);
- }
-
- // we're using a combined array for both the add and remove
- // operations since the ORDER OF addClass and removeClass matters
- var classes, cache = element.data(STORAGE_KEY);
- var hasCache = !!cache;
- if (!cache) {
- cache = {};
- cache.classes = {};
- }
- classes = cache.classes;
-
- add = isArray(add) ? add : add.split(' ');
- forEach(add, function(c) {
- if (c && c.length) {
- classes[c] = true;
- }
- });
-
- remove = isArray(remove) ? remove : remove.split(' ');
- forEach(remove, function(c) {
- if (c && c.length) {
- classes[c] = false;
- }
- });
-
- if (hasCache) {
- if (options && cache.options) {
- cache.options = angular.extend(cache.options || {}, options);
- }
-
- //the digest cycle will combine all the animations into one function
- return cache.promise;
- } else {
- element.data(STORAGE_KEY, cache = {
- classes: classes,
- options: options
- });
- }
-
- return cache.promise = runAnimationPostDigest(function(done) {
- var parentElement = element.parent();
- var elementNode = extractElementNode(element);
- var parentNode = elementNode.parentNode;
- // TODO(matsko): move this code into the animationsDisabled() function once #8092 is fixed
- if (!parentNode || parentNode['$$NG_REMOVED'] || elementNode['$$NG_REMOVED']) {
- done();
- return;
- }
-
- var cache = element.data(STORAGE_KEY);
- element.removeData(STORAGE_KEY);
-
- var state = element.data(NG_ANIMATE_STATE) || {};
- var classes = resolveElementClasses(element, cache, state.active);
- return !classes
- ? done()
- : performAnimation('setClass', classes, element, parentElement, null, function() {
- if (classes[0]) $delegate.$$addClassImmediately(element, classes[0]);
- if (classes[1]) $delegate.$$removeClassImmediately(element, classes[1]);
- }, cache.options, done);
- });
- },
-
- /**
- * @ngdoc method
- * @name $animate#cancel
- * @kind function
- *
- * @param {Promise} animationPromise The animation promise that is returned when an animation is started.
- *
- * @description
- * Cancels the provided animation.
- */
- cancel: function(promise) {
- promise.$$cancelFn();
- },
-
- /**
- * @ngdoc method
- * @name $animate#enabled
- * @kind function
- *
- * @param {boolean=} value If provided then set the animation on or off.
- * @param {DOMElement=} element If provided then the element will be used to represent the enable/disable operation
- * @return {boolean} Current animation state.
- *
- * @description
- * Globally enables/disables animations.
- *
- */
- enabled: function(value, element) {
- switch (arguments.length) {
- case 2:
- if (value) {
- cleanup(element);
- } else {
- var data = element.data(NG_ANIMATE_STATE) || {};
- data.disabled = true;
- element.data(NG_ANIMATE_STATE, data);
- }
- break;
-
- case 1:
- rootAnimateState.disabled = !value;
- break;
-
- default:
- value = !rootAnimateState.disabled;
- break;
- }
- return !!value;
- }
- };
-
- /*
- all animations call this shared animation triggering function internally.
- The animationEvent variable refers to the JavaScript animation event that will be triggered
- and the className value is the name of the animation that will be applied within the
- CSS code. Element, parentElement and afterElement are provided DOM elements for the animation
- and the onComplete callback will be fired once the animation is fully complete.
- */
- function performAnimation(animationEvent, className, element, parentElement, afterElement, domOperation, options, doneCallback) {
- var noopCancel = noop;
- var runner = animationRunner(element, animationEvent, className, options);
- if (!runner) {
- fireDOMOperation();
- fireBeforeCallbackAsync();
- fireAfterCallbackAsync();
- closeAnimation();
- return noopCancel;
- }
-
- animationEvent = runner.event;
- className = runner.className;
- var elementEvents = angular.element._data(runner.node);
- elementEvents = elementEvents && elementEvents.events;
-
- if (!parentElement) {
- parentElement = afterElement ? afterElement.parent() : element.parent();
- }
-
- //skip the animation if animations are disabled, a parent is already being animated,
- //the element is not currently attached to the document body or then completely close
- //the animation if any matching animations are not found at all.
- //NOTE: IE8 + IE9 should close properly (run closeAnimation()) in case an animation was found.
- if (animationsDisabled(element, parentElement)) {
- fireDOMOperation();
- fireBeforeCallbackAsync();
- fireAfterCallbackAsync();
- closeAnimation();
- return noopCancel;
- }
-
- var ngAnimateState = element.data(NG_ANIMATE_STATE) || {};
- var runningAnimations = ngAnimateState.active || {};
- var totalActiveAnimations = ngAnimateState.totalActive || 0;
- var lastAnimation = ngAnimateState.last;
- var skipAnimation = false;
-
- if (totalActiveAnimations > 0) {
- var animationsToCancel = [];
- if (!runner.isClassBased) {
- if (animationEvent == 'leave' && runningAnimations['ng-leave']) {
- skipAnimation = true;
- } else {
- //cancel all animations when a structural animation takes place
- for (var klass in runningAnimations) {
- animationsToCancel.push(runningAnimations[klass]);
- }
- ngAnimateState = {};
- cleanup(element, true);
- }
- } else if (lastAnimation.event == 'setClass') {
- animationsToCancel.push(lastAnimation);
- cleanup(element, className);
- }
- else if (runningAnimations[className]) {
- var current = runningAnimations[className];
- if (current.event == animationEvent) {
- skipAnimation = true;
- } else {
- animationsToCancel.push(current);
- cleanup(element, className);
- }
- }
-
- if (animationsToCancel.length > 0) {
- forEach(animationsToCancel, function(operation) {
- operation.cancel();
- });
- }
- }
-
- if (runner.isClassBased
- && !runner.isSetClassOperation
- && animationEvent != 'animate'
- && !skipAnimation) {
- skipAnimation = (animationEvent == 'addClass') == element.hasClass(className); //opposite of XOR
- }
-
- if (skipAnimation) {
- fireDOMOperation();
- fireBeforeCallbackAsync();
- fireAfterCallbackAsync();
- fireDoneCallbackAsync();
- return noopCancel;
- }
-
- runningAnimations = ngAnimateState.active || {};
- totalActiveAnimations = ngAnimateState.totalActive || 0;
-
- if (animationEvent == 'leave') {
- //there's no need to ever remove the listener since the element
- //will be removed (destroyed) after the leave animation ends or
- //is cancelled midway
- element.one('$destroy', function(e) {
- var element = angular.element(this);
- var state = element.data(NG_ANIMATE_STATE);
- if (state) {
- var activeLeaveAnimation = state.active['ng-leave'];
- if (activeLeaveAnimation) {
- activeLeaveAnimation.cancel();
- cleanup(element, 'ng-leave');
- }
- }
- });
- }
-
- //the ng-animate class does nothing, but it's here to allow for
- //parent animations to find and cancel child animations when needed
- element.addClass(NG_ANIMATE_CLASS_NAME);
- if (options && options.tempClasses) {
- forEach(options.tempClasses, function(className) {
- element.addClass(className);
- });
- }
-
- var localAnimationCount = globalAnimationCounter++;
- totalActiveAnimations++;
- runningAnimations[className] = runner;
-
- element.data(NG_ANIMATE_STATE, {
- last: runner,
- active: runningAnimations,
- index: localAnimationCount,
- totalActive: totalActiveAnimations
- });
-
- //first we run the before animations and when all of those are complete
- //then we perform the DOM operation and run the next set of animations
- fireBeforeCallbackAsync();
- runner.before(function(cancelled) {
- var data = element.data(NG_ANIMATE_STATE);
- cancelled = cancelled ||
- !data || !data.active[className] ||
- (runner.isClassBased && data.active[className].event != animationEvent);
-
- fireDOMOperation();
- if (cancelled === true) {
- closeAnimation();
- } else {
- fireAfterCallbackAsync();
- runner.after(closeAnimation);
- }
- });
-
- return runner.cancel;
-
- function fireDOMCallback(animationPhase) {
- var eventName = '$animate:' + animationPhase;
- if (elementEvents && elementEvents[eventName] && elementEvents[eventName].length > 0) {
- $$asyncCallback(function() {
- element.triggerHandler(eventName, {
- event: animationEvent,
- className: className
- });
- });
- }
- }
-
- function fireBeforeCallbackAsync() {
- fireDOMCallback('before');
- }
-
- function fireAfterCallbackAsync() {
- fireDOMCallback('after');
- }
-
- function fireDoneCallbackAsync() {
- fireDOMCallback('close');
- doneCallback();
- }
-
- //it is less complicated to use a flag than managing and canceling
- //timeouts containing multiple callbacks.
- function fireDOMOperation() {
- if (!fireDOMOperation.hasBeenRun) {
- fireDOMOperation.hasBeenRun = true;
- domOperation();
- }
- }
-
- function closeAnimation() {
- if (!closeAnimation.hasBeenRun) {
- if (runner) { //the runner doesn't exist if it fails to instantiate
- runner.applyStyles();
- }
-
- closeAnimation.hasBeenRun = true;
- if (options && options.tempClasses) {
- forEach(options.tempClasses, function(className) {
- element.removeClass(className);
- });
- }
-
- var data = element.data(NG_ANIMATE_STATE);
- if (data) {
-
- /* only structural animations wait for reflow before removing an
- animation, but class-based animations don't. An example of this
- failing would be when a parent HTML tag has a ng-class attribute
- causing ALL directives below to skip animations during the digest */
- if (runner && runner.isClassBased) {
- cleanup(element, className);
- } else {
- $$asyncCallback(function() {
- var data = element.data(NG_ANIMATE_STATE) || {};
- if (localAnimationCount == data.index) {
- cleanup(element, className, animationEvent);
- }
- });
- element.data(NG_ANIMATE_STATE, data);
- }
- }
- fireDoneCallbackAsync();
- }
- }
- }
-
- function cancelChildAnimations(element) {
- var node = extractElementNode(element);
- if (node) {
- var nodes = angular.isFunction(node.getElementsByClassName) ?
- node.getElementsByClassName(NG_ANIMATE_CLASS_NAME) :
- node.querySelectorAll('.' + NG_ANIMATE_CLASS_NAME);
- forEach(nodes, function(element) {
- element = angular.element(element);
- var data = element.data(NG_ANIMATE_STATE);
- if (data && data.active) {
- forEach(data.active, function(runner) {
- runner.cancel();
- });
- }
- });
- }
- }
-
- function cleanup(element, className) {
- if (isMatchingElement(element, $rootElement)) {
- if (!rootAnimateState.disabled) {
- rootAnimateState.running = false;
- rootAnimateState.structural = false;
- }
- } else if (className) {
- var data = element.data(NG_ANIMATE_STATE) || {};
-
- var removeAnimations = className === true;
- if (!removeAnimations && data.active && data.active[className]) {
- data.totalActive--;
- delete data.active[className];
- }
-
- if (removeAnimations || !data.totalActive) {
- element.removeClass(NG_ANIMATE_CLASS_NAME);
- element.removeData(NG_ANIMATE_STATE);
- }
- }
- }
-
- function animationsDisabled(element, parentElement) {
- if (rootAnimateState.disabled) {
- return true;
- }
-
- if (isMatchingElement(element, $rootElement)) {
- return rootAnimateState.running;
- }
-
- var allowChildAnimations, parentRunningAnimation, hasParent;
- do {
- //the element did not reach the root element which means that it
- //is not apart of the DOM. Therefore there is no reason to do
- //any animations on it
- if (parentElement.length === 0) break;
-
- var isRoot = isMatchingElement(parentElement, $rootElement);
- var state = isRoot ? rootAnimateState : (parentElement.data(NG_ANIMATE_STATE) || {});
- if (state.disabled) {
- return true;
- }
-
- //no matter what, for an animation to work it must reach the root element
- //this implies that the element is attached to the DOM when the animation is run
- if (isRoot) {
- hasParent = true;
- }
-
- //once a flag is found that is strictly false then everything before
- //it will be discarded and all child animations will be restricted
- if (allowChildAnimations !== false) {
- var animateChildrenFlag = parentElement.data(NG_ANIMATE_CHILDREN);
- if (angular.isDefined(animateChildrenFlag)) {
- allowChildAnimations = animateChildrenFlag;
- }
- }
-
- parentRunningAnimation = parentRunningAnimation ||
- state.running ||
- (state.last && !state.last.isClassBased);
- }
- while (parentElement = parentElement.parent());
-
- return !hasParent || (!allowChildAnimations && parentRunningAnimation);
- }
- }]);
-
- $animateProvider.register('', ['$window', '$sniffer', '$timeout', '$$animateReflow',
- function($window, $sniffer, $timeout, $$animateReflow) {
- // Detect proper transitionend/animationend event names.
- var CSS_PREFIX = '', TRANSITION_PROP, TRANSITIONEND_EVENT, ANIMATION_PROP, ANIMATIONEND_EVENT;
-
- // If unprefixed events are not supported but webkit-prefixed are, use the latter.
- // Otherwise, just use W3C names, browsers not supporting them at all will just ignore them.
- // Note: Chrome implements `window.onwebkitanimationend` and doesn't implement `window.onanimationend`
- // but at the same time dispatches the `animationend` event and not `webkitAnimationEnd`.
- // Register both events in case `window.onanimationend` is not supported because of that,
- // do the same for `transitionend` as Safari is likely to exhibit similar behavior.
- // Also, the only modern browser that uses vendor prefixes for transitions/keyframes is webkit
- // therefore there is no reason to test anymore for other vendor prefixes: http://caniuse.com/#search=transition
- if (window.ontransitionend === undefined && window.onwebkittransitionend !== undefined) {
- CSS_PREFIX = '-webkit-';
- TRANSITION_PROP = 'WebkitTransition';
- TRANSITIONEND_EVENT = 'webkitTransitionEnd transitionend';
- } else {
- TRANSITION_PROP = 'transition';
- TRANSITIONEND_EVENT = 'transitionend';
- }
-
- if (window.onanimationend === undefined && window.onwebkitanimationend !== undefined) {
- CSS_PREFIX = '-webkit-';
- ANIMATION_PROP = 'WebkitAnimation';
- ANIMATIONEND_EVENT = 'webkitAnimationEnd animationend';
- } else {
- ANIMATION_PROP = 'animation';
- ANIMATIONEND_EVENT = 'animationend';
- }
-
- var DURATION_KEY = 'Duration';
- var PROPERTY_KEY = 'Property';
- var DELAY_KEY = 'Delay';
- var ANIMATION_ITERATION_COUNT_KEY = 'IterationCount';
- var ANIMATION_PLAYSTATE_KEY = 'PlayState';
- var NG_ANIMATE_PARENT_KEY = '$$ngAnimateKey';
- var NG_ANIMATE_CSS_DATA_KEY = '$$ngAnimateCSS3Data';
- var ELAPSED_TIME_MAX_DECIMAL_PLACES = 3;
- var CLOSING_TIME_BUFFER = 1.5;
- var ONE_SECOND = 1000;
-
- var lookupCache = {};
- var parentCounter = 0;
- var animationReflowQueue = [];
- var cancelAnimationReflow;
- function clearCacheAfterReflow() {
- if (!cancelAnimationReflow) {
- cancelAnimationReflow = $$animateReflow(function() {
- animationReflowQueue = [];
- cancelAnimationReflow = null;
- lookupCache = {};
- });
- }
- }
-
- function afterReflow(element, callback) {
- if (cancelAnimationReflow) {
- cancelAnimationReflow();
- }
- animationReflowQueue.push(callback);
- cancelAnimationReflow = $$animateReflow(function() {
- forEach(animationReflowQueue, function(fn) {
- fn();
- });
-
- animationReflowQueue = [];
- cancelAnimationReflow = null;
- lookupCache = {};
- });
- }
-
- var closingTimer = null;
- var closingTimestamp = 0;
- var animationElementQueue = [];
- function animationCloseHandler(element, totalTime) {
- var node = extractElementNode(element);
- element = angular.element(node);
-
- //this item will be garbage collected by the closing
- //animation timeout
- animationElementQueue.push(element);
-
- //but it may not need to cancel out the existing timeout
- //if the timestamp is less than the previous one
- var futureTimestamp = Date.now() + totalTime;
- if (futureTimestamp <= closingTimestamp) {
- return;
- }
-
- $timeout.cancel(closingTimer);
-
- closingTimestamp = futureTimestamp;
- closingTimer = $timeout(function() {
- closeAllAnimations(animationElementQueue);
- animationElementQueue = [];
- }, totalTime, false);
- }
-
- function closeAllAnimations(elements) {
- forEach(elements, function(element) {
- var elementData = element.data(NG_ANIMATE_CSS_DATA_KEY);
- if (elementData) {
- forEach(elementData.closeAnimationFns, function(fn) {
- fn();
- });
- }
- });
- }
-
- function getElementAnimationDetails(element, cacheKey) {
- var data = cacheKey ? lookupCache[cacheKey] : null;
- if (!data) {
- var transitionDuration = 0;
- var transitionDelay = 0;
- var animationDuration = 0;
- var animationDelay = 0;
-
- //we want all the styles defined before and after
- forEach(element, function(element) {
- if (element.nodeType == ELEMENT_NODE) {
- var elementStyles = $window.getComputedStyle(element) || {};
-
- var transitionDurationStyle = elementStyles[TRANSITION_PROP + DURATION_KEY];
- transitionDuration = Math.max(parseMaxTime(transitionDurationStyle), transitionDuration);
-
- var transitionDelayStyle = elementStyles[TRANSITION_PROP + DELAY_KEY];
- transitionDelay = Math.max(parseMaxTime(transitionDelayStyle), transitionDelay);
-
- var animationDelayStyle = elementStyles[ANIMATION_PROP + DELAY_KEY];
- animationDelay = Math.max(parseMaxTime(elementStyles[ANIMATION_PROP + DELAY_KEY]), animationDelay);
-
- var aDuration = parseMaxTime(elementStyles[ANIMATION_PROP + DURATION_KEY]);
-
- if (aDuration > 0) {
- aDuration *= parseInt(elementStyles[ANIMATION_PROP + ANIMATION_ITERATION_COUNT_KEY], 10) || 1;
- }
- animationDuration = Math.max(aDuration, animationDuration);
- }
- });
- data = {
- total: 0,
- transitionDelay: transitionDelay,
- transitionDuration: transitionDuration,
- animationDelay: animationDelay,
- animationDuration: animationDuration
- };
- if (cacheKey) {
- lookupCache[cacheKey] = data;
- }
- }
- return data;
- }
-
- function parseMaxTime(str) {
- var maxValue = 0;
- var values = isString(str) ?
- str.split(/\s*,\s*/) :
- [];
- forEach(values, function(value) {
- maxValue = Math.max(parseFloat(value) || 0, maxValue);
- });
- return maxValue;
- }
-
- function getCacheKey(element) {
- var parentElement = element.parent();
- var parentID = parentElement.data(NG_ANIMATE_PARENT_KEY);
- if (!parentID) {
- parentElement.data(NG_ANIMATE_PARENT_KEY, ++parentCounter);
- parentID = parentCounter;
- }
- return parentID + '-' + extractElementNode(element).getAttribute('class');
- }
-
- function animateSetup(animationEvent, element, className, styles) {
- var structural = ['ng-enter','ng-leave','ng-move'].indexOf(className) >= 0;
-
- var cacheKey = getCacheKey(element);
- var eventCacheKey = cacheKey + ' ' + className;
- var itemIndex = lookupCache[eventCacheKey] ? ++lookupCache[eventCacheKey].total : 0;
-
- var stagger = {};
- if (itemIndex > 0) {
- var staggerClassName = className + '-stagger';
- var staggerCacheKey = cacheKey + ' ' + staggerClassName;
- var applyClasses = !lookupCache[staggerCacheKey];
-
- applyClasses && element.addClass(staggerClassName);
-
- stagger = getElementAnimationDetails(element, staggerCacheKey);
-
- applyClasses && element.removeClass(staggerClassName);
- }
-
- element.addClass(className);
-
- var formerData = element.data(NG_ANIMATE_CSS_DATA_KEY) || {};
- var timings = getElementAnimationDetails(element, eventCacheKey);
- var transitionDuration = timings.transitionDuration;
- var animationDuration = timings.animationDuration;
-
- if (structural && transitionDuration === 0 && animationDuration === 0) {
- element.removeClass(className);
- return false;
- }
-
- var blockTransition = styles || (structural && transitionDuration > 0);
- var blockAnimation = animationDuration > 0 &&
- stagger.animationDelay > 0 &&
- stagger.animationDuration === 0;
-
- var closeAnimationFns = formerData.closeAnimationFns || [];
- element.data(NG_ANIMATE_CSS_DATA_KEY, {
- stagger: stagger,
- cacheKey: eventCacheKey,
- running: formerData.running || 0,
- itemIndex: itemIndex,
- blockTransition: blockTransition,
- closeAnimationFns: closeAnimationFns
- });
-
- var node = extractElementNode(element);
-
- if (blockTransition) {
- blockTransitions(node, true);
- if (styles) {
- element.css(styles);
- }
- }
-
- if (blockAnimation) {
- blockAnimations(node, true);
- }
-
- return true;
- }
-
- function animateRun(animationEvent, element, className, activeAnimationComplete, styles) {
- var node = extractElementNode(element);
- var elementData = element.data(NG_ANIMATE_CSS_DATA_KEY);
- if (node.getAttribute('class').indexOf(className) == -1 || !elementData) {
- activeAnimationComplete();
- return;
- }
-
- var activeClassName = '';
- var pendingClassName = '';
- forEach(className.split(' '), function(klass, i) {
- var prefix = (i > 0 ? ' ' : '') + klass;
- activeClassName += prefix + '-active';
- pendingClassName += prefix + '-pending';
- });
-
- var style = '';
- var appliedStyles = [];
- var itemIndex = elementData.itemIndex;
- var stagger = elementData.stagger;
- var staggerTime = 0;
- if (itemIndex > 0) {
- var transitionStaggerDelay = 0;
- if (stagger.transitionDelay > 0 && stagger.transitionDuration === 0) {
- transitionStaggerDelay = stagger.transitionDelay * itemIndex;
- }
-
- var animationStaggerDelay = 0;
- if (stagger.animationDelay > 0 && stagger.animationDuration === 0) {
- animationStaggerDelay = stagger.animationDelay * itemIndex;
- appliedStyles.push(CSS_PREFIX + 'animation-play-state');
- }
-
- staggerTime = Math.round(Math.max(transitionStaggerDelay, animationStaggerDelay) * 100) / 100;
- }
-
- if (!staggerTime) {
- element.addClass(activeClassName);
- if (elementData.blockTransition) {
- blockTransitions(node, false);
- }
- }
-
- var eventCacheKey = elementData.cacheKey + ' ' + activeClassName;
- var timings = getElementAnimationDetails(element, eventCacheKey);
- var maxDuration = Math.max(timings.transitionDuration, timings.animationDuration);
- if (maxDuration === 0) {
- element.removeClass(activeClassName);
- animateClose(element, className);
- activeAnimationComplete();
- return;
- }
-
- if (!staggerTime && styles) {
- if (!timings.transitionDuration) {
- element.css('transition', timings.animationDuration + 's linear all');
- appliedStyles.push('transition');
- }
- element.css(styles);
- }
-
- var maxDelay = Math.max(timings.transitionDelay, timings.animationDelay);
- var maxDelayTime = maxDelay * ONE_SECOND;
-
- if (appliedStyles.length > 0) {
- //the element being animated may sometimes contain comment nodes in
- //the jqLite object, so we're safe to use a single variable to house
- //the styles since there is always only one element being animated
- var oldStyle = node.getAttribute('style') || '';
- if (oldStyle.charAt(oldStyle.length - 1) !== ';') {
- oldStyle += ';';
- }
- node.setAttribute('style', oldStyle + ' ' + style);
- }
-
- var startTime = Date.now();
- var css3AnimationEvents = ANIMATIONEND_EVENT + ' ' + TRANSITIONEND_EVENT;
- var animationTime = (maxDelay + maxDuration) * CLOSING_TIME_BUFFER;
- var totalTime = (staggerTime + animationTime) * ONE_SECOND;
-
- var staggerTimeout;
- if (staggerTime > 0) {
- element.addClass(pendingClassName);
- staggerTimeout = $timeout(function() {
- staggerTimeout = null;
-
- if (timings.transitionDuration > 0) {
- blockTransitions(node, false);
- }
- if (timings.animationDuration > 0) {
- blockAnimations(node, false);
- }
-
- element.addClass(activeClassName);
- element.removeClass(pendingClassName);
-
- if (styles) {
- if (timings.transitionDuration === 0) {
- element.css('transition', timings.animationDuration + 's linear all');
- }
- element.css(styles);
- appliedStyles.push('transition');
- }
- }, staggerTime * ONE_SECOND, false);
- }
-
- element.on(css3AnimationEvents, onAnimationProgress);
- elementData.closeAnimationFns.push(function() {
- onEnd();
- activeAnimationComplete();
- });
-
- elementData.running++;
- animationCloseHandler(element, totalTime);
- return onEnd;
-
- // This will automatically be called by $animate so
- // there is no need to attach this internally to the
- // timeout done method.
- function onEnd() {
- element.off(css3AnimationEvents, onAnimationProgress);
- element.removeClass(activeClassName);
- element.removeClass(pendingClassName);
- if (staggerTimeout) {
- $timeout.cancel(staggerTimeout);
- }
- animateClose(element, className);
- var node = extractElementNode(element);
- for (var i in appliedStyles) {
- node.style.removeProperty(appliedStyles[i]);
- }
- }
-
- function onAnimationProgress(event) {
- event.stopPropagation();
- var ev = event.originalEvent || event;
- var timeStamp = ev.$manualTimeStamp || ev.timeStamp || Date.now();
-
- /* Firefox (or possibly just Gecko) likes to not round values up
- * when a ms measurement is used for the animation */
- var elapsedTime = parseFloat(ev.elapsedTime.toFixed(ELAPSED_TIME_MAX_DECIMAL_PLACES));
-
- /* $manualTimeStamp is a mocked timeStamp value which is set
- * within browserTrigger(). This is only here so that tests can
- * mock animations properly. Real events fallback to event.timeStamp,
- * or, if they don't, then a timeStamp is automatically created for them.
- * We're checking to see if the timeStamp surpasses the expected delay,
- * but we're using elapsedTime instead of the timeStamp on the 2nd
- * pre-condition since animations sometimes close off early */
- if (Math.max(timeStamp - startTime, 0) >= maxDelayTime && elapsedTime >= maxDuration) {
- activeAnimationComplete();
- }
- }
- }
-
- function blockTransitions(node, bool) {
- node.style[TRANSITION_PROP + PROPERTY_KEY] = bool ? 'none' : '';
- }
-
- function blockAnimations(node, bool) {
- node.style[ANIMATION_PROP + ANIMATION_PLAYSTATE_KEY] = bool ? 'paused' : '';
- }
-
- function animateBefore(animationEvent, element, className, styles) {
- if (animateSetup(animationEvent, element, className, styles)) {
- return function(cancelled) {
- cancelled && animateClose(element, className);
- };
- }
- }
-
- function animateAfter(animationEvent, element, className, afterAnimationComplete, styles) {
- if (element.data(NG_ANIMATE_CSS_DATA_KEY)) {
- return animateRun(animationEvent, element, className, afterAnimationComplete, styles);
- } else {
- animateClose(element, className);
- afterAnimationComplete();
- }
- }
-
- function animate(animationEvent, element, className, animationComplete, options) {
- //If the animateSetup function doesn't bother returning a
- //cancellation function then it means that there is no animation
- //to perform at all
- var preReflowCancellation = animateBefore(animationEvent, element, className, options.from);
- if (!preReflowCancellation) {
- clearCacheAfterReflow();
- animationComplete();
- return;
- }
-
- //There are two cancellation functions: one is before the first
- //reflow animation and the second is during the active state
- //animation. The first function will take care of removing the
- //data from the element which will not make the 2nd animation
- //happen in the first place
- var cancel = preReflowCancellation;
- afterReflow(element, function() {
- //once the reflow is complete then we point cancel to
- //the new cancellation function which will remove all of the
- //animation properties from the active animation
- cancel = animateAfter(animationEvent, element, className, animationComplete, options.to);
- });
-
- return function(cancelled) {
- (cancel || noop)(cancelled);
- };
- }
-
- function animateClose(element, className) {
- element.removeClass(className);
- var data = element.data(NG_ANIMATE_CSS_DATA_KEY);
- if (data) {
- if (data.running) {
- data.running--;
- }
- if (!data.running || data.running === 0) {
- element.removeData(NG_ANIMATE_CSS_DATA_KEY);
- }
- }
- }
-
- return {
- animate: function(element, className, from, to, animationCompleted, options) {
- options = options || {};
- options.from = from;
- options.to = to;
- return animate('animate', element, className, animationCompleted, options);
- },
-
- enter: function(element, animationCompleted, options) {
- options = options || {};
- return animate('enter', element, 'ng-enter', animationCompleted, options);
- },
-
- leave: function(element, animationCompleted, options) {
- options = options || {};
- return animate('leave', element, 'ng-leave', animationCompleted, options);
- },
-
- move: function(element, animationCompleted, options) {
- options = options || {};
- return animate('move', element, 'ng-move', animationCompleted, options);
- },
-
- beforeSetClass: function(element, add, remove, animationCompleted, options) {
- options = options || {};
- var className = suffixClasses(remove, '-remove') + ' ' +
- suffixClasses(add, '-add');
- var cancellationMethod = animateBefore('setClass', element, className, options.from);
- if (cancellationMethod) {
- afterReflow(element, animationCompleted);
- return cancellationMethod;
- }
- clearCacheAfterReflow();
- animationCompleted();
- },
-
- beforeAddClass: function(element, className, animationCompleted, options) {
- options = options || {};
- var cancellationMethod = animateBefore('addClass', element, suffixClasses(className, '-add'), options.from);
- if (cancellationMethod) {
- afterReflow(element, animationCompleted);
- return cancellationMethod;
- }
- clearCacheAfterReflow();
- animationCompleted();
- },
-
- beforeRemoveClass: function(element, className, animationCompleted, options) {
- options = options || {};
- var cancellationMethod = animateBefore('removeClass', element, suffixClasses(className, '-remove'), options.from);
- if (cancellationMethod) {
- afterReflow(element, animationCompleted);
- return cancellationMethod;
- }
- clearCacheAfterReflow();
- animationCompleted();
- },
-
- setClass: function(element, add, remove, animationCompleted, options) {
- options = options || {};
- remove = suffixClasses(remove, '-remove');
- add = suffixClasses(add, '-add');
- var className = remove + ' ' + add;
- return animateAfter('setClass', element, className, animationCompleted, options.to);
- },
-
- addClass: function(element, className, animationCompleted, options) {
- options = options || {};
- return animateAfter('addClass', element, suffixClasses(className, '-add'), animationCompleted, options.to);
- },
-
- removeClass: function(element, className, animationCompleted, options) {
- options = options || {};
- return animateAfter('removeClass', element, suffixClasses(className, '-remove'), animationCompleted, options.to);
- }
- };
-
- function suffixClasses(classes, suffix) {
- var className = '';
- classes = isArray(classes) ? classes : classes.split(/\s+/);
- forEach(classes, function(klass, i) {
- if (klass && klass.length > 0) {
- className += (i > 0 ? ' ' : '') + klass + suffix;
- }
- });
- return className;
- }
- }]);
- }]);
-
-
-})(window, window.angular);
diff --git a/public/browse/lib/angular-animate/angular-animate.min.js b/public/browse/lib/angular-animate/angular-animate.min.js
deleted file mode 100644
index 63cbbbb02..000000000
--- a/public/browse/lib/angular-animate/angular-animate.min.js
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- AngularJS v1.3.5
- (c) 2010-2014 Google, Inc. http://angularjs.org
- License: MIT
-*/
-(function(M,f,S){'use strict';f.module("ngAnimate",["ng"]).directive("ngAnimateChildren",function(){return function(T,B,k){k=k.ngAnimateChildren;f.isString(k)&&0===k.length?B.data("$$ngAnimateChildren",!0):T.$watch(k,function(f){B.data("$$ngAnimateChildren",!!f)})}}).factory("$$animateReflow",["$$rAF","$document",function(f,B){return function(k){return f(function(){k()})}}]).config(["$provide","$animateProvider",function(T,B){function k(f){for(var g=0;g=A&&d>=x&&c()}var m=k(d);a=d.data("$$ngAnimateCSS3Data");if(-1!=m.getAttribute("class").indexOf(b)&&a){var q="",r="";g(b.split(" "),function(a,d){var b=(0",
- "license": "MIT",
- "bugs": {
- "url": "https://github.com/angular/angular.js/issues"
- },
- "homepage": "http://angularjs.org"
-}
diff --git a/public/browse/lib/angular-bindonce/.bower.json b/public/browse/lib/angular-bindonce/.bower.json
deleted file mode 100644
index 313c654cc..000000000
--- a/public/browse/lib/angular-bindonce/.bower.json
+++ /dev/null
@@ -1,37 +0,0 @@
-{
- "name": "angular-bindonce",
- "version": "0.3.3",
- "main": "bindonce.js",
- "description": "Zero watchers binding directives for AngularJS",
- "homepage": "https://github.com/Pasvaz/bindonce",
- "author": "Pasquale Vazzana ",
- "repository": {
- "type": "git",
- "url": "https://github.com/Pasvaz/bindonce.git"
- },
- "license": "MIT",
- "ignore": [
- "**/.*",
- "node_modules",
- "components"
- ],
- "dependencies": {},
- "keywords": [
- "angularjs",
- "angular",
- "directive",
- "binding",
- "watcher",
- "bindonce"
- ],
- "_release": "0.3.3",
- "_resolution": {
- "type": "version",
- "tag": "0.3.3",
- "commit": "0fcf71e6effc88179893c9c06baf6c6bf9037632"
- },
- "_source": "git://github.com/Pasvaz/bindonce.git",
- "_target": "~0.3.3",
- "_originalSource": "angular-bindonce",
- "_direct": true
-}
\ No newline at end of file
diff --git a/public/browse/lib/angular-bindonce/CHANGELOG.md b/public/browse/lib/angular-bindonce/CHANGELOG.md
deleted file mode 100644
index 8246d986e..000000000
--- a/public/browse/lib/angular-bindonce/CHANGELOG.md
+++ /dev/null
@@ -1,43 +0,0 @@
-# 0.3.3 (2014-02-12)
-### Features
-- **bo-disabled:**
- - Add support for ng-disabled/bo-disabled #110
-
-
-# 0.3.2 (2014-11-23)
-### Bug Fixes
-- **Angular 1.3 compatibility**
-
-
-# 0.3.1 (2014-02-12)
-### Features
-- **bo-bind:**
- - alias for bo-text
-
-### Bug Fixes
-- **Angular Promises**
- - Ensures that promises are resolved before to run binders ([b3ef1b4](https://github.com/Pasvaz/bindonce/commit/b3ef1b46edfe83f10ed455d5520027f731563f32))
-
-### Minor improvements
-- Updated Readme
-
-
-# 0.3.0 (2014-01-21)
-### Features
-- **bo-switch:**
- - Create new directive: bo-switch ([652d0db](https://github.com/Pasvaz/bindonce/commit/652d0db04325166a180377c738a376543b5f2357))
-
-
-# 0.2.3 (2014-01-20)
-### Bug Fixes
-
-- **bo-if:**
- - Ensures that we both process newly added binders from bo-if, and that
-we only process each binder once ([d11f863](https://github.com/Pasvaz/bindonce/commit/e091c273bbd17603d410fecc363874f0d1e6f38e))
-
-### Features
-
-- **Minification:**
- - add min file ([47277ee](https://github.com/Pasvaz/bindonce/commit/47277eedd092b3210de362c725a7dadcddac8e87))
-- **Changelog:**
- - Created a changelog file
diff --git a/public/browse/lib/angular-bindonce/README.md b/public/browse/lib/angular-bindonce/README.md
deleted file mode 100644
index c8d753fbe..000000000
--- a/public/browse/lib/angular-bindonce/README.md
+++ /dev/null
@@ -1,154 +0,0 @@
-Bindonce
-========
-
-High performance binding for AngularJs
-
-## Usage
-* download, clone or fork it or install it using [bower](http://twitter.github.com/bower/) `bower install angular-bindonce`
-* Include the `bindonce.js` script provided by this component into your app.
-* Add `'pasvaz.bindonce'` as a module dependency to your app: `angular.module('app', ['pasvaz.bindonce'])`
-
-## Demo
-Here is an example of how AngularJs can [freeze your UI](http://plnkr.co/edit/jwrHVb?p=preview), try to press and hold a key inside the input field, when the table is filled with only 1 person everything is ok, you can see how the DOM is updated by the input in real time, however if you try to load 1000 person *(or even 500 if the testing device is not powerfull)* and repeat the experiment you can see how the UI is frozen. In [this other demo](http://plnkr.co/edit/0DGOrk?p=preview) BindOnce will take care of your watchers and the UI will be reactive as it should be. The code is the same for both demos, the only difference is that I replaced any `ng-*` tag inside the table with the equivalent `bo-*` tag.
-* [AngularJs regular Demo](http://plnkr.co/edit/jwrHVb?p=preview)
-* [Demo with Bindonce](http://plnkr.co/edit/0DGOrk?p=preview)
-
-## Overview
-AngularJs provides a great data binding system but if you abuse of it the page can run into some performance issues, it's known that more of 2000 watchers can lag the UI and that amount can be reached easily if you don't pay attention to the data-binding. Sometime you really need to bind your data using watchers, especially for SPA because the data are updated in real time, but often you can avoid it with some efforts, most of the data presented in your page, once rendered, are immutable so you shouldn't keep watching them for changes.
-
-For instance, take a look to this snippet:
-```html
-
-
-
-
-
-
-
-```
-Angular internally creates a `$watch` for each `ng-*` directive in order to keep the data up to date, so in this example just for displaying few info it creates 6 + 1 *(ngRepeatWatch)* watchers per `person`, even if the `person` is supposed to remain the same once shown. Iterate this amount for each person and you can have an idea about how easy is to reach 2000 watchers. Now if you need it because those data could change while you show the page or are bound to some models, it's ok. But most of the time they are static data that don't change once rendered. This is where **bindonce** can really help you.
-
-The above example done with **bindonce**:
-```html
-
-
-
-
-
-
-
-```
-Now this example uses **0 watches** per `person` and renders exactly the same result as the above that uses ng-*. *(Angular still uses 1 watcher for ngRepeatWatch)*
-
-### The smart approach
-OK until here nothing completely new, with a bit of efforts you could create your own directive and render the `person` inside the `link` function, or you could use [watch fighters](https://github.com/abourget/abourget-angular) that has a similar approach, but there is still one problem that you have to face and **bindonce** already handles it: *the existence of the data when the directive renders the content*. Usually the directives, unless you use watchers or bind their attributes to the scope (still a watcher), render the content when they are loaded into the markup, but if at that given time your data is not available, the directive can't render it. Bindonce can wait until the data is ready before to rendering the content.
-Let's take a look at the follow snippet to better understand the concept:
-```html
-
-
-...
-
-```
-This basic directive works as expected, it renders the `Person` data without using any watchers. However, if `Person` is not yet available inside the $scope when the page is loaded (say we get `Person` via $http or via $resource), the directive is useless, `scope.$eval(attr.myCustomSetText)` simply renders nothing and exits.
-
-Here is how we can solve this issue with **bindonce**:
-```html
-
-
-
-
-
-
-```
-`bindonce="Person"` does the trick, any `bo-*` attribute belonging to `bindonce` waits until the parent `bindonce="{somedata}"` is validated and then renders its content. Once the scope contains the value `Person` then each bo-* child gets filled with the proper values. In order to accomplish this task, **bindonce** uses just **one** temporary watcher, no matters how many children need to be rendered. As soon as it gets `Person` the watcher is promptly removed. If the $scope already contains the data `bindonce` is looking for, then it doesn't create the temporary watcher and simply starts rendering its children.
-
-You may have noticed that the first example didn't assign any value to the `bindonce` attribute:
-```html
-
-
- ...
-```
-when used with `ng-repeat` `bindonce` doesn't need to check if `person` is defined because `ng-repeat` creates the directives only when `person` exists. You could be more explicit: `
`, however assigning a value to `bindonce` in an `ng-repeat` won't make any difference.
-
-### Interpolation
-Some directives (ng-href, ng-src) use interpolation, ie: `ng-href="/profile/{{User.profileId}}"`.
-Both `ng-href` and `ng-src` have the bo-* equivalent directives: `bo-href-i` and `bo-src-i` (pay attention to the **-i**, it stands for **interpolate**). As expected they don't use watchers however Angular creates one watcher per interpolation, for instance `bo-href-i="/profile/{{User.profileId}}"` sets the element's href **once**, as expected, but Angular keeps a watcher active on `{{User.profileId}}` even if `bo-href-i` doesn't use it.
-That's why by default the `bo-href` doesn't use interpolation or watchers. The above equivalent with 0 watchers would be `bo-href="'/profile/' + User.profileId"`. Nevertheless, `bo-href-i` and `bo-src-i` are still maintained for compatibility reasons.
-
-### Filters
-Almost every `bo-*` directive replace the equivalent `ng-*` and works in the same ways, except it is evaluated once.
-Consequentially you can use any valid angular expression, including filters. This is an example how to use a filter:
-```html
-
-
-
-```
-
-## Attribute Usage
-| Directive | Description | Example |
-|------------|----------------|-----|
-| `bindonce="{somedata}"`| **bindonce** is the main directive. `{somedata}` is optional, and if present, forces bindonce to wait until `somedata` is defined before rendering its children | `
...
` |
-| `bo-if = "condition"` | equivalent to `ng-if` but doesn't use watchers |``|
-| `bo-switch = "expression"` | equivalent to `ng-switch` but doesn't use watchers |`
` `public` `private` `
`|
-| `bo-show = "condition"` | equivalent to `ng-show` but doesn't use watchers |``|
-| `bo-hide = "condition"` | equivalent to `ng-hide` but doesn't use watchers |``|
-| `bo-disabled = "condition"` | equivalent to `ng-disabled` but doesn't use watchers |``|
-| `bo-text = "text"` | evaluates "text" and print it as text inside the element | `` |
-| `bo-bind = "text"` | alias for `bo-text`, equivalent to `ng-bind` but doesn't use watchers | `` |
-| `bo-html = "markup"` | evaluates "markup" and render it as html inside the element |`bo-html="Person.description"`|
-| `bo-href-i = "url"` *use `bo-href` instead* | **equivalent** to `ng-href`. **Heads up!** Using interpolation `{{}}` it creates one watcher: `bo-href-i="/p/{{Person.id}}"`. Use `bo-href` to avoid the watcher: `bo-href="'/p/' + Person.id"` |``|
-| `bo-href = "url"` | **similar** to `ng-href` but doesn't allow interpolation using `{{}}` like `ng-href`. **Heads up!** You can't use interpolation `{{}}` inside the url, use bo-href-i for that purpose |`` or ``|
-| `bo-src-i = "url"` *use `bo-src` instead* | **equivalent** to `ng-src`. **Heads up!** It creates one watcher |``|
-| `bo-src = "url"` | **similar** to `ng-src` but doesn't allow interpolation using `{{}}` like `ng-src`. **Heads up!** You can't use interpolation `{{}}`, use bo-src-i for that purpose |``|
-| `bo-class = "object/string"` | equivalent to `ng-class` but doesn't use watchers |``|
-| `bo-alt = "text"` | evaluates "text" and render it as `alt` for the element |``|
-| `bo-title = "text"` | evaluates "text" and render it as `title` for the element |``|
-| `bo-id = "#id"` | evaluates "#id" and render it as `id` for the element |``|
-| `bo-style = "object"` | equivalent to `ng-style` but doesn't use watchers |``|
-| `bo-value = "expression"` | evaluates "expression" and render it as `value` for the element |``|
-| `bo-attr bo-attr-foo = "text"` | evaluates "text" and render it as a custom attribute for the element |``|
-
-## Build
-```
-$ npm install uglify-js -g
-$ uglifyjs bindonce.js -c -m -o bindonce.min.js
-```
-
-## Todo
-Tests
-
-## Copyright
-BindOnce was written by **Pasquale Vazzana**, you can follow him on [google+](https://plus.google.com/101872882413388363602) or on [@twitter](https://twitter.com/PasqualeVazzana)
-
-Thanks to all the [contributors](https://github.com/Pasvaz/bindonce/graphs/contributors)
-
-## LICENSE - "MIT License"
-
-Copyright (c) 2013-2014 Pasquale Vazzana
-
-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.
diff --git a/public/browse/lib/angular-bindonce/bindonce.js b/public/browse/lib/angular-bindonce/bindonce.js
deleted file mode 100644
index 8742d8917..000000000
--- a/public/browse/lib/angular-bindonce/bindonce.js
+++ /dev/null
@@ -1,325 +0,0 @@
-(function () {
- "use strict";
- /**
- * Bindonce - Zero watches binding for AngularJs
- * @version v0.3.3
- * @link https://github.com/Pasvaz/bindonce
- * @author Pasquale Vazzana
- * @license MIT License, http://www.opensource.org/licenses/MIT
- */
-
- var bindonceModule = angular.module('pasvaz.bindonce', []);
-
- bindonceModule.directive('bindonce', function ()
- {
- var toBoolean = function (value)
- {
- if (value && value.length !== 0)
- {
- var v = angular.lowercase("" + value);
- value = !(v === 'f' || v === '0' || v === 'false' || v === 'no' || v === 'n' || v === '[]');
- }
- else
- {
- value = false;
- }
- return value;
- };
-
- var msie = parseInt((/msie (\d+)/.exec(angular.lowercase(navigator.userAgent)) || [])[1], 10);
- if (isNaN(msie))
- {
- msie = parseInt((/trident\/.*; rv:(\d+)/.exec(angular.lowercase(navigator.userAgent)) || [])[1], 10);
- }
-
- var bindonceDirective =
- {
- restrict: "AM",
- controller: ['$scope', '$element', '$attrs', '$interpolate', function ($scope, $element, $attrs, $interpolate)
- {
- var showHideBinder = function (elm, attr, value)
- {
- var show = (attr === 'show') ? '' : 'none';
- var hide = (attr === 'hide') ? '' : 'none';
- elm.css('display', toBoolean(value) ? show : hide);
- };
- var classBinder = function (elm, value)
- {
- if (angular.isObject(value) && !angular.isArray(value))
- {
- var results = [];
- angular.forEach(value, function (value, index)
- {
- if (value) results.push(index);
- });
- value = results;
- }
- if (value)
- {
- elm.addClass(angular.isArray(value) ? value.join(' ') : value);
- }
- };
- var transclude = function (transcluder, scope)
- {
- transcluder.transclude(scope, function (clone)
- {
- var parent = transcluder.element.parent();
- var afterNode = transcluder.element && transcluder.element[transcluder.element.length - 1];
- var parentNode = parent && parent[0] || afterNode && afterNode.parentNode;
- var afterNextSibling = (afterNode && afterNode.nextSibling) || null;
- angular.forEach(clone, function (node)
- {
- parentNode.insertBefore(node, afterNextSibling);
- });
- });
- };
-
- var ctrl =
- {
- watcherRemover: undefined,
- binders: [],
- group: $attrs.boName,
- element: $element,
- ran: false,
-
- addBinder: function (binder)
- {
- this.binders.push(binder);
-
- // In case of late binding (when using the directive bo-name/bo-parent)
- // it happens only when you use nested bindonce, if the bo-children
- // are not dom children the linking can follow another order
- if (this.ran)
- {
- this.runBinders();
- }
- },
-
- setupWatcher: function (bindonceValue)
- {
- var that = this;
- this.watcherRemover = $scope.$watch(bindonceValue, function (newValue)
- {
- if (newValue === undefined) return;
- that.removeWatcher();
- that.checkBindonce(newValue);
- }, true);
- },
-
- checkBindonce: function (value)
- {
- var that = this, promise = (value.$promise) ? value.$promise.then : value.then;
- // since Angular 1.2 promises are no longer
- // undefined until they don't get resolved
- if (typeof promise === 'function')
- {
- promise(function ()
- {
- that.runBinders();
- });
- }
- else
- {
- that.runBinders();
- }
- },
-
- removeWatcher: function ()
- {
- if (this.watcherRemover !== undefined)
- {
- this.watcherRemover();
- this.watcherRemover = undefined;
- }
- },
-
- runBinders: function ()
- {
- while (this.binders.length > 0)
- {
- var binder = this.binders.shift();
- if (this.group && this.group != binder.group) continue;
- var value = binder.scope.$eval((binder.interpolate) ? $interpolate(binder.value) : binder.value);
- switch (binder.attr)
- {
- case 'boIf':
- if (toBoolean(value))
- {
- transclude(binder, binder.scope.$new());
- }
- break;
- case 'boSwitch':
- var selectedTranscludes, switchCtrl = binder.controller[0];
- if ((selectedTranscludes = switchCtrl.cases['!' + value] || switchCtrl.cases['?']))
- {
- binder.scope.$eval(binder.attrs.change);
- angular.forEach(selectedTranscludes, function (selectedTransclude)
- {
- transclude(selectedTransclude, binder.scope.$new());
- });
- }
- break;
- case 'boSwitchWhen':
- var ctrl = binder.controller[0];
- ctrl.cases['!' + binder.attrs.boSwitchWhen] = (ctrl.cases['!' + binder.attrs.boSwitchWhen] || []);
- ctrl.cases['!' + binder.attrs.boSwitchWhen].push({ transclude: binder.transclude, element: binder.element });
- break;
- case 'boSwitchDefault':
- var ctrl = binder.controller[0];
- ctrl.cases['?'] = (ctrl.cases['?'] || []);
- ctrl.cases['?'].push({ transclude: binder.transclude, element: binder.element });
- break;
- case 'hide':
- case 'show':
- showHideBinder(binder.element, binder.attr, value);
- break;
- case 'class':
- classBinder(binder.element, value);
- break;
- case 'text':
- binder.element.text(value);
- break;
- case 'html':
- binder.element.html(value);
- break;
- case 'style':
- binder.element.css(value);
- break;
- case 'disabled':
- binder.element.prop('disabled', value);
- break;
- case 'src':
- binder.element.attr(binder.attr, value);
- if (msie) binder.element.prop('src', value);
- break;
- case 'attr':
- angular.forEach(binder.attrs, function (attrValue, attrKey)
- {
- var newAttr, newValue;
- if (attrKey.match(/^boAttr./) && binder.attrs[attrKey])
- {
- newAttr = attrKey.replace(/^boAttr/, '').replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
- newValue = binder.scope.$eval(binder.attrs[attrKey]);
- binder.element.attr(newAttr, newValue);
- }
- });
- break;
- case 'href':
- case 'alt':
- case 'title':
- case 'id':
- case 'value':
- binder.element.attr(binder.attr, value);
- break;
- }
- }
- this.ran = true;
- }
- };
-
- angular.extend(this, ctrl);
- }],
-
- link: function (scope, elm, attrs, bindonceController)
- {
- var value = attrs.bindonce && scope.$eval(attrs.bindonce);
- if (value !== undefined)
- {
- bindonceController.checkBindonce(value);
- }
- else
- {
- bindonceController.setupWatcher(attrs.bindonce);
- elm.bind("$destroy", bindonceController.removeWatcher);
- }
- }
- };
-
- return bindonceDirective;
- });
-
- angular.forEach(
- [
- { directiveName: 'boShow', attribute: 'show' },
- { directiveName: 'boHide', attribute: 'hide' },
- { directiveName: 'boClass', attribute: 'class' },
- { directiveName: 'boText', attribute: 'text' },
- { directiveName: 'boBind', attribute: 'text' },
- { directiveName: 'boHtml', attribute: 'html' },
- { directiveName: 'boSrcI', attribute: 'src', interpolate: true },
- { directiveName: 'boSrc', attribute: 'src' },
- { directiveName: 'boHrefI', attribute: 'href', interpolate: true },
- { directiveName: 'boHref', attribute: 'href' },
- { directiveName: 'boAlt', attribute: 'alt' },
- { directiveName: 'boTitle', attribute: 'title' },
- { directiveName: 'boId', attribute: 'id' },
- { directiveName: 'boStyle', attribute: 'style' },
- { directiveName: 'boDisabled', attribute: 'disabled' },
- { directiveName: 'boValue', attribute: 'value' },
- { directiveName: 'boAttr', attribute: 'attr' },
-
- { directiveName: 'boIf', transclude: 'element', terminal: true, priority: 1000 },
- { directiveName: 'boSwitch', require: 'boSwitch', controller: function () { this.cases = {}; } },
- { directiveName: 'boSwitchWhen', transclude: 'element', priority: 800, require: '^boSwitch' },
- { directiveName: 'boSwitchDefault', transclude: 'element', priority: 800, require: '^boSwitch' }
- ],
- function (boDirective)
- {
- var childPriority = 200;
- return bindonceModule.directive(boDirective.directiveName, function ()
- {
- var bindonceDirective =
- {
- priority: boDirective.priority || childPriority,
- transclude: boDirective.transclude || false,
- terminal: boDirective.terminal || false,
- require: ['^bindonce'].concat(boDirective.require || []),
- controller: boDirective.controller,
- compile: function (tElement, tAttrs, transclude)
- {
- return function (scope, elm, attrs, controllers)
- {
- var bindonceController = controllers[0];
- var name = attrs.boParent;
- if (name && bindonceController.group !== name)
- {
- var element = bindonceController.element.parent();
- bindonceController = undefined;
- var parentValue;
-
- while (element[0].nodeType !== 9 && element.length)
- {
- if ((parentValue = element.data('$bindonceController'))
- && parentValue.group === name)
- {
- bindonceController = parentValue;
- break;
- }
- element = element.parent();
- }
- if (!bindonceController)
- {
- throw new Error("No bindonce controller: " + name);
- }
- }
-
- bindonceController.addBinder(
- {
- element: elm,
- attr: boDirective.attribute || boDirective.directiveName,
- attrs: attrs,
- value: attrs[boDirective.directiveName],
- interpolate: boDirective.interpolate,
- group: name,
- transclude: transclude,
- controller: controllers.slice(1),
- scope: scope
- });
- };
- }
- };
-
- return bindonceDirective;
- });
- })
-})();
diff --git a/public/browse/lib/angular-bindonce/bindonce.min.js b/public/browse/lib/angular-bindonce/bindonce.min.js
deleted file mode 100644
index 555ded4bf..000000000
--- a/public/browse/lib/angular-bindonce/bindonce.min.js
+++ /dev/null
@@ -1 +0,0 @@
-!function(){"use strict";var e=angular.module("pasvaz.bindonce",[]);e.directive("bindonce",function(){var e=function(e){if(e&&0!==e.length){var t=angular.lowercase(""+e);e=!("f"===t||"0"===t||"false"===t||"no"===t||"n"===t||"[]"===t)}else e=!1;return e},t=parseInt((/msie (\d+)/.exec(angular.lowercase(navigator.userAgent))||[])[1],10);isNaN(t)&&(t=parseInt((/trident\/.*; rv:(\d+)/.exec(angular.lowercase(navigator.userAgent))||[])[1],10));var r={restrict:"AM",controller:["$scope","$element","$attrs","$interpolate",function(r,a,i,n){var c=function(t,r,a){var i="show"===r?"":"none",n="hide"===r?"":"none";t.css("display",e(a)?i:n)},o=function(e,t){if(angular.isObject(t)&&!angular.isArray(t)){var r=[];angular.forEach(t,function(e,t){e&&r.push(t)}),t=r}t&&e.addClass(angular.isArray(t)?t.join(" "):t)},s=function(e,t){e.transclude(t,function(t){var r=e.element.parent(),a=e.element&&e.element[e.element.length-1],i=r&&r[0]||a&&a.parentNode,n=a&&a.nextSibling||null;angular.forEach(t,function(e){i.insertBefore(e,n)})})},l={watcherRemover:void 0,binders:[],group:i.boName,element:a,ran:!1,addBinder:function(e){this.binders.push(e),this.ran&&this.runBinders()},setupWatcher:function(e){var t=this;this.watcherRemover=r.$watch(e,function(e){void 0!==e&&(t.removeWatcher(),t.checkBindonce(e))},!0)},checkBindonce:function(e){var t=this,r=e.$promise?e.$promise.then:e.then;"function"==typeof r?r(function(){t.runBinders()}):t.runBinders()},removeWatcher:function(){void 0!==this.watcherRemover&&(this.watcherRemover(),this.watcherRemover=void 0)},runBinders:function(){for(;this.binders.length>0;){var r=this.binders.shift();if(!this.group||this.group==r.group){var a=r.scope.$eval(r.interpolate?n(r.value):r.value);switch(r.attr){case"boIf":e(a)&&s(r,r.scope.$new());break;case"boSwitch":var i,l=r.controller[0];(i=l.cases["!"+a]||l.cases["?"])&&(r.scope.$eval(r.attrs.change),angular.forEach(i,function(e){s(e,r.scope.$new())}));break;case"boSwitchWhen":var u=r.controller[0];u.cases["!"+r.attrs.boSwitchWhen]=u.cases["!"+r.attrs.boSwitchWhen]||[],u.cases["!"+r.attrs.boSwitchWhen].push({transclude:r.transclude,element:r.element});break;case"boSwitchDefault":var u=r.controller[0];u.cases["?"]=u.cases["?"]||[],u.cases["?"].push({transclude:r.transclude,element:r.element});break;case"hide":case"show":c(r.element,r.attr,a);break;case"class":o(r.element,a);break;case"text":r.element.text(a);break;case"html":r.element.html(a);break;case"style":r.element.css(a);break;case"disabled":r.element.prop("disabled",a);break;case"src":r.element.attr(r.attr,a),t&&r.element.prop("src",a);break;case"attr":angular.forEach(r.attrs,function(e,t){var a,i;t.match(/^boAttr./)&&r.attrs[t]&&(a=t.replace(/^boAttr/,"").replace(/([a-z])([A-Z])/g,"$1-$2").toLowerCase(),i=r.scope.$eval(r.attrs[t]),r.element.attr(a,i))});break;case"href":case"alt":case"title":case"id":case"value":r.element.attr(r.attr,a)}}}this.ran=!0}};angular.extend(this,l)}],link:function(e,t,r,a){var i=r.bindonce&&e.$eval(r.bindonce);void 0!==i?a.checkBindonce(i):(a.setupWatcher(r.bindonce),t.bind("$destroy",a.removeWatcher))}};return r}),angular.forEach([{directiveName:"boShow",attribute:"show"},{directiveName:"boHide",attribute:"hide"},{directiveName:"boClass",attribute:"class"},{directiveName:"boText",attribute:"text"},{directiveName:"boBind",attribute:"text"},{directiveName:"boHtml",attribute:"html"},{directiveName:"boSrcI",attribute:"src",interpolate:!0},{directiveName:"boSrc",attribute:"src"},{directiveName:"boHrefI",attribute:"href",interpolate:!0},{directiveName:"boHref",attribute:"href"},{directiveName:"boAlt",attribute:"alt"},{directiveName:"boTitle",attribute:"title"},{directiveName:"boId",attribute:"id"},{directiveName:"boStyle",attribute:"style"},{directiveName:"boDisabled",attribute:"disabled"},{directiveName:"boValue",attribute:"value"},{directiveName:"boAttr",attribute:"attr"},{directiveName:"boIf",transclude:"element",terminal:!0,priority:1e3},{directiveName:"boSwitch",require:"boSwitch",controller:function(){this.cases={}}},{directiveName:"boSwitchWhen",transclude:"element",priority:800,require:"^boSwitch"},{directiveName:"boSwitchDefault",transclude:"element",priority:800,require:"^boSwitch"}],function(t){var r=200;return e.directive(t.directiveName,function(){var e={priority:t.priority||r,transclude:t.transclude||!1,terminal:t.terminal||!1,require:["^bindonce"].concat(t.require||[]),controller:t.controller,compile:function(e,r,a){return function(e,r,i,n){var c=n[0],o=i.boParent;if(o&&c.group!==o){var s=c.element.parent();c=void 0;for(var l;9!==s[0].nodeType&&s.length;){if((l=s.data("$bindonceController"))&&l.group===o){c=l;break}s=s.parent()}if(!c)throw new Error("No bindonce controller: "+o)}c.addBinder({element:r,attr:t.attribute||t.directiveName,attrs:i,value:i[t.directiveName],interpolate:t.interpolate,group:o,transclude:a,controller:n.slice(1),scope:e})}}};return e})})}();
\ No newline at end of file
diff --git a/public/browse/lib/angular-bindonce/bower.json b/public/browse/lib/angular-bindonce/bower.json
deleted file mode 100644
index 924259459..000000000
--- a/public/browse/lib/angular-bindonce/bower.json
+++ /dev/null
@@ -1,28 +0,0 @@
-{
- "name": "angular-bindonce",
- "version": "0.3.3",
- "main": "bindonce.js",
- "description": "Zero watchers binding directives for AngularJS",
- "homepage": "https://github.com/Pasvaz/bindonce",
- "author": "Pasquale Vazzana ",
- "repository": {
- "type": "git",
- "url": "https://github.com/Pasvaz/bindonce.git"
- },
- "license": "MIT",
- "ignore": [
- "**/.*",
- "node_modules",
- "components"
- ],
- "dependencies": {
- },
- "keywords": [
- "angularjs",
- "angular",
- "directive",
- "binding",
- "watcher",
- "bindonce"
- ]
-}
diff --git a/public/browse/lib/angular-bindonce/package.json b/public/browse/lib/angular-bindonce/package.json
deleted file mode 100644
index 924259459..000000000
--- a/public/browse/lib/angular-bindonce/package.json
+++ /dev/null
@@ -1,28 +0,0 @@
-{
- "name": "angular-bindonce",
- "version": "0.3.3",
- "main": "bindonce.js",
- "description": "Zero watchers binding directives for AngularJS",
- "homepage": "https://github.com/Pasvaz/bindonce",
- "author": "Pasquale Vazzana ",
- "repository": {
- "type": "git",
- "url": "https://github.com/Pasvaz/bindonce.git"
- },
- "license": "MIT",
- "ignore": [
- "**/.*",
- "node_modules",
- "components"
- ],
- "dependencies": {
- },
- "keywords": [
- "angularjs",
- "angular",
- "directive",
- "binding",
- "watcher",
- "bindonce"
- ]
-}
diff --git a/public/browse/lib/angular-loader/.bower.json b/public/browse/lib/angular-loader/.bower.json
deleted file mode 100644
index c0b518149..000000000
--- a/public/browse/lib/angular-loader/.bower.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "name": "angular-loader",
- "version": "1.3.5",
- "main": "./angular-loader.js",
- "ignore": [],
- "dependencies": {
- "angular": "1.3.5"
- },
- "homepage": "https://github.com/angular/bower-angular-loader",
- "_release": "1.3.5",
- "_resolution": {
- "type": "version",
- "tag": "v1.3.5",
- "commit": "afb779fa2e865a1f13f87278586aa71bbea518bb"
- },
- "_source": "git://github.com/angular/bower-angular-loader.git",
- "_target": "1.3.x",
- "_originalSource": "angular-loader"
-}
\ No newline at end of file
diff --git a/public/browse/lib/angular-loader/README.md b/public/browse/lib/angular-loader/README.md
deleted file mode 100644
index 0f16d5def..000000000
--- a/public/browse/lib/angular-loader/README.md
+++ /dev/null
@@ -1,65 +0,0 @@
-# packaged angular-loader
-
-This repo is for distribution on `npm` and `bower`. The source for this module is in the
-[main AngularJS repo](https://github.com/angular/angular.js/blob/master/src/loader.js).
-Please file issues and pull requests against that repo.
-
-## Install
-
-You can install this package either with `npm` or with `bower`.
-
-### npm
-
-```shell
-npm install angular-loader
-```
-
-Add a `
-```
-
-Note that this package is not in CommonJS format, so doing `require('angular-loader')` will
-return `undefined`.
-
-### bower
-
-```shell
-bower install angular-loader
-```
-
-Add a `
-```
-
-## Documentation
-
-Documentation is available on the
-[AngularJS docs site](http://docs.angularjs.org/guide/bootstrap).
-
-## License
-
-The MIT License
-
-Copyright (c) 2010-2012 Google, Inc. http://angularjs.org
-
-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.
diff --git a/public/browse/lib/angular-loader/angular-loader.js b/public/browse/lib/angular-loader/angular-loader.js
deleted file mode 100644
index 3b27049c1..000000000
--- a/public/browse/lib/angular-loader/angular-loader.js
+++ /dev/null
@@ -1,405 +0,0 @@
-/**
- * @license AngularJS v1.3.5
- * (c) 2010-2014 Google, Inc. http://angularjs.org
- * License: MIT
- */
-
-(function() {'use strict';
-
-/**
- * @description
- *
- * This object provides a utility for producing rich Error messages within
- * Angular. It can be called as follows:
- *
- * var exampleMinErr = minErr('example');
- * throw exampleMinErr('one', 'This {0} is {1}', foo, bar);
- *
- * The above creates an instance of minErr in the example namespace. The
- * resulting error will have a namespaced error code of example.one. The
- * resulting error will replace {0} with the value of foo, and {1} with the
- * value of bar. The object is not restricted in the number of arguments it can
- * take.
- *
- * If fewer arguments are specified than necessary for interpolation, the extra
- * interpolation markers will be preserved in the final string.
- *
- * Since data will be parsed statically during a build step, some restrictions
- * are applied with respect to how minErr instances are created and called.
- * Instances should have names of the form namespaceMinErr for a minErr created
- * using minErr('namespace') . Error codes, namespaces and template strings
- * should all be static strings, not variables or general expressions.
- *
- * @param {string} module The namespace to use for the new minErr instance.
- * @param {function} ErrorConstructor Custom error constructor to be instantiated when returning
- * error from returned function, for cases when a particular type of error is useful.
- * @returns {function(code:string, template:string, ...templateArgs): Error} minErr instance
- */
-
-function minErr(module, ErrorConstructor) {
- ErrorConstructor = ErrorConstructor || Error;
- return function() {
- var code = arguments[0],
- prefix = '[' + (module ? module + ':' : '') + code + '] ',
- template = arguments[1],
- templateArgs = arguments,
-
- message, i;
-
- message = prefix + template.replace(/\{\d+\}/g, function(match) {
- var index = +match.slice(1, -1), arg;
-
- if (index + 2 < templateArgs.length) {
- return toDebugString(templateArgs[index + 2]);
- }
- return match;
- });
-
- message = message + '\nhttp://errors.angularjs.org/1.3.5/' +
- (module ? module + '/' : '') + code;
- for (i = 2; i < arguments.length; i++) {
- message = message + (i == 2 ? '?' : '&') + 'p' + (i - 2) + '=' +
- encodeURIComponent(toDebugString(arguments[i]));
- }
- return new ErrorConstructor(message);
- };
-}
-
-/**
- * @ngdoc type
- * @name angular.Module
- * @module ng
- * @description
- *
- * Interface for configuring angular {@link angular.module modules}.
- */
-
-function setupModuleLoader(window) {
-
- var $injectorMinErr = minErr('$injector');
- var ngMinErr = minErr('ng');
-
- function ensure(obj, name, factory) {
- return obj[name] || (obj[name] = factory());
- }
-
- var angular = ensure(window, 'angular', Object);
-
- // We need to expose `angular.$$minErr` to modules such as `ngResource` that reference it during bootstrap
- angular.$$minErr = angular.$$minErr || minErr;
-
- return ensure(angular, 'module', function() {
- /** @type {Object.} */
- var modules = {};
-
- /**
- * @ngdoc function
- * @name angular.module
- * @module ng
- * @description
- *
- * The `angular.module` is a global place for creating, registering and retrieving Angular
- * modules.
- * All modules (angular core or 3rd party) that should be available to an application must be
- * registered using this mechanism.
- *
- * When passed two or more arguments, a new module is created. If passed only one argument, an
- * existing module (the name passed as the first argument to `module`) is retrieved.
- *
- *
- * # Module
- *
- * A module is a collection of services, directives, controllers, filters, and configuration information.
- * `angular.module` is used to configure the {@link auto.$injector $injector}.
- *
- * ```js
- * // Create a new module
- * var myModule = angular.module('myModule', []);
- *
- * // register a new service
- * myModule.value('appName', 'MyCoolApp');
- *
- * // configure existing services inside initialization blocks.
- * myModule.config(['$locationProvider', function($locationProvider) {
- * // Configure existing providers
- * $locationProvider.hashPrefix('!');
- * }]);
- * ```
- *
- * Then you can create an injector and load your modules like this:
- *
- * ```js
- * var injector = angular.injector(['ng', 'myModule'])
- * ```
- *
- * However it's more likely that you'll just use
- * {@link ng.directive:ngApp ngApp} or
- * {@link angular.bootstrap} to simplify this process for you.
- *
- * @param {!string} name The name of the module to create or retrieve.
- * @param {!Array.=} requires If specified then new module is being created. If
- * unspecified then the module is being retrieved for further configuration.
- * @param {Function=} configFn Optional configuration function for the module. Same as
- * {@link angular.Module#config Module#config()}.
- * @returns {module} new module with the {@link angular.Module} api.
- */
- return function module(name, requires, configFn) {
- var assertNotHasOwnProperty = function(name, context) {
- if (name === 'hasOwnProperty') {
- throw ngMinErr('badname', 'hasOwnProperty is not a valid {0} name', context);
- }
- };
-
- assertNotHasOwnProperty(name, 'module');
- if (requires && modules.hasOwnProperty(name)) {
- modules[name] = null;
- }
- return ensure(modules, name, function() {
- if (!requires) {
- throw $injectorMinErr('nomod', "Module '{0}' is not available! You either misspelled " +
- "the module name or forgot to load it. If registering a module ensure that you " +
- "specify the dependencies as the second argument.", name);
- }
-
- /** @type {!Array.>} */
- var invokeQueue = [];
-
- /** @type {!Array.} */
- var configBlocks = [];
-
- /** @type {!Array.} */
- var runBlocks = [];
-
- var config = invokeLater('$injector', 'invoke', 'push', configBlocks);
-
- /** @type {angular.Module} */
- var moduleInstance = {
- // Private state
- _invokeQueue: invokeQueue,
- _configBlocks: configBlocks,
- _runBlocks: runBlocks,
-
- /**
- * @ngdoc property
- * @name angular.Module#requires
- * @module ng
- *
- * @description
- * Holds the list of modules which the injector will load before the current module is
- * loaded.
- */
- requires: requires,
-
- /**
- * @ngdoc property
- * @name angular.Module#name
- * @module ng
- *
- * @description
- * Name of the module.
- */
- name: name,
-
-
- /**
- * @ngdoc method
- * @name angular.Module#provider
- * @module ng
- * @param {string} name service name
- * @param {Function} providerType Construction function for creating new instance of the
- * service.
- * @description
- * See {@link auto.$provide#provider $provide.provider()}.
- */
- provider: invokeLater('$provide', 'provider'),
-
- /**
- * @ngdoc method
- * @name angular.Module#factory
- * @module ng
- * @param {string} name service name
- * @param {Function} providerFunction Function for creating new instance of the service.
- * @description
- * See {@link auto.$provide#factory $provide.factory()}.
- */
- factory: invokeLater('$provide', 'factory'),
-
- /**
- * @ngdoc method
- * @name angular.Module#service
- * @module ng
- * @param {string} name service name
- * @param {Function} constructor A constructor function that will be instantiated.
- * @description
- * See {@link auto.$provide#service $provide.service()}.
- */
- service: invokeLater('$provide', 'service'),
-
- /**
- * @ngdoc method
- * @name angular.Module#value
- * @module ng
- * @param {string} name service name
- * @param {*} object Service instance object.
- * @description
- * See {@link auto.$provide#value $provide.value()}.
- */
- value: invokeLater('$provide', 'value'),
-
- /**
- * @ngdoc method
- * @name angular.Module#constant
- * @module ng
- * @param {string} name constant name
- * @param {*} object Constant value.
- * @description
- * Because the constant are fixed, they get applied before other provide methods.
- * See {@link auto.$provide#constant $provide.constant()}.
- */
- constant: invokeLater('$provide', 'constant', 'unshift'),
-
- /**
- * @ngdoc method
- * @name angular.Module#animation
- * @module ng
- * @param {string} name animation name
- * @param {Function} animationFactory Factory function for creating new instance of an
- * animation.
- * @description
- *
- * **NOTE**: animations take effect only if the **ngAnimate** module is loaded.
- *
- *
- * Defines an animation hook that can be later used with
- * {@link ngAnimate.$animate $animate} service and directives that use this service.
- *
- * ```js
- * module.animation('.animation-name', function($inject1, $inject2) {
- * return {
- * eventName : function(element, done) {
- * //code to run the animation
- * //once complete, then run done()
- * return function cancellationFunction(element) {
- * //code to cancel the animation
- * }
- * }
- * }
- * })
- * ```
- *
- * See {@link ng.$animateProvider#register $animateProvider.register()} and
- * {@link ngAnimate ngAnimate module} for more information.
- */
- animation: invokeLater('$animateProvider', 'register'),
-
- /**
- * @ngdoc method
- * @name angular.Module#filter
- * @module ng
- * @param {string} name Filter name.
- * @param {Function} filterFactory Factory function for creating new instance of filter.
- * @description
- * See {@link ng.$filterProvider#register $filterProvider.register()}.
- */
- filter: invokeLater('$filterProvider', 'register'),
-
- /**
- * @ngdoc method
- * @name angular.Module#controller
- * @module ng
- * @param {string|Object} name Controller name, or an object map of controllers where the
- * keys are the names and the values are the constructors.
- * @param {Function} constructor Controller constructor function.
- * @description
- * See {@link ng.$controllerProvider#register $controllerProvider.register()}.
- */
- controller: invokeLater('$controllerProvider', 'register'),
-
- /**
- * @ngdoc method
- * @name angular.Module#directive
- * @module ng
- * @param {string|Object} name Directive name, or an object map of directives where the
- * keys are the names and the values are the factories.
- * @param {Function} directiveFactory Factory function for creating new instance of
- * directives.
- * @description
- * See {@link ng.$compileProvider#directive $compileProvider.directive()}.
- */
- directive: invokeLater('$compileProvider', 'directive'),
-
- /**
- * @ngdoc method
- * @name angular.Module#config
- * @module ng
- * @param {Function} configFn Execute this function on module load. Useful for service
- * configuration.
- * @description
- * Use this method to register work which needs to be performed on module loading.
- * For more about how to configure services, see
- * {@link providers#provider-recipe Provider Recipe}.
- */
- config: config,
-
- /**
- * @ngdoc method
- * @name angular.Module#run
- * @module ng
- * @param {Function} initializationFn Execute this function after injector creation.
- * Useful for application initialization.
- * @description
- * Use this method to register work which should be performed when the injector is done
- * loading all modules.
- */
- run: function(block) {
- runBlocks.push(block);
- return this;
- }
- };
-
- if (configFn) {
- config(configFn);
- }
-
- return moduleInstance;
-
- /**
- * @param {string} provider
- * @param {string} method
- * @param {String=} insertMethod
- * @returns {angular.Module}
- */
- function invokeLater(provider, method, insertMethod, queue) {
- if (!queue) queue = invokeQueue;
- return function() {
- queue[insertMethod || 'push']([provider, method, arguments]);
- return moduleInstance;
- };
- }
- });
- };
- });
-
-}
-
-setupModuleLoader(window);
-})(window);
-
-/**
- * Closure compiler type information
- *
- * @typedef { {
- * requires: !Array.,
- * invokeQueue: !Array.>,
- *
- * service: function(string, Function):angular.Module,
- * factory: function(string, Function):angular.Module,
- * value: function(string, *):angular.Module,
- *
- * filter: function(string, Function):angular.Module,
- *
- * init: function(Function):angular.Module
- * } }
- */
-angular.Module;
-
diff --git a/public/browse/lib/angular-loader/angular-loader.min.js b/public/browse/lib/angular-loader/angular-loader.min.js
deleted file mode 100644
index bc6333ed5..000000000
--- a/public/browse/lib/angular-loader/angular-loader.min.js
+++ /dev/null
@@ -1,9 +0,0 @@
-/*
- AngularJS v1.3.5
- (c) 2010-2014 Google, Inc. http://angularjs.org
- License: MIT
-*/
-(function(){'use strict';function d(b){return function(){var c=arguments[0],e;e="["+(b?b+":":"")+c+"] http://errors.angularjs.org/1.3.5/"+(b?b+"/":"")+c;for(c=1;c",
- "license": "MIT",
- "bugs": {
- "url": "https://github.com/angular/angular.js/issues"
- },
- "homepage": "http://angularjs.org"
-}
diff --git a/public/browse/lib/angular-mocks/.bower.json b/public/browse/lib/angular-mocks/.bower.json
deleted file mode 100644
index e321d3002..000000000
--- a/public/browse/lib/angular-mocks/.bower.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "name": "angular-mocks",
- "version": "1.3.5",
- "main": "./angular-mocks.js",
- "ignore": [],
- "dependencies": {
- "angular": "1.3.5"
- },
- "homepage": "https://github.com/angular/bower-angular-mocks",
- "_release": "1.3.5",
- "_resolution": {
- "type": "version",
- "tag": "v1.3.5",
- "commit": "e5356ca3fa80f824ac7e3d9651156401e6bf2a38"
- },
- "_source": "git://github.com/angular/bower-angular-mocks.git",
- "_target": "~1.3.x",
- "_originalSource": "angular-mocks"
-}
\ No newline at end of file
diff --git a/public/browse/lib/angular-mocks/README.md b/public/browse/lib/angular-mocks/README.md
deleted file mode 100644
index 1604ef880..000000000
--- a/public/browse/lib/angular-mocks/README.md
+++ /dev/null
@@ -1,57 +0,0 @@
-# packaged angular-mocks
-
-This repo is for distribution on `npm` and `bower`. The source for this module is in the
-[main AngularJS repo](https://github.com/angular/angular.js/tree/master/src/ngMock).
-Please file issues and pull requests against that repo.
-
-## Install
-
-You can install this package either with `npm` or with `bower`.
-
-### npm
-
-```shell
-npm install angular-mocks
-```
-
-The mocks are then available at `node_modules/angular-mocks/angular-mocks.js`.
-
-Note that this package is not in CommonJS format, so doing `require('angular-mocks')` will
-return `undefined`.
-
-### bower
-
-```shell
-bower install angular-mocks
-```
-
-The mocks are then available at `bower_components/angular-mocks/angular-mocks.js`.
-
-## Documentation
-
-Documentation is available on the
-[AngularJS docs site](https://docs.angularjs.org/guide/unit-testing).
-
-## License
-
-The MIT License
-
-Copyright (c) 2010-2012 Google, Inc. http://angularjs.org
-
-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.
diff --git a/public/browse/lib/angular-mocks/angular-mocks.js b/public/browse/lib/angular-mocks/angular-mocks.js
deleted file mode 100644
index 3d33b2232..000000000
--- a/public/browse/lib/angular-mocks/angular-mocks.js
+++ /dev/null
@@ -1,2380 +0,0 @@
-/**
- * @license AngularJS v1.3.5
- * (c) 2010-2014 Google, Inc. http://angularjs.org
- * License: MIT
- */
-(function(window, angular, undefined) {
-
-'use strict';
-
-/**
- * @ngdoc object
- * @name angular.mock
- * @description
- *
- * Namespace from 'angular-mocks.js' which contains testing related code.
- */
-angular.mock = {};
-
-/**
- * ! This is a private undocumented service !
- *
- * @name $browser
- *
- * @description
- * This service is a mock implementation of {@link ng.$browser}. It provides fake
- * implementation for commonly used browser apis that are hard to test, e.g. setTimeout, xhr,
- * cookies, etc...
- *
- * The api of this service is the same as that of the real {@link ng.$browser $browser}, except
- * that there are several helper methods available which can be used in tests.
- */
-angular.mock.$BrowserProvider = function() {
- this.$get = function() {
- return new angular.mock.$Browser();
- };
-};
-
-angular.mock.$Browser = function() {
- var self = this;
-
- this.isMock = true;
- self.$$url = "http://server/";
- self.$$lastUrl = self.$$url; // used by url polling fn
- self.pollFns = [];
-
- // TODO(vojta): remove this temporary api
- self.$$completeOutstandingRequest = angular.noop;
- self.$$incOutstandingRequestCount = angular.noop;
-
-
- // register url polling fn
-
- self.onUrlChange = function(listener) {
- self.pollFns.push(
- function() {
- if (self.$$lastUrl !== self.$$url || self.$$state !== self.$$lastState) {
- self.$$lastUrl = self.$$url;
- self.$$lastState = self.$$state;
- listener(self.$$url, self.$$state);
- }
- }
- );
-
- return listener;
- };
-
- self.$$checkUrlChange = angular.noop;
-
- self.cookieHash = {};
- self.lastCookieHash = {};
- self.deferredFns = [];
- self.deferredNextId = 0;
-
- self.defer = function(fn, delay) {
- delay = delay || 0;
- self.deferredFns.push({time:(self.defer.now + delay), fn:fn, id: self.deferredNextId});
- self.deferredFns.sort(function(a, b) { return a.time - b.time;});
- return self.deferredNextId++;
- };
-
-
- /**
- * @name $browser#defer.now
- *
- * @description
- * Current milliseconds mock time.
- */
- self.defer.now = 0;
-
-
- self.defer.cancel = function(deferId) {
- var fnIndex;
-
- angular.forEach(self.deferredFns, function(fn, index) {
- if (fn.id === deferId) fnIndex = index;
- });
-
- if (fnIndex !== undefined) {
- self.deferredFns.splice(fnIndex, 1);
- return true;
- }
-
- return false;
- };
-
-
- /**
- * @name $browser#defer.flush
- *
- * @description
- * Flushes all pending requests and executes the defer callbacks.
- *
- * @param {number=} number of milliseconds to flush. See {@link #defer.now}
- */
- self.defer.flush = function(delay) {
- if (angular.isDefined(delay)) {
- self.defer.now += delay;
- } else {
- if (self.deferredFns.length) {
- self.defer.now = self.deferredFns[self.deferredFns.length - 1].time;
- } else {
- throw new Error('No deferred tasks to be flushed');
- }
- }
-
- while (self.deferredFns.length && self.deferredFns[0].time <= self.defer.now) {
- self.deferredFns.shift().fn();
- }
- };
-
- self.$$baseHref = '/';
- self.baseHref = function() {
- return this.$$baseHref;
- };
-};
-angular.mock.$Browser.prototype = {
-
-/**
- * @name $browser#poll
- *
- * @description
- * run all fns in pollFns
- */
- poll: function poll() {
- angular.forEach(this.pollFns, function(pollFn) {
- pollFn();
- });
- },
-
- addPollFn: function(pollFn) {
- this.pollFns.push(pollFn);
- return pollFn;
- },
-
- url: function(url, replace, state) {
- if (angular.isUndefined(state)) {
- state = null;
- }
- if (url) {
- this.$$url = url;
- // Native pushState serializes & copies the object; simulate it.
- this.$$state = angular.copy(state);
- return this;
- }
-
- return this.$$url;
- },
-
- state: function() {
- return this.$$state;
- },
-
- cookies: function(name, value) {
- if (name) {
- if (angular.isUndefined(value)) {
- delete this.cookieHash[name];
- } else {
- if (angular.isString(value) && //strings only
- value.length <= 4096) { //strict cookie storage limits
- this.cookieHash[name] = value;
- }
- }
- } else {
- if (!angular.equals(this.cookieHash, this.lastCookieHash)) {
- this.lastCookieHash = angular.copy(this.cookieHash);
- this.cookieHash = angular.copy(this.cookieHash);
- }
- return this.cookieHash;
- }
- },
-
- notifyWhenNoOutstandingRequests: function(fn) {
- fn();
- }
-};
-
-
-/**
- * @ngdoc provider
- * @name $exceptionHandlerProvider
- *
- * @description
- * Configures the mock implementation of {@link ng.$exceptionHandler} to rethrow or to log errors
- * passed to the `$exceptionHandler`.
- */
-
-/**
- * @ngdoc service
- * @name $exceptionHandler
- *
- * @description
- * Mock implementation of {@link ng.$exceptionHandler} that rethrows or logs errors passed
- * to it. See {@link ngMock.$exceptionHandlerProvider $exceptionHandlerProvider} for configuration
- * information.
- *
- *
- * ```js
- * describe('$exceptionHandlerProvider', function() {
- *
- * it('should capture log messages and exceptions', function() {
- *
- * module(function($exceptionHandlerProvider) {
- * $exceptionHandlerProvider.mode('log');
- * });
- *
- * inject(function($log, $exceptionHandler, $timeout) {
- * $timeout(function() { $log.log(1); });
- * $timeout(function() { $log.log(2); throw 'banana peel'; });
- * $timeout(function() { $log.log(3); });
- * expect($exceptionHandler.errors).toEqual([]);
- * expect($log.assertEmpty());
- * $timeout.flush();
- * expect($exceptionHandler.errors).toEqual(['banana peel']);
- * expect($log.log.logs).toEqual([[1], [2], [3]]);
- * });
- * });
- * });
- * ```
- */
-
-angular.mock.$ExceptionHandlerProvider = function() {
- var handler;
-
- /**
- * @ngdoc method
- * @name $exceptionHandlerProvider#mode
- *
- * @description
- * Sets the logging mode.
- *
- * @param {string} mode Mode of operation, defaults to `rethrow`.
- *
- * - `rethrow`: If any errors are passed to the handler in tests, it typically means that there
- * is a bug in the application or test, so this mock will make these tests fail.
- * - `log`: Sometimes it is desirable to test that an error is thrown, for this case the `log`
- * mode stores an array of errors in `$exceptionHandler.errors`, to allow later
- * assertion of them. See {@link ngMock.$log#assertEmpty assertEmpty()} and
- * {@link ngMock.$log#reset reset()}
- */
- this.mode = function(mode) {
- switch (mode) {
- case 'rethrow':
- handler = function(e) {
- throw e;
- };
- break;
- case 'log':
- var errors = [];
-
- handler = function(e) {
- if (arguments.length == 1) {
- errors.push(e);
- } else {
- errors.push([].slice.call(arguments, 0));
- }
- };
-
- handler.errors = errors;
- break;
- default:
- throw new Error("Unknown mode '" + mode + "', only 'log'/'rethrow' modes are allowed!");
- }
- };
-
- this.$get = function() {
- return handler;
- };
-
- this.mode('rethrow');
-};
-
-
-/**
- * @ngdoc service
- * @name $log
- *
- * @description
- * Mock implementation of {@link ng.$log} that gathers all logged messages in arrays
- * (one array per logging level). These arrays are exposed as `logs` property of each of the
- * level-specific log function, e.g. for level `error` the array is exposed as `$log.error.logs`.
- *
- */
-angular.mock.$LogProvider = function() {
- var debug = true;
-
- function concat(array1, array2, index) {
- return array1.concat(Array.prototype.slice.call(array2, index));
- }
-
- this.debugEnabled = function(flag) {
- if (angular.isDefined(flag)) {
- debug = flag;
- return this;
- } else {
- return debug;
- }
- };
-
- this.$get = function() {
- var $log = {
- log: function() { $log.log.logs.push(concat([], arguments, 0)); },
- warn: function() { $log.warn.logs.push(concat([], arguments, 0)); },
- info: function() { $log.info.logs.push(concat([], arguments, 0)); },
- error: function() { $log.error.logs.push(concat([], arguments, 0)); },
- debug: function() {
- if (debug) {
- $log.debug.logs.push(concat([], arguments, 0));
- }
- }
- };
-
- /**
- * @ngdoc method
- * @name $log#reset
- *
- * @description
- * Reset all of the logging arrays to empty.
- */
- $log.reset = function() {
- /**
- * @ngdoc property
- * @name $log#log.logs
- *
- * @description
- * Array of messages logged using {@link ng.$log#log `log()`}.
- *
- * @example
- * ```js
- * $log.log('Some Log');
- * var first = $log.log.logs.unshift();
- * ```
- */
- $log.log.logs = [];
- /**
- * @ngdoc property
- * @name $log#info.logs
- *
- * @description
- * Array of messages logged using {@link ng.$log#info `info()`}.
- *
- * @example
- * ```js
- * $log.info('Some Info');
- * var first = $log.info.logs.unshift();
- * ```
- */
- $log.info.logs = [];
- /**
- * @ngdoc property
- * @name $log#warn.logs
- *
- * @description
- * Array of messages logged using {@link ng.$log#warn `warn()`}.
- *
- * @example
- * ```js
- * $log.warn('Some Warning');
- * var first = $log.warn.logs.unshift();
- * ```
- */
- $log.warn.logs = [];
- /**
- * @ngdoc property
- * @name $log#error.logs
- *
- * @description
- * Array of messages logged using {@link ng.$log#error `error()`}.
- *
- * @example
- * ```js
- * $log.error('Some Error');
- * var first = $log.error.logs.unshift();
- * ```
- */
- $log.error.logs = [];
- /**
- * @ngdoc property
- * @name $log#debug.logs
- *
- * @description
- * Array of messages logged using {@link ng.$log#debug `debug()`}.
- *
- * @example
- * ```js
- * $log.debug('Some Error');
- * var first = $log.debug.logs.unshift();
- * ```
- */
- $log.debug.logs = [];
- };
-
- /**
- * @ngdoc method
- * @name $log#assertEmpty
- *
- * @description
- * Assert that all of the logging methods have no logged messages. If any messages are present,
- * an exception is thrown.
- */
- $log.assertEmpty = function() {
- var errors = [];
- angular.forEach(['error', 'warn', 'info', 'log', 'debug'], function(logLevel) {
- angular.forEach($log[logLevel].logs, function(log) {
- angular.forEach(log, function(logItem) {
- errors.push('MOCK $log (' + logLevel + '): ' + String(logItem) + '\n' +
- (logItem.stack || ''));
- });
- });
- });
- if (errors.length) {
- errors.unshift("Expected $log to be empty! Either a message was logged unexpectedly, or " +
- "an expected log message was not checked and removed:");
- errors.push('');
- throw new Error(errors.join('\n---------\n'));
- }
- };
-
- $log.reset();
- return $log;
- };
-};
-
-
-/**
- * @ngdoc service
- * @name $interval
- *
- * @description
- * Mock implementation of the $interval service.
- *
- * Use {@link ngMock.$interval#flush `$interval.flush(millis)`} to
- * move forward by `millis` milliseconds and trigger any functions scheduled to run in that
- * time.
- *
- * @param {function()} fn A function that should be called repeatedly.
- * @param {number} delay Number of milliseconds between each function call.
- * @param {number=} [count=0] Number of times to repeat. If not set, or 0, will repeat
- * indefinitely.
- * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
- * will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
- * @returns {promise} A promise which will be notified on each iteration.
- */
-angular.mock.$IntervalProvider = function() {
- this.$get = ['$browser', '$rootScope', '$q', '$$q',
- function($browser, $rootScope, $q, $$q) {
- var repeatFns = [],
- nextRepeatId = 0,
- now = 0;
-
- var $interval = function(fn, delay, count, invokeApply) {
- var iteration = 0,
- skipApply = (angular.isDefined(invokeApply) && !invokeApply),
- deferred = (skipApply ? $$q : $q).defer(),
- promise = deferred.promise;
-
- count = (angular.isDefined(count)) ? count : 0;
- promise.then(null, null, fn);
-
- promise.$$intervalId = nextRepeatId;
-
- function tick() {
- deferred.notify(iteration++);
-
- if (count > 0 && iteration >= count) {
- var fnIndex;
- deferred.resolve(iteration);
-
- angular.forEach(repeatFns, function(fn, index) {
- if (fn.id === promise.$$intervalId) fnIndex = index;
- });
-
- if (fnIndex !== undefined) {
- repeatFns.splice(fnIndex, 1);
- }
- }
-
- if (skipApply) {
- $browser.defer.flush();
- } else {
- $rootScope.$apply();
- }
- }
-
- repeatFns.push({
- nextTime:(now + delay),
- delay: delay,
- fn: tick,
- id: nextRepeatId,
- deferred: deferred
- });
- repeatFns.sort(function(a, b) { return a.nextTime - b.nextTime;});
-
- nextRepeatId++;
- return promise;
- };
- /**
- * @ngdoc method
- * @name $interval#cancel
- *
- * @description
- * Cancels a task associated with the `promise`.
- *
- * @param {promise} promise A promise from calling the `$interval` function.
- * @returns {boolean} Returns `true` if the task was successfully cancelled.
- */
- $interval.cancel = function(promise) {
- if (!promise) return false;
- var fnIndex;
-
- angular.forEach(repeatFns, function(fn, index) {
- if (fn.id === promise.$$intervalId) fnIndex = index;
- });
-
- if (fnIndex !== undefined) {
- repeatFns[fnIndex].deferred.reject('canceled');
- repeatFns.splice(fnIndex, 1);
- return true;
- }
-
- return false;
- };
-
- /**
- * @ngdoc method
- * @name $interval#flush
- * @description
- *
- * Runs interval tasks scheduled to be run in the next `millis` milliseconds.
- *
- * @param {number=} millis maximum timeout amount to flush up until.
- *
- * @return {number} The amount of time moved forward.
- */
- $interval.flush = function(millis) {
- now += millis;
- while (repeatFns.length && repeatFns[0].nextTime <= now) {
- var task = repeatFns[0];
- task.fn();
- task.nextTime += task.delay;
- repeatFns.sort(function(a, b) { return a.nextTime - b.nextTime;});
- }
- return millis;
- };
-
- return $interval;
- }];
-};
-
-
-/* jshint -W101 */
-/* The R_ISO8061_STR regex is never going to fit into the 100 char limit!
- * This directive should go inside the anonymous function but a bug in JSHint means that it would
- * not be enacted early enough to prevent the warning.
- */
-var R_ISO8061_STR = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?:\:?(\d\d)(?:\:?(\d\d)(?:\.(\d{3}))?)?)?(Z|([+-])(\d\d):?(\d\d)))?$/;
-
-function jsonStringToDate(string) {
- var match;
- if (match = string.match(R_ISO8061_STR)) {
- var date = new Date(0),
- tzHour = 0,
- tzMin = 0;
- if (match[9]) {
- tzHour = int(match[9] + match[10]);
- tzMin = int(match[9] + match[11]);
- }
- date.setUTCFullYear(int(match[1]), int(match[2]) - 1, int(match[3]));
- date.setUTCHours(int(match[4] || 0) - tzHour,
- int(match[5] || 0) - tzMin,
- int(match[6] || 0),
- int(match[7] || 0));
- return date;
- }
- return string;
-}
-
-function int(str) {
- return parseInt(str, 10);
-}
-
-function padNumber(num, digits, trim) {
- var neg = '';
- if (num < 0) {
- neg = '-';
- num = -num;
- }
- num = '' + num;
- while (num.length < digits) num = '0' + num;
- if (trim)
- num = num.substr(num.length - digits);
- return neg + num;
-}
-
-
-/**
- * @ngdoc type
- * @name angular.mock.TzDate
- * @description
- *
- * *NOTE*: this is not an injectable instance, just a globally available mock class of `Date`.
- *
- * Mock of the Date type which has its timezone specified via constructor arg.
- *
- * The main purpose is to create Date-like instances with timezone fixed to the specified timezone
- * offset, so that we can test code that depends on local timezone settings without dependency on
- * the time zone settings of the machine where the code is running.
- *
- * @param {number} offset Offset of the *desired* timezone in hours (fractions will be honored)
- * @param {(number|string)} timestamp Timestamp representing the desired time in *UTC*
- *
- * @example
- * !!!! WARNING !!!!!
- * This is not a complete Date object so only methods that were implemented can be called safely.
- * To make matters worse, TzDate instances inherit stuff from Date via a prototype.
- *
- * We do our best to intercept calls to "unimplemented" methods, but since the list of methods is
- * incomplete we might be missing some non-standard methods. This can result in errors like:
- * "Date.prototype.foo called on incompatible Object".
- *
- * ```js
- * var newYearInBratislava = new TzDate(-1, '2009-12-31T23:00:00Z');
- * newYearInBratislava.getTimezoneOffset() => -60;
- * newYearInBratislava.getFullYear() => 2010;
- * newYearInBratislava.getMonth() => 0;
- * newYearInBratislava.getDate() => 1;
- * newYearInBratislava.getHours() => 0;
- * newYearInBratislava.getMinutes() => 0;
- * newYearInBratislava.getSeconds() => 0;
- * ```
- *
- */
-angular.mock.TzDate = function(offset, timestamp) {
- var self = new Date(0);
- if (angular.isString(timestamp)) {
- var tsStr = timestamp;
-
- self.origDate = jsonStringToDate(timestamp);
-
- timestamp = self.origDate.getTime();
- if (isNaN(timestamp))
- throw {
- name: "Illegal Argument",
- message: "Arg '" + tsStr + "' passed into TzDate constructor is not a valid date string"
- };
- } else {
- self.origDate = new Date(timestamp);
- }
-
- var localOffset = new Date(timestamp).getTimezoneOffset();
- self.offsetDiff = localOffset * 60 * 1000 - offset * 1000 * 60 * 60;
- self.date = new Date(timestamp + self.offsetDiff);
-
- self.getTime = function() {
- return self.date.getTime() - self.offsetDiff;
- };
-
- self.toLocaleDateString = function() {
- return self.date.toLocaleDateString();
- };
-
- self.getFullYear = function() {
- return self.date.getFullYear();
- };
-
- self.getMonth = function() {
- return self.date.getMonth();
- };
-
- self.getDate = function() {
- return self.date.getDate();
- };
-
- self.getHours = function() {
- return self.date.getHours();
- };
-
- self.getMinutes = function() {
- return self.date.getMinutes();
- };
-
- self.getSeconds = function() {
- return self.date.getSeconds();
- };
-
- self.getMilliseconds = function() {
- return self.date.getMilliseconds();
- };
-
- self.getTimezoneOffset = function() {
- return offset * 60;
- };
-
- self.getUTCFullYear = function() {
- return self.origDate.getUTCFullYear();
- };
-
- self.getUTCMonth = function() {
- return self.origDate.getUTCMonth();
- };
-
- self.getUTCDate = function() {
- return self.origDate.getUTCDate();
- };
-
- self.getUTCHours = function() {
- return self.origDate.getUTCHours();
- };
-
- self.getUTCMinutes = function() {
- return self.origDate.getUTCMinutes();
- };
-
- self.getUTCSeconds = function() {
- return self.origDate.getUTCSeconds();
- };
-
- self.getUTCMilliseconds = function() {
- return self.origDate.getUTCMilliseconds();
- };
-
- self.getDay = function() {
- return self.date.getDay();
- };
-
- // provide this method only on browsers that already have it
- if (self.toISOString) {
- self.toISOString = function() {
- return padNumber(self.origDate.getUTCFullYear(), 4) + '-' +
- padNumber(self.origDate.getUTCMonth() + 1, 2) + '-' +
- padNumber(self.origDate.getUTCDate(), 2) + 'T' +
- padNumber(self.origDate.getUTCHours(), 2) + ':' +
- padNumber(self.origDate.getUTCMinutes(), 2) + ':' +
- padNumber(self.origDate.getUTCSeconds(), 2) + '.' +
- padNumber(self.origDate.getUTCMilliseconds(), 3) + 'Z';
- };
- }
-
- //hide all methods not implemented in this mock that the Date prototype exposes
- var unimplementedMethods = ['getUTCDay',
- 'getYear', 'setDate', 'setFullYear', 'setHours', 'setMilliseconds',
- 'setMinutes', 'setMonth', 'setSeconds', 'setTime', 'setUTCDate', 'setUTCFullYear',
- 'setUTCHours', 'setUTCMilliseconds', 'setUTCMinutes', 'setUTCMonth', 'setUTCSeconds',
- 'setYear', 'toDateString', 'toGMTString', 'toJSON', 'toLocaleFormat', 'toLocaleString',
- 'toLocaleTimeString', 'toSource', 'toString', 'toTimeString', 'toUTCString', 'valueOf'];
-
- angular.forEach(unimplementedMethods, function(methodName) {
- self[methodName] = function() {
- throw new Error("Method '" + methodName + "' is not implemented in the TzDate mock");
- };
- });
-
- return self;
-};
-
-//make "tzDateInstance instanceof Date" return true
-angular.mock.TzDate.prototype = Date.prototype;
-/* jshint +W101 */
-
-angular.mock.animate = angular.module('ngAnimateMock', ['ng'])
-
- .config(['$provide', function($provide) {
-
- var reflowQueue = [];
- $provide.value('$$animateReflow', function(fn) {
- var index = reflowQueue.length;
- reflowQueue.push(fn);
- return function cancel() {
- reflowQueue.splice(index, 1);
- };
- });
-
- $provide.decorator('$animate', ['$delegate', '$$asyncCallback', '$timeout', '$browser',
- function($delegate, $$asyncCallback, $timeout, $browser) {
- var animate = {
- queue: [],
- cancel: $delegate.cancel,
- enabled: $delegate.enabled,
- triggerCallbackEvents: function() {
- $$asyncCallback.flush();
- },
- triggerCallbackPromise: function() {
- $timeout.flush(0);
- },
- triggerCallbacks: function() {
- this.triggerCallbackEvents();
- this.triggerCallbackPromise();
- },
- triggerReflow: function() {
- angular.forEach(reflowQueue, function(fn) {
- fn();
- });
- reflowQueue = [];
- }
- };
-
- angular.forEach(
- ['animate','enter','leave','move','addClass','removeClass','setClass'], function(method) {
- animate[method] = function() {
- animate.queue.push({
- event: method,
- element: arguments[0],
- options: arguments[arguments.length - 1],
- args: arguments
- });
- return $delegate[method].apply($delegate, arguments);
- };
- });
-
- return animate;
- }]);
-
- }]);
-
-
-/**
- * @ngdoc function
- * @name angular.mock.dump
- * @description
- *
- * *NOTE*: this is not an injectable instance, just a globally available function.
- *
- * Method for serializing common angular objects (scope, elements, etc..) into strings, useful for
- * debugging.
- *
- * This method is also available on window, where it can be used to display objects on debug
- * console.
- *
- * @param {*} object - any object to turn into string.
- * @return {string} a serialized string of the argument
- */
-angular.mock.dump = function(object) {
- return serialize(object);
-
- function serialize(object) {
- var out;
-
- if (angular.isElement(object)) {
- object = angular.element(object);
- out = angular.element('');
- angular.forEach(object, function(element) {
- out.append(angular.element(element).clone());
- });
- out = out.html();
- } else if (angular.isArray(object)) {
- out = [];
- angular.forEach(object, function(o) {
- out.push(serialize(o));
- });
- out = '[ ' + out.join(', ') + ' ]';
- } else if (angular.isObject(object)) {
- if (angular.isFunction(object.$eval) && angular.isFunction(object.$apply)) {
- out = serializeScope(object);
- } else if (object instanceof Error) {
- out = object.stack || ('' + object.name + ': ' + object.message);
- } else {
- // TODO(i): this prevents methods being logged,
- // we should have a better way to serialize objects
- out = angular.toJson(object, true);
- }
- } else {
- out = String(object);
- }
-
- return out;
- }
-
- function serializeScope(scope, offset) {
- offset = offset || ' ';
- var log = [offset + 'Scope(' + scope.$id + '): {'];
- for (var key in scope) {
- if (Object.prototype.hasOwnProperty.call(scope, key) && !key.match(/^(\$|this)/)) {
- log.push(' ' + key + ': ' + angular.toJson(scope[key]));
- }
- }
- var child = scope.$$childHead;
- while (child) {
- log.push(serializeScope(child, offset + ' '));
- child = child.$$nextSibling;
- }
- log.push('}');
- return log.join('\n' + offset);
- }
-};
-
-/**
- * @ngdoc service
- * @name $httpBackend
- * @description
- * Fake HTTP backend implementation suitable for unit testing applications that use the
- * {@link ng.$http $http service}.
- *
- * *Note*: For fake HTTP backend implementation suitable for end-to-end testing or backend-less
- * development please see {@link ngMockE2E.$httpBackend e2e $httpBackend mock}.
- *
- * During unit testing, we want our unit tests to run quickly and have no external dependencies so
- * we don’t want to send [XHR](https://developer.mozilla.org/en/xmlhttprequest) or
- * [JSONP](http://en.wikipedia.org/wiki/JSONP) requests to a real server. All we really need is
- * to verify whether a certain request has been sent or not, or alternatively just let the
- * application make requests, respond with pre-trained responses and assert that the end result is
- * what we expect it to be.
- *
- * This mock implementation can be used to respond with static or dynamic responses via the
- * `expect` and `when` apis and their shortcuts (`expectGET`, `whenPOST`, etc).
- *
- * When an Angular application needs some data from a server, it calls the $http service, which
- * sends the request to a real server using $httpBackend service. With dependency injection, it is
- * easy to inject $httpBackend mock (which has the same API as $httpBackend) and use it to verify
- * the requests and respond with some testing data without sending a request to a real server.
- *
- * There are two ways to specify what test data should be returned as http responses by the mock
- * backend when the code under test makes http requests:
- *
- * - `$httpBackend.expect` - specifies a request expectation
- * - `$httpBackend.when` - specifies a backend definition
- *
- *
- * # Request Expectations vs Backend Definitions
- *
- * Request expectations provide a way to make assertions about requests made by the application and
- * to define responses for those requests. The test will fail if the expected requests are not made
- * or they are made in the wrong order.
- *
- * Backend definitions allow you to define a fake backend for your application which doesn't assert
- * if a particular request was made or not, it just returns a trained response if a request is made.
- * The test will pass whether or not the request gets made during testing.
- *
- *
- *
- *
Request expectations
Backend definitions
- *
- *
Syntax
- *
.expect(...).respond(...)
- *
.when(...).respond(...)
- *
- *
- *
Typical usage
- *
strict unit tests
- *
loose (black-box) unit testing
- *
- *
- *
Fulfills multiple requests
- *
NO
- *
YES
- *
- *
- *
Order of requests matters
- *
YES
- *
NO
- *
- *
- *
Request required
- *
YES
- *
NO
- *
- *
- *
Response required
- *
optional (see below)
- *
YES
- *
- *
- *
- * In cases where both backend definitions and request expectations are specified during unit
- * testing, the request expectations are evaluated first.
- *
- * If a request expectation has no response specified, the algorithm will search your backend
- * definitions for an appropriate response.
- *
- * If a request didn't match any expectation or if the expectation doesn't have the response
- * defined, the backend definitions are evaluated in sequential order to see if any of them match
- * the request. The response from the first matched definition is returned.
- *
- *
- * # Flushing HTTP requests
- *
- * The $httpBackend used in production always responds to requests asynchronously. If we preserved
- * this behavior in unit testing, we'd have to create async unit tests, which are hard to write,
- * to follow and to maintain. But neither can the testing mock respond synchronously; that would
- * change the execution of the code under test. For this reason, the mock $httpBackend has a
- * `flush()` method, which allows the test to explicitly flush pending requests. This preserves
- * the async api of the backend, while allowing the test to execute synchronously.
- *
- *
- * # Unit testing with mock $httpBackend
- * The following code shows how to setup and use the mock backend when unit testing a controller.
- * First we create the controller under test:
- *
- ```js
- // The module code
- angular
- .module('MyApp', [])
- .controller('MyController', MyController);
-
- // The controller code
- function MyController($scope, $http) {
- var authToken;
-
- $http.get('/auth.py').success(function(data, status, headers) {
- authToken = headers('A-Token');
- $scope.user = data;
- });
-
- $scope.saveMessage = function(message) {
- var headers = { 'Authorization': authToken };
- $scope.status = 'Saving...';
-
- $http.post('/add-msg.py', message, { headers: headers } ).success(function(response) {
- $scope.status = '';
- }).error(function() {
- $scope.status = 'ERROR!';
- });
- };
- }
- ```
- *
- * Now we setup the mock backend and create the test specs:
- *
- ```js
- // testing controller
- describe('MyController', function() {
- var $httpBackend, $rootScope, createController, authRequestHandler;
-
- // Set up the module
- beforeEach(module('MyApp'));
-
- beforeEach(inject(function($injector) {
- // Set up the mock http service responses
- $httpBackend = $injector.get('$httpBackend');
- // backend definition common for all tests
- authRequestHandler = $httpBackend.when('GET', '/auth.py')
- .respond({userId: 'userX'}, {'A-Token': 'xxx'});
-
- // Get hold of a scope (i.e. the root scope)
- $rootScope = $injector.get('$rootScope');
- // The $controller service is used to create instances of controllers
- var $controller = $injector.get('$controller');
-
- createController = function() {
- return $controller('MyController', {'$scope' : $rootScope });
- };
- }));
-
-
- afterEach(function() {
- $httpBackend.verifyNoOutstandingExpectation();
- $httpBackend.verifyNoOutstandingRequest();
- });
-
-
- it('should fetch authentication token', function() {
- $httpBackend.expectGET('/auth.py');
- var controller = createController();
- $httpBackend.flush();
- });
-
-
- it('should fail authentication', function() {
-
- // Notice how you can change the response even after it was set
- authRequestHandler.respond(401, '');
-
- $httpBackend.expectGET('/auth.py');
- var controller = createController();
- $httpBackend.flush();
- expect($rootScope.status).toBe('Failed...');
- });
-
-
- it('should send msg to server', function() {
- var controller = createController();
- $httpBackend.flush();
-
- // now you don’t care about the authentication, but
- // the controller will still send the request and
- // $httpBackend will respond without you having to
- // specify the expectation and response for this request
-
- $httpBackend.expectPOST('/add-msg.py', 'message content').respond(201, '');
- $rootScope.saveMessage('message content');
- expect($rootScope.status).toBe('Saving...');
- $httpBackend.flush();
- expect($rootScope.status).toBe('');
- });
-
-
- it('should send auth header', function() {
- var controller = createController();
- $httpBackend.flush();
-
- $httpBackend.expectPOST('/add-msg.py', undefined, function(headers) {
- // check if the header was send, if it wasn't the expectation won't
- // match the request and the test will fail
- return headers['Authorization'] == 'xxx';
- }).respond(201, '');
-
- $rootScope.saveMessage('whatever');
- $httpBackend.flush();
- });
- });
- ```
- */
-angular.mock.$HttpBackendProvider = function() {
- this.$get = ['$rootScope', createHttpBackendMock];
-};
-
-/**
- * General factory function for $httpBackend mock.
- * Returns instance for unit testing (when no arguments specified):
- * - passing through is disabled
- * - auto flushing is disabled
- *
- * Returns instance for e2e testing (when `$delegate` and `$browser` specified):
- * - passing through (delegating request to real backend) is enabled
- * - auto flushing is enabled
- *
- * @param {Object=} $delegate Real $httpBackend instance (allow passing through if specified)
- * @param {Object=} $browser Auto-flushing enabled if specified
- * @return {Object} Instance of $httpBackend mock
- */
-function createHttpBackendMock($rootScope, $delegate, $browser) {
- var definitions = [],
- expectations = [],
- responses = [],
- responsesPush = angular.bind(responses, responses.push),
- copy = angular.copy;
-
- function createResponse(status, data, headers, statusText) {
- if (angular.isFunction(status)) return status;
-
- return function() {
- return angular.isNumber(status)
- ? [status, data, headers, statusText]
- : [200, status, data, headers];
- };
- }
-
- // TODO(vojta): change params to: method, url, data, headers, callback
- function $httpBackend(method, url, data, callback, headers, timeout, withCredentials) {
- var xhr = new MockXhr(),
- expectation = expectations[0],
- wasExpected = false;
-
- function prettyPrint(data) {
- return (angular.isString(data) || angular.isFunction(data) || data instanceof RegExp)
- ? data
- : angular.toJson(data);
- }
-
- function wrapResponse(wrapped) {
- if (!$browser && timeout && timeout.then) timeout.then(handleTimeout);
-
- return handleResponse;
-
- function handleResponse() {
- var response = wrapped.response(method, url, data, headers);
- xhr.$$respHeaders = response[2];
- callback(copy(response[0]), copy(response[1]), xhr.getAllResponseHeaders(),
- copy(response[3] || ''));
- }
-
- function handleTimeout() {
- for (var i = 0, ii = responses.length; i < ii; i++) {
- if (responses[i] === handleResponse) {
- responses.splice(i, 1);
- callback(-1, undefined, '');
- break;
- }
- }
- }
- }
-
- if (expectation && expectation.match(method, url)) {
- if (!expectation.matchData(data))
- throw new Error('Expected ' + expectation + ' with different data\n' +
- 'EXPECTED: ' + prettyPrint(expectation.data) + '\nGOT: ' + data);
-
- if (!expectation.matchHeaders(headers))
- throw new Error('Expected ' + expectation + ' with different headers\n' +
- 'EXPECTED: ' + prettyPrint(expectation.headers) + '\nGOT: ' +
- prettyPrint(headers));
-
- expectations.shift();
-
- if (expectation.response) {
- responses.push(wrapResponse(expectation));
- return;
- }
- wasExpected = true;
- }
-
- var i = -1, definition;
- while ((definition = definitions[++i])) {
- if (definition.match(method, url, data, headers || {})) {
- if (definition.response) {
- // if $browser specified, we do auto flush all requests
- ($browser ? $browser.defer : responsesPush)(wrapResponse(definition));
- } else if (definition.passThrough) {
- $delegate(method, url, data, callback, headers, timeout, withCredentials);
- } else throw new Error('No response defined !');
- return;
- }
- }
- throw wasExpected ?
- new Error('No response defined !') :
- new Error('Unexpected request: ' + method + ' ' + url + '\n' +
- (expectation ? 'Expected ' + expectation : 'No more request expected'));
- }
-
- /**
- * @ngdoc method
- * @name $httpBackend#when
- * @description
- * Creates a new backend definition.
- *
- * @param {string} method HTTP method.
- * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
- * and returns true if the url match the current definition.
- * @param {(string|RegExp|function(string))=} data HTTP request body or function that receives
- * data string and returns true if the data is as expected.
- * @param {(Object|function(Object))=} headers HTTP headers or function that receives http header
- * object and returns true if the headers match the current definition.
- * @returns {requestHandler} Returns an object with `respond` method that controls how a matched
- * request is handled. You can save this object for later use and invoke `respond` again in
- * order to change how a matched request is handled.
- *
- * - respond –
- * `{function([status,] data[, headers, statusText])
- * | function(function(method, url, data, headers)}`
- * – The respond method takes a set of static data to be returned or a function that can
- * return an array containing response status (number), response data (string), response
- * headers (Object), and the text for the status (string). The respond method returns the
- * `requestHandler` object for possible overrides.
- */
- $httpBackend.when = function(method, url, data, headers) {
- var definition = new MockHttpExpectation(method, url, data, headers),
- chain = {
- respond: function(status, data, headers, statusText) {
- definition.passThrough = undefined;
- definition.response = createResponse(status, data, headers, statusText);
- return chain;
- }
- };
-
- if ($browser) {
- chain.passThrough = function() {
- definition.response = undefined;
- definition.passThrough = true;
- return chain;
- };
- }
-
- definitions.push(definition);
- return chain;
- };
-
- /**
- * @ngdoc method
- * @name $httpBackend#whenGET
- * @description
- * Creates a new backend definition for GET requests. For more info see `when()`.
- *
- * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
- * and returns true if the url match the current definition.
- * @param {(Object|function(Object))=} headers HTTP headers.
- * @returns {requestHandler} Returns an object with `respond` method that control how a matched
- * request is handled. You can save this object for later use and invoke `respond` again in
- * order to change how a matched request is handled.
- */
-
- /**
- * @ngdoc method
- * @name $httpBackend#whenHEAD
- * @description
- * Creates a new backend definition for HEAD requests. For more info see `when()`.
- *
- * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
- * and returns true if the url match the current definition.
- * @param {(Object|function(Object))=} headers HTTP headers.
- * @returns {requestHandler} Returns an object with `respond` method that control how a matched
- * request is handled. You can save this object for later use and invoke `respond` again in
- * order to change how a matched request is handled.
- */
-
- /**
- * @ngdoc method
- * @name $httpBackend#whenDELETE
- * @description
- * Creates a new backend definition for DELETE requests. For more info see `when()`.
- *
- * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
- * and returns true if the url match the current definition.
- * @param {(Object|function(Object))=} headers HTTP headers.
- * @returns {requestHandler} Returns an object with `respond` method that control how a matched
- * request is handled. You can save this object for later use and invoke `respond` again in
- * order to change how a matched request is handled.
- */
-
- /**
- * @ngdoc method
- * @name $httpBackend#whenPOST
- * @description
- * Creates a new backend definition for POST requests. For more info see `when()`.
- *
- * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
- * and returns true if the url match the current definition.
- * @param {(string|RegExp|function(string))=} data HTTP request body or function that receives
- * data string and returns true if the data is as expected.
- * @param {(Object|function(Object))=} headers HTTP headers.
- * @returns {requestHandler} Returns an object with `respond` method that control how a matched
- * request is handled. You can save this object for later use and invoke `respond` again in
- * order to change how a matched request is handled.
- */
-
- /**
- * @ngdoc method
- * @name $httpBackend#whenPUT
- * @description
- * Creates a new backend definition for PUT requests. For more info see `when()`.
- *
- * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
- * and returns true if the url match the current definition.
- * @param {(string|RegExp|function(string))=} data HTTP request body or function that receives
- * data string and returns true if the data is as expected.
- * @param {(Object|function(Object))=} headers HTTP headers.
- * @returns {requestHandler} Returns an object with `respond` method that control how a matched
- * request is handled. You can save this object for later use and invoke `respond` again in
- * order to change how a matched request is handled.
- */
-
- /**
- * @ngdoc method
- * @name $httpBackend#whenJSONP
- * @description
- * Creates a new backend definition for JSONP requests. For more info see `when()`.
- *
- * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
- * and returns true if the url match the current definition.
- * @returns {requestHandler} Returns an object with `respond` method that control how a matched
- * request is handled. You can save this object for later use and invoke `respond` again in
- * order to change how a matched request is handled.
- */
- createShortMethods('when');
-
-
- /**
- * @ngdoc method
- * @name $httpBackend#expect
- * @description
- * Creates a new request expectation.
- *
- * @param {string} method HTTP method.
- * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
- * and returns true if the url match the current definition.
- * @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that
- * receives data string and returns true if the data is as expected, or Object if request body
- * is in JSON format.
- * @param {(Object|function(Object))=} headers HTTP headers or function that receives http header
- * object and returns true if the headers match the current expectation.
- * @returns {requestHandler} Returns an object with `respond` method that control how a matched
- * request is handled. You can save this object for later use and invoke `respond` again in
- * order to change how a matched request is handled.
- *
- * - respond –
- * `{function([status,] data[, headers, statusText])
- * | function(function(method, url, data, headers)}`
- * – The respond method takes a set of static data to be returned or a function that can
- * return an array containing response status (number), response data (string), response
- * headers (Object), and the text for the status (string). The respond method returns the
- * `requestHandler` object for possible overrides.
- */
- $httpBackend.expect = function(method, url, data, headers) {
- var expectation = new MockHttpExpectation(method, url, data, headers),
- chain = {
- respond: function(status, data, headers, statusText) {
- expectation.response = createResponse(status, data, headers, statusText);
- return chain;
- }
- };
-
- expectations.push(expectation);
- return chain;
- };
-
-
- /**
- * @ngdoc method
- * @name $httpBackend#expectGET
- * @description
- * Creates a new request expectation for GET requests. For more info see `expect()`.
- *
- * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
- * and returns true if the url match the current definition.
- * @param {Object=} headers HTTP headers.
- * @returns {requestHandler} Returns an object with `respond` method that control how a matched
- * request is handled. You can save this object for later use and invoke `respond` again in
- * order to change how a matched request is handled. See #expect for more info.
- */
-
- /**
- * @ngdoc method
- * @name $httpBackend#expectHEAD
- * @description
- * Creates a new request expectation for HEAD requests. For more info see `expect()`.
- *
- * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
- * and returns true if the url match the current definition.
- * @param {Object=} headers HTTP headers.
- * @returns {requestHandler} Returns an object with `respond` method that control how a matched
- * request is handled. You can save this object for later use and invoke `respond` again in
- * order to change how a matched request is handled.
- */
-
- /**
- * @ngdoc method
- * @name $httpBackend#expectDELETE
- * @description
- * Creates a new request expectation for DELETE requests. For more info see `expect()`.
- *
- * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
- * and returns true if the url match the current definition.
- * @param {Object=} headers HTTP headers.
- * @returns {requestHandler} Returns an object with `respond` method that control how a matched
- * request is handled. You can save this object for later use and invoke `respond` again in
- * order to change how a matched request is handled.
- */
-
- /**
- * @ngdoc method
- * @name $httpBackend#expectPOST
- * @description
- * Creates a new request expectation for POST requests. For more info see `expect()`.
- *
- * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
- * and returns true if the url match the current definition.
- * @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that
- * receives data string and returns true if the data is as expected, or Object if request body
- * is in JSON format.
- * @param {Object=} headers HTTP headers.
- * @returns {requestHandler} Returns an object with `respond` method that control how a matched
- * request is handled. You can save this object for later use and invoke `respond` again in
- * order to change how a matched request is handled.
- */
-
- /**
- * @ngdoc method
- * @name $httpBackend#expectPUT
- * @description
- * Creates a new request expectation for PUT requests. For more info see `expect()`.
- *
- * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
- * and returns true if the url match the current definition.
- * @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that
- * receives data string and returns true if the data is as expected, or Object if request body
- * is in JSON format.
- * @param {Object=} headers HTTP headers.
- * @returns {requestHandler} Returns an object with `respond` method that control how a matched
- * request is handled. You can save this object for later use and invoke `respond` again in
- * order to change how a matched request is handled.
- */
-
- /**
- * @ngdoc method
- * @name $httpBackend#expectPATCH
- * @description
- * Creates a new request expectation for PATCH requests. For more info see `expect()`.
- *
- * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
- * and returns true if the url match the current definition.
- * @param {(string|RegExp|function(string)|Object)=} data HTTP request body or function that
- * receives data string and returns true if the data is as expected, or Object if request body
- * is in JSON format.
- * @param {Object=} headers HTTP headers.
- * @returns {requestHandler} Returns an object with `respond` method that control how a matched
- * request is handled. You can save this object for later use and invoke `respond` again in
- * order to change how a matched request is handled.
- */
-
- /**
- * @ngdoc method
- * @name $httpBackend#expectJSONP
- * @description
- * Creates a new request expectation for JSONP requests. For more info see `expect()`.
- *
- * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
- * and returns true if the url match the current definition.
- * @returns {requestHandler} Returns an object with `respond` method that control how a matched
- * request is handled. You can save this object for later use and invoke `respond` again in
- * order to change how a matched request is handled.
- */
- createShortMethods('expect');
-
-
- /**
- * @ngdoc method
- * @name $httpBackend#flush
- * @description
- * Flushes all pending requests using the trained responses.
- *
- * @param {number=} count Number of responses to flush (in the order they arrived). If undefined,
- * all pending requests will be flushed. If there are no pending requests when the flush method
- * is called an exception is thrown (as this typically a sign of programming error).
- */
- $httpBackend.flush = function(count, digest) {
- if (digest !== false) $rootScope.$digest();
- if (!responses.length) throw new Error('No pending request to flush !');
-
- if (angular.isDefined(count) && count !== null) {
- while (count--) {
- if (!responses.length) throw new Error('No more pending request to flush !');
- responses.shift()();
- }
- } else {
- while (responses.length) {
- responses.shift()();
- }
- }
- $httpBackend.verifyNoOutstandingExpectation(digest);
- };
-
-
- /**
- * @ngdoc method
- * @name $httpBackend#verifyNoOutstandingExpectation
- * @description
- * Verifies that all of the requests defined via the `expect` api were made. If any of the
- * requests were not made, verifyNoOutstandingExpectation throws an exception.
- *
- * Typically, you would call this method following each test case that asserts requests using an
- * "afterEach" clause.
- *
- * ```js
- * afterEach($httpBackend.verifyNoOutstandingExpectation);
- * ```
- */
- $httpBackend.verifyNoOutstandingExpectation = function(digest) {
- if (digest !== false) $rootScope.$digest();
- if (expectations.length) {
- throw new Error('Unsatisfied requests: ' + expectations.join(', '));
- }
- };
-
-
- /**
- * @ngdoc method
- * @name $httpBackend#verifyNoOutstandingRequest
- * @description
- * Verifies that there are no outstanding requests that need to be flushed.
- *
- * Typically, you would call this method following each test case that asserts requests using an
- * "afterEach" clause.
- *
- * ```js
- * afterEach($httpBackend.verifyNoOutstandingRequest);
- * ```
- */
- $httpBackend.verifyNoOutstandingRequest = function() {
- if (responses.length) {
- throw new Error('Unflushed requests: ' + responses.length);
- }
- };
-
-
- /**
- * @ngdoc method
- * @name $httpBackend#resetExpectations
- * @description
- * Resets all request expectations, but preserves all backend definitions. Typically, you would
- * call resetExpectations during a multiple-phase test when you want to reuse the same instance of
- * $httpBackend mock.
- */
- $httpBackend.resetExpectations = function() {
- expectations.length = 0;
- responses.length = 0;
- };
-
- return $httpBackend;
-
-
- function createShortMethods(prefix) {
- angular.forEach(['GET', 'DELETE', 'JSONP', 'HEAD'], function(method) {
- $httpBackend[prefix + method] = function(url, headers) {
- return $httpBackend[prefix](method, url, undefined, headers);
- };
- });
-
- angular.forEach(['PUT', 'POST', 'PATCH'], function(method) {
- $httpBackend[prefix + method] = function(url, data, headers) {
- return $httpBackend[prefix](method, url, data, headers);
- };
- });
- }
-}
-
-function MockHttpExpectation(method, url, data, headers) {
-
- this.data = data;
- this.headers = headers;
-
- this.match = function(m, u, d, h) {
- if (method != m) return false;
- if (!this.matchUrl(u)) return false;
- if (angular.isDefined(d) && !this.matchData(d)) return false;
- if (angular.isDefined(h) && !this.matchHeaders(h)) return false;
- return true;
- };
-
- this.matchUrl = function(u) {
- if (!url) return true;
- if (angular.isFunction(url.test)) return url.test(u);
- if (angular.isFunction(url)) return url(u);
- return url == u;
- };
-
- this.matchHeaders = function(h) {
- if (angular.isUndefined(headers)) return true;
- if (angular.isFunction(headers)) return headers(h);
- return angular.equals(headers, h);
- };
-
- this.matchData = function(d) {
- if (angular.isUndefined(data)) return true;
- if (data && angular.isFunction(data.test)) return data.test(d);
- if (data && angular.isFunction(data)) return data(d);
- if (data && !angular.isString(data)) {
- return angular.equals(angular.fromJson(angular.toJson(data)), angular.fromJson(d));
- }
- return data == d;
- };
-
- this.toString = function() {
- return method + ' ' + url;
- };
-}
-
-function createMockXhr() {
- return new MockXhr();
-}
-
-function MockXhr() {
-
- // hack for testing $http, $httpBackend
- MockXhr.$$lastInstance = this;
-
- this.open = function(method, url, async) {
- this.$$method = method;
- this.$$url = url;
- this.$$async = async;
- this.$$reqHeaders = {};
- this.$$respHeaders = {};
- };
-
- this.send = function(data) {
- this.$$data = data;
- };
-
- this.setRequestHeader = function(key, value) {
- this.$$reqHeaders[key] = value;
- };
-
- this.getResponseHeader = function(name) {
- // the lookup must be case insensitive,
- // that's why we try two quick lookups first and full scan last
- var header = this.$$respHeaders[name];
- if (header) return header;
-
- name = angular.lowercase(name);
- header = this.$$respHeaders[name];
- if (header) return header;
-
- header = undefined;
- angular.forEach(this.$$respHeaders, function(headerVal, headerName) {
- if (!header && angular.lowercase(headerName) == name) header = headerVal;
- });
- return header;
- };
-
- this.getAllResponseHeaders = function() {
- var lines = [];
-
- angular.forEach(this.$$respHeaders, function(value, key) {
- lines.push(key + ': ' + value);
- });
- return lines.join('\n');
- };
-
- this.abort = angular.noop;
-}
-
-
-/**
- * @ngdoc service
- * @name $timeout
- * @description
- *
- * This service is just a simple decorator for {@link ng.$timeout $timeout} service
- * that adds a "flush" and "verifyNoPendingTasks" methods.
- */
-
-angular.mock.$TimeoutDecorator = ['$delegate', '$browser', function($delegate, $browser) {
-
- /**
- * @ngdoc method
- * @name $timeout#flush
- * @description
- *
- * Flushes the queue of pending tasks.
- *
- * @param {number=} delay maximum timeout amount to flush up until
- */
- $delegate.flush = function(delay) {
- $browser.defer.flush(delay);
- };
-
- /**
- * @ngdoc method
- * @name $timeout#verifyNoPendingTasks
- * @description
- *
- * Verifies that there are no pending tasks that need to be flushed.
- */
- $delegate.verifyNoPendingTasks = function() {
- if ($browser.deferredFns.length) {
- throw new Error('Deferred tasks to flush (' + $browser.deferredFns.length + '): ' +
- formatPendingTasksAsString($browser.deferredFns));
- }
- };
-
- function formatPendingTasksAsString(tasks) {
- var result = [];
- angular.forEach(tasks, function(task) {
- result.push('{id: ' + task.id + ', ' + 'time: ' + task.time + '}');
- });
-
- return result.join(', ');
- }
-
- return $delegate;
-}];
-
-angular.mock.$RAFDecorator = ['$delegate', function($delegate) {
- var queue = [];
- var rafFn = function(fn) {
- var index = queue.length;
- queue.push(fn);
- return function() {
- queue.splice(index, 1);
- };
- };
-
- rafFn.supported = $delegate.supported;
-
- rafFn.flush = function() {
- if (queue.length === 0) {
- throw new Error('No rAF callbacks present');
- }
-
- var length = queue.length;
- for (var i = 0; i < length; i++) {
- queue[i]();
- }
-
- queue = [];
- };
-
- return rafFn;
-}];
-
-angular.mock.$AsyncCallbackDecorator = ['$delegate', function($delegate) {
- var callbacks = [];
- var addFn = function(fn) {
- callbacks.push(fn);
- };
- addFn.flush = function() {
- angular.forEach(callbacks, function(fn) {
- fn();
- });
- callbacks = [];
- };
- return addFn;
-}];
-
-/**
- *
- */
-angular.mock.$RootElementProvider = function() {
- this.$get = function() {
- return angular.element('');
- };
-};
-
-/**
- * @ngdoc module
- * @name ngMock
- * @packageName angular-mocks
- * @description
- *
- * # ngMock
- *
- * The `ngMock` module provides support to inject and mock Angular services into unit tests.
- * In addition, ngMock also extends various core ng services such that they can be
- * inspected and controlled in a synchronous manner within test code.
- *
- *
- *
- *
- */
-angular.module('ngMock', ['ng']).provider({
- $browser: angular.mock.$BrowserProvider,
- $exceptionHandler: angular.mock.$ExceptionHandlerProvider,
- $log: angular.mock.$LogProvider,
- $interval: angular.mock.$IntervalProvider,
- $httpBackend: angular.mock.$HttpBackendProvider,
- $rootElement: angular.mock.$RootElementProvider
-}).config(['$provide', function($provide) {
- $provide.decorator('$timeout', angular.mock.$TimeoutDecorator);
- $provide.decorator('$$rAF', angular.mock.$RAFDecorator);
- $provide.decorator('$$asyncCallback', angular.mock.$AsyncCallbackDecorator);
- $provide.decorator('$rootScope', angular.mock.$RootScopeDecorator);
-}]);
-
-/**
- * @ngdoc module
- * @name ngMockE2E
- * @module ngMockE2E
- * @packageName angular-mocks
- * @description
- *
- * The `ngMockE2E` is an angular module which contains mocks suitable for end-to-end testing.
- * Currently there is only one mock present in this module -
- * the {@link ngMockE2E.$httpBackend e2e $httpBackend} mock.
- */
-angular.module('ngMockE2E', ['ng']).config(['$provide', function($provide) {
- $provide.decorator('$httpBackend', angular.mock.e2e.$httpBackendDecorator);
-}]);
-
-/**
- * @ngdoc service
- * @name $httpBackend
- * @module ngMockE2E
- * @description
- * Fake HTTP backend implementation suitable for end-to-end testing or backend-less development of
- * applications that use the {@link ng.$http $http service}.
- *
- * *Note*: For fake http backend implementation suitable for unit testing please see
- * {@link ngMock.$httpBackend unit-testing $httpBackend mock}.
- *
- * This implementation can be used to respond with static or dynamic responses via the `when` api
- * and its shortcuts (`whenGET`, `whenPOST`, etc) and optionally pass through requests to the
- * real $httpBackend for specific requests (e.g. to interact with certain remote apis or to fetch
- * templates from a webserver).
- *
- * As opposed to unit-testing, in an end-to-end testing scenario or in scenario when an application
- * is being developed with the real backend api replaced with a mock, it is often desirable for
- * certain category of requests to bypass the mock and issue a real http request (e.g. to fetch
- * templates or static files from the webserver). To configure the backend with this behavior
- * use the `passThrough` request handler of `when` instead of `respond`.
- *
- * Additionally, we don't want to manually have to flush mocked out requests like we do during unit
- * testing. For this reason the e2e $httpBackend flushes mocked out requests
- * automatically, closely simulating the behavior of the XMLHttpRequest object.
- *
- * To setup the application to run with this http backend, you have to create a module that depends
- * on the `ngMockE2E` and your application modules and defines the fake backend:
- *
- * ```js
- * myAppDev = angular.module('myAppDev', ['myApp', 'ngMockE2E']);
- * myAppDev.run(function($httpBackend) {
- * phones = [{name: 'phone1'}, {name: 'phone2'}];
- *
- * // returns the current list of phones
- * $httpBackend.whenGET('/phones').respond(phones);
- *
- * // adds a new phone to the phones array
- * $httpBackend.whenPOST('/phones').respond(function(method, url, data) {
- * var phone = angular.fromJson(data);
- * phones.push(phone);
- * return [200, phone, {}];
- * });
- * $httpBackend.whenGET(/^\/templates\//).passThrough();
- * //...
- * });
- * ```
- *
- * Afterwards, bootstrap your app with this new module.
- */
-
-/**
- * @ngdoc method
- * @name $httpBackend#when
- * @module ngMockE2E
- * @description
- * Creates a new backend definition.
- *
- * @param {string} method HTTP method.
- * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
- * and returns true if the url match the current definition.
- * @param {(string|RegExp)=} data HTTP request body.
- * @param {(Object|function(Object))=} headers HTTP headers or function that receives http header
- * object and returns true if the headers match the current definition.
- * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
- * control how a matched request is handled. You can save this object for later use and invoke
- * `respond` or `passThrough` again in order to change how a matched request is handled.
- *
- * - respond –
- * `{function([status,] data[, headers, statusText])
- * | function(function(method, url, data, headers)}`
- * – The respond method takes a set of static data to be returned or a function that can return
- * an array containing response status (number), response data (string), response headers
- * (Object), and the text for the status (string).
- * - passThrough – `{function()}` – Any request matching a backend definition with
- * `passThrough` handler will be passed through to the real backend (an XHR request will be made
- * to the server.)
- * - Both methods return the `requestHandler` object for possible overrides.
- */
-
-/**
- * @ngdoc method
- * @name $httpBackend#whenGET
- * @module ngMockE2E
- * @description
- * Creates a new backend definition for GET requests. For more info see `when()`.
- *
- * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
- * and returns true if the url match the current definition.
- * @param {(Object|function(Object))=} headers HTTP headers.
- * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
- * control how a matched request is handled. You can save this object for later use and invoke
- * `respond` or `passThrough` again in order to change how a matched request is handled.
- */
-
-/**
- * @ngdoc method
- * @name $httpBackend#whenHEAD
- * @module ngMockE2E
- * @description
- * Creates a new backend definition for HEAD requests. For more info see `when()`.
- *
- * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
- * and returns true if the url match the current definition.
- * @param {(Object|function(Object))=} headers HTTP headers.
- * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
- * control how a matched request is handled. You can save this object for later use and invoke
- * `respond` or `passThrough` again in order to change how a matched request is handled.
- */
-
-/**
- * @ngdoc method
- * @name $httpBackend#whenDELETE
- * @module ngMockE2E
- * @description
- * Creates a new backend definition for DELETE requests. For more info see `when()`.
- *
- * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
- * and returns true if the url match the current definition.
- * @param {(Object|function(Object))=} headers HTTP headers.
- * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
- * control how a matched request is handled. You can save this object for later use and invoke
- * `respond` or `passThrough` again in order to change how a matched request is handled.
- */
-
-/**
- * @ngdoc method
- * @name $httpBackend#whenPOST
- * @module ngMockE2E
- * @description
- * Creates a new backend definition for POST requests. For more info see `when()`.
- *
- * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
- * and returns true if the url match the current definition.
- * @param {(string|RegExp)=} data HTTP request body.
- * @param {(Object|function(Object))=} headers HTTP headers.
- * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
- * control how a matched request is handled. You can save this object for later use and invoke
- * `respond` or `passThrough` again in order to change how a matched request is handled.
- */
-
-/**
- * @ngdoc method
- * @name $httpBackend#whenPUT
- * @module ngMockE2E
- * @description
- * Creates a new backend definition for PUT requests. For more info see `when()`.
- *
- * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
- * and returns true if the url match the current definition.
- * @param {(string|RegExp)=} data HTTP request body.
- * @param {(Object|function(Object))=} headers HTTP headers.
- * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
- * control how a matched request is handled. You can save this object for later use and invoke
- * `respond` or `passThrough` again in order to change how a matched request is handled.
- */
-
-/**
- * @ngdoc method
- * @name $httpBackend#whenPATCH
- * @module ngMockE2E
- * @description
- * Creates a new backend definition for PATCH requests. For more info see `when()`.
- *
- * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
- * and returns true if the url match the current definition.
- * @param {(string|RegExp)=} data HTTP request body.
- * @param {(Object|function(Object))=} headers HTTP headers.
- * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
- * control how a matched request is handled. You can save this object for later use and invoke
- * `respond` or `passThrough` again in order to change how a matched request is handled.
- */
-
-/**
- * @ngdoc method
- * @name $httpBackend#whenJSONP
- * @module ngMockE2E
- * @description
- * Creates a new backend definition for JSONP requests. For more info see `when()`.
- *
- * @param {string|RegExp|function(string)} url HTTP url or function that receives the url
- * and returns true if the url match the current definition.
- * @returns {requestHandler} Returns an object with `respond` and `passThrough` methods that
- * control how a matched request is handled. You can save this object for later use and invoke
- * `respond` or `passThrough` again in order to change how a matched request is handled.
- */
-angular.mock.e2e = {};
-angular.mock.e2e.$httpBackendDecorator =
- ['$rootScope', '$delegate', '$browser', createHttpBackendMock];
-
-
-/**
- * @ngdoc type
- * @name $rootScope.Scope
- * @module ngMock
- * @description
- * {@link ng.$rootScope.Scope Scope} type decorated with helper methods useful for testing. These
- * methods are automatically available on any {@link ng.$rootScope.Scope Scope} instance when
- * `ngMock` module is loaded.
- *
- * In addition to all the regular `Scope` methods, the following helper methods are available:
- */
-angular.mock.$RootScopeDecorator = ['$delegate', function($delegate) {
-
- var $rootScopePrototype = Object.getPrototypeOf($delegate);
-
- $rootScopePrototype.$countChildScopes = countChildScopes;
- $rootScopePrototype.$countWatchers = countWatchers;
-
- return $delegate;
-
- // ------------------------------------------------------------------------------------------ //
-
- /**
- * @ngdoc method
- * @name $rootScope.Scope#$countChildScopes
- * @module ngMock
- * @description
- * Counts all the direct and indirect child scopes of the current scope.
- *
- * The current scope is excluded from the count. The count includes all isolate child scopes.
- *
- * @returns {number} Total number of child scopes.
- */
- function countChildScopes() {
- // jshint validthis: true
- var count = 0; // exclude the current scope
- var pendingChildHeads = [this.$$childHead];
- var currentScope;
-
- while (pendingChildHeads.length) {
- currentScope = pendingChildHeads.shift();
-
- while (currentScope) {
- count += 1;
- pendingChildHeads.push(currentScope.$$childHead);
- currentScope = currentScope.$$nextSibling;
- }
- }
-
- return count;
- }
-
-
- /**
- * @ngdoc method
- * @name $rootScope.Scope#$countWatchers
- * @module ngMock
- * @description
- * Counts all the watchers of direct and indirect child scopes of the current scope.
- *
- * The watchers of the current scope are included in the count and so are all the watchers of
- * isolate child scopes.
- *
- * @returns {number} Total number of watchers.
- */
- function countWatchers() {
- // jshint validthis: true
- var count = this.$$watchers ? this.$$watchers.length : 0; // include the current scope
- var pendingChildHeads = [this.$$childHead];
- var currentScope;
-
- while (pendingChildHeads.length) {
- currentScope = pendingChildHeads.shift();
-
- while (currentScope) {
- count += currentScope.$$watchers ? currentScope.$$watchers.length : 0;
- pendingChildHeads.push(currentScope.$$childHead);
- currentScope = currentScope.$$nextSibling;
- }
- }
-
- return count;
- }
-}];
-
-
-if (window.jasmine || window.mocha) {
-
- var currentSpec = null,
- isSpecRunning = function() {
- return !!currentSpec;
- };
-
-
- (window.beforeEach || window.setup)(function() {
- currentSpec = this;
- });
-
- (window.afterEach || window.teardown)(function() {
- var injector = currentSpec.$injector;
-
- angular.forEach(currentSpec.$modules, function(module) {
- if (module && module.$$hashKey) {
- module.$$hashKey = undefined;
- }
- });
-
- currentSpec.$injector = null;
- currentSpec.$modules = null;
- currentSpec = null;
-
- if (injector) {
- injector.get('$rootElement').off();
- injector.get('$browser').pollFns.length = 0;
- }
-
- // clean up jquery's fragment cache
- angular.forEach(angular.element.fragments, function(val, key) {
- delete angular.element.fragments[key];
- });
-
- MockXhr.$$lastInstance = null;
-
- angular.forEach(angular.callbacks, function(val, key) {
- delete angular.callbacks[key];
- });
- angular.callbacks.counter = 0;
- });
-
- /**
- * @ngdoc function
- * @name angular.mock.module
- * @description
- *
- * *NOTE*: This function is also published on window for easy access.
- * *NOTE*: This function is declared ONLY WHEN running tests with jasmine or mocha
- *
- * This function registers a module configuration code. It collects the configuration information
- * which will be used when the injector is created by {@link angular.mock.inject inject}.
- *
- * See {@link angular.mock.inject inject} for usage example
- *
- * @param {...(string|Function|Object)} fns any number of modules which are represented as string
- * aliases or as anonymous module initialization functions. The modules are used to
- * configure the injector. The 'ng' and 'ngMock' modules are automatically loaded. If an
- * object literal is passed they will be registered as values in the module, the key being
- * the module name and the value being what is returned.
- */
- window.module = angular.mock.module = function() {
- var moduleFns = Array.prototype.slice.call(arguments, 0);
- return isSpecRunning() ? workFn() : workFn;
- /////////////////////
- function workFn() {
- if (currentSpec.$injector) {
- throw new Error('Injector already created, can not register a module!');
- } else {
- var modules = currentSpec.$modules || (currentSpec.$modules = []);
- angular.forEach(moduleFns, function(module) {
- if (angular.isObject(module) && !angular.isArray(module)) {
- modules.push(function($provide) {
- angular.forEach(module, function(value, key) {
- $provide.value(key, value);
- });
- });
- } else {
- modules.push(module);
- }
- });
- }
- }
- };
-
- /**
- * @ngdoc function
- * @name angular.mock.inject
- * @description
- *
- * *NOTE*: This function is also published on window for easy access.
- * *NOTE*: This function is declared ONLY WHEN running tests with jasmine or mocha
- *
- * The inject function wraps a function into an injectable function. The inject() creates new
- * instance of {@link auto.$injector $injector} per test, which is then used for
- * resolving references.
- *
- *
- * ## Resolving References (Underscore Wrapping)
- * Often, we would like to inject a reference once, in a `beforeEach()` block and reuse this
- * in multiple `it()` clauses. To be able to do this we must assign the reference to a variable
- * that is declared in the scope of the `describe()` block. Since we would, most likely, want
- * the variable to have the same name of the reference we have a problem, since the parameter
- * to the `inject()` function would hide the outer variable.
- *
- * To help with this, the injected parameters can, optionally, be enclosed with underscores.
- * These are ignored by the injector when the reference name is resolved.
- *
- * For example, the parameter `_myService_` would be resolved as the reference `myService`.
- * Since it is available in the function body as _myService_, we can then assign it to a variable
- * defined in an outer scope.
- *
- * ```
- * // Defined out reference variable outside
- * var myService;
- *
- * // Wrap the parameter in underscores
- * beforeEach( inject( function(_myService_){
- * myService = _myService_;
- * }));
- *
- * // Use myService in a series of tests.
- * it('makes use of myService', function() {
- * myService.doStuff();
- * });
- *
- * ```
- *
- * See also {@link angular.mock.module angular.mock.module}
- *
- * ## Example
- * Example of what a typical jasmine tests looks like with the inject method.
- * ```js
- *
- * angular.module('myApplicationModule', [])
- * .value('mode', 'app')
- * .value('version', 'v1.0.1');
- *
- *
- * describe('MyApp', function() {
- *
- * // You need to load modules that you want to test,
- * // it loads only the "ng" module by default.
- * beforeEach(module('myApplicationModule'));
- *
- *
- * // inject() is used to inject arguments of all given functions
- * it('should provide a version', inject(function(mode, version) {
- * expect(version).toEqual('v1.0.1');
- * expect(mode).toEqual('app');
- * }));
- *
- *
- * // The inject and module method can also be used inside of the it or beforeEach
- * it('should override a version and test the new version is injected', function() {
- * // module() takes functions or strings (module aliases)
- * module(function($provide) {
- * $provide.value('version', 'overridden'); // override version here
- * });
- *
- * inject(function(version) {
- * expect(version).toEqual('overridden');
- * });
- * });
- * });
- *
- * ```
- *
- * @param {...Function} fns any number of functions which will be injected using the injector.
- */
-
-
-
- var ErrorAddingDeclarationLocationStack = function(e, errorForStack) {
- this.message = e.message;
- this.name = e.name;
- if (e.line) this.line = e.line;
- if (e.sourceId) this.sourceId = e.sourceId;
- if (e.stack && errorForStack)
- this.stack = e.stack + '\n' + errorForStack.stack;
- if (e.stackArray) this.stackArray = e.stackArray;
- };
- ErrorAddingDeclarationLocationStack.prototype.toString = Error.prototype.toString;
-
- window.inject = angular.mock.inject = function() {
- var blockFns = Array.prototype.slice.call(arguments, 0);
- var errorForStack = new Error('Declaration Location');
- return isSpecRunning() ? workFn.call(currentSpec) : workFn;
- /////////////////////
- function workFn() {
- var modules = currentSpec.$modules || [];
- var strictDi = !!currentSpec.$injectorStrict;
- modules.unshift('ngMock');
- modules.unshift('ng');
- var injector = currentSpec.$injector;
- if (!injector) {
- if (strictDi) {
- // If strictDi is enabled, annotate the providerInjector blocks
- angular.forEach(modules, function(moduleFn) {
- if (typeof moduleFn === "function") {
- angular.injector.$$annotate(moduleFn);
- }
- });
- }
- injector = currentSpec.$injector = angular.injector(modules, strictDi);
- currentSpec.$injectorStrict = strictDi;
- }
- for (var i = 0, ii = blockFns.length; i < ii; i++) {
- if (currentSpec.$injectorStrict) {
- // If the injector is strict / strictDi, and the spec wants to inject using automatic
- // annotation, then annotate the function here.
- injector.annotate(blockFns[i]);
- }
- try {
- /* jshint -W040 *//* Jasmine explicitly provides a `this` object when calling functions */
- injector.invoke(blockFns[i] || angular.noop, this);
- /* jshint +W040 */
- } catch (e) {
- if (e.stack && errorForStack) {
- throw new ErrorAddingDeclarationLocationStack(e, errorForStack);
- }
- throw e;
- } finally {
- errorForStack = null;
- }
- }
- }
- };
-
-
- angular.mock.inject.strictDi = function(value) {
- value = arguments.length ? !!value : true;
- return isSpecRunning() ? workFn() : workFn;
-
- function workFn() {
- if (value !== currentSpec.$injectorStrict) {
- if (currentSpec.$injector) {
- throw new Error('Injector already created, can not modify strict annotations');
- } else {
- currentSpec.$injectorStrict = value;
- }
- }
- }
- };
-}
-
-
-})(window, window.angular);
diff --git a/public/browse/lib/angular-mocks/bower.json b/public/browse/lib/angular-mocks/bower.json
deleted file mode 100644
index 739097ac6..000000000
--- a/public/browse/lib/angular-mocks/bower.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "name": "angular-mocks",
- "version": "1.3.5",
- "main": "./angular-mocks.js",
- "ignore": [],
- "dependencies": {
- "angular": "1.3.5"
- }
-}
diff --git a/public/browse/lib/angular-mocks/package.json b/public/browse/lib/angular-mocks/package.json
deleted file mode 100644
index a4665805e..000000000
--- a/public/browse/lib/angular-mocks/package.json
+++ /dev/null
@@ -1,27 +0,0 @@
-{
- "name": "angular-mocks",
- "version": "1.3.5",
- "description": "AngularJS mocks for testing",
- "main": "angular-mocks.js",
- "scripts": {
- "test": "echo \"Error: no test specified\" && exit 1"
- },
- "repository": {
- "type": "git",
- "url": "https://github.com/angular/angular.js.git"
- },
- "keywords": [
- "angular",
- "framework",
- "browser",
- "mocks",
- "testing",
- "client-side"
- ],
- "author": "Angular Core Team ",
- "license": "MIT",
- "bugs": {
- "url": "https://github.com/angular/angular.js/issues"
- },
- "homepage": "http://angularjs.org"
-}
diff --git a/public/browse/lib/angular-route/.bower.json b/public/browse/lib/angular-route/.bower.json
deleted file mode 100644
index 011e7abb2..000000000
--- a/public/browse/lib/angular-route/.bower.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "name": "angular-route",
- "version": "1.3.5",
- "main": "./angular-route.js",
- "ignore": [],
- "dependencies": {
- "angular": "1.3.5"
- },
- "homepage": "https://github.com/angular/bower-angular-route",
- "_release": "1.3.5",
- "_resolution": {
- "type": "version",
- "tag": "v1.3.5",
- "commit": "4a949e84a15e474daa1cf0a4f4fbb3dd1f7536cb"
- },
- "_source": "git://github.com/angular/bower-angular-route.git",
- "_target": "1.3.x",
- "_originalSource": "angular-route"
-}
\ No newline at end of file
diff --git a/public/browse/lib/angular-route/README.md b/public/browse/lib/angular-route/README.md
deleted file mode 100644
index b33a0dc33..000000000
--- a/public/browse/lib/angular-route/README.md
+++ /dev/null
@@ -1,77 +0,0 @@
-# packaged angular-route
-
-This repo is for distribution on `npm` and `bower`. The source for this module is in the
-[main AngularJS repo](https://github.com/angular/angular.js/tree/master/src/ngRoute).
-Please file issues and pull requests against that repo.
-
-## Install
-
-You can install this package either with `npm` or with `bower`.
-
-### npm
-
-```shell
-npm install angular-route
-```
-
-Add a `
-```
-
-Then add `ngRoute` as a dependency for your app:
-
-```javascript
-angular.module('myApp', ['ngRoute']);
-```
-
-Note that this package is not in CommonJS format, so doing `require('angular-route')` will
-return `undefined`.
-
-### bower
-
-```shell
-bower install angular-route
-```
-
-Add a `
-```
-
-Then add `ngRoute` as a dependency for your app:
-
-```javascript
-angular.module('myApp', ['ngRoute']);
-```
-
-## Documentation
-
-Documentation is available on the
-[AngularJS docs site](http://docs.angularjs.org/api/ngRoute).
-
-## License
-
-The MIT License
-
-Copyright (c) 2010-2012 Google, Inc. http://angularjs.org
-
-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.
diff --git a/public/browse/lib/angular-route/angular-route.js b/public/browse/lib/angular-route/angular-route.js
deleted file mode 100644
index 2959c50b5..000000000
--- a/public/browse/lib/angular-route/angular-route.js
+++ /dev/null
@@ -1,996 +0,0 @@
-/**
- * @license AngularJS v1.3.5
- * (c) 2010-2014 Google, Inc. http://angularjs.org
- * License: MIT
- */
-(function(window, angular, undefined) {'use strict';
-
-/**
- * @ngdoc module
- * @name ngRoute
- * @description
- *
- * # ngRoute
- *
- * The `ngRoute` module provides routing and deeplinking services and directives for angular apps.
- *
- * ## Example
- * See {@link ngRoute.$route#example $route} for an example of configuring and using `ngRoute`.
- *
- *
- *
- */
- /* global -ngRouteModule */
-var ngRouteModule = angular.module('ngRoute', ['ng']).
- provider('$route', $RouteProvider),
- $routeMinErr = angular.$$minErr('ngRoute');
-
-/**
- * @ngdoc provider
- * @name $routeProvider
- *
- * @description
- *
- * Used for configuring routes.
- *
- * ## Example
- * See {@link ngRoute.$route#example $route} for an example of configuring and using `ngRoute`.
- *
- * ## Dependencies
- * Requires the {@link ngRoute `ngRoute`} module to be installed.
- */
-function $RouteProvider() {
- function inherit(parent, extra) {
- return angular.extend(Object.create(parent), extra);
- }
-
- var routes = {};
-
- /**
- * @ngdoc method
- * @name $routeProvider#when
- *
- * @param {string} path Route path (matched against `$location.path`). If `$location.path`
- * contains redundant trailing slash or is missing one, the route will still match and the
- * `$location.path` will be updated to add or drop the trailing slash to exactly match the
- * route definition.
- *
- * * `path` can contain named groups starting with a colon: e.g. `:name`. All characters up
- * to the next slash are matched and stored in `$routeParams` under the given `name`
- * when the route matches.
- * * `path` can contain named groups starting with a colon and ending with a star:
- * e.g.`:name*`. All characters are eagerly stored in `$routeParams` under the given `name`
- * when the route matches.
- * * `path` can contain optional named groups with a question mark: e.g.`:name?`.
- *
- * For example, routes like `/color/:color/largecode/:largecode*\/edit` will match
- * `/color/brown/largecode/code/with/slashes/edit` and extract:
- *
- * * `color: brown`
- * * `largecode: code/with/slashes`.
- *
- *
- * @param {Object} route Mapping information to be assigned to `$route.current` on route
- * match.
- *
- * Object properties:
- *
- * - `controller` – `{(string|function()=}` – Controller fn that should be associated with
- * newly created scope or the name of a {@link angular.Module#controller registered
- * controller} if passed as a string.
- * - `controllerAs` – `{string=}` – A controller alias name. If present the controller will be
- * published to scope under the `controllerAs` name.
- * - `template` – `{string=|function()=}` – html template as a string or a function that
- * returns an html template as a string which should be used by {@link
- * ngRoute.directive:ngView ngView} or {@link ng.directive:ngInclude ngInclude} directives.
- * This property takes precedence over `templateUrl`.
- *
- * If `template` is a function, it will be called with the following parameters:
- *
- * - `{Array.