From f5d1d4acf7b1a01064feec629fee3d3207b5914f Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Thu, 7 Jul 2016 12:48:10 +0100 Subject: [PATCH 001/669] Fixed width on project visibility icon in project list Closes #19583 --- CHANGELOG | 1 + app/views/shared/projects/_project.html.haml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index bc9bb7747a4..eb7cd7dd1f7 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -40,6 +40,7 @@ v 8.10.0 (unreleased) - Metrics for Rouge::Plugins::Redcarpet and Rouge::Formatters::HTMLGitlab - RailsCache metris now includes fetch_hit/fetch_miss and read_hit/read_miss info. - Allow [ci skip] to be in any case and allow [skip ci]. !4785 (simon_w) + - Made project list visibility icon fixed width - Set import_url validation to be more strict - Add basic system information like memory and disk usage to the admin panel - Don't garbage collect commits that have related DB records like comments diff --git a/app/views/shared/projects/_project.html.haml b/app/views/shared/projects/_project.html.haml index b8b66d08db8..92803838d02 100644 --- a/app/views/shared/projects/_project.html.haml +++ b/app/views/shared/projects/_project.html.haml @@ -24,7 +24,7 @@ = icon('star') = project.star_count %span.visibility-icon.has-tooltip{data: { container: 'body', placement: 'left' }, title: visibility_icon_description(project)} - = visibility_level_icon(project.visibility_level, fw: false) + = visibility_level_icon(project.visibility_level, fw: true) .title = link_to project_path(project), class: dom_class(project) do From 26055b16b58afd73e31f7aaacb9aaa79ba3794c2 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Tue, 5 Jul 2016 13:52:20 +0100 Subject: [PATCH 002/669] Highlight empty lines Closes #19484 --- app/assets/stylesheets/framework/highlight.scss | 10 ++++++++-- app/views/projects/blob/_editor.html.haml | 2 +- .../files/project_owner_creates_license_file_spec.rb | 4 ++-- ...ink_to_create_license_file_in_empty_project_spec.rb | 2 +- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/app/assets/stylesheets/framework/highlight.scss b/app/assets/stylesheets/framework/highlight.scss index 7cf4d4fba42..51ae9df9685 100644 --- a/app/assets/stylesheets/framework/highlight.scss +++ b/app/assets/stylesheets/framework/highlight.scss @@ -6,11 +6,11 @@ table-layout: fixed; pre { - padding: 10px; + padding: 10px 0; border: none; border-radius: 0; font-family: $monospace_font; - font-size: $code_font_size !important; + font-size: 0; line-height: $code_line_height !important; margin: 0; overflow: auto; @@ -21,12 +21,18 @@ code { font-family: $monospace_font; + font-size: 0; white-space: pre; word-wrap: normal; padding: 0; .line { display: inline-block; + width: 100%; + min-height: 19px; + padding-left: 10px; + padding-right: 10px; + font-size: $code_font_size; } } } diff --git a/app/views/projects/blob/_editor.html.haml b/app/views/projects/blob/_editor.html.haml index ff379bafb26..0237e152b54 100644 --- a/app/views/projects/blob/_editor.html.haml +++ b/app/views/projects/blob/_editor.html.haml @@ -24,7 +24,7 @@ .encoding-selector = select_tag :encoding, options_for_select([ "base64", "text" ], "text"), class: 'select2' - .file-content.code + .file-editor.code %pre.js-edit-mode-pane#editor #{params[:content] || local_assigns[:blob_data]} - if local_assigns[:path] .js-edit-mode-pane#preview.hide diff --git a/spec/features/projects/files/project_owner_creates_license_file_spec.rb b/spec/features/projects/files/project_owner_creates_license_file_spec.rb index e1e105e6bbe..26f8a8fab2f 100644 --- a/spec/features/projects/files/project_owner_creates_license_file_spec.rb +++ b/spec/features/projects/files/project_owner_creates_license_file_spec.rb @@ -23,7 +23,7 @@ feature 'project owner creates a license file', feature: true, js: true do select_template('MIT License') - file_content = find('.file-content') + file_content = first('.file-editor') expect(file_content).to have_content('The MIT License (MIT)') expect(file_content).to have_content("Copyright (c) #{Time.now.year} #{project.namespace.human_name}") @@ -46,7 +46,7 @@ feature 'project owner creates a license file', feature: true, js: true do select_template('MIT License') - file_content = find('.file-content') + file_content = first('.file-editor') expect(file_content).to have_content('The MIT License (MIT)') expect(file_content).to have_content("Copyright (c) #{Time.now.year} #{project.namespace.human_name}") diff --git a/spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb b/spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb index 67aac25e427..bebec666eb5 100644 --- a/spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb +++ b/spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb @@ -22,7 +22,7 @@ feature 'project owner sees a link to create a license file in empty project', f select_template('MIT License') - file_content = find('.file-content') + file_content = first('.file-editor') expect(file_content).to have_content('The MIT License (MIT)') expect(file_content).to have_content("Copyright (c) #{Time.now.year} #{project.namespace.human_name}") From 5cf89e70b70de008d5b91e89ce015522616e96cb Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Thu, 14 Jul 2016 09:12:10 +0100 Subject: [PATCH 003/669] Uses white-space instead of setting font size to 0 --- app/assets/stylesheets/framework/highlight.scss | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/app/assets/stylesheets/framework/highlight.scss b/app/assets/stylesheets/framework/highlight.scss index 51ae9df9685..11b2a4cbf89 100644 --- a/app/assets/stylesheets/framework/highlight.scss +++ b/app/assets/stylesheets/framework/highlight.scss @@ -10,7 +10,7 @@ border: none; border-radius: 0; font-family: $monospace_font; - font-size: 0; + font-size: $code_font_size; line-height: $code_line_height !important; margin: 0; overflow: auto; @@ -21,18 +21,16 @@ code { font-family: $monospace_font; - font-size: 0; - white-space: pre; + white-space: normal; word-wrap: normal; padding: 0; .line { - display: inline-block; + display: block; width: 100%; min-height: 19px; padding-left: 10px; padding-right: 10px; - font-size: $code_font_size; } } } From cf33acb32b12cf482e0279043e8cd02131c456e6 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Tue, 19 Jul 2016 19:19:22 +0100 Subject: [PATCH 004/669] Fixed wrapping of lines on smaller viewports --- app/assets/stylesheets/framework/highlight.scss | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/assets/stylesheets/framework/highlight.scss b/app/assets/stylesheets/framework/highlight.scss index 11b2a4cbf89..07c8874bf03 100644 --- a/app/assets/stylesheets/framework/highlight.scss +++ b/app/assets/stylesheets/framework/highlight.scss @@ -20,6 +20,8 @@ border-left: 1px solid; code { + display: inline-block; + min-width: 100%; font-family: $monospace_font; white-space: normal; word-wrap: normal; @@ -31,6 +33,7 @@ min-height: 19px; padding-left: 10px; padding-right: 10px; + white-space: pre; } } } From 283bd88a77786b44d2f491f73a1b22be802fad68 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Thu, 21 Jul 2016 12:50:30 +0100 Subject: [PATCH 005/669] Changed project description width Closes #20020 --- app/assets/stylesheets/pages/projects.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss index cc3aef5199e..53cdc3a1400 100644 --- a/app/assets/stylesheets/pages/projects.scss +++ b/app/assets/stylesheets/pages/projects.scss @@ -99,7 +99,7 @@ margin-left: auto; margin-right: auto; margin-bottom: 15px; - max-width: 480px; + max-width: 700px; > p { margin-bottom: 0; From af5fc6e24ce3e2f5fa42d6764a780afe0d6471d9 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Thu, 30 Jun 2016 17:21:57 +0100 Subject: [PATCH 006/669] Diff line comments resolve --- Gemfile | 1 + Gemfile.lock | 6 +++ .../line_comments/application.js.coffee | 6 +++ .../components/line_btn.js.coffee | 19 ++++++++ app/assets/stylesheets/pages/notes.scss | 44 +++++++++++++++++++ .../projects/merge_requests/_show.html.haml | 2 + app/views/projects/notes/_note.html.haml | 4 ++ config/application.rb | 1 + 8 files changed, 83 insertions(+) create mode 100644 app/assets/javascripts/line_comments/application.js.coffee create mode 100644 app/assets/javascripts/line_comments/components/line_btn.js.coffee diff --git a/Gemfile b/Gemfile index 0504e643ed7..74fb7b1a2af 100644 --- a/Gemfile +++ b/Gemfile @@ -349,3 +349,4 @@ gem 'health_check', '~> 2.1.0' # System information gem 'vmstat', '~> 2.1.1' gem 'sys-filesystem', '~> 1.1.6' +gem 'vuejs-rails' diff --git a/Gemfile.lock b/Gemfile.lock index 195516d1bf1..e9068d1d69e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -776,6 +776,7 @@ GEM descendants_tracker (~> 0.0, >= 0.0.3) equalizer (~> 0.0, >= 0.0.9) vmstat (2.1.1) + vuejs-rails (1.0.24) warden (1.2.6) rack (>= 1.0) web-console (2.3.0) @@ -980,7 +981,12 @@ DEPENDENCIES unicorn-worker-killer (~> 0.4.2) version_sorter (~> 2.0.0) virtus (~> 1.0.1) +<<<<<<< HEAD vmstat (~> 2.1.1) +======= + vmstat (~> 2.1.0) + vuejs-rails +>>>>>>> Diff line comments resolve web-console (~> 2.0) webmock (~> 1.21.0) wikicloth (= 0.8.1) diff --git a/app/assets/javascripts/line_comments/application.js.coffee b/app/assets/javascripts/line_comments/application.js.coffee new file mode 100644 index 00000000000..396416efb78 --- /dev/null +++ b/app/assets/javascripts/line_comments/application.js.coffee @@ -0,0 +1,6 @@ +#= require vue +#= require_directory ./components + +$ -> + new Vue + el: '#notes' diff --git a/app/assets/javascripts/line_comments/components/line_btn.js.coffee b/app/assets/javascripts/line_comments/components/line_btn.js.coffee new file mode 100644 index 00000000000..3abcd41df1e --- /dev/null +++ b/app/assets/javascripts/line_comments/components/line_btn.js.coffee @@ -0,0 +1,19 @@ +LineBtn = Vue.extend + props: + noteId: Number + resolved: Boolean + computed: + buttonText: -> + if this.resolved then "Mark as un-resolved" else "Mark as resolved" + methods: + updateTooltip: -> + $(this.$el) + .tooltip('hide') + .tooltip('fixTitle') + resolve: -> + this.$set('resolved', !this.resolved) + this.$nextTick this.updateTooltip + compiled: -> + $(this.$el).tooltip() + +Vue.component 'line-btn', LineBtn diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss index a2b5437e503..49331aa641a 100644 --- a/app/assets/stylesheets/pages/notes.scss +++ b/app/assets/stylesheets/pages/notes.scss @@ -383,3 +383,47 @@ ul.notes { color: $gl-link-color; } } + +.line-resolve-all { + padding: 10px; + border: 1px solid $border-color; + border-radius: 2px; + + .btn { + margin-right: 10px; + } +} + +.line-resolve-text { + vertical-align: middle; +} + +.line-resolve-btn { + position: relative; + top: -1px; + width: 14px; + height: 14px; + padding: 0; + background-color: transparent; + border: 1px solid #c3c3c3; + border-radius: 50%; + outline: 0; + vertical-align: middle; + + &:hover, + &.is-active { + color: #fff; + background-color: $gl-text-green; + border-color: $gl-text-green; + + .fa { + color: #fff; + } + } + + .fa { + top: 2px; + font-size: 8px; + vertical-align: top; + } +} diff --git a/app/views/projects/merge_requests/_show.html.haml b/app/views/projects/merge_requests/_show.html.haml index 873ed9b59ee..f7f7182b2a0 100644 --- a/app/views/projects/merge_requests/_show.html.haml +++ b/app/views/projects/merge_requests/_show.html.haml @@ -1,6 +1,8 @@ - page_title "#{@merge_request.title} (#{@merge_request.to_reference})", "Merge Requests" - page_description @merge_request.description - page_card_attributes @merge_request.card_attributes +- content_for :page_specific_javascripts do + = page_specific_javascript_tag('line_comments/application.js') - if diff_view == 'parallel' - fluid_layout true diff --git a/app/views/projects/notes/_note.html.haml b/app/views/projects/notes/_note.html.haml index 71da8ac9d7c..9b1eb8545e5 100644 --- a/app/views/projects/notes/_note.html.haml +++ b/app/views/projects/notes/_note.html.haml @@ -20,6 +20,10 @@ - access = note_max_access_for_user(note) - if access and not note.system %span.note-role.hidden-xs= access + - unless note.system + %line-btn{ ":note-id" => note.id, ":resolved" => "false", "inline-template" => true } + %button.note-action-button.line-resolve-btn{ type: "button", "v-bind:class" => "{ 'is-active': resolved }", "v-bind:aria-label" => "buttonText", "v-on:click" => "resolve", "v-bind:title" => "buttonText" } + = icon("check") - if current_user and not note.system = link_to '#', title: 'Award Emoji', class: 'note-action-button note-emoji-button js-add-award js-note-emoji', data: { position: 'right' } do = icon('spinner spin') diff --git a/config/application.rb b/config/application.rb index 06ebb14a5fe..54c82bbcf26 100644 --- a/config/application.rb +++ b/config/application.rb @@ -85,6 +85,7 @@ module Gitlab config.assets.precompile << "users/users_bundle.js" config.assets.precompile << "network/network_bundle.js" config.assets.precompile << "profile/profile_bundle.js" + config.assets.precompile << "line_comments/application.js" config.assets.precompile << "lib/utils/*.js" config.assets.precompile << "lib/*.js" config.assets.precompile << "u2f.js" From 70b46b280c07807c4df0a0c2c8b71d725a60f8c7 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Fri, 1 Jul 2016 13:54:55 +0100 Subject: [PATCH 007/669] Resolve all comments button Store that manages the state of each button --- .../line_comments/application.js.coffee | 4 ++++ .../components/line_btn.js.coffee | 19 --------------- .../components/resolve_all.js.coffee | 19 +++++++++++++++ .../components/resolve_btn.js.coffee | 24 +++++++++++++++++++ .../line_comments/stores/comments.js.coffee | 9 +++++++ app/assets/stylesheets/behaviors.scss | 4 ++++ .../projects/merge_requests/_show.html.haml | 10 +++++++- app/views/projects/notes/_note.html.haml | 4 ++-- 8 files changed, 71 insertions(+), 22 deletions(-) delete mode 100644 app/assets/javascripts/line_comments/components/line_btn.js.coffee create mode 100644 app/assets/javascripts/line_comments/components/resolve_all.js.coffee create mode 100644 app/assets/javascripts/line_comments/components/resolve_btn.js.coffee create mode 100644 app/assets/javascripts/line_comments/stores/comments.js.coffee diff --git a/app/assets/javascripts/line_comments/application.js.coffee b/app/assets/javascripts/line_comments/application.js.coffee index 396416efb78..3c0957ce458 100644 --- a/app/assets/javascripts/line_comments/application.js.coffee +++ b/app/assets/javascripts/line_comments/application.js.coffee @@ -1,6 +1,10 @@ #= require vue +#= require_directory ./stores #= require_directory ./components $ -> new Vue el: '#notes' + + new Vue + el: '#resolve-all-app' diff --git a/app/assets/javascripts/line_comments/components/line_btn.js.coffee b/app/assets/javascripts/line_comments/components/line_btn.js.coffee deleted file mode 100644 index 3abcd41df1e..00000000000 --- a/app/assets/javascripts/line_comments/components/line_btn.js.coffee +++ /dev/null @@ -1,19 +0,0 @@ -LineBtn = Vue.extend - props: - noteId: Number - resolved: Boolean - computed: - buttonText: -> - if this.resolved then "Mark as un-resolved" else "Mark as resolved" - methods: - updateTooltip: -> - $(this.$el) - .tooltip('hide') - .tooltip('fixTitle') - resolve: -> - this.$set('resolved', !this.resolved) - this.$nextTick this.updateTooltip - compiled: -> - $(this.$el).tooltip() - -Vue.component 'line-btn', LineBtn diff --git a/app/assets/javascripts/line_comments/components/resolve_all.js.coffee b/app/assets/javascripts/line_comments/components/resolve_all.js.coffee new file mode 100644 index 00000000000..0cc19a7a399 --- /dev/null +++ b/app/assets/javascripts/line_comments/components/resolve_all.js.coffee @@ -0,0 +1,19 @@ +ResolveAll = Vue.extend + data: -> + { comments: CommentsStore.state } + computed: + resolved: -> + resolvedCount = 0 + for noteId, resolved of this.comments + resolvedCount++ if resolved + resolvedCount + commentsCount: -> + Object.keys(this.comments).length + buttonText: -> + if this.resolved is this.commentsCount then 'Un-resolve all' else 'Resolve all' + methods: + updateAll: -> + resolveAll = !(this.resolved is this.commentsCount) + CommentsStore.updateAll(resolveAll) + +Vue.component 'resolve-all', ResolveAll diff --git a/app/assets/javascripts/line_comments/components/resolve_btn.js.coffee b/app/assets/javascripts/line_comments/components/resolve_btn.js.coffee new file mode 100644 index 00000000000..7470dc517fe --- /dev/null +++ b/app/assets/javascripts/line_comments/components/resolve_btn.js.coffee @@ -0,0 +1,24 @@ +ResolveBtn = Vue.extend + props: + noteId: Number + resolved: Boolean + data: -> comments: CommentsStore.state + computed: + buttonText: -> + if this.comments[this.noteId] then "Mark as un-resolved" else "Mark as resolved" + isResolved: -> this.comments[this.noteId] + methods: + updateTooltip: -> + $(this.$el) + .tooltip('hide') + .tooltip('fixTitle') + resolve: -> + CommentsStore.update(this.noteId, !this.comments[this.noteId]) + + this.$nextTick this.updateTooltip + compiled: -> + $(this.$el).tooltip() + created: -> + CommentsStore.create(this.noteId, this.resolved) + +Vue.component 'resolve-btn', ResolveBtn diff --git a/app/assets/javascripts/line_comments/stores/comments.js.coffee b/app/assets/javascripts/line_comments/stores/comments.js.coffee new file mode 100644 index 00000000000..c002dc0c4d6 --- /dev/null +++ b/app/assets/javascripts/line_comments/stores/comments.js.coffee @@ -0,0 +1,9 @@ +@CommentsStore = + state: {} + create: (id, resolved) -> + Vue.set(this.state, id, resolved) + update: (id, resolved) -> + this.state[id] = resolved + updateAll: (state) -> + for id,resolved of this.state + this.update(id, state) if resolved isnt state diff --git a/app/assets/stylesheets/behaviors.scss b/app/assets/stylesheets/behaviors.scss index 542a53f0377..c629229e4d9 100644 --- a/app/assets/stylesheets/behaviors.scss +++ b/app/assets/stylesheets/behaviors.scss @@ -20,3 +20,7 @@ .turn-off { display: block; } } } + +[v-cloak="true"] { + display: none; +} diff --git a/app/views/projects/merge_requests/_show.html.haml b/app/views/projects/merge_requests/_show.html.haml index f7f7182b2a0..de6d3d52936 100644 --- a/app/views/projects/merge_requests/_show.html.haml +++ b/app/views/projects/merge_requests/_show.html.haml @@ -44,7 +44,15 @@ = succeed '.' do = link_to "command line", "#modal_merge_info", class: "how_to_merge_link vlink", title: "How To Merge", "data-toggle" => "modal" - - if @commits_count.nonzero? + #resolve-all-app{ "v-cloak" => true } + %resolve-all{ "inline-template" => true } + .line-resolve-all{ "v-show" => "commentsCount > 0" } + %button.btn.btn-gray{ type: "button", "aria-label" => "Resolve all", "v-on:click" => "updateAll" } + {{ buttonText }} + %span.line-resolve-text + {{ resolved }}/{{ commentsCount }} comments resolved + + - if @commits.nonzero? %ul.merge-request-tabs.nav-links.no-top.no-bottom %li.notes-tab = link_to namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: {target: 'div#notes', action: 'notes', toggle: 'tab'} do diff --git a/app/views/projects/notes/_note.html.haml b/app/views/projects/notes/_note.html.haml index 9b1eb8545e5..beaae53992d 100644 --- a/app/views/projects/notes/_note.html.haml +++ b/app/views/projects/notes/_note.html.haml @@ -21,8 +21,8 @@ - if access and not note.system %span.note-role.hidden-xs= access - unless note.system - %line-btn{ ":note-id" => note.id, ":resolved" => "false", "inline-template" => true } - %button.note-action-button.line-resolve-btn{ type: "button", "v-bind:class" => "{ 'is-active': resolved }", "v-bind:aria-label" => "buttonText", "v-on:click" => "resolve", "v-bind:title" => "buttonText" } + %resolve-btn{ ":note-id" => note.id, ":resolved" => "false", "inline-template" => true } + %button.note-action-button.line-resolve-btn{ type: "button", "v-bind:class" => "{ 'is-active': isResolved }", "v-bind:aria-label" => "buttonText", "v-on:click" => "resolve", "v-bind:title" => "buttonText" } = icon("check") - if current_user and not note.system = link_to '#', title: 'Award Emoji', class: 'note-action-button note-emoji-button js-add-award js-note-emoji', data: { position: 'right' } do From 0ab8264ea622a1d38ab457b368804fad4cb003ca Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Fri, 1 Jul 2016 17:02:48 +0100 Subject: [PATCH 008/669] VueJS updates --- .../javascripts/line_comments/application.js.coffee | 8 ++++++-- .../line_comments/components/resolve_all.js.coffee | 4 +--- .../line_comments/components/resolve_btn.js.coffee | 7 ++++--- app/views/projects/merge_requests/_show.html.haml | 2 +- app/views/projects/notes/_note.html.haml | 2 +- 5 files changed, 13 insertions(+), 10 deletions(-) diff --git a/app/assets/javascripts/line_comments/application.js.coffee b/app/assets/javascripts/line_comments/application.js.coffee index 3c0957ce458..cb9ff54ac05 100644 --- a/app/assets/javascripts/line_comments/application.js.coffee +++ b/app/assets/javascripts/line_comments/application.js.coffee @@ -2,9 +2,13 @@ #= require_directory ./stores #= require_directory ./components -$ -> - new Vue +$ => + @DiffNotesApp = new Vue el: '#notes' + components: + 'resolve-btn': ResolveBtn new Vue el: '#resolve-all-app' + components: + 'resolve-all': ResolveAll diff --git a/app/assets/javascripts/line_comments/components/resolve_all.js.coffee b/app/assets/javascripts/line_comments/components/resolve_all.js.coffee index 0cc19a7a399..76add1ed005 100644 --- a/app/assets/javascripts/line_comments/components/resolve_all.js.coffee +++ b/app/assets/javascripts/line_comments/components/resolve_all.js.coffee @@ -1,4 +1,4 @@ -ResolveAll = Vue.extend +@ResolveAll = Vue.extend data: -> { comments: CommentsStore.state } computed: @@ -15,5 +15,3 @@ ResolveAll = Vue.extend updateAll: -> resolveAll = !(this.resolved is this.commentsCount) CommentsStore.updateAll(resolveAll) - -Vue.component 'resolve-all', ResolveAll diff --git a/app/assets/javascripts/line_comments/components/resolve_btn.js.coffee b/app/assets/javascripts/line_comments/components/resolve_btn.js.coffee index 7470dc517fe..3363f0a9854 100644 --- a/app/assets/javascripts/line_comments/components/resolve_btn.js.coffee +++ b/app/assets/javascripts/line_comments/components/resolve_btn.js.coffee @@ -1,4 +1,4 @@ -ResolveBtn = Vue.extend +@ResolveBtn = Vue.extend props: noteId: Number resolved: Boolean @@ -18,7 +18,8 @@ ResolveBtn = Vue.extend this.$nextTick this.updateTooltip compiled: -> $(this.$el).tooltip() + destroyed: -> + console.log this.noteId created: -> + console.log this.noteId CommentsStore.create(this.noteId, this.resolved) - -Vue.component 'resolve-btn', ResolveBtn diff --git a/app/views/projects/merge_requests/_show.html.haml b/app/views/projects/merge_requests/_show.html.haml index de6d3d52936..be38341c6b2 100644 --- a/app/views/projects/merge_requests/_show.html.haml +++ b/app/views/projects/merge_requests/_show.html.haml @@ -47,7 +47,7 @@ #resolve-all-app{ "v-cloak" => true } %resolve-all{ "inline-template" => true } .line-resolve-all{ "v-show" => "commentsCount > 0" } - %button.btn.btn-gray{ type: "button", "aria-label" => "Resolve all", "v-on:click" => "updateAll" } + %button.btn.btn-gray{ type: "button", "aria-label" => "Resolve all", "@click" => "updateAll" } {{ buttonText }} %span.line-resolve-text {{ resolved }}/{{ commentsCount }} comments resolved diff --git a/app/views/projects/notes/_note.html.haml b/app/views/projects/notes/_note.html.haml index beaae53992d..ed304aef4dc 100644 --- a/app/views/projects/notes/_note.html.haml +++ b/app/views/projects/notes/_note.html.haml @@ -22,7 +22,7 @@ %span.note-role.hidden-xs= access - unless note.system %resolve-btn{ ":note-id" => note.id, ":resolved" => "false", "inline-template" => true } - %button.note-action-button.line-resolve-btn{ type: "button", "v-bind:class" => "{ 'is-active': isResolved }", "v-bind:aria-label" => "buttonText", "v-on:click" => "resolve", "v-bind:title" => "buttonText" } + %button.note-action-button.line-resolve-btn{ type: "button", ":class" => "{ 'is-active': isResolved }", ":aria-label" => "buttonText", "@click" => "resolve", ":title" => "buttonText" } = icon("check") - if current_user and not note.system = link_to '#', title: 'Award Emoji', class: 'note-action-button note-emoji-button js-add-award js-note-emoji', data: { position: 'right' } do From a8927a75b097bbe6d10ad9977fa1fe945b613263 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Mon, 4 Jul 2016 09:01:59 +0100 Subject: [PATCH 009/669] Fixed issue when adding or deleting through jQuery --- .../line_comments/components/resolve_btn.js.coffee | 3 +-- .../line_comments/stores/comments.js.coffee | 2 ++ app/assets/javascripts/notes.js.coffee | 10 ++++++++++ app/views/projects/notes/_note.html.haml | 2 +- 4 files changed, 14 insertions(+), 3 deletions(-) diff --git a/app/assets/javascripts/line_comments/components/resolve_btn.js.coffee b/app/assets/javascripts/line_comments/components/resolve_btn.js.coffee index 3363f0a9854..5ade02c56f5 100644 --- a/app/assets/javascripts/line_comments/components/resolve_btn.js.coffee +++ b/app/assets/javascripts/line_comments/components/resolve_btn.js.coffee @@ -19,7 +19,6 @@ compiled: -> $(this.$el).tooltip() destroyed: -> - console.log this.noteId + CommentsStore.delete(this.noteId) created: -> - console.log this.noteId CommentsStore.create(this.noteId, this.resolved) diff --git a/app/assets/javascripts/line_comments/stores/comments.js.coffee b/app/assets/javascripts/line_comments/stores/comments.js.coffee index c002dc0c4d6..ae44ab90290 100644 --- a/app/assets/javascripts/line_comments/stores/comments.js.coffee +++ b/app/assets/javascripts/line_comments/stores/comments.js.coffee @@ -4,6 +4,8 @@ Vue.set(this.state, id, resolved) update: (id, resolved) -> this.state[id] = resolved + delete: (id) -> + Vue.delete(this.state, id) updateAll: (state) -> for id,resolved of this.state this.update(id, state) if resolved isnt state diff --git a/app/assets/javascripts/notes.js.coffee b/app/assets/javascripts/notes.js.coffee index d4de712f88c..6c4c18c98c6 100644 --- a/app/assets/javascripts/notes.js.coffee +++ b/app/assets/javascripts/notes.js.coffee @@ -271,6 +271,10 @@ class @Notes # append new note to all matching discussions discussionContainer.append note_html + if $('resolve-btn').length and DiffNotesApp? + $('resolve-btn').each -> + DiffNotesApp.$compile $(this).get(0) + gl.utils.localTimeAgo($('.js-timeago', note_html), false) @updateNotesCount(1) @@ -465,6 +469,12 @@ class @Notes note = $(el) notes = note.closest(".notes") + if DiffNotesApp? + ref = DiffNotesApp.$refs["#{noteId}"] + + if ref? + ref.$destroy(true) + # check if this is the last note for this line if notes.find(".note").length is 1 diff --git a/app/views/projects/notes/_note.html.haml b/app/views/projects/notes/_note.html.haml index ed304aef4dc..0c42296e492 100644 --- a/app/views/projects/notes/_note.html.haml +++ b/app/views/projects/notes/_note.html.haml @@ -21,7 +21,7 @@ - if access and not note.system %span.note-role.hidden-xs= access - unless note.system - %resolve-btn{ ":note-id" => note.id, ":resolved" => "false", "inline-template" => true } + %resolve-btn{ ":note-id" => note.id, ":resolved" => "false", "inline-template" => true, "v-ref:note_#{note.id}" => true } %button.note-action-button.line-resolve-btn{ type: "button", ":class" => "{ 'is-active': isResolved }", ":aria-label" => "buttonText", "@click" => "resolve", ":title" => "buttonText" } = icon("check") - if current_user and not note.system From 662f5edd36b6910074df222474bab4ff4849d313 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Mon, 4 Jul 2016 09:03:01 +0100 Subject: [PATCH 010/669] Fixed tabs --- app/assets/javascripts/notes.js.coffee | 5 +---- app/assets/stylesheets/pages/notes.scss | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/app/assets/javascripts/notes.js.coffee b/app/assets/javascripts/notes.js.coffee index 6c4c18c98c6..7bd308f6765 100644 --- a/app/assets/javascripts/notes.js.coffee +++ b/app/assets/javascripts/notes.js.coffee @@ -470,10 +470,7 @@ class @Notes notes = note.closest(".notes") if DiffNotesApp? - ref = DiffNotesApp.$refs["#{noteId}"] - - if ref? - ref.$destroy(true) + ref = DiffNotesApp.$refs["#{noteId}"]?.$destroy(true) # check if this is the last note for this line if notes.find(".note").length is 1 diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss index 49331aa641a..540d134d77b 100644 --- a/app/assets/stylesheets/pages/notes.scss +++ b/app/assets/stylesheets/pages/notes.scss @@ -390,7 +390,7 @@ ul.notes { border-radius: 2px; .btn { - margin-right: 10px; + margin-right: 10px; } } From b550e6ee67ebfc1cfbbb7a77414f9fe05ffad419 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Mon, 4 Jul 2016 15:00:39 +0100 Subject: [PATCH 011/669] Posts to rails to update note eventually --- .../line_comments/application.js.coffee | 1 + .../components/resolve_all.js.coffee | 19 ++++++++++++++---- .../components/resolve_btn.js.coffee | 20 ++++++++++++++----- .../line_comments/services/resolve.js.coffee | 19 ++++++++++++++++++ .../line_comments/stores/comments.js.coffee | 5 +++++ app/assets/stylesheets/pages/notes.scss | 2 +- app/controllers/projects/notes_controller.rb | 5 +++++ .../projects/merge_requests/_show.html.haml | 3 ++- app/views/projects/notes/_note.html.haml | 8 +++++--- config/routes.rb | 1 + 10 files changed, 69 insertions(+), 14 deletions(-) create mode 100644 app/assets/javascripts/line_comments/services/resolve.js.coffee diff --git a/app/assets/javascripts/line_comments/application.js.coffee b/app/assets/javascripts/line_comments/application.js.coffee index cb9ff54ac05..b15b09e5fa2 100644 --- a/app/assets/javascripts/line_comments/application.js.coffee +++ b/app/assets/javascripts/line_comments/application.js.coffee @@ -1,5 +1,6 @@ #= require vue #= require_directory ./stores +#= require_directory ./services #= require_directory ./components $ => diff --git a/app/assets/javascripts/line_comments/components/resolve_all.js.coffee b/app/assets/javascripts/line_comments/components/resolve_all.js.coffee index 76add1ed005..f8a56293d67 100644 --- a/app/assets/javascripts/line_comments/components/resolve_all.js.coffee +++ b/app/assets/javascripts/line_comments/components/resolve_all.js.coffee @@ -1,6 +1,7 @@ @ResolveAll = Vue.extend data: -> - { comments: CommentsStore.state } + comments: CommentsStore.state + loading: false computed: resolved: -> resolvedCount = 0 @@ -10,8 +11,18 @@ commentsCount: -> Object.keys(this.comments).length buttonText: -> - if this.resolved is this.commentsCount then 'Un-resolve all' else 'Resolve all' + if this.allResolved then 'Un-resolve all' else 'Resolve all' + allResolved: -> + this.resolved is this.commentsCount methods: updateAll: -> - resolveAll = !(this.resolved is this.commentsCount) - CommentsStore.updateAll(resolveAll) + ids = CommentsStore.getAllForState(this.allResolved) + this.$set('loading', true) + + promise = if this.allResolved then ResolveService.resolveAll(ids) else ResolveService.resolveAll(ids) + + promise + .done => + CommentsStore.updateAll(!this.allResolved) + .always => + this.$set('loading', false) diff --git a/app/assets/javascripts/line_comments/components/resolve_btn.js.coffee b/app/assets/javascripts/line_comments/components/resolve_btn.js.coffee index 5ade02c56f5..79f97aa354e 100644 --- a/app/assets/javascripts/line_comments/components/resolve_btn.js.coffee +++ b/app/assets/javascripts/line_comments/components/resolve_btn.js.coffee @@ -2,22 +2,32 @@ props: noteId: Number resolved: Boolean - data: -> comments: CommentsStore.state + endpoint: String + data: -> + comments: CommentsStore.state + loading: false computed: buttonText: -> if this.comments[this.noteId] then "Mark as un-resolved" else "Mark as resolved" isResolved: -> this.comments[this.noteId] methods: updateTooltip: -> - $(this.$el) + $(this.$els.button) .tooltip('hide') .tooltip('fixTitle') resolve: -> - CommentsStore.update(this.noteId, !this.comments[this.noteId]) + this.$set('loading', true) + ResolveService + .resolve(this.endpoint, !this.isResolved) + .done => + this.$set('loading', false) + CommentsStore.update(this.noteId, !this.isResolved) - this.$nextTick this.updateTooltip + this.$nextTick this.updateTooltip + .always => + this.$set('loading', false) compiled: -> - $(this.$el).tooltip() + $(this.$els.button).tooltip() destroyed: -> CommentsStore.delete(this.noteId) created: -> diff --git a/app/assets/javascripts/line_comments/services/resolve.js.coffee b/app/assets/javascripts/line_comments/services/resolve.js.coffee new file mode 100644 index 00000000000..690fcad6232 --- /dev/null +++ b/app/assets/javascripts/line_comments/services/resolve.js.coffee @@ -0,0 +1,19 @@ +@ResolveService = + resolve: (endpoint, resolve) -> + $.ajax + data: + resolved: resolve + type: 'post' + url: endpoint + resolveAll: (ids) -> + $.ajax + data: + id: ids + type: 'get' + url: '/' + unResolveAll: (ids) -> + $.ajax + data: + id: ids + type: 'get' + url: '/' diff --git a/app/assets/javascripts/line_comments/stores/comments.js.coffee b/app/assets/javascripts/line_comments/stores/comments.js.coffee index ae44ab90290..9bea16d3de0 100644 --- a/app/assets/javascripts/line_comments/stores/comments.js.coffee +++ b/app/assets/javascripts/line_comments/stores/comments.js.coffee @@ -9,3 +9,8 @@ updateAll: (state) -> for id,resolved of this.state this.update(id, state) if resolved isnt state + getAllForState: (state) -> + ids = [] + for id,resolved of this.state + ids.push(id) if resolved is state + ids diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss index 540d134d77b..8a5d3215077 100644 --- a/app/assets/stylesheets/pages/notes.scss +++ b/app/assets/stylesheets/pages/notes.scss @@ -387,7 +387,7 @@ ul.notes { .line-resolve-all { padding: 10px; border: 1px solid $border-color; - border-radius: 2px; + border-radius: $border-radius-default; .btn { margin-right: 10px; diff --git a/app/controllers/projects/notes_controller.rb b/app/controllers/projects/notes_controller.rb index 766b7e9cf22..5ace460d02f 100644 --- a/app/controllers/projects/notes_controller.rb +++ b/app/controllers/projects/notes_controller.rb @@ -66,6 +66,11 @@ class Projects::NotesController < Projects::ApplicationController end end + def resolve + sleep 2 + render nothing: true, status: 200 + end + private def note diff --git a/app/views/projects/merge_requests/_show.html.haml b/app/views/projects/merge_requests/_show.html.haml index be38341c6b2..765ff68aeb1 100644 --- a/app/views/projects/merge_requests/_show.html.haml +++ b/app/views/projects/merge_requests/_show.html.haml @@ -47,7 +47,8 @@ #resolve-all-app{ "v-cloak" => true } %resolve-all{ "inline-template" => true } .line-resolve-all{ "v-show" => "commentsCount > 0" } - %button.btn.btn-gray{ type: "button", "aria-label" => "Resolve all", "@click" => "updateAll" } + %button.btn.btn-gray{ type: "button", "aria-label" => "Resolve all", "@click" => "updateAll", ":disabled" => "loading" } + = icon("spinner spin", "v-show" => "loading") {{ buttonText }} %span.line-resolve-text {{ resolved }}/{{ commentsCount }} comments resolved diff --git a/app/views/projects/notes/_note.html.haml b/app/views/projects/notes/_note.html.haml index 0c42296e492..57ffd6e5432 100644 --- a/app/views/projects/notes/_note.html.haml +++ b/app/views/projects/notes/_note.html.haml @@ -21,9 +21,11 @@ - if access and not note.system %span.note-role.hidden-xs= access - unless note.system - %resolve-btn{ ":note-id" => note.id, ":resolved" => "false", "inline-template" => true, "v-ref:note_#{note.id}" => true } - %button.note-action-button.line-resolve-btn{ type: "button", ":class" => "{ 'is-active': isResolved }", ":aria-label" => "buttonText", "@click" => "resolve", ":title" => "buttonText" } - = icon("check") + %resolve-btn{ ":endpoint" => "'#{resolve_namespace_project_note_path(note.project.namespace, note.project, note)}'", ":note-id" => note.id, ":resolved" => "false", "inline-template" => true, "v-ref:note_#{note.id}" => true } + .note-action-button + = icon("spin spinner", "v-show" => "loading") + %button.line-resolve-btn{ type: "button", ":class" => "{ 'is-active': isResolved }", ":aria-label" => "buttonText", "@click" => "resolve", ":title" => "buttonText", "v-show" => "!loading", "v-el:button" => true } + = icon("check") - if current_user and not note.system = link_to '#', title: 'Award Emoji', class: 'note-action-button note-emoji-button js-add-award js-note-emoji', data: { position: 'right' } do = icon('spinner spin') diff --git a/config/routes.rb b/config/routes.rb index 21f3585bacd..9be5d423052 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -828,6 +828,7 @@ Rails.application.routes.draw do member do post :toggle_award_emoji delete :delete_attachment + post :resolve end end From 50e0728cc98ad42230daa1ddf010ff5c4ef0d3ad Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Tue, 5 Jul 2016 13:06:27 +0100 Subject: [PATCH 012/669] Moved away from vuejs-rails Fixed issue with resolve buttons always being visible - even when not logged in --- Gemfile | 1 - Gemfile.lock | 4 +++- .../components/resolve_btn.js.coffee | 2 +- .../projects/merge_requests/_show.html.haml | 17 +++++++++-------- app/views/projects/notes/_note.html.haml | 2 +- vendor/assets/javascripts/vue.js | 9 +++++++++ 6 files changed, 23 insertions(+), 12 deletions(-) create mode 100644 vendor/assets/javascripts/vue.js diff --git a/Gemfile b/Gemfile index 74fb7b1a2af..0504e643ed7 100644 --- a/Gemfile +++ b/Gemfile @@ -349,4 +349,3 @@ gem 'health_check', '~> 2.1.0' # System information gem 'vmstat', '~> 2.1.1' gem 'sys-filesystem', '~> 1.1.6' -gem 'vuejs-rails' diff --git a/Gemfile.lock b/Gemfile.lock index e9068d1d69e..a2a39320059 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -776,7 +776,6 @@ GEM descendants_tracker (~> 0.0, >= 0.0.3) equalizer (~> 0.0, >= 0.0.9) vmstat (2.1.1) - vuejs-rails (1.0.24) warden (1.2.6) rack (>= 1.0) web-console (2.3.0) @@ -985,8 +984,11 @@ DEPENDENCIES vmstat (~> 2.1.1) ======= vmstat (~> 2.1.0) +<<<<<<< HEAD vuejs-rails >>>>>>> Diff line comments resolve +======= +>>>>>>> Moved away from vuejs-rails web-console (~> 2.0) webmock (~> 1.21.0) wikicloth (= 0.8.1) diff --git a/app/assets/javascripts/line_comments/components/resolve_btn.js.coffee b/app/assets/javascripts/line_comments/components/resolve_btn.js.coffee index 79f97aa354e..5560a390424 100644 --- a/app/assets/javascripts/line_comments/components/resolve_btn.js.coffee +++ b/app/assets/javascripts/line_comments/components/resolve_btn.js.coffee @@ -8,7 +8,7 @@ loading: false computed: buttonText: -> - if this.comments[this.noteId] then "Mark as un-resolved" else "Mark as resolved" + if this.isResolved then "Mark as un-resolved" else "Mark as resolved" isResolved: -> this.comments[this.noteId] methods: updateTooltip: -> diff --git a/app/views/projects/merge_requests/_show.html.haml b/app/views/projects/merge_requests/_show.html.haml index 765ff68aeb1..4a99fe24ae3 100644 --- a/app/views/projects/merge_requests/_show.html.haml +++ b/app/views/projects/merge_requests/_show.html.haml @@ -44,14 +44,15 @@ = succeed '.' do = link_to "command line", "#modal_merge_info", class: "how_to_merge_link vlink", title: "How To Merge", "data-toggle" => "modal" - #resolve-all-app{ "v-cloak" => true } - %resolve-all{ "inline-template" => true } - .line-resolve-all{ "v-show" => "commentsCount > 0" } - %button.btn.btn-gray{ type: "button", "aria-label" => "Resolve all", "@click" => "updateAll", ":disabled" => "loading" } - = icon("spinner spin", "v-show" => "loading") - {{ buttonText }} - %span.line-resolve-text - {{ resolved }}/{{ commentsCount }} comments resolved + - if current_user + #resolve-all-app{ "v-cloak" => true } + %resolve-all{ "inline-template" => true } + .line-resolve-all{ "v-show" => "commentsCount > 0" } + %button.btn.btn-gray{ type: "button", "aria-label" => "Resolve all", "@click" => "updateAll", ":disabled" => "loading" } + = icon("spinner spin", "v-show" => "loading") + {{ buttonText }} + %span.line-resolve-text + {{ resolved }}/{{ commentsCount }} comments resolved - if @commits.nonzero? %ul.merge-request-tabs.nav-links.no-top.no-bottom diff --git a/app/views/projects/notes/_note.html.haml b/app/views/projects/notes/_note.html.haml index 57ffd6e5432..86194daeed1 100644 --- a/app/views/projects/notes/_note.html.haml +++ b/app/views/projects/notes/_note.html.haml @@ -20,7 +20,7 @@ - access = note_max_access_for_user(note) - if access and not note.system %span.note-role.hidden-xs= access - - unless note.system + - if !note.system && current_user %resolve-btn{ ":endpoint" => "'#{resolve_namespace_project_note_path(note.project.namespace, note.project, note)}'", ":note-id" => note.id, ":resolved" => "false", "inline-template" => true, "v-ref:note_#{note.id}" => true } .note-action-button = icon("spin spinner", "v-show" => "loading") diff --git a/vendor/assets/javascripts/vue.js b/vendor/assets/javascripts/vue.js new file mode 100644 index 00000000000..2c9a8a0e117 --- /dev/null +++ b/vendor/assets/javascripts/vue.js @@ -0,0 +1,9 @@ +/*! + * Vue.js v1.0.26 + * (c) 2016 Evan You + * Released under the MIT License. + */ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):t.Vue=e()}(this,function(){"use strict";function t(e,n,r){if(i(e,n))return void(e[n]=r);if(e._isVue)return void t(e._data,n,r);var s=e.__ob__;if(!s)return void(e[n]=r);if(s.convert(n,r),s.dep.notify(),s.vms)for(var o=s.vms.length;o--;){var a=s.vms[o];a._proxy(n),a._digest()}return r}function e(t,e){if(i(t,e)){delete t[e];var n=t.__ob__;if(!n)return void(t._isVue&&(delete t._data[e],t._digest()));if(n.dep.notify(),n.vms)for(var r=n.vms.length;r--;){var s=n.vms[r];s._unproxy(e),s._digest()}}}function i(t,e){return Oi.call(t,e)}function n(t){return Ti.test(t)}function r(t){var e=(t+"").charCodeAt(0);return 36===e||95===e}function s(t){return null==t?"":t.toString()}function o(t){if("string"!=typeof t)return t;var e=Number(t);return isNaN(e)?t:e}function a(t){return"true"===t?!0:"false"===t?!1:t}function h(t){var e=t.charCodeAt(0),i=t.charCodeAt(t.length-1);return e!==i||34!==e&&39!==e?t:t.slice(1,-1)}function l(t){return t.replace(Ni,c)}function c(t,e){return e?e.toUpperCase():""}function u(t){return t.replace(ji,"$1-$2").toLowerCase()}function f(t){return t.replace(Ei,c)}function p(t,e){return function(i){var n=arguments.length;return n?n>1?t.apply(e,arguments):t.call(e,i):t.call(e)}}function d(t,e){e=e||0;for(var i=t.length-e,n=new Array(i);i--;)n[i]=t[i+e];return n}function v(t,e){for(var i=Object.keys(e),n=i.length;n--;)t[i[n]]=e[i[n]];return t}function m(t){return null!==t&&"object"==typeof t}function g(t){return Si.call(t)===Fi}function _(t,e,i,n){Object.defineProperty(t,e,{value:i,enumerable:!!n,writable:!0,configurable:!0})}function y(t,e){var i,n,r,s,o,a=function h(){var a=Date.now()-s;e>a&&a>=0?i=setTimeout(h,e-a):(i=null,o=t.apply(r,n),i||(r=n=null))};return function(){return r=this,n=arguments,s=Date.now(),i||(i=setTimeout(a,e)),o}}function b(t,e){for(var i=t.length;i--;)if(t[i]===e)return i;return-1}function w(t){var e=function i(){return i.cancelled?void 0:t.apply(this,arguments)};return e.cancel=function(){e.cancelled=!0},e}function C(t,e){return t==e||(m(t)&&m(e)?JSON.stringify(t)===JSON.stringify(e):!1)}function $(t){this.size=0,this.limit=t,this.head=this.tail=void 0,this._keymap=Object.create(null)}function k(){var t,e=en.slice(hn,on).trim();if(e){t={};var i=e.match(vn);t.name=i[0],i.length>1&&(t.args=i.slice(1).map(x))}t&&(nn.filters=nn.filters||[]).push(t),hn=on+1}function x(t){if(mn.test(t))return{value:o(t),dynamic:!1};var e=h(t),i=e===t;return{value:i?t:e,dynamic:i}}function A(t){var e=dn.get(t);if(e)return e;for(en=t,ln=cn=!1,un=fn=pn=0,hn=0,nn={},on=0,an=en.length;an>on;on++)if(sn=rn,rn=en.charCodeAt(on),ln)39===rn&&92!==sn&&(ln=!ln);else if(cn)34===rn&&92!==sn&&(cn=!cn);else if(124===rn&&124!==en.charCodeAt(on+1)&&124!==en.charCodeAt(on-1))null==nn.expression?(hn=on+1,nn.expression=en.slice(0,on).trim()):k();else switch(rn){case 34:cn=!0;break;case 39:ln=!0;break;case 40:pn++;break;case 41:pn--;break;case 91:fn++;break;case 93:fn--;break;case 123:un++;break;case 125:un--}return null==nn.expression?nn.expression=en.slice(0,on).trim():0!==hn&&k(),dn.put(t,nn),nn}function O(t){return t.replace(_n,"\\$&")}function T(){var t=O(An.delimiters[0]),e=O(An.delimiters[1]),i=O(An.unsafeDelimiters[0]),n=O(An.unsafeDelimiters[1]);bn=new RegExp(i+"((?:.|\\n)+?)"+n+"|"+t+"((?:.|\\n)+?)"+e,"g"),wn=new RegExp("^"+i+"((?:.|\\n)+?)"+n+"$"),yn=new $(1e3)}function N(t){yn||T();var e=yn.get(t);if(e)return e;if(!bn.test(t))return null;for(var i,n,r,s,o,a,h=[],l=bn.lastIndex=0;i=bn.exec(t);)n=i.index,n>l&&h.push({value:t.slice(l,n)}),r=wn.test(i[0]),s=r?i[1]:i[2],o=s.charCodeAt(0),a=42===o,s=a?s.slice(1):s,h.push({tag:!0,value:s.trim(),html:r,oneTime:a}),l=n+i[0].length;return l1?t.map(function(t){return E(t,e)}).join("+"):E(t[0],e,!0)}function E(t,e,i){return t.tag?t.oneTime&&e?'"'+e.$eval(t.value)+'"':S(t.value,i):'"'+t.value+'"'}function S(t,e){if(Cn.test(t)){var i=A(t);return i.filters?"this._applyFilters("+i.expression+",null,"+JSON.stringify(i.filters)+",false)":"("+t+")"}return e?t:"("+t+")"}function F(t,e,i,n){R(t,1,function(){e.appendChild(t)},i,n)}function D(t,e,i,n){R(t,1,function(){B(t,e)},i,n)}function P(t,e,i){R(t,-1,function(){z(t)},e,i)}function R(t,e,i,n,r){var s=t.__v_trans;if(!s||!s.hooks&&!qi||!n._isCompiled||n.$parent&&!n.$parent._isCompiled)return i(),void(r&&r());var o=e>0?"enter":"leave";s[o](i,r)}function L(t){if("string"==typeof t){t=document.querySelector(t)}return t}function H(t){if(!t)return!1;var e=t.ownerDocument.documentElement,i=t.parentNode;return e===t||e===i||!(!i||1!==i.nodeType||!e.contains(i))}function I(t,e){var i=t.getAttribute(e);return null!==i&&t.removeAttribute(e),i}function M(t,e){var i=I(t,":"+e);return null===i&&(i=I(t,"v-bind:"+e)),i}function V(t,e){return t.hasAttribute(e)||t.hasAttribute(":"+e)||t.hasAttribute("v-bind:"+e)}function B(t,e){e.parentNode.insertBefore(t,e)}function W(t,e){e.nextSibling?B(t,e.nextSibling):e.parentNode.appendChild(t)}function z(t){t.parentNode.removeChild(t)}function U(t,e){e.firstChild?B(t,e.firstChild):e.appendChild(t)}function J(t,e){var i=t.parentNode;i&&i.replaceChild(e,t)}function q(t,e,i,n){t.addEventListener(e,i,n)}function Q(t,e,i){t.removeEventListener(e,i)}function G(t){var e=t.className;return"object"==typeof e&&(e=e.baseVal||""),e}function Z(t,e){Mi&&!/svg$/.test(t.namespaceURI)?t.className=e:t.setAttribute("class",e)}function X(t,e){if(t.classList)t.classList.add(e);else{var i=" "+G(t)+" ";i.indexOf(" "+e+" ")<0&&Z(t,(i+e).trim())}}function Y(t,e){if(t.classList)t.classList.remove(e);else{for(var i=" "+G(t)+" ",n=" "+e+" ";i.indexOf(n)>=0;)i=i.replace(n," ");Z(t,i.trim())}t.className||t.removeAttribute("class")}function K(t,e){var i,n;if(it(t)&&at(t.content)&&(t=t.content),t.hasChildNodes())for(tt(t),n=e?document.createDocumentFragment():document.createElement("div");i=t.firstChild;)n.appendChild(i);return n}function tt(t){for(var e;e=t.firstChild,et(e);)t.removeChild(e);for(;e=t.lastChild,et(e);)t.removeChild(e)}function et(t){return t&&(3===t.nodeType&&!t.data.trim()||8===t.nodeType)}function it(t){return t.tagName&&"template"===t.tagName.toLowerCase()}function nt(t,e){var i=An.debug?document.createComment(t):document.createTextNode(e?" ":"");return i.__v_anchor=!0,i}function rt(t){if(t.hasAttributes())for(var e=t.attributes,i=0,n=e.length;n>i;i++){var r=e[i].name;if(Nn.test(r))return l(r.replace(Nn,""))}}function st(t,e,i){for(var n;t!==e;)n=t.nextSibling,i(t),t=n;i(e)}function ot(t,e,i,n,r){function s(){if(a++,o&&a>=h.length){for(var t=0;tr;r++){var o=n[r];jn.test(o)||En.test(o)||(e=i[o],g(e)&&(i[o]=wi.extend(e)))}}function dt(t){var e,i,n=t.props;if(Di(n))for(t.props={},e=n.length;e--;)i=n[e],"string"==typeof i?t.props[i]=null:i.name&&(t.props[i.name]=i);else if(g(n)){var r=Object.keys(n);for(e=r.length;e--;)i=n[r[e]],"function"==typeof i&&(n[r[e]]={type:i})}}function vt(t){if(Di(t)){for(var e,i={},n=t.length;n--;){e=t[n];var r="function"==typeof e?e.options&&e.options.name||e.id:e.name||e.id;r&&(i[r]=e)}return i}return t}function mt(t,e,n){function r(i){var r=Sn[i]||Fn;o[i]=r(t[i],e[i],n,i)}pt(e),dt(e);var s,o={};if(e["extends"]&&(t="function"==typeof e["extends"]?mt(t,e["extends"].options,n):mt(t,e["extends"],n)),e.mixins)for(var a=0,h=e.mixins.length;h>a;a++){var l=e.mixins[a],c=l.prototype instanceof wi?l.options:l;t=mt(t,c,n)}for(s in t)r(s);for(s in e)i(t,s)||r(s);return o}function gt(t,e,i,n){if("string"==typeof i){var r,s=t[e],o=s[i]||s[r=l(i)]||s[r.charAt(0).toUpperCase()+r.slice(1)];return o}}function _t(){this.id=Dn++,this.subs=[]}function yt(t){Hn=!1,t(),Hn=!0}function bt(t){if(this.value=t,this.dep=new _t,_(t,"__ob__",this),Di(t)){var e=Pi?wt:Ct;e(t,Rn,Ln),this.observeArray(t)}else this.walk(t)}function wt(t,e){t.__proto__=e}function Ct(t,e,i){for(var n=0,r=i.length;r>n;n++){var s=i[n];_(t,s,e[s])}}function $t(t,e){if(t&&"object"==typeof t){var n;return i(t,"__ob__")&&t.__ob__ instanceof bt?n=t.__ob__:Hn&&(Di(t)||g(t))&&Object.isExtensible(t)&&!t._isVue&&(n=new bt(t)),n&&e&&n.addVm(e),n}}function kt(t,e,i){var n=new _t,r=Object.getOwnPropertyDescriptor(t,e);if(!r||r.configurable!==!1){var s=r&&r.get,o=r&&r.set,a=$t(i);Object.defineProperty(t,e,{enumerable:!0,configurable:!0,get:function(){var e=s?s.call(t):i;if(_t.target&&(n.depend(),a&&a.dep.depend(),Di(e)))for(var r,o=0,h=e.length;h>o;o++)r=e[o],r&&r.__ob__&&r.__ob__.dep.depend();return e},set:function(e){var r=s?s.call(t):i;e!==r&&(o?o.call(t,e):i=e,a=$t(e),n.notify())}})}}function xt(t){t.prototype._init=function(t){t=t||{},this.$el=null,this.$parent=t.parent,this.$root=this.$parent?this.$parent.$root:this,this.$children=[],this.$refs={},this.$els={},this._watchers=[],this._directives=[],this._uid=Mn++,this._isVue=!0,this._events={},this._eventsCount={},this._isFragment=!1,this._fragment=this._fragmentStart=this._fragmentEnd=null,this._isCompiled=this._isDestroyed=this._isReady=this._isAttached=this._isBeingDestroyed=this._vForRemoving=!1,this._unlinkFn=null,this._context=t._context||this.$parent,this._scope=t._scope,this._frag=t._frag,this._frag&&this._frag.children.push(this),this.$parent&&this.$parent.$children.push(this),t=this.$options=mt(this.constructor.options,t,this),this._updateRef(),this._data={},this._callHook("init"),this._initState(),this._initEvents(),this._callHook("created"),t.el&&this.$mount(t.el)}}function At(t){if(void 0===t)return"eof";var e=t.charCodeAt(0);switch(e){case 91:case 93:case 46:case 34:case 39:case 48:return t;case 95:case 36:return"ident";case 32:case 9:case 10:case 13:case 160:case 65279:case 8232:case 8233:return"ws"}return e>=97&&122>=e||e>=65&&90>=e?"ident":e>=49&&57>=e?"number":"else"}function Ot(t){var e=t.trim();return"0"===t.charAt(0)&&isNaN(t)?!1:n(e)?h(e):"*"+e}function Tt(t){function e(){var e=t[c+1];return u===Xn&&"'"===e||u===Yn&&'"'===e?(c++,n="\\"+e,p[Bn](),!0):void 0}var i,n,r,s,o,a,h,l=[],c=-1,u=Jn,f=0,p=[];for(p[Wn]=function(){void 0!==r&&(l.push(r),r=void 0)},p[Bn]=function(){void 0===r?r=n:r+=n},p[zn]=function(){p[Bn](),f++},p[Un]=function(){if(f>0)f--,u=Zn,p[Bn]();else{if(f=0,r=Ot(r),r===!1)return!1;p[Wn]()}};null!=u;)if(c++,i=t[c],"\\"!==i||!e()){if(s=At(i),h=er[u],o=h[s]||h["else"]||tr,o===tr)return;if(u=o[0],a=p[o[1]],a&&(n=o[2],n=void 0===n?i:n,a()===!1))return;if(u===Kn)return l.raw=t,l}}function Nt(t){var e=Vn.get(t);return e||(e=Tt(t),e&&Vn.put(t,e)),e}function jt(t,e){return It(e).get(t)}function Et(e,i,n){var r=e;if("string"==typeof i&&(i=Tt(i)),!i||!m(e))return!1;for(var s,o,a=0,h=i.length;h>a;a++)s=e,o=i[a],"*"===o.charAt(0)&&(o=It(o.slice(1)).get.call(r,r)),h-1>a?(e=e[o],m(e)||(e={},t(s,o,e))):Di(e)?e.$set(o,n):o in e?e[o]=n:t(e,o,n);return!0}function St(){}function Ft(t,e){var i=vr.length;return vr[i]=e?t.replace(lr,"\\n"):t,'"'+i+'"'}function Dt(t){var e=t.charAt(0),i=t.slice(1);return sr.test(i)?t:(i=i.indexOf('"')>-1?i.replace(ur,Pt):i,e+"scope."+i)}function Pt(t,e){return vr[e]}function Rt(t){ar.test(t),vr.length=0;var e=t.replace(cr,Ft).replace(hr,"");return e=(" "+e).replace(pr,Dt).replace(ur,Pt),Lt(e)}function Lt(t){try{return new Function("scope","return "+t+";")}catch(e){return St}}function Ht(t){var e=Nt(t);return e?function(t,i){Et(t,e,i)}:void 0}function It(t,e){t=t.trim();var i=nr.get(t);if(i)return e&&!i.set&&(i.set=Ht(i.exp)),i;var n={exp:t};return n.get=Mt(t)&&t.indexOf("[")<0?Lt("scope."+t):Rt(t),e&&(n.set=Ht(t)),nr.put(t,n),n}function Mt(t){return fr.test(t)&&!dr.test(t)&&"Math."!==t.slice(0,5)}function Vt(){gr.length=0,_r.length=0,yr={},br={},wr=!1}function Bt(){for(var t=!0;t;)t=!1,Wt(gr),Wt(_r),gr.length?t=!0:(Li&&An.devtools&&Li.emit("flush"),Vt())}function Wt(t){for(var e=0;e0){var o=s+(n?e:ht(e));r=Pr.get(o),r||(r=De(i,t.$options,!0),Pr.put(o,r))}else r=De(i,t.$options,!0);this.linker=r}function oe(t,e,i){var n=t.node.previousSibling;if(n){for(t=n.__v_frag;!(t&&t.forId===i&&t.inserted||n===e);){if(n=n.previousSibling,!n)return;t=n.__v_frag}return t}}function ae(t){var e=t.node;if(t.end)for(;!e.__vue__&&e!==t.end&&e.nextSibling;)e=e.nextSibling;return e.__vue__}function he(t){for(var e=-1,i=new Array(Math.floor(t));++ea;a++)if(n=t.options[a],s=i?n.hasAttribute("selected"):n.selected){if(r=n.hasOwnProperty("_value")?n._value:n.value,!e)return r;o.push(r)}return o}function ue(t,e){for(var i=t.length;i--;)if(C(t[i],e))return i;return-1}function fe(t,e){var i=e.map(function(t){var e=t.charCodeAt(0);return e>47&&58>e?parseInt(t,10):1===t.length&&(e=t.toUpperCase().charCodeAt(0),e>64&&91>e)?e:is[t]});return i=[].concat.apply([],i),function(e){return i.indexOf(e.keyCode)>-1?t.call(this,e):void 0}}function pe(t){return function(e){return e.stopPropagation(),t.call(this,e)}}function de(t){return function(e){return e.preventDefault(),t.call(this,e)}}function ve(t){return function(e){return e.target===e.currentTarget?t.call(this,e):void 0}}function me(t){if(as[t])return as[t];var e=ge(t);return as[t]=as[e]=e,e}function ge(t){t=u(t);var e=l(t),i=e.charAt(0).toUpperCase()+e.slice(1);hs||(hs=document.createElement("div"));var n,r=rs.length;if("filter"!==e&&e in hs.style)return{kebab:t,camel:e};for(;r--;)if(n=ss[r]+i,n in hs.style)return{kebab:rs[r]+t,camel:n}}function _e(t){var e=[];if(Di(t))for(var i=0,n=t.length;n>i;i++){var r=t[i];if(r)if("string"==typeof r)e.push(r);else for(var s in r)r[s]&&e.push(s)}else if(m(t))for(var o in t)t[o]&&e.push(o);return e}function ye(t,e,i){if(e=e.trim(),-1===e.indexOf(" "))return void i(t,e);for(var n=e.split(/\s+/),r=0,s=n.length;s>r;r++)i(t,n[r])}function be(t,e,i){function n(){++s>=r?i():t[s].call(e,n)}var r=t.length,s=0;t[0].call(e,n)}function we(t,e,i){for(var r,s,o,a,h,c,f,p=[],d=Object.keys(e),v=d.length;v--;)s=d[v],r=e[s]||ks,h=l(s),xs.test(h)&&(f={name:s,path:h,options:r,mode:$s.ONE_WAY,raw:null},o=u(s),null===(a=M(t,o))&&(null!==(a=M(t,o+".sync"))?f.mode=$s.TWO_WAY:null!==(a=M(t,o+".once"))&&(f.mode=$s.ONE_TIME)),null!==a?(f.raw=a,c=A(a),a=c.expression,f.filters=c.filters,n(a)&&!c.filters?f.optimizedLiteral=!0:f.dynamic=!0,f.parentPath=a):null!==(a=I(t,o))&&(f.raw=a),p.push(f));return Ce(p)}function Ce(t){return function(e,n){e._props={};for(var r,s,l,c,f,p=e.$options.propsData,d=t.length;d--;)if(r=t[d],f=r.raw,s=r.path,l=r.options,e._props[s]=r,p&&i(p,s)&&ke(e,r,p[s]),null===f)ke(e,r,void 0);else if(r.dynamic)r.mode===$s.ONE_TIME?(c=(n||e._context||e).$get(r.parentPath),ke(e,r,c)):e._context?e._bindDir({name:"prop",def:Os,prop:r},null,null,n):ke(e,r,e.$get(r.parentPath));else if(r.optimizedLiteral){var v=h(f);c=v===f?a(o(f)):v,ke(e,r,c)}else c=l.type!==Boolean||""!==f&&f!==u(r.name)?f:!0,ke(e,r,c)}}function $e(t,e,i,n){var r=e.dynamic&&Mt(e.parentPath),s=i;void 0===s&&(s=Ae(t,e)),s=Te(e,s,t);var o=s!==i;Oe(e,s,t)||(s=void 0),r&&!o?yt(function(){n(s)}):n(s)}function ke(t,e,i){$e(t,e,i,function(i){kt(t,e.path,i)})}function xe(t,e,i){$e(t,e,i,function(i){t[e.path]=i})}function Ae(t,e){var n=e.options;if(!i(n,"default"))return n.type===Boolean?!1:void 0;var r=n["default"];return m(r),"function"==typeof r&&n.type!==Function?r.call(t):r}function Oe(t,e,i){if(!t.options.required&&(null===t.raw||null==e))return!0;var n=t.options,r=n.type,s=!r,o=[];if(r){Di(r)||(r=[r]);for(var a=0;ar;r++)n[r]._bind();return n}function Re(t,e){return t=t.descriptor.def.priority||zs,e=e.descriptor.def.priority||zs,t>e?-1:t===e?0:1}function Le(t,e,i,n){function r(r){He(t,e,r),i&&n&&He(i,n)}return r.dirs=e,r}function He(t,e,i){for(var n=e.length;n--;)e[n]._teardown()}function Ie(t,e,i,n){var r=we(e,i,t),s=Pe(function(){r(t,n)},t);return Le(t,s)}function Me(t,e,i){var n,r,s=e._containerAttrs,o=e._replacerAttrs;return 11!==t.nodeType&&(e._asComponent?(s&&i&&(n=ti(s,i)),o&&(r=ti(o,e))):r=ti(t.attributes,e)),e._containerAttrs=e._replacerAttrs=null,function(t,e,i){var s,o=t._context;o&&n&&(s=Pe(function(){n(o,e,null,i)},o));var a=Pe(function(){r&&r(t,e)},t);return Le(t,a,o,s)}}function Ve(t,e){var i=t.nodeType;return 1!==i||ri(t)?3===i&&t.data.trim()?We(t,e):null:Be(t,e)}function Be(t,e){if("TEXTAREA"===t.tagName){var i=N(t.value);i&&(t.setAttribute(":value",j(i)),t.value="")}var n,r=t.hasAttributes(),s=r&&d(t.attributes);return r&&(n=Xe(t,s,e)),n||(n=Ge(t,e)),n||(n=Ze(t,e)),!n&&r&&(n=ti(s,e)),n}function We(t,e){if(t._skip)return ze;var i=N(t.wholeText);if(!i)return null;for(var n=t.nextSibling;n&&3===n.nodeType;)n._skip=!0,n=n.nextSibling;for(var r,s,o=document.createDocumentFragment(),a=0,h=i.length;h>a;a++)s=i[a],r=s.tag?Ue(s,e):document.createTextNode(s.value),o.appendChild(r);return Je(i,o,e)}function ze(t,e){z(e)}function Ue(t,e){function i(e){if(!t.descriptor){var i=A(t.value);t.descriptor={name:e,def:bs[e],expression:i.expression,filters:i.filters}}}var n;return t.oneTime?n=document.createTextNode(t.value):t.html?(n=document.createComment("v-html"),i("html")):(n=document.createTextNode(" "),i("text")),n}function Je(t,e){return function(i,n,r,o){for(var a,h,l,c=e.cloneNode(!0),u=d(c.childNodes),f=0,p=t.length;p>f;f++)a=t[f],h=a.value,a.tag&&(l=u[f],a.oneTime?(h=(o||i).$eval(h),a.html?J(l,Xt(h,!0)):l.data=s(h)):i._bindDir(a.descriptor,l,r,o));J(n,c)}}function qe(t,e){for(var i,n,r,s=[],o=0,a=t.length;a>o;o++)r=t[o],i=Ve(r,e),n=i&&i.terminal||"SCRIPT"===r.tagName||!r.hasChildNodes()?null:qe(r.childNodes,e),s.push(i,n);return s.length?Qe(s):null}function Qe(t){return function(e,i,n,r,s){for(var o,a,h,l=0,c=0,u=t.length;u>l;c++){o=i[c],a=t[l++],h=t[l++];var f=d(o.childNodes);a&&a(e,o,n,r,s),h&&h(e,f,n,r,s)}}}function Ge(t,e){var i=t.tagName.toLowerCase();if(!jn.test(i)){var n=gt(e,"elementDirectives",i);return n?Ke(t,i,"",e,n):void 0}}function Ze(t,e){var i=lt(t,e);if(i){var n=rt(t),r={name:"component",ref:n,expression:i.id,def:Hs.component,modifiers:{literal:!i.dynamic}},s=function(t,e,i,s,o){n&&kt((s||t).$refs,n,null),t._bindDir(r,e,i,s,o)};return s.terminal=!0,s}}function Xe(t,e,i){if(null!==I(t,"v-pre"))return Ye;if(t.hasAttribute("v-else")){var n=t.previousElementSibling;if(n&&n.hasAttribute("v-if"))return Ye}for(var r,s,o,a,h,l,c,u,f,p,d=0,v=e.length;v>d;d++)r=e[d],s=r.name.replace(Bs,""),(h=s.match(Vs))&&(f=gt(i,"directives",h[1]),f&&f.terminal&&(!p||(f.priority||Us)>p.priority)&&(p=f,c=r.name,a=ei(r.name),o=r.value,l=h[1],u=h[2]));return p?Ke(t,l,o,i,p,c,u,a):void 0}function Ye(){}function Ke(t,e,i,n,r,s,o,a){var h=A(i),l={name:e,arg:o,expression:h.expression,filters:h.filters,raw:i,attr:s,modifiers:a,def:r};"for"!==e&&"router-view"!==e||(l.ref=rt(t));var c=function(t,e,i,n,r){l.ref&&kt((n||t).$refs,l.ref,null),t._bindDir(l,e,i,n,r)};return c.terminal=!0,c}function ti(t,e){function i(t,e,i){var n=i&&ni(i),r=!n&&A(s);v.push({name:t,attr:o,raw:a,def:e,arg:l,modifiers:c,expression:r&&r.expression,filters:r&&r.filters,interp:i,hasOneTime:n})}for(var n,r,s,o,a,h,l,c,u,f,p,d=t.length,v=[];d--;)if(n=t[d],r=o=n.name,s=a=n.value,f=N(s),l=null,c=ei(r),r=r.replace(Bs,""),f)s=j(f),l=r,i("bind",bs.bind,f);else if(Ws.test(r))c.literal=!Is.test(r),i("transition",Hs.transition);else if(Ms.test(r))l=r.replace(Ms,""),i("on",bs.on);else if(Is.test(r))h=r.replace(Is,""),"style"===h||"class"===h?i(h,Hs[h]):(l=h,i("bind",bs.bind));else if(p=r.match(Vs)){if(h=p[1],l=p[2],"else"===h)continue;u=gt(e,"directives",h,!0),u&&i(h,u)}return v.length?ii(v):void 0}function ei(t){var e=Object.create(null),i=t.match(Bs);if(i)for(var n=i.length;n--;)e[i[n].slice(1)]=!0;return e}function ii(t){return function(e,i,n,r,s){for(var o=t.length;o--;)e._bindDir(t[o],i,n,r,s)}}function ni(t){for(var e=t.length;e--;)if(t[e].oneTime)return!0}function ri(t){return"SCRIPT"===t.tagName&&(!t.hasAttribute("type")||"text/javascript"===t.getAttribute("type"))}function si(t,e){return e&&(e._containerAttrs=ai(t)),it(t)&&(t=Xt(t)),e&&(e._asComponent&&!e.template&&(e.template=""),e.template&&(e._content=K(t),t=oi(t,e))),at(t)&&(U(nt("v-start",!0),t),t.appendChild(nt("v-end",!0))),t}function oi(t,e){var i=e.template,n=Xt(i,!0);if(n){var r=n.firstChild,s=r.tagName&&r.tagName.toLowerCase();return e.replace?(t===document.body,n.childNodes.length>1||1!==r.nodeType||"component"===s||gt(e,"components",s)||V(r,"is")||gt(e,"elementDirectives",s)||r.hasAttribute("v-for")||r.hasAttribute("v-if")?n:(e._replacerAttrs=ai(r),hi(t,r),r)):(t.appendChild(n),t)}}function ai(t){return 1===t.nodeType&&t.hasAttributes()?d(t.attributes):void 0}function hi(t,e){for(var i,n,r=t.attributes,s=r.length;s--;)i=r[s].name,n=r[s].value,e.hasAttribute(i)||Js.test(i)?"class"===i&&!N(n)&&(n=n.trim())&&n.split(/\s+/).forEach(function(t){X(e,t)}):e.setAttribute(i,n)}function li(t,e){if(e){for(var i,n,r=t._slotContents=Object.create(null),s=0,o=e.children.length;o>s;s++)i=e.children[s],(n=i.getAttribute("slot"))&&(r[n]||(r[n]=[])).push(i);for(n in r)r[n]=ci(r[n],e);if(e.hasChildNodes()){var a=e.childNodes;if(1===a.length&&3===a[0].nodeType&&!a[0].data.trim())return;r["default"]=ci(e.childNodes,e)}}}function ci(t,e){var i=document.createDocumentFragment();t=d(t);for(var n=0,r=t.length;r>n;n++){var s=t[n];!it(s)||s.hasAttribute("v-if")||s.hasAttribute("v-for")||(e.removeChild(s),s=Xt(s,!0)),i.appendChild(s)}return i}function ui(t){function e(){}function n(t,e){var i=new Ut(e,t,null,{lazy:!0});return function(){return i.dirty&&i.evaluate(),_t.target&&i.depend(),i.value}}Object.defineProperty(t.prototype,"$data",{get:function(){return this._data},set:function(t){t!==this._data&&this._setData(t)}}),t.prototype._initState=function(){this._initProps(),this._initMeta(),this._initMethods(),this._initData(),this._initComputed()},t.prototype._initProps=function(){var t=this.$options,e=t.el,i=t.props;e=t.el=L(e),this._propsUnlinkFn=e&&1===e.nodeType&&i?Ie(this,e,i,this._scope):null},t.prototype._initData=function(){var t=this.$options.data,e=this._data=t?t():{};g(e)||(e={});var n,r,s=this._props,o=Object.keys(e);for(n=o.length;n--;)r=o[n],s&&i(s,r)||this._proxy(r);$t(e,this)},t.prototype._setData=function(t){t=t||{};var e=this._data;this._data=t;var n,r,s;for(n=Object.keys(e),s=n.length;s--;)r=n[s],r in t||this._unproxy(r);for(n=Object.keys(t),s=n.length;s--;)r=n[s],i(this,r)||this._proxy(r);e.__ob__.removeVm(this),$t(t,this),this._digest()},t.prototype._proxy=function(t){if(!r(t)){var e=this;Object.defineProperty(e,t,{configurable:!0,enumerable:!0,get:function(){return e._data[t]},set:function(i){e._data[t]=i}})}},t.prototype._unproxy=function(t){r(t)||delete this[t]},t.prototype._digest=function(){for(var t=0,e=this._watchers.length;e>t;t++)this._watchers[t].update(!0)},t.prototype._initComputed=function(){var t=this.$options.computed;if(t)for(var i in t){var r=t[i],s={enumerable:!0,configurable:!0};"function"==typeof r?(s.get=n(r,this),s.set=e):(s.get=r.get?r.cache!==!1?n(r.get,this):p(r.get,this):e,s.set=r.set?p(r.set,this):e),Object.defineProperty(this,i,s)}},t.prototype._initMethods=function(){var t=this.$options.methods;if(t)for(var e in t)this[e]=p(t[e],this)},t.prototype._initMeta=function(){var t=this.$options._meta;if(t)for(var e in t)kt(this,e,t[e])}}function fi(t){function e(t,e){for(var i,n,r,s=e.attributes,o=0,a=s.length;a>o;o++)i=s[o].name,Qs.test(i)&&(i=i.replace(Qs,""),n=s[o].value,Mt(n)&&(n+=".apply(this, $arguments)"),r=(t._scope||t._context).$eval(n,!0),r._fromParent=!0,t.$on(i.replace(Qs),r))}function i(t,e,i){if(i){var r,s,o,a;for(s in i)if(r=i[s],Di(r))for(o=0,a=r.length;a>o;o++)n(t,e,s,r[o]);else n(t,e,s,r)}}function n(t,e,i,r,s){var o=typeof r;if("function"===o)t[e](i,r,s);else if("string"===o){var a=t.$options.methods,h=a&&a[r];h&&t[e](i,h,s)}else r&&"object"===o&&n(t,e,i,r.handler,r)}function r(){this._isAttached||(this._isAttached=!0,this.$children.forEach(s))}function s(t){!t._isAttached&&H(t.$el)&&t._callHook("attached")}function o(){this._isAttached&&(this._isAttached=!1,this.$children.forEach(a))}function a(t){t._isAttached&&!H(t.$el)&&t._callHook("detached")}t.prototype._initEvents=function(){var t=this.$options;t._asComponent&&e(this,t.el),i(this,"$on",t.events),i(this,"$watch",t.watch)},t.prototype._initDOMHooks=function(){this.$on("hook:attached",r),this.$on("hook:detached",o)},t.prototype._callHook=function(t){this.$emit("pre-hook:"+t);var e=this.$options[t];if(e)for(var i=0,n=e.length;n>i;i++)e[i].call(this);this.$emit("hook:"+t)}}function pi(){}function di(t,e,i,n,r,s){this.vm=e,this.el=i,this.descriptor=t,this.name=t.name,this.expression=t.expression,this.arg=t.arg,this.modifiers=t.modifiers,this.filters=t.filters,this.literal=this.modifiers&&this.modifiers.literal,this._locked=!1,this._bound=!1,this._listeners=null,this._host=n,this._scope=r,this._frag=s}function vi(t){t.prototype._updateRef=function(t){var e=this.$options._ref;if(e){var i=(this._scope||this._context).$refs;t?i[e]===this&&(i[e]=null):i[e]=this}},t.prototype._compile=function(t){var e=this.$options,i=t;if(t=si(t,e),this._initElement(t),1!==t.nodeType||null===I(t,"v-pre")){var n=this._context&&this._context.$options,r=Me(t,e,n);li(this,e._content);var s,o=this.constructor;e._linkerCachable&&(s=o.linker,s||(s=o.linker=De(t,e)));var a=r(this,t,this._scope),h=s?s(this,t):De(t,e)(this,t);this._unlinkFn=function(){a(),h(!0)},e.replace&&J(i,t),this._isCompiled=!0,this._callHook("compiled")}},t.prototype._initElement=function(t){at(t)?(this._isFragment=!0,this.$el=this._fragmentStart=t.firstChild,this._fragmentEnd=t.lastChild,3===this._fragmentStart.nodeType&&(this._fragmentStart.data=this._fragmentEnd.data=""),this._fragment=t):this.$el=t,this.$el.__vue__=this,this._callHook("beforeCompile")},t.prototype._bindDir=function(t,e,i,n,r){this._directives.push(new di(t,this,e,i,n,r))},t.prototype._destroy=function(t,e){if(this._isBeingDestroyed)return void(e||this._cleanup());var i,n,r=this,s=function(){!i||n||e||r._cleanup()};t&&this.$el&&(n=!0,this.$remove(function(){ +n=!1,s()})),this._callHook("beforeDestroy"),this._isBeingDestroyed=!0;var o,a=this.$parent;for(a&&!a._isBeingDestroyed&&(a.$children.$remove(this),this._updateRef(!0)),o=this.$children.length;o--;)this.$children[o].$destroy();for(this._propsUnlinkFn&&this._propsUnlinkFn(),this._unlinkFn&&this._unlinkFn(),o=this._watchers.length;o--;)this._watchers[o].teardown();this.$el&&(this.$el.__vue__=null),i=!0,s()},t.prototype._cleanup=function(){this._isDestroyed||(this._frag&&this._frag.children.$remove(this),this._data&&this._data.__ob__&&this._data.__ob__.removeVm(this),this.$el=this.$parent=this.$root=this.$children=this._watchers=this._context=this._scope=this._directives=null,this._isDestroyed=!0,this._callHook("destroyed"),this.$off())}}function mi(t){t.prototype._applyFilters=function(t,e,i,n){var r,s,o,a,h,l,c,u,f;for(l=0,c=i.length;c>l;l++)if(r=i[n?c-l-1:l],s=gt(this.$options,"filters",r.name,!0),s&&(s=n?s.write:s.read||s,"function"==typeof s)){if(o=n?[t,e]:[t],h=n?2:1,r.args)for(u=0,f=r.args.length;f>u;u++)a=r.args[u],o[u+h]=a.dynamic?this.$get(a.value):a.value;t=s.apply(this,o)}return t},t.prototype._resolveComponent=function(e,i){var n;if(n="function"==typeof e?e:gt(this.$options,"components",e,!0))if(n.options)i(n);else if(n.resolved)i(n.resolved);else if(n.requested)n.pendingCallbacks.push(i);else{n.requested=!0;var r=n.pendingCallbacks=[i];n.call(this,function(e){g(e)&&(e=t.extend(e)),n.resolved=e;for(var i=0,s=r.length;s>i;i++)r[i](e)},function(t){})}}}function gi(t){function i(t){return JSON.parse(JSON.stringify(t))}t.prototype.$get=function(t,e){var i=It(t);if(i){if(e){var n=this;return function(){n.$arguments=d(arguments);var t=i.get.call(n,n);return n.$arguments=null,t}}try{return i.get.call(this,this)}catch(r){}}},t.prototype.$set=function(t,e){var i=It(t,!0);i&&i.set&&i.set.call(this,this,e)},t.prototype.$delete=function(t){e(this._data,t)},t.prototype.$watch=function(t,e,i){var n,r=this;"string"==typeof t&&(n=A(t),t=n.expression);var s=new Ut(r,t,e,{deep:i&&i.deep,sync:i&&i.sync,filters:n&&n.filters,user:!i||i.user!==!1});return i&&i.immediate&&e.call(r,s.value),function(){s.teardown()}},t.prototype.$eval=function(t,e){if(Gs.test(t)){var i=A(t),n=this.$get(i.expression,e);return i.filters?this._applyFilters(n,null,i.filters):n}return this.$get(t,e)},t.prototype.$interpolate=function(t){var e=N(t),i=this;return e?1===e.length?i.$eval(e[0].value)+"":e.map(function(t){return t.tag?i.$eval(t.value):t.value}).join(""):t},t.prototype.$log=function(t){var e=t?jt(this._data,t):this._data;if(e&&(e=i(e)),!t){var n;for(n in this.$options.computed)e[n]=i(this[n]);if(this._props)for(n in this._props)e[n]=i(this[n])}console.log(e)}}function _i(t){function e(t,e,n,r,s,o){e=i(e);var a=!H(e),h=r===!1||a?s:o,l=!a&&!t._isAttached&&!H(t.$el);return t._isFragment?(st(t._fragmentStart,t._fragmentEnd,function(i){h(i,e,t)}),n&&n()):h(t.$el,e,t,n),l&&t._callHook("attached"),t}function i(t){return"string"==typeof t?document.querySelector(t):t}function n(t,e,i,n){e.appendChild(t),n&&n()}function r(t,e,i,n){B(t,e),n&&n()}function s(t,e,i){z(t),i&&i()}t.prototype.$nextTick=function(t){Yi(t,this)},t.prototype.$appendTo=function(t,i,r){return e(this,t,i,r,n,F)},t.prototype.$prependTo=function(t,e,n){return t=i(t),t.hasChildNodes()?this.$before(t.firstChild,e,n):this.$appendTo(t,e,n),this},t.prototype.$before=function(t,i,n){return e(this,t,i,n,r,D)},t.prototype.$after=function(t,e,n){return t=i(t),t.nextSibling?this.$before(t.nextSibling,e,n):this.$appendTo(t.parentNode,e,n),this},t.prototype.$remove=function(t,e){if(!this.$el.parentNode)return t&&t();var i=this._isAttached&&H(this.$el);i||(e=!1);var n=this,r=function(){i&&n._callHook("detached"),t&&t()};if(this._isFragment)ot(this._fragmentStart,this._fragmentEnd,this,this._fragment,r);else{var o=e===!1?s:P;o(this.$el,this,r)}return this}}function yi(t){function e(t,e,n){var r=t.$parent;if(r&&n&&!i.test(e))for(;r;)r._eventsCount[e]=(r._eventsCount[e]||0)+n,r=r.$parent}t.prototype.$on=function(t,i){return(this._events[t]||(this._events[t]=[])).push(i),e(this,t,1),this},t.prototype.$once=function(t,e){function i(){n.$off(t,i),e.apply(this,arguments)}var n=this;return i.fn=e,this.$on(t,i),this},t.prototype.$off=function(t,i){var n;if(!arguments.length){if(this.$parent)for(t in this._events)n=this._events[t],n&&e(this,t,-n.length);return this._events={},this}if(n=this._events[t],!n)return this;if(1===arguments.length)return e(this,t,-n.length),this._events[t]=null,this;for(var r,s=n.length;s--;)if(r=n[s],r===i||r.fn===i){e(this,t,-1),n.splice(s,1);break}return this},t.prototype.$emit=function(t){var e="string"==typeof t;t=e?t:t.name;var i=this._events[t],n=e||!i;if(i){i=i.length>1?d(i):i;var r=e&&i.some(function(t){return t._fromParent});r&&(n=!1);for(var s=d(arguments,1),o=0,a=i.length;a>o;o++){var h=i[o],l=h.apply(this,s);l!==!0||r&&!h._fromParent||(n=!0)}}return n},t.prototype.$broadcast=function(t){var e="string"==typeof t;if(t=e?t:t.name,this._eventsCount[t]){var i=this.$children,n=d(arguments);e&&(n[0]={name:t,source:this});for(var r=0,s=i.length;s>r;r++){var o=i[r],a=o.$emit.apply(o,n);a&&o.$broadcast.apply(o,n)}return this}},t.prototype.$dispatch=function(t){var e=this.$emit.apply(this,arguments);if(e){var i=this.$parent,n=d(arguments);for(n[0]={name:t,source:this};i;)e=i.$emit.apply(i,n),i=e?i.$parent:null;return this}};var i=/^hook:/}function bi(t){function e(){this._isAttached=!0,this._isReady=!0,this._callHook("ready")}t.prototype.$mount=function(t){return this._isCompiled?void 0:(t=L(t),t||(t=document.createElement("div")),this._compile(t),this._initDOMHooks(),H(this.$el)?(this._callHook("attached"),e.call(this)):this.$once("hook:attached",e),this)},t.prototype.$destroy=function(t,e){this._destroy(t,e)},t.prototype.$compile=function(t,e,i,n){return De(t,this.$options,!0)(this,t,e,i,n)}}function wi(t){this._init(t)}function Ci(t,e,i){return i=i?parseInt(i,10):0,e=o(e),"number"==typeof e?t.slice(i,i+e):t}function $i(t,e,i){if(t=Ks(t),null==e)return t;if("function"==typeof e)return t.filter(e);e=(""+e).toLowerCase();for(var n,r,s,o,a="in"===i?3:2,h=Array.prototype.concat.apply([],d(arguments,a)),l=[],c=0,u=t.length;u>c;c++)if(n=t[c],s=n&&n.$value||n,o=h.length){for(;o--;)if(r=h[o],"$key"===r&&xi(n.$key,e)||xi(jt(s,r),e)){l.push(n);break}}else xi(n,e)&&l.push(n);return l}function ki(t){function e(t,e,i){var r=n[i];return r&&("$key"!==r&&(m(t)&&"$value"in t&&(t=t.$value),m(e)&&"$value"in e&&(e=e.$value)),t=m(t)?jt(t,r):t,e=m(e)?jt(e,r):e),t===e?0:t>e?s:-s}var i=null,n=void 0;t=Ks(t);var r=d(arguments,1),s=r[r.length-1];"number"==typeof s?(s=0>s?-1:1,r=r.length>1?r.slice(0,-1):r):s=1;var o=r[0];return o?("function"==typeof o?i=function(t,e){return o(t,e)*s}:(n=Array.prototype.concat.apply([],r),i=function(t,r,s){return s=s||0,s>=n.length-1?e(t,r,s):e(t,r,s)||i(t,r,s+1)}),t.slice().sort(i)):t}function xi(t,e){var i;if(g(t)){var n=Object.keys(t);for(i=n.length;i--;)if(xi(t[n[i]],e))return!0}else if(Di(t)){for(i=t.length;i--;)if(xi(t[i],e))return!0}else if(null!=t)return t.toString().toLowerCase().indexOf(e)>-1}function Ai(i){function n(t){return new Function("return function "+f(t)+" (options) { this._init(options) }")()}i.options={directives:bs,elementDirectives:Ys,filters:eo,transitions:{},components:{},partials:{},replace:!0},i.util=In,i.config=An,i.set=t,i["delete"]=e,i.nextTick=Yi,i.compiler=qs,i.FragmentFactory=se,i.internalDirectives=Hs,i.parsers={path:ir,text:$n,template:Fr,directive:gn,expression:mr},i.cid=0;var r=1;i.extend=function(t){t=t||{};var e=this,i=0===e.cid;if(i&&t._Ctor)return t._Ctor;var s=t.name||e.options.name,o=n(s||"VueComponent");return o.prototype=Object.create(e.prototype),o.prototype.constructor=o,o.cid=r++,o.options=mt(e.options,t),o["super"]=e,o.extend=e.extend,An._assetTypes.forEach(function(t){o[t]=e[t]}),s&&(o.options.components[s]=o),i&&(t._Ctor=o),o},i.use=function(t){if(!t.installed){var e=d(arguments,1);return e.unshift(this),"function"==typeof t.install?t.install.apply(t,e):t.apply(null,e),t.installed=!0,this}},i.mixin=function(t){i.options=mt(i.options,t)},An._assetTypes.forEach(function(t){i[t]=function(e,n){return n?("component"===t&&g(n)&&(n.name||(n.name=e),n=i.extend(n)),this.options[t+"s"][e]=n,n):this.options[t+"s"][e]}}),v(i.transition,Tn)}var Oi=Object.prototype.hasOwnProperty,Ti=/^\s?(true|false|-?[\d\.]+|'[^']*'|"[^"]*")\s?$/,Ni=/-(\w)/g,ji=/([a-z\d])([A-Z])/g,Ei=/(?:^|[-_\/])(\w)/g,Si=Object.prototype.toString,Fi="[object Object]",Di=Array.isArray,Pi="__proto__"in{},Ri="undefined"!=typeof window&&"[object Object]"!==Object.prototype.toString.call(window),Li=Ri&&window.__VUE_DEVTOOLS_GLOBAL_HOOK__,Hi=Ri&&window.navigator.userAgent.toLowerCase(),Ii=Hi&&Hi.indexOf("trident")>0,Mi=Hi&&Hi.indexOf("msie 9.0")>0,Vi=Hi&&Hi.indexOf("android")>0,Bi=Hi&&/(iphone|ipad|ipod|ios)/i.test(Hi),Wi=Bi&&Hi.match(/os ([\d_]+)/),zi=Wi&&Wi[1].split("_"),Ui=zi&&Number(zi[0])>=9&&Number(zi[1])>=3&&!window.indexedDB,Ji=void 0,qi=void 0,Qi=void 0,Gi=void 0;if(Ri&&!Mi){var Zi=void 0===window.ontransitionend&&void 0!==window.onwebkittransitionend,Xi=void 0===window.onanimationend&&void 0!==window.onwebkitanimationend;Ji=Zi?"WebkitTransition":"transition",qi=Zi?"webkitTransitionEnd":"transitionend",Qi=Xi?"WebkitAnimation":"animation",Gi=Xi?"webkitAnimationEnd":"animationend"}var Yi=function(){function t(){n=!1;var t=i.slice(0);i=[];for(var e=0;ee;e++)t[e].update()};var Pn=Array.prototype,Rn=Object.create(Pn);["push","pop","shift","unshift","splice","sort","reverse"].forEach(function(t){var e=Pn[t];_(Rn,t,function(){for(var i=arguments.length,n=new Array(i);i--;)n[i]=arguments[i];var r,s=e.apply(this,n),o=this.__ob__;switch(t){case"push":r=n;break;case"unshift":r=n;break;case"splice":r=n.slice(2)}return r&&o.observeArray(r),o.dep.notify(),s})}),_(Pn,"$set",function(t,e){return t>=this.length&&(this.length=Number(t)+1),this.splice(t,1,e)[0]}),_(Pn,"$remove",function(t){if(this.length){var e=b(this,t);return e>-1?this.splice(e,1):void 0}});var Ln=Object.getOwnPropertyNames(Rn),Hn=!0;bt.prototype.walk=function(t){for(var e=Object.keys(t),i=0,n=e.length;n>i;i++)this.convert(e[i],t[e[i]])},bt.prototype.observeArray=function(t){for(var e=0,i=t.length;i>e;e++)$t(t[e])},bt.prototype.convert=function(t,e){kt(this.value,t,e)},bt.prototype.addVm=function(t){(this.vms||(this.vms=[])).push(t)},bt.prototype.removeVm=function(t){this.vms.$remove(t)};var In=Object.freeze({defineReactive:kt,set:t,del:e,hasOwn:i,isLiteral:n,isReserved:r,_toString:s,toNumber:o,toBoolean:a,stripQuotes:h,camelize:l,hyphenate:u,classify:f,bind:p,toArray:d,extend:v,isObject:m,isPlainObject:g,def:_,debounce:y,indexOf:b,cancellable:w,looseEqual:C,isArray:Di,hasProto:Pi,inBrowser:Ri,devtools:Li,isIE:Ii,isIE9:Mi,isAndroid:Vi,isIos:Bi,iosVersionMatch:Wi,iosVersion:zi,hasMutationObserverBug:Ui,get transitionProp(){return Ji},get transitionEndEvent(){return qi},get animationProp(){return Qi},get animationEndEvent(){return Gi},nextTick:Yi,get _Set(){return Ki},query:L,inDoc:H,getAttr:I,getBindAttr:M,hasBindAttr:V,before:B,after:W,remove:z,prepend:U,replace:J,on:q,off:Q,setClass:Z,addClass:X,removeClass:Y,extractContent:K,trimNode:tt,isTemplate:it,createAnchor:nt,findRef:rt,mapNodeRange:st,removeNodeRange:ot,isFragment:at,getOuterHTML:ht,mergeOptions:mt,resolveAsset:gt,checkComponentAttr:lt,commonTagRE:jn,reservedTagRE:En,warn:On}),Mn=0,Vn=new $(1e3),Bn=0,Wn=1,zn=2,Un=3,Jn=0,qn=1,Qn=2,Gn=3,Zn=4,Xn=5,Yn=6,Kn=7,tr=8,er=[];er[Jn]={ws:[Jn],ident:[Gn,Bn],"[":[Zn],eof:[Kn]},er[qn]={ws:[qn],".":[Qn],"[":[Zn],eof:[Kn]},er[Qn]={ws:[Qn],ident:[Gn,Bn]},er[Gn]={ident:[Gn,Bn],0:[Gn,Bn],number:[Gn,Bn],ws:[qn,Wn],".":[Qn,Wn],"[":[Zn,Wn],eof:[Kn,Wn]},er[Zn]={"'":[Xn,Bn],'"':[Yn,Bn],"[":[Zn,zn],"]":[qn,Un],eof:tr,"else":[Zn,Bn]},er[Xn]={"'":[Zn,Bn],eof:tr,"else":[Xn,Bn]},er[Yn]={'"':[Zn,Bn],eof:tr,"else":[Yn,Bn]};var ir=Object.freeze({parsePath:Nt,getPath:jt,setPath:Et}),nr=new $(1e3),rr="Math,Date,this,true,false,null,undefined,Infinity,NaN,isNaN,isFinite,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,parseInt,parseFloat",sr=new RegExp("^("+rr.replace(/,/g,"\\b|")+"\\b)"),or="break,case,class,catch,const,continue,debugger,default,delete,do,else,export,extends,finally,for,function,if,import,in,instanceof,let,return,super,switch,throw,try,var,while,with,yield,enum,await,implements,package,protected,static,interface,private,public",ar=new RegExp("^("+or.replace(/,/g,"\\b|")+"\\b)"),hr=/\s/g,lr=/\n/g,cr=/[\{,]\s*[\w\$_]+\s*:|('(?:[^'\\]|\\.)*'|"(?:[^"\\]|\\.)*"|`(?:[^`\\]|\\.)*\$\{|\}(?:[^`\\]|\\.)*`|`(?:[^`\\]|\\.)*`)|new |typeof |void /g,ur=/"(\d+)"/g,fr=/^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*|\['.*?'\]|\[".*?"\]|\[\d+\]|\[[A-Za-z_$][\w$]*\])*$/,pr=/[^\w$\.](?:[A-Za-z_$][\w$]*)/g,dr=/^(?:true|false|null|undefined|Infinity|NaN)$/,vr=[],mr=Object.freeze({parseExpression:It,isSimplePath:Mt}),gr=[],_r=[],yr={},br={},wr=!1,Cr=0;Ut.prototype.get=function(){this.beforeGet();var t,e=this.scope||this.vm;try{t=this.getter.call(e,e)}catch(i){}return this.deep&&Jt(t),this.preProcess&&(t=this.preProcess(t)),this.filters&&(t=e._applyFilters(t,null,this.filters,!1)),this.postProcess&&(t=this.postProcess(t)),this.afterGet(),t},Ut.prototype.set=function(t){var e=this.scope||this.vm;this.filters&&(t=e._applyFilters(t,this.value,this.filters,!0));try{this.setter.call(e,e,t)}catch(i){}var n=e.$forContext;if(n&&n.alias===this.expression){if(n.filters)return;n._withLock(function(){e.$key?n.rawValue[e.$key]=t:n.rawValue.$set(e.$index,t)})}},Ut.prototype.beforeGet=function(){_t.target=this},Ut.prototype.addDep=function(t){var e=t.id;this.newDepIds.has(e)||(this.newDepIds.add(e),this.newDeps.push(t),this.depIds.has(e)||t.addSub(this))},Ut.prototype.afterGet=function(){_t.target=null;for(var t=this.deps.length;t--;){var e=this.deps[t];this.newDepIds.has(e.id)||e.removeSub(this)}var i=this.depIds;this.depIds=this.newDepIds,this.newDepIds=i,this.newDepIds.clear(),i=this.deps,this.deps=this.newDeps,this.newDeps=i,this.newDeps.length=0},Ut.prototype.update=function(t){this.lazy?this.dirty=!0:this.sync||!An.async?this.run():(this.shallow=this.queued?t?this.shallow:!1:!!t,this.queued=!0,zt(this))},Ut.prototype.run=function(){if(this.active){var t=this.get();if(t!==this.value||(m(t)||this.deep)&&!this.shallow){var e=this.value;this.value=t;this.prevError;this.cb.call(this.vm,t,e)}this.queued=this.shallow=!1}},Ut.prototype.evaluate=function(){var t=_t.target;this.value=this.get(),this.dirty=!1,_t.target=t},Ut.prototype.depend=function(){for(var t=this.deps.length;t--;)this.deps[t].depend()},Ut.prototype.teardown=function(){if(this.active){this.vm._isBeingDestroyed||this.vm._vForRemoving||this.vm._watchers.$remove(this);for(var t=this.deps.length;t--;)this.deps[t].removeSub(this);this.active=!1,this.vm=this.cb=this.value=null}};var $r=new Ki,kr={bind:function(){this.attr=3===this.el.nodeType?"data":"textContent"},update:function(t){this.el[this.attr]=s(t)}},xr=new $(1e3),Ar=new $(1e3),Or={efault:[0,"",""],legend:[1,"
","
"],tr:[2,"","
"],col:[2,"","
"]};Or.td=Or.th=[3,"","
"],Or.option=Or.optgroup=[1,'"],Or.thead=Or.tbody=Or.colgroup=Or.caption=Or.tfoot=[1,"","
"],Or.g=Or.defs=Or.symbol=Or.use=Or.image=Or.text=Or.circle=Or.ellipse=Or.line=Or.path=Or.polygon=Or.polyline=Or.rect=[1,'',""];var Tr=/<([\w:-]+)/,Nr=/&#?\w+?;/,jr=/ E + } + entry.newer = undefined; // D --x + entry.older = this.tail; // D. --> E + if (this.tail) { + this.tail.newer = entry; // E. <-- D + } + this.tail = entry; + return returnEntry ? entry : entry.value; + }; + + var cache$1 = new Cache(1000); + var filterTokenRE = /[^\s'"]+|'[^']*'|"[^"]*"/g; + var reservedArgRE = /^in$|^-?\d+/; + + /** + * Parser state + */ + + var str; + var dir; + var c; + var prev; + var i; + var l; + var lastFilterIndex; + var inSingle; + var inDouble; + var curly; + var square; + var paren; + /** + * Push a filter to the current directive object + */ + + function pushFilter() { + var exp = str.slice(lastFilterIndex, i).trim(); + var filter; + if (exp) { + filter = {}; + var tokens = exp.match(filterTokenRE); + filter.name = tokens[0]; + if (tokens.length > 1) { + filter.args = tokens.slice(1).map(processFilterArg); + } + } + if (filter) { + (dir.filters = dir.filters || []).push(filter); + } + lastFilterIndex = i + 1; + } + + /** + * Check if an argument is dynamic and strip quotes. + * + * @param {String} arg + * @return {Object} + */ + + function processFilterArg(arg) { + if (reservedArgRE.test(arg)) { + return { + value: toNumber(arg), + dynamic: false + }; + } else { + var stripped = stripQuotes(arg); + var dynamic = stripped === arg; + return { + value: dynamic ? arg : stripped, + dynamic: dynamic + }; + } + } + + /** + * Parse a directive value and extract the expression + * and its filters into a descriptor. + * + * Example: + * + * "a + 1 | uppercase" will yield: + * { + * expression: 'a + 1', + * filters: [ + * { name: 'uppercase', args: null } + * ] + * } + * + * @param {String} s + * @return {Object} + */ + + function parseDirective(s) { + var hit = cache$1.get(s); + if (hit) { + return hit; + } + + // reset parser state + str = s; + inSingle = inDouble = false; + curly = square = paren = 0; + lastFilterIndex = 0; + dir = {}; + + for (i = 0, l = str.length; i < l; i++) { + prev = c; + c = str.charCodeAt(i); + if (inSingle) { + // check single quote + if (c === 0x27 && prev !== 0x5C) inSingle = !inSingle; + } else if (inDouble) { + // check double quote + if (c === 0x22 && prev !== 0x5C) inDouble = !inDouble; + } else if (c === 0x7C && // pipe + str.charCodeAt(i + 1) !== 0x7C && str.charCodeAt(i - 1) !== 0x7C) { + if (dir.expression == null) { + // first filter, end of expression + lastFilterIndex = i + 1; + dir.expression = str.slice(0, i).trim(); + } else { + // already has filter + pushFilter(); + } + } else { + switch (c) { + case 0x22: + inDouble = true;break; // " + case 0x27: + inSingle = true;break; // ' + case 0x28: + paren++;break; // ( + case 0x29: + paren--;break; // ) + case 0x5B: + square++;break; // [ + case 0x5D: + square--;break; // ] + case 0x7B: + curly++;break; // { + case 0x7D: + curly--;break; // } + } + } + } + + if (dir.expression == null) { + dir.expression = str.slice(0, i).trim(); + } else if (lastFilterIndex !== 0) { + pushFilter(); + } + + cache$1.put(s, dir); + return dir; + } + +var directive = Object.freeze({ + parseDirective: parseDirective + }); + + var regexEscapeRE = /[-.*+?^${}()|[\]\/\\]/g; + var cache = undefined; + var tagRE = undefined; + var htmlRE = undefined; + /** + * Escape a string so it can be used in a RegExp + * constructor. + * + * @param {String} str + */ + + function escapeRegex(str) { + return str.replace(regexEscapeRE, '\\$&'); + } + + function compileRegex() { + var open = escapeRegex(config.delimiters[0]); + var close = escapeRegex(config.delimiters[1]); + var unsafeOpen = escapeRegex(config.unsafeDelimiters[0]); + var unsafeClose = escapeRegex(config.unsafeDelimiters[1]); + tagRE = new RegExp(unsafeOpen + '((?:.|\\n)+?)' + unsafeClose + '|' + open + '((?:.|\\n)+?)' + close, 'g'); + htmlRE = new RegExp('^' + unsafeOpen + '((?:.|\\n)+?)' + unsafeClose + '$'); + // reset cache + cache = new Cache(1000); + } + + /** + * Parse a template text string into an array of tokens. + * + * @param {String} text + * @return {Array | null} + * - {String} type + * - {String} value + * - {Boolean} [html] + * - {Boolean} [oneTime] + */ + + function parseText(text) { + if (!cache) { + compileRegex(); + } + var hit = cache.get(text); + if (hit) { + return hit; + } + if (!tagRE.test(text)) { + return null; + } + var tokens = []; + var lastIndex = tagRE.lastIndex = 0; + var match, index, html, value, first, oneTime; + /* eslint-disable no-cond-assign */ + while (match = tagRE.exec(text)) { + /* eslint-enable no-cond-assign */ + index = match.index; + // push text token + if (index > lastIndex) { + tokens.push({ + value: text.slice(lastIndex, index) + }); + } + // tag token + html = htmlRE.test(match[0]); + value = html ? match[1] : match[2]; + first = value.charCodeAt(0); + oneTime = first === 42; // * + value = oneTime ? value.slice(1) : value; + tokens.push({ + tag: true, + value: value.trim(), + html: html, + oneTime: oneTime + }); + lastIndex = index + match[0].length; + } + if (lastIndex < text.length) { + tokens.push({ + value: text.slice(lastIndex) + }); + } + cache.put(text, tokens); + return tokens; + } + + /** + * Format a list of tokens into an expression. + * e.g. tokens parsed from 'a {{b}} c' can be serialized + * into one single expression as '"a " + b + " c"'. + * + * @param {Array} tokens + * @param {Vue} [vm] + * @return {String} + */ + + function tokensToExp(tokens, vm) { + if (tokens.length > 1) { + return tokens.map(function (token) { + return formatToken(token, vm); + }).join('+'); + } else { + return formatToken(tokens[0], vm, true); + } + } + + /** + * Format a single token. + * + * @param {Object} token + * @param {Vue} [vm] + * @param {Boolean} [single] + * @return {String} + */ + + function formatToken(token, vm, single) { + return token.tag ? token.oneTime && vm ? '"' + vm.$eval(token.value) + '"' : inlineFilters(token.value, single) : '"' + token.value + '"'; + } + + /** + * For an attribute with multiple interpolation tags, + * e.g. attr="some-{{thing | filter}}", in order to combine + * the whole thing into a single watchable expression, we + * have to inline those filters. This function does exactly + * that. This is a bit hacky but it avoids heavy changes + * to directive parser and watcher mechanism. + * + * @param {String} exp + * @param {Boolean} single + * @return {String} + */ + + var filterRE = /[^|]\|[^|]/; + function inlineFilters(exp, single) { + if (!filterRE.test(exp)) { + return single ? exp : '(' + exp + ')'; + } else { + var dir = parseDirective(exp); + if (!dir.filters) { + return '(' + exp + ')'; + } else { + return 'this._applyFilters(' + dir.expression + // value + ',null,' + // oldValue (null for read) + JSON.stringify(dir.filters) + // filter descriptors + ',false)'; // write? + } + } + } + +var text = Object.freeze({ + compileRegex: compileRegex, + parseText: parseText, + tokensToExp: tokensToExp + }); + + var delimiters = ['{{', '}}']; + var unsafeDelimiters = ['{{{', '}}}']; + + var config = Object.defineProperties({ + + /** + * Whether to print debug messages. + * Also enables stack trace for warnings. + * + * @type {Boolean} + */ + + debug: false, + + /** + * Whether to suppress warnings. + * + * @type {Boolean} + */ + + silent: false, + + /** + * Whether to use async rendering. + */ + + async: true, + + /** + * Whether to warn against errors caught when evaluating + * expressions. + */ + + warnExpressionErrors: true, + + /** + * Whether to allow devtools inspection. + * Disabled by default in production builds. + */ + + devtools: 'development' !== 'production', + + /** + * Internal flag to indicate the delimiters have been + * changed. + * + * @type {Boolean} + */ + + _delimitersChanged: true, + + /** + * List of asset types that a component can own. + * + * @type {Array} + */ + + _assetTypes: ['component', 'directive', 'elementDirective', 'filter', 'transition', 'partial'], + + /** + * prop binding modes + */ + + _propBindingModes: { + ONE_WAY: 0, + TWO_WAY: 1, + ONE_TIME: 2 + }, + + /** + * Max circular updates allowed in a batcher flush cycle. + */ + + _maxUpdateCount: 100 + + }, { + delimiters: { /** + * Interpolation delimiters. Changing these would trigger + * the text parser to re-compile the regular expressions. + * + * @type {Array} + */ + + get: function get() { + return delimiters; + }, + set: function set(val) { + delimiters = val; + compileRegex(); + }, + configurable: true, + enumerable: true + }, + unsafeDelimiters: { + get: function get() { + return unsafeDelimiters; + }, + set: function set(val) { + unsafeDelimiters = val; + compileRegex(); + }, + configurable: true, + enumerable: true + } + }); + + var warn = undefined; + var formatComponentName = undefined; + + if ('development' !== 'production') { + (function () { + var hasConsole = typeof console !== 'undefined'; + + warn = function (msg, vm) { + if (hasConsole && !config.silent) { + console.error('[Vue warn]: ' + msg + (vm ? formatComponentName(vm) : '')); + } + }; + + formatComponentName = function (vm) { + var name = vm._isVue ? vm.$options.name : vm.name; + return name ? ' (found in component: <' + hyphenate(name) + '>)' : ''; + }; + })(); + } + + /** + * Append with transition. + * + * @param {Element} el + * @param {Element} target + * @param {Vue} vm + * @param {Function} [cb] + */ + + function appendWithTransition(el, target, vm, cb) { + applyTransition(el, 1, function () { + target.appendChild(el); + }, vm, cb); + } + + /** + * InsertBefore with transition. + * + * @param {Element} el + * @param {Element} target + * @param {Vue} vm + * @param {Function} [cb] + */ + + function beforeWithTransition(el, target, vm, cb) { + applyTransition(el, 1, function () { + before(el, target); + }, vm, cb); + } + + /** + * Remove with transition. + * + * @param {Element} el + * @param {Vue} vm + * @param {Function} [cb] + */ + + function removeWithTransition(el, vm, cb) { + applyTransition(el, -1, function () { + remove(el); + }, vm, cb); + } + + /** + * Apply transitions with an operation callback. + * + * @param {Element} el + * @param {Number} direction + * 1: enter + * -1: leave + * @param {Function} op - the actual DOM operation + * @param {Vue} vm + * @param {Function} [cb] + */ + + function applyTransition(el, direction, op, vm, cb) { + var transition = el.__v_trans; + if (!transition || + // skip if there are no js hooks and CSS transition is + // not supported + !transition.hooks && !transitionEndEvent || + // skip transitions for initial compile + !vm._isCompiled || + // if the vm is being manipulated by a parent directive + // during the parent's compilation phase, skip the + // animation. + vm.$parent && !vm.$parent._isCompiled) { + op(); + if (cb) cb(); + return; + } + var action = direction > 0 ? 'enter' : 'leave'; + transition[action](op, cb); + } + +var transition = Object.freeze({ + appendWithTransition: appendWithTransition, + beforeWithTransition: beforeWithTransition, + removeWithTransition: removeWithTransition, + applyTransition: applyTransition + }); + + /** + * Query an element selector if it's not an element already. + * + * @param {String|Element} el + * @return {Element} + */ + + function query(el) { + if (typeof el === 'string') { + var selector = el; + el = document.querySelector(el); + if (!el) { + 'development' !== 'production' && warn('Cannot find element: ' + selector); + } + } + return el; + } + + /** + * Check if a node is in the document. + * Note: document.documentElement.contains should work here + * but always returns false for comment nodes in phantomjs, + * making unit tests difficult. This is fixed by doing the + * contains() check on the node's parentNode instead of + * the node itself. + * + * @param {Node} node + * @return {Boolean} + */ + + function inDoc(node) { + if (!node) return false; + var doc = node.ownerDocument.documentElement; + var parent = node.parentNode; + return doc === node || doc === parent || !!(parent && parent.nodeType === 1 && doc.contains(parent)); + } + + /** + * Get and remove an attribute from a node. + * + * @param {Node} node + * @param {String} _attr + */ + + function getAttr(node, _attr) { + var val = node.getAttribute(_attr); + if (val !== null) { + node.removeAttribute(_attr); + } + return val; + } + + /** + * Get an attribute with colon or v-bind: prefix. + * + * @param {Node} node + * @param {String} name + * @return {String|null} + */ + + function getBindAttr(node, name) { + var val = getAttr(node, ':' + name); + if (val === null) { + val = getAttr(node, 'v-bind:' + name); + } + return val; + } + + /** + * Check the presence of a bind attribute. + * + * @param {Node} node + * @param {String} name + * @return {Boolean} + */ + + function hasBindAttr(node, name) { + return node.hasAttribute(name) || node.hasAttribute(':' + name) || node.hasAttribute('v-bind:' + name); + } + + /** + * Insert el before target + * + * @param {Element} el + * @param {Element} target + */ + + function before(el, target) { + target.parentNode.insertBefore(el, target); + } + + /** + * Insert el after target + * + * @param {Element} el + * @param {Element} target + */ + + function after(el, target) { + if (target.nextSibling) { + before(el, target.nextSibling); + } else { + target.parentNode.appendChild(el); + } + } + + /** + * Remove el from DOM + * + * @param {Element} el + */ + + function remove(el) { + el.parentNode.removeChild(el); + } + + /** + * Prepend el to target + * + * @param {Element} el + * @param {Element} target + */ + + function prepend(el, target) { + if (target.firstChild) { + before(el, target.firstChild); + } else { + target.appendChild(el); + } + } + + /** + * Replace target with el + * + * @param {Element} target + * @param {Element} el + */ + + function replace(target, el) { + var parent = target.parentNode; + if (parent) { + parent.replaceChild(el, target); + } + } + + /** + * Add event listener shorthand. + * + * @param {Element} el + * @param {String} event + * @param {Function} cb + * @param {Boolean} [useCapture] + */ + + function on(el, event, cb, useCapture) { + el.addEventListener(event, cb, useCapture); + } + + /** + * Remove event listener shorthand. + * + * @param {Element} el + * @param {String} event + * @param {Function} cb + */ + + function off(el, event, cb) { + el.removeEventListener(event, cb); + } + + /** + * For IE9 compat: when both class and :class are present + * getAttribute('class') returns wrong value... + * + * @param {Element} el + * @return {String} + */ + + function getClass(el) { + var classname = el.className; + if (typeof classname === 'object') { + classname = classname.baseVal || ''; + } + return classname; + } + + /** + * In IE9, setAttribute('class') will result in empty class + * if the element also has the :class attribute; However in + * PhantomJS, setting `className` does not work on SVG elements... + * So we have to do a conditional check here. + * + * @param {Element} el + * @param {String} cls + */ + + function setClass(el, cls) { + /* istanbul ignore if */ + if (isIE9 && !/svg$/.test(el.namespaceURI)) { + el.className = cls; + } else { + el.setAttribute('class', cls); + } + } + + /** + * Add class with compatibility for IE & SVG + * + * @param {Element} el + * @param {String} cls + */ + + function addClass(el, cls) { + if (el.classList) { + el.classList.add(cls); + } else { + var cur = ' ' + getClass(el) + ' '; + if (cur.indexOf(' ' + cls + ' ') < 0) { + setClass(el, (cur + cls).trim()); + } + } + } + + /** + * Remove class with compatibility for IE & SVG + * + * @param {Element} el + * @param {String} cls + */ + + function removeClass(el, cls) { + if (el.classList) { + el.classList.remove(cls); + } else { + var cur = ' ' + getClass(el) + ' '; + var tar = ' ' + cls + ' '; + while (cur.indexOf(tar) >= 0) { + cur = cur.replace(tar, ' '); + } + setClass(el, cur.trim()); + } + if (!el.className) { + el.removeAttribute('class'); + } + } + + /** + * Extract raw content inside an element into a temporary + * container div + * + * @param {Element} el + * @param {Boolean} asFragment + * @return {Element|DocumentFragment} + */ + + function extractContent(el, asFragment) { + var child; + var rawContent; + /* istanbul ignore if */ + if (isTemplate(el) && isFragment(el.content)) { + el = el.content; + } + if (el.hasChildNodes()) { + trimNode(el); + rawContent = asFragment ? document.createDocumentFragment() : document.createElement('div'); + /* eslint-disable no-cond-assign */ + while (child = el.firstChild) { + /* eslint-enable no-cond-assign */ + rawContent.appendChild(child); + } + } + return rawContent; + } + + /** + * Trim possible empty head/tail text and comment + * nodes inside a parent. + * + * @param {Node} node + */ + + function trimNode(node) { + var child; + /* eslint-disable no-sequences */ + while ((child = node.firstChild, isTrimmable(child))) { + node.removeChild(child); + } + while ((child = node.lastChild, isTrimmable(child))) { + node.removeChild(child); + } + /* eslint-enable no-sequences */ + } + + function isTrimmable(node) { + return node && (node.nodeType === 3 && !node.data.trim() || node.nodeType === 8); + } + + /** + * Check if an element is a template tag. + * Note if the template appears inside an SVG its tagName + * will be in lowercase. + * + * @param {Element} el + */ + + function isTemplate(el) { + return el.tagName && el.tagName.toLowerCase() === 'template'; + } + + /** + * Create an "anchor" for performing dom insertion/removals. + * This is used in a number of scenarios: + * - fragment instance + * - v-html + * - v-if + * - v-for + * - component + * + * @param {String} content + * @param {Boolean} persist - IE trashes empty textNodes on + * cloneNode(true), so in certain + * cases the anchor needs to be + * non-empty to be persisted in + * templates. + * @return {Comment|Text} + */ + + function createAnchor(content, persist) { + var anchor = config.debug ? document.createComment(content) : document.createTextNode(persist ? ' ' : ''); + anchor.__v_anchor = true; + return anchor; + } + + /** + * Find a component ref attribute that starts with $. + * + * @param {Element} node + * @return {String|undefined} + */ + + var refRE = /^v-ref:/; + + function findRef(node) { + if (node.hasAttributes()) { + var attrs = node.attributes; + for (var i = 0, l = attrs.length; i < l; i++) { + var name = attrs[i].name; + if (refRE.test(name)) { + return camelize(name.replace(refRE, '')); + } + } + } + } + + /** + * Map a function to a range of nodes . + * + * @param {Node} node + * @param {Node} end + * @param {Function} op + */ + + function mapNodeRange(node, end, op) { + var next; + while (node !== end) { + next = node.nextSibling; + op(node); + node = next; + } + op(end); + } + + /** + * Remove a range of nodes with transition, store + * the nodes in a fragment with correct ordering, + * and call callback when done. + * + * @param {Node} start + * @param {Node} end + * @param {Vue} vm + * @param {DocumentFragment} frag + * @param {Function} cb + */ + + function removeNodeRange(start, end, vm, frag, cb) { + var done = false; + var removed = 0; + var nodes = []; + mapNodeRange(start, end, function (node) { + if (node === end) done = true; + nodes.push(node); + removeWithTransition(node, vm, onRemoved); + }); + function onRemoved() { + removed++; + if (done && removed >= nodes.length) { + for (var i = 0; i < nodes.length; i++) { + frag.appendChild(nodes[i]); + } + cb && cb(); + } + } + } + + /** + * Check if a node is a DocumentFragment. + * + * @param {Node} node + * @return {Boolean} + */ + + function isFragment(node) { + return node && node.nodeType === 11; + } + + /** + * Get outerHTML of elements, taking care + * of SVG elements in IE as well. + * + * @param {Element} el + * @return {String} + */ + + function getOuterHTML(el) { + if (el.outerHTML) { + return el.outerHTML; + } else { + var container = document.createElement('div'); + container.appendChild(el.cloneNode(true)); + return container.innerHTML; + } + } + + var commonTagRE = /^(div|p|span|img|a|b|i|br|ul|ol|li|h1|h2|h3|h4|h5|h6|code|pre|table|th|td|tr|form|label|input|select|option|nav|article|section|header|footer)$/i; + var reservedTagRE = /^(slot|partial|component)$/i; + + var isUnknownElement = undefined; + if ('development' !== 'production') { + isUnknownElement = function (el, tag) { + if (tag.indexOf('-') > -1) { + // http://stackoverflow.com/a/28210364/1070244 + return el.constructor === window.HTMLUnknownElement || el.constructor === window.HTMLElement; + } else { + return (/HTMLUnknownElement/.test(el.toString()) && + // Chrome returns unknown for several HTML5 elements. + // https://code.google.com/p/chromium/issues/detail?id=540526 + // Firefox returns unknown for some "Interactive elements." + !/^(data|time|rtc|rb|details|dialog|summary)$/.test(tag) + ); + } + }; + } + + /** + * Check if an element is a component, if yes return its + * component id. + * + * @param {Element} el + * @param {Object} options + * @return {Object|undefined} + */ + + function checkComponentAttr(el, options) { + var tag = el.tagName.toLowerCase(); + var hasAttrs = el.hasAttributes(); + if (!commonTagRE.test(tag) && !reservedTagRE.test(tag)) { + if (resolveAsset(options, 'components', tag)) { + return { id: tag }; + } else { + var is = hasAttrs && getIsBinding(el, options); + if (is) { + return is; + } else if ('development' !== 'production') { + var expectedTag = options._componentNameMap && options._componentNameMap[tag]; + if (expectedTag) { + warn('Unknown custom element: <' + tag + '> - ' + 'did you mean <' + expectedTag + '>? ' + 'HTML is case-insensitive, remember to use kebab-case in templates.'); + } else if (isUnknownElement(el, tag)) { + warn('Unknown custom element: <' + tag + '> - did you ' + 'register the component correctly? For recursive components, ' + 'make sure to provide the "name" option.'); + } + } + } + } else if (hasAttrs) { + return getIsBinding(el, options); + } + } + + /** + * Get "is" binding from an element. + * + * @param {Element} el + * @param {Object} options + * @return {Object|undefined} + */ + + function getIsBinding(el, options) { + // dynamic syntax + var exp = el.getAttribute('is'); + if (exp != null) { + if (resolveAsset(options, 'components', exp)) { + el.removeAttribute('is'); + return { id: exp }; + } + } else { + exp = getBindAttr(el, 'is'); + if (exp != null) { + return { id: exp, dynamic: true }; + } + } + } + + /** + * Option overwriting strategies are functions that handle + * how to merge a parent option value and a child option + * value into the final value. + * + * All strategy functions follow the same signature: + * + * @param {*} parentVal + * @param {*} childVal + * @param {Vue} [vm] + */ + + var strats = config.optionMergeStrategies = Object.create(null); + + /** + * Helper that recursively merges two data objects together. + */ + + function mergeData(to, from) { + var key, toVal, fromVal; + for (key in from) { + toVal = to[key]; + fromVal = from[key]; + if (!hasOwn(to, key)) { + set(to, key, fromVal); + } else if (isObject(toVal) && isObject(fromVal)) { + mergeData(toVal, fromVal); + } + } + return to; + } + + /** + * Data + */ + + strats.data = function (parentVal, childVal, vm) { + if (!vm) { + // in a Vue.extend merge, both should be functions + if (!childVal) { + return parentVal; + } + if (typeof childVal !== 'function') { + 'development' !== 'production' && warn('The "data" option should be a function ' + 'that returns a per-instance value in component ' + 'definitions.', vm); + return parentVal; + } + if (!parentVal) { + return childVal; + } + // when parentVal & childVal are both present, + // we need to return a function that returns the + // merged result of both functions... no need to + // check if parentVal is a function here because + // it has to be a function to pass previous merges. + return function mergedDataFn() { + return mergeData(childVal.call(this), parentVal.call(this)); + }; + } else if (parentVal || childVal) { + return function mergedInstanceDataFn() { + // instance merge + var instanceData = typeof childVal === 'function' ? childVal.call(vm) : childVal; + var defaultData = typeof parentVal === 'function' ? parentVal.call(vm) : undefined; + if (instanceData) { + return mergeData(instanceData, defaultData); + } else { + return defaultData; + } + }; + } + }; + + /** + * El + */ + + strats.el = function (parentVal, childVal, vm) { + if (!vm && childVal && typeof childVal !== 'function') { + 'development' !== 'production' && warn('The "el" option should be a function ' + 'that returns a per-instance value in component ' + 'definitions.', vm); + return; + } + var ret = childVal || parentVal; + // invoke the element factory if this is instance merge + return vm && typeof ret === 'function' ? ret.call(vm) : ret; + }; + + /** + * Hooks and param attributes are merged as arrays. + */ + + strats.init = strats.created = strats.ready = strats.attached = strats.detached = strats.beforeCompile = strats.compiled = strats.beforeDestroy = strats.destroyed = strats.activate = function (parentVal, childVal) { + return childVal ? parentVal ? parentVal.concat(childVal) : isArray(childVal) ? childVal : [childVal] : parentVal; + }; + + /** + * Assets + * + * When a vm is present (instance creation), we need to do + * a three-way merge between constructor options, instance + * options and parent options. + */ + + function mergeAssets(parentVal, childVal) { + var res = Object.create(parentVal || null); + return childVal ? extend(res, guardArrayAssets(childVal)) : res; + } + + config._assetTypes.forEach(function (type) { + strats[type + 's'] = mergeAssets; + }); + + /** + * Events & Watchers. + * + * Events & watchers hashes should not overwrite one + * another, so we merge them as arrays. + */ + + strats.watch = strats.events = function (parentVal, childVal) { + if (!childVal) return parentVal; + if (!parentVal) return childVal; + var ret = {}; + extend(ret, parentVal); + for (var key in childVal) { + var parent = ret[key]; + var child = childVal[key]; + if (parent && !isArray(parent)) { + parent = [parent]; + } + ret[key] = parent ? parent.concat(child) : [child]; + } + return ret; + }; + + /** + * Other object hashes. + */ + + strats.props = strats.methods = strats.computed = function (parentVal, childVal) { + if (!childVal) return parentVal; + if (!parentVal) return childVal; + var ret = Object.create(null); + extend(ret, parentVal); + extend(ret, childVal); + return ret; + }; + + /** + * Default strategy. + */ + + var defaultStrat = function defaultStrat(parentVal, childVal) { + return childVal === undefined ? parentVal : childVal; + }; + + /** + * Make sure component options get converted to actual + * constructors. + * + * @param {Object} options + */ + + function guardComponents(options) { + if (options.components) { + var components = options.components = guardArrayAssets(options.components); + var ids = Object.keys(components); + var def; + if ('development' !== 'production') { + var map = options._componentNameMap = {}; + } + for (var i = 0, l = ids.length; i < l; i++) { + var key = ids[i]; + if (commonTagRE.test(key) || reservedTagRE.test(key)) { + 'development' !== 'production' && warn('Do not use built-in or reserved HTML elements as component ' + 'id: ' + key); + continue; + } + // record a all lowercase <-> kebab-case mapping for + // possible custom element case error warning + if ('development' !== 'production') { + map[key.replace(/-/g, '').toLowerCase()] = hyphenate(key); + } + def = components[key]; + if (isPlainObject(def)) { + components[key] = Vue.extend(def); + } + } + } + } + + /** + * Ensure all props option syntax are normalized into the + * Object-based format. + * + * @param {Object} options + */ + + function guardProps(options) { + var props = options.props; + var i, val; + if (isArray(props)) { + options.props = {}; + i = props.length; + while (i--) { + val = props[i]; + if (typeof val === 'string') { + options.props[val] = null; + } else if (val.name) { + options.props[val.name] = val; + } + } + } else if (isPlainObject(props)) { + var keys = Object.keys(props); + i = keys.length; + while (i--) { + val = props[keys[i]]; + if (typeof val === 'function') { + props[keys[i]] = { type: val }; + } + } + } + } + + /** + * Guard an Array-format assets option and converted it + * into the key-value Object format. + * + * @param {Object|Array} assets + * @return {Object} + */ + + function guardArrayAssets(assets) { + if (isArray(assets)) { + var res = {}; + var i = assets.length; + var asset; + while (i--) { + asset = assets[i]; + var id = typeof asset === 'function' ? asset.options && asset.options.name || asset.id : asset.name || asset.id; + if (!id) { + 'development' !== 'production' && warn('Array-syntax assets must provide a "name" or "id" field.'); + } else { + res[id] = asset; + } + } + return res; + } + return assets; + } + + /** + * Merge two option objects into a new one. + * Core utility used in both instantiation and inheritance. + * + * @param {Object} parent + * @param {Object} child + * @param {Vue} [vm] - if vm is present, indicates this is + * an instantiation merge. + */ + + function mergeOptions(parent, child, vm) { + guardComponents(child); + guardProps(child); + if ('development' !== 'production') { + if (child.propsData && !vm) { + warn('propsData can only be used as an instantiation option.'); + } + } + var options = {}; + var key; + if (child['extends']) { + parent = typeof child['extends'] === 'function' ? mergeOptions(parent, child['extends'].options, vm) : mergeOptions(parent, child['extends'], vm); + } + if (child.mixins) { + for (var i = 0, l = child.mixins.length; i < l; i++) { + var mixin = child.mixins[i]; + var mixinOptions = mixin.prototype instanceof Vue ? mixin.options : mixin; + parent = mergeOptions(parent, mixinOptions, vm); + } + } + for (key in parent) { + mergeField(key); + } + for (key in child) { + if (!hasOwn(parent, key)) { + mergeField(key); + } + } + function mergeField(key) { + var strat = strats[key] || defaultStrat; + options[key] = strat(parent[key], child[key], vm, key); + } + return options; + } + + /** + * Resolve an asset. + * This function is used because child instances need access + * to assets defined in its ancestor chain. + * + * @param {Object} options + * @param {String} type + * @param {String} id + * @param {Boolean} warnMissing + * @return {Object|Function} + */ + + function resolveAsset(options, type, id, warnMissing) { + /* istanbul ignore if */ + if (typeof id !== 'string') { + return; + } + var assets = options[type]; + var camelizedId; + var res = assets[id] || + // camelCase ID + assets[camelizedId = camelize(id)] || + // Pascal Case ID + assets[camelizedId.charAt(0).toUpperCase() + camelizedId.slice(1)]; + if ('development' !== 'production' && warnMissing && !res) { + warn('Failed to resolve ' + type.slice(0, -1) + ': ' + id, options); + } + return res; + } + + var uid$1 = 0; + + /** + * A dep is an observable that can have multiple + * directives subscribing to it. + * + * @constructor + */ + function Dep() { + this.id = uid$1++; + this.subs = []; + } + + // the current target watcher being evaluated. + // this is globally unique because there could be only one + // watcher being evaluated at any time. + Dep.target = null; + + /** + * Add a directive subscriber. + * + * @param {Directive} sub + */ + + Dep.prototype.addSub = function (sub) { + this.subs.push(sub); + }; + + /** + * Remove a directive subscriber. + * + * @param {Directive} sub + */ + + Dep.prototype.removeSub = function (sub) { + this.subs.$remove(sub); + }; + + /** + * Add self as a dependency to the target watcher. + */ + + Dep.prototype.depend = function () { + Dep.target.addDep(this); + }; + + /** + * Notify all subscribers of a new value. + */ + + Dep.prototype.notify = function () { + // stablize the subscriber list first + var subs = toArray(this.subs); + for (var i = 0, l = subs.length; i < l; i++) { + subs[i].update(); + } + }; + + var arrayProto = Array.prototype; + var arrayMethods = Object.create(arrayProto) + + /** + * Intercept mutating methods and emit events + */ + + ;['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse'].forEach(function (method) { + // cache original method + var original = arrayProto[method]; + def(arrayMethods, method, function mutator() { + // avoid leaking arguments: + // http://jsperf.com/closure-with-arguments + var i = arguments.length; + var args = new Array(i); + while (i--) { + args[i] = arguments[i]; + } + var result = original.apply(this, args); + var ob = this.__ob__; + var inserted; + switch (method) { + case 'push': + inserted = args; + break; + case 'unshift': + inserted = args; + break; + case 'splice': + inserted = args.slice(2); + break; + } + if (inserted) ob.observeArray(inserted); + // notify change + ob.dep.notify(); + return result; + }); + }); + + /** + * Swap the element at the given index with a new value + * and emits corresponding event. + * + * @param {Number} index + * @param {*} val + * @return {*} - replaced element + */ + + def(arrayProto, '$set', function $set(index, val) { + if (index >= this.length) { + this.length = Number(index) + 1; + } + return this.splice(index, 1, val)[0]; + }); + + /** + * Convenience method to remove the element at given index or target element reference. + * + * @param {*} item + */ + + def(arrayProto, '$remove', function $remove(item) { + /* istanbul ignore if */ + if (!this.length) return; + var index = indexOf(this, item); + if (index > -1) { + return this.splice(index, 1); + } + }); + + var arrayKeys = Object.getOwnPropertyNames(arrayMethods); + + /** + * By default, when a reactive property is set, the new value is + * also converted to become reactive. However in certain cases, e.g. + * v-for scope alias and props, we don't want to force conversion + * because the value may be a nested value under a frozen data structure. + * + * So whenever we want to set a reactive property without forcing + * conversion on the new value, we wrap that call inside this function. + */ + + var shouldConvert = true; + + function withoutConversion(fn) { + shouldConvert = false; + fn(); + shouldConvert = true; + } + + /** + * Observer class that are attached to each observed + * object. Once attached, the observer converts target + * object's property keys into getter/setters that + * collect dependencies and dispatches updates. + * + * @param {Array|Object} value + * @constructor + */ + + function Observer(value) { + this.value = value; + this.dep = new Dep(); + def(value, '__ob__', this); + if (isArray(value)) { + var augment = hasProto ? protoAugment : copyAugment; + augment(value, arrayMethods, arrayKeys); + this.observeArray(value); + } else { + this.walk(value); + } + } + + // Instance methods + + /** + * Walk through each property and convert them into + * getter/setters. This method should only be called when + * value type is Object. + * + * @param {Object} obj + */ + + Observer.prototype.walk = function (obj) { + var keys = Object.keys(obj); + for (var i = 0, l = keys.length; i < l; i++) { + this.convert(keys[i], obj[keys[i]]); + } + }; + + /** + * Observe a list of Array items. + * + * @param {Array} items + */ + + Observer.prototype.observeArray = function (items) { + for (var i = 0, l = items.length; i < l; i++) { + observe(items[i]); + } + }; + + /** + * Convert a property into getter/setter so we can emit + * the events when the property is accessed/changed. + * + * @param {String} key + * @param {*} val + */ + + Observer.prototype.convert = function (key, val) { + defineReactive(this.value, key, val); + }; + + /** + * Add an owner vm, so that when $set/$delete mutations + * happen we can notify owner vms to proxy the keys and + * digest the watchers. This is only called when the object + * is observed as an instance's root $data. + * + * @param {Vue} vm + */ + + Observer.prototype.addVm = function (vm) { + (this.vms || (this.vms = [])).push(vm); + }; + + /** + * Remove an owner vm. This is called when the object is + * swapped out as an instance's $data object. + * + * @param {Vue} vm + */ + + Observer.prototype.removeVm = function (vm) { + this.vms.$remove(vm); + }; + + // helpers + + /** + * Augment an target Object or Array by intercepting + * the prototype chain using __proto__ + * + * @param {Object|Array} target + * @param {Object} src + */ + + function protoAugment(target, src) { + /* eslint-disable no-proto */ + target.__proto__ = src; + /* eslint-enable no-proto */ + } + + /** + * Augment an target Object or Array by defining + * hidden properties. + * + * @param {Object|Array} target + * @param {Object} proto + */ + + function copyAugment(target, src, keys) { + for (var i = 0, l = keys.length; i < l; i++) { + var key = keys[i]; + def(target, key, src[key]); + } + } + + /** + * Attempt to create an observer instance for a value, + * returns the new observer if successfully observed, + * or the existing observer if the value already has one. + * + * @param {*} value + * @param {Vue} [vm] + * @return {Observer|undefined} + * @static + */ + + function observe(value, vm) { + if (!value || typeof value !== 'object') { + return; + } + var ob; + if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) { + ob = value.__ob__; + } else if (shouldConvert && (isArray(value) || isPlainObject(value)) && Object.isExtensible(value) && !value._isVue) { + ob = new Observer(value); + } + if (ob && vm) { + ob.addVm(vm); + } + return ob; + } + + /** + * Define a reactive property on an Object. + * + * @param {Object} obj + * @param {String} key + * @param {*} val + */ + + function defineReactive(obj, key, val) { + var dep = new Dep(); + + var property = Object.getOwnPropertyDescriptor(obj, key); + if (property && property.configurable === false) { + return; + } + + // cater for pre-defined getter/setters + var getter = property && property.get; + var setter = property && property.set; + + var childOb = observe(val); + Object.defineProperty(obj, key, { + enumerable: true, + configurable: true, + get: function reactiveGetter() { + var value = getter ? getter.call(obj) : val; + if (Dep.target) { + dep.depend(); + if (childOb) { + childOb.dep.depend(); + } + if (isArray(value)) { + for (var e, i = 0, l = value.length; i < l; i++) { + e = value[i]; + e && e.__ob__ && e.__ob__.dep.depend(); + } + } + } + return value; + }, + set: function reactiveSetter(newVal) { + var value = getter ? getter.call(obj) : val; + if (newVal === value) { + return; + } + if (setter) { + setter.call(obj, newVal); + } else { + val = newVal; + } + childOb = observe(newVal); + dep.notify(); + } + }); + } + + + + var util = Object.freeze({ + defineReactive: defineReactive, + set: set, + del: del, + hasOwn: hasOwn, + isLiteral: isLiteral, + isReserved: isReserved, + _toString: _toString, + toNumber: toNumber, + toBoolean: toBoolean, + stripQuotes: stripQuotes, + camelize: camelize, + hyphenate: hyphenate, + classify: classify, + bind: bind, + toArray: toArray, + extend: extend, + isObject: isObject, + isPlainObject: isPlainObject, + def: def, + debounce: _debounce, + indexOf: indexOf, + cancellable: cancellable, + looseEqual: looseEqual, + isArray: isArray, + hasProto: hasProto, + inBrowser: inBrowser, + devtools: devtools, + isIE: isIE, + isIE9: isIE9, + isAndroid: isAndroid, + isIos: isIos, + iosVersionMatch: iosVersionMatch, + iosVersion: iosVersion, + hasMutationObserverBug: hasMutationObserverBug, + get transitionProp () { return transitionProp; }, + get transitionEndEvent () { return transitionEndEvent; }, + get animationProp () { return animationProp; }, + get animationEndEvent () { return animationEndEvent; }, + nextTick: nextTick, + get _Set () { return _Set; }, + query: query, + inDoc: inDoc, + getAttr: getAttr, + getBindAttr: getBindAttr, + hasBindAttr: hasBindAttr, + before: before, + after: after, + remove: remove, + prepend: prepend, + replace: replace, + on: on, + off: off, + setClass: setClass, + addClass: addClass, + removeClass: removeClass, + extractContent: extractContent, + trimNode: trimNode, + isTemplate: isTemplate, + createAnchor: createAnchor, + findRef: findRef, + mapNodeRange: mapNodeRange, + removeNodeRange: removeNodeRange, + isFragment: isFragment, + getOuterHTML: getOuterHTML, + mergeOptions: mergeOptions, + resolveAsset: resolveAsset, + checkComponentAttr: checkComponentAttr, + commonTagRE: commonTagRE, + reservedTagRE: reservedTagRE, + get warn () { return warn; } + }); + + var uid = 0; + + function initMixin (Vue) { + /** + * The main init sequence. This is called for every + * instance, including ones that are created from extended + * constructors. + * + * @param {Object} options - this options object should be + * the result of merging class + * options and the options passed + * in to the constructor. + */ + + Vue.prototype._init = function (options) { + options = options || {}; + + this.$el = null; + this.$parent = options.parent; + this.$root = this.$parent ? this.$parent.$root : this; + this.$children = []; + this.$refs = {}; // child vm references + this.$els = {}; // element references + this._watchers = []; // all watchers as an array + this._directives = []; // all directives + + // a uid + this._uid = uid++; + + // a flag to avoid this being observed + this._isVue = true; + + // events bookkeeping + this._events = {}; // registered callbacks + this._eventsCount = {}; // for $broadcast optimization + + // fragment instance properties + this._isFragment = false; + this._fragment = // @type {DocumentFragment} + this._fragmentStart = // @type {Text|Comment} + this._fragmentEnd = null; // @type {Text|Comment} + + // lifecycle state + this._isCompiled = this._isDestroyed = this._isReady = this._isAttached = this._isBeingDestroyed = this._vForRemoving = false; + this._unlinkFn = null; + + // context: + // if this is a transcluded component, context + // will be the common parent vm of this instance + // and its host. + this._context = options._context || this.$parent; + + // scope: + // if this is inside an inline v-for, the scope + // will be the intermediate scope created for this + // repeat fragment. this is used for linking props + // and container directives. + this._scope = options._scope; + + // fragment: + // if this instance is compiled inside a Fragment, it + // needs to reigster itself as a child of that fragment + // for attach/detach to work properly. + this._frag = options._frag; + if (this._frag) { + this._frag.children.push(this); + } + + // push self into parent / transclusion host + if (this.$parent) { + this.$parent.$children.push(this); + } + + // merge options. + options = this.$options = mergeOptions(this.constructor.options, options, this); + + // set ref + this._updateRef(); + + // initialize data as empty object. + // it will be filled up in _initData(). + this._data = {}; + + // call init hook + this._callHook('init'); + + // initialize data observation and scope inheritance. + this._initState(); + + // setup event system and option events. + this._initEvents(); + + // call created hook + this._callHook('created'); + + // if `el` option is passed, start compilation. + if (options.el) { + this.$mount(options.el); + } + }; + } + + var pathCache = new Cache(1000); + + // actions + var APPEND = 0; + var PUSH = 1; + var INC_SUB_PATH_DEPTH = 2; + var PUSH_SUB_PATH = 3; + + // states + var BEFORE_PATH = 0; + var IN_PATH = 1; + var BEFORE_IDENT = 2; + var IN_IDENT = 3; + var IN_SUB_PATH = 4; + var IN_SINGLE_QUOTE = 5; + var IN_DOUBLE_QUOTE = 6; + var AFTER_PATH = 7; + var ERROR = 8; + + var pathStateMachine = []; + + pathStateMachine[BEFORE_PATH] = { + 'ws': [BEFORE_PATH], + 'ident': [IN_IDENT, APPEND], + '[': [IN_SUB_PATH], + 'eof': [AFTER_PATH] + }; + + pathStateMachine[IN_PATH] = { + 'ws': [IN_PATH], + '.': [BEFORE_IDENT], + '[': [IN_SUB_PATH], + 'eof': [AFTER_PATH] + }; + + pathStateMachine[BEFORE_IDENT] = { + 'ws': [BEFORE_IDENT], + 'ident': [IN_IDENT, APPEND] + }; + + pathStateMachine[IN_IDENT] = { + 'ident': [IN_IDENT, APPEND], + '0': [IN_IDENT, APPEND], + 'number': [IN_IDENT, APPEND], + 'ws': [IN_PATH, PUSH], + '.': [BEFORE_IDENT, PUSH], + '[': [IN_SUB_PATH, PUSH], + 'eof': [AFTER_PATH, PUSH] + }; + + pathStateMachine[IN_SUB_PATH] = { + "'": [IN_SINGLE_QUOTE, APPEND], + '"': [IN_DOUBLE_QUOTE, APPEND], + '[': [IN_SUB_PATH, INC_SUB_PATH_DEPTH], + ']': [IN_PATH, PUSH_SUB_PATH], + 'eof': ERROR, + 'else': [IN_SUB_PATH, APPEND] + }; + + pathStateMachine[IN_SINGLE_QUOTE] = { + "'": [IN_SUB_PATH, APPEND], + 'eof': ERROR, + 'else': [IN_SINGLE_QUOTE, APPEND] + }; + + pathStateMachine[IN_DOUBLE_QUOTE] = { + '"': [IN_SUB_PATH, APPEND], + 'eof': ERROR, + 'else': [IN_DOUBLE_QUOTE, APPEND] + }; + + /** + * Determine the type of a character in a keypath. + * + * @param {Char} ch + * @return {String} type + */ + + function getPathCharType(ch) { + if (ch === undefined) { + return 'eof'; + } + + var code = ch.charCodeAt(0); + + switch (code) { + case 0x5B: // [ + case 0x5D: // ] + case 0x2E: // . + case 0x22: // " + case 0x27: // ' + case 0x30: + // 0 + return ch; + + case 0x5F: // _ + case 0x24: + // $ + return 'ident'; + + case 0x20: // Space + case 0x09: // Tab + case 0x0A: // Newline + case 0x0D: // Return + case 0xA0: // No-break space + case 0xFEFF: // Byte Order Mark + case 0x2028: // Line Separator + case 0x2029: + // Paragraph Separator + return 'ws'; + } + + // a-z, A-Z + if (code >= 0x61 && code <= 0x7A || code >= 0x41 && code <= 0x5A) { + return 'ident'; + } + + // 1-9 + if (code >= 0x31 && code <= 0x39) { + return 'number'; + } + + return 'else'; + } + + /** + * Format a subPath, return its plain form if it is + * a literal string or number. Otherwise prepend the + * dynamic indicator (*). + * + * @param {String} path + * @return {String} + */ + + function formatSubPath(path) { + var trimmed = path.trim(); + // invalid leading 0 + if (path.charAt(0) === '0' && isNaN(path)) { + return false; + } + return isLiteral(trimmed) ? stripQuotes(trimmed) : '*' + trimmed; + } + + /** + * Parse a string path into an array of segments + * + * @param {String} path + * @return {Array|undefined} + */ + + function parse(path) { + var keys = []; + var index = -1; + var mode = BEFORE_PATH; + var subPathDepth = 0; + var c, newChar, key, type, transition, action, typeMap; + + var actions = []; + + actions[PUSH] = function () { + if (key !== undefined) { + keys.push(key); + key = undefined; + } + }; + + actions[APPEND] = function () { + if (key === undefined) { + key = newChar; + } else { + key += newChar; + } + }; + + actions[INC_SUB_PATH_DEPTH] = function () { + actions[APPEND](); + subPathDepth++; + }; + + actions[PUSH_SUB_PATH] = function () { + if (subPathDepth > 0) { + subPathDepth--; + mode = IN_SUB_PATH; + actions[APPEND](); + } else { + subPathDepth = 0; + key = formatSubPath(key); + if (key === false) { + return false; + } else { + actions[PUSH](); + } + } + }; + + function maybeUnescapeQuote() { + var nextChar = path[index + 1]; + if (mode === IN_SINGLE_QUOTE && nextChar === "'" || mode === IN_DOUBLE_QUOTE && nextChar === '"') { + index++; + newChar = '\\' + nextChar; + actions[APPEND](); + return true; + } + } + + while (mode != null) { + index++; + c = path[index]; + + if (c === '\\' && maybeUnescapeQuote()) { + continue; + } + + type = getPathCharType(c); + typeMap = pathStateMachine[mode]; + transition = typeMap[type] || typeMap['else'] || ERROR; + + if (transition === ERROR) { + return; // parse error + } + + mode = transition[0]; + action = actions[transition[1]]; + if (action) { + newChar = transition[2]; + newChar = newChar === undefined ? c : newChar; + if (action() === false) { + return; + } + } + + if (mode === AFTER_PATH) { + keys.raw = path; + return keys; + } + } + } + + /** + * External parse that check for a cache hit first + * + * @param {String} path + * @return {Array|undefined} + */ + + function parsePath(path) { + var hit = pathCache.get(path); + if (!hit) { + hit = parse(path); + if (hit) { + pathCache.put(path, hit); + } + } + return hit; + } + + /** + * Get from an object from a path string + * + * @param {Object} obj + * @param {String} path + */ + + function getPath(obj, path) { + return parseExpression(path).get(obj); + } + + /** + * Warn against setting non-existent root path on a vm. + */ + + var warnNonExistent; + if ('development' !== 'production') { + warnNonExistent = function (path, vm) { + warn('You are setting a non-existent path "' + path.raw + '" ' + 'on a vm instance. Consider pre-initializing the property ' + 'with the "data" option for more reliable reactivity ' + 'and better performance.', vm); + }; + } + + /** + * Set on an object from a path + * + * @param {Object} obj + * @param {String | Array} path + * @param {*} val + */ + + function setPath(obj, path, val) { + var original = obj; + if (typeof path === 'string') { + path = parse(path); + } + if (!path || !isObject(obj)) { + return false; + } + var last, key; + for (var i = 0, l = path.length; i < l; i++) { + last = obj; + key = path[i]; + if (key.charAt(0) === '*') { + key = parseExpression(key.slice(1)).get.call(original, original); + } + if (i < l - 1) { + obj = obj[key]; + if (!isObject(obj)) { + obj = {}; + if ('development' !== 'production' && last._isVue) { + warnNonExistent(path, last); + } + set(last, key, obj); + } + } else { + if (isArray(obj)) { + obj.$set(key, val); + } else if (key in obj) { + obj[key] = val; + } else { + if ('development' !== 'production' && obj._isVue) { + warnNonExistent(path, obj); + } + set(obj, key, val); + } + } + } + return true; + } + +var path = Object.freeze({ + parsePath: parsePath, + getPath: getPath, + setPath: setPath + }); + + var expressionCache = new Cache(1000); + + var allowedKeywords = 'Math,Date,this,true,false,null,undefined,Infinity,NaN,' + 'isNaN,isFinite,decodeURI,decodeURIComponent,encodeURI,' + 'encodeURIComponent,parseInt,parseFloat'; + var allowedKeywordsRE = new RegExp('^(' + allowedKeywords.replace(/,/g, '\\b|') + '\\b)'); + + // keywords that don't make sense inside expressions + var improperKeywords = 'break,case,class,catch,const,continue,debugger,default,' + 'delete,do,else,export,extends,finally,for,function,if,' + 'import,in,instanceof,let,return,super,switch,throw,try,' + 'var,while,with,yield,enum,await,implements,package,' + 'protected,static,interface,private,public'; + var improperKeywordsRE = new RegExp('^(' + improperKeywords.replace(/,/g, '\\b|') + '\\b)'); + + var wsRE = /\s/g; + var newlineRE = /\n/g; + var saveRE = /[\{,]\s*[\w\$_]+\s*:|('(?:[^'\\]|\\.)*'|"(?:[^"\\]|\\.)*"|`(?:[^`\\]|\\.)*\$\{|\}(?:[^`\\]|\\.)*`|`(?:[^`\\]|\\.)*`)|new |typeof |void /g; + var restoreRE = /"(\d+)"/g; + var pathTestRE = /^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*|\['.*?'\]|\[".*?"\]|\[\d+\]|\[[A-Za-z_$][\w$]*\])*$/; + var identRE = /[^\w$\.](?:[A-Za-z_$][\w$]*)/g; + var literalValueRE$1 = /^(?:true|false|null|undefined|Infinity|NaN)$/; + + function noop() {} + + /** + * Save / Rewrite / Restore + * + * When rewriting paths found in an expression, it is + * possible for the same letter sequences to be found in + * strings and Object literal property keys. Therefore we + * remove and store these parts in a temporary array, and + * restore them after the path rewrite. + */ + + var saved = []; + + /** + * Save replacer + * + * The save regex can match two possible cases: + * 1. An opening object literal + * 2. A string + * If matched as a plain string, we need to escape its + * newlines, since the string needs to be preserved when + * generating the function body. + * + * @param {String} str + * @param {String} isString - str if matched as a string + * @return {String} - placeholder with index + */ + + function save(str, isString) { + var i = saved.length; + saved[i] = isString ? str.replace(newlineRE, '\\n') : str; + return '"' + i + '"'; + } + + /** + * Path rewrite replacer + * + * @param {String} raw + * @return {String} + */ + + function rewrite(raw) { + var c = raw.charAt(0); + var path = raw.slice(1); + if (allowedKeywordsRE.test(path)) { + return raw; + } else { + path = path.indexOf('"') > -1 ? path.replace(restoreRE, restore) : path; + return c + 'scope.' + path; + } + } + + /** + * Restore replacer + * + * @param {String} str + * @param {String} i - matched save index + * @return {String} + */ + + function restore(str, i) { + return saved[i]; + } + + /** + * Rewrite an expression, prefixing all path accessors with + * `scope.` and generate getter/setter functions. + * + * @param {String} exp + * @return {Function} + */ + + function compileGetter(exp) { + if (improperKeywordsRE.test(exp)) { + 'development' !== 'production' && warn('Avoid using reserved keywords in expression: ' + exp); + } + // reset state + saved.length = 0; + // save strings and object literal keys + var body = exp.replace(saveRE, save).replace(wsRE, ''); + // rewrite all paths + // pad 1 space here because the regex matches 1 extra char + body = (' ' + body).replace(identRE, rewrite).replace(restoreRE, restore); + return makeGetterFn(body); + } + + /** + * Build a getter function. Requires eval. + * + * We isolate the try/catch so it doesn't affect the + * optimization of the parse function when it is not called. + * + * @param {String} body + * @return {Function|undefined} + */ + + function makeGetterFn(body) { + try { + /* eslint-disable no-new-func */ + return new Function('scope', 'return ' + body + ';'); + /* eslint-enable no-new-func */ + } catch (e) { + if ('development' !== 'production') { + /* istanbul ignore if */ + if (e.toString().match(/unsafe-eval|CSP/)) { + warn('It seems you are using the default build of Vue.js in an environment ' + 'with Content Security Policy that prohibits unsafe-eval. ' + 'Use the CSP-compliant build instead: ' + 'http://vuejs.org/guide/installation.html#CSP-compliant-build'); + } else { + warn('Invalid expression. ' + 'Generated function body: ' + body); + } + } + return noop; + } + } + + /** + * Compile a setter function for the expression. + * + * @param {String} exp + * @return {Function|undefined} + */ + + function compileSetter(exp) { + var path = parsePath(exp); + if (path) { + return function (scope, val) { + setPath(scope, path, val); + }; + } else { + 'development' !== 'production' && warn('Invalid setter expression: ' + exp); + } + } + + /** + * Parse an expression into re-written getter/setters. + * + * @param {String} exp + * @param {Boolean} needSet + * @return {Function} + */ + + function parseExpression(exp, needSet) { + exp = exp.trim(); + // try cache + var hit = expressionCache.get(exp); + if (hit) { + if (needSet && !hit.set) { + hit.set = compileSetter(hit.exp); + } + return hit; + } + var res = { exp: exp }; + res.get = isSimplePath(exp) && exp.indexOf('[') < 0 + // optimized super simple getter + ? makeGetterFn('scope.' + exp) + // dynamic getter + : compileGetter(exp); + if (needSet) { + res.set = compileSetter(exp); + } + expressionCache.put(exp, res); + return res; + } + + /** + * Check if an expression is a simple path. + * + * @param {String} exp + * @return {Boolean} + */ + + function isSimplePath(exp) { + return pathTestRE.test(exp) && + // don't treat literal values as paths + !literalValueRE$1.test(exp) && + // Math constants e.g. Math.PI, Math.E etc. + exp.slice(0, 5) !== 'Math.'; + } + +var expression = Object.freeze({ + parseExpression: parseExpression, + isSimplePath: isSimplePath + }); + + // we have two separate queues: one for directive updates + // and one for user watcher registered via $watch(). + // we want to guarantee directive updates to be called + // before user watchers so that when user watchers are + // triggered, the DOM would have already been in updated + // state. + + var queue = []; + var userQueue = []; + var has = {}; + var circular = {}; + var waiting = false; + + /** + * Reset the batcher's state. + */ + + function resetBatcherState() { + queue.length = 0; + userQueue.length = 0; + has = {}; + circular = {}; + waiting = false; + } + + /** + * Flush both queues and run the watchers. + */ + + function flushBatcherQueue() { + var _again = true; + + _function: while (_again) { + _again = false; + + runBatcherQueue(queue); + runBatcherQueue(userQueue); + // user watchers triggered more watchers, + // keep flushing until it depletes + if (queue.length) { + _again = true; + continue _function; + } + // dev tool hook + /* istanbul ignore if */ + if (devtools && config.devtools) { + devtools.emit('flush'); + } + resetBatcherState(); + } + } + + /** + * Run the watchers in a single queue. + * + * @param {Array} queue + */ + + function runBatcherQueue(queue) { + // do not cache length because more watchers might be pushed + // as we run existing watchers + for (var i = 0; i < queue.length; i++) { + var watcher = queue[i]; + var id = watcher.id; + has[id] = null; + watcher.run(); + // in dev build, check and stop circular updates. + if ('development' !== 'production' && has[id] != null) { + circular[id] = (circular[id] || 0) + 1; + if (circular[id] > config._maxUpdateCount) { + warn('You may have an infinite update loop for watcher ' + 'with expression "' + watcher.expression + '"', watcher.vm); + break; + } + } + } + queue.length = 0; + } + + /** + * Push a watcher into the watcher queue. + * Jobs with duplicate IDs will be skipped unless it's + * pushed when the queue is being flushed. + * + * @param {Watcher} watcher + * properties: + * - {Number} id + * - {Function} run + */ + + function pushWatcher(watcher) { + var id = watcher.id; + if (has[id] == null) { + // push watcher into appropriate queue + var q = watcher.user ? userQueue : queue; + has[id] = q.length; + q.push(watcher); + // queue the flush + if (!waiting) { + waiting = true; + nextTick(flushBatcherQueue); + } + } + } + + var uid$2 = 0; + + /** + * A watcher parses an expression, collects dependencies, + * and fires callback when the expression value changes. + * This is used for both the $watch() api and directives. + * + * @param {Vue} vm + * @param {String|Function} expOrFn + * @param {Function} cb + * @param {Object} options + * - {Array} filters + * - {Boolean} twoWay + * - {Boolean} deep + * - {Boolean} user + * - {Boolean} sync + * - {Boolean} lazy + * - {Function} [preProcess] + * - {Function} [postProcess] + * @constructor + */ + function Watcher(vm, expOrFn, cb, options) { + // mix in options + if (options) { + extend(this, options); + } + var isFn = typeof expOrFn === 'function'; + this.vm = vm; + vm._watchers.push(this); + this.expression = expOrFn; + this.cb = cb; + this.id = ++uid$2; // uid for batching + this.active = true; + this.dirty = this.lazy; // for lazy watchers + this.deps = []; + this.newDeps = []; + this.depIds = new _Set(); + this.newDepIds = new _Set(); + this.prevError = null; // for async error stacks + // parse expression for getter/setter + if (isFn) { + this.getter = expOrFn; + this.setter = undefined; + } else { + var res = parseExpression(expOrFn, this.twoWay); + this.getter = res.get; + this.setter = res.set; + } + this.value = this.lazy ? undefined : this.get(); + // state for avoiding false triggers for deep and Array + // watchers during vm._digest() + this.queued = this.shallow = false; + } + + /** + * Evaluate the getter, and re-collect dependencies. + */ + + Watcher.prototype.get = function () { + this.beforeGet(); + var scope = this.scope || this.vm; + var value; + try { + value = this.getter.call(scope, scope); + } catch (e) { + if ('development' !== 'production' && config.warnExpressionErrors) { + warn('Error when evaluating expression ' + '"' + this.expression + '": ' + e.toString(), this.vm); + } + } + // "touch" every property so they are all tracked as + // dependencies for deep watching + if (this.deep) { + traverse(value); + } + if (this.preProcess) { + value = this.preProcess(value); + } + if (this.filters) { + value = scope._applyFilters(value, null, this.filters, false); + } + if (this.postProcess) { + value = this.postProcess(value); + } + this.afterGet(); + return value; + }; + + /** + * Set the corresponding value with the setter. + * + * @param {*} value + */ + + Watcher.prototype.set = function (value) { + var scope = this.scope || this.vm; + if (this.filters) { + value = scope._applyFilters(value, this.value, this.filters, true); + } + try { + this.setter.call(scope, scope, value); + } catch (e) { + if ('development' !== 'production' && config.warnExpressionErrors) { + warn('Error when evaluating setter ' + '"' + this.expression + '": ' + e.toString(), this.vm); + } + } + // two-way sync for v-for alias + var forContext = scope.$forContext; + if (forContext && forContext.alias === this.expression) { + if (forContext.filters) { + 'development' !== 'production' && warn('It seems you are using two-way binding on ' + 'a v-for alias (' + this.expression + '), and the ' + 'v-for has filters. This will not work properly. ' + 'Either remove the filters or use an array of ' + 'objects and bind to object properties instead.', this.vm); + return; + } + forContext._withLock(function () { + if (scope.$key) { + // original is an object + forContext.rawValue[scope.$key] = value; + } else { + forContext.rawValue.$set(scope.$index, value); + } + }); + } + }; + + /** + * Prepare for dependency collection. + */ + + Watcher.prototype.beforeGet = function () { + Dep.target = this; + }; + + /** + * Add a dependency to this directive. + * + * @param {Dep} dep + */ + + Watcher.prototype.addDep = function (dep) { + var id = dep.id; + if (!this.newDepIds.has(id)) { + this.newDepIds.add(id); + this.newDeps.push(dep); + if (!this.depIds.has(id)) { + dep.addSub(this); + } + } + }; + + /** + * Clean up for dependency collection. + */ + + Watcher.prototype.afterGet = function () { + Dep.target = null; + var i = this.deps.length; + while (i--) { + var dep = this.deps[i]; + if (!this.newDepIds.has(dep.id)) { + dep.removeSub(this); + } + } + var tmp = this.depIds; + this.depIds = this.newDepIds; + this.newDepIds = tmp; + this.newDepIds.clear(); + tmp = this.deps; + this.deps = this.newDeps; + this.newDeps = tmp; + this.newDeps.length = 0; + }; + + /** + * Subscriber interface. + * Will be called when a dependency changes. + * + * @param {Boolean} shallow + */ + + Watcher.prototype.update = function (shallow) { + if (this.lazy) { + this.dirty = true; + } else if (this.sync || !config.async) { + this.run(); + } else { + // if queued, only overwrite shallow with non-shallow, + // but not the other way around. + this.shallow = this.queued ? shallow ? this.shallow : false : !!shallow; + this.queued = true; + // record before-push error stack in debug mode + /* istanbul ignore if */ + if ('development' !== 'production' && config.debug) { + this.prevError = new Error('[vue] async stack trace'); + } + pushWatcher(this); + } + }; + + /** + * Batcher job interface. + * Will be called by the batcher. + */ + + Watcher.prototype.run = function () { + if (this.active) { + var value = this.get(); + if (value !== this.value || + // Deep watchers and watchers on Object/Arrays should fire even + // when the value is the same, because the value may + // have mutated; but only do so if this is a + // non-shallow update (caused by a vm digest). + (isObject(value) || this.deep) && !this.shallow) { + // set new value + var oldValue = this.value; + this.value = value; + // in debug + async mode, when a watcher callbacks + // throws, we also throw the saved before-push error + // so the full cross-tick stack trace is available. + var prevError = this.prevError; + /* istanbul ignore if */ + if ('development' !== 'production' && config.debug && prevError) { + this.prevError = null; + try { + this.cb.call(this.vm, value, oldValue); + } catch (e) { + nextTick(function () { + throw prevError; + }, 0); + throw e; + } + } else { + this.cb.call(this.vm, value, oldValue); + } + } + this.queued = this.shallow = false; + } + }; + + /** + * Evaluate the value of the watcher. + * This only gets called for lazy watchers. + */ + + Watcher.prototype.evaluate = function () { + // avoid overwriting another watcher that is being + // collected. + var current = Dep.target; + this.value = this.get(); + this.dirty = false; + Dep.target = current; + }; + + /** + * Depend on all deps collected by this watcher. + */ + + Watcher.prototype.depend = function () { + var i = this.deps.length; + while (i--) { + this.deps[i].depend(); + } + }; + + /** + * Remove self from all dependencies' subcriber list. + */ + + Watcher.prototype.teardown = function () { + if (this.active) { + // remove self from vm's watcher list + // this is a somewhat expensive operation so we skip it + // if the vm is being destroyed or is performing a v-for + // re-render (the watcher list is then filtered by v-for). + if (!this.vm._isBeingDestroyed && !this.vm._vForRemoving) { + this.vm._watchers.$remove(this); + } + var i = this.deps.length; + while (i--) { + this.deps[i].removeSub(this); + } + this.active = false; + this.vm = this.cb = this.value = null; + } + }; + + /** + * Recrusively traverse an object to evoke all converted + * getters, so that every nested property inside the object + * is collected as a "deep" dependency. + * + * @param {*} val + */ + + var seenObjects = new _Set(); + function traverse(val, seen) { + var i = undefined, + keys = undefined; + if (!seen) { + seen = seenObjects; + seen.clear(); + } + var isA = isArray(val); + var isO = isObject(val); + if ((isA || isO) && Object.isExtensible(val)) { + if (val.__ob__) { + var depId = val.__ob__.dep.id; + if (seen.has(depId)) { + return; + } else { + seen.add(depId); + } + } + if (isA) { + i = val.length; + while (i--) traverse(val[i], seen); + } else if (isO) { + keys = Object.keys(val); + i = keys.length; + while (i--) traverse(val[keys[i]], seen); + } + } + } + + var text$1 = { + + bind: function bind() { + this.attr = this.el.nodeType === 3 ? 'data' : 'textContent'; + }, + + update: function update(value) { + this.el[this.attr] = _toString(value); + } + }; + + var templateCache = new Cache(1000); + var idSelectorCache = new Cache(1000); + + var map = { + efault: [0, '', ''], + legend: [1, '
', '
'], + tr: [2, '', '
'], + col: [2, '', '
'] + }; + + map.td = map.th = [3, '', '
']; + + map.option = map.optgroup = [1, '']; + + map.thead = map.tbody = map.colgroup = map.caption = map.tfoot = [1, '', '
']; + + map.g = map.defs = map.symbol = map.use = map.image = map.text = map.circle = map.ellipse = map.line = map.path = map.polygon = map.polyline = map.rect = [1, '', '']; + + /** + * Check if a node is a supported template node with a + * DocumentFragment content. + * + * @param {Node} node + * @return {Boolean} + */ + + function isRealTemplate(node) { + return isTemplate(node) && isFragment(node.content); + } + + var tagRE$1 = /<([\w:-]+)/; + var entityRE = /&#?\w+?;/; + var commentRE = / E + } + entry.newer = undefined; // D --x + entry.older = this.tail; // D. --> E + if (this.tail) { + this.tail.newer = entry; // E. <-- D + } + this.tail = entry; + return returnEntry ? entry : entry.value; + }; + + var cache$1 = new Cache(1000); + var filterTokenRE = /[^\s'"]+|'[^']*'|"[^"]*"/g; + var reservedArgRE = /^in$|^-?\d+/; + + /** + * Parser state + */ + + var str; + var dir; + var c; + var prev; + var i; + var l; + var lastFilterIndex; + var inSingle; + var inDouble; + var curly; + var square; + var paren; + /** + * Push a filter to the current directive object + */ + + function pushFilter() { + var exp = str.slice(lastFilterIndex, i).trim(); + var filter; + if (exp) { + filter = {}; + var tokens = exp.match(filterTokenRE); + filter.name = tokens[0]; + if (tokens.length > 1) { + filter.args = tokens.slice(1).map(processFilterArg); + } + } + if (filter) { + (dir.filters = dir.filters || []).push(filter); + } + lastFilterIndex = i + 1; + } + + /** + * Check if an argument is dynamic and strip quotes. + * + * @param {String} arg + * @return {Object} + */ + + function processFilterArg(arg) { + if (reservedArgRE.test(arg)) { + return { + value: toNumber(arg), + dynamic: false + }; + } else { + var stripped = stripQuotes(arg); + var dynamic = stripped === arg; + return { + value: dynamic ? arg : stripped, + dynamic: dynamic + }; + } + } + + /** + * Parse a directive value and extract the expression + * and its filters into a descriptor. + * + * Example: + * + * "a + 1 | uppercase" will yield: + * { + * expression: 'a + 1', + * filters: [ + * { name: 'uppercase', args: null } + * ] + * } + * + * @param {String} s + * @return {Object} + */ + + function parseDirective(s) { + var hit = cache$1.get(s); + if (hit) { + return hit; + } + + // reset parser state + str = s; + inSingle = inDouble = false; + curly = square = paren = 0; + lastFilterIndex = 0; + dir = {}; + + for (i = 0, l = str.length; i < l; i++) { + prev = c; + c = str.charCodeAt(i); + if (inSingle) { + // check single quote + if (c === 0x27 && prev !== 0x5C) inSingle = !inSingle; + } else if (inDouble) { + // check double quote + if (c === 0x22 && prev !== 0x5C) inDouble = !inDouble; + } else if (c === 0x7C && // pipe + str.charCodeAt(i + 1) !== 0x7C && str.charCodeAt(i - 1) !== 0x7C) { + if (dir.expression == null) { + // first filter, end of expression + lastFilterIndex = i + 1; + dir.expression = str.slice(0, i).trim(); + } else { + // already has filter + pushFilter(); + } + } else { + switch (c) { + case 0x22: + inDouble = true;break; // " + case 0x27: + inSingle = true;break; // ' + case 0x28: + paren++;break; // ( + case 0x29: + paren--;break; // ) + case 0x5B: + square++;break; // [ + case 0x5D: + square--;break; // ] + case 0x7B: + curly++;break; // { + case 0x7D: + curly--;break; // } + } + } + } + + if (dir.expression == null) { + dir.expression = str.slice(0, i).trim(); + } else if (lastFilterIndex !== 0) { + pushFilter(); + } + + cache$1.put(s, dir); + return dir; + } + +var directive = Object.freeze({ + parseDirective: parseDirective + }); + + var regexEscapeRE = /[-.*+?^${}()|[\]\/\\]/g; + var cache = undefined; + var tagRE = undefined; + var htmlRE = undefined; + /** + * Escape a string so it can be used in a RegExp + * constructor. + * + * @param {String} str + */ + + function escapeRegex(str) { + return str.replace(regexEscapeRE, '\\$&'); + } + + function compileRegex() { + var open = escapeRegex(config.delimiters[0]); + var close = escapeRegex(config.delimiters[1]); + var unsafeOpen = escapeRegex(config.unsafeDelimiters[0]); + var unsafeClose = escapeRegex(config.unsafeDelimiters[1]); + tagRE = new RegExp(unsafeOpen + '((?:.|\\n)+?)' + unsafeClose + '|' + open + '((?:.|\\n)+?)' + close, 'g'); + htmlRE = new RegExp('^' + unsafeOpen + '((?:.|\\n)+?)' + unsafeClose + '$'); + // reset cache + cache = new Cache(1000); + } + + /** + * Parse a template text string into an array of tokens. + * + * @param {String} text + * @return {Array | null} + * - {String} type + * - {String} value + * - {Boolean} [html] + * - {Boolean} [oneTime] + */ + + function parseText(text) { + if (!cache) { + compileRegex(); + } + var hit = cache.get(text); + if (hit) { + return hit; + } + if (!tagRE.test(text)) { + return null; + } + var tokens = []; + var lastIndex = tagRE.lastIndex = 0; + var match, index, html, value, first, oneTime; + /* eslint-disable no-cond-assign */ + while (match = tagRE.exec(text)) { + /* eslint-enable no-cond-assign */ + index = match.index; + // push text token + if (index > lastIndex) { + tokens.push({ + value: text.slice(lastIndex, index) + }); + } + // tag token + html = htmlRE.test(match[0]); + value = html ? match[1] : match[2]; + first = value.charCodeAt(0); + oneTime = first === 42; // * + value = oneTime ? value.slice(1) : value; + tokens.push({ + tag: true, + value: value.trim(), + html: html, + oneTime: oneTime + }); + lastIndex = index + match[0].length; + } + if (lastIndex < text.length) { + tokens.push({ + value: text.slice(lastIndex) + }); + } + cache.put(text, tokens); + return tokens; + } + + /** + * Format a list of tokens into an expression. + * e.g. tokens parsed from 'a {{b}} c' can be serialized + * into one single expression as '"a " + b + " c"'. + * + * @param {Array} tokens + * @param {Vue} [vm] + * @return {String} + */ + + function tokensToExp(tokens, vm) { + if (tokens.length > 1) { + return tokens.map(function (token) { + return formatToken(token, vm); + }).join('+'); + } else { + return formatToken(tokens[0], vm, true); + } + } + + /** + * Format a single token. + * + * @param {Object} token + * @param {Vue} [vm] + * @param {Boolean} [single] + * @return {String} + */ + + function formatToken(token, vm, single) { + return token.tag ? token.oneTime && vm ? '"' + vm.$eval(token.value) + '"' : inlineFilters(token.value, single) : '"' + token.value + '"'; + } + + /** + * For an attribute with multiple interpolation tags, + * e.g. attr="some-{{thing | filter}}", in order to combine + * the whole thing into a single watchable expression, we + * have to inline those filters. This function does exactly + * that. This is a bit hacky but it avoids heavy changes + * to directive parser and watcher mechanism. + * + * @param {String} exp + * @param {Boolean} single + * @return {String} + */ + + var filterRE = /[^|]\|[^|]/; + function inlineFilters(exp, single) { + if (!filterRE.test(exp)) { + return single ? exp : '(' + exp + ')'; + } else { + var dir = parseDirective(exp); + if (!dir.filters) { + return '(' + exp + ')'; + } else { + return 'this._applyFilters(' + dir.expression + // value + ',null,' + // oldValue (null for read) + JSON.stringify(dir.filters) + // filter descriptors + ',false)'; // write? + } + } + } + +var text = Object.freeze({ + compileRegex: compileRegex, + parseText: parseText, + tokensToExp: tokensToExp + }); + + var delimiters = ['{{', '}}']; + var unsafeDelimiters = ['{{{', '}}}']; + + var config = Object.defineProperties({ + + /** + * Whether to print debug messages. + * Also enables stack trace for warnings. + * + * @type {Boolean} + */ + + debug: false, + + /** + * Whether to suppress warnings. + * + * @type {Boolean} + */ + + silent: false, + + /** + * Whether to use async rendering. + */ + + async: true, + + /** + * Whether to warn against errors caught when evaluating + * expressions. + */ + + warnExpressionErrors: true, + + /** + * Whether to allow devtools inspection. + * Disabled by default in production builds. + */ + + devtools: 'development' !== 'production', + + /** + * Internal flag to indicate the delimiters have been + * changed. + * + * @type {Boolean} + */ + + _delimitersChanged: true, + + /** + * List of asset types that a component can own. + * + * @type {Array} + */ + + _assetTypes: ['component', 'directive', 'elementDirective', 'filter', 'transition', 'partial'], + + /** + * prop binding modes + */ + + _propBindingModes: { + ONE_WAY: 0, + TWO_WAY: 1, + ONE_TIME: 2 + }, + + /** + * Max circular updates allowed in a batcher flush cycle. + */ + + _maxUpdateCount: 100 + + }, { + delimiters: { /** + * Interpolation delimiters. Changing these would trigger + * the text parser to re-compile the regular expressions. + * + * @type {Array} + */ + + get: function get() { + return delimiters; + }, + set: function set(val) { + delimiters = val; + compileRegex(); + }, + configurable: true, + enumerable: true + }, + unsafeDelimiters: { + get: function get() { + return unsafeDelimiters; + }, + set: function set(val) { + unsafeDelimiters = val; + compileRegex(); + }, + configurable: true, + enumerable: true + } + }); + + var warn = undefined; + var formatComponentName = undefined; + + if ('development' !== 'production') { + (function () { + var hasConsole = typeof console !== 'undefined'; + + warn = function (msg, vm) { + if (hasConsole && !config.silent) { + console.error('[Vue warn]: ' + msg + (vm ? formatComponentName(vm) : '')); + } + }; + + formatComponentName = function (vm) { + var name = vm._isVue ? vm.$options.name : vm.name; + return name ? ' (found in component: <' + hyphenate(name) + '>)' : ''; + }; + })(); + } + + /** + * Append with transition. + * + * @param {Element} el + * @param {Element} target + * @param {Vue} vm + * @param {Function} [cb] + */ + + function appendWithTransition(el, target, vm, cb) { + applyTransition(el, 1, function () { + target.appendChild(el); + }, vm, cb); + } + + /** + * InsertBefore with transition. + * + * @param {Element} el + * @param {Element} target + * @param {Vue} vm + * @param {Function} [cb] + */ + + function beforeWithTransition(el, target, vm, cb) { + applyTransition(el, 1, function () { + before(el, target); + }, vm, cb); + } + + /** + * Remove with transition. + * + * @param {Element} el + * @param {Vue} vm + * @param {Function} [cb] + */ + + function removeWithTransition(el, vm, cb) { + applyTransition(el, -1, function () { + remove(el); + }, vm, cb); + } + + /** + * Apply transitions with an operation callback. + * + * @param {Element} el + * @param {Number} direction + * 1: enter + * -1: leave + * @param {Function} op - the actual DOM operation + * @param {Vue} vm + * @param {Function} [cb] + */ + + function applyTransition(el, direction, op, vm, cb) { + var transition = el.__v_trans; + if (!transition || + // skip if there are no js hooks and CSS transition is + // not supported + !transition.hooks && !transitionEndEvent || + // skip transitions for initial compile + !vm._isCompiled || + // if the vm is being manipulated by a parent directive + // during the parent's compilation phase, skip the + // animation. + vm.$parent && !vm.$parent._isCompiled) { + op(); + if (cb) cb(); + return; + } + var action = direction > 0 ? 'enter' : 'leave'; + transition[action](op, cb); + } + +var transition = Object.freeze({ + appendWithTransition: appendWithTransition, + beforeWithTransition: beforeWithTransition, + removeWithTransition: removeWithTransition, + applyTransition: applyTransition + }); + + /** + * Query an element selector if it's not an element already. + * + * @param {String|Element} el + * @return {Element} + */ + + function query(el) { + if (typeof el === 'string') { + var selector = el; + el = document.querySelector(el); + if (!el) { + 'development' !== 'production' && warn('Cannot find element: ' + selector); + } + } + return el; + } + + /** + * Check if a node is in the document. + * Note: document.documentElement.contains should work here + * but always returns false for comment nodes in phantomjs, + * making unit tests difficult. This is fixed by doing the + * contains() check on the node's parentNode instead of + * the node itself. + * + * @param {Node} node + * @return {Boolean} + */ + + function inDoc(node) { + if (!node) return false; + var doc = node.ownerDocument.documentElement; + var parent = node.parentNode; + return doc === node || doc === parent || !!(parent && parent.nodeType === 1 && doc.contains(parent)); + } + + /** + * Get and remove an attribute from a node. + * + * @param {Node} node + * @param {String} _attr + */ + + function getAttr(node, _attr) { + var val = node.getAttribute(_attr); + if (val !== null) { + node.removeAttribute(_attr); + } + return val; + } + + /** + * Get an attribute with colon or v-bind: prefix. + * + * @param {Node} node + * @param {String} name + * @return {String|null} + */ + + function getBindAttr(node, name) { + var val = getAttr(node, ':' + name); + if (val === null) { + val = getAttr(node, 'v-bind:' + name); + } + return val; + } + + /** + * Check the presence of a bind attribute. + * + * @param {Node} node + * @param {String} name + * @return {Boolean} + */ + + function hasBindAttr(node, name) { + return node.hasAttribute(name) || node.hasAttribute(':' + name) || node.hasAttribute('v-bind:' + name); + } + + /** + * Insert el before target + * + * @param {Element} el + * @param {Element} target + */ + + function before(el, target) { + target.parentNode.insertBefore(el, target); + } + + /** + * Insert el after target + * + * @param {Element} el + * @param {Element} target + */ + + function after(el, target) { + if (target.nextSibling) { + before(el, target.nextSibling); + } else { + target.parentNode.appendChild(el); + } + } + + /** + * Remove el from DOM + * + * @param {Element} el + */ + + function remove(el) { + el.parentNode.removeChild(el); + } + + /** + * Prepend el to target + * + * @param {Element} el + * @param {Element} target + */ + + function prepend(el, target) { + if (target.firstChild) { + before(el, target.firstChild); + } else { + target.appendChild(el); + } + } + + /** + * Replace target with el + * + * @param {Element} target + * @param {Element} el + */ + + function replace(target, el) { + var parent = target.parentNode; + if (parent) { + parent.replaceChild(el, target); + } + } + + /** + * Add event listener shorthand. + * + * @param {Element} el + * @param {String} event + * @param {Function} cb + * @param {Boolean} [useCapture] + */ + + function on(el, event, cb, useCapture) { + el.addEventListener(event, cb, useCapture); + } + + /** + * Remove event listener shorthand. + * + * @param {Element} el + * @param {String} event + * @param {Function} cb + */ + + function off(el, event, cb) { + el.removeEventListener(event, cb); + } + + /** + * For IE9 compat: when both class and :class are present + * getAttribute('class') returns wrong value... + * + * @param {Element} el + * @return {String} + */ + + function getClass(el) { + var classname = el.className; + if (typeof classname === 'object') { + classname = classname.baseVal || ''; + } + return classname; + } + + /** + * In IE9, setAttribute('class') will result in empty class + * if the element also has the :class attribute; However in + * PhantomJS, setting `className` does not work on SVG elements... + * So we have to do a conditional check here. + * + * @param {Element} el + * @param {String} cls + */ + + function setClass(el, cls) { + /* istanbul ignore if */ + if (isIE9 && !/svg$/.test(el.namespaceURI)) { + el.className = cls; + } else { + el.setAttribute('class', cls); + } + } + + /** + * Add class with compatibility for IE & SVG + * + * @param {Element} el + * @param {String} cls + */ + + function addClass(el, cls) { + if (el.classList) { + el.classList.add(cls); + } else { + var cur = ' ' + getClass(el) + ' '; + if (cur.indexOf(' ' + cls + ' ') < 0) { + setClass(el, (cur + cls).trim()); + } + } + } + + /** + * Remove class with compatibility for IE & SVG + * + * @param {Element} el + * @param {String} cls + */ + + function removeClass(el, cls) { + if (el.classList) { + el.classList.remove(cls); + } else { + var cur = ' ' + getClass(el) + ' '; + var tar = ' ' + cls + ' '; + while (cur.indexOf(tar) >= 0) { + cur = cur.replace(tar, ' '); + } + setClass(el, cur.trim()); + } + if (!el.className) { + el.removeAttribute('class'); + } + } + + /** + * Extract raw content inside an element into a temporary + * container div + * + * @param {Element} el + * @param {Boolean} asFragment + * @return {Element|DocumentFragment} + */ + + function extractContent(el, asFragment) { + var child; + var rawContent; + /* istanbul ignore if */ + if (isTemplate(el) && isFragment(el.content)) { + el = el.content; + } + if (el.hasChildNodes()) { + trimNode(el); + rawContent = asFragment ? document.createDocumentFragment() : document.createElement('div'); + /* eslint-disable no-cond-assign */ + while (child = el.firstChild) { + /* eslint-enable no-cond-assign */ + rawContent.appendChild(child); + } + } + return rawContent; + } + + /** + * Trim possible empty head/tail text and comment + * nodes inside a parent. + * + * @param {Node} node + */ + + function trimNode(node) { + var child; + /* eslint-disable no-sequences */ + while ((child = node.firstChild, isTrimmable(child))) { + node.removeChild(child); + } + while ((child = node.lastChild, isTrimmable(child))) { + node.removeChild(child); + } + /* eslint-enable no-sequences */ + } + + function isTrimmable(node) { + return node && (node.nodeType === 3 && !node.data.trim() || node.nodeType === 8); + } + + /** + * Check if an element is a template tag. + * Note if the template appears inside an SVG its tagName + * will be in lowercase. + * + * @param {Element} el + */ + + function isTemplate(el) { + return el.tagName && el.tagName.toLowerCase() === 'template'; + } + + /** + * Create an "anchor" for performing dom insertion/removals. + * This is used in a number of scenarios: + * - fragment instance + * - v-html + * - v-if + * - v-for + * - component + * + * @param {String} content + * @param {Boolean} persist - IE trashes empty textNodes on + * cloneNode(true), so in certain + * cases the anchor needs to be + * non-empty to be persisted in + * templates. + * @return {Comment|Text} + */ + + function createAnchor(content, persist) { + var anchor = config.debug ? document.createComment(content) : document.createTextNode(persist ? ' ' : ''); + anchor.__v_anchor = true; + return anchor; + } + + /** + * Find a component ref attribute that starts with $. + * + * @param {Element} node + * @return {String|undefined} + */ + + var refRE = /^v-ref:/; + + function findRef(node) { + if (node.hasAttributes()) { + var attrs = node.attributes; + for (var i = 0, l = attrs.length; i < l; i++) { + var name = attrs[i].name; + if (refRE.test(name)) { + return camelize(name.replace(refRE, '')); + } + } + } + } + + /** + * Map a function to a range of nodes . + * + * @param {Node} node + * @param {Node} end + * @param {Function} op + */ + + function mapNodeRange(node, end, op) { + var next; + while (node !== end) { + next = node.nextSibling; + op(node); + node = next; + } + op(end); + } + + /** + * Remove a range of nodes with transition, store + * the nodes in a fragment with correct ordering, + * and call callback when done. + * + * @param {Node} start + * @param {Node} end + * @param {Vue} vm + * @param {DocumentFragment} frag + * @param {Function} cb + */ + + function removeNodeRange(start, end, vm, frag, cb) { + var done = false; + var removed = 0; + var nodes = []; + mapNodeRange(start, end, function (node) { + if (node === end) done = true; + nodes.push(node); + removeWithTransition(node, vm, onRemoved); + }); + function onRemoved() { + removed++; + if (done && removed >= nodes.length) { + for (var i = 0; i < nodes.length; i++) { + frag.appendChild(nodes[i]); + } + cb && cb(); + } + } + } + + /** + * Check if a node is a DocumentFragment. + * + * @param {Node} node + * @return {Boolean} + */ + + function isFragment(node) { + return node && node.nodeType === 11; + } + + /** + * Get outerHTML of elements, taking care + * of SVG elements in IE as well. + * + * @param {Element} el + * @return {String} + */ + + function getOuterHTML(el) { + if (el.outerHTML) { + return el.outerHTML; + } else { + var container = document.createElement('div'); + container.appendChild(el.cloneNode(true)); + return container.innerHTML; + } + } + + var commonTagRE = /^(div|p|span|img|a|b|i|br|ul|ol|li|h1|h2|h3|h4|h5|h6|code|pre|table|th|td|tr|form|label|input|select|option|nav|article|section|header|footer)$/i; + var reservedTagRE = /^(slot|partial|component)$/i; + + var isUnknownElement = undefined; + if ('development' !== 'production') { + isUnknownElement = function (el, tag) { + if (tag.indexOf('-') > -1) { + // http://stackoverflow.com/a/28210364/1070244 + return el.constructor === window.HTMLUnknownElement || el.constructor === window.HTMLElement; + } else { + return (/HTMLUnknownElement/.test(el.toString()) && + // Chrome returns unknown for several HTML5 elements. + // https://code.google.com/p/chromium/issues/detail?id=540526 + // Firefox returns unknown for some "Interactive elements." + !/^(data|time|rtc|rb|details|dialog|summary)$/.test(tag) + ); + } + }; + } + + /** + * Check if an element is a component, if yes return its + * component id. + * + * @param {Element} el + * @param {Object} options + * @return {Object|undefined} + */ + + function checkComponentAttr(el, options) { + var tag = el.tagName.toLowerCase(); + var hasAttrs = el.hasAttributes(); + if (!commonTagRE.test(tag) && !reservedTagRE.test(tag)) { + if (resolveAsset(options, 'components', tag)) { + return { id: tag }; + } else { + var is = hasAttrs && getIsBinding(el, options); + if (is) { + return is; + } else if ('development' !== 'production') { + var expectedTag = options._componentNameMap && options._componentNameMap[tag]; + if (expectedTag) { + warn('Unknown custom element: <' + tag + '> - ' + 'did you mean <' + expectedTag + '>? ' + 'HTML is case-insensitive, remember to use kebab-case in templates.'); + } else if (isUnknownElement(el, tag)) { + warn('Unknown custom element: <' + tag + '> - did you ' + 'register the component correctly? For recursive components, ' + 'make sure to provide the "name" option.'); + } + } + } + } else if (hasAttrs) { + return getIsBinding(el, options); + } + } + + /** + * Get "is" binding from an element. + * + * @param {Element} el + * @param {Object} options + * @return {Object|undefined} + */ + + function getIsBinding(el, options) { + // dynamic syntax + var exp = el.getAttribute('is'); + if (exp != null) { + if (resolveAsset(options, 'components', exp)) { + el.removeAttribute('is'); + return { id: exp }; + } + } else { + exp = getBindAttr(el, 'is'); + if (exp != null) { + return { id: exp, dynamic: true }; + } + } + } + + /** + * Option overwriting strategies are functions that handle + * how to merge a parent option value and a child option + * value into the final value. + * + * All strategy functions follow the same signature: + * + * @param {*} parentVal + * @param {*} childVal + * @param {Vue} [vm] + */ + + var strats = config.optionMergeStrategies = Object.create(null); + + /** + * Helper that recursively merges two data objects together. + */ + + function mergeData(to, from) { + var key, toVal, fromVal; + for (key in from) { + toVal = to[key]; + fromVal = from[key]; + if (!hasOwn(to, key)) { + set(to, key, fromVal); + } else if (isObject(toVal) && isObject(fromVal)) { + mergeData(toVal, fromVal); + } + } + return to; + } + + /** + * Data + */ + + strats.data = function (parentVal, childVal, vm) { + if (!vm) { + // in a Vue.extend merge, both should be functions + if (!childVal) { + return parentVal; + } + if (typeof childVal !== 'function') { + 'development' !== 'production' && warn('The "data" option should be a function ' + 'that returns a per-instance value in component ' + 'definitions.', vm); + return parentVal; + } + if (!parentVal) { + return childVal; + } + // when parentVal & childVal are both present, + // we need to return a function that returns the + // merged result of both functions... no need to + // check if parentVal is a function here because + // it has to be a function to pass previous merges. + return function mergedDataFn() { + return mergeData(childVal.call(this), parentVal.call(this)); + }; + } else if (parentVal || childVal) { + return function mergedInstanceDataFn() { + // instance merge + var instanceData = typeof childVal === 'function' ? childVal.call(vm) : childVal; + var defaultData = typeof parentVal === 'function' ? parentVal.call(vm) : undefined; + if (instanceData) { + return mergeData(instanceData, defaultData); + } else { + return defaultData; + } + }; + } + }; + + /** + * El + */ + + strats.el = function (parentVal, childVal, vm) { + if (!vm && childVal && typeof childVal !== 'function') { + 'development' !== 'production' && warn('The "el" option should be a function ' + 'that returns a per-instance value in component ' + 'definitions.', vm); + return; + } + var ret = childVal || parentVal; + // invoke the element factory if this is instance merge + return vm && typeof ret === 'function' ? ret.call(vm) : ret; + }; + + /** + * Hooks and param attributes are merged as arrays. + */ + + strats.init = strats.created = strats.ready = strats.attached = strats.detached = strats.beforeCompile = strats.compiled = strats.beforeDestroy = strats.destroyed = strats.activate = function (parentVal, childVal) { + return childVal ? parentVal ? parentVal.concat(childVal) : isArray(childVal) ? childVal : [childVal] : parentVal; + }; + + /** + * Assets + * + * When a vm is present (instance creation), we need to do + * a three-way merge between constructor options, instance + * options and parent options. + */ + + function mergeAssets(parentVal, childVal) { + var res = Object.create(parentVal || null); + return childVal ? extend(res, guardArrayAssets(childVal)) : res; + } + + config._assetTypes.forEach(function (type) { + strats[type + 's'] = mergeAssets; + }); + + /** + * Events & Watchers. + * + * Events & watchers hashes should not overwrite one + * another, so we merge them as arrays. + */ + + strats.watch = strats.events = function (parentVal, childVal) { + if (!childVal) return parentVal; + if (!parentVal) return childVal; + var ret = {}; + extend(ret, parentVal); + for (var key in childVal) { + var parent = ret[key]; + var child = childVal[key]; + if (parent && !isArray(parent)) { + parent = [parent]; + } + ret[key] = parent ? parent.concat(child) : [child]; + } + return ret; + }; + + /** + * Other object hashes. + */ + + strats.props = strats.methods = strats.computed = function (parentVal, childVal) { + if (!childVal) return parentVal; + if (!parentVal) return childVal; + var ret = Object.create(null); + extend(ret, parentVal); + extend(ret, childVal); + return ret; + }; + + /** + * Default strategy. + */ + + var defaultStrat = function defaultStrat(parentVal, childVal) { + return childVal === undefined ? parentVal : childVal; + }; + + /** + * Make sure component options get converted to actual + * constructors. + * + * @param {Object} options + */ + + function guardComponents(options) { + if (options.components) { + var components = options.components = guardArrayAssets(options.components); + var ids = Object.keys(components); + var def; + if ('development' !== 'production') { + var map = options._componentNameMap = {}; + } + for (var i = 0, l = ids.length; i < l; i++) { + var key = ids[i]; + if (commonTagRE.test(key) || reservedTagRE.test(key)) { + 'development' !== 'production' && warn('Do not use built-in or reserved HTML elements as component ' + 'id: ' + key); + continue; + } + // record a all lowercase <-> kebab-case mapping for + // possible custom element case error warning + if ('development' !== 'production') { + map[key.replace(/-/g, '').toLowerCase()] = hyphenate(key); + } + def = components[key]; + if (isPlainObject(def)) { + components[key] = Vue.extend(def); + } + } + } + } + + /** + * Ensure all props option syntax are normalized into the + * Object-based format. + * + * @param {Object} options + */ + + function guardProps(options) { + var props = options.props; + var i, val; + if (isArray(props)) { + options.props = {}; + i = props.length; + while (i--) { + val = props[i]; + if (typeof val === 'string') { + options.props[val] = null; + } else if (val.name) { + options.props[val.name] = val; + } + } + } else if (isPlainObject(props)) { + var keys = Object.keys(props); + i = keys.length; + while (i--) { + val = props[keys[i]]; + if (typeof val === 'function') { + props[keys[i]] = { type: val }; + } + } + } + } + + /** + * Guard an Array-format assets option and converted it + * into the key-value Object format. + * + * @param {Object|Array} assets + * @return {Object} + */ + + function guardArrayAssets(assets) { + if (isArray(assets)) { + var res = {}; + var i = assets.length; + var asset; + while (i--) { + asset = assets[i]; + var id = typeof asset === 'function' ? asset.options && asset.options.name || asset.id : asset.name || asset.id; + if (!id) { + 'development' !== 'production' && warn('Array-syntax assets must provide a "name" or "id" field.'); + } else { + res[id] = asset; + } + } + return res; + } + return assets; + } + + /** + * Merge two option objects into a new one. + * Core utility used in both instantiation and inheritance. + * + * @param {Object} parent + * @param {Object} child + * @param {Vue} [vm] - if vm is present, indicates this is + * an instantiation merge. + */ + + function mergeOptions(parent, child, vm) { + guardComponents(child); + guardProps(child); + if ('development' !== 'production') { + if (child.propsData && !vm) { + warn('propsData can only be used as an instantiation option.'); + } + } + var options = {}; + var key; + if (child['extends']) { + parent = typeof child['extends'] === 'function' ? mergeOptions(parent, child['extends'].options, vm) : mergeOptions(parent, child['extends'], vm); + } + if (child.mixins) { + for (var i = 0, l = child.mixins.length; i < l; i++) { + var mixin = child.mixins[i]; + var mixinOptions = mixin.prototype instanceof Vue ? mixin.options : mixin; + parent = mergeOptions(parent, mixinOptions, vm); + } + } + for (key in parent) { + mergeField(key); + } + for (key in child) { + if (!hasOwn(parent, key)) { + mergeField(key); + } + } + function mergeField(key) { + var strat = strats[key] || defaultStrat; + options[key] = strat(parent[key], child[key], vm, key); + } + return options; + } + + /** + * Resolve an asset. + * This function is used because child instances need access + * to assets defined in its ancestor chain. + * + * @param {Object} options + * @param {String} type + * @param {String} id + * @param {Boolean} warnMissing + * @return {Object|Function} + */ + + function resolveAsset(options, type, id, warnMissing) { + /* istanbul ignore if */ + if (typeof id !== 'string') { + return; + } + var assets = options[type]; + var camelizedId; + var res = assets[id] || + // camelCase ID + assets[camelizedId = camelize(id)] || + // Pascal Case ID + assets[camelizedId.charAt(0).toUpperCase() + camelizedId.slice(1)]; + if ('development' !== 'production' && warnMissing && !res) { + warn('Failed to resolve ' + type.slice(0, -1) + ': ' + id, options); + } + return res; + } + + var uid$1 = 0; + + /** + * A dep is an observable that can have multiple + * directives subscribing to it. + * + * @constructor + */ + function Dep() { + this.id = uid$1++; + this.subs = []; + } + + // the current target watcher being evaluated. + // this is globally unique because there could be only one + // watcher being evaluated at any time. + Dep.target = null; + + /** + * Add a directive subscriber. + * + * @param {Directive} sub + */ + + Dep.prototype.addSub = function (sub) { + this.subs.push(sub); + }; + + /** + * Remove a directive subscriber. + * + * @param {Directive} sub + */ + + Dep.prototype.removeSub = function (sub) { + this.subs.$remove(sub); + }; + + /** + * Add self as a dependency to the target watcher. + */ + + Dep.prototype.depend = function () { + Dep.target.addDep(this); + }; + + /** + * Notify all subscribers of a new value. + */ + + Dep.prototype.notify = function () { + // stablize the subscriber list first + var subs = toArray(this.subs); + for (var i = 0, l = subs.length; i < l; i++) { + subs[i].update(); + } + }; + + var arrayProto = Array.prototype; + var arrayMethods = Object.create(arrayProto) + + /** + * Intercept mutating methods and emit events + */ + + ;['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse'].forEach(function (method) { + // cache original method + var original = arrayProto[method]; + def(arrayMethods, method, function mutator() { + // avoid leaking arguments: + // http://jsperf.com/closure-with-arguments + var i = arguments.length; + var args = new Array(i); + while (i--) { + args[i] = arguments[i]; + } + var result = original.apply(this, args); + var ob = this.__ob__; + var inserted; + switch (method) { + case 'push': + inserted = args; + break; + case 'unshift': + inserted = args; + break; + case 'splice': + inserted = args.slice(2); + break; + } + if (inserted) ob.observeArray(inserted); + // notify change + ob.dep.notify(); + return result; + }); + }); + + /** + * Swap the element at the given index with a new value + * and emits corresponding event. + * + * @param {Number} index + * @param {*} val + * @return {*} - replaced element + */ + + def(arrayProto, '$set', function $set(index, val) { + if (index >= this.length) { + this.length = Number(index) + 1; + } + return this.splice(index, 1, val)[0]; + }); + + /** + * Convenience method to remove the element at given index or target element reference. + * + * @param {*} item + */ + + def(arrayProto, '$remove', function $remove(item) { + /* istanbul ignore if */ + if (!this.length) return; + var index = indexOf(this, item); + if (index > -1) { + return this.splice(index, 1); + } + }); + + var arrayKeys = Object.getOwnPropertyNames(arrayMethods); + + /** + * By default, when a reactive property is set, the new value is + * also converted to become reactive. However in certain cases, e.g. + * v-for scope alias and props, we don't want to force conversion + * because the value may be a nested value under a frozen data structure. + * + * So whenever we want to set a reactive property without forcing + * conversion on the new value, we wrap that call inside this function. + */ + + var shouldConvert = true; + + function withoutConversion(fn) { + shouldConvert = false; + fn(); + shouldConvert = true; + } + + /** + * Observer class that are attached to each observed + * object. Once attached, the observer converts target + * object's property keys into getter/setters that + * collect dependencies and dispatches updates. + * + * @param {Array|Object} value + * @constructor + */ + + function Observer(value) { + this.value = value; + this.dep = new Dep(); + def(value, '__ob__', this); + if (isArray(value)) { + var augment = hasProto ? protoAugment : copyAugment; + augment(value, arrayMethods, arrayKeys); + this.observeArray(value); + } else { + this.walk(value); + } + } + + // Instance methods + + /** + * Walk through each property and convert them into + * getter/setters. This method should only be called when + * value type is Object. + * + * @param {Object} obj + */ + + Observer.prototype.walk = function (obj) { + var keys = Object.keys(obj); + for (var i = 0, l = keys.length; i < l; i++) { + this.convert(keys[i], obj[keys[i]]); + } + }; + + /** + * Observe a list of Array items. + * + * @param {Array} items + */ + + Observer.prototype.observeArray = function (items) { + for (var i = 0, l = items.length; i < l; i++) { + observe(items[i]); + } + }; + + /** + * Convert a property into getter/setter so we can emit + * the events when the property is accessed/changed. + * + * @param {String} key + * @param {*} val + */ + + Observer.prototype.convert = function (key, val) { + defineReactive(this.value, key, val); + }; + + /** + * Add an owner vm, so that when $set/$delete mutations + * happen we can notify owner vms to proxy the keys and + * digest the watchers. This is only called when the object + * is observed as an instance's root $data. + * + * @param {Vue} vm + */ + + Observer.prototype.addVm = function (vm) { + (this.vms || (this.vms = [])).push(vm); + }; + + /** + * Remove an owner vm. This is called when the object is + * swapped out as an instance's $data object. + * + * @param {Vue} vm + */ + + Observer.prototype.removeVm = function (vm) { + this.vms.$remove(vm); + }; + + // helpers + + /** + * Augment an target Object or Array by intercepting + * the prototype chain using __proto__ + * + * @param {Object|Array} target + * @param {Object} src + */ + + function protoAugment(target, src) { + /* eslint-disable no-proto */ + target.__proto__ = src; + /* eslint-enable no-proto */ + } + + /** + * Augment an target Object or Array by defining + * hidden properties. + * + * @param {Object|Array} target + * @param {Object} proto + */ + + function copyAugment(target, src, keys) { + for (var i = 0, l = keys.length; i < l; i++) { + var key = keys[i]; + def(target, key, src[key]); + } + } + + /** + * Attempt to create an observer instance for a value, + * returns the new observer if successfully observed, + * or the existing observer if the value already has one. + * + * @param {*} value + * @param {Vue} [vm] + * @return {Observer|undefined} + * @static + */ + + function observe(value, vm) { + if (!value || typeof value !== 'object') { + return; + } + var ob; + if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) { + ob = value.__ob__; + } else if (shouldConvert && (isArray(value) || isPlainObject(value)) && Object.isExtensible(value) && !value._isVue) { + ob = new Observer(value); + } + if (ob && vm) { + ob.addVm(vm); + } + return ob; + } + + /** + * Define a reactive property on an Object. + * + * @param {Object} obj + * @param {String} key + * @param {*} val + */ + + function defineReactive(obj, key, val) { + var dep = new Dep(); + + var property = Object.getOwnPropertyDescriptor(obj, key); + if (property && property.configurable === false) { + return; + } + + // cater for pre-defined getter/setters + var getter = property && property.get; + var setter = property && property.set; + + var childOb = observe(val); + Object.defineProperty(obj, key, { + enumerable: true, + configurable: true, + get: function reactiveGetter() { + var value = getter ? getter.call(obj) : val; + if (Dep.target) { + dep.depend(); + if (childOb) { + childOb.dep.depend(); + } + if (isArray(value)) { + for (var e, i = 0, l = value.length; i < l; i++) { + e = value[i]; + e && e.__ob__ && e.__ob__.dep.depend(); + } + } + } + return value; + }, + set: function reactiveSetter(newVal) { + var value = getter ? getter.call(obj) : val; + if (newVal === value) { + return; + } + if (setter) { + setter.call(obj, newVal); + } else { + val = newVal; + } + childOb = observe(newVal); + dep.notify(); + } + }); + } + + + + var util = Object.freeze({ + defineReactive: defineReactive, + set: set, + del: del, + hasOwn: hasOwn, + isLiteral: isLiteral, + isReserved: isReserved, + _toString: _toString, + toNumber: toNumber, + toBoolean: toBoolean, + stripQuotes: stripQuotes, + camelize: camelize, + hyphenate: hyphenate, + classify: classify, + bind: bind, + toArray: toArray, + extend: extend, + isObject: isObject, + isPlainObject: isPlainObject, + def: def, + debounce: _debounce, + indexOf: indexOf, + cancellable: cancellable, + looseEqual: looseEqual, + isArray: isArray, + hasProto: hasProto, + inBrowser: inBrowser, + devtools: devtools, + isIE: isIE, + isIE9: isIE9, + isAndroid: isAndroid, + isIos: isIos, + iosVersionMatch: iosVersionMatch, + iosVersion: iosVersion, + hasMutationObserverBug: hasMutationObserverBug, + get transitionProp () { return transitionProp; }, + get transitionEndEvent () { return transitionEndEvent; }, + get animationProp () { return animationProp; }, + get animationEndEvent () { return animationEndEvent; }, + nextTick: nextTick, + get _Set () { return _Set; }, + query: query, + inDoc: inDoc, + getAttr: getAttr, + getBindAttr: getBindAttr, + hasBindAttr: hasBindAttr, + before: before, + after: after, + remove: remove, + prepend: prepend, + replace: replace, + on: on, + off: off, + setClass: setClass, + addClass: addClass, + removeClass: removeClass, + extractContent: extractContent, + trimNode: trimNode, + isTemplate: isTemplate, + createAnchor: createAnchor, + findRef: findRef, + mapNodeRange: mapNodeRange, + removeNodeRange: removeNodeRange, + isFragment: isFragment, + getOuterHTML: getOuterHTML, + mergeOptions: mergeOptions, + resolveAsset: resolveAsset, + checkComponentAttr: checkComponentAttr, + commonTagRE: commonTagRE, + reservedTagRE: reservedTagRE, + get warn () { return warn; } + }); + + var uid = 0; + + function initMixin (Vue) { + /** + * The main init sequence. This is called for every + * instance, including ones that are created from extended + * constructors. + * + * @param {Object} options - this options object should be + * the result of merging class + * options and the options passed + * in to the constructor. + */ + + Vue.prototype._init = function (options) { + options = options || {}; + + this.$el = null; + this.$parent = options.parent; + this.$root = this.$parent ? this.$parent.$root : this; + this.$children = []; + this.$refs = {}; // child vm references + this.$els = {}; // element references + this._watchers = []; // all watchers as an array + this._directives = []; // all directives + + // a uid + this._uid = uid++; + + // a flag to avoid this being observed + this._isVue = true; + + // events bookkeeping + this._events = {}; // registered callbacks + this._eventsCount = {}; // for $broadcast optimization + + // fragment instance properties + this._isFragment = false; + this._fragment = // @type {DocumentFragment} + this._fragmentStart = // @type {Text|Comment} + this._fragmentEnd = null; // @type {Text|Comment} + + // lifecycle state + this._isCompiled = this._isDestroyed = this._isReady = this._isAttached = this._isBeingDestroyed = this._vForRemoving = false; + this._unlinkFn = null; + + // context: + // if this is a transcluded component, context + // will be the common parent vm of this instance + // and its host. + this._context = options._context || this.$parent; + + // scope: + // if this is inside an inline v-for, the scope + // will be the intermediate scope created for this + // repeat fragment. this is used for linking props + // and container directives. + this._scope = options._scope; + + // fragment: + // if this instance is compiled inside a Fragment, it + // needs to reigster itself as a child of that fragment + // for attach/detach to work properly. + this._frag = options._frag; + if (this._frag) { + this._frag.children.push(this); + } + + // push self into parent / transclusion host + if (this.$parent) { + this.$parent.$children.push(this); + } + + // merge options. + options = this.$options = mergeOptions(this.constructor.options, options, this); + + // set ref + this._updateRef(); + + // initialize data as empty object. + // it will be filled up in _initData(). + this._data = {}; + + // call init hook + this._callHook('init'); + + // initialize data observation and scope inheritance. + this._initState(); + + // setup event system and option events. + this._initEvents(); + + // call created hook + this._callHook('created'); + + // if `el` option is passed, start compilation. + if (options.el) { + this.$mount(options.el); + } + }; + } + + var pathCache = new Cache(1000); + + // actions + var APPEND = 0; + var PUSH = 1; + var INC_SUB_PATH_DEPTH = 2; + var PUSH_SUB_PATH = 3; + + // states + var BEFORE_PATH = 0; + var IN_PATH = 1; + var BEFORE_IDENT = 2; + var IN_IDENT = 3; + var IN_SUB_PATH = 4; + var IN_SINGLE_QUOTE = 5; + var IN_DOUBLE_QUOTE = 6; + var AFTER_PATH = 7; + var ERROR = 8; + + var pathStateMachine = []; + + pathStateMachine[BEFORE_PATH] = { + 'ws': [BEFORE_PATH], + 'ident': [IN_IDENT, APPEND], + '[': [IN_SUB_PATH], + 'eof': [AFTER_PATH] + }; + + pathStateMachine[IN_PATH] = { + 'ws': [IN_PATH], + '.': [BEFORE_IDENT], + '[': [IN_SUB_PATH], + 'eof': [AFTER_PATH] + }; + + pathStateMachine[BEFORE_IDENT] = { + 'ws': [BEFORE_IDENT], + 'ident': [IN_IDENT, APPEND] + }; + + pathStateMachine[IN_IDENT] = { + 'ident': [IN_IDENT, APPEND], + '0': [IN_IDENT, APPEND], + 'number': [IN_IDENT, APPEND], + 'ws': [IN_PATH, PUSH], + '.': [BEFORE_IDENT, PUSH], + '[': [IN_SUB_PATH, PUSH], + 'eof': [AFTER_PATH, PUSH] + }; + + pathStateMachine[IN_SUB_PATH] = { + "'": [IN_SINGLE_QUOTE, APPEND], + '"': [IN_DOUBLE_QUOTE, APPEND], + '[': [IN_SUB_PATH, INC_SUB_PATH_DEPTH], + ']': [IN_PATH, PUSH_SUB_PATH], + 'eof': ERROR, + 'else': [IN_SUB_PATH, APPEND] + }; + + pathStateMachine[IN_SINGLE_QUOTE] = { + "'": [IN_SUB_PATH, APPEND], + 'eof': ERROR, + 'else': [IN_SINGLE_QUOTE, APPEND] + }; + + pathStateMachine[IN_DOUBLE_QUOTE] = { + '"': [IN_SUB_PATH, APPEND], + 'eof': ERROR, + 'else': [IN_DOUBLE_QUOTE, APPEND] + }; + + /** + * Determine the type of a character in a keypath. + * + * @param {Char} ch + * @return {String} type + */ + + function getPathCharType(ch) { + if (ch === undefined) { + return 'eof'; + } + + var code = ch.charCodeAt(0); + + switch (code) { + case 0x5B: // [ + case 0x5D: // ] + case 0x2E: // . + case 0x22: // " + case 0x27: // ' + case 0x30: + // 0 + return ch; + + case 0x5F: // _ + case 0x24: + // $ + return 'ident'; + + case 0x20: // Space + case 0x09: // Tab + case 0x0A: // Newline + case 0x0D: // Return + case 0xA0: // No-break space + case 0xFEFF: // Byte Order Mark + case 0x2028: // Line Separator + case 0x2029: + // Paragraph Separator + return 'ws'; + } + + // a-z, A-Z + if (code >= 0x61 && code <= 0x7A || code >= 0x41 && code <= 0x5A) { + return 'ident'; + } + + // 1-9 + if (code >= 0x31 && code <= 0x39) { + return 'number'; + } + + return 'else'; + } + + /** + * Format a subPath, return its plain form if it is + * a literal string or number. Otherwise prepend the + * dynamic indicator (*). + * + * @param {String} path + * @return {String} + */ + + function formatSubPath(path) { + var trimmed = path.trim(); + // invalid leading 0 + if (path.charAt(0) === '0' && isNaN(path)) { + return false; + } + return isLiteral(trimmed) ? stripQuotes(trimmed) : '*' + trimmed; + } + + /** + * Parse a string path into an array of segments + * + * @param {String} path + * @return {Array|undefined} + */ + + function parse(path) { + var keys = []; + var index = -1; + var mode = BEFORE_PATH; + var subPathDepth = 0; + var c, newChar, key, type, transition, action, typeMap; + + var actions = []; + + actions[PUSH] = function () { + if (key !== undefined) { + keys.push(key); + key = undefined; + } + }; + + actions[APPEND] = function () { + if (key === undefined) { + key = newChar; + } else { + key += newChar; + } + }; + + actions[INC_SUB_PATH_DEPTH] = function () { + actions[APPEND](); + subPathDepth++; + }; + + actions[PUSH_SUB_PATH] = function () { + if (subPathDepth > 0) { + subPathDepth--; + mode = IN_SUB_PATH; + actions[APPEND](); + } else { + subPathDepth = 0; + key = formatSubPath(key); + if (key === false) { + return false; + } else { + actions[PUSH](); + } + } + }; + + function maybeUnescapeQuote() { + var nextChar = path[index + 1]; + if (mode === IN_SINGLE_QUOTE && nextChar === "'" || mode === IN_DOUBLE_QUOTE && nextChar === '"') { + index++; + newChar = '\\' + nextChar; + actions[APPEND](); + return true; + } + } + + while (mode != null) { + index++; + c = path[index]; + + if (c === '\\' && maybeUnescapeQuote()) { + continue; + } + + type = getPathCharType(c); + typeMap = pathStateMachine[mode]; + transition = typeMap[type] || typeMap['else'] || ERROR; + + if (transition === ERROR) { + return; // parse error + } + + mode = transition[0]; + action = actions[transition[1]]; + if (action) { + newChar = transition[2]; + newChar = newChar === undefined ? c : newChar; + if (action() === false) { + return; + } + } + + if (mode === AFTER_PATH) { + keys.raw = path; + return keys; + } + } + } + + /** + * External parse that check for a cache hit first + * + * @param {String} path + * @return {Array|undefined} + */ + + function parsePath(path) { + var hit = pathCache.get(path); + if (!hit) { + hit = parse(path); + if (hit) { + pathCache.put(path, hit); + } + } + return hit; + } + + /** + * Get from an object from a path string + * + * @param {Object} obj + * @param {String} path + */ + + function getPath(obj, path) { + return parseExpression(path).get(obj); + } + + /** + * Warn against setting non-existent root path on a vm. + */ + + var warnNonExistent; + if ('development' !== 'production') { + warnNonExistent = function (path, vm) { + warn('You are setting a non-existent path "' + path.raw + '" ' + 'on a vm instance. Consider pre-initializing the property ' + 'with the "data" option for more reliable reactivity ' + 'and better performance.', vm); + }; + } + + /** + * Set on an object from a path + * + * @param {Object} obj + * @param {String | Array} path + * @param {*} val + */ + + function setPath(obj, path, val) { + var original = obj; + if (typeof path === 'string') { + path = parse(path); + } + if (!path || !isObject(obj)) { + return false; + } + var last, key; + for (var i = 0, l = path.length; i < l; i++) { + last = obj; + key = path[i]; + if (key.charAt(0) === '*') { + key = parseExpression(key.slice(1)).get.call(original, original); + } + if (i < l - 1) { + obj = obj[key]; + if (!isObject(obj)) { + obj = {}; + if ('development' !== 'production' && last._isVue) { + warnNonExistent(path, last); + } + set(last, key, obj); + } + } else { + if (isArray(obj)) { + obj.$set(key, val); + } else if (key in obj) { + obj[key] = val; + } else { + if ('development' !== 'production' && obj._isVue) { + warnNonExistent(path, obj); + } + set(obj, key, val); + } + } + } + return true; + } + +var path = Object.freeze({ + parsePath: parsePath, + getPath: getPath, + setPath: setPath + }); + + var expressionCache = new Cache(1000); + + var allowedKeywords = 'Math,Date,this,true,false,null,undefined,Infinity,NaN,' + 'isNaN,isFinite,decodeURI,decodeURIComponent,encodeURI,' + 'encodeURIComponent,parseInt,parseFloat'; + var allowedKeywordsRE = new RegExp('^(' + allowedKeywords.replace(/,/g, '\\b|') + '\\b)'); + + // keywords that don't make sense inside expressions + var improperKeywords = 'break,case,class,catch,const,continue,debugger,default,' + 'delete,do,else,export,extends,finally,for,function,if,' + 'import,in,instanceof,let,return,super,switch,throw,try,' + 'var,while,with,yield,enum,await,implements,package,' + 'protected,static,interface,private,public'; + var improperKeywordsRE = new RegExp('^(' + improperKeywords.replace(/,/g, '\\b|') + '\\b)'); + + var wsRE = /\s/g; + var newlineRE = /\n/g; + var saveRE = /[\{,]\s*[\w\$_]+\s*:|('(?:[^'\\]|\\.)*'|"(?:[^"\\]|\\.)*"|`(?:[^`\\]|\\.)*\$\{|\}(?:[^`\\]|\\.)*`|`(?:[^`\\]|\\.)*`)|new |typeof |void /g; + var restoreRE = /"(\d+)"/g; + var pathTestRE = /^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*|\['.*?'\]|\[".*?"\]|\[\d+\]|\[[A-Za-z_$][\w$]*\])*$/; + var identRE = /[^\w$\.](?:[A-Za-z_$][\w$]*)/g; + var literalValueRE$1 = /^(?:true|false|null|undefined|Infinity|NaN)$/; + + function noop() {} + + /** + * Save / Rewrite / Restore + * + * When rewriting paths found in an expression, it is + * possible for the same letter sequences to be found in + * strings and Object literal property keys. Therefore we + * remove and store these parts in a temporary array, and + * restore them after the path rewrite. + */ + + var saved = []; + + /** + * Save replacer + * + * The save regex can match two possible cases: + * 1. An opening object literal + * 2. A string + * If matched as a plain string, we need to escape its + * newlines, since the string needs to be preserved when + * generating the function body. + * + * @param {String} str + * @param {String} isString - str if matched as a string + * @return {String} - placeholder with index + */ + + function save(str, isString) { + var i = saved.length; + saved[i] = isString ? str.replace(newlineRE, '\\n') : str; + return '"' + i + '"'; + } + + /** + * Path rewrite replacer + * + * @param {String} raw + * @return {String} + */ + + function rewrite(raw) { + var c = raw.charAt(0); + var path = raw.slice(1); + if (allowedKeywordsRE.test(path)) { + return raw; + } else { + path = path.indexOf('"') > -1 ? path.replace(restoreRE, restore) : path; + return c + 'scope.' + path; + } + } + + /** + * Restore replacer + * + * @param {String} str + * @param {String} i - matched save index + * @return {String} + */ + + function restore(str, i) { + return saved[i]; + } + + /** + * Rewrite an expression, prefixing all path accessors with + * `scope.` and generate getter/setter functions. + * + * @param {String} exp + * @return {Function} + */ + + function compileGetter(exp) { + if (improperKeywordsRE.test(exp)) { + 'development' !== 'production' && warn('Avoid using reserved keywords in expression: ' + exp); + } + // reset state + saved.length = 0; + // save strings and object literal keys + var body = exp.replace(saveRE, save).replace(wsRE, ''); + // rewrite all paths + // pad 1 space here because the regex matches 1 extra char + body = (' ' + body).replace(identRE, rewrite).replace(restoreRE, restore); + return makeGetterFn(body); + } + + /** + * Build a getter function. Requires eval. + * + * We isolate the try/catch so it doesn't affect the + * optimization of the parse function when it is not called. + * + * @param {String} body + * @return {Function|undefined} + */ + + function makeGetterFn(body) { + try { + /* eslint-disable no-new-func */ + return new Function('scope', 'return ' + body + ';'); + /* eslint-enable no-new-func */ + } catch (e) { + if ('development' !== 'production') { + /* istanbul ignore if */ + if (e.toString().match(/unsafe-eval|CSP/)) { + warn('It seems you are using the default build of Vue.js in an environment ' + 'with Content Security Policy that prohibits unsafe-eval. ' + 'Use the CSP-compliant build instead: ' + 'http://vuejs.org/guide/installation.html#CSP-compliant-build'); + } else { + warn('Invalid expression. ' + 'Generated function body: ' + body); + } + } + return noop; + } + } + + /** + * Compile a setter function for the expression. + * + * @param {String} exp + * @return {Function|undefined} + */ + + function compileSetter(exp) { + var path = parsePath(exp); + if (path) { + return function (scope, val) { + setPath(scope, path, val); + }; + } else { + 'development' !== 'production' && warn('Invalid setter expression: ' + exp); + } + } + + /** + * Parse an expression into re-written getter/setters. + * + * @param {String} exp + * @param {Boolean} needSet + * @return {Function} + */ + + function parseExpression(exp, needSet) { + exp = exp.trim(); + // try cache + var hit = expressionCache.get(exp); + if (hit) { + if (needSet && !hit.set) { + hit.set = compileSetter(hit.exp); + } + return hit; + } + var res = { exp: exp }; + res.get = isSimplePath(exp) && exp.indexOf('[') < 0 + // optimized super simple getter + ? makeGetterFn('scope.' + exp) + // dynamic getter + : compileGetter(exp); + if (needSet) { + res.set = compileSetter(exp); + } + expressionCache.put(exp, res); + return res; + } + + /** + * Check if an expression is a simple path. + * + * @param {String} exp + * @return {Boolean} + */ + + function isSimplePath(exp) { + return pathTestRE.test(exp) && + // don't treat literal values as paths + !literalValueRE$1.test(exp) && + // Math constants e.g. Math.PI, Math.E etc. + exp.slice(0, 5) !== 'Math.'; + } + +var expression = Object.freeze({ + parseExpression: parseExpression, + isSimplePath: isSimplePath + }); + + // we have two separate queues: one for directive updates + // and one for user watcher registered via $watch(). + // we want to guarantee directive updates to be called + // before user watchers so that when user watchers are + // triggered, the DOM would have already been in updated + // state. + + var queue = []; + var userQueue = []; + var has = {}; + var circular = {}; + var waiting = false; + + /** + * Reset the batcher's state. + */ + + function resetBatcherState() { + queue.length = 0; + userQueue.length = 0; + has = {}; + circular = {}; + waiting = false; + } + + /** + * Flush both queues and run the watchers. + */ + + function flushBatcherQueue() { + var _again = true; + + _function: while (_again) { + _again = false; + + runBatcherQueue(queue); + runBatcherQueue(userQueue); + // user watchers triggered more watchers, + // keep flushing until it depletes + if (queue.length) { + _again = true; + continue _function; + } + // dev tool hook + /* istanbul ignore if */ + if (devtools && config.devtools) { + devtools.emit('flush'); + } + resetBatcherState(); + } + } + + /** + * Run the watchers in a single queue. + * + * @param {Array} queue + */ + + function runBatcherQueue(queue) { + // do not cache length because more watchers might be pushed + // as we run existing watchers + for (var i = 0; i < queue.length; i++) { + var watcher = queue[i]; + var id = watcher.id; + has[id] = null; + watcher.run(); + // in dev build, check and stop circular updates. + if ('development' !== 'production' && has[id] != null) { + circular[id] = (circular[id] || 0) + 1; + if (circular[id] > config._maxUpdateCount) { + warn('You may have an infinite update loop for watcher ' + 'with expression "' + watcher.expression + '"', watcher.vm); + break; + } + } + } + queue.length = 0; + } + + /** + * Push a watcher into the watcher queue. + * Jobs with duplicate IDs will be skipped unless it's + * pushed when the queue is being flushed. + * + * @param {Watcher} watcher + * properties: + * - {Number} id + * - {Function} run + */ + + function pushWatcher(watcher) { + var id = watcher.id; + if (has[id] == null) { + // push watcher into appropriate queue + var q = watcher.user ? userQueue : queue; + has[id] = q.length; + q.push(watcher); + // queue the flush + if (!waiting) { + waiting = true; + nextTick(flushBatcherQueue); + } + } + } + + var uid$2 = 0; + + /** + * A watcher parses an expression, collects dependencies, + * and fires callback when the expression value changes. + * This is used for both the $watch() api and directives. + * + * @param {Vue} vm + * @param {String|Function} expOrFn + * @param {Function} cb + * @param {Object} options + * - {Array} filters + * - {Boolean} twoWay + * - {Boolean} deep + * - {Boolean} user + * - {Boolean} sync + * - {Boolean} lazy + * - {Function} [preProcess] + * - {Function} [postProcess] + * @constructor + */ + function Watcher(vm, expOrFn, cb, options) { + // mix in options + if (options) { + extend(this, options); + } + var isFn = typeof expOrFn === 'function'; + this.vm = vm; + vm._watchers.push(this); + this.expression = expOrFn; + this.cb = cb; + this.id = ++uid$2; // uid for batching + this.active = true; + this.dirty = this.lazy; // for lazy watchers + this.deps = []; + this.newDeps = []; + this.depIds = new _Set(); + this.newDepIds = new _Set(); + this.prevError = null; // for async error stacks + // parse expression for getter/setter + if (isFn) { + this.getter = expOrFn; + this.setter = undefined; + } else { + var res = parseExpression(expOrFn, this.twoWay); + this.getter = res.get; + this.setter = res.set; + } + this.value = this.lazy ? undefined : this.get(); + // state for avoiding false triggers for deep and Array + // watchers during vm._digest() + this.queued = this.shallow = false; + } + + /** + * Evaluate the getter, and re-collect dependencies. + */ + + Watcher.prototype.get = function () { + this.beforeGet(); + var scope = this.scope || this.vm; + var value; + try { + value = this.getter.call(scope, scope); + } catch (e) { + if ('development' !== 'production' && config.warnExpressionErrors) { + warn('Error when evaluating expression ' + '"' + this.expression + '": ' + e.toString(), this.vm); + } + } + // "touch" every property so they are all tracked as + // dependencies for deep watching + if (this.deep) { + traverse(value); + } + if (this.preProcess) { + value = this.preProcess(value); + } + if (this.filters) { + value = scope._applyFilters(value, null, this.filters, false); + } + if (this.postProcess) { + value = this.postProcess(value); + } + this.afterGet(); + return value; + }; + + /** + * Set the corresponding value with the setter. + * + * @param {*} value + */ + + Watcher.prototype.set = function (value) { + var scope = this.scope || this.vm; + if (this.filters) { + value = scope._applyFilters(value, this.value, this.filters, true); + } + try { + this.setter.call(scope, scope, value); + } catch (e) { + if ('development' !== 'production' && config.warnExpressionErrors) { + warn('Error when evaluating setter ' + '"' + this.expression + '": ' + e.toString(), this.vm); + } + } + // two-way sync for v-for alias + var forContext = scope.$forContext; + if (forContext && forContext.alias === this.expression) { + if (forContext.filters) { + 'development' !== 'production' && warn('It seems you are using two-way binding on ' + 'a v-for alias (' + this.expression + '), and the ' + 'v-for has filters. This will not work properly. ' + 'Either remove the filters or use an array of ' + 'objects and bind to object properties instead.', this.vm); + return; + } + forContext._withLock(function () { + if (scope.$key) { + // original is an object + forContext.rawValue[scope.$key] = value; + } else { + forContext.rawValue.$set(scope.$index, value); + } + }); + } + }; + + /** + * Prepare for dependency collection. + */ + + Watcher.prototype.beforeGet = function () { + Dep.target = this; + }; + + /** + * Add a dependency to this directive. + * + * @param {Dep} dep + */ + + Watcher.prototype.addDep = function (dep) { + var id = dep.id; + if (!this.newDepIds.has(id)) { + this.newDepIds.add(id); + this.newDeps.push(dep); + if (!this.depIds.has(id)) { + dep.addSub(this); + } + } + }; + + /** + * Clean up for dependency collection. + */ + + Watcher.prototype.afterGet = function () { + Dep.target = null; + var i = this.deps.length; + while (i--) { + var dep = this.deps[i]; + if (!this.newDepIds.has(dep.id)) { + dep.removeSub(this); + } + } + var tmp = this.depIds; + this.depIds = this.newDepIds; + this.newDepIds = tmp; + this.newDepIds.clear(); + tmp = this.deps; + this.deps = this.newDeps; + this.newDeps = tmp; + this.newDeps.length = 0; + }; + + /** + * Subscriber interface. + * Will be called when a dependency changes. + * + * @param {Boolean} shallow + */ + + Watcher.prototype.update = function (shallow) { + if (this.lazy) { + this.dirty = true; + } else if (this.sync || !config.async) { + this.run(); + } else { + // if queued, only overwrite shallow with non-shallow, + // but not the other way around. + this.shallow = this.queued ? shallow ? this.shallow : false : !!shallow; + this.queued = true; + // record before-push error stack in debug mode + /* istanbul ignore if */ + if ('development' !== 'production' && config.debug) { + this.prevError = new Error('[vue] async stack trace'); + } + pushWatcher(this); + } + }; + + /** + * Batcher job interface. + * Will be called by the batcher. + */ + + Watcher.prototype.run = function () { + if (this.active) { + var value = this.get(); + if (value !== this.value || + // Deep watchers and watchers on Object/Arrays should fire even + // when the value is the same, because the value may + // have mutated; but only do so if this is a + // non-shallow update (caused by a vm digest). + (isObject(value) || this.deep) && !this.shallow) { + // set new value + var oldValue = this.value; + this.value = value; + // in debug + async mode, when a watcher callbacks + // throws, we also throw the saved before-push error + // so the full cross-tick stack trace is available. + var prevError = this.prevError; + /* istanbul ignore if */ + if ('development' !== 'production' && config.debug && prevError) { + this.prevError = null; + try { + this.cb.call(this.vm, value, oldValue); + } catch (e) { + nextTick(function () { + throw prevError; + }, 0); + throw e; + } + } else { + this.cb.call(this.vm, value, oldValue); + } + } + this.queued = this.shallow = false; + } + }; + + /** + * Evaluate the value of the watcher. + * This only gets called for lazy watchers. + */ + + Watcher.prototype.evaluate = function () { + // avoid overwriting another watcher that is being + // collected. + var current = Dep.target; + this.value = this.get(); + this.dirty = false; + Dep.target = current; + }; + + /** + * Depend on all deps collected by this watcher. + */ + + Watcher.prototype.depend = function () { + var i = this.deps.length; + while (i--) { + this.deps[i].depend(); + } + }; + + /** + * Remove self from all dependencies' subcriber list. + */ + + Watcher.prototype.teardown = function () { + if (this.active) { + // remove self from vm's watcher list + // this is a somewhat expensive operation so we skip it + // if the vm is being destroyed or is performing a v-for + // re-render (the watcher list is then filtered by v-for). + if (!this.vm._isBeingDestroyed && !this.vm._vForRemoving) { + this.vm._watchers.$remove(this); + } + var i = this.deps.length; + while (i--) { + this.deps[i].removeSub(this); + } + this.active = false; + this.vm = this.cb = this.value = null; + } + }; + + /** + * Recrusively traverse an object to evoke all converted + * getters, so that every nested property inside the object + * is collected as a "deep" dependency. + * + * @param {*} val + */ + + var seenObjects = new _Set(); + function traverse(val, seen) { + var i = undefined, + keys = undefined; + if (!seen) { + seen = seenObjects; + seen.clear(); + } + var isA = isArray(val); + var isO = isObject(val); + if ((isA || isO) && Object.isExtensible(val)) { + if (val.__ob__) { + var depId = val.__ob__.dep.id; + if (seen.has(depId)) { + return; + } else { + seen.add(depId); + } + } + if (isA) { + i = val.length; + while (i--) traverse(val[i], seen); + } else if (isO) { + keys = Object.keys(val); + i = keys.length; + while (i--) traverse(val[keys[i]], seen); + } + } + } + + var text$1 = { + + bind: function bind() { + this.attr = this.el.nodeType === 3 ? 'data' : 'textContent'; + }, + + update: function update(value) { + this.el[this.attr] = _toString(value); + } + }; + + var templateCache = new Cache(1000); + var idSelectorCache = new Cache(1000); + + var map = { + efault: [0, '', ''], + legend: [1, '
', '
'], + tr: [2, '', '
'], + col: [2, '', '
'] + }; + + map.td = map.th = [3, '', '
']; + + map.option = map.optgroup = [1, '']; + + map.thead = map.tbody = map.colgroup = map.caption = map.tfoot = [1, '', '
']; + + map.g = map.defs = map.symbol = map.use = map.image = map.text = map.circle = map.ellipse = map.line = map.path = map.polygon = map.polyline = map.rect = [1, '', '']; + + /** + * Check if a node is a supported template node with a + * DocumentFragment content. + * + * @param {Node} node + * @return {Boolean} + */ + + function isRealTemplate(node) { + return isTemplate(node) && isFragment(node.content); + } + + var tagRE$1 = /<([\w:-]+)/; + var entityRE = /&#?\w+?;/; + var commentRE = / zLJk&3DU7V5ET#PO7AD!nvmpBzv^J^>Rn*T=4W0|=RE2SFEQLp7>pnzI%U@T6HwFBI zPJZ2U#!o7MNUoN*DL-BGTLYQOQQS|$L-NWKqulW96mO*a6UeBKhWVNKtysMU9g>$M zx_O@nKdA(zt_dUu?JLJK(d9P7uMuiUMG;c`;Hac8r4$Xa_{NZ!mPu_?6x{$YAP_Gn zvN978_ex#toyAz!s$-;oY3^emOrBVTEhrKjkJqChQT(oGg%!M-kz zdGd;x>hOx%o^cgXI)LNi^uz;Dq`?oLnQRHaz%wVf7h7w-_hkys{o`J<`mu$qlewAt1ZPE2v4auR2 zuWJ1wtTN+2cXWc9Q5GH9P3>_>b@I4+?r7^NDzQMX&u!SEz)DT&rEwY4v72<56H#-= z<cq}E{+Tiq7L~#- z@on@=vm&eh5m5d!9oR0o1_o+(<5r#j>(-FuDG)ns$guOFu$F9rg?1IF>Ju4_3Hd43 zdC?lTf_rAjMmv)Qwm}tOdW0PQ&y1;Wu@(vG>S2*=jDwUNQOfiI%*L(mQD+djX(PSl zqGb8pYK)B*jP)`{ZEc=da(;Bcdb+;%X4FVHKmnp9x*BjR{wH1(OPJK51;_;o40o(E zZVMrDGigonN+sd7`TOKuwV)`2f~)VtCd0&U3VmXa&Sccc0@h*%g zrdOZJ*rC|re9@h_Xz;oQ?HxFr|2)3)=i*G(tYEe8F9%8zfZLl zsFt#~?RpCP-^G^?TCOgC-=zDdy4LQB=P>#=PkH#S=*@mGWv8YKao>ZccLw7A!pM{6vDr5G# zxw*Oi4|dw~#1-cIAanbzV~V{J;VB06rncJ~j#fui6t81zjY9z~v4iptDhab(u@pi@ z@;>}eEFxw44Y@mheESqQd)q8z&B-Bi?{d1}jJgjhAWe%S!RTK_=iL8sj~}%hIIa){ z0-uDqqg>C{r893CPnEM1q_&izEtqp2R?~(OCvfHAlpUw>mhIOPe0v2UUQsamuD-Bi zZq4;Cqob)2mxWbDfcnY2JSB7$mNr2Rb&e0?G!+@pG3_wO)HY^P%a08iY9c&89I8yB z1BHL!qwRmlnrqa$q>wv5?DBE0*7C_;V%5+Pt0XLc(Mz84x*>C87t^h7JrrJPBQo2k z87_|Xx_VLa`~N#v{?}Un&$uGODiy8Vfo$4K#U(Ib(xn}=RfW^y@3~22(EQ44*fp`W z(&yDDnh@6lQht5f)-z~_>bQydXhW7i_Jn(X`q%a7nE&@{nEDY!y$PEo3(rH{mJ|Gc z3cSeDQl=6se01^0E&BG@fC)BLhh+>AT_03H(45VZ2``cH{Z$uvcdO$&@s; zpi^JU`S3r;y*;8C6q^yMgxa1t&S;y-%uq?n9%qa7sBL=9&sgpT>DM9e`p3hf41tQM zz8`~xsq*Nd4+Qn#TuYn^uZ?ipni<)OBZi&fjkfMFyhoW~q~%!5B@z*+xC;n_dm?V9 zEpA(h_0z?XRDQ}aGR;LJKD=Ew(C*StxBi`B!y+{=VZmMyHL7v5x_6cK3Av-QCb($* zaevExfmT@1UW^R3s;Jux56jBE{!Mfry%AOJr@>Kaxvh|iQfRSC6@rcT7_<>w-y(Im zo~SxdW;jgtpgV-JY)gL%z8!iNjpf6R^|X{45SxGlHy?J8 zq0Egh@~UZ8(I0ocQO~87day=nk1+5RZeC7QJEtHXNL*( zgcH-V-o2U#zrzY!Xu!oCDjyz@S@xLF6P`=|WDO05hxws0omo1X(YK4D81;MpAM)NZ zF3PQM7-dGf8$qO{8ziI#sZnX^7C{h{l#T&OQA%Pc2|+=+LqJfZkw&C*D5bmKHMsZv zJm)>{@0{n$`E_Xv zh)IriES7nGSc&}qa?u*Ylaj*GKyfl{yC!_O}X$k$)2 zY_Yvq`$c9eR7(gn$>D~~*1q@*?k2aenT+gK^LhWmF$3)NpQ^y`q?H)DzXyV;4dO-< z@^uSfGydm%gB+^YNh$?r9%61`VDMnwLnzAY7~RMtG50^FdUkwlGu3*rr}crtyEH50 zc#-dWEbMiiN;IwgK`<-Lk#^I_)MgPEu#eL7y~|)5n#qB? zV=02&PJ`vuWNqf7LXIl(TE6MSPW=?oCpUAG!Ev;gUZoG;3x4dd`=p>cmQ03c(JlNs zMf(}{&PREI4c%z{azgKmj(Tc5%Y*e9fwrM%l-W;Z@W#lQ2PFPX{kEQ)dpeu>^)CFw zdPd;`hI@))Rx5%PEBAQ>W87b`O_Yc|!yx~<8UoZyGf$(>+-c8t^a5LTn(X6`h*qCB zT^|o8y9F9?Nu;+hROJVLB5ZoYZTvxElzMWP2ll=kj2;g_O>5+`^jDO*O^6xPY&;af zNmf?b=^EY*N%xXPf^NfHF^zO-CB; ztjlZ|FSi#?^Y`YH`8%Sb!)u0Qc#@a>M>l0Hb6O254*BD~#24yer(X_scPXGObI%Eg zRUIki+xNa)7xpCmB0f3y`<&N&OnyW7Nos8t0XY*;cvf>i!j~?7%E?l2A0bfuzGgmq zK1Yj3(cd1%vGZt}#@#p!4eL(%;-lq#{|Q~sOg(X<)Hz9<{~d6C!ky;lyCSvF zh!q*X*(r^dY}7{CeVzzhkXl55c`}W%xo4*|-@nxSx~pnc-QqJhafU~E(hx;Kn#hn- zX~{UV6s^$Top{K(|D8G9RE9+OvFeQL57hiCn;+hqA#b+3T9^)&ABetZ4>yBG6h|43)Y4YwQVBR5u75i2ahYEq6ep`FD#qdzs>j|gU$HVdAJWSCEsQuV4CKK+u&@kk*( ztY5#rIXP=LMEu5oE14Ajx=k~1Nd#Ig8Do~yTqw*!TqzO>%HHw@MKL`3s);Hp`&J)K zr?G6<`RQ&zJQ!%xmG@;Ma&pJ@P3ID*z6ov)l|~TinhN#W5$3V57Flo{d$Ogi*zG*i z#}1L6<6IdC1@jBS>Fch~S6@Dl&7oR1VCy1Sbn-u_ciOMWuzDl$c7^8!TpWzY!I2pA zYuFO~P$YN!i?+7%h{CFNhDE?MMx|h9=u`pBDJUAOBwM`AwKT-2WH|P8b=(T~*)fJr z(g1?79fs$cLdg{C)F~p3`7P`)z%@?a=v8dE*9Y;iwWy4qBew7rk(T?I%UT~r<1^0a zj^2wGXRl+23l|ipV_vAaAdn^g7Zhn3PgA0Qe(Y2>lNZpWSuUbFtUs}FZKi2YR)QT2 z5+D=81PEHbnO?sdMnL9zrxx-qJIkob4j~~RHD*~HBerH*Y7rPx!^$1Klyy&9@weqi z^>_G|>JHnMWdo&!8qcmv`#047nXD5jW-O;3e5D46uRMiu*#0$d4X6h4qNy}Z`)4N2 zj!FO){CL5wz_BK4<_OZpRu@Nb)B=Ex_1t8ODsBS)(WS=GsUBY0zaX zkDVi>S3I{V-Tf?!OeRbG#ybv&5|Y?&oe4c>qwZOE#RqD0rj*ePW6in5if`wVC{=Q% z%i4v6gve{g?B|3vx_~;@U^tVcq+vW6>2=&WgD8>BTalkuR=P=jSP^<}xa7_(^y%6u z*M;NtnXnhBIPoSlcwez@^AZPAr)J0@80NPwG?|#?Nw<~C;96UeuU^Ru8OM7@lZtTb zN08C4HjT@AN4+v;supMpoW@~Qjv{~kyYuzLgd<;H#Z8^V1RkL!AN6C~Nva(GF?5lK zZ;ct*LQT^b;^R5nARtfZpXy1617uBa^S!4TkOy>I9$zr0)cpW zvCIWb`{lTIl&P9@M#}gF^XJ3*2xJbOoww&}n697RKb#(b9jin#Jf_A`dv^y5zV%3v zi3DD0KPqQfR=U>ph%<6JY~!x;t`em}M$6@*G=}#Ipy@JC`S3=yh$@hxlu-va+`NBuqm@*;o8nLM*XvvCP!WAJWZuSZ|%jk8XY` z`n=*1Ep0atriAeDAn~2?mdE|lwCd5UmpMbQlb8H*Q$*!*qg0o={r?d7#GvSBwTN$4 zC@Fp)RsWWr0B0ab!`JBTmW9r3L3+Ey!f>BodFFW$pMSpR*^~xFEb}Lllq|O*9O>Nd z>jtODC;ZWKIx@mci)J2l}DfW?p?*d8oz1$-M2S@fIy+m*w-0u(m3m7%Ccqv8SJA zBV0q$Jw_lj(UU)js*djZ3Ww@Rna8h-k`)tp_G^_zFEH_m-SPRqfp8ewojVO02WU*24>Oa3H-zwC;Y2y0~QByHsQYel;DDX}t{pox9!%~-7 zJ?>3O5@VDkx#Ly;Xyzy)_YKb|^Zq0S z?+T)8I+oXd^TqADskV#dD47R6n+zXdrEC(=C+yb0NPU_{?u92@y3U`zF>7`Qx1nn; zt-yY|Pq<2whne=RMn+5AGtxgiNH=K#{7mgWrPspYsXm`z&Ls3+h-h0cybB3xTY617 zTf$nbq@VS9)zqM^-)4Oi`T77KJ81@M*{zW~6rb2mw$WASpx3<3g9cx`4gXj?`Q57WDf#Q~^70#Inypf}pv3yU1s4QsY|w~uc~)+WB|~gk z<|6B^?_yxls`LmQj;q1Pz~BQGLE+aby{yf&e#9y6>V)09bQZa>no0pvs&+w`}NTH=M&Xm(e?0r&juPK_co@wUlsAC zT1cOzgW4_B^cMM(x1dp!{!Oa!{T6?<92X`g7cqY-?)O@wvQ%dVoyCM zrwi>>Xd_hv5R^D@kt(pjQ|!-+U!$qd0wd5^K47@Pgf+p(bcs|?##%|y9_P!H?`|8{1Cz{!bUzaaT3RoSL9XL7df~Q}dBs$_UGswoo zBoo{7{|S?GFbR0kz%gdK5Fs0FGEkfoMx(P${8Ab6$O)-&Pa>5L$H&3sW%%N6Cq5Z0 z;j&9_hFEreUsCRmpI?jhC*2aF#zAHl0|*DcL=V={+M;$=XODUCmsDA6P`+)LX)53o zx}(+0s`leV0_=$|3;okE5-=B_x!}H6UY#?fwzh7%c#2P_351~xNgw7-yxr{Sk(%j{ zxOP=CU_cJ2v#fzH^mYUmJTwdSG8sMgs+ZY`2RFtJnGfwwCBi{?=!MNaZ&G4M>*Rw1vdI;GvEEpUY`6tCDJBqlx{^BN8j^>o_sX>X>1kwv;onZ;T}x5QIlAxIc<~jr23%LpS2}0yJW(u|Du_u5l1+07 z4CGK;fTFHE!?b31jVONf-4Fw=;USuCmSb(P?>QVT7f0P&9wwCZ8gIx(*^J(1saf3e z{5c`27xeOFb9=iA`}W`N4kWA)f`dShzMw3XOpC-bAQiOprMva3)K=PD5W+zwhz?$w zIFVBqFNv|oyh{&+=6s29mLZ;efOYrX^8(F)7xq1ulBd;wg+!glTQ4c3_-GqCVIvrU zK@jtX#aO!A8lt`3ATY^&B{^C!9k3weZXe~Hh&VTCpj^pMOA-5%3}L4p^|a*}tM2vL zlZ-4d1_Sun-258!2csY5+4(swA%)W&$WFkXj5lUP^lO#IFaosnND=kgN+ercfw0PV zgQ5ehndj4lv9UHqs=j`HnT8cl`iq|%bDDmx)b)0b>geeS&hQ_H?gY7bjyc&Lbg+uA zpT{O8;W|6pJ443|O9&+b8D0xB6ZC#elBUtRE9oeAT{}x?m|N?PiZ&)`LJEc}7`GQ5 zZ_x4WRF~xPCv&X!I{DYxsD=KUjdEQuvuNS+idj)_`4g6t>wjL=vni^^Pc!G?zu4jC zP`w6)W-7iS7ryZyIU1Y!)li8vjafZ1Cdmxd?ZQ|rcG16-{|gNw5O7ASM}}p+`Pq4PKbiCR4M>-fjo8YqkI67(oS5 zGk@UXqE)zUWF(cCxQWQz&=Kwt2eXk$eU|vu(3_ew8O^RK9PM&p3v|f^>j8ZZ>Wpvc zrCD?b|F0IDjU6t$!)(%5Q8okFgT=oHoX8s)P1PTer^l?FhQjol?vrAhy+323lsP^+ z`t_WVLl~KX7H^BupjtQjtmEXw8W3gMbu^RYS9&)Px1stue_D7Xucle=q6zf&OYW~J z?QIe@+QpH7Yli_;I%op-boXA=Ixk@N$9@Bz)0V=Sp+p=xPFDJtewjjkQG$GoOLmjc zDjE_PTib6e5=xc?#gZ%S7@rIo71j>c{8a9NA-!Qvw&6xZJ|-X5AJ`lxi9P7S?4bzWDU?PakTcI|n2eL0GCY29SnpKuZWj< zIXO9LMftCIA!GtRWJ|zDmsk&`f3W~GD)KetA1qh~yh#ONlk0zp%z1;JpsljdS=m{&(|{5W&`NohJv=i*+HPHHNib6z!Fvd@a#--S1es<^s4aI2^&~L zl0h!ppMn6mm(83WTWrNK=1^3j~X0HgK9GA2U9zy-WP% z#%&`SDfD*!vvW#0=pq#tA0H7sT=8r42;83K~igkIn1UY8d`Osd2Pm z&5=9!!7GxK5?q!Q3^Wc2(CQN+uuPMJCe^rlxjw(*j%-|Dt#g*QR+s=IvhVa;ktK4w z6vB43INCwL(ZK(oC?sxnr*;a#HOVLPZ(PHucis6N|B4q2N`M1erE1T_ZfMTDmwBx& zdZgBMWF|0~HJGpDyJDOK4}~DbU*kehJWV4hfC4yd==xa+G9vv}bO`TC;5l!Aa+3cC zTKtc!!9s&a8`OnhqM0?smfXe~`UFr6dML|M=q?_G6U$#>$KrTDm!H&pQ=>U=ISEUs z_oh+LL|sFj*p)S+1soJB%CUJveu9{YWxqK+AtXr&gdbr64Pn~aLY@O9a?M@(T+Fl1 zi~2oVZx?1nBFydyo#^SB+m@4C*i3yf@8CCq#&L#n5n(3Zeev1(RoxtG*GH<&$(ZFs z+H=|&QM2IB(mF`;0{l~buR$+mx9)8-IM z(KZq&`cXr2 z_`Q39_M^ptVPQDI!NCUXJ6B@{!HKldCweedd{;aX3m&4}frXaEw~$Pw5JE(2WV1@U ze=rK?OE4Yhj^}cj&>yT%wNsf=l`@OxDeCGcidcZN2Q66$Yq$--87?S0Yj^Je`3Nt{m9u}m(J;Y8bZS%)8$T|-N(npsQAv_0^L-7l-boK_(v-s_mf#K%67 z)akl5gr*BK4HocSur6H3J>gW$WNxC&j%cY$~pjKX*o&CPcm+l=ZP z;U_j$)@$hTiI~EnI?W;Yz|rM4EN82&uNNWv2fpO3=x_~nQ{eG4S%R1yyf;6Rk+CHZ zjw_*dMgPXHuc#)YZ#^*l1`Xikg`alPH3!v9vvX_2y4Skpf8$4H*%Y~}uRi>C_?!8- zWIe`tj?iks(hhwX3a771D;p^8puTI--!8}MGZORO3lcYPX1;vMISiX+d66~yS?_a) zJDJiY)3XU2d*i!&Mz|y2-0%7Yfr3JQY&#h42QnJkp?uw*ZQ;XS$;0G?mAd7I%5P$b3m3%?}OMuyiOV)Ns>ILHaM?N38PL)Qth zg?QPBE?uKF+yd2ecWazP#l>lMcXvm`E3ZMIn7FFJ0nkCk@0t^&`0y$%sc@t`Xk#PQ z3=M#4(@I8p6JX_NeJEr_&M84fNl1@)G6RN-Y2+cFOug#)kb(425i(e2Ie6CkTcMaH ztc#n!g&bK{0}&zzYp2j?!t7*&?r>{MuZ<8hcv%@YZK0E=hVjKqHDySuVfQ*GhZxfq=1&#^V(!f9J z&ux%oO3>RR_@tUJZl>?SJe*9oEDY~o{S+}1X%+x=4S4SV4b+VPcTi*El3ovjm5knK zDXwNilHGuE-CdwEFfyXsgt&9S01C?RD~keN`1>=Q`^!Z|M=u<tMI_VqV8(jp=hebqIO?dz>_z=lj*W|9VL8Tx@H#=Ft1;c|=lp3m=}MFxh3_q^GWt@!XdHf!~((=s;)V8Jzr;MAqE-W>+jTU(5E=LhJkT; z$r~0&SmXW$a$<}S?Cv^IKWoZg^P5R^SaCS`@nnco`3*jlPKoRVOifhe347R4?AH?EDx@$v%*5jVVqXEW?3*y7rbh~j8X9Gk4-$E4o$k5+ z`9%gAT=-9Vl0`T`R``wug5wk)mudgDbMTcElZIJf1P%}~StqTur8?voJY=<+1Zd-SWZ2=&Lqx(RrjP{jDpKkR@GFu@JomKRsA~ ztuf=I@WR7`rsDU?O1OPV-N%_O6p>NdE9o7&I(=o?L2*Ro7WMy^Y(90ZbcVMWhz zwZ<({TTVeeDBRT4)cI&@&Y;ZK%fzMg7SS?yz;KMUCJt5%cIyX`D^bD@3urdLV?y13 z;qI=ip`p=mP*oBcLO{J|NDs-8WebvJ3J|pwra?j!p+d-jYM@EmYMKr3nRN9nd;g3% zkLc>_de~#;FO8?DPg^;%UoymHlX2XylEBtt^FshpT0awF~n(aq4!z zJaUNfnIhvWPf3wbMW`ThOBRZSP_!t-j6qM1pQv#Zcqx1DbnrEQ#E`mF5prh$Gv+`a zs$zaVK02RllfLTq+-ug{_Q$c(buNmbTaa*#?icFp-u#3xjjcv$o2*zuicZh8?UZG z;jCGI7_JBhfhJe->pYMga4BMYM3)@6MFzq1LIiVf$-ZQrit>&&##3;A&351AjzDa} z8*ICwk7}>Q8@D4H+j=j=r(ZnOf^gOBUf>YZcl-!_4r-5`Q3?77l7|4_%Dt|ciBySZ zyA^UbKxZ~x-b85{1&oebFNplV_yt*C1K~gb-Wk_N!$w`=;;43S@WDdp4aY)V`8%hD z74zQ+1PbR!C}C@>s{kryFP4&R+K!js(cq9UyxH{I^eH>&1vNM|11iU7qmCuy>mWYuNhrRWPUHM1BJUT^?Y)h0gZD)${rpb&b&eD0*EoDZk7Um zYu%g)hkCwpjcS1A_7Qzk-DlB@B#@lgVRr#EOWsD@zK7wtz>68b!`8zum*?-zFFZRRn33D0`FlT?6BiDCF|#&O^%!aH?`74T zH{J!wX*j%vG$HRs@)e}>zf`?EJo#-8K=m(wxL??tpBnKkin_MFsXbXM$gUta$)~F( zWJm2A8gjKa{VDJEo@yF*l#s)U34J*F>%UM*iALqUIQG`ml18!5pFhtp3HUOn7wHgo zRap|roY{SQGv^c9Il5SzgH#TKN#Uw8XKyQwD-ZX*YJEr zEx}Gbay;d>{d{!^qEW)_!fUw|3y3a2Z8rh6iCr_g_E%|Ip^5CF1uu4t_Q}D7W3&pR zPa&)X+xv@K`_1jG7808Fu8}bJ&1q8|fqXs2H38{(8d)s*(`OsZTyynlin11{59J=)R#GPsp~eiP8SMw>HQmt3a` z1mn{Mfdto@JRN?h5$UzNL^T08EgX%GiDPifDs%Lc-;U|olDUuT4j*dBP#xohKO>;Q z=YJEYerMGn)R_qB+z7nwM>N+9AUVEU_4-8-^&6iH1e3&`8#Syb3FPYvaO1?R@i3YC zjpz#5|11o3-=~V1_Fb>iD$*M+#D`0cJ}^J->aftUK_tWw-{iil&3b;*fhvaX3pFv| z;>;>cZ*TAU?RG{1{{gF=>ZZgG5Ruq=&+Yk(&wF<+ny-<3?|mmF{`xVX9ht*P3ZNo* zqLu~fKqJe+XNMe*lhkFWp2tA$-i`y8W_|~r`D3QtuRZb@PX&!mt}GK?#G8-J2Eermf>{5;h=@P?i|oh;sb? zfl4d_>hGQ4X;D+tY^_ob#Of2eBh6cqseEx2%jrH2&l}Eeo&S0qP1UrgF123SVg9mZ zitfiQ{IF-agIm2%_Vk&RQtmTUjPCjV7-Ao=zFe?Q-!dazx%R->@oqs_)bT@%)udGu zI5Myn!iy0627N3U5KlQ`q2WIxP9Ujc3_i7g*$NT({;|s=qT)vZrB7`+Id8t>vFZG! z&-s3A;D=`%^ax)Q_c7}#2L+%FCoi@iX5@!tnr)peAD;NTud`=2Fb9Zs5zHO{QnC$& zC0^8DUYx#GbkJM)#QyYmd#|}V5Xyk(^@g=F>}qGs!6|7S$16Y8nn%?<8!I2*_i_OB z$gLN!!1Qq}wO=ca>E}e}dqWy3p?+%?7WU2ED3PoZ#y z0ard`Y!x_GGaUcTK8ChYe2bE9>IueRcC;)V+87ua+HR=mi=t^3)x zLD|0J^Sz{gKEe!(Fq9nDCEs+hU(&u{|8uwvfx3mb-> z+z+VO>s2?%m|zx1m_VvN9s1bXmB5qgQt=hrM{?&Qiu4EA{zuiVI(clVJ{NetbTqhL zd?RD7_>VY{CT3Lc+0{}g!6l^rUbXU$$n_l(Y+$FdBEKp?`4EECSVqhNm4MlfkbQ_R z`g4IN7~11cGC()ga1xDx8U6A*9|w9cAlKh>)U*s(6XSJMK!@H+2+*t}x*ZUokRa>V zLR7^KmvpCoC6T++xOH~1(`J+Y3M7anz)(3e-}WOa0fg7_0c$y5fGA6k!(E_^=cqVw zVt}DWhXB{0_GUUBsiKgB#isQUzlBv@eLwJ8>?3s;3Q3khHDAS%k~Glm9T#KeEdAqE z_Kz3ZB3my&|G_AjHbv9Up_)WW8^v97cI#aeW`*#>3(GWdN3))Enfl2OeFqlHV>SU@ zfk8MV)FW?P)IpWyotYDxLbH0ik$j`N?}S(gYY9$cS;urKr&(ATqK(#u-uXhQy(`*x z!}r4XAWh|h`PQYyTmP{W0;ct`3XUC;yIy?_V(S_bbHN>KZguOw%CaTIfV$n8Gn*LW zF!mxEVwc$=5ds#Tkk`)QdpkV`#^>Ea=|%BbJwn8cvL3R+~1)>W@(~V_%!90SX(p>_Qiv z=aEqOapU9-hlaAFDCa8k>^@){ez!Nwe6vdul9RPkmk7-J$BGs}gb-F*_2<#O|0Ijh z#(pVG`S#L^C(M;jca4j&AWG|^XRD(wfzqkEVKj(D_BvYJd2m(R{79j)N%wk^vCuBu zCmSRxp_%S+Oj}^;8U=XBajrkFYk(p_J7NT52ndIT_=oDB%*MAwWHy^FFN|zIPI4*8 z(*EkyV}y126oP@1eRr&9ObQ59Ibq#4@! zQ>RPpNppc#cbSIl@uIAJuFDKz=?9hDq&l+53EFa_GE1fNx%rd^$9>b^LvwZ42)Gdz z-I7+_0S~7O*7i-1^Q_n4$HYYJqPkzE#s1;vSgf}D7+jaoQ^NDT(H()&%cfD#t}wm& zK;SbcS`Nxi?ba90)Se&AOI7X9*#Fr4u;h`|C%4%kJBkYI^V@JOE7Hznx(3%bchg<; zc>jCCqv^2GpwZjSxwc7i(c`0I{d%?MM{TPtt?te9FGt@9ZeW8OxEz;+AURL$=n$^~ z60+GeiJ7buvJw)seN={aXml>fc`je}n0uqn*CbF*>XMZYiMphZ7vq#*AIF<6M0mE- z+yt+wb&^V_bU{pYh@B&Bz1c>v3Pxo<)AsqTTBh z)JVDc=|ty%OJB81=ybRE^OFps8)CM@+^i`7YQmcdM6PMO+=$H1m|@V3dGpw0tm|vZ zJPf5`=5aXXL34|_VAMJ@*IVtN`*!DX;--*hNUn=!fp>;-pZokP4r;1|e807s)I!Vn z!)KJdUH3I;^XwM25G5}psmu+f6)(z$N@QPcS~!X$<;Qo-x?_heuv>zTRQ@>)M3kKIUdPA;{^s{-PBEs7# zf$?_rKyTSK#g}X7eeLAFE#!Ob>T&{ARX`59hHue&qNy`xP(8_Wu&6OAiH@I z;RznDRbCvgmHw>x&ueFcQm6WenZRY>WXI|T=067pLWtYO^0st_ZgTlct?IP~7pcqH za)+tUEVoRHWaHa!RN0|EnC$wFx}>E&2%X%S>d%ym0b@m~wl?7gj1MQqf!{i&q<|GO6-fPr+ZhA<*Tbu&$`!PS)PvcF=+ zjN1yy;6tDb`kC}EY2kB#QC}VJF4LHn&;NKFEu;5)n$tJ#Yb?E#@v$!;L*g#0CL9LO zOkBYc^SD!#&lAnHv)w)cZVXi2GnAde2&w9E%AbenDjPPygp-q%+Unb>5T&d4{c>UG zy67Tdn~9-~jj$1>jL%AaHd3ltwmTWkk?zSN<}hjSXJm$Fs9RE55*~lE`w41IpLVG$ zQ>!}Py6oZcb~fXA9<_T{vj#Sz>$e^;LbpURrLVGsX>792)yGXBEVP_OOV6%r&kcJ@ zxH5ipMBk1(EUv4VwsyS1%T?$ib~=l2M7QAXeoD+uC~~k0O^N?|gaTNnqSO*8z!wrK zA5;s~0f4=Y$`?gR#Vc?D9y}gD$y7y*F4m&#?iw<4@bD)XXA5c^n+3hI@%nR7-MxU! zC>w9`{bKSe*Za#rTETKx2I_X#mKyeB;WrN*P(CB|iKi&{P>=GvntIgvdPeHpIBs2Y z=`NbN(lcmFj=}3ogM(yKVQ@l1V(6fY11-F3OD8l`SSS9lXV!2!`A)h;kiS<_>%7(sRLm`{oa+ zhv{+8kppPcEbuEj=rmoJPy&KZs1XqlfKq7=AX;@>=v2OW?G32B&KDgM;32bCdViuv zOsIQ}cg!a93af5t?zakGvK^1-dN>azX+>uB?AmTTygF62aB?LH5sHzXAyrRdg4Pbsn#RiQ!XD+|>IJKYz~iccs@!Oex^u1g-YHQaR&Q0SMra)hP71Mp}bYV(Y z5TlYF$+a$J>qEBR_#=HvI6ezIHtgy%SU>qw(MO$?HVKNG^V0?NDf3A%bWay;j%9<2 z0xH35vtOl;6rR@tSFRONZVloN;6BU`KpgUv-vRaV6;Q482MdJUrcPh6lx8^!9;1Le z`;LZ|G~bby+NjCjZ?PhQhXo~rgiVvwJEpGTms09LL1Yk z$E-nohW9?w;d0?f0)6SC$zH;vFWJ@HjmMD|6ZSgs(Z|BKam=yL_8}kUEvBNgdMX_9 zLhDie8i?Ih0Sq1USPr6!9gS=~Vqw&=cPc`(Zu85jC2*fwQP!ht=dSO1Q+)=9Lw&4Y4)@Kol=`JUq z3zx<{$|#hG=WEd#<7jz8d)K(!>fSc-O$jF^2LGeE@hX%gl_E`|fBdK)2&cBv@5<6% zN9#Yn7kb1@3D-;{k(Hcbvx9d`3+&(4blaDwXy3k$Je1h}PVxFsY`GNpnd5~nG9tDg z(8(!2gs3?THOUgilWK(kLCrJ+8LS?GfeeRDf2GANjSf6;!t+Kyh zt-1J;fS>avXMtYP8ddeD&D2wrogy$ul@}6uRz&ZZ%jmgxJw|n@kI0Vn5q1sh$K;}n-#d&s1YG?pdjc!!1QW5xh1b*3Fj*St)D_eTC0Hb zp^Pl(R8A6ltgQ8eQ-KwDuj*F1na>QpICu`M>~*L(+9ztAA3J|JVO3x=bmItuOZK77 zqrCZtGUn$!{)VQutr1j>-&lcXqxPGaU!s7y*&lr=8K6{@wmyE&$ne@MWJ(Z|bjX&pX)2`N zYhk=7J@AijvGS5N4)qq!sr1;KW@O|%?}<=0yte}HGw>IbOR$|R@s^Gjkp-A|T`!_s}z5F)`S^0$J zD4S~KM>Qs|(;Rzmx2TPA$lbm&3zR_g0VI{oX3E4qV+kb%4TPXAl4_rZJ#}B;}&%h(r3R)vpm-bPttrg>d>J8p{y-n2!L@gUG6)b95lM+T@>ARpeN18QR|p1 zTEM81Q(b!dy9>=<(fu%+4J3H(Z)LwQhU93y^e{$;N|^*rpi@&*&cIt~2MsgcQzqh?dt3;oTZQ3qdd31;`mHGx;Q&_?&8YbyCX*Ju2*7q6J*vHoVXw6sz-|S zNmt-96a5;vcLho9Kr;04h1P_eSs^(>WrXY?NeuLA3P=CY5XJA&lIUwV#31RU0^~ar zxR!Ie;fAPJj#{c%E4V@0xTnTwo3nsPEm`)D; zp>1D;9Q&KTr36bWn}WX#BP|p;0DRt0Iw)V|(mDKqZTr)_<*Rfc#-K&z-mU-W09e5E z`2z?B1`OjK7=eHesc;irB`C@NKTA*&lR@DNzxmK~@q7I#-c^c@0)Rz<8hj=E=m8PP zY-)E~mtQ3g(5cY@8t{kn+t)j3!JcxeeXdFY$i`tn+7eMalSYG+;_{mQUFa&;N6Z4E zxueG5`zxZm%9f*n6AElSQLAr>bl}YoiQQIzU!gIuPV5EWih!TG_xzCMDj!K! z83=Ua4c>Vs1`v!UHTe7&&Q}E(#ENJD)c|Pw7S-hb&4H2;8iLOq!F;#DYY+I4oqwMv zMdJnNhNpX@7Hl@)hmid@pfEgn>6aLTOrY936uN*9yBnC^muH(~)y+BeGlEpH)*S#$v2QDA@e34$48WLKy9&o7>! zIjRYpRr1<@%cGIrzy*fpR~F)VGRzq4zz;nCl%;?Q5dZ;i0yGA_eT=Ts;H1qlXya7% zm-aRA&ag}Je^sB5S?qy7DI0`Q?cFw52U_yH&uy>?g>r`o37dJ*ud$uV1oI)W8}r+*M$+aYYIG08?6|w(S^$ zB>qP&wIKdwxjoIbh3fwT(8i8to^2kiS*uVP}%d- z1JBh5=5)F5yzN@-jkZBRhNn11@^3Z~j^=Ew%$wKXHPhbq(p3(o4Io~*P*~9$0jwIP zjk8{l`QU}<=x+Y{!mI-u+0!v_?U;(Q?5Xu-1Aj@M^Y{lmrmF7y-o#gAeyQK;$-#i`q$-r8sO9{^`zfK2aXlS(3v~5!Gp(iQ~%TZ7nUC)w9(4LxSAKOJho2s zBsl|yxp}P9uTCxwPAtyKXXD(ahM2CF`UYk+&NuB;N@Vh+Up4#-Ud6aPygf#Ph$}2S&T)W#VwE*&( zg>pA5p8SXqH}iALSSWG!=j;nq6z2VSWkiRfgd7hb;F2g z{zX>1@l~L;NW))%Vd4uvu{$H36om){RE<38mn5@#x}UE}^`DUKY7z6P94#URw4%@E z1M;92ZA_&hr>_hYLMZ5r{p@BBycehI%8UpFFh^Ag7=Ol?Z&SASe&*6f__dd+`>D~t zvOVzm8V}Y$zXqfY@^=-48bO%b{IEX#)gj`vWIn4%gK+uz8#N16yfh&XrL#GWOP4gk z#{)?z$WHVt&9hkJApF`^P!dImt2+S(!Y{;)n$kETCMMn&6cl*Z9-aNX=|Sn&XINK0 zx_u^lsPE8tySQ;F#jHKUsD|I6h@J+v)@m7s-h;A&1wew5)DdTsryR)U0A_WuQX*Yn z!78^L20s2{;K$$Y1~_6k$GEmvDSK^}a3|i4j_sGks%+Y3s|5325*j;<2*LYM$EJOf zh^>Lu1XvqF`qXWEexWz2(=<-`shGn9kiR=%lqL0WsFk}oxJX@?yFbgX0MBUn6V&3N zzzW>+faY+ZHt?7tJ6O9=V2mX=o@)VA z@(?~%{4K)v#b2OWo#=e<&2Ney{sL{cKZbE2%g~5@M017Lj49WLR!1w20>_t_(V?c3 zL~So&*s&K2P5!mG%#FV%#akzOefJHL5+$#ID+H>i02?k8EC{1fbe$;B&g~sKo&&;R z%8&7%d-MTDZ3QzIBQ!@f3z!Tu=6qxdhqlJ5cRGIf3K)%jo%|;Xh5TQPy>(PnZPY$Y ziGqQMh|)?)OG~4qNJvX}35c}hK~WJwQaVQIMp|kR5s+?>98#L0h5-g-~Le zeQSN|`_E_jEYF;C@3{80uf1>k8p7Ky7MquKi*qhz5?&A(U3grCgOZEQy( zj>cdGZ%0@)Tfu`Zgh93g`ELKr!}a{R**{NE8!SaZJcbntsH{hmsBvlO;p(ictXErQ zh(Y>V8RaZbXK-g(d0jO|4?KBtrfdIy40@Hk@gUbcEMz8h;ZO|w9&`^HZf?u`A~L+N zW()JRSKCaxjyufNjM$l(iNqU03g>_ZVfIu0CSf}@nAxIuz|pJeQ_!5oD?ot80RBH-+l=eUTUFA4@ z!ZQh&+)r>S4vkH((uM}fLnMMpT))mXi8JalbG)AOe@1rsDD!M5TCBU;aPdmNP7OA{ zch6<)VF~{vqo#%Qlr@9&g>%nLOsEFqW|IJOXU!P=-M`8To~_a$4o;>jQcm(hbcLW6 z>AON+d3jjlcKvJ2)a+Ou(NOL7kE~VyzOMMu?Y0##HN41OJ4-um=AmA;s99o6Q>!0& znHgnOejY(sc;~_oTUlm##_c`}Noh`;WQlgy8ZK7B9sH%he^vn-OD`I^$2jn$E|5SMUW8qf%8}Fo9Ak|Mw2MXFoBr%u#W` zR~+sT60!m~>uacf9^e3yOfq|Gcj0!5NZ$i#yKai9^TXcz>as^LR;hk#$QqBo7?r;E zULbie8SqAWHkfD@N9dadN;A3c^Kekz)BPe79}YmgH9^W%5?$$~wf~V(Iojcp;9A-4 z=+*C?+>CNgj6a}1e?`a@e62$>b4{`D;A>eh*#l=B;3C?(DQEP<;*qC%(z7h&+FBT1 zVzkf}4!kMLTT0B^8DVyiE)(ciwitSi;S&%5{LWMi_hUeSZi4eny@(xX@VYjhtedSE zIp$@(9U4}p5;ed(=_>vZo1{~!$MK(jxOn9SRjpeJ{)0{S*6P7J{A$*_lEv`dRYs^i zF_@qoUjR%Q|HL4sS{cE?8R>mZCsN@L+6}j!94V;ISq0+5GH8)*7YJRXfN<6ccwS2= z>B)kWfed_(}XkNzsqgMH(>2+AR4~q z=CBbmScfZJO?l01^{aR_N&nbZ95rIrb(j_tG)>uHUTKmlq5->DcJqN$qlY#9-`D2! zCe0G{XqV5CeUS?=)%1=`|6Agl;(r--r+1~y5fbbg;ZHcQYHDVFk8%*dPlm07nhoK= zD0)IZ$B`NJyHyM@#wEr)1M#1aIe2j4vcrk|jU6mSSbrP-hY6iKj`crVVM_cDeOU4H z6}XpZt{r2IXccR(Qk=^2c&w?Q%$6-^>HWK^GRyj~UqLO+AlU|4@m4tl^%psKe$r1j zcUm5PU;FkKmj#u)i)Jh%X+2aLUs4^&FJh5s;BwOHyn{0HMF0Ml9v?Jy?e~&zob|5* zGR5l!;}7H0BTJu9#?f>v31Nq$#w)UX9yh>o&!=4R_ADN&nLAIxD0LfehgUwTCq1~! zu95bfbx|_oawLP}m6a%-2ihCHOUbK`62DawGD9ac*MF`e+LI4ycCfWLTK~sHB<-QW z1hJqRc|9!625f9n!Qw}=Lo+f=a`9)Y*zcY=?)fbDjTB0Ojm*^~4>z{If^`A8yfvxI zlf`Z?^5b^~=S};6_etVJ{SHgQIWJ3C4^4N*v#l}^ZItTDOkxf)R>h|oh9hBS;<9qz zRr0OfJ$X**RP#3@x{UORp74&GoB#TnpbgkBREh`1n~3J-OAMpv&a*2_wznMtQKRVF zd!n8Gxzw!~dNXg-k43It!TSg^bh{Dw$Xu_hEEuYH^kwDa#~CZksd_7W}4p>d_;S zg@*Y55W&HVS!4Amh5AZJ403BmjfC+@?&gnp^NCPVSz1Z#mZtSk&zXSN+K6gPChYW4 zUL%3@Ogy~dni6RYdv9s+@Vi-PrvSB;ud7r@@<$>8Ub!b;oKeafIF)8O?p`Tc+UjH_S&`heBE1&j`?Ju?8_9ubsBL&2y zVR)PYh{8xv_$rDsWk7Q#CdaLI9}=pvs2tk;7-!NC?t$2hPt)gkAN(P4?gt?y)B)m? z+opG^b08rS+9>5jX}%IyE)ajomuf8M^}SxYYjyj!61COcjacNbq6JE~k-T(u(1 zcB}f!7*Fu#@ch+i-X!{$MfIJbe^*h_zPm5jD7dc}PcXDhq;l41)@uTjHy-=F&2%d7 z=_N%yoX~%tNC{Qj`$^eTdUQS|0$k2>K4!Q>tJg1vDK)C@==efigAr|fu4L9xe7Er%sY;#Wva9VBK4hn4K0U0KR5&NLuavDi}Ps^uVu@hc4jOZK_<&k5BgVmTZ*=xfa!us2MuWtbXJF3vw_` zsa6sXw>!ROn|6iVWwx{)IvKv8J_brmF7l~zHyiDiY%a0 zroXm6MtLB>G{Wh68TN%%izAQ;?Z!j}*bICtFn(FbR@#g`v06npAp_kgW_?#i5q3Y% zz7?+o6H7k%FN>wz2dP>?O};uU7~Q;_(DM$D+MWT@;O^5Y#+!04rgBggB$py+-prq7 zo^3bCGR&mHsdc!0LrYcJ(q&3K@Hy!CV?myxZjExK^xk(Ng4@+=4 zNfz9YGCc5z?`Ko?XcIs=9?~werY!pxFK*5>)QX0tX~I1~(cIaaTYZHIJVK{hRRwgu z@k(wH+f%$EZg-+Ts77=Qc{Yn|v-2mXT2T^fD2SqI;o*-&lWE%DG>>2=J@sXbiIl{(|X}E?WRmAvyMD$ z-s5h*L1XHv1?AB(o@30;C)@myE)0A z1D{ja8(cEfoM-*mv*$Q@)nw<>YSPH`jv8vVwOmQuyD}ikE3MkzXsS1=^9 z7`}BH(*cCa+5s9FQgxTEdU=Ul+LQKC)Yk?|SOdzj&g;XV=zC%9GE-lDyU5StcyC$2 z&1#w9_TvozqRlbY=Hc`WlYGsmd#|UaX7y*Jb2SOGt*tyL@koOSijaRZf6YRwZX@}5 z^UB0y@4=Bew}l=o&T8_?_UT;m#jJ)s@oFdSG$CjQnnyl={wp9-Yp)Kok@$Ivo=GDdOq80g?Q$?K$N zHBFZ+K;+LYhFSj~+Jug-^phSB*>ww<&mPi@eYIAHa&O43Z%0HHa9jOap!uDh!yggJ z>G9M)6fSP!^hL-i0a+daxVVhxK$Ai^qIJxq58z1A`?rGA`%7_}?VtzuBKXc@iTQW! zIC<_6)n(>qW?w9GuZY-gfZ_@W0o(BMkTd+C&D#r?KW$l`#q9gzFbKrP9)6gqL-rbW zH|fFrUz{BsVYXSecVbH|K!0-0M6C>RC%uwb!I%E)7u(J_eAFY#8s{~wRoP5N@?HK` zikH?e*Jd{C(a_i<%FIyBRzvso+8u?Pv!oLUvx~U=(~j3vEl0Y6#UQ|v_q_Go!YoBL>sw{_9TPM%=X5bOydj0hiouBp5ncRoS~I$ zJ}yrZwl-EX8=y|7qSF;i`N1r4%Y;DyRi%3U-``g9K#o@j%7R~F=Cgn>r}4+?LO6e< zPvas(n|B5V(~QI5Rqvn9bTq_sR#P9vWI3J#Qt_1;^z`kEj16pdFp<2+vq$2G#WU0w zYZyL~39+|B*>!Oz`lYn1^O7qHD?{UL@7~ks`-w0@U%Tnj>H0*vFe2UP=k1+4S|6e- zdSSA%6)&`^ZP~IwEvpYE-tNeCF>41JSK6uLXC=nxuMqPZRponc0w}Qyrc0l zZqZfL;w>1njHZKOrdJj!VQ0=ZdbxP13FBkmr5LMs6hS*7ZYOJb6z)|pPt7=d%8PlF zorXJ)SpEA6#xKJ*%9`P~55Q!Wd796xuWVh5mNP@QA7k71`ou?40Nv%1U-2PW^J(6% z-Ob_HF77=>aWwPD?C7|bZ6%6zwS1X~v;WOohKbWEiqOdzx2Offf48{HD#=xdjm3dB z4~SGii__CnV{7OsL4m3MkO%1hzPylfrij@-le9)yBR&$xt4a!Kq|uuW)4dPpn*YMt zon_rwCS`DzFK!tRweT%~b}bctb}YP`R_|r!x)3r5-GHYu75^+~VwW@{>tCpyI}MxH zjRs^B=QS`1#9Xr3{CF@DQ>!>0K_;+uv=(xiNpE+>gq~sF%(# z%FLSTFS+Mf>&J9`p97az)51=dIKrncGheMD@B5GMljFV|p-WJZwMR2(_aLt_OX#Iv zZ|K6&+GWi5&p8&Vu+FOspsD!txwT_@DCUgm`7cAfBRC|0R%Ruuu{9X09DB}DiRWCJ zi9)Vw97qm$a9neR1igbW{M@5aHSJ69<1#%Shpa0zP_g8~s2IW_xclhpyD0biT11dP zblQtJRTtRj25ezz)8V95!|7r>oohrtgxzoZR@=1Y;&!~8n5cXp$X3E@iOWF%GRwm&kCOy*&=PiD--;W* zxB#$T4y5#Ef4}n{)t?`4GVVVK=*fokz{bx11H}Fzo z8p7NYKEo0RATn#4$8s^-TC5Gju%0$KSts6Lph5A(j_g8?Gf>PuJ|sJ5v!Ji0Bp)P$ zwaf_%DzjMh`()X$|6&oF@(&Z3o*7>s= z=&o9)_rwApI3vFz`fv~_7f&S}df1N5gVQxM;~=ZUWT8wa)f{q-)&MQGG(k6j^qVWR z2|4A-uS%XB>Br;TAjvBqaE{!s}=%PjgH46vl$*R%T>G|<^N#DF;c zCl<~PVQQgGl(59;%5xy2lWAo-ZDG1O8h2tcFbAxe_-5#(>xr$k zfIj}pdwvK^a;jCu9}ecju^x@5NBjPFuCXUo;C5P$7N~sMLyTefxwzE}12|UWyUnhz z@INdWPpaGRnJp<_8NjNdaw4D0Si8aYFV<7E4L87eBm0wuS^lYI4CeJm5;s_PW7FGq z6?InHtH|QP&EUi9#42K^o1s<{5sGdQBB5j9(95Ueu}H>$VF|ZQF)9)IK|DG-M}1XVoZ-Z$H2EZaVbZVk2cT z#iZ&W4Gin8pw=f55(w00t6Rq~x;-+)|5M$HpV@OCm$El0--V`;5LK?jrSt4a4zgpG z+>0zepgO2ZVth~VW|#B9-?`s%sx$GpSF;|7&x1|J7=gtR!@zc$2%u6-i& zxTX8SX*$mvc7@qXJv2SUCAb7+hzd|(BFB9`~{$XRD zc3|EOCED+L8a|#HpUA@dK9^pQWndWAC^Q)sI})6`eU?VQ4T*G3okt8C>da!LFI&H< zH0d8a*Y$j{5S5ovcp6m*;0Yyua3;$S)?M4bGt_`M+s^dU(icD3m&NVhlk>t$jUXHn z*R<-l+eXtNIlCLVXWMoN)Le^TY(bN#a9lU`s# ziE(*H$GgV~!mdCvc717v?_#mrNNlNr2$(RU&AW={V3{BXAv^}vC00piNOwElqtPSc z^11c)a&BK(zxi&=Y9W1D4fZYP=>BNGCT`Vfx4g?db82STR9Y7!0G53EB4mRrkcR7*nLBT#T+$YTqC_2L{aOBl9#!!K|X62KSgUDFBt&B zC}3_1GNkuIUU2<EasYa>p3`Pe+8(r=RB2O6uyL79mu`mJE{z&vLr@IIN+e5qs;s zg#tykbfq&2=Lwo)+;w*Tq@h($gmpab&Gk60QLkG~)qB1si2aUNtgXDzfik44`>^Z! zZy0tBCJJ^cJXq8z4!?YXo zp_Cq3ho=E{r58kuU{#2b;j13@qVjm=W$P|S1Er2^*l8~hv5A{*-Ut8B?l*e(7&af` zF~;MEckH^a52)0DA*J6SQH2}xnZu<76@-%x@gq3M(>~jjTTnJ@BiCr!;!#*8?9uiE*QP1OroSHx`R*twaS*3E->ujv-<+eH7f=Eqf= zQTujTexv6J(KdfQ1JnKWu=0hqJ#}U`Zdtk#=Od^2MJ~xO>w|);TjU^V8YaEx&~P)B7yOn{n$!$+U-AfxJlOz_$Vy0po1YIOo$uWP?Bwl52QQPg(*@quwBC%x$qodsV#kVs@=J*g*jyjuQnDd9j+E9)nDzhcxRqIu;-@VVp5GE$E z^NpAJ8^8bULjfWTh?%(#p^e%g?(+e=f#nD0j6LK}3^@zn@faXyfgj}Xx8=#83Kn9o zh@Xv`pXq6}6bD6=1uS#B&3KJdhhB(Y_u8aNjQIhqtKkwT5*9fKvm=kDon+~KUOs1l z4$g2oJGMLj#>4`6at(edfw{XcN`%?`QbEe6Eof}%YN~9X>8lr~v+tXqzk363JZ#uC zZ^ksUv_76NgZ8=?h-FcW&Cv%8=9t#!O~>U6N6nI3@w@QLv)axpQCIzIe$(L)uA`;h z);JW@)_k+9P}ixj#+^DxDL%FEtPnOzFa*+k31cBiqQpWqhuKY6@w1B6_03PR*cMs+ z$BGnVedga+dyal{&l*hehlUhhzgp@;wxHe3@wTUl8FVn;r42Xv zoJrm4CW}GCU7E7ju3oiAr*r8LmAN4%eX{)E_~&KlZeNCv_HY z{9cglGTo=3Wv^1RBpHJYKzg)x%2H9d`g6&ghG>qBu@c+fAurOeE;JjC=${Y5r9uMA z)_6MlXAC}2I*({b13{aki1cM3Xw$a%-V*jE+K6*baC$!Byj5>ft55!MIUv;k^B&`W zacQhLtavBRvIbu|<_TK403mL<(|8n4G!tBxOg;K3^6($Nhvn0ZnTd)2SmCZs8r((w zWgCv!2I`H)CXEH^vXADcZK@7Cbv1xFKSG(~P?>u=X8SbIE{%Y#DuT;__&pZ8%Y+kv zpDy#$u)t9zuAgCN6R?tNh>icPLm#pSkA$~h`;XMAiuw8K;)6oMY*v57KEyZcxz4?? zZXCp2IG^@3vFU-#!Em$5M-a7uR;swlqm5?P;GJQG$8r6_LKoPh{vP{1|K=CVbbfPC z`-@t-o1o_s7yGyC%2&O+HmMe1W+?yBrSzkZ>%UWlBNk4uCT)O^%pWSiTFEdx>)E(o@(iB(!mLnLM#X$aJ= z@9s&g*a%u2bauNZ(EbBJCIFti?KtEA5n($2GCmRaht`MDp72j65z| zsKGzeY4TnEsn5TkCED6`PJ{0SmaDk4tcRj-@_}=gBLfbfxAHO_|4{~lC2i`}OC^S- zpu3dk?=UQ1j@j01&o1b1Uuwfa{ys$PieB5$=~i+^yrJda+Bx&z7h2eUDBmM5{rL6c z)5d>xLhPktex}=qr9x=%cGh5$LfmRxufyL6I<9+f@8xUVd#rHbj($vf@|%go4F6f; z(Xj(hv0*ZPP!Y*;EX?gW*}0b2nOe1C(KxQsu@vuGeC9mcIH5l}BtY*u@aP{>?x@=SS%}KY!K8|D)rM!W zh=|Cc_Ep*HoXkWIrjqG{IN0fLUv4mNLxv3;a9cmld73!6|LtxTSSF#iUBAKS{}SBn z?2c?ge`xZ_CW!4@>yt!&85+`_>HtMQmomMZ!YiI_1|pT0R}T~KW`pS-Z9V2$LOjtj zIjFNt$I|!3R??swO*8HKWM=+`&jU8$;H7KX??^4Do%UxgpgTXMJ2|)A<*2H#MC#Ys zY)82~W3O5tin@g}x&@V+kPCXSjgvUn=xWy0=1`|D)9r6pdDGr>Z}>5;Z@Qux^qUlZO_&`m z;q=UT`?&dvev5nQ=+6nmegrc$O3#}YCbO?`NB_Z3@vRA`Mp;}2boEQ*bvXh;l1%dJ za-X{5+&RdYbEabj?~+_!eMwYK%5e`vlKrAhXz2Sk8z=q59-Zv;xUd*0>%d>0Hz(|l zg`zk@#=9g`jqOW<0glNFNFmjsry4iSw;y<@zufWk_Yv-S)h~_y1LPIIk?3xgD5-nL z$Hyi0Mfv&Bbgqqq`jAW5t&~em1Kb8>Cxg2e3cXcO%9X6&oeGv1Os)&C-pUtq8j0q^ zX5R47JF-xF1*c7W(obzZYoO>CA&QZHnZ zxUPZ0Q=n$d`TF&zI6bNw4mT5?&i;1qta065(sSy&Wrzb?)}f59x!-z0p3U}j-8WOE z0OU2YwKUhdfnZH*Kc^i!Ub3B% zF`~Y=5=49I+oQWLUTE`!tUtg|`bp8w>E6i3Qg)E?ijo5Xr}k^5Dbts~q;r;GQ@)Di%qXPR zz5X;0*YGZd!?zD02aA=Et)iu-E!dwA(#Ezr%lZ>$rgp|kmzm$|E4$ZwhrWM2zLdI; zjM4Nit5oloUDZ8?m0?3Y3`Y!nVBfy6ul%Z^mDrlX&?5UG|Bg1VOU%IpMCD|_XrNy1 z31ccb)kA8V(@V?)TNkXZYABFg7EW515X!b3KFuf0KBS za>w84=PX{ZW)8ilxO?wI|2^@mDKLRA{BXS{+!PU`Mjd|}M+~cUq z?znj6Hn_`5oHs>SSolx-XS%I&ut@rjaQ@bEiAa?v0AZc8P5#CQceZ-L_M2Ng2pkse zLWM@;I9S3R2wAz96^H-PCl2-yvOqpmAAJZ~$w&%{BtamdTdQl(ILb&9w9x&2@0r72 zpj!yyxGc&$n(OURNF|O;H^@tghBu%5;oR$OJq#2m!1!_SES7G2jQ;5qY;^cOU3Ek` z6)!Xv-!R_gV}?t<%6*k{m0zg8zFX=7)w1|)4=>e_d*Ljzo+sRL1Ys0JM350wb5*`PD#S9EWmn8nVZh>xr*3TGRNolJv|Jb30%Ydz?E)Jb} zgaYIGW@da~*IkA3+YlKf)gK5dH)PntQY2+PocOyW?Q3n|(LWPjk>$L5nX7{GZWu5~4U&;Ph`5K}j z8a+v4JvqNW0R_7Uqh)QsnF=xo=1$>)m`(qsPEGT8L~)WW7v1qv*s!Zm{AcpsGuK+Z zD5ZFMo~Wn>z3KSG+-tI?FC|Wfh$HVN>_kWgd$!LBxc7${OkigSvsLDqUGkwvUtRlf z1;t!b16C&QlckrEWJ0@E;w6_V_X5p@=_WOew<$S!vOP}Q8yjrYkJ@#h=c8DSX2Rb10rt}K4W0J$z=EPz5g4aQoa#VtKq>RLZ!Y%mj z2e6A}HbeF>$=YTlUyE|e{T|c^Ms;@h=oNwa#40h5%_;m2OU5ymo}ir_pQE)$2!=AE zy4j@r`Rj=NKk_%(KD=jz*rrm<3oBcxW2dn$M0>vSxXAYF0$0^Z1SzNR{me&^u(M5j z(bt0sQ+~_qda`{<#9sb6-dm~KxQWZL=y;wd$ax=)I@hC3|YFB}7qPe7gi>3Q?CybU355nTZJx(8YR+k!?F2ITSsa->}!O zHEZ$<%iWks%^1dJ&J54Uc;YmnlQ=M;hNKBiH1$qS1Jdem>YM&e{k>ucXJTbPIW#JC zv%X%U?q7FIe5R zIiLEnz7wnb$RX7MIaQf4c(OzxLkUhG} zvOhteFdJO7Zt~CNG|$E7F^*-KR%a$Zw}5YfinCh%s=FGJG8T@z{Hc3`%cU*D&qHcP zN=O*mV{z}Eit6$=HkkBp5?s66sq!?DlYfSNn_xumGBPo~VJro6v@|&UvLX;-bYQRo zNy`H(z1O+z)pD#UeI(p~NO%=3db<4CR9|%crNha^!r3lILl}lzAYYkTuZEt-UAt#wC)?9+cs{WA4{CLFEBITn3F@ zpEx=eNQ>C@+`i-cn{qzI4dVF(Z0P>Ow8wZGdi1mV;#N^l?Wd745yI@&Prp|vnD`23 zpL3#?Q49Uu(LD=2e;=zjD#nUhWFGl5xjM9>nZoNx*+7%Us31T8dt%^*F(P(YV+tKk zApOSE-TfCbVbni~*ZHe{~;miN)tbLu|Y(YSh^gW(yl4 zimd4C@(g_0H#Y@JC3j6&7=9SQx7IpLKi}u(?*1_KnEO_Ie0(S1n?l-+v{blh9G`>D z{=FZ<4!38xY31BS&sq$+gFhVR#77-u)GHR&FC9>xO#c1r&?=vDIQ}z=6gogEWcM-< zNUUYYEv*-o)y(HV#wVN#o6Z~l$$iV9{op`ZID}a(2kYV{Mg5}8PZwysOa0`E?mK?{ zGXb_;^62Cy^%po9!vpHJTE!IzI%DRj6U#{e_#Gvw7Yxo$=r0X?x@~+y(_N_N?=D#3 zlF!D^qWo|2*#O*LBM94~vlk_D*+nu>A|`OST~_#}=W(NCPSvT0@$PC%nJI^CAg;fn zDEIMn3w_?b7=6W)kb>ZYthVL^aw@Yf)&6K-np4$^VdEfi=O0tGBEdIlf4Un`z5r?^ zCkXY@SU?psxI626injR`Ex`NXW(mw;B~9a=9`}&AnH0LCV(?v?r=o_ z#_%H|6#=)w+u(mwk$Q7T!f~%R({I^B+aBWDxJe(&@0iR!a)X^^M0c3gOY%i_dHs`9 z@m%+?Uidr5)%qtM%<2K+@@)w8^G^B)N&ypXrIid*fnZtYGVtKb-tJ(LXBXIRzzmkb zMxLU|psS4IUA!GkWi5F%F6ZgUf23C(rR@|{pwql<+qpJ;|IT~Mpt@MQp()5WOYM^5 z9+pdGn^D3?*32opat9xeRw)X>_JB+JyhH0sM$7j-hY4ayVV}-4by)m_lI3K4eUHpt7+)OIw=3qOIrp zB}QzTvS*&(AID};TxE7-W!?fiD{fxBBc7Tdl`i2`c-6XTuZw#RjL(bbZ31c3E&9es zac{!!K`M9OyuSD#Q%_F2eSkTfaX(d6f%d@dVzkWkak5GE+=}1i2bYY8XQJYnD~}EX zjd8CJ5V+{(fV~PA8SlBl3Y%{7!JSCSqe_Q;_d4IsGMCg{_MZLrm2Ob?+%JEZVf4X% zXz6%Ah%eCHNVb31dF@^u(j1e)t11+qk|DDXLAK9Z2>g*X??SM3E;%OXfATd=q}gV$ zQzxCag5^Y#e#8O)G0f*sdVJ}c(VC)5opROp0ePmr=(QsAO7!?{f5V(*XaApSWY!sF ziRMau!Uq{^5Bq_3$Hg{$6=W6>BXeE^UE_(qPsqwp5G2qjllK~I@l{2}#_ES~K*1xQ zSpN}|L|d^h65)-loMe(J?W1r=%IJRf_AsOp^(|-@{pS*$oM5wWbbA-6W1&b(VgOZu z0Ah~POK2-q{Q{%;;5ci^(#AqJ&!@>oX$~CVi#v-GCodc#F{t z7ZAOeUGO4N7k*~EYwr@524M|LxV4hac~tzq9g&*31_^y}tiocNqBksHR@)ezpF?A!cpRSXt%7n1x8unsME~@1S?A0^J^))0CGFaiJ@i)czZZ zW;$JD!ri}2vyEZTe5DuqxNOutn|5+|U9Elwu$S(eS;WEJrU4X1A%AXg#W-~9DkT&%k<#eFLK0k@`I z21-^&U`|udx+D#C`dJ%Mg}g(S zH>1bG(Or8@cHEZ^HOi1N_<`e4R+~|3+33l*z2l+l#$mu+gPw+N=tJtk0FIm9hFGQV z7?{Y&*7|$&)Uizp!I0Bk>J(LO(e6>#X;-d?TmCY?HVB5=yIcgf;w5{|h`s-Y>|-Xs zKFj4M$r%&l3sPvOpk-OPD%n}X61-F_SazPA%*a@^2|AN?v@E}^R>poa<^fBC_S`v5 z8}!#vb(;GD`Ou;G>z%oLbH*}rXLCbCM;P(w$|J8~d-m~^pabzC_I>BvAi}d(`#DIL z39y#xzHzNfTyDEkV1V%ndV{0&!&Rs595*MRSAALK837QLXQZ5e2-UojLBq?iksv8~ z_mh-YT3U8R%m@*UyVtd zH#NKPB=jGO))8iQTvN+*_2OE!(KnS^;`bq76T0)I0yum&ceA?wnVntk(!YO`pp;}? z!ppjyR23E9OBb#MTonh4hi5z^fYL3rWGwqGXURKZ&(#59vr-7=+3VRb_xAD<*iwAO ztP+%ZzDM(+A>Zz=yu(_6O`YT2VDA$*SObv=hL5_y(#)wBFC}n56Et1pQ95eC0NC|m z8$hoo&O{Q4L7AaTO(onRRo@6%rRPhJvXH|)xDHvbqc!)w0jiveZ-9&0b@g>TvzpK` z=dFcMse)@?b*cW7J@ZDI!xK`%YBra$S!lem_B>{TldNgCn%dG)i(n((sroC z|Gs-SS@E7U`hfQ8C3Sl5PicRVDu(rERLRE^rxw>$p_SdgjyPWB_@ou5Lsu6vX2)pz zg>bPcE)Bnl=+mG*b7gZY|DK|LuSxvf5-CZRoseMg`j9nJv43;|&j$qlyP5imc4Db67c^psp) zinBd}cKC5;r5%$ud;3Zd)0hIWY?xK01BQ7lwgq&VJ+T)pc@adFQFp1nPzpkY;Gh4u6J{H*OS5jjkdSCzD_ZH6 zXVQ?J(~aU0f1YvM$EnEs+arz=jf0)>QrE$4gKqn-;i7*RqTYY_@|NS?CLnp z(QCL@<=}gCQQ7Ri0i(BfcnC0(wLp07+)9PjO3JNqCBNYeg4ojT_xuRRPF`bvOrhh| z=v$0!T|xUzm*MEqGL0s!$PND=^!b`w9WMFf?KcR*MI#41cCn|Svr*{txU@^D@&&9u zxGQgyf4oxC7QUq*LgE>A{Mggy*(wmLg0kh0N53pn0Hbg$xWxEW@!!*#nLwv0!%F)p za+Ufr^f@wov~KBICzZM12H1|IQ#s;X8vCJ8X-(iqXm)a!i#JvSFu#hbKzNH(qgZW-;!P?xes{u50nsL2mS?$|l? ziip9q|5c#-mAII2R;cX40>jTAm^0b#G_PTjVMO^-BI{S|(5N*&B!p?cugo5A17 z8B5dGfRK{^GFI56|G3^~&AgQ~Kyc{P{oer9QgdVqyR_OzPEUXDEn|1YP%{ZdXwjF0 z-EFVEt#Ra4{rluJ+T`BX?UY-EX!_5}ou?}mJsHQNGT142FsYF4h+efrdTI=>4--yW z-1cYwtqxRgW^ecMKepzY4o!yFRi_I}Of@gEE)x9{j{%h7*8mH+!rvxG2m90L#U)(S zu_o1rdPVP1T@?pefM)(TFOFEO>`m99FBB=(A<=*KCic*y`#rCTwp+cS2*Z6?#*ry! z*EAYp>s$7U7j*0E)xzkua+_oD)xJd$N3YBZ6al7;ozILFKOTIu7rcT-V0&{=5FrVvMOJ1#}mtB z9MjX!?YWqxS>7;QW@!BO(iE0PN4lzZd`zW?1{X}RE>)hCGDqb+E{&^ zp}83B^)=@c`CR>5?zrf+v_+A|V496PaQjF+>&pVorOOFkeBeFurMuauB)$nXDtgo7 znI&{bOG+W&9~AZj4{gSf6YQurO5*unVG(?HwkIBpS{0Dp6-g#|2AjSoUW5K-*=n3I z^Wd?vM8{|U+NUL?2^E)@|H`nij>D+Gd5tq^{OgCtHw4ZhryD*MWLu^e(3slDKctzidLpRO4RZf$zX6y zWgW4KAJT2Hy)(KcBz;))&jEUEIHW&0@{W*_663C|+$n0@oZ>^;-u|9V*B8!MySGpK za$8uN%(%H7af=;Mu5M7CsgyYxa~q_S2nV+FM&tU<-XqMv6RrZ&W`)88X}0$)du&ai z2-cUzIBmHiW|2{mCyTSBgMl!R!)JQ>W)l;59ox*~Bkrz*@e3iUo+3%&BN4yw#}p=< zwXSLQr5(kug1tLWq{4ox_qy=tQ+o#M2*!6A8Z)u|XNa~f_@=!@y)r)A^3JV=9OedC zES73dR2~_`CYy7J6T7qW?sqR0`}6e@4%bvXBDzZ0$RV%7jGZjv3x7o@*%8p5swZOVhd(=B1g(H zIFB#BPdrE_5+EPEDPxQwSt!rgO5{%=l7wdDnJI}?xSAaX?*T+U#`l(L)o|}{s=^QT z!oSBfFdsx4eSY^s3Po~?wf7rp1goFV2$@Ujm)>O@m?#se)z)%*@w9YX!AQGI76Hb&#C88yrB3Wq4a7i>v1+Tfy5)Ha21BFU? zX#o`uZJEbq%`a&>806e*N7ohO`ee;Ng@?EDWj1Jo>y%jow|7T<_kYa_4FTRG#^zxp zo~6C6#mq-BnR;FOEK*M!JwfC+*`P5b^nz8I+hU)UmF73sD!z!H zzijpu=UB~mD7C!{Hb?)xtQaL2&{DsZ;`o7jZl5XPeF#8uazkXS?jXH-WQaQ@fS#rC zIJiEf3#>p?jA|fO@$&K#wEm~&_~J#y7F@==_zImU&!*AoMhJxs*aLWIVrlu!}&4Cz#A)uXqJDPkN)NJCtmeXRP^Y@MCATR?{l71IT4p2~(k-Q$5ZpZLJ)*52kcPX0Z^bfbUfzsC3^J6PJ_qEV%)PAG#bs4MLuCnTwd$=$mc?J1IG z5%u965uuK!B@W-v{swl|{)tSN+?vS9tr%dX;vt_A{(;Xdio{RruhKqz)*i*gODI_pK1LZq?*9 z?V$=`FB7*ih(w_oh2VZj%+Mh>jDU!fKYEpr)s(>J#~;J!0RnA667%?N@UB$RyB*ED z15x<}#75t*_m^$YK3qLa>R*XF55NE})~u-zJdyNW{48cObAqao-NGHXE!ynNwH!8K zC<2u#z$|fWOw7E@G$#f`g7?X(_@A~*1%6s$CXC3`1|Ka!E4~t6A^xbDX!5TeR=^W- zS?bi8?d?j(788P;{QMLdbP_fnBZLU=qQ?daV)gY?1U&4%lgA#G5N5L|N8T)%t8&43 zyCO?#D5P>OoS0x+JxPdtGAgHexj*K5uP{txvC31^fL1WBEn=~ zD~tKD?d2YS){=3)tq&(Qx*32!4}>ra^Nm5dHAi=ST7ywC{$> z6{h~jGALK*wk9Lfz#b^d#QWcf?4ZLmGxMpJ&m=!B4P+B8D_NS1p6*!i5VZlTBzWrow$$ z)n97pc41MG?fkFz6@eX*`r{jKg3eAl$vT*rMCWcE5>ZgxklVW+R|@LfHz4H_Wx<=%A=Y*f_TV_8j_YKqQH|Xfq;NqF{n=xj-XIb z1WH7dD#)QgRjd+HQH~}+QHd?NB%<7+7!4vIBBDZsC`3d>ij{{K1?8~F6~R2v&W7fn zyli%7XJ_^|JKyf?d~11KsUfr*d5c-uj|ANaq4)I1ic?c^TXas!V|z*CcAdHY?7cO5 zp(1vlf?6X9%C_)hhkPF;Ncbr!Mr@ot#Ya0vB~6e>r>wp{R6G6A$-StO=p$y-g#>c91#FZ}byRC{CU;af8)^ z0*~0jtgMAYFKWv7#Kuzl_$-kBhgWxY(&_Xvz{~Psk!FaryGsySe#!Oar!rZQ;Gm$j zMQ2H(7~UY4avDd11FKh5Ol-b}1Y@!QPf_7>`yc63tp4}IimR*HaCjWuOt-SKf;0qg zd^TJuhc|dU%eqA%5GGt=L*eH-!08-Pj{QCUx6sz&R z)rsH>Hjxiq{t%}soSjW+Q>!gb^uM`2zAb|Yb{OnJxT*U@saC|<-~B)|IAb@`b+|eB zgLz?*Ab2VYt!LEVPMVLIRlan%qF&cJXT6&my=cX0lZ>b(_{8+4bLTvyU&AL%;Rzx5 z3**b50XM02=nS27LI$Tl>>{s z>f`irH?tAXZtIY$8?~_oJ@2|+{&aM%e(+#gyD^ZG)eb;VXz?Vja5nMkY>euFOG_pV z_AQ9pgp8a*Cbxta;-T$GFM7Do@NPp)mv@4yB$oR&?&ezPlE?A^m2iV;^;fNV(p@8} zION}7!h%5oC{mXtJRqFPDjU@=U&AO*p|p1 zOe)E&iF_%9N>*SQWPXi~ zgsuZ+&bqqaX+XUfzAS5q^~JPRDBWdBIhL`Q*Q5u<%Y`-2 zz@R83qe{o_CJOx0H)?A(pEun)c1NL5&QwguIF`Jr3k#B=y(=l6gkHZ`wq)N1jP376 z5;>!O3y!Mht%x=_^^`T;l}| t>{hWMUk3Yfh0UZV`~}{jJh@`#tDcoZvs+kaI2!|>P2K@sS2skY{|Bh*ijx2U delta 130837 zcmZU51ymecvo#tV1}DMYLx2FmJq#W^2_7_9fZ#T``w-lM1$TFM5AN>n&fmHBe(!zn z{;UCJF|($-&#BtAYu9cTextUpp+*v-1|q+Jfq|J5s`^w$8HEA&_8qhmLk_|rwaN+n zndGa4qAKtk4)_MXU?qSb41fOyp2L>f7KHmq!@!8ZNK1&SI>8>Kpy;ViUUn-YNBW9@ z!83+YFt2O9CP)cC7op{LRjF5gX05hT%VPRmB+DGEx%k*nIklK?kHnLop*~g*<4sY{ zAn^%K8kvTMP9*yI(aJV}-*G9)87dboy~QuHWIKKBdfk+8z2$bDWx3Q?r(g;_#pZ#w zV&bE&h*E^X(O@wxNJ3Y!rBFoRXwp$Wcy@Y0l|T~E6-=ZG1{^&&;GK-f%?J!4XObNV z&@wC$s3#U00&3*D7f>%8=?W1LDJ;Z``+d60Q(U?8l0~1;f$47Ka)tbb$9_M)@@?8~ zbltJ&xO49?6)9h3kVgfS1~|@tJ^G~5%gdGX3kr<(r;7Tfd9MNyz@C2|bBtc$r2I1P z-}~F`j%TNkQDTMs^$G<6ENbKz>@R#MkuZNhps%oALTIqP=IqT44<`xxrjBE!fBh8C z-qu#6Q96ETC_kDDQhwa+iOwOxyA!wz&N6bm92vyJp@98Aj}wXyDk{{Qo11uK&ZVob z|9Q=n5e`JPxv>FuadDC5>T~$}PJwra5_?&J=u8< znwZ)>vL_Q#Mzv~Wd)d%06!p)-{CMw_!f=jBD&PbqaWq>at#JrR=6Ed7qXScDrRyVpNqo0tZZK~bbtr_3`^VKTDyEt2)`Fr~o& z!ZvzK6|R)}uU!H8dEV)_94sYe+1?GTCX7qeKU-xOlHU)UJW7|V-FBlXJ4_E@H}&xy zF!VKSBnCb%i2mP25P{P{2!;9Da9DjVvnBMONcJM2Ia!Yo-kV|&F%#Xf2u1)?Na%f< zboo@8ClPDG1kKpPP%bxu#xPG?#O}?#N}t6@&c z{1tG*iQN&|(ok3sB_v%Ec|uL2Z%>z;wThVgePvwPF>EyC2hMGlV<_1CkhBZxL9I!^ z61el;Mbzt}@q8>RYyodf|L9*yW~v5@p2WPk#5lJ)-=-*gydr03d8YV1#fps_`N~`apN!((@tB@Dzn^5Y(eImd5e|c>=UZ+_AW0S#^_VvsW5{BTYA`yS6uMZof6Df395;8a^&EaX=%CNNp-Nw5|Pu z7h;Z}J`Mju3vhZWaAG7V|Ac3x0I-}gso&dDBSlnEJUwgh0IzSJaT2IdLos z(Z|TR&o-f^?A^nO{cD&k|3(ZW(BsZ){Kwvzp=Agar)*r3{46iOuEHUgoWIF6`r&%8 zFc1h2vv2&M*Z`VDdy5RsO)A?i(v}eu91rINcrOWV)&KAwj+T?SbA4lg<7-cZaA)+iDe;thd=x`OuOW@b2l4 z^UeL>DyDBKcfat#`kQhW)EiQDRQQOy3;qmXhXh0)6l8%ujHqUPfMHA(o>XD5(Djj zgWP`w2{Ma__f2koesCu^y$jjU*jU+j;!EW$2qjXa90ct7r(uM9QMkj9*7E#I+i9${ zfpPi$eJnW?fB$#wV$>znsTDS10(rjR^B*7-4jKtr?-}F_S_$FydP|j-B--Nw1~6ZV zOz(aSBM$~C>mz6Vt~5G@dWJI)PJKye*U^7N+c=1!>G0L;MH-L675#C4i_DZ)K-b_j z&Pyg8SM@1j>j1F4<-}HfD6hILTP=qf8QnkO{6BavGKvhIoSY1G>s%erKmegIQu{=? zYvS<{0|;ws|0i|t81<0A>5JGmb{$N0MLQ5>?GT2X%dt>}-6q+PPz|Ms_D%7p03pjo zoVu2sfe*LmFG6G31z+sL(V5|JZ!!KH-{?BdtGaXOzFbhcGjR})&SEYbxB7HDUSSZs zw3TKJ9K-K?g#aiSR1g|`uQ`nUY^SwvSzA5i23O4cqtrCV(dH84e4T^yg)b)#JZWpR zSk;b)0%zs^RQw*b8n8=AGy6FQ{Qtz--(_kK2boDEzpzkF8!T|9PCc3}8>eobgz=}O zikJiYlgE`?A&+C)f*{1e7Co>2ph%h?rSWPK&8M_VLqV5S>{a3qLV`YIrC>S3OnkM? zvx)qY&5m-ayvdA=yR!yk!d_MU+1?FKgyT=Ab&btdd2@v$8ZFC(28tD74(s zJYoC+Ctq*ozwkfO4I#fdo|YEUERn_SLPL2Wz{;uO@_cTz8~M9Q4J)gZR#e+{7PS^*g0rLtXSomoUV#NX6P?zwFJ>(bX%VL|*O8F{>I6 zZOJ5*>eXAQ!O=lrmE8q3Fc%cBcBkl7W0`|bwuX}SX+LL)0uW109jS#dfu*-kUa!rh z>TdVft5%`=1M0fEx;!-Mt_YH-pe06K zN=LVd9VsPr7m92bQ4i#(a3&&_;~y;3*b!!XZgk(w87j=DQ*FPCVvY-)^oP;F~KxYP;@F{>_r?# zCAh3awF2+yLXWoxr`ynXRPHF64`C#;-viw~Lz}6nU@xJoRFaV8BIVoubDQgm9xl*1 z35jE!1YYjlG9-H=QQAi1hx-HL_+t%Wk9IiXzjwjs&o0=c&hIHH1G_LnaxV`@Gx`zO zg)Tac&!3snJnr%eKUL7tRI_KhTpzKz9+U;3lk%woSf}SuGjAj>ABKmI-v=4bmfdVP zZie>v_m>)UZSSOu`WT+9w2ikwAfl=yiM?m^X5Oj@7|$=Bb_A7gCXcB-ELvqVRok^+~ZKB6ZTFr6j~+XimnAUd4jB zH@WzKAQ{nNE@&R`Qfjq!@MLk%xml?OFa*&X5J<_`;?fJ8@& z4ApZfa~PFdd^)jTcpSLfU5$3!y|jswmGCNWu!`*G(FtqFA8t5&eXDW=tqf0Ddp+=P z-g1}*tk&T(NzEp87EB&%n&4Fm!rTk5p`@DLsl?BVvlkbb(PMS?%RiMoH-xPyoZ>l6 z!Uq$%WGNaULB>cV)}9A-+o@yamA93^l@AbqYs4n#qMsAR$HVK5k|JYVY;cT-Wu+Y_ zb3I_6E!FqgE)#2X=){(C%Bk{8fyOnlp)t$0*P9utf7Z)VE){g|l-74nG&dML*tVN= znExnTaeQ<()9~Bu2``7VbfsI3@klD``S!@PzH~)JMO8VmnenUt1~Moq76zo! z2u?HBow;i}Z7EkAd_1e-B6w1mWn|2i?`D8Dsixk$SJ5qPS$7?gp|r17a)El}qRNLg z%V@^^Z?w;%0}8wHd1K9wOogn751PEjS5O3S`YlS#x7*pXzM4!vp$Q|1gsQ^;|u$JqP4(K%Ea0_z`$Iz6Y0u#@6_OiHQlv zhQ(%5>ElNR4PAG8Eu;7ZfckQKb%hWP#4xIey<}^?`SM81SeZ#$(sU0CCXn(8#-=PhDX!o6{nUi#~6%F@{&4dHo<}R zZ)VpOVvn}9aF~gI|BJyXM*`Wv=rle*N(msizXCyn44kDWjIUHue!gT~H)3^Ys6zB~ zljh2U{16y6nnx62>t-i2q7j$)3S!mrcxAidg(PETWi{buDTr;b(M70hF|JSIxL{Mh z=rGTf7hbJZ+k_g~oe|YxRRwYJ=3Rf!P6tdgm)hfqo^BFI~MulnFHWr0(<+0UvIJI3{)r1W*$idJ^FwP^W{ z_SudPlH5&#f=3xSBEM1`V!ervzn%8V=eWQA*G@#o0Xxy>YBj_86GDyz3orvQFg^LP-~=M$J^y;ZEvF!D8B&hSKt4#@{d7L z6VEbG)oD<;>D&oa%sJ`1(LwTdwOYxXRLha_SVZVzC<8c~sXSqCdZI0$cleW_oUw90 zE2D^6wn{h~N?@y@kf(t?y#9DN-yXx^Lj)W0TO4FD5y(rmHC(rowGI+*d0;Q9Wo}2sJ_PA2NUyMew`in6t;h>zCm)G|Gum;JhhPNj{n+FlhjZq8*7$za4 zk`Qk4yAU+GfGxWIJs+{BczxnZ;k3_)^ylqRf;MGMb*e7HG)6A-skik_m7&AYkaPHP z=K%e%VjskRE%qF}mmx02kJ#9Lpy*YxDNGk@8}*PnTBNNwt9l_@d!LHLizN`S>9Ex1 ztfKjWDIV{yv9cjHehA7xV2T5(XgBZbO;O=*0>ykM@>F_qRB zjJnKPH5}3*k=lJ2ztwfQ zr&%L`=B9915pob$!P-8lf!}p@(|>zr-}RaFC-S!WT`Gh=U~1^LB9pW&V1|30{@ZcQ zbwasS0=w?iJtXN-1B)y>ll&)H45PAAdcsK&2VY>k!eeIsEiD3QVw+fy8y}0=a!JV7 zy2I-EEKb+!qahi8xU4N~iXosPlDVCTx*sXLTSa)u?_jZVJ`>X`=P+v+#Lm!gSx=O^`Fu%kIrf+AuwEO9n6&GAZ?K{~8LeC$Aa_HWV0Q`Rc zrh>-gffv@61MR;n50DH@*kEp0oK7h;0+!KVFwpw;ymz^lbCuFUPd5f_Wi6CX0`PSv;Cf|2nv$KpV`6C7+Z#nq%g^7CofvA0j+7{>3$pxfoHq9-Kf$BNx1a7`UbwN70}awk z$b@Ba>{^Hit7gk{bKjeC5097)`No{SON6}iiz{=Z-=RF-hGB`n*3-py?U#Qmoxh3t zN2U6QzfxQx(|q>4xZO_M5311aX*V@o&3t3G^I`Vuuau2HMD+H2d;h>Xl$6U%wK7Bh zYqb*!inu>|6d-EyvM9PjmSB2bavJvn9l@pk7v-Z4On$lX-@oS%^m*RD@wGXb)X?3P z&RK+)QY{j^UQoHaI^3tL3OU3Qx)D(?*2;@OG-xS88=dQtUKOom^1{GRim^6=nvnA` znA{W=qVG;s$$oU%%wbZ?kug)O%zNf!gg?)ejjs z8U*<_xJR1EubP67&2Z`DJ}5Quan*-ce=co8iIk~PmlZXxUTO9}_9;V;iUwISDEXId zOdpMXPt_PoSNv+b+u{MIt>kqt(xBh*;ua{#8@kVT8WJtVwQH!e`T?X=SKpCPh~PkFi`E?& zE}T)`L@F)Q(b$nV z@kk*eD)jrmo7@TlSHkQ<6@^YyNaiYct5{fACa}>HsYE`Peep{ToSKLTM9$?=LvJPn z0I@h6#?RpW1i9Q2MoVmLHAJmI9i`K>GzYnD4WEJ%j-XqVrK5Jn^|;Bv$o%^*fERTt z-IzSounV{$(?9Zpwy2j89rh-a&dzN!s&%S8GF8>4(fAfaZv}0$pg7Ll0YKGMsLIU+ z>v-I5o}^5vgJ6|`=I1qb1SEG-V!TjH@2(wgUTUw~y*HCE@SbeS0_9`M+3FrzQ2UnveGkdtla0 zw!EF?Y7oi6Bqf~^j%hII+CICh&*od^oezs-cg{P1B<=YIWS@A3UmQ_kH4I~HhXB>A zmg`}a{?FT2)Dor=s~v{li{x4f;JcUwzFJHlax3)!3@e#~Q+4LAY_;G8k+!{=ANa!> zr+uEj%CsDmmmR5y-a~iXPL~vM7lrnz0jfv@@$$v}c$3w;ASFql8Wh1UGPH=rygfpaCSA2!67HVth zm@(CoJDCAt;j~YG`g5|U?nUOXjN1gY|4px5b)i;JWImN7c<3c!5U`#t9-owzsT73| z$tML9VNir3AvZcFyT8)*TJey`ob;SFEiLxvzqS0RS#n|i*(CIE(xJj(D&>kxv3R~7 z$C0_gpM5F~ZTfy^MmdhDUG0vzqe3D-?^^J5>wBzshuQ9C$NBqd z0g&_^e#ja|jU{9CPaP6Y22?xLP6Q|GHh4J$^vAXi5Sfb}vfn(=eZPEb`XNLJMBK%8 zr&r){8W~K8==7oI2^Rjv%@xL~TNGiBvYHw#A|m3Qk!a)U-N}lHj>3u`!tlAnyd^#V zQLO=F@Fm}gH{7khlb60!hxeOMeeR@Je-^d!In!E_!RNW$?0vjuEVS;98JqUNMDkj z&f3!JWpSRi<098l+0ZV{u+zI(JsJsdNrd4u# zduugSYI*M>>0NidqT@X}Q~SK~aZI=|xx7TJw7m(Jb7!U2nx*!26c0b~5`NoYsFXl2 zZ^Bb%YMT!d5}9LdvrU?a^93Or7(1#&qr_4-G2^m(OK-Wx`e6lztX9D~Y(;0sNN;rJ zK1aiSK?;zW2q1^vt(q;^jGw5=rJFc)3XPiz&E}NUVy61<)Z`1O)pw8FCCbke8AO!p zsb{5!dgr8BYwm-3+aMv6EdO7>6(|DqAUZoI{MVr`IV;)VJfwOg%5DS~1`?S>&hnx6 zpHpETJb{w-i`a@07U#ip1s)zUFf@e!PHp~0TI8n+ZW_uezRhx#dSSy$Es z&gel@rNxz6w^5cD1(;99h_{Qhi`$$GEZ;j`WH3xl_)3XM-KHYe>C7fIM!;oR`_?*& zvwXQ%p5t91t_5KC{ms+bIZPVbmg}%666wSi{bRuK3J@aS$UUIbSVE8+y;=9`#Uw4o za@98`!z8zBA#7sJX+x82H~Qq(t+3^fSMxj?xHglnx8>JH`jSmYFo-rKKA_!P@3u3Y zK3me$+??V1i0mLaavR&;3W7IIk(s{?xm{JZhz$72ZLLNY|#2fP<8`+AIg1q`1S zr{f~6<9?~eQ{dtJ#%4`|H8v1z=a8QI^>@y#KRN<#V3)@k?xjy&z|Th3^fyXA1h2Jn zTOvK{%t5GHHeL9iEA@Vfwtio-F#?gUu~P`zE9R` z;U(aYXb=Lpo;xJj*rIk9#FlK+{ZdI7X8r5*X4tvylJoYhj?@m;a2Jq1*@$LV&(!lePVrUYh0Zx)WS51tQA%ak9*TJB!8-@qd>U1IbFXbs=J)h?6~`S9&XQ)OMJZ!)P3F@7*tMDfwNxf zpZ9sYai7*gxQ{xVq&JP;9R-lNfKNCk22M(SMi2!~ZW3Hc6U-kEYnH>~`(UZs0f-hn z$Y$wB=GkoCon||t2TB<}Fz#1Om*5q2KcS};%1^V=?4NKgqutZp*e`1h_*{{#pw1Tl zK>6Al5tieMERk+EWun9@tjbQ!y42-5e*WZ%y{V!X8!Ko7kGuMP>_3y+{|r)0O%Os2 zikA`Mx2%U~QjPgjY3V-urNMdp_D{opNE*z_vJ%vRz|qLLg+A`UKajk!ImF~YSRt64 z??r=vCXO%fg&s^-p!#R6x(Gtp@gI2uf0E33wza?sy^3eShgON1BBs44J@_p(#IUNL z14-d`oboU_(QWrF(DUg7JI;Om^@cl;L`_vSi{3!e-q`k&+>3paKmxD3NWw#>m*MbK zlov>HkTGsLlf&`s5RI!*A-Q4Kg!59yc~P;;%SJD_dY(v-XK~3fwKR{A^ireNV`ORt%qF88(y38 zcXF;}t3o(n1b~fEkmMI(Kpf*1X;td&!#vWy&zCHyvThPnb);`!_eLow9no3|iq~dOQ6NBlArGfLd}mQ9gik&mX=o13hC0v7&riQHd1=cd?hhap zis_!DK^7Htd+pZ}2z0I6hO$ILzgE{1(YaTXc(R>j-CJQUkQ{~XH4q(%opp%EIIttb zQy)nZ=Z*Io&SQQC^pedAs-^Md?MMOY{bw$HEuYJS2}!cKUF3=cqhc_#$0N6%L@^3m(xio)7f^}BSB zAe_Cx3h(+zB&(MSb6$X~A=$@$GyDi*BmIFj`p zfO3X+7rWpqE)uk1cB)@Q9q^|ZJPUfb0C|}VP*y`d=J)8w6B~GaSaKfCa#B4^*nMajkkwAy;aN8{acnT`+n2Q zokhd_gc*AGCqW@=#kQVI%RPApB_R_2sUSx+mjChw{TXVH3Zc+cz@Q9wg534QRHs)) zU?7B=dIo4ID+8zJY0m<3re~May5^@*nuOJq9A3vs%y-t1^LBD1Z%m?2a?rYyJZ7lN z3c05TQN?{+T-+}|89-m>>2q-gWK%OQ{0AhVyB%sks6&(GA#QTLCXhI_!4Sh$G11rm zc~Cy^+KS*%;|3VHNF4NF-sBztDjD|I9W1wnK_?r|))IurHi;UL!EM5{^XWjy<0*3F zo1gF8?jd>r<;x5uVizmvIY-(i^mwJ?e;&sEW!@iy_`-MHLu*AAX_@=}UF&#Y_KK8G zE=l0HKEK?0BOviu)iZ`dto=NDxng=c8$r%(7O*%(A{&O?1=)Tdh^Z^AgM-_Wf6TLNNj`Zp0jj=@X690;=chczcPR7pd#+L={i*a zIO(g`O_)EilMeuqSo1O6j6<&)Spovz7C=*2hX~Hmb`1)^6i6h=_Y}Lj}VQ!t1XVO+hztn_oE9`=w91{i4Sk z$xHx!?u8Ak#EbWxUItzEM#4L@w}zXms3a@ z5??};J_Mw}pjbMiaGZ?8Vcot{kZ`t%fRFM|H*{b%ZD80w3wL&aaXZe`{u$M_7iN*-WdXdsGwWF10n3tk#gT zmLE^<`I-N!Ein8KGx*0xQt*Xiw@{Fe1Kcm= z4LPRDk`9#_)&pN70vlZ#?|Zg1c4&{zTsx_23uL;UwON!eyiL|~Q;p!>I@Do#^&Ylj z)|1gqMX#1_h4ag=eS~eSPTL-m?{eT!|MRE4f)al>&{()8Qs?&*sMiR%P};xEcA?hB zMW6vax!Bk8i$$wO$a}cMC=svB_4mGM+Km ziV!ugGi6WJ2$Z$VKYaPb*#ju*`+Y}`ofT!RsdnSi%|Z)h{d6jP4{r!rKgW!|ZVPyo z#(UVN{K?a9;UR9XMPuzgn=j$(o_}_n88Hvrd6)|1SygjyK21&qJ96PTg9wQ)g2^D( z*g}ukIF9{Zj;zEEIdT-fGH)Q?<-_kzh?ncYBC}9jk$sg*%hwVg8Hmlajl&PdiX~uV zS24_2pr%J{N1Cxx8LO|?jqBBQMDHsO3M0DTWP>nDk=XdoPWapdLMXaQ#M*#xhKim8 zyg}dt{0j#J3XQjhXKVU+o0dMmpJ?N>GQET z@v?^ThB45CrSuDW@MU`mjMAh&k~s>*m%sZ49Hf{aB|eFqj3Uix4FxKR)(Fht9NI!) z40ia>0Pg>cDXAo;4T@idB+p>?9L%ac0e|ZU*ps75n2wm6^F||6X5iJRgw3a-)@dL+->$YAsynHNQ zZ#*AHTMuKCdG~9JBopTDYe+*o6H2X@hYrx(+!=v%%xbrJ^&nh)iIae)Q&7<}&!%a* z-qUCF?G8~14Z+cA7tyB_DJtr~bvT~gV51XP@vWqoY{{ut(iinK>L z1^&az4_rFyFQ<8qApVT~>jTf6BLcWg0r(odzV5x|kZ}Dp_R0{CpE`{(o$go$L`FFF z%Wo~aDmo8D>0(?)ZNnIGE3LNvx1E3nW1&O5kl{4B0~>9
thX_W4$Z{H6Ez7!Ic zHxx<})a04&OQhY}=1-FgTUay)C)yooJ!k4HsI^|}n{Y)XO#2q^nr+)K@wxXL)D{^1 z|3H+^3eax6MnE@*nY6l_Z-aa1ttiH+aulkXgmF`JdNDj;UeT3{x)fWBSO zhH?$$5Fsi{xk>__V zqL<5zP-8ajpChIE9Ty0-z3^MztHkyc!7n5vOP?RMh38C=)?ct7VZ6$!n=y*S!j&Qx z=Diq^5D|NYe(BBFO&1RD%pU%sg_n#3?ZM^_a(!Gv-`@4nSFgW#Ue?oBh%z64cmRkk zBAn=-BY-qzr~3M`Xk~lMtC~=3$or~!qM2{Eb8J8A2c)wRNJQBz07)QfJ906 zOxe+jn4u77B7omCSXP8TUJ9Cn7`QfE0hKcSt8*sI*Ps4J+i#BT-)osb1SCW$z6{!P z^oTPhFKf5GI9u088M8egZrV2m-V+Wc>HfM{8AeM+ar(h4smYR+R^%+0#M?vUqfda& z{7IzWCw#3Wb_0I_pmqPb2ohX@Pe(^++mO~t|+HhykSW8N-JWM^#ItHg2Eq6ak zTu617N}BKXB4Gv#6p|G+Zs2SPjVn(%0uw=GB>sdlwGP&7T*lwo?>$aKbdjIxw!$5+ zQ!Tf9LPbn_1V>);Wa+v{?`C6HJjd6!B2)~--$zY5g-=BQ`dJ@fpE1opH(b$?qT{^t zi__HEB9l@%O47NMnm6f80v)_?2etWt5VU~--n4hI=_O|vU_B*(;E1i<*GLE{L4Qp$ z{fvrJ%T23|WulD^5b9%YX!v&MSXJ%}ZK(M=pEBvDh3LcgwixF|L(RdLesAoGC+>4$s$Xa^Utwsh54f~5#WCWUO_uI|5FI0x(Cq($#lt&lEcrj%ux>#9&~Xat!; zL-rxdglKE4X{Y$8gte1YKZy@Bt@@)gc5##8jk zGCc;aZlgAyF)$PqOP?K#1a{M%P@l535Wsi%jh4> zjz>=M3ulk?92FLRM~SyxFwUQqJq;mqehaxeW|d)hcjKTM>7q&LZA{Y5S^XZ1fk-j) zA~IN%44>fO_X^X~zPNsD{nj79v37(_5+pnE4&Gl5*#=`MA zKgy->aZQM~^fLE)z7z+>czArqN$lfovjm*!klgw38(+8Xg@FDF~_vlI#NS467B}a35svSK0$eU$BWtKX2R7p1lC)N243%Xq1+x^MrwM|5&cx30}A|iw%Ret-3(_!qwr&-dDaaX4lL$azyaW)B57#S+AbW|l&0!K~bMVwLB z@(o8H_uso2o*`mWin?6@Qb-~dUm{+H%ovmsNYnIBC=bW)qi9Q{zI{n?(P)u-3Z3|rA%ZzghS6_-i{c@)1wdFIZ01kqF{ui@ z;0v+a(#hXb7+zyt_Ta#ZuDo@**a<9dT}E$dB5vX2?~hJ{={v%GAYNHtO^1HbtXp^Qa<+Va>5N`O9&;tZ!dFeqlTnqRNgvlPXXlEu3f*}u$Y zBTA}X@?s`I$i4pR8>GW`Q)j!2)lf>!8;rS*{bCuU={fOBF)i>Mwj~}gr*YYZuOht& zFB>GF@T%K)im29g-o!ubj3^6|_JX$A@J-pUry#7+dY0)lTDkAM;@G4l+DrXCY4PH- zRpAWHjS2CQ&!2H>CQcpQ+@K(#kY}E;&Kh+GOd3+{HB~+Z#J4_BXUC*=~779N!&%BFij3-%CNs|8-LABV3tgefIOY2{gl2=@@TdF_Mf}a>Uc?`M$K&>x2&cM zo=`%TV%At!uk#8}u_7NEuAzYO*>@W)nw4V$&10NsFGRl(8odyQ7h&oWG7Q{Yf_mHFPZqGKHHeGbFI=3BPyLO#2F&@^w zu4j$*OthH-JqpWM%B{`eZ7le@;-h;<*&G$Z1pH4Z%HqDpF<>W5CpVR^cO5L7 zb8gs%ch(YBkF+7j`c{cOG%6+Wy2D2QK?=84vH$*{lbs9R%|0^73>qZFPp#Ky);De zpc^deBbWEx2#)yhf{mpu!la4wd|Tk8jIC6CY>W>d(A0Lw5|lWDKZZsbTg(v!<1LD%ZkQNkyp z>e&o(elwiTPbW3Dv#RRqe~e=G_|@^f6G31JB3<*TLhQnhv<~hD^t&%;k#B4YNVAbQ z-`qB03+O`%5yDjQBs>l0a$x#|#I?RfAjrrJ7@fzSm}B>#tbU-k*G6R5D(TwqkBMY_ zARGTFo_H}h5@ue0KygT^n2#EH^6~=k`34|#do+Sf-#@BE3Y_u==8ts6ZbgSq_QOi`S5 zUHcoB4#YJB{^M!CdX6mF)P*X8rjwWa-`?Y8jc;D=-pq60!M>v zLNN$w#qpmd9p>Fmj%Uf_{XPHHdZA@2(Y%s_$2eQT|6>Ljy(`6-FSDDqB%?!0t+aTu z(Tv0ZaX|^VhPNZ?G2S2?Wzw=H#6EE8kB6WR5QOccncoCE3Lpqt-7nk*)s9kDVtM^> z5!gMCE(1QHc^)|E@Wwg4`tpK7mjy{6j&gql@R#QJIZnN93QqWdd2)ss zwf!*Iw7fE~B1x!?H!c2iQFj52qP3lcXKb(ut3E1sVZS#lb$jX%;GV}xR*z%Vr(ZCX zE>65BxY@9y<8Bz3nPnj!oj5Xc_TN+f;-71DC+qiA$GSzqe*7p-Q$Dbub02TGVof%L=DMthgOp+OJmEcCIHA%%`J`bhk|l}FQ9 znx=+mP>OIbWaeCbxM_GSfj4qHctyfiO&*Wm&%5TVf?@h5FmyxzIB3xVORdm{rvU$C z93mP4at1ykmxkO0ph)o05SMk zZVh3=$;~Z{#()r0OCp1OuLiNWrR}9>U(7Z-%OW%v4x-~rGxC3dP&s5}z%b_C^qxqH zAeMkV=$e{XPiHRyc>(O~>|8LHB%l;2H2rHjmI#S6Ktl-J?LBAl3K*rGaUb5YoX zl2c~Falv23$$piA^bt9w=jQgOi%)Vv2F2t=9?HzCGsvIebv*Kb&@+RN<-IFZy5{<) z2Xus`Y=r14Ea9P624aUzS1|tP2jl9+ z?>Gh8DwqQljqIE~=Oe-;A&8{cqR#UW_fyRp>Ii+~$Q(E6(tG@ik8&;P6FtK5{8sX* z66HO0WnI>y-BOX~w->(^2Y}J7Wj)FDc$4moTxQVyf&T%!(Qyx->ee4kOnp03XkP17 zd-T3uJHY)xvnNIc^>$zf4+$|o?AK?qeW+WAi{fYO4nA&FtF zgf$^7E{sl>NorGmX2uhDx4m$2^QF}a+<4!FoXv>Xwv=VRd51 zpoc~hE?&0-bDZ1tDpg#HE@q)ue0I4HfMPNob-!jbuYOLgysY`HX|ixp7%)4zOO6c9 zSu?9G{qeTR#P#_IPeHbcG9-ioJ$zk%{B_6QpW7X@Z=T}l0B4UOy_9y3;8+ox83gu+ zX@6+KV{*FUd#4SJk>oJ*4QX15SCdU?p?%DuYVLy<6jWJ;IOMCI3?jkKpOfg}Uzi&p zf~(j0T}=49#V254qn%4zJGRs`wDHd=v}^*jw=*Mzm;nAfVUJ*6d2Kd|Usnr~Yvl?Pfh+6ES8vKlE21$3{S^!jKG*>q18mu5gc8F1$Bo|^P});~0gr&4uH&)P&rl`x zg>@u@z=n)ZEX8Hxi}kqf%Xa%%<)reyzGr~(#P}mupquZx(#M$#wjh1{?>>LQz5wz> z(>0Q`Cf7VQZGSPw9@0ArF>fNqbj!Sa=$g?|xF&1?veEvh+>D?eYMQ;=;G=XBvU>mL zbfWyxZ`nPds1EW|*-elC+@SrpjOc|&8EFPbb6?rc1Fz&o!Q|COiGx`S!npke(jNkb zJBUg)EAXE6n1UA{AWavzbhDPTm+Ov~+77c_3YbNI=JU$R${96>U?~qc8du2iQj-zj zE`Wg6D&raFCv@w}Ix0 zyqhsw7F2nAR^Q;VjMVmx*47-~uAjenlIXr5Dx5xDB)I095y00sJ*zq1vwv_NlJYc+ zLou>y?}y+PYz+X$Po_SVH_S!FF;=@NK1ShD%!$a1vz=1!@PK~?kvzI3(=9np1dG!@ zJACUz;rS**qeQ2^pxDQ86#R0GisBKl5yeFa-GQeg0^l#^nS&Kr)XNZPtZpeVpH7j< z7p{PXYDXv2Yci5GM3%j-EyYkmG+uhM*Xz_H4jEm?YzIBIS-b>pmcSWIg*6{W23u*0 zQZ1w_7K1U_1iB;0BWNr|6DYoe{s?CIjW=r{^;V(x6j3eSXH!4k->Q82lqZRGGd>4M zuc90I6j)mxYIBcbsip?Y#nj038;Ufpm0v?ry+b2DK1$TPlZ&U(%f(Y5%UX3N&TN}V zIXMR;*qn4t#t*$EgNe>&k;Mi=@Z4VAsYcWLA@3%!N3=9_eltPy|3}cUfOJTA2}p-Di$=P;`OWpd zdw<`4_iv0d#`))*F$@L+)-&gP?s?BUuIrj{qg|u?bWGL6E}Btc9`|rz%UjD>Q!=A| z>ni>HU7xY{UGdM(W_wBE{}I86p*~iijzyQ_|Fi4ho7%kGdsM2r*?4oU_j!Tu(OZ*n zBPnX7h+6BBCkE0kE)|cU_rGW+Qy&N4TFWbHh(^||evpxo>D8HeeN{@`^eD!|jrn|w z)Ep=L?L6MODdSe4${nwOxkZ9*>K~kayT4%XnW?(pz6gF<^81BQ+mnR^O4uzcPy+wq zuqZ>u`8vSDU>s|YKuWIIA0RCO{Vt1+m`qgU5&2IM@$vE3RG4iLfMfC*6rJ5R!hYx5 z#v{GB!SJFs@FD!->kg zq-EzVSYBe8hJe4Pe*PCoW`ptHz~uc*zQez1!!9A})y67`N(Thg36~{tRYr-P-;>9t zp|VfDWq^guATcTZ(frR@+~eFC>LOzHxY^^0>B7R!4MX7a?^Df-!6kf`h#4z7Eoc2mexa*;r!YD<>Lq{@A|p=QnPGdW-{j+tOglJ2-+dLYCf zq<^rxz^^xcHLn*k_WG#Twwt2WXRG=s1wiG_GlM#JvSfuC?WpQ#FRC^-A)A)6HMZ$z z__#bW`Fzl|7ptJem0QUNQ`=7_anXRu$*I`}xScEjU+!u-Wsm-aI>7H8+A%!!QVR3} z>w@t{q<*;eE90ZY=`)U={k+---@T8i^w1_ma15W1hF*a7{sgMbE7Av|nDSdQ_U|bB zL~kyuYPOHZND9xj0$ivaC`_;%`yu>om+5T>ZjeQfQS1n|zvU(%Y?Iw1eB%Su0PX{* zHvZ|Qd6d18%_}XI;k)B`{sI(fe)|i86IHx!K1DB_S>@ngQp8tKHF>fx)w9#7+5k}m zi|pA;v!d<=*3QfS+96wEV!4=+Bu{nHq-8!M#>-u2+?lxN&7T7pTMf48v#BPcbfU{^ zyi#d}ig%bkB)d?uKi&sh{DC@ByV!okH=R7*aiX5QAEC_3q zu(K-+1Knyny&_XWvn8Hu<_r2YC@07je4(=o7 z+MOAGi=i~s3=r~&Ycd}awa}j4A!E!c{ap8;fs$Y50rVxG=A{H#u=m_uyjJ(Xfi9ky z57fVc;RBS6(8p?2n&GqKDf^&4jXG5N;ShN@;Az9PSkL`Ut2VfJ09cZY!&uA`)fhXH zo9&tgG~jF$NAqkNMJ5fTUemd9$74PwMw7cwg--5tdROL4ktTi0-19FR1F6&{J}6r27JCw*2Wj7Q7YY(1p>Q68FH`>`E9?bbkM z&;)}t;N>s<&C3_amHn!;O3s#o`{r%SCsqmnR6aDhPD_v}*8t9~Bo|2;eHy1}`>znD zl<{cgkL7{v+k4oNs_hYX{jnjK&^Euo@@G>C=UUtux2BrK2%&Vr$!{|og|%$lbb&0# zB@|+>gdx>D13?^)5E7_$gP5pI{e8bX2)Rmyg8Tw=V?x5}l=f}WeMSn7tESLsw5hm_*V}Z!XShF6+s8f%tA&A^pSw3S8N&UinF7+kj zwQJ0P!!Wi^`rJkMxJJKy!)x+{D5ie51?LSwrj_M|*a)kwOmcrBb;U=&+HJ-2h!^%j zTo4#;qKEu?^K`v^NZ9A3w6)J>)RyMaarH?vHA2}yr>0}xIc4**w?4vQgFzzwG`qU9 z6uDuDAtThJu~0Af_)q4C4cPir7H+gkVKqtujQO+2-@e!jJux}R64bpgD6aE4x_?&z z-lvO#E?50z*7#30$#&kd_EE)^m37wo^+o9B4e6ieVTUQ7!vB&W%Aoht#HVgfAdm7g z4t^5wOY90jU6kHon+ySBHRSy868p9EogZ`;Y514-s0r7nYby&eP^mAE@jk%Fev1FP zjYBIYAtK~YSV5ERr*j8hOzWW{EsgGC^MQ)c>t)y(R%E2zcN6lb_z9Rtl3zajQZ)9% zG6XzjF|$GQ(2(NWYr%!L4YTe>ka-8pVc#iKj2{(hrlmT^3Njyt@!o@ok_Ea_(@^Py ze}qB7Ik>NLM7+;eD+btxdaIiQ=1n^yhyjs;$$PJjG%Fi$46Nr#yCm;dm~|3TJjNm_ zYaP4I3yN8h_S6v=B3#B;vsg-R!}i|fbE0NMM-#F>EWNnf{=gonW5JQcvJ&3|x5GhM zn`UBkxsUwu^!V~=kfyXmZUh0=;~$!b!o4&S);p;5pJ3^*$M8@6k?}@80*4fBoA%ob zB0?H8f`)+X$eRB&sylx4LT+cW{5t}HkB&7;tGSPlg#!7lD9_*yqZ0ufSR!ss?jtq~i-_^jNq7~9#$gs^! zY`8-ZZ6_p_7LrvtTJ;bRr<{%_EIOS1$z4B3W$seHkwpvX8Lac<$X+C-7QQM z%i$}Cm_S96_K|sm1jd}qCoBf;{Hg^M{=im(nV$Sxdo9S!qRl@zQ6iy$cEl;U zgVHGwEoM)XZ!j05QqfkJy;csDKYmoF4)^?rDWB)=1|6PdEAJaXsz7Vr%W?IoJk0fZ z)k@Ef&f6%oc17+%R7!3tuia)hLHeJw~w5Cu?~R&!ZB#? z7AK|o9>;QpClbOznXXJ(`crZz_4@Gp0HpNTPy(}3r098;NU7I+AgR-;(c25qr5Upi zA(I0wB6`&TzGFSdjrOAe!LcH3+`C=7%}%{MV?Xa7AzWv@O;FVk7#wV`9CgpaWn*xj zjcz%FJ}XHV`}#s(YR$QD_u1{mi2%>zt`8OdiPIhJDK?d?+PkI)KBx0RZ2g!x-)hVLqZC*|rvZ3Sk?!Z){7PIkZ_ zybl4{9i7YcUv*Hh=15~d4kCh(xKrW}ho-2&`<~Y}al>7sy_}`)=Bwkn8DsbixY(}^ zG_%AN++z%Gz8OW*3aXGEUAvBPNnyjXPMJBl&FTLWBjIr}Pc z$u=s?D27rW&8Z0m15=8I1FED54jGu?oAsi@|NQe=k)@;^S*GxTWXP!qKWR(bU)6-Ez!S5+5$xMJ?X8IliCe@YO))FLku5B{KwK*Q2yZ#U))@ZcEo!YELbnKsyx|8XGf$gqJob@--LU)4ZQolco5xfss%Z zr&pA9%q)i5+o?Dk4+X|<%ndx%z(;>v`~ANCL`FJQJ)6EwCDym7lX3zklfg}wGLVyn zi-(%shy4ZL=oVavtC+}hu1_*P1#l^lOUR+rg@$( zQPX1Ix2-sn1{puuPoZ{ICMiL;NXL6E5#4OHN}&{x(&UcMiO>YF!QQOx4J3h)^_WwL zz?x)%rs#TM9PqLv#UB{=(3XDw{ebr8AE}hq*oCMl%)SqHF!+zTo)$?)-eVVY3 zLoyqmU!N|TYxHlv2P@?6qvkjv3)NQmhdFB>20I2j@&ef@Rj3Dhz4eNKy)?`{S!KzQ z&c5wa%g6Jyz7vnA2cQA?HP^%~WWmDC;iE_kV(&vdcU9wq+eDZ#J#U|zH|k251x=W~ zD`~|kkYsh-RTiB{%zNbHS$=$g| ze7!wVN@6x49s;Yu_+_J|I_BvbCG5jwb>^w#Sq+L5p_sB zFuQqamwH=BkHCkE&!0pHFP)5r3i4SAG6MW(AQP!88zwFkjBR=`+f?}nmxhQVe_OfxMyey6{}$ZA>hCG!ChEtvPu!#);T0h9a(w-w(xzzB|7 zwec4z7jKJ5KY(#81)2(+2XnstDVg=cHRP8vzU;)c1tZ>MGmmlmLoXW6JI0@XA&Ao^ zY!~&A5Mu8lX#=dANHIu=LA4s|WZQZo_j26YrgcZHicKiXRW+3^In%}^j z1ThGk={flf%p4%A@oJBN@uFQA$!HxdG_XpedDA6-@JEkU&uC|E`aBwS}8 zNQ81>H}H{BnJBRL;F>*rtog_>43c#hx_Ii@pCLqV0N&x=NZ`AIcb1is(+ei!5k6+m zYWsG^@t}{{zex~c{JZ_owT4i`H<$|=#o-1r#p0hJC+D_|EWB-EV-oD<1aKl719^;i zajT+VW_#ZfGqO_7e_-(lVT^uv;DHr+$$xWw(nyLayZfi_fz(~hy$gV7l%%fVO1}l) zjtJ6;xDlGZf=FD*78`?#l?f~`yAyNVKqpR>6ckXktocC z#*v3GSkCSae6nP&5TA1d2Vc!Gf2Ey=N-^ozK=zZNDy=>q=srJHTxEE09DK85ku6pCEKxe`gUvLg7Inx~+wOldwU)rIf_0jNjYM%XdyNupl}@B<-k5QCFIat~2syVTb8d2$9Mj*8fP(|n%sG9hW!WE=<$OX#^ln9`rCLaw&N1}zPPmYBaLaJoRVh0bQtsm#WOa1 z(=tE9{z)UJmd5-%>%uwc$Q??2#i%!7rto3)PDJ0XslVtgFE41W=#AI&*GD73F=XF1 zVpFoj_9OB+2%`R}f*{PZD{>kRaYUP?$hWYtPz2S=`XB4wv(Qa_PZFO>k*BoS51jP= zT`LrfV70lTJ5kEqju#&~wQWWDDxdDRy0WJ5ZVCeWdBTrfVgJ-m1Y1o(w-NrMKv*lc zpQRnA>-B4wV(8@ABRVfahlmB+jy#b@Z=i_k@f2+hZbX4l0VEPP)DkHwoXi1)EX@fUBLdA0n$sKgS zbi)%|P0J9y(}-)>u<3o4l`euk^z&aBXV!az5Ny}G^2Jqr)^$=AE%m%mn2jK8(msxH z+Dp5l`?ELLD|Uita#_mBS?7@-UH0@b61As<-W)~dJf^(D+yoKwArL0%0u?)A8cea3 z#O~ccXBqGpLtL8N+Tn*3?Fd+oOv59qQpVxx0wBfSp0+*zqCN zw`B>>17WBZ-b7d`Kj%m0UAxy#E(zgXtOk)Y+_7C~$N75ayw14Uzc_&p;kbBwk6o1d z{b{eg4-w;MNqsvrx-xVZI@yR}yqbz#Oe>CH5(5-%?@yNEzdaSk0hb|&^E^3`vz3@K z!ON%as*img8OE*MDcolzyP`#B+3a3N=FqH8rbZ27ShOW=Mt)D@J2BetD{s0+Roa*Jq} zz&4K;NRAesZ8w@s^F5#bYlZS)b1aFx`&pbB}fO7g;YhgA%;P zVMnc=_q(2tj8WzCbsc?>>D+z$!fAFLU`?_$x%urprAvd`QE``$0DPDGu(GpFUo`DSE*IqYFmy4}tHNAL((VvpD2MY$-7%`D9aA&A70<-GQD@gIR2m_^w)tNHuN7En+GndvWADS0BG5gqgs7 zh<=qM3N=g+JBI{|F@1R_A@^nOy^IN8VrUM&EscNpRc22{wPG+8$2BMKL9u0>+KTg-0VzSOB5B$6+ye**pvHS35QpfLOY;Q=2EGS%oWLp> zGrJ{RQIrTHXH_{PxB0-Y*}8^j3uG|+}fN|&x`y~|luG!@lwnfsGxQ6^ks#`WQ> zx3(z#S#0S^?HI@vcD%dUl7cU?45-GCB7ekC+B8wN9?Smq8(N0Y4;0qr=T@6S#OOJQ ztF@S}}y?4vJT@S?U$(jPWMCYG`U3@@?Gyie|*b!I+USG!2gd4`W+PWzwf zAPQly0#K#ScB3VP10j{otI%5yO)=2rIB#(RrM9#-tkaN4ATlmWjO6zgA?{PTtA#Y+ z5q)blay#9fpZq>#kLoe}9za@FgM$Wb%&a}BcjvmQpB0#e5S|Zr`}D9stiZ(VShK?e z3dTaN&z0=Xu89(KD5sN6bM`v)NBNxlGR^(&hBSQKxM{Z1xHiF-nLQslugT!8A%N}Is%kREZ2 z;(#HAgHJa8F`GAd((LZp)o?z3=H(s?x+}2V(Pc9!15F#EqWxx!<7brGPvo^tv_K8}!h~N2)wViJE=L5p(e;TralIYqsO>5~0`+9s6aZBy_BL;28NxpQAorMgk;hJz zguoQErr1HHj7uvp&P^Q2hz+VJ@n_}$_GWU?bLTI<%5k{mht;Q+IG_IL+-V+|1sqbS z82@wD-F8MPrO!NVB)vZu?okGh9wSknxh-+Q_#dumW;5jBhvQqL1xZMNtAjU|#9>wk zrKi%EH>izZ)7tX{(Yzi5Q4K3n_tO5Tq|mh1`1u&kg9#+q7}FYI(=rTe5ZP_I{o~!d zL@7(z&nujT%5M>Z3bIbMYgtf|(?cn1{(iX=u3qm~e9*~vn+F7EcCi1Qkho^3ud zued@#HhwyoE>i}y9@e@hUQo4blr_-#;}?=P?ghKZ!YB)N^bKk~`hk>~IwnS~eD^=iOY}Y$8^co}O^`E?Ah!|j2g^DSJPr`}F zyz=GD8z#Dul(>KVaRcJfokXEKeP;Jhn>sRph@47*zNY5=bs?|Cx=StzvPq~38(q$J zj=m(6KGGlU6#?PpkjIjXhEKTlej1~mXP7S}e!omh~ zq@ZiCB49`UJ@V5Og$Nx*?F9&Plb*!@u?oi4TM}-}e z_j;)Y=ukr~5K_BOo%u`7_Z#1E`a7@LI`>i$>tKPoOT3k{_6Gr!dD=yzCI|Rm=>bkk z6jQ>I=qLU?Gti9FEAzvP0S!2$WQu0T1@%#d3*{qHemW`YhJ5i`1GTR9tYX%^4KxeC zK!v2Bjgw!S|7KM?Kgj42USDZQ6{<i4B_jDbLVs@a8+gSF3khz zbRMI(Fe^)DU=&zFQMWA1O6(m!^y@cfW~&Fj@%Kw;z1&AkcWz5!?lz&0DXWsWQ21+#O4XyFCbcCA~r_4YJ2w_PB6FG9+t)BEvQg~JaOEL(MmR>Y zD1?#k-4pMYVaa_W(6=clPYnA#YLDcgDBEr4kEa00w8+77xvfD*99xmj-It0h-Af}%wSo_C2#G(>I$yhxP zHW1|6{CvkzZLa7&`t>T_s6%KsEXh}2`@%$>7bN)d0&ruwLj<3$3sW;yTSnfzv6G&? zP%HV-^`fufMslSl)XRO0nZ9t{3^9iC0gVD__?BWDCWnS~;Ff^YfGq zSEJLIl3Q!NfMfK{TE-rX$wWY2_%anoc60R(YqgV!UdpNRk|$)D{}CHGSFt3VI?#IB z209ZeakXQHp49;IQ`x)Ggc`rMh5`r!AJItq9Jd#1lRY;)R?L-t6;}D6d-OBWMMh4%^>{#qA5*7dd1*wjS>@#q8UW6?{LWHV%>4misx?4xATDgL#u-~C{GkoQa zaLgh(pQgQ}Ecqp>|3xWd1{Py%-)%)Dx<#2JSV)s#xmP^TxW`N>s&vscW>mG|MLR?; zPa8dBQ1_(`DE}rSawKJH3*vM+!}?4=+`^LE#73^05DxS06Mr1GcM1~fXCp;Ee}I0# zXkYp3J@{S#38YGds$u9FYFItse12KJxqkkN;bg{Z#XJl4Y;QWy?rXnV7mMQQ&vcZ$ zH-|pMtttX7uz`X-m{0ifn7#9gO!CsJ+46_=y*U4~*O9wEO%oWULhS3hV|;3q9N}SI zMpVqQ?_%{#)aBo8Wp$71+|L&#N3&RN!G|i*Fc{tMYY|0snSe z%YfZAMwEuv{$P9k9g>;FP6$m->>P&P4;+!73xVoM6sY1@5818&6`-{~;geTvcd{qn zC>E>2_dP3kvFC9g zEUk2`$H=0mW?hq|*oMR6`V>U=cZy0H9qC~Ejr8o(W({?I|Foeez=m?v!^S94>8Z3Q(f-{nYky~)#M0)>gCki3Dl>U@WD_LXkEJL zhX44?u`m2A*70B^qiC2O8f$`)%nA%daI9=d+jUj7i55bh#3*KRs9p1tm-4WYaJxpMoso-y;LowJ69z)GsWA<(M5 zKViEtln}=K4sW)0i1YRsYgh-|34Gj;fg33>LrV?6YDd!9*fP-Rd2#a?m^K)bD z0NgO-Xopx-X42js{N6yC5uywQC+$WwHX8j#WSCJVd-)7Djc7!Nz1%$^c(l;iue5P# zxoh4q_KhxiqtyJj$1d(a=YOHh|ow?WqqneFI zw{E3+VaN9-tg>v=v&l09IME)Qg3x8?_O?9L{g0$RMI53Zvb7l)Xtze~KYN;WG0DSZ zaeDA*ZJw5Yxj5dpsX2<<=hOOjpBR`8GXWhuDvSc+p)Y>d;An5KMHE%&YB#@-L`7`9 za{xmK`JDE&2zA1XMD$n9RctN|-9}7xQ)RiC6~y$~Ehz3Cbjmt($RuBS+E8r5VG+mm zl+IYCa|Hi;W+NA{95|5zMzcG_NJI6n>UoHQmaFcImXV8is)_AabN>OCgm+!7%}~(x zmaYgvClk??cs=!**;n?J-s5_z>BVLCVLYk{>1w%S5$pM*hr;oWo~IcZ1#x6wggGS> zF(ZA40|NNqU-u~>LHy6BWsWLWoz?bP+=gU-=<7G&k>)omTN7L))kW<|`l#0yksDl9 z@QuOl%jcCDR8=)9-0OBTzfVEnEv4 zv(8cxBFC=iZ&#_U2GgbOT7<6aKT<7W(_K)l-6@>uoYgFzUlBTT%SeF@-&SW1z1(O{ z;;+2k>pRkWT-Qza4+~R$>8DN<2}I4vD~-jk4FcTwwN?j>4hJNxO1YEHA$@ieeTp>= z1|C(-)1KAy)1I|F-YtVqrsE4Lv~sG?BYia;lftm+;3(mbpkDmXLcP@`CqgF+nIg@W zeGuc9RVbLe^0b4$Uf|E~K)b%fo4cc>+ui(QuF}7g290mL(%h#zE$D6C{2lYQXWb+W zY5pf4qV*L#)y=)Trjg)u_GO2aJE(%6rsIM(Uh93KEHY z_LRajT6T^c7VK#$uo{;wg?$3g+o+gMa$ppKOLxsJGLbQ^EGnT83fv*`5j3ENw%q$} zJBRDb#b#8S&GUZII-%KW-3G^uz)(bh>q92$d#~!@8)X41&-Er@e08CYisv1H*M)r_ zDxK`$8ecX>E%v-lL;rDVXzHX1V95~|VwcMP6;7wM;($#v?}~B@EXN0I@U=MK^E~8I zQNxMDNg)bN<8AI0#^);txClYc@3*O5OYn%917Vt8XS=S`K)Z;3HTAWb?&^jQ-an!| zp6gBD=yoyDvaW9<%tiJr{}@C&oPPMn0Lo&)8?a^QegAhT&&&oa%z>^Q8P~6?f$ijh z$jvAEA5(>UL=xGkDjB!)uTb(&R2PZ5+AT}0h#0P#D;ut6`Bb>I%zXH=F)_wOU9fq> zzIb!;Xch57#42ZO;I*UqKf+pSRY0YV?0V64_wPi)vILBSHOo{2X$M*8a$>n_y|RCh zk>4Xrzn7R#zpNlW|Ne5ZgtEfe=ZYh0u*%r5;VHHMrpY=PLAZ`$70A|iZ+fu0SLJ=- z#!!LI132wJ%#jtGk2!x_ltTWRyciJu5qna}d>{#?X)Ot+IXV7fm=L+g?Y}g6-n`#V za7-q@C{McV@;4LcE|{LEHW8V(JjCiNXsCpWH2%c(fB9$rLyJm-Vl~&~SE#`xl6rss zHOJpeMogpwdQ(XpCKAtXuCFe%-wO0R_$z)o2XRYogRMk3(mC2!kbdSIt@iZUYH)Y2 zb8H~Wup@uEgYePjAIr3u8Vh9j=Uk$i06p~2a)0U$QYyK|b%*laABKOuqO#bgF9MDT zpnvo#p3UG@s)+Zbb;(nVzn+PWe5QZ67%}phmh1RBOUtvDvkgxU4C1e@$Ey3#jr{Q#k^$oj|QcxhRB ztC&oO9*kwc4(XH0g>huyC6P}>nYE}7{WIt@4C_6r?WSv@f;FE|F8=K>2Cz{WD7_DQ z`Rv-m$mI74>Z!_6;qu5h<{=4qXCL_}wPe9(u<#3hY67Zdh{Ltt(;!M0>UvU|^7l|R zlYOIMak}PYV?Yi&H;gmXJY?v2!&mw*4_ zeFD{mC=aU5iBgLwPO>nhX{Z)~agV?UqQwE*2YkRAF*6dl+L-`+Hy90jI1ha1sOF6> zJKXO^@Gf{t7d6-}WcUf_@Teofd%)t3kWpa0o$e?Od~Z+iE||qLa0+VPkuvv#ms|+p z_=C z42y3*LlL5zB-JT4_5)}U!4O%kACF^$%X*%5SM?K9(ao1zc5lB?j&zxgA+6v8~+{ z5Aj6cnSLw*&r~US?+e}kelP|2VBpX|VS7Zo8u!&VBp^!H6C8`XFPd`y8ZZ6`()4-W z24*>fU7CZngEU|KGUT4w@-=Ls1z9snh#K4k{v7WKJNU^z;rc(&KoFhY9v_vCDntk( z1f)ye%y^SP1Gbro86$F=5rHjKfQ)|2{bLhS&@#HJo@pcZ8sRNJbL3&DRLuJ@87+g? z-<Zcuc`)E zb&9FaidI5NSQV~GWtdyxK!RD|%II|n!>g6PWcZE83vu8Q6bLL|2uXWtd}3bw-y+W6 zUkx}Q&$T{V734!nt>gC^P-qpa+z*zkfq*_!i0oGLSE&p(gPN*BAj{XWfJ~}~eZ{IL zA5SJd93R*GXY3AK3omk(;b}?L4?xz1)xH`(-+@B=Dib}%iQ9Gi)ptti+^^Y889@B% znY>Ky$8%K>3Ryya3gsGQd|QpSIVk@+GyZ3oTdV^!SaRovK$<-#{6QR`5oL^>%GkRU zlhRW=7vJk!M=mZEB<76c1^l&qzwC&P;!(hGfqtcR{zGR8FrfREp)Q|}v+nURhyLY+ z|5YCR>-gzHn-oG>tI)T1X0JbeO&6=oJMnX?VI?JeX2X(QPHf#$|I3jy(sTdEFWvG> zBt7+7kU9ailv-j8JQr|l6I66|WP+|h^m%u}!frHQ_s#Tn&A00+hs9U@l){K6@ec}l zn5Hz5bR4#m+;|a~-UdcDsp?axv6ik~H2c3=@oGCd!sN}%Z%{C*c*gYd2H#pu zJ#^Sj4?}G`u7Ae%N!QufPdb#OTEKC+3b0`{%O#L6xSuvz&^dP<@=zB*!)I<3)2{>z znQ04TA1?=TRUB<3=!U$uNOg|Wu-9t+i02yQb1{|KTWpeVeWf&zA8Ty(-?O`K zxr3I`_{H5EP8oSveUbeQRw&>9UMmqT9K^ZSkm6r*okz0 z2f%uOG-k8BhYZ`Sf*b*m3TOP<(D zwU=iN+$ zcEs7(!t$>q;*B!lA;kh}bg~As7Dao%O=%sSz`zPuBbi!V=wfCI*$?BhA zC?BtMSKk|JoeYWxW}ALA%$q3aZ2c@nguM_D4V2068_W~RWM}pdGvwobTf!{U7Sih8 z3KtfMGxS(ns$mWvkNCbrJ$#{|hqV=FCkL*ENi~bHDXi%Vrx4k$Uq#`9 z7+e#QAfEoUcmhN-=UpSx^7@ZOFWT5!6uU-Jd`4wLlGvJE0!+>c!iWFJ{89a0yIs72D{CFw3S9k?t@`x!3AiXM-nkY6pz-Y* zo5IKWpFHr@RA?&#niv^a4mW0JadR(L)@>DBL!g(adWLGR7arOauDMKkpCHU4>fDFB zImka3IZxW`)K7bC6wO*53GR!GV5YaQFYrFKalp17#-p9uDVBs&{{$AIdt|wN;bIg@ z6sce}m00_{on2WB<*ahrBk%WhyjD!G)9%-x8Wa(oMiNC}4xt+w5rT~eeL{isO@Pq_ z^(HTUNPNsnI^dwWB@9?K-&5pc0yOjf6j`KhWvQg5Xg2Cs+HJ?AUgdWRa2oP?zbLky z#)B>wU2c>}#!3o|;?EOmcHVa*ugWQu-wCuenDx*x^fb_}v=GwD+v+uNomm4`k!e;* zUNULDJtv7PKaIY1bi!7+YG&{cKlzu3l}6?L zToyx?t#9k?o?#5DV1vQP7Af6N=gms=8n$0e%?K9<7?*lr%T%xJK(0IIzLTnnYDhPpb9l9!~1dFPZWZ`XcZ#5iXk9`Iv*AKxEtr|?8Lg!eH4uls4_+wlBx z9R(A0TZf(A)XVkv4~m@pVBYE*M`H%s+*VvY4n^L_4jToPhHkoCF!u|?-h8P9mh*-i zKWEm|pZUm+eigv4H}oj3Lj0u~7sMV}`Q_y=CGrYMZA!-HJVtJI=_1}qUai#U6Q)`m zlF4DoWgdQs;pz8qo2`Il=J#jc<8!LrDUp5r?b(ZuVxF(GwIzkLLbt-V(=Pjgkm5x2 zd0lpY_}+=U!xXX!;<{=Q#4~YT!`Yb`|0){ct;^S`cJa-9B58yf8r*Sfyj!mF#AT-U z%I;gDC=qw_{Jnp=YQGwyY$wzqo1%t9di zJmr44(#^WTl@Wcln?uoUyXQT`O$1NO6#X-x~N9Au@UI zA$Ru36nlzzjt`a3=~w-wow|&a;I8uN@5)KbjNWH&)HCPv3Lk3s2Kp+Ij}Mz=2zs~P zv3i`Q=vq5O+V>S=-c@uhx!w}eK$zgVPWEF|p^8^+x|||LwbE#qCEI`rodMx9WgA$z{)bD| zBv9}4X9et=7p!^X+>k@k{^_|=!OW1M_n%l96tZ=1t<=WHtVEa>cKY5g^RirWM<^qZYj8mZ{g-0FU`|{Cu z8}^^%@uNQvd@VY~%ZDO=kUiRuW^&~w_0Lcz+sIFWk$R2K(A%(*llo8O<{CtIwWk8< z{jP5(bp&zVXZ+T`PZ#Jv;-j=}^tZ*DhWIhtI(f!;vH59HH604N&2!r9&93Wba>CR( zhekeU68@d5;e0N&n>99{#5QJf%^NFlt!nWTLC1={cmeHBa6Tv*fB??F! z-B5WDFFW=XJ~{dRVhSw-fRe_xt_tik*{&ym89^tru0|%~CbMS|`ftXITQ;n{2`80D z*jZ6>^fnA&N9r8=$P<#LS$S)zIq1<)#tBzJ?KX9`VKjHR#{+pAjlAh#@1ivl@X~VR z6=&4;wh)auC_XgC;cg4++6Y$2 z-EOKQzkk^JhW$XeQYn%9v96TfzN2E?wAyzp@U|GJwKRmZY_`Jd4b_tzdhmSa;!b9H z#$Ur|>Qi}U>P5a@oUNoNGHT(quWyy=l%(3~NBe5Ny}tW*0q%d_N}4)qtddwFxPGj5 zuI>Nl<8+kliWitY$_&j@3#6$gujzecR~%QELKjU+e;BTnttxW=>xA)foTC zX$S-{X6W~Qv)FSEeToe0qe1ueWSX8|*@*2P*)w{c?2D_D8Aos(m7M>3XADHMPu=VK z%~eGXbmn!oX?JlSY<%@+y`b^|7dknF_Un!FOWGgWf%|FLJ{4Mxd=p=#__m_1Sgqxa zCt%{ubGx7v)#}>iPpo`&#HayETm8l1W5k4BvugRv7%zIhf_~SlbA;Q~k-V|9BdYV0 z`S^=-*L??ol1DlxxPzey)S%Ud5+DxD<(#Y?d;kPv4TeLrb15 ze??`mKiWDp)ryU%yPt@Acake-*&hAwKFxT-+Gs!9(8lNtzoMuWy_~zv=XtzoHf8m2 zT1%+GrqVpaq0GmG3Jc<5cTUA#4C;s*)xRiGDAwp#!j9HPl`@+B4fEi`?08Y)t=>^O zDJayqBu#u%f+g4H@xE%|NB67KuhcWpLByW%+kR;is< zRf{~b!(X}9AH9c8P&|{8N(c$39cRQKuI}BBkrW1PrN-tzK_09vGyU#8SBG=?frAH zDWwa!l78!~$=;fj%HM%21-9Rv!ZRv(%2f8p%2j3@h~koubZoYIwV(_AA<3vwi=z4y zmyI*SmbdaYp)Ql|7L_48U#Ccf3=xWsmO=|xwZr{Tg^33R%due9@YT#HeC5A_Jj@u$ zv}i23+|-7m0avX*H3BgWkVEVI3WFperfi4`pc>hi{2Xhum6MlW&%EP#c&*!Ju6I zc#+mt6?SCgZ{T<|(m6%&B@P2*!O$y_1{)!PT5^-X#_ofun{q3 z?^<+bXfV`eEpkf(rShSQFlEMws1g%hQU>u%(Q*er$I5r6)Xl=98Nf|d&ZWRO{kft3 zSQPR;%kjt_-?Aez+TZrcr?2d0ujfuM^wax(xoIJ9>@;q_Rq-PPrxWcl#0|5*NKr5I zB1RXy-Xv}Ob@#m%j1;>tq!sHh{xs&3t5JHbX74dBaTSTjfhozwI z{qyWy!6ISRXML^>7t<2yFHC4}q)?{$E&`r!5m~({h@yjU<*@(O%1@Z?SD60Z;zJfU zGUO4oR%Vpy)b)5<-u~oJLnUy6(LBk%MA{_j-d>1~?5S?w?FUH$C(p;vP}8 z^-WpX>Sx0Yiay|q@MDQJ?0qCx-$)^O^l%yO>Sbv(=LwufR=am`bTR&z&`NFQjpt_mq)>L{*tP`##b>p#L zWE!ds$TUIUGjHs!<>*|s9>Oxw9kZB@)BiXr+|(jl1_ z7mIHMQlG1`Wa^+sN9(`XUm1W-d1={dh?ZinJEoIeCUXYUrYNt%l9ui}JI-{q> z6bpz^)y`hguk_T?+v=f{nWVCny?10=>z-Gd`lE>S#lo13yyd>i=*1w%kAwjeVBdF*d(GeF6$o z%EC;KO=N{VC#AmkkX@iuc$bY4?QsjbUIM8s96kZL+IHMKdu5P^!Di`ZvMXX987eZu z*FChxAY?sdfkc1&&1Ap6i;RM0BZA2;&n#SHZR56QxW$Hf>eR+=-MMArsmDxThlsth z(9xHj0$HrYy=wIXZT-UItl_Jk(VWpq@>*D%aLi=C+IgRJYO-@aI1=FNj;_oeJ3U-| za)jD%vUZ@97G;{v%f+jyK2g>^l_?q9`FJC*sHa^%(3_&cAIBG}qW=Wvf!vU}QY@1w zQq#!W=y0I%#vm@2CF1q%oBFr)q=b>{-Z-T`|Lw)7RW;LwjUSW85MU%4cnwO+7k`Y# z8onLrZ)yvX344@j_y>30KAGJ~aX+^b;y*g8Jf7+=0N0&`f1L3BR+jdDWY2n9cWhQy zuqZ=0uj$pav@S}RyRm7e~nfE6fa^?Fox%ZxJz#H^U#vYo<@e>0-Y} z`{+(hA3y(^_Qw?3{V-fJ;oVm#37pFH+uLF47R$4crfQOZ^7X=PJINMt%)7AfYQ=Cu zVyCgU=<-)Ug`PEsw9rk&_NqoFGOnQio=ElThmUA^{B!EAF|ZG-TV)<>kgX7Tw%t^w z+hy69f`nchM)pMdv6%epc|~KP9+5E@fxg*r#ZI}emXnI?)jz%GcRr?S54VOBvTEih zY>yW~#;y_YjSRy#vQYfBk>dG%)H zWL8HFCn=tY0}&3*w(UmugW@Sc+mt=e4_^JZXAe+LCmAbZ7Eg4ObvxEJIxa#89bscM0`qJ8M93Vmx0O4+(p571@i=pQpXWKNKxNFD z?VQ`=ZmS)KeZoj5W#pY;O!DIHM_ye_&Tm(XN;G4#ow8LtezEAEo1J5L)5ag;7z9CY ze{?d+zw8Y*M*&5~6~mGhR2kL)ti9e;I-=o*B`yMvn=&O$X7 zH1!633T=Lk-cPom@;)47EFHJ}7LJgEp0`PN*EKU4K8ZA7IONDQtSfu*L~m^Rp-3&g zJz%VR%wz{TzR}5y^v&4dIQq5U)y)olHzfbXh_;INfS-d*mhX$I5PZ}wesbBu;I?&x z?%4m~?L7mU+P1D?MNmNz1QZ2nhYkW3inM^B(xmqm1VL&jA~nDUr3gxqs`TDNsG$=9 z6%pw@p@^WA5PAp@%DZ#!J?FXi-0%12FB6iLz1Lo4t}(|Pxx5=I`tYJ_W69%9c{iwU zJC&L_qMt8EWZ+gaT^Fgo^=wqEtY+CK`MN+MC$!g8#7v3HbahO$tE1N#^qXl%8ANJ_zM7`8k61;k7eWqI?y6wkMMy7-q z6<+8vZ(?Wcy$)JS$AX0d+TshHUW?NiK9jtSPn%!f@rnQfs|ugE@HPu{J8dNjuCW8- zu<1I>9-V%5js0NPE3HM8r313+@7*L6Fu((bX-5;E8<`-$%ivJqWn3A<;P8{PMV({^ z^Py_YfcHs*utfGiENJgn#Boy@5ahT#jKC(R_ju+?X)K3t+{5bq-qb}@Fy>Wbv>G6Ah9M& z^OK%p)v7Y`tjx?6okH8Q)0eG869VZ!M74c1(pJft@D^+-nlX4WPMm3l^ZPWV00NF7 zwkJ*7TEs04u`peWdxc(I0aWixI=1N^kthO=v>kv0L-kKqvy`*N$Rtr3?J{by zozCiR&jqHD-Eqqimka&kDcwe?UX3{}Ksj6dK>O#@$$9 zK*6R^jt!Q`TWu?CHE7bY`f++O`zd_Y6;k)(kgO&?ox#nVc{5U?#fu69fbORCd;bW1 zceHwON@kfo^@rkKqgz$+PKh_A{O6;mMcYK{bjs}lzDv~~dqb_wGT@0DQ@!U#fHnBw z zYztM<|01K%v$Ue*1ud}=p!;qd%Uu?8?Xpqc3dc4>+%ahK-J~4QZz!~Ke@T2cFTH~5 z#i4M+fdeoj`;kMze*b|Tn}*~E)!`{HZRJXrwI{;OJ6SB1vmLNCE8OOjAQ4DW9#tq< zaE^!IlK+4!gYG9ZK2e~qaW-W{IpW(~1V`phviJc1hoy6W8d3slTj5X+?afGc5L4zz z*aT4(pygMxdHe&R3}LI?#mT2f5;Ya*#9Ah+EZ(~tz>8^QV4lRU3$std{O{5%?%YC_ zQ|2=Vx=H6`u*msVV%zJdg-W~dZTtp=7r9TJtbjwiQQ4c^c-?NgoM{bKC~Q3pW!k>m zbo!HFo3Ut81K^`eGIfuYC%!-)Y=^~6*LrF;_Ib1m;bk7R9u_Z}T^YSEzl5k+YwC6; zgtGS8u@rh2yis5lS!BGL7(hCPuS*k-nWHK$dnHiO>T8<;#Lf-^&Il6eo(8L@&3gvH z><*#=Hz{|wjnWkdhx)6{9t9i~XVb%qY%>m{Db~=ydYkR+B|;?50mqR=>J;C#xDq>@ zJbtbKYK%Qd_Lt`v8-<_>GxV_eo@tmc1Pb%51Yw{{+RtC7)p5nBBn2mq!7~slm~AsB zw^e%|%Xxt+nc5`llZ3FD@naU(+$RcXZ2y>tn7TFl^C+SloR-O|W|FnS!HjUR%(+Zw z6$oNlCtBb5pBSe&QIQwi#h&s_^Vr9qWT>FWh4uyTvSxwfsH_vH`E1!l?lNH-17B}* zp4H04kwy@Q#N(rY)re!9)U&`DH^;%=@Cx+t0S`2%V0+@pE7~bZJFO@Xr7AFgwfrBD z?7#81Y*$K`?C_Vb$9H`0#=Lp?km+rqEmP7xE-uQ7u;n3&*Hc`UH&gK(>7_C;kbE0kD7MLgEY5&=M;Y1}; zg=VMjVf*U?2G@-^u3dabMm^!zhxp5Y8AI`eLpXk?yYndSNXQ+(9O1KH z?lGp)5R99>N)RacB%5@P{#%SOtRH_&f6lR_LWUh0Fh@lMQ>M%mLGzm~ocR=hO6+dP z*If-Kyg8TjW7I6^n3(W@r*{^mk@~wCV(qT_Vs-MAxF%!#@0}@E)>bX&gb{f6m7o({ zc>|Z1(bJ0~HSzu?)erBN(3D>C`7%~%^Q?EeNWA~|nE9}YY^zqyI7wZ+ae6k%lJ`>Z zD139bO09?m+WXlReed4w5p(PYaFt_5SUy_&-NJcj0j3BFR)2) z@7q)x>>_3UR04r1^?Q0YZ6ZzHh8uPMFkSK+xBR>L2Qk})Uv#UZF$p@~-UYuPj2iQI z>!dDHx7mM)qrZ}z1B7DF1iAq}2MgvRB*)o=5(b~urW4R|(F?tU9l4r81lQ=F?nb&t z641sdf7^g5{;XnKUe4(2clp%r=$hxv6e^u+DID~gKcbboIRO?Z$A{i-olVaTt*X>a zyK4!LX6?JKZlIf1u@Hn$+w>FWnQ_heaq&XnolIBB?09cPfo<8F05>HJF-gE0{zQ#Weg7%8tJbr| z|Bc?AD0bzl`MTdVE^-JMytBG?<__r-e{{)&9j*=m1Wf163H`aUjDahQ#lKb-w67-X z2@KGb<@MpUj$x4~?behV@l1=?FnkeYGHsA)Hl$Wv&E*-h|-l&jG z`oz*!Kj~4FF;$obOCFdw8rgLy4DmK;0kF>5l^5&mQ1!;W+-t4+>yt+UGwTxRFaMEp zRpg}-0w2XI?WI9lD6plzbX^Vy*9u&RXQHi>gT(rTSxISq%V#4+M4AQ%uNYelmafMc zo7!Eek45|GN?)K>{WW3>{of;20)?cGa>#9Al9=`HeZ`Lz5MM1T_T>x3^u*b)Q;wvMB?T)bm4BqC zst=tJb@>sA0Md67zu#KaelIDqCu(0^%4(bN`lq6kb6KFR4`|92^{;sb$<|zfJzBmHImNj)^!oIfw+#8H< z8+h!fK(FNfkdzK%@E5v(Bse4tukNI-`Em@D^Q1IP@vQJy}vWYKEd5ZmZ{A)7JeMHXg4km`|vs3IS2)D+&7!`2@}{K|8ub2}ym_ zIiF5{^=9{;9oj2!(TKKx#R8LkTI7b`w2oyJ(dR|NYH&%TP%LFzOXz%qanWZDAGLMW z6<)PA$@3UKPW*3p>V$hIZ6}Y!esMF!F{%ArLQ@w>)g-4mV91lf#TCG4)9P2R)YHk9 zyCZDt--O%qhB})-s}{E!w7k(h&Q{f6@z^*@ex+6QWIo>T9F{u@!$%O9oaGt%v|W-k zE=kR=rFamb{YC%f8+Eyxup<}k2P?euB}JLf&jcVt{0i!*RX2BN4zx5V^esCq{~%a& zA^p!At_KUPbgM-^ZUUeVT7yA3Jh9KO1kUK_pw+7=c{0XFm6H%Ps1SxO1Aee<(LdEm z>!=nWg49Oogj!s~TzZc890=y6^JK5wO=^|YfwRYdQATE2%fN$%qb5*=b&CxxxcBZ_ zgLj5pDXbOXnEq3!=pN?_qxwbh(-J3o@t~8tz`3-ELT6C`-kUSGDLoN16NPn)M&|nE z2PV^YTeGN;>ijusNp&;ERXwkf94<#S$!`6IoA<1Nf#;Z?2Orn$O|ezHQd^{t+$pTDPcD6iQ67~ptK|7$x zmvu*yoVG5elSC%jjH6952nG1#Hv7;dV`$^8Qh$er5#n(!EH0(R=9RL~bRdz(#N=)j zUhjsYk;!Wy_mnA>e(8jwYO?}1GdliqFGrd~&XLOLLiJpOBeBM%+>ZAwsH01=4In+G z7|>O8w5B}ylv;ql3(i|80#X0l8ZS9(^Co}BUjZ=%@0SOeDVZ8)OU9+@)^jEnTJJTA zzST#>qIv}iV#<(J;j$msJDvEIsCVob^fK$Wx_Rnzc9}S1+lR$sNM?WDP^tV zW=n-;G3+k1>wy{4Ej6N$PJVgI%U@1sxkvjnpna0%b|&AI03bKI60_zzsy7mpMZK~LmqZ>)%fqt*N;>IY=w?v)1qj2H2;vsP!EPpao1r{B9RO)Rz4TUW6sJz1^I zbzY5oyFH*x*C=x2JzU#VNcT`pKV|>ZC}?shvu$zx3vI0W-e8?lV^oE36fdXXzUf&Z zr@UIxoEAJB5dgxb@!Rb)0DL_I3)g?o7c|oNpvxDL=-zi8KQw}Dd(IUp&a*a=Z<`@D zz9Ii&k}}&pXjmp?`$mcvTVCKJuMzvE^8P2gEW>?^(pftmS?iIiyluN`GcJ3K7};J0 ztrwN^VT;y>8#3!2t%PwO_#Ugwk_Agt>sgmRd(%L^npXKqFWT)(KrAX|lTgR@47+v< z!M=?lZunIqD(I>!3|#`vpUb-y(e?LCYdN-IBHVW6Jyt~9FlB8t}zbb?SIF$@MXohF#B^QC{Og)&PK4Oy^5WV0MX4gvAJ+*<`P=RCF))% zGJHR*tNaLZaq%+n57;6^ou<~9VyNO+cDeVk_h{>zGH9du{BB;02N*u(@8g==e)Dk| z3hk>BxK69lF#R`C18i$)0NjSTFDUuwK(YL%VKvj0o$c#{(0Pp>x@=^y z6=AZl!8b+?oT$4-Kf(n&)(3A)`dLf5-^&7M%C^7 z-m-syZ)a`V{8c(_oW_j9-rayv!vrYj&wOfGWNl#KgnMt>4X`HP4_EO^PX?Kt#RSH-n(xP#3pr@Q=?w zso2@HPPv|yvNa|=BJF(S0!Mmy!Jc48Znee>)Y6qqJiWg?xU+3XwE803%qr|Obp4{;9l8dc5!Pc$-c>HaJ!K0c;ey^&}x(uEQ; zh1FQ5G+dhRiuN=eA9mZC@6F#2*+vOSFBRv-JjW=wIKn96@t;+gt7lE07J=;fYO4*zKGS zqyRiDYJ*lR9X5WnZ)QJ2j$)mp-&9-xr|WXf$JxMj$+?&h2V7=q`YQ!@T9E8-U)X=I zbw=y0H17;)q}(wxe9PE(9c4+g?szg{FUz|sU@gr%g%>htu*^*xNG%u-X>Gt5i)jl>v)gAI4=al3JZH0T%Mz_Cia(0k!^wZ z3Yh%WghV(<%kT>f))o{bV_30gOdGsuNSV8iSZCLJ;e=zl7zN0(sc3*3_gzb4z}ZB= z8sg8kKI;uEgCOA0nWqj4;z4F&{r*S}dqlQ?uIi1tq9U;=5H!!C+Z0`!A^TFQhYAG2&`v2uo8!^cp1s_+gzC z1`#YO(;kR?#r?Fh{FJzCChhTcGFk5lN8)?KRkm!{hAMQUOTyR+|K&g|Q(c6{NVhWm zCBB1gpO6_JuSB6FxGiKit?@w{9Vwzvlx66b89Xek{s~ZzhdOx zb?}7e3iefxmh5^uWj+5Hmg5C-`XJx-%pLsBTqB-Jxhu|pr&83>$Klej5iZXXppq2Y z6Hf&8UDvE!&p#MzDq&`#!eeaK6WwO};WP1+JZ#%CyM`{DsW7_T9Umqu1@3H&YtaDT z#6q)2RzUm>))hfPQFULLy#eJ5?cHNHVOfHb7TaPft*|s#Y=6V?9N=~D(vHl|6Eb6y zKjgE&cDFS73{I$h76rQt?q&QTaRDqwO86F(pHbEJ>oXo2lgZX?V?=s1x?INQ0mIvX z#&zC&=>q946_aNeNJc$02V#n|k4?GdTGh2@q7z3rg2Wv)hG*8V?vx_mCN3CX_-ytC z_rdU_683Ww-vazR>h04AT2Wicqf@ALUXt%QM zn#+q71PY==)jNhHy1F<5^G!kHj?KlTr?H5VnWx~CaijwMkt6eca_VRN%LWftKEr1I z(E0&7A^R(cd<)W-6z%by>GtVeZ#i19NMT2qNVcYc- z(5HyFHlnXBk}f4 z`H1;xl*S70${KJaEUg{X&)+6EsnS((bdkRBO}_-pi?%p)4`l7;R30?%XBv!@rADo_ z9pozjYX*rInfx0@oJk)HkQ#!LA%e~USP1)zjrML@Ht~w7KKaFTB{$z3;}T!UF3T1B=U!4pu^iSG}W_ck@-Ym{Yq&H;F2;9(tUwxZ>ZwVKAYYI1NK@oPm!h$rhy z+d<3lR2svl?H>|<&z*nAvA?bsKcE<@8@HGzQ;()fg+dlXIgW4bSBS$NOgo59eZ2+q z^>t$dltrfVYb+klo?O*XDt)o_ZY&JsqQi85|6Mi+{5?A*grA&|*jjs^UjNecw1YQG z+C`gJVg~Kkx46P_8k<&-t`#3#eXD}PAL(>Ht~&CJ_5u!J`9tfMIcj{{{WHlBf*h3A)<#Fg=%sFTyIV8g&;4)zq)8 ztpfkzG2|saA3wQ;bn>f(g-?s6>MMYN6@7goti*0I*a8bNI@tT_j0HEwJzIp;)C@3A z3?JuKhg{qSS(?s-KWq{XI^3xMr`h44XN-q0Zm`cY>Lflk!vmjptBac0K|4v;uLC)a zqnEIJuH5RAqNyHBw465|wC|?v$zCo!GSH<{=DJr;4tA~7NqQ?y0s<#ti&@$jBi4)M z+rbRxqn+v^iFyoi9sVsiU<71@vu4CUcOl!jO{1``&a>*7!k3q;z*>QmZH1G0m#v{> zbJu0@=(m7bTCgo#QD$hpbEQ$0I&JsRPPh4*;Oi<+sIs+LLEXsRYEd-C0*wJ$=8uzR-g_HUjOwVraIU?ts`)WN(f3?sS11&wG-L#S&!H=@k#?8f+12u6eN%7^@ z!WXZ_rPY@EE!M^EKBK}QU6c%pQ~n*iUMekQkE;!W{c8)98)nyN%+yY+xPc$}{^9Pl z!trJ-pIWSw8*1_y>o~~$uYH)Z0~M*0>OS^A-ggC^8P!^4jj0OAeQ)^inVPhCEQ=R9|&rJ zzv$TqDEW9P5UXxM1+&WEOn2DajTrRIc{m&`!IIX+t9JjNIFnxpOF@N>(W%soptp3{ z0Xy$h;_J`u|9D5H178xAGY;a$IPv%7Kz1cC1j>Uv-CXtvkc7q?O-lN%RtXYZ0dH5^Qaxm|iMU>vO$Bm18_o1fp4d5}BH9zsn+gji5HzydLiunM}Q5+Ht zRsG?x2C-YjLi_OtT_Ibg37Us$3}*w7`YVnAU!n)(JcQ?o;QK=|$zSc3@ii%Y)rfcZ z*?H^}IF{X|?ekSv5}UWG`CAg`BREySY?Z#sk2y&)Nx5pk#y7^+>Uy-OaKY#7usFGb zW1(l;=9#ze7{oBfKgEf8Of96&$&)bulHpU(?i;HH;Q)9k6dXJ1luMu`{k2v;fL+7! zZWKawMs5}LSQgUJ0{f94lMwgAXnCF+3F|RO>a3R&hDmb)B?MjbB93=v<|A*yVtx$> zfBcJt>uhhnxjdikW+_|T+AnO4{Y26f#D301{yM>TUh*t^FfQyz-bOtFYj(|}jnzr< z#u2`zbA+d{kd++;CIE}m^F^9*q$LD1jm?2X>gNhu@~$%r@Fd;+8DiTaS=VriG6M8l zlwD5Z|2_{Q0BS*B4RuJr+lUW&1(xN?^HXaTcM}d9R{}V8*kbc2cP_WtOJ3oXln1re zK6H0jPkv^vLt47GQ>`%{2ju3mCqp+B9u-k_r*K!!juioklstrwWTiL01X^~vd(_K#ali5H%?5wV3U4P&t)nYg z)9Ko>j#pW{gm@Jd!^JBvS;YL?wj*2t%+42oON{xi<4HOgk7R`tlJj*k@2 zgvhQp3~Pm@WtTvR)1KN}(~smhTKhE2)LGF5>jk`Ab%tB-RvuI6Y1H2s{%`FBuvx`v zawfS z;TV3Z&@lEw10O1J4zScCY;<5_KsagU?U`>h+|T4dbjgVB(Te;$NCOq*5fOOpvVd{s z_pHU=S1nb;Y0iU$E0Gr2M3Qhf}|kNUvSf~E!V zBT(Xp6zp}fre0zW9B%K{Mwivf>l4ew z7O`ud*tRgTDGGYgyt`7Cu<|L!yBTGR9(}CgXr*qN0{pP!z;DK*tgs$s%YGURaRvZL zc)?Nm;la&v?JD}jp1^QzjOc`h#k#8g06?w7bpMZfHl1LmC3)u{&vR1)a<3V^J~w<- z#JL%d(uhy^Ny)=|3_~C7uBpxTWPQ6fD?G`U=3>L|Ht1RBslw)!*u2(+OXZQDye<@? zJ`W_9F=;3c)pf#-*V4`0OuvdUf$(olA_JwtpNJS(*2LGJwym;whHbu1uNuRPO?WrP zd+9sfuwx+J>qSAoNBd}|RAOb#N@*Ei_pn)8U*j2lh`o~;7|wcWgU)6>4t-Cnb_aug z4+V7g-srfqD)A&B=KQ>^JjQNO(-{d6e|nFJ0-)UHnoiaNOA0*jkA>~ym<7otl9>EK#lM(<%1&cnG(%9Le=l-U~^W_1x7Eu_4=g-Lic+T87ku>D97 zdn+w;B)MC~jI2U|y8hwvKjY=|Bc+Pa>_;WI#4EwiipEp)m=BtBaD4|t08Na{T!g}7 z3e^r@7Vj!;J+sOu_qUQ6)Di>e)u9^^`0I-E!ngj+HZm|(h<&L|KYiw0_$1$b5gJ!& zyQdt!*L?&l_HmaK$=uGoY^716MwUfEbu3zcN9H(Yu+G3`YXCfMu1Ze682-LemJ$Wd zcCPCcq9dc`Z{uZ{m;eJca64reDm&`o`&1l+8B^!$UK!w)x}DFJ6az|C_;`w~ zHc&HN&5hE!p(V+^kVouFv%*T(J+}H!DwHjlL)6NHw<%Oa+K7 zl7?@0-AFhzMn3Y8CWpRAP@jGQ-xU~pnUyrtVGy*Mz&ZLV{u`JdoNIgP|5MLRBNfzR zf6W*t-Wx47vvi5LXnKWkYxDJbl|i?Zhc4ayR7g6q?$S#4^7p&_FO(xL!Ni+1UDN^d zXV**@TL(y{zDSAK&;P0~<(Ey$2xz`Bd+~nA1}JXe$v}^U#_bXn-ZN`Fj=_~}O2EiC z@oOxp9G6iEwU(({lsv80+2a+{(;P$HGqB~=83k%{gq8k+IJK_Y>(zBBY{(x7zWzgW z#Zqvle%_-4XM@j67OvT7ybWjtXg8m|NvJ9JM~t*6U;l+v^Cot+imYT1Bxm2)3sfOs z&2@Cxv|tAo-XewlPmI=Ee2ecG-HfW2RVnwx8abx6pSpQYgkM@R=c9`8jsq zC)4#(W<+0L6z)OFBO3gC;0AN9!;+B==GZ64zu8{xvIxLTcV#aF88xfX60230t;|1s z-e&qI8XR@rK<2dCEC&uw0?W4(3y$UecU0S)abQia>2G5fK6T0=dm>0EmKJG7(EO+L z&3~3vIZslSOXOHo^YLlh-{RYY;@@#i*}@{ z2+%yh26eF|P`)%hzJzPiN4-opbkRwA35d2X#PeL^dt5dX?7cDUO>B2?Yb7MZe=ip$ zG|}!vYOJ)XwTlVS6pvYY8XDMBy%L*;fAT%58;@^ZG4ecRBN$@d9VKyC6(Z}8!$Lk9 z%I6yZ803UEomar0r_AHNBUC=Gd+3}W2{G1vHi?MGN~zr%W~;n1Rcec=N-vQrKqyn zZG8}$Yu&ZqY>B&O6n8jjpJBLH9oT@*J1&IW)`oQ$oIE@PmFX6lLJ>Bws1Hd^+I6)v z)|Ta#H!N7bsKHx0_+Ny9BAgbHv_;2n6bljZ zWV{TMY0t|!Ny%*)o4H7Q2RjNv+MeTWKO6^+Qs9+ysRU5`-a40^c)@}7? ze{2pjPqa^ob~1L-3g=*TUCPyBNI8Kax}xzni_b>;IjI#twfU1dI>3E)D{}A5*^8=} zkT-#MK3%s@&$$nTQ4048iyl~;FHS$dVwoooioABON^W)i`1+2Uwbu-{6^DlE>)III zy2xF^Mz)kpkP#eQ=gfMYZnS$^T&@JwPrQ?`q>eXqugq6g5 z;$s}Fs88dsJ^FLO(_wMxoi7~vGH5JA)>H9v5hPudr7`YCUOyL?Z{Y~euQ_JUuMt~v z3-oI$g{1_lIJ(vLIcqc+&7_WG^pp3olALu3+si|F2a`i(scTnfd*Cl$XSCm~+aWN`_e&zE+oF4!okJ$rBX#)d8xlQuNZe70N}f z$FrS_pHv(2FRbjuk{Vm{Dk(l+*$^hR*uVuUL+q1wgzcKk`c{tS4n6x}OxcOd;wCO= z!0=AOOV;^6^6m}XxoLHOX-@0dF(iGnrIb)dJM_&w_MU*t-PxzF7>G)0pweOI>eCx< z-LSl}P|UU$8NB&$6E*=xd~49nZd$*GxFXrv2;2KqpDll*-Lt@HDr9s?dPk=oEC=g$ zkjxS5DIW}G%e3*9&UVCFOaVFUq`m~*SxuKcqrvX53J?oZ8| zm>3-vFPuNRb!Ci~9g0AD9lwjDE$l6Gp7Jyh#6H}vQIqrA9=`>T8N)qatuFv-#Zb%_ z%_H=X{nZq2>Mo6%R5QfwbXGEaQnE2Lng&@wNj$o$k!RHdbbsnrJx8qPXh+`8aWG}w zb2cOFzB5Wx&3`a^LPDQtfPl7m({KSpe&Wp(W7LisJK0(AIf9@+i~G)d9AH|$B-ipg z)wwXH@aZGcv&L^A@hX8m9S~RGr9-YUvcan4Ims0mn*Q@c5>vEo_1cyfYQ?z}$Hj9} z1e#Z!0@?enn~sa#QFBg!QRrb7(aD+f>W=odC7~hP0o9gZGXBfx{?e)0=C=%Ql>`Yb z`3u~EnF2=Yh>hR66T9+n zu^?N^Z+x^X%Qv^Vn<#3qYWC2po{Vm zsQFgB#Fo(2wT2sQI(qbW(Cfr*{kb=%dhtNVTiN2TTL|fc^M*=XStXd4q^a#x=P25M`qnQFP3rrC_i&}c$j7CHq9Z=Dp8emQFi;Do zd!^X{(?@cM#Om1@JR@eL=7B|ZOcJOofLUH63DsSF0Av_6&1s)EFg{g*|NIF&ZIwyo zG6#rV5Tbc0yPT-c@}aCK7aKT~LveNZ8w*6hPX&nB1xe}5XR)X55Xy5idC1v-4tM#% z+a6{TM8k zQoRiUBs=c;-}K6Ia%_cdSQrIoBD8%gV2ByRm-C?XT(N%kz=2<~xe&}?vlEW@1x+PDw6w&EBE7lccu1?DRv??5+eWTRb;+*BlvI(_9 z-=vpL#}}xnu zpB3;tZ{dukaxsyUAj!lGMjQ3{y^`3Q?1?+2wOQz(7{=GNZ^^cHYqvQ}5TOEWY3ho` z+P6J)gLlIq@3iK-9+FnUe3!Y;1gJZax@$UHQ|vF(G;O8O_3IRnc{rSPoVXKzl@8?D z&7+dBL%H)>D4DZ6R^4ZTcEwg!!EV*Xy7snu5kh=k=FQQ0)jeHHHKvtcO2ba?{R{Mz za-tv!F1Up1RP&MFMWEh>4+JI=)ZpFM?5$R&p~|U4r`xovfg_agE;i_4u8(#>eF{d! zg0!(F)a^%sxy}Mk$hD2Exwgk@Gx}-yP+7txGBNZH9G^;%z7O<7GZy`X#))fbDD*g4 zp(lxbX=5`kYj8({w4L(xKm%Tp(}L?aYKRb0LtUVDei7-Z*?1G~pnnKXg7y!on?pI6 znk!t_2mzRb+S&~NDdO8Q&(J6c_j2=T-i*@X4F7K87nTZUqwPpnM;QFh^S&$)Jm@H$ zmy;xcdGwjIomwclE#ad(E)UwBki@`2Tf9FX*^WytbQ|X9vZ3Cp` z(SI!+;L34>ymIIrWdduBJYTpf%GxwWec*l%(Xq?2qYbOS&?+?Y7rHuEetGRhzhaMD zv3pa^{@2>^@3a~KGS2iVXg&^2V-`uAe7untH!PpydP>XnoGA3(L)*C%__e(+1XL!) z>oTb#f)i{Ww!b}4a(kxy^S-tfzZY|+G1G>`*tuvS_ky(bXr=qHezkZeNz;(OY_BmK98a#X7hf`O7E*`6Gam6c@gqXAix?iub%8kZ6hh5 z8401GAA7-g=>2{%RzkDviH&rM86PRzwvL*nZNz(I$FV17v51nVj(hg|hlGnOi@0*m z>9IsTqM%4#0m0SvXf>n#4ez>y&kR8_DE;fEewJc(;3nui>@$1_0c&*d{EqGKOt1Dz zLptOjJNE$uCaZIke#Q;grFI-p5@_}imiMxG81q#}jB0D;2B{8x)?sb)+HYNatdsK# z+MEXtFmqVm=`&{&M}8+(yE@S&a5NnH@qceNfty4gp%R-4qw}2kGK62n#+#qL#F8lK zG~H4Z2#q9~`S9Kqxa#C)L4F)GO?u-et+3ypC3fIwsYM6Gqh zu4#r_XKWV+(v;aPYrm2T#TCO!aa{QIo_*Y!UeuUwkBgcv+sWLk;kxfFxj0_}WkK#o zfLCiWci}pGo+9HM-H!b41w>5-M9!FmMTzrj=qGGy^LUUGZUbmr1rO)Di#G+>#^lx#ctlx1U_A@5G!GTI#qR zg?h)JIvONiG%zEs^2XyYrK!K!P{o?30~bs06u+F!QkZu$$%8f$GSb?Zr@`#&w9N4% zaWN9B#LSx8vs9x?a(hpto-ce|I4kTk?PtHmhH6v5c-2o&6$(lXsHdrjpj9aJMBL<8 zV*Zx`sg>PGt;%-k^%Ym+({LYKUUpz1^W7c=L2vd)s}V@xu- znd{0I%_u!WqVMvbcA06iyu6ETny!^V+pK6lB-v|3#fQ6sn#W2n)yCu!6{|o8?W<>T zsdzBUuZ0g(qyDzC54uO6N^Oi6(^wWM(z%>jtNJmBZ^~u6cly#Z?3cR++JQh*g@GxI zFgkr7axXXUY6a4~?U(tmRtZA)xr15mLZx-*)YZ14jARRyp_$qM_?^FmQvZ$x>i!_B zGF9tT4{C_DE$vP@BNu+Z^VgQTa&QEyE-f@02cGOJppU)g!X?zdG!oaEr^#s?+#a+> zRtZ$-0=Ql5#{Q|y2P%I(`tfwObD+-HDx*Bs|AB75025{DeZ|vui&=2jq0X3s_Py;m&7E&=|Nombyv#daKVbQo`4F>zxBDOi$2=KD-j*>V;xv z2q9){?4f*OF_G!$eMM*7h-nVp^P&BW-L0>GbT;WQ7^B(M+_bCoUsr1FMYuO(Lupe3kbMZpoRU3pf(>_ zElPFcnuJp#Hn3mb*)6QtWBR;+0|8$@^IYSgd0GL~ttaPex|@!G-L*5fqV62c?htbH8e47TOmRbu?0w5pC1{l6Ey$01&#WLnklaQ)1t!-ygKg*dG2mY(_a^ zC-a2VVx2tM%QqSNxcZl@kF8Hp+qR#*{dfjZ3ON&fP+Ijg&1>{- zgXD~5qf?SRI_PjvrLDQT%YXe8*T7_^4Bsq(HZU?$_xEoa0EN7rz7LO4P{v`J&Q1g= z0~G!cFP7g@;#T*xH8eGoK7IP+E^0H92x~vw-}-q$Y~pB8wj$GOcQRMrxbYlq(sG6| z`s5fcYj%b;#lpX2!F%aPrbuDt_K`ofR5ra&Kiv(55HYN!?NLlns59w?>AIwYdE zK;{q$roV0z*w?tI-jA;*vi83zqz-sOVR^Uh7$f@P<^E+jNN>|LKkX?cwDGCdvHHtY z69OQzuCBB%4={e5F)H}HN23K17BTnJ?C{r)`>R5?{kT@DlKrz~d{FlC2o_N4?}C;bX~Zhf@5ercVt zN{(JJ>KDd-_OB)K@3G9eN>%GI8OX@5?&sHNWlDE%Lvawec)qqk@ky{UDG`ThSNEE7_=C?uVLe(6a3zm#BW1>7(uAF1P(>987T+lL z`3O82;vr4u)Ak|TezQ=h()!*Ol%u@o+L^~L@UW8tla{}0!KkLJr1UcXL#EkvGh@Y0 zmHuPATebDk!C9&Fv@~IsXNzC1*uX_-$BlX`V%i`X1PhDUKDC-&OasOOaX`@Lt!z5Kj^E2 zX9|E;$DQK)jUyul-QC^Pex}b{EELyE3sCs)8LNzpjI36{(y2VztvL&ei`eiPJhnb% zXJ>~`gadaMN3vqgc2d?^wE>PCUZ)=|Hbkd4MUBRE8anh3Vt)g=l*qHmoKNGCc&MtY z$0sHxy5D5617%H(m>i6amd!pidYI;SQ8k$MH8x*Q@recX?#aK>F88oOPewT8hcPNli^H`66Hb-7WGy)=p`*0uB_u_oDOvwQ7SS z;Plzw3wDdmHFxO=g8yX85QyK*(W>F zpb9=GeUzd;c{x(LY{&lJo55*H8{^&M>_WG{LC+3(-}>UU7vmyYu{<$3TiBrz(|^!w)+kcEBegB8D%`?X() zAAH~hrIJ6jm@mC&{PX#1{pn>D7KR&6+SJ`DC@845?mVmZ_;F%-db*@FXYdH$stXfYVfprXg^-^=Z3Kmc z;`8%)mM5yXTRH1It~jo%;KmRMQBgE%+S)1JpsSEtqYQ>Mdil@56+V#n;fPbbuv%$=n zpmnTx0US{7;A44iz47NACxDhr=MJgPbMC`8$Pb+S`n(1BfGw`c{dsc<8)1~^0B{f- zv$v2R&7ZGRPW}Jz;~vQzR|}{fJ)WEzDzgndUz_@|EU(%eX6{0^z_~^Pb`3b>+@^Kz zq}={^nw>#_9voOyN!L1?!O;{hoMow!U>(i;fA<15cew!kN?ol0&Y3)=5GB2+gv*K7 zs5h>F-)!?z?gsVO*%@*b!J)@wU~_Su;&lGCiU4mm@aLE>xKn>Zm{jF{A*2@lDJGvy z(xxzeny^VyVt|B1ZEYR!-GA&cdcjw zt_?J}701nv%Zg4OdPc9w;^QcPpkR5AOpHG%U;iT*6umc&;^FGgz4hn7jz%KvV% zp4=pXw!RK*vYsVJ?%z$mCpWoG<23gZY|>iCDB@pDHiJz%Agxc15;TvM=pTV|RDy!Z zE&*)PG^|>d{N2mJ!Qfr-1lNwfwEx##ouc464_?J-!Ki0k z!AuX6x+_3|a@orWF2z$N5{aGmtl*+lBq~5no>Fv|!Mpe)H`S~>jxx^dZG3|60ZRgX z{2z2x;HL#8S0*PlC{$x8V?ieYUVuJ{qW|ciBB0Wx@a9yDl2EB|-gA!0l8vjXQQC=Y z)y+L~@)6yWXO1U?!bAcV?F2t;mKao++>}VVK}5XldxTQs6uqs>&`eCOZKX?mo2NZp z=oQxFZf%_d?l-Chez7AXBcV;#wk0^}nVI<`3q^;AhIqKS^FpM}U58ed-DJM~_Cd!F z`DsYc*4+?xR?7ZNwIi3+G`|~v)OD2Kv(I0eo62VHUOoBzE0 zA0;2RIwYQVo)mVwv8MPou^GiE>Qj1uTjuq_!>e|_E=?tVR?4h*>Q$fISjy0=vJLv$ zbBmi|jxTPcENcN8l*jX8rY|Aa@rT3wmuNj*-MQ`qQ%8iNo?iUI!oq}NJTsqN&z5cX zXhOk4N*J^})9a7m;0Ovw*>%p=HME`{o4+@~UAX+u_%>Ste4KUR&-YwjozmMIq2j%t z!1aL_xXN^I@f8-fSB$0(uxRMU6 zxCV|SyezkD9t)2Z=S=wUK@j|xD^I-T(j08P%VTI{#79L%1(^p0-eIJuSLJg=ePqpC zUTp?RHAO?~-S;E!ggpbu;wzooG$EDr#iAl9FOflsqxx32*QX!ma^)Y3Xu*%e-0zLJ0!!wjY0hg3zd!H`yza(B zwW+dFXKQ==VW$e4tT&JENN$t4apC=Z&_QUDUeCxV+1A$9C1Zl3-{}9b_MYKzwq4t> zh!7D{Bm~hCC88zKqDw??(IVQ2=)L!Hl0q6IYILGS?`1H9NQgGNVU&sJZ3cs3M)^+H zmHT<`=Y9WvKls76&78-19P3zX?Q36aSJVOYw|P#cDQ*x|TkLQg{v+i1CFJ2_R|hzT z4!vBfICIO4j@25|fX7ZQDI5PJ%l;goS2#Oz55j#W_g>k}4-sHk!VUD%y9dfQ`kj3C zd_kB_t-qT1xbBJUW6vg&R+~du*l#80_7d$Zfo2c zuqEe3(+ugfBdeAU%v*rUzV5b&f0B_p^DwfZIu_+2X7C=1tn}3E9GMlwVfhcuC>UuA*tE`xHETS&zV5ly>{c^b>MbU8B79%V7A&t?GY$ zQ-L8o@$%;C{?6Ts!KO9lHY?%P5d#1Q296hL&R^wc+Iem+dTkRMqzMF*+JiZuR z{&^~2^!OV13U3+2_bQX|so#yA25+2khKA+2_iv!z4=)c~9*T=JV_eM3_5TkxpkPgH zU}&fYroaXU2IBy+v9S>_0qt)+8jOwAf`gm6xVTio`}`;=EzQ|NWh_I_eE!^80uW0-iwA?uxB&@Ey1Gr8Prh#evbuhyH2FAjAN8*DI-;(Kxj@>1_ zAtS%ft$YAjF(y2JnX|m06NKxaL^Y!a3Qa_*h+mT;xVsERmWGoU5ucw`sKx$nLYyF|l|-1pt2?a7pg z)}{PuBUPar^tJ8UPglFr5)ybhvhUAZ3GX@KWiGS2WoN zB8=p-0^psI<`h|V3Q1(2M#|H70p>-nuxqrnzvRHp(ggqZp=1?Ie2sUN9R8lQtPKiv zb#-e{T(*uZK#!-KLFn^@k`wm~1=KTEFIUGgh$&^%keIjdYp5zX85WQrATV)<<*s^O zxA({SoyhnXi|i>AhC)GQ6(%E10m9eCm|Sm=CJ6lny0tuTdf74QtYmWPn` zViOa`e5Lyn|9& zgKJm9l|f%5LH^@Z^n~N_Y3Q!1RQvQk7`k8PDn6~^gL;i*dZt|xZa@=7Ov+M+-d{t% zY)Y=Aqy(n8Zhl0-kj0wV2-^!FnyZ;bht~_QK|Lf8@C+laS z8HdkmkceoJ;VP}?E26`s!Ae$Aijjw{_WjwMh3%aW6IJIF?S zbMM3_Byg{+04u&y|JuNR?=HuKe>OIsGLKH;uP2yYR0(*g2s*lnVg*g-5%poh(CKou z%4rf6IHthmMw&)FJ%vlM0&Ye8V{PFKUwj{pIOU*?K)SKGcF{RBI*VN~- z#){Z94WW0hJ_cRm|Cs52M#_i3`{&mDeB+wbI=H8&e&`J=$GH#G|M5e*e0}3;r`L{X z&V%O^;rHml@WA%^V-N7PfdWlnoXcbOMhJ97kHPt(r$f=B!CYVE)&n*$X;hZgRsVY{ z*t3Mk#$KJM$)oy;>Q3yDP6Zf97rxGB3-PT~Rj-_J=wElON~ON&098fCSQztoY4)p# zNR-FJl-6t#sF_w`oE9akClw@b)z_C(<+^Pfb?fto#y4-@Vo^|!)~T4~vNMmg-Hnga z3mi{61ubi8MD4ErKfM|pmmi%v`djb9zD59*psf}dg-6}X&$ZVT057O@Lk^w~#V=ER z`%d?F(m+t)lfv`!n{sp?9kVWelrD)sl?@Z2|$$eKObm3IiaRkHy3{YHYouE-K zp|hR;v#E*y+()j{Ql@Vb3P(Mcs+jbinJ@6iQpWtzyre{(j{)|Z>J*vw`}vNDW3<;pXZ_>?XnGDD;3qprd4u>T`O~hkxVlKGo3{1rvk9 zGimqIo{;ffd7vir1HC+p78 zBm1Wq=FQ0pT43pUp*ZJzHrYT`U*A3Pk|?Dd!>opeCk%oncee5wGjnsFoOYTQryH3J z8MLb~KkgQnrGuxpJb{?WqJ+b)HI#DE3v}Oyv)FKPsd*UYIe!zV4gcDDu;Y_7@9U|I z3inhXWo%o`G6&c$I2-Gwusc6%@nH0xQrgq{RlB543vk{S)lyJ=fe9AT4<)YfYC*eV zrv2iw6(a*ZgXV&ivAZU z*!Yb;F$o5(SE~3kB9q`%SPO)IV$T7k8`N!cXuk8RqGX&1$@Z15nj`h@AVqJK>`*C3|N`u+VZ-d#% zC?qJ!a>!7ROGHHf!Gi~BYLJLcUXX z_PmSJ*<(Rn6*loQ71V`{{kMAd=}6N7sZ(<_DcEu5M*oe0p9F(&9M-bDuVE^k$2Yo39zVr`=6+%%g!?;*UlbM;1m{zCzLRr&IGatyJDj84 zYWYl0@8x$({=D3pC$YUG^Y)wR(tdOY@FLC+&CR2sJ$@h{+~%dIa3xrHa{Kw#^;ZDz z70wFx*;`EVmahbz2-xX`GHKjBIOk85Clj?XXz59?D&!o%E}X)9okw{@NKO~QZ?=KT z`5gM4XS{!cDDSkP{_60(M30ZEdfc%Ctmf!q4`%zpG2&H;=x3&71s!H~cTx$}KkTg4JTuW4 z#>py~&y6ns=0K$jW*{tM)$yrPVsQwQs1kj1g+Qu;SeZ1qXTzTjH2Jx;IFuSH6MUPu zqgQ{w8k^1Y(-I}FdKdG#l>Ed~YF(1Czu zt?h&`SY%-eAG^S@F&-KuS$uM3h<8%-tN2NANm=ZlZarg5toF&28?M`PSRp>!BYcdG z1Ag4WvW<2sCtY7}J$oshM))Csal0wZ%-}8!7QYp-&2x05+Z&U(=G(&Xol8ybA+p-b zjL4H_Qdu)`RoT z9pt}rbY}BjdTE`@MvtZZLlIL4|IToj{9YXa7jwSx&Z#s-vczl&37_^ zEv0lDvFHAOHfKQ@BM56#%qw< z)7Y+@AU5hr)NxbI16)TgZY?&s`s#hyQR_<_UHDm5)cjNk`|#=BJ2&B#l@;+X_IA!4 znGQNKoEE`bHtF1Azh!K?+hZ-qFjJhHX|p8-V)AxrE~{2f5wA?FOqtn8OHSo#o_ZU0 znt{rVX@T8*T2kdrA9 zUqyd>_H34FZmy(H^d%cC>5^QJef!GyB%n2KteK{=Ez$#SS^nU`n|67eAe6g{?>c)x zF|%YakAAOP*~^wj%Kst=yJyA>o~f=7PU5Oy7!57s!XL>PovUcSnE7x;?mPgPrZf`c zR*IEa6&=n(JpNOS)tZ~bUDP64|=B@?Yy2h>Syk<0X;qZwJog~Gjh?ROYOlje&tOJ`kT-#pX$;BxoCsi-KUz> zPhKgMP@Ec5b-x^cX6RmWX(EkqgTmgVn>@*^T?M4Z)nNvMQtN=M`YBHhE(7!GZdI~E zV`l*{=RW@is^CNs!*gUAzdjKVM$2|?(hL4#d$dRr1h3gHi6?sqof;GD>;vul(GL&Z zB}wb@lEMKOAN^iPviJ?Wq;mvf-8BH9vuHX^SlCB76N$4G^KFWu9~GtUZ_&rya5 z1#Q$C4M<+N09;sSEt1>c%*mRKP;~}PM#ak7`o-C;G3Ogt*DO{+P)BL0fyGr6&QMyx z_>3*>Fs#N6Q_}<-$+=}r`Jkrj7!xDt6lpI)LUs*98STAEI5+_zbMgwNfc}*wJ3JKt zj`yWei0XC4nV_Co)^>Dv>}+0r-f++Jtm^3K=+`!YjuksDW19FSwMtIz!c)Qg=Fy!>Vxg#@t!%D4uG8ejO!c1YNOpI-*6I@yB!E5x4tE290M zXy{1fj5k7m!GZCN>j*;8e9MlJS10HR#>ki6_ahUg zid~cDA*N^j#KT01-i3vCplGt#h{`cc5FC2jXZ%DByC87@!E<^44P_hch(QaWPThKK z@zXtnvrh=qeim_|esmW(U`c*D!y8nT@!n|=U_-I>LAjFAi<$C|KG^nMXHg*9JMQm>&EL(z+Erv3 zXc@naFMV#s6x-y>kv6h^_EsRHa}>d2XSLGqG=APc|Kl;4TFX*Xy9)YBtE63~ON&NR zJD?&dDd{;~i$ddOXY~~YO|O!x3a)jbPt&SrjGGU_M&!8lGi2ri2c_%YJ`fOk&b<`s z9(1R=V_gO;T$Qixew<6^`La3b)-v%u^TEqEH-SSBpI2wX&*XxN*eMWK9&v|AUd%;p@I$cc~2w#Z0BK(ZYot~t*laNva10!``^@!$> zDK51Stz<*_RgWe2FjgC(%hBv;FCCZ@X7MC{w*4b0XYdaUG-a4Oo9#ni{`tc}OQQ;k zB(oH|#^sW!xW4oJJQ!-nD5pX)KE=^(&;hdA=uFumxh0+9zfj8Z%ml^}hcFF2SV)TT z73b&IU<=)!jd6QX!0!|JiTtc);}Hqhg7LHJ0mYxY_qXPbLX$#{c2Nsr!*fmW!J*fe z#19rjIXAvI@su~i>4fadRa!Dd$E*d4&4TC;9Ttz9G%{7nlOB4NRw_~I15itLg$L4& zSe#qWhxh&C=3{Izl%a=jxUB8=&woIiXf0;yv$U=s{T7Q2vENLsA~O6|>!tQTl8csn z>U%0^Z+|=7{u0NEpYwMW(@R3+s-}Yer?RC_a>1)1x8{dI!0|ikAx^QLB|V5CXJ*O% zBLqaYGg`WV#8w5=Ke`Iw8flJXydw8$IPf3)pCy*qarxz{zIEc{9@ z-h4Q4?7mLN17q=9eW1@4@Wb0lzF4iv9yo+A*tW0()8U_q&y>ju<&rmVmUl+de;K^m z2xTqTSeMKAUODUSwPz8e0}EUi<5{mRGmdJr>pxb*riubxu7N0Xs-7={Ioy%~Ypm+E z2rS$!w)g%cZq^4PA`7QU){h@(>A2M$a2ourYQ)jAXxY6RgE22bxIEqHWO+wz@fOro zh02_e1J(Qt5~@gz+47(Ph#Cmxzs+p@{`NDA!Vtk#N$IVou<;$dx`cY>$le3d;^G~V zGy8e@fG)DPuh`nMOL^j{uA@A=1)I!NHCs$kuek}mCYhtXtr4uD^YTi3JkQ%j5-tw> zNlG>P6|;l%)NMk5L?te;+UL9-o+X53o-i`m^DVtKhyf0M z6j-yjaZiW&`oA@T*-1{k^vLQOGOkFh7KQW<4z^9SP7inwO#J)$JX+s%-Oe{pX(7-y9*=9mXE&*Lr zPk?@iaPTr`7ZT~KMS6qL$NERCkKzW1bf#oX-+l1fOPZ4hqFc*$-W%CWcIp%dK zv(s^S6JONNp1AO~IAm_83keIc9y(6aP}Y;i>@NX978&~ow4nENzJ7iQB#G|t9}zG; zV0$cg@%FZJHb@}IwP-<9_0I(L(B<2)ZM>2l-vlp@9!85`K0IS@k|Q2aGy^j;XAoYf z>dXlG1!5lrr%&bbzR2Sh-a_$7FUq4fFF%pYpd&QL0U-d-<Tchm^e#@ARm$6) z0UtE78@jcSB)&7ZBR*7SEstN-Rllf;K!gTAd{ z>A67!ENDnRHlaiH!?jqSfn9;;6|I!NYQlpY9aAL7d}&~nn;?9kg)?eNoy+=FCfpeh z{1$3@<1KR#km6~R9Jqlh&zw*3nX(a<8kxE7Zps|7v{0J3(3A9jk3;We^q{6!+D4t} z5sC4J0+6!3skrAqS>q7bn<;N0?uM-IMDI-!;?wuhPe@ z%V8@NGnLbK_kAgs#yud?P?JcIFox9dSbe6lT=VJ`IcyP)CVYc%!SKLJ|mbgP006)HufA;Vx*k5lcg(b*uD!iy>p#w>$Wwez9LI&ti+wIw?*V1EG@(hE@2O* zm(EV3uHgfIv%P}rfa>Hf82!%9q=)T zC0hn%J0Wk0@kX|qTccY5;I=mZn;Soo2b9BbJO;YO+h+w5+C@Rm=-t~IM&Zk zSn~MYY{E;F%vZF+Qwp){o7C3>wtdWn_k2jsD=+C~R$sQuo5$|nEW=1TTAM4qKYUuD zY`d`3MUD^gUJbjgC9Gzu7#hCjj9j~bmlS!qx2ET^Cn(LQq%8txXPvApcX^m&7b`3w zoK#@cn^=4O=eFw75m%SyptQQ(Ju@NDMo9)mi zO_Zp98u;(S$Rk1=X!#fdIQ5sbj_+Scb+bj!OyBKgH3M}x9qTuakN-GhLZee~?~w#a z)^eQX(Ie!*7*}-l*8b-S*J)j>0e#>NsVB1{O}`* zO>rVoq#C`eHoZpH1^*!`fu9>v8SMnOx<)0)HfVvY+w>;TFiOd+~GG z8f+0T*;*F|+n7}#&dnmpAhEl%r=_-Em__C>u@)y( zNZpm+W>*_rO=Jw%L-`#h7USMlJ9`GZT)KuAFO7)|4K74X{G33zn)Xy!kv10MLnBpD zJ7$1BmcrN~R#<PA?`w|B&XR~Rc5I{Ho3GIt%~X4-@m@;-acZMb-ayk!X?|Y z$WodrcRI}VwwQT;UT?z5)mi4bu7ObZX6m#rSh11NR)ie=@dfq7yU2%^r)16U+t#dG zk}HL`e`3P?n$s^p-+TO9G^BJ5jzv3ZWdSc0D!P0+CfJ?J8>${brD$B3JoaZJlRLiI zO&T?_qeZ%jv@F)mD-*va4mphqivdbykYi2!PQQr|X zZ!~}eZTQ$#g*d-wi$Nqy>gQ{xFFL)$&4iV}vzUxfu0td=WPplA5)XXP^pASJo`Le0H-8s?^YvpRlxg>iHzuUc zW2c69wM->lCA!&ck6FC8*6^eNeFG?x%txHeQk_sQCI|stKN)*MN#_Uy=a>U^SiJ|r zx0|TNN}=(TQAN?a{0iyfW<(VVrz>IXv>T9;zUX>4 zoJr$eAt`NE&WK{~iLTuvk+0dil&LKUkHFyR;2yz6Z4ZqNDfU2j&o}@}u_RX@ny1-l z4u0ut>YqwHWLwKQKC5!^b0)(14)=y6_s9u^hPmj3EBTf{h4SL=sN!#_G<<&~I+h4y|RgVlmXG;2?$8q@h5v|B~E3#{nL;L@729P?HU37J6`|=V`4#;+~Ww87nptWYOYZo8lwDcad(CC+j6A@Dn3#9UYkXBo-Lvy`Dvl4NKo zL5$5Dv57Nk_zXbW%b29c5XzXw0^46-GTN;b0;%Xl9&|<>BpE%sL(d2Z(r8F@eba90&T7zPc|4+^ z^zF6uyKgX{!erSz`ZyxunZC6o$6YEJIJc@QAZbIBc&id+Jq%yCU!hCw4#=YJ05%&4TCZ z56e{U;L@(_4*O~KwbTDthbX9LD_9#G@+`> zKHXekw0BtSmkid&@!;9@^7@>>(ds@J3quz#KO(7bLFwxPE`3ysZdLAyRIV+|Xn}C3 zKTN+{?*v>o2LfNFtOIGo8g%zb>6hmtM3Hi01~UsvPI*<0-DV%1{WEJyPRx(f=UI9@ zt2feneSXA|Sm&GeR*Zfz1ke7%q*3&PcTC0exsCAYRWEc{@+t0prn7Q&iB*pyS6yrn z6oc~_3Z&SHyShF{37N-|F2&Bz9PO&qQP!K9S4;>M%ZmL3lAUgCO~7JbCTcC~Nhth= z=tjXJjP`~#3!hhI`KGFM#a5AKVn=eIL3PTRYk@_0r}A>%dGCuRGmG(+>jX)?`)*~0 zG{a8KFis1-enjkp7xj&2?&*JD)mo!Xg#|=cR@t1_TTL0dS|}tgk?#0{&Ac~px2ZhW zvE8IloRs(lnA9EGJACa!TZLv|Ss2}#N;#7oS(hEjd8DNexQ$@!c45bmrZ^a+Na9W7 zxLNrK=G7Vv#{$@v6gZGdT8X;nGk`JM1uGCUPOkBLsYe?)aDr_$%EtRhYPoS&VmaD_sPl3^DDq*olnJGiZ*x=7%j3?-x|>C8G0sH zCnM%ZngE|grSgZ+eXXKxn!Jvw5&jUunITvAmaMh0&qyMD)sRcSR-@)@2~4lf9u|Tr z*jwRbYNsTElWL9MUhCcOa(1d+=_=DhC%cGVEAyV3c=jebILeKnwQ;qC5YMc zivr?HUPmP3joyZA#CIXi&+06oqx59_vJJ{GT!u=E5mhS=vAcjGccs4eYYn3k6W+I& zqnCYu^kcalnvlN0pUKg>_m1wfVeh$Hgkoc1A9K;cbUfBIaq%Th0a=G^j-?CWlmflTr@S2H7 zF&v_dd_%U!AEACJ(8msC0Q4RG`^7gW?c|xpCU({>g?~Dy8}`VCU`@BD+)gH>s@`V4 zwF152R|`M$Y3Z$VlRkd!>a+vP>4&w1&rc~gj#Pp&j6r{J+rbXjN){Cw;3d)Mx9BC2 z<xg_J?gjaM4=xaLQG?4a~h&8ZAHTOcv!KAzly2)XDCTwCqM$xw>F7~2XD zMK)*4I7%KLAL6%3q;Ya^^pd9(4; z7;2shTTVaj(ft(~=vpW|Qa#{<9AK-!Hsa}m)+xmO=>#$nzM0jpv@ZFik%CcAjn_;w zr7N;!tu#Xp@2}}$4w3!@kJ35Ow6EbE5fQ}bHPE91nY51LH6_}^gr!}cFZrYuw$)-P zf(&sgMDDx{dn3WF$#r`E_v=fEOBUbYzkipgK$AMzLViG0X)YE^;TzbevvmmjtxL=| z8$+jPIavwXH#j!`q(E*qVFSGw`*|*6w;lZ5Us0o01DY#m(M}yH5C=*Laj-MGDKz*t zi~m(%A8~Q_#;8>DNqASjT@w2S`gOV;^SE=mTHu!c>xPq36JGw}4>qT~B-21Uhs>JY zS303K$-VcZENorH;o8ZUhh8sA7bTs^HLKnbX`+q4?HM$Q`w$4*O+8H59{Iq|-7lIb z$O~13FU|yP>QiW%SR`CMK{cNyG|N}7`{NRAGSnAq z8w$jBrj8`%v3m|4X*BQwsG%r*ie| zi_Gy-Khg?BRq4Bb9|xZg)>##$^#oi4&tABx&2;}UgRrr4dr0{3YS4z9j##bsbf+Sq zkBl;5*q}COx5R=TRlc|}#p|$N{$xF)Pp+kl!lBlK;i47S= z=}R%4mzdX_tB^SmH*g57hj>LU>NrFCW%EuCb~aV#tV)hth(f5yY~hP`wtT`$5IB&o zDz;wy$FXHPY^yg3`fIVORKmq8an$A0vfno|v3XHUEqu}rkh|?BSagJ2Z(}8O=|2ig zOQ|HD649ln(`PCG?r2=ea9w(_Zeln?xePW&|N->!^$v$JZd@nx4I`4^pB5l`+W z35!P|=JI;r!`#{W^`+GkIiIfgFm^?#Nu*G2)Xuh)@{9EMidQKg8b64Z8x?g$(Pf(Q_msXPEi3-XpXfN`I5$7=G6qFr)%dl8D^!zO=f z|LF?2F>Oa`Dk!GPT?CWI!0$ia(<`}MV18&1T|>IL7VVhO56_V*t3gklBtfSsfAGO>{mG^x#ri!{Kov=wG70qjJTG@eNEnIQ*L@U23b!G$ryVdOzYM8 z=LOY-l*wA}-T*$&XZXLv-CUOoC2GQuZ-5WZ#^mN=H*(ub(yZ1(F$1l@5HSgplwgZV zA4m+EYn+yYMu~88(m$rXkv6BZ#I(N>S2c^tBu1+cN)Ul!@Ec|KCXEU8KojrelDSGI zr@4?+A#y*Fd3J%+kk|by@E`1+nekm62rU=z1{(lydayGg;*>|P@Z`Mz6@?Vv&DsYX z1@+S>w}wpzEaZTUar=ISpp=j22v|QD?(v5iZs+e3IukzY!#*)nE<#+(N>NWEv~13K z&UO+;s5#AL=LIAY{l~OrkA(vdckNCte+~lFi@IM$B&8)do?ofb;q4M$)V70MoMliL z5?04X{D|79ZsM$^e3n5XVOUImXrsb<;ftNRM{N%(9_0hb%Qvzr<-2FRpoiNZPcG?U zDdQT`_Ac(U&Qt9=sJ8|}Zj9*X zsX(!M_RK(%{NDIn=om2Fumf_ykV0{8ujL zdlpTcjJ84+!b+K?EyMjg^-z7L-iI;Kx%_+BJ?G%6O`t>UYDn}d#**`C6 zyQgJ|50yqT?CIp!-MvsX>H)YT!a~c*(U0W$HQDy*tQm6#A3E-^c{w9{oCXelk^x*} zxYkW#4}MXf$72#*(u;nokjK}<4n53S3GX_2*;xL9Q*JOTkB!lB@~QFbQf=XHpEBKx zar-FB|D?h1a z(prSa+-c#%_n_dIXw;I?Dg@81i;lcuwZY9hj#vv=_x6hJ5$9x(6>bLh|7iG56IHZ$ zX1waXSB8E{lx6c`i5`o?KHqFkj*qyz%$^2fVJ#$0A2z?RNBtq_+sR&ta$NI#C~l3Y zxa-$_ZU5UWRcWfq$Iv9n#b_9-R(n#YgJe|_^{tgTkdl9Z-tm;|r+|*dGp17V+&Z}- zV;1}PP@Aa%PJ|eJi2$T-+qMXyU#Q^nrF*BM2&W|9GFXpmA?&o;hiuApG2vNQd^zd5 zl5TC?q5XBKgN{{dq+Y#c%j5)Q7L;z$Z%ULKnjvNcZ}YYE^O$eaZO~R4wX!a0Zc0}y zJ!y#&-TZEziS=?j`%yG#=(^FT&$1D8yMj15-iNoRmm*#OI9fYI2b+%U!nMJS$+YZB z7nr}f6jN} z60M{;NzENrbMUrMZ|8U|s!V$656B(BC>}0O9uA4}1^TV^g&p#^2I#WX zf#>_iT59t_!pd%hb6Ro@V>Xf?YsI|9E1C03p1D{|!dxJMKk-Y)GEbOwqS|u9E@37= zv9j?+TnS>;d6-@;U=!GIVVXStIa7wbcXIjyix z&NT|jj~!ALhI5lh_s--#Ro#$5Pa>z9Re`;gSLfBI5Ubp^}r z9qf6Xw2ULh$mt%v^nhMcKV=L;3@49ouH>Ad5b-;(FFK_s*!q;qckNs?u-q#|aJnq9 za#`WRtM-x`&s?)ho{FQ3%czH}H`hQ%-KMsJ-{ixH8BB4DV02YG#5F@dzNv5MBcyIlvN zqBT>B9F7*1eOVgw-OW)RbGBe@O?mAuF#eb``Zn0ccdh!gE67slvdbAR7e#Nl17j{~ zw062*c98_%yH?bG8!G3BJ|AM2ndysm@SMM*GQL!~6A8AzkBXB%kdf>1{q`Yq@OYGw zMrw13Lg#VkcYjG6?yMWZP81Y%{-*nl`(4=RSV{Zs)GbR;&& zW?7S6LVrsSS{O)mAbceJ$^m#c`^73+JgNcJ1N53F?38Js#|K!8sK+=&D((k`MCne` z+VA$Hi~pcq4_A9F%$OPh`Uj8w8r}@isJlnN6PAF31@Vf(r|FLM_!ANaRTqBHYb;{Z z@d-WCT+>NM8}}o%sik>;NIp1f)F%~?S`#3>_4?gv{@5|587%$5z#&>Pd6S-$w04>S z`x&J|#MXQ+60v`7y)K5@U)2bT8en7F*&k?|{$_4LwdSG*9j-)~IRQ8Qm?@>rlPINa z{~?fcbYVU1-E@FczM$(ZdtrJk+g)#qvq2_93sZ1cSUZfhtPcCMYsPLDKzb$3#a`# zZKGREWae&y9<+MBb=B#&N`m;pWQBHQcb0EMoxOhlg0mB+Ah`#fJ-*(*VfWl;9@C2s zhnQBrd>gzu3y#m~UkPS@K0wg1;#9Q*$6%XLu_Za?wlOThb0&uZ^5u_eg15U0koh*> z_f2yFHw*%SiW+?_l0ypqO~)Nn&hG@ApGmPRmX^NCYuWLWe=o}3VTR=ng?+OVc0;B-#p9#5faI4J=vvY zQujtdIJ&79dIjk||5;_cpLVHMPRP7*WDkg$e{=rq>qKn8+03S%g5jOVf0n^=lUePj zOF98hZ2MAd7*R*=fSi+?0S-aRNYC%F2pLTXUD8SaO?SL{yb{{jU+Fu`b2!-lSk_{? zW-Dm2DMqMh_Up}I8eQebvDZ>B&r;$;v|r0h+4rlIV*|h1oyk=P=``6Ip3;&zYYKp5 zR*25Qpy-po{V8q*K4N~0@Y{Cpjt)IrpzA*Zk4qqMbZ97yR~iQ`Keh|x4GJy_ioGb& zHUV~3w8Tx>Wrhgp$nC~sf{Blhpt6fMjO#^{22hIEAnP!^_ zuVGE7!ps1o9116Z#f4%6{Qvg=L;us3op!!z`Zt3!o)CH4ufger>M7acy?S8uO#{Wj zi~ZM#nFwYY4tVV{KP+U?+itX~cxA%w`wZjwnmtbNNZFONSgr?K@Qa=Ed#K<#g}*6X z-bDC{$mjja7@hXpG*Vh%{*z3}(mj|LrZg(jCp{8j8TjKK{LV@r#Yw=9d6jvfirtEvsS&pk-^@<~oVhzJS#CH^Fxo5)RmVMlv1U$nhY*3Vk$`ARR%Jk>)nTYae2BUwCc=ZZ?@EnAe#YcWgIOaUZsxbwdd0m5 zsvy!kIuDw0C-3(@c=w=mx;{0dl^di4pO@?Uwz(Y6{aZd@X$44uyZ1?0x+c-LUn|M< zy6P>uJNQh?b$Gq8Jd#PDL}VFu`1tE~=pB5Kyyd{W9$ zxjR_38fJP`@keqh;_`%d212G>Fryis!lsQ4e%}=+=2t|Q1PM}baYDuOSVs9z zwO5`qvc77z4cJ2X*s=ln)*0SqZZlarQ_u20VafEox*HDics0LuQ{?x?3?N?5e`++2 zC1C|d-{vPBKu-kEm7kbjt)GNQVfMZVThG&R{Isi0DvPt&)bi?{dT#C<==$Lru=8wV zeNiSU;Jb0GWuVN^Q^P?OH`U{hrhvujJ=fUWbiq?1c%ZhDDPI zFSr8Gf6`-d{1PCc9Ej43z%iaZ)8pG2E^~!)rPI+NX6>n~O^bmUFs7Vgkci(i>_mZG z6Gzaxw9}V2%hC#cA$YtHmP4m%LaBkzX*nl4fApB?ZZ)3eK)lcn%a+d7vtye+KA_M2 zbv+9h-0))ws+&LbkjKwn2SJXOTWcq}K`tsrrH^9SB+Qp5KLi~if5p#CCeH*4CC0Ov zTQB4;z1pLThn-wrky^YsEb{b&0E`&QmtH?2#AX-xl6hyvf?LjNP0W!XK1IqpQ}#7; zu_uMsBJPhQeq%dbQ{j%)G8rBW8pSPL55E9%)?r*eNS_Z3J080`5}Gk<0n%DQ0;}$S z+G2;CqzlnsglSY}<}B*^3p9e848T)whQ{lIqd7j8oUq&yGaS|19EDcRr%?3;!1X9Y zMf=i>oF*mD35GGPlxgg)?Y54_*3IoL-ZZ<#f;ljIHYI6}-k7m)7S=Zo5E20khy^AEe%KaDIjMN63%_3&G7EeE}hh^>j1`t(q<+o-G-|8QX#Qs*oB zh!>yNWo!=aH&M>DQm^XPY5EZkbWnU149g`+4^L_Oqv>_V#j|CD_O8KU-|A|I>nsUc zDc0!w0@WL5g~TzVk+k@hK@BU&XSsATy<8N>f(lvq7skz7VLRKpe(H=~r~uZKs~sLx zAyaL6Ad6!s`lV6mag46>^Kgw|TdndjHF06BWm_JSB2lM{XE7tOBTsVK+fyjGLrncF>G|h%w z^Bx`R>e}JM-8N{m{SOd)HdEYE?ZPuB~EOc2A58JuASWlQK8va}$s_uYgm= z_vTH5qJ-aHt|i1}#xmW$$#F&wfiMBkM;MzJf)9)nx9~O*M|L7arIJge>e=S^RHo=>^kWzX2d*J0+vRbKRK zxF2Rn>Qp~|$2odwI5AZ5ENlRaZrk9>z;RScf+nm;OGOCvDq;`R=v z<0tP%vaXxvF&8oyT3PSC2+=0^CMhod5^!vp@oqkBuZAz}pKT<*>73taWP$+({fP{9 zNnB=Q!>;A@%v{FPrg1l+Y(MI2tK?x5)bNo|IduJO>U`W8&@r#_2+q)n$$5K_UbkK` zpMTAG>3FRRW>`o0l5R<`3YFV6oDFF9OJv0d?j@u?B}0`zLy^7?-Wb)1N#5^(B2+QcI!r3 zL@(JS!c{pVpuAhUAFhEjqNe?C)AO;vjis9ZLV8+xZJT&?&A2Aw>u;RTI#)gQqxlmf z|Mj&2x?7Lb0-;vWya$2z?P2@G4AsTJ!oP~oa`oVmgP(u7ZBDp}OkJTvdALwq{2Z2F z909nxx;pWYE_==R1K3&#BI#Fw^_vsKQ8K;^JzAO?g)M->|A_R8nN4t4P4Yz!LdS zXgY*A%A zj4L!HL}1-=uPA3A=3z9JN7DPVijY+M zW8rsGsc3(~Pk?nubprEGWgR5-;VCDz3}Mc6y@aP`>7eOzu`Mc+S0x_TlMgYH^0P%I z+K0*l30q@QQd)On;vX}TINJo;z_Nvlhiw)ZDlE0%BEjyHFan67GBQSFz1_blz^S%p zOba&#ePYoO5jW#lp3Ksb#GxiTP1Wv>xpxyEGw_%SqX40V-{v0~bkqR&VRsESk3JdW zLQJx%=HbXxcss5K4!Q~{S&8IZx{QSS!FPpcq9@>oo*LE##f#I`S$~Bd6yz%)H$)xp+ z`c7FRGLQX!_$l+Qf!MYB^g*vA=Wi-VU@B<3`D>qWMo1wwyBe%2=j$^6e&>2a5@lne zH7F1gwRs>@pFjDN&?uJeMln;!ha1Y=-i%yWJDMx53V_ zY8KL;q*R7tit(EVo(6%fPqk~NjYcijbH6$`t|h!QSH!i##1gi>IDGn54X%3GfeU7B z-f86Xv|%bwk)wF|uJH;@cm(&y(-8*&`A{Bo?Y?XW^j>E>p*D;b_cV-8x{_*a?8=Iz zfu$#iG5TdWj3P(}92hU8-fAq07eB7A;JDYblK~}InIdk=&8tdn$&^b|+&_d|i*mJ+ zu)S~91lihbSmqwHHZXqO7M8pFz+9;A_9C+=3h0Yh$#A9bPDFQ{vJfKJaH=Nk4%bfV z0jx7a66VnMB?2ApBU!##fP*c!mVao$$oyfLwMS$9E8u((^S53vB88n`6!VKFV=(@= z%goGNb#aRpdOCg709YAnh@v_Z zfd>5g(xTW${kN~s63qHkthZ1UpMWqCsC1+pkByJ|DFJ@i1`f~@aTbyuPwGA=#~2S{ zdoMrq^r2psvlG9)1|O-k=t8r!=>;hgv1{#Eq-=JL%u@P*;;}OypzE&B^}fN;9S$-$ z9JaDiARL$DGsXTrcuXBU%8zrW8Ylb!tu8p}_M&7T*d&dOE?%1S%Zz1_I z3{o~k=+{bwL3f!-h{3I5^*Fu8jxxx)|@vh zLaTBD)RdbUZNM#mH}a=1q4LQsf9v1nAMQq28`^CJ|2}>-s(SwL$kw|$IR_T^D&&(C za33?dN>HJL)`}qxFF?~1_WSxQkpcwkJ1&-*mxhi-a|S{Ca~u_jF$de(lm1%PY>2XY zAZx^UMgnEx!UQZ0p;{*)L}9QKstw3Ntq&0uWDrwi1dOl>4Q0p3v>!J$`OaBlGQ`Ux z7g;&7@Gk9o&mKjWF@HM5FB$S6Ai2Gb!PCEaI}&rs@w)M;Wx}16cX{ef1*c4$AqjtK zYjv{z#mH_o2^A>b&>SC|({PmSBpn_;8wk!NzX>-m2h`q*M&QuwI9F)KOjaN%vMN z^DvK7k0zS}wU643{HB?Ac#rthLDnqQ#VCD`wkxV6e3m+!G({}zqyM6n>2!E=4s$CM?>JMfL6L=0U}}Z45ZBAF z6dTebA~jZsezP*;oRyVy&N{ok=A;}czF%9z5Spcwfri_aD^7n@U=eY2bLy7&4w!r7 z+^PIs+sc}B&vIXFZfAaq9gA$3{*cb)NU2ex6`x&c`u_pG6;-HjhyrFg8WaleLF1jn zprwwtfw&2aerC)-7`}`xIIr1B&R8nQsd8j^+=Awhbi#QDjBvjJje2ZyiMSSX4_xwj5Ep>&)GywH^r>;kN zz5UO?R5}C$ze|K+4T?#<9me7_*H0L^*0f32GLhxDRHPV_w|YXm?@wKhNz@;X=V9^3 z`~9h0>p)Jc{iT<-3FJX~v~9DE^dcTxp>!MIxampXkj4?8*V@OkbU{zCa6Fb;ho9Mf z!%+~2s}WD3k6nStWuK|z%y;%Cnb+#Y8)6cG7=---Zv^hoZ?+);rLdZ*7qm!3ze>9_ zAwy!>gDFcWaZ`96h-0CsDcB#)Vcq|X;A{_d$%y>eiJkw1DL;EJB_6sLDOs5eg!ZS1 z%?8$;>wwbp`0D+`;#6&m_)7a1JDn&zns*J#_LL`QIBl1FH?7~EYOOgI1?e2ILsJKU zqQ{agg7aeB%(*AtjlIqEG80xHgt7t_FIM{ye`086fjf0?J0g5U1lRIsJR3BKn@y@J zR+5@^`vYl}QIz1KQAkD4gGw2lF;u)~U})<^@g(-#;>3f83sldUFzXA`xRf83?wlHN zXnR!M2`cp;PDb(2T8cnY{6t?SynrilxZj^B@l6mz1~c zEKYlK5p{(<&Vn5=GE6Z47UB|3R5A&8&gXO;M~8H?KSkg7g3q1jsp>Rbn$vGY>6joiT_5cc!o_DsR>m7R&V$5&P-cfuCuafz;0vSr{8;K zJ+rHDJA%^n{_AlH1`Ys>943XVA$4@NF^98~eLX6m@+?*Xml-rhbptbIe2L>@v7Z{n z5nbF76>f=aMw84Ch31RHUos30WSE2s+5T2|t7zkM$2k;Aqpt|EebUT;9W(ve@jh1p zU#*w57pso;8J72wd{_W@1;O8u@sQ(vE1COfrWTL+$ZOrMKm|k>OVWYHHI>E!(26(0 zuj0Lx_RHsJxVW4!>nC52t%WqcX|3*!rWl_l;$5QUkqBDnVrcUX?K@i*R_04m=C*p? zb;+*yDY@9UtWEb-2N9O1@Aoyl9UWIVCblS2e(~%g(9LJeoMbC?n?vVBm%jIF6O2md z2VO4eTH0-sMgT2h`2=P}Wx-j}hL1C{)a|J% zzixf4LAzhRAc`c*Xbq};54_j62Y&vNR+3iTe<`(t+G?hk6+ z@~!chBn4g0bqVIzYP5q&&N;#O>VEXfdOa0Ql*4n>FfEL4CS;v9s7$iW8Rb*T&m?a@ zskD~^kfwZYB{Mu&!i9n^b1T(Y|HRpro^n%=qv~x1uZopE>C}-?wA9atA;90p9yJ9Qt7@ z(aC2PsSZKEPZ9$Y>v-Mv_~>ERXtT-P3(w5qi+RHF+z09S8)>Zxyuy6vS~c+@Y?6x3 z9NV4snUb)>+2)v*7t**FDuNowGVqk|zt;G_Sr^Hi%z&hr+-ugR0TrC%uRAk!>J9DM zst3!N$j+sAm4Au2coLjL3#$h@?F>xozxy7Hv#jU5rn|#I8F~!o z^IT1oVr({`CChcu!lzVh)bn{l<)+TX9;x-Ttqvp8+1aU* zCx=Uf!xim1E_k2Wd(#hMza()Qz^IbN1gF9`ITvmA$!?{91sW!2ey}nSsOUf*2iGz6 z?h$H3%Mnq?%M7LKWMWSJSq_p&L;&xfwJaIfb2cW(-(y{oT0(s_bQo&a=w7#0^uhqM z`U&lH3DgJA+m@$8HwVYLe#%hBD++WFO3n=t4rS)AdwZU3g&%h}O&9-8JBaxjsVeJu9)fCpZB^ z2=nI6Po7D~$_5;?j0)8Cl^_!-X#0pdpwLXE zjpp{4!D(Jy$w<9j_T@gF7B1H3iHc<`HSCa4tCZd!%#-xOaN23%tEikA#>_Yu;pR60_X8Ugl;k|Xph>0}^Hy>5;$Y&=plu#H4LVzy*?Ek@E5zf<{zQv!V8 zG}H??O5IB9^O{cyo4`c}v};`P?h!#Tvhu8C@6$-(I`}t5lvIQZrM23)T$Tvgzjm1? z1vmNXv^y*eaK6CL_3MmgE~O^E>t^E1E__<{8yma=g5b z3sXM*8ch~m2im-6a<%sFuCiptoMZEc13^A;RPDC$G; z<&2Z|bMRE*qdLE)Xb~e}Zd0+=u*R^ghdht9LG=$(OaPOD*5ujf6?paAgEinKyXvL6;PagT^L~z1$Uq7OSO>0F;K=((BZ}!LdUJcOo zM-XpPisq%Ry8IMJPrF!G${It51dodhri>d6$Dfd4Nw)Kxm4$l?$`xn3p}DcUE(-Ys zDbTDDT)E>|toea1b_X-eoKJNsoIl}Ey7+$Uy!|B1m-S+}dKXnWmJ7heG#qxuz|p53 zA>oF{tNs$%WnDJGg=DMSqz&J8Wy4>yCiY&J!Tc-aZS7H9#}P$UqVeRc+xXeWE16~i z0_Rnq^pY@F$`B8^Ts}G-dhJu$^K|?jKNh*9chiThI)JYF()+@Zevzr0@VAgD@kVk7 zd^eN_DttRUOLkN4dlVqH%zYV5MG5O1Geu6BdU4vgttbG3?!6B3( z8H!JIZG2*#G|1;cu;%1sRtu`IbS~EJKn4ef<~4R9*<^Wknnb-SeFR;)^21ac^xHp-G zS`)&AdL)YrO_I@_tchBr%S*#gCGYSxb7wkQ?JnvXpF=-9r%sYh!*KzQxm$H9f{{m< z9NEOjY7;+sVE~|yZL^!7KlgRQW+B2axeQfS8Mo-DZ!$*>C;a9fwHq9%52Gsl@(owP zoAky59^vTiPoxW@g}#}T)n(|#xv4!8vKDFHOV*k4@Ws!R##jQ~jizc3Y<=BE!;nZb zzS{#0-&};68E2(uT4Ym|QSOp`w=JPDYZ6|e|2SNLhfZYzRz|{CQYLBJ7gi>T`61%p z2b>M@FNKI2EIW!7>uc4{@^1uLs74^tQ=<&WYCI({hXq3z}xpyR|lqm#&mU*vuX zO=v^SEX@@1H*CnHzlcj`W{*@jGVrh|{a|vccWCaO3ww=C8&Ur>ARB&^xFJ2gvt!oH z1?NQ$V|XTvAh7HgQLNuQCw zRa)V}45?Ew4>Il3ZOK}KZh;wu>ubC$oMb$f4*3v=r}Z0t`HH8K^;l#F_!Gq~5q*gx zfBKS^?7cni{evf}6WUloHnaYeNtwQ!LRUqb!s3Ry7Z=gskT`mE| zHwGgdLtU{#n2uv&g5pd%KwK0nl;KuFE1)9262Ln^vlBa&|gh#7`tb^=*vr#>cSx3;!=ocyk)*U7+d z_1@wCyw%RRp0>-%!kv4g>*1FbL8>Gcqp5ycBBl6bg^oMC@q#vY#5_NCLT<3Wdu3}f zxo0jyt2C<7AfOAwW78=DSesI&-?zEfJKo>w4dvIHZm}=i!|_C*a&Vc1C)R%5L{JZN zX$b!)h6sI06}%?lm_eFPYgiKgqcED0-g(2Um1a$#igd1FjMX{~PEteYoe(ooB0;o~ z`TF^+&nHAC40jRs=VRBk`LW3GZ_SPK6wHgkylw}f&3uGr1H2dkz`;@85#64C?+o#> zhyf$8c}vbwjU8!soncYtrlO`wdfRSnrP1MFVv{*Xtv`$}$V>{SO{Ho}`t8Y6p-(e| zq(_VKZ| zI?;chbEJ$`dsHuP>)?>1a|0Bg6LupVk){tsR#YO%z=phz=Z}<;xxDR;AcM_bJ>`%F zv$BHjd`z(w>OcwV+Mhpp5PK}E-Hz=xERf#ivye(9x~IHA5sL|L3Xx3n`49I4f1gKMqE zk}XOWsPqMF^4@&vOm-V~>b#|ld9~{-u#uetS^BC?O<#eoKPpxypieMQq{bQ$N(+DU z0mdh~ZurMF31SSmSy;R03Y_}IEQXRIR>?ZQ7d6Rz1BS1#6g(Hya<&Xe*?zP|Y8UA& zrHP&Ui7*ve%=`o^?8PW)k#o$A`O>^Jl^a^E?Prmp$C_NZN=$OquF{#jOO~Ee zUC2X*y6t-R{zO&aYy8iQ9SvU`UQ-_Gw1KXAMgG&;8G&bDlyDr}2vWB-v*RGctc@{rV+ij#a}4&F$mweAb3$Y z8N_{L~_T#p0) z&d~rUx8EYh8045ncoe!)1jsRGJF9)>AOE57fB5+lK;`P9x1uTz&tZe)yQ68LT}Okv z=aqO%Pd|eDzppEP3TJq1z2bicG$FARd6=z)U<4czF_K%{@6VNujX_)6ME`iogH9hMY%t0?ghuTX{r63C^}k)$~+N{MgI8u<0aZ+F00 z!Hu1b4v z4KV4P4AY5WKAE5duncy3USF=+E+&gLDUqvVJ~-1lca>>csuTC@k)-hNhZBLK6^LNa?`I~ptSvLl{V|yXQ^-iOizNW8^go3y(*ZoOf+zX;Bi@cq9KNX^9tp^(t7L5`jA3sOms zYa|Jiq|F*cmguo@4Q0U8P)#nO@iK41eV;`*Uy|c)L9n??qqc(LUUAbDs;S61%K4>Lu{?)qF`% zpo=y(HWq2O2a7t~4$WOOSXhe3bqQqOQ~$g@BK+tThjA_lQ)o z#9&p<<&%`gmoyXpq@NukV$%(l_Ndz5MhGw{-*P7_T<9mVPGogYZ%yfv4RigUV{8CC z$6jIhm(KUppolQ^&DF!te&{A_hcU_`XJFp@9hqtVau#3t>4h!!6q>?KyuF!!yN^CJ zEb^Of_U>Qbbwxt>S*&&Wf#AK_^nO&>ZVvn8k}p>a7&!O_{y(4RA#|~xGIuQtwTqL# z@rJz2)ukaVPaaKOQ4vYzv&~tf0??b7Mi&knFMbucxaXZfyKazP7$vrKs+tLYr zLiE4zRGq~d<7QDmJ|1e+-JWLdg!5tc9Y~@gKWvbk+14$ig^4r@fJ#xY0k+C(mt!Fq zJVrS~R+~i4;tY^wtVz`DC9*B|`9oeeZI~vbQYzSB*z|(6Xj?jpM}qal5OFSZX=qG7 z_npf1D-yIaYC^A6sj>_`5$p0|lMlj_m{N{{ewu6sKiFOO3k=H9kyW`AL$pX;L( z7$|}ml(U_4Vt3c-e=Kw^0g^58sY8BTU%-rC>87ktb2>Pf%(=IvLFEP_kJ7W^E)FMBVwG?*w&mh?G zEDWJ9p2zyj4JDbyAxR$SRMjTqW`>Jr2`jK-K3l?_7;A;qO|{|fIoy(>3_?>BlRQ)o=7l^6BDLR|-& zo*9bT8pJ4ev|57CHM(%~I#>3E-E)k%N|odLjj-#9j*SfLK^UwIY~ja72Jo@QQG)u0 z5JOtwz!qUY1^u2fdo_789}aK4a<+>G$!5=iWt~{-1*qgA#tXHN1ifc>NfK(q%8buj z!rHH{$|^)mz;ydVAAdDHP&)Y1{;@@+CVn9N>a5Y5FJQH0r&7q8966>!w2v67Hb0=oWF zi&f_V*j2TxN4mBn4$t{F4OX?xZ(IvASihy$vl}Zd_P0z{@;SB!E&OdHWHKJw z*{ZTVQ|EF$=`6|4A7BHyCOvI$J{Jo9$gEIoI*8Z)ur=NzbnoZe1T-^4js9Nw1O!pa zM^#=8()f}eltEF<69=#?PWvNscqb(;lfuwuf(L~O1xB`to7O^4LU|XZ4L0)?-G!<- zAYh+#HoSC}2b-Wlt?%vixwj^Ei;s{DT%$(eN~6qNikM(wsjD_eq(14-&U0{asUz$i z=*r_Yv^|)V4H&))IDiDDT-0ARIKbmZUj^}9rE~#UrQjf>3VfpzxYMP&_|7HO?>Un? z>Vf=bG%U1x`QK*8#>er&$)nV3RY%Q#0M2>j%iLS;vah=mWNs53kPhI507i}o%l8E$r55pUu$L9=y>sa~d9AbN^;fx3yn@R$Io!ZcMRMn!BtXJ4z@@Z1t&&~XW z6b6SZEm#vDtuuayhu*&pd;$lWCR6%-e4AAqW*Q`PDf}6acY{&05Q+6QVu{fKcsoPC zc2mmC>}Ims8w9L`^MmvsJ2TH~ssf(IQ%{75J%iR1tH;ID?af6%aP$Ynn=cA3NBpYZ zh66lL7Icx2x7_{_1$*K?N7s^llk5Cajx!d&O3aH)1)9xO`AlTzU^I_4ckUmP*}j7R zZ%!LWjSTSDbt1W}cMuA-$EyLyUq|P1-sWCM6~^7tmgCr01?v>UiLDi(Mzd~N3I!I5 z%$g;?IMZKHSt||;fw=*8ko~~;fg9apiD{=UnYx!N_@@28R8j1H{Qv5rY~vUMCXr+4 z$ATt|jQiHf!VlgobrXPr5xdbYqx)Xm5pDe+Z|8%DDrnrERr^YtZdvs{Nzjv_^%8$X)*&A5igd-C&1n{p z%FzMj6!hxBZ}Wk_*kA5@yNqxdBxzRt3%Ik)@o^lBwwO~;?0yCRhaeQPJT3U;<0KYY zzg|CZeJ5~F7*0Ou0dxC%+!>vts2O1|f+aJ)nV}28JVM`z?LOd6Rv_p0W|_O7unF4o zxzF3!Vk=&E*way-M`ly^gy)~OcW)=21xgjeJYETK?F01 zJ!BrSQH))Vk}%tH#L{B87Kde1tR&Dhq*l3<4(>{LzDlhoKlj}OVMIqOF5EX#h24J{9>y>I8m7xuK8Sv)oxBB6QhBt1Dkvj`(O z$>1nh*q3>M#V+nE!PRd2j0W=@kM(sBX{rU<#&|l(2vxLQwH~@fzd2HeUJf&AjR)Er zNH6Qvgq5lN^5woveS`6gvcj$8OXRdGdXBrjZ3g7Ny+II0s@KCwXlNHFR-U6IM&8~i z6m>sTF1QRvEP(?kC@3zp)`k9=xA=`O`l~czd?avt^f)eSn}A`VjN$QHnJZh~m>%a8 z-iXW4pRlYYkLx1(Y>NP%cd9dEfY+DuwERhs=n7a}XTo)vIUoi&yGtsZ=SLO_^7Fgi zpy4Z4S|fd;kB0<)s$g`~N@?U*j& zA+cue)^dz>n}!HzXn2O;Evz6O{SWeE*pkr3#+xE|iW<_$!Gp<2ihm|w^^ky;scc;f zyZLe><6U^N5X(RCh%8Xh-|3zYpao8S*hoU7Wdf+vnl5H6V@o3HZ6A>yUfsguA+6u1 z?h^pZE*20gbriXAM0GL#*dmXMNBt7of5 zc=zm*6Z6|u{iK2Oo_8}-L)g{@j3(K#SVw@9y}doAq>y-_(oSC%O|)JZ4f<7%z_;;q zXlgiW3+MKt??0%`un2e_#I@EfAsb53Bcli7X!$^WlBYTi4wyG*tH^Tk)h*nSVY;>M zRkR1y{R$bZ+B5ELSo9!DO}%;WAKF z#j_c%B>blT9X&6vO4|GDj)uI%)AIs-n-B9p^45v!-R;k+(HlG|yu(+|lEQN{j`@0( zUlpAWZ@=mDfZ`~%qjuG>c_$PM5BUY;jean!I)Nf*7O)w+zd%-HNMDpqixge zO#R}5hqTS`=G-NxC!fU2Cg-1c>4y`do^8K{L+7Gip4mo*J^-BMUip))-vDanEO)Tq z39-Ozo8ZJp+fM($TcY80mFoQ3?D`$FP9Y^mr0FX$ zPU68f5i;YDSnI>iEsaBC-qMwh4^nH^(7TCMy8aC1$&T-RC1-We-&8+ za>{SuJ@Y;)iBis0lH*xbVFoOgij`(r0k|&o#JD8-r2XO_;Mzd~uW6EA>g_iM4!mcC zV~di0_04p)rwuAI@^jN`9RHBc;d^XL_Jm0D*d{$*eFbH7VlMAUcVU=sn>@-3x51Zx zKaa}EfNm~49zL)z#g?cSGnU$!Hfr{p3-?!d^1Ee+ESGfN_Z}LRJWXD~}qkl<-?; zhoWPKsVGj;>Y%xLX!r3WI&ZgW?6Dv0ycYUJ`F7VnIqb|Wl#G1YTo*R%YuMd+-l_G~ zfHtf+pACK-V}IS;JUvL77&zC(BR4lQ(~$1w@M-f(rsyveZbs~N4<}h)E^O{i<}Y=nHO0I1D**G_Hza&D%A5@i z^i-zQk1$>~i}-qdCok}0Hz^bkI6xt$h9}wn?B%12>2(E$kag?@`aewA_6)YbA50SzaX{_|fa`!j$eUGtA;`FyJ&MXN`F}7mjEipn z+gd+w5q<%9V+CBT`ITbQ+d}1*PBOSx0lK~#7f*k_^nk@q6jWam{#7t_9lK;qS>|sA z52C-V!q_O;O}-qMO$f4eeAFbv#D;ZNjDt6Q(}x43i1Xz)H6XEmzW5pET;{YNNv%F3 z)t0>Y?%m$Uo0`yZ9bOs_Px2tDs_IYm^ex3L8!yJ*a_aE6MVS-|CPsH{+7tj>!g%D~ zMOB&DE~4b#9l0d8yC#lEbR}qD3)+Bie6~d$j%?UswGW(bYhFBHXI>i2s4l`4Z*J-= z@^;NikprCy1IfH|tz9QW$rikY>;ht{cp%iF-x?=9eR z+tw9|oVNCt2&h=Itm|f5l!VDza^|wY$U*UPMyTL8(a;NXsqVXYfff*jhaAUq^7i~O zkeGUefZZXcvQ#A2%8&I@ql`I5$L}mHM>^X2aj~QXk78TGTmm^*wo?4Q*tzHH>l11= z>Xb4`{Z2t$M){zJ)HrEHs862F4-ZU4&~__LxTt~UIZ}b*x;I^qN`gM5$E^o8>CXq_ zpNO@8Q`{%BfBrB#G`#^1RFi2wn|va}pN^xK;LGWqW5f?jBspfD*`p8-w%ShZ>+3<> z&SH%EC>`~8xcB5wP=K%7e1(0S*?zgfMJIg2_Sc~4XyC9yc(1P^UqItnSYw>SR7!l5 z@Kfy;{TMTjhwL0z+kn54gTtO#+?rT0j_QDdOzmg9verQh*vDg_KcnO{_8tpy%A@r$ zXm%mTtM?3`5Boz&~X%}c{W@t zC9T;Zxv7}E0#6O6UPd$Nw7E)&^M%*!uNq8^_01?Pmlz? z!l7U{OZD~1-^B^QDA#xdw&$FxKJNJ8b&Z>%w~Q$r0kC}Ada;@4JF9BJ>*4gc|ja|tY8zDumQ9L>N98wvCHwp-;LXzf+#dF6T>0ncE* zVSKVx;e6QqoDFxoEBC~6n--P02tc&h*?M!Ti#LK8}y+|I17DPKHp3;qsu~0O?4A}{qkT` z`Em)i`fDFAJR{$m-{03Yc~b@L)UtT7MJ%`KOVHTJ842^E4&kFt{Z?AL#`FU2&`b)KU8kH5gO8N5gW4GQ^ zT<5HDCd^oyltX#gB;*bm1}US)z0t*se71Xeb*~yZpHS)VcAQjh9FNaCa5n!(mlZ;E z@$~fq@XTfLmZ)QlTT=b@Bv-=8l2jnRHAuB#fV~fSkrE>={WIzunqhz3WQ9`2_0HM> zz1GWVT!};$1*h2t87As4VvmH&pibZHrFY>ydxjsL)jX(-bNLEnz zd3r<91UR&+C-uk^9J@Ngae{!BXVB)=IGZ2kv^P?<1QWfdI-oo@IDLP#SYz>Jl-G8x zgEvgt(y)BS$@GOR9!4$X}Mk@?PTY)P`xklG`GNtodQOp&r*if;r} z`k~u0g#KoveOg~j#x^&V2 zy>X3ZC~CL&Er)q&?C;=MCg|GVAcx32#RtP85Mu8}ym-%TW9aba(^E!IW30n5a734~ zv1L2_fcbr)O#wSyl~UT9meYj>O^As&G}TOqS1{RyY`@kpHT^%9rCJIsQqbLwUpK9R zU}(Q5pU(i}xtMYXGbEN@+FB`_0M3tk+->A4ZAa-!hl`$fgbMZI>QRXfw+9a3u5G+@ z3OvJH%8H()j=GP{O?k;`lIAj)o?b7xPcRAh7Iim&a*`jXn$qWnHOT69V z!_5bcKu46X=6pYAkhyZ(nWPt$7>5U-{AvVFW(Vn4!J_s`!E-CoT7<_y{HCzp$yy!n zQ@!I$s^ff`4s4fAhP(pU7R?e3KfLIAUx-?ho9<}gE%>`_JuE`>;#(?$N{e$tofh}d z798aL43A<#))t^mIYd(_O$gR3J`9HG{<9rQEqw~!>+k6r&SJV=b$r8Pe0_Bu?@F>y z9ue_@(AM(sIP&o<>UfkDl3hm4@BZuW58{6mwWKs`)QfMihN6$8kzH(NixKIR(gW<< z9_POK)wDLLdCaO34PxQyQj<&H(y1DZCV$%48GPS3et!kVbV=<%#Y;F&>w}0WW!66P4 zP-m-2rUE}sv^zcVnQp+WrK>7Es@%9%nLoKC@=#o>_vL6!<)W@v%Ys(*4!vFYg z_eXahMGMcB?hM}lX56VNmgwuletcwg&K{VFOhhWGcOEdGYoNANOj%m)9V>H;{$3*tvBUQaSi^Z z07H2MKkEBNRGp$+fQY@mi26`BKGp^I+7MW6fd5t}-?bimR{J+slb4lSInbaO5VNt$H#_vV)%9g0hE;SH#iPiNA|t8`Hdv& zBqAYIuOF?drA`}1vcs@%dAyCEzSHWCc8>~Q(AeG7D~5~Hd7q!5RLuUI8X8{<6ogbG zw%eKltE!VBiUGqz>kF|+x{b3AYYakfOgv(J_)U(4^JO&!XPh#O+fj@UjebM|T3H;< zWs6v1FLK=#3u}47ZBRpr`Z=5+<3-a1$yu;87U^0HS*i8dEmwU-!I4Qnyx!J}M&Kga z(ASK*rwO@?qgAUwuo@{yeG(r$&|&T5oZyD|T$kbJ1muu%Hvg{$*Fx0x%TD5ucSQne z9z$<3YgnOsE=f^2fu8q9Xsq|uj3gMAE1goDcnQ(pl(wDDZxuJt?ZJ-XG|Ft4!iOWW zA*rRdV*%?1FU{?dl=)9F?w061rOyb$g?YMHeeAPOlb}Fs3deUlOsTmfIpHBY*0X9o6LhpawQGWSjlBOJn(6_-S&_PZ$rz2Q-aEn z8fD&Hehy!M2Cu+Y>q%o_7>rh$1;p`f%x}rkFKt=jaQ+GC*$!4gsl%8uu@6lyG+}-@ zKuDCn^POQzc#fLF1NO`>T1xPG>~t#t#40oF8z}0l_S;v!oiv6yDkgQBrZ%*-Pe-EG z3OGIQAZ(L*dn{d;@#h&DCXH$V?dWfj7Bw&&Gpv`ZAHg)~JSx%W+C|&Q7tMK)jdqnI z#$)K{ufB*$|HEa|@pQo~kJ}@YGY{0UpA+?lhyQFdIFotbV7{bsu!*ie2cZB2lzU8X zkNaenk=H>!KIMq{W+bU3qg&q-97J*B2kIK}uYai-d=Z~)c8n8VvE;CRCJhl|lAc10 zos7cWIJ3t@FG+BuM+;Svkr87x8B9!`CED}@Y+=OQ(d93LBeo4&J_Mi~!TF%th`vlt zJNQf?QFvuJU}eoL)k3r|!43llKgE1;K;O9oP?Kzmu!Vw$q7M>u}EE%L2dhx zgS_TCKcww7jQwJE`MursBS`xHi?O$kiZbf@Kw$()=}@U5q#Klm5k!#gZlt8U8B%bl zK~khcx#lYGVy$7;Gtb#)pWlwN_ism=7e-VF7#Out zJKS8v;(}T`9*yv&#c0lt^TSox@BObAXu9zY&fN#JJh%YB^7FMm6#)S=(yNM=CW@##w%8Kd!V(@C?pZxUsX z1&FLvs9$bd%nip>r(XyQ$}@G>0C%vC>9VW25^eiF%HS=R-U z_^88x!my=NeAdfIpH1a7&Rc~eZyd4`$ACVdB1Ua1tR zJ;^npXrHB=e*M4!W_I2CsS+38=j3F2w7YWTH21j5o7tdlZC&hn(ooyY1(XgJaMk!T z0~mzewF_b(K|$d$j=Wbp? zQ~s%Eb{$pKrXi_c7SH9mveE0F+1CnA+yE&PR9$_Sm16zdutv@0nCcY;#=GYa?hLK&GOyh=AjxltPwd?tn;^&JcC@rRZ zLq^73Xi_0_fElV3T& zozjukmwshv=HqMXxDndw;?udYd}yU(riEnOn21ZduzTomy0ETvwy)P!C>FC0ZvBBa zS01T&uJ4#EH^VsfOIv7-6$7;f-^8uQxyx^1;QnU$VS4taQfzWoZB1knRwm)}T>W3zcKT>6Xf+l6U(e6rsn=Wh4t;8!tF)m2c1v@pag> z`gx;bJTbJw@u^1);B3o&=kp#wYdVfM3p3;Z1oTpUCStJ( zy3fR)JnekQ91+pV_(E;$y{ag7SjMfhs6ppvVb|r!>K<<^cLro{(d{d7g1i9f3=S-p$+r(&nM(+Q&##HJzK`;tpYv& zywzjZ-ddS1zK7Ow^*JdiV=M9g3wdzd(rD`2knNVHFt77y` zrD|a1C$W@5YRT~kHAkMW+-hWENGpW$E;aeFJF(=YQg{PB;35&-!-DMSJ;j1OE9Yqa zqFQHWP6~H^P8Q_gSFf(K$3p^c6-G5Xr4f*Ov#gC?c6cT+_hrDCv~y-9lW;syu=wFi znBVK?!(#WW-a9)v(u?6a@?=Ubc=iv$Rq;^7@(5@VuFGrDBI2Dp99@ormwb+BFaJqD9O114%muc8O|24uT&>G$9w;aje>;_cvOL8H1aYuN~haD*g{bmn0Z|kKhEKEwVn}u&v9rK zab1nlsjV=6A&=u@Q^if0-MoVk! zer}tEi_S^Cp0do^$qU&DWij8Dw>Z^FH1 z|F*QFFlOgN{k)I7PJ`<8@tWIi+4X_^%;!H${_usdp*uS zm$0?05yjY?UP(A@8*LAT-6Bi_Bc=n!j5#8s+y%|j{brJ^M-GFDUXxoZSDEut@|Pi0(I zn{PSRGInmqrR1M+0*o8=Ks=hmt$sVTY=ZTQb$thL$=h)%|0>r+O2S7w4s&q5_3&p& z1w_4em4V~?!|1wFzz-t2o(rHjgti)&;PcG1nPZgd9)?-=yu$fHTs<&xjQ}{3;@>g@VqnE*zF*TuNH?HdX6h+|YalAW?546~2jdZQ1ZWikq#!KRTj1W4?I^}qm z-rq{>kIBg}7yRi4k?s27apj+%x--u7xJ0T~QaeE7&H6j(cC3xtl?Z8zOehieaC=Y# zr~YSl!RjXIeS{7X7Vk~Vg`B7LWO3rAg}Vbo^=SLJEJL$jkBbzoqE#*U^m_ z(b0;2y6hLu-s@%$NV_YOLfUIm>5*Pm0xsE=Mgr*R22|wxr9TSnKE7%C#v{)3+^coZ z{_uv7qBuUEHYzb6k}1Ecsl9sgYsU5cpC#X0yj{CbE7)eEH#-9q0{`{j|A$hEJLs46 z9jVgoL~F@nGhaIv?eNuV$U;!{=R z?!6`m`Wqb!4j9VdO3N3n(5;`X_kb?2QL{4f6EVMlB^lGASBKvOv#S~TH?Z)NYy7Ne zcS9!_QfeF@=y_g9MT8yM>|ht798&MZx`yPJ1&{5uj{~hZsR&!~GXeXX2TUym6#Cs8a>f*L%bRV(UTzr%NxH_g4rb^muU8 z=*!l)nOn8XE>x;Vtev=QY>U#ydP;Tgf3>>JEz}x*uqG_uGJ^pVpPCymHi94LGuQ4g zKtrX*_?BgDuJt^FiKvV~0$h%Ug*!xja=&xfIfsV6M@b9Zt zzFOI%y2{l&HpM;WNk>r<7V0egVEvEnp(z!1?WCmkzX`95w{hZj@xt{% zAUU|p0lz^!#_WCQXI0P6o6VbH64UptpwwR+GiTNs|9pEqVu@u|c)irTmL|0HF{4Bj zC}+p1v(=B(UjMidjE+;g+seyzVJYae0GVm^6##f3wZ1JXWr`bKa?0<2F*s%&Y{LAh z({C-V?-y^-@O|~;Yo^(>BA^KI7_E9XjdEzoUnCS~)OsU=eV8G=-k*#xUd=Eg5b7dj zbpLcI;B&;Du2aB8xRd=KvJ!40R}En9JWOI1^TvP0opu=Ou2*?G@tar5v)bL}E;W2C zje%JId&AL&W)|mf>3r{F-pt9bZ@cu8yj_YFKaDOu?>Ewt+ieqpn@ke&r=wsi9ef=uu> z#sbe^MEYgZ#fGJP`rZ#i^FO$I-OiQ>C)_t61}^2o0-dvJSaNqHl5L|BmX`K6hiw4v z05On*Nwb*QAy8IG`d39DZq0HcYM=r!y!z~(kC7#}Z&J1QZKPXf8}~B?({m3Q$~aZr z*kTkGLUdW+0trof*%8xJ-Dz|T4kM;w%IO*n9;*fo(vx+A5U(BpR;{pI1= z^_Z!k^Kz-`k?68#Gmtp9_tMZHdGXSyyXVKgAOb|N0Hr~prR{{^s8cmIGzgl$W2Tna z%*)CT%n6XrHfSW+>!cc@6uLN*GmC#g!UNAeVAWuDY-ku&73YmQ$VESiJL3`(dgQ0F zqFU@`!yJY)L4^f=?IRBA=OKtS?;yTR|H7WH!oS>Kgab$9m@O&OynpoqvdknX_z(oL zV-ll8K;@GxtW|x0Vdnk0q3sf(CgSxqTs8{8O$&NXPVSc!*0*%gV}hUL68f*atSTOS z0gH-KE>+%qc`rybGV4?;cz$($ND$&@lcwHw)6dk*$;+$O>qkSOWmNgUe@bm9$N6l3`IMW_(vIkbXkcu zeVs47wDY?wm}%MYgi!3`dH^0awu@ftJq*0AS?|LaEyC_^a0v0Sgx>FoGu>ZVzgQnN zZ-7SJ;@DU3h?AVhIdw#EOiGFCuZw@;+5J`=!`$B^;buJQsxy}yG^4d?rA?L3#Ac;N z$!|0E0^Aw?D25#jxIxgd9Fy}&Xg0qdO>vCbVI;GXMELE>5vJP9^n)^7lyebe@KV<-ppF_lah|DA96GDd06B_d+YQ{Fpl7pL_gCCSJ#Wcvb3bWj zV>>55YB-{#XG;}u?vuXwlR9aIbKQo8gF}3^@d#oboWaDvJ^U_y*K_|8E7Q|r?|fz3 zGo|$auzogv^<&{i`1s0{G;;)@?d0pNuSbg7TdNNPDwDY`@4B1*S-gMtZ-)UH8rJ73 zYA@$5aO>?gejs6Df2etgAEft$Z83volRWO1YW#MhGqu12QSW6+>^QR?sMIuvCe|Bt z4Ud!`?bA}USF5D5vadjno?O-`(a~P?0v-OoT!41GwgY7*_HB{O0A5v zM7r`h)f=-khtMMJChUX*4{`FW)%Z!*zin|cf8?7VJz$xxkknHk;T%>9r4!U%*KFl% z@V0btC{$MN%E_x#XI|Y0RSY~0MW^fh4Wg}GFREZYo6g%S zQa`+0%%=^t1V%-RF~eU|NskTn41&Gze6*psy+sWk;M8Wg4at?Q zRsdJs2Kle&VWVPIBWkoa?M|{%s)--#na-vP8FY~8ET&LHBC}k&v-Ej31_DtzE2v?h z_->1nzsT-#%Xg#ld&q=;Ru+*7s@n5Ey2~C_|A!q9sFE7sBx!}B6s?_XINc=e?{NR% zpl{C`+ydoYb;WIcsK*4Z3TxP3uauFw+5_6ktbo=pIT9EY0u~n5Q`l*(e_bVI>mw6G z8T6sX66b}*09t412R`R+*;BvpD73EEJTS_4Y-Ah;CVC>WZqLmKT;v_nLqn>xYs2_! z7o-M)t#t#NQx=5k*$KeTDuLm5O;&7QtC)3~!a&}S^k1(nWxB;FWgcWKS%jVS6Wfm0 z7xvKMVTm7_Lz^&zb9s`V7o(CunVrzS5qXgas?27INOqL&+a#GR$3T`Oal}yXBL5W0 zc~cLRl%9`aI39sDr<PPavC9WUNu%*D=#96!DQyrctEQmrUMK`ad+lvwb7x_9I|UmDHM zdBZ^oR3aW7#gjCVy`R0ddDef_$h6ru%w4FS?r`11QW$c3?H%?|20|Cr-l9!RCB!=3 zU53g3|6+ZR987%~!yv!8(@|Xcm0A2;O#Ab**~lpgF*9OX@DLS@oXcTgIQC?~3Kg2n zQ-Vqc1+O8+u+n0gc8?f^`;MDnLEIeV860?bCcdScB+v}-M+)GOA4u(z4+~eLd_4|W zyPR>?qKroxWq2}jm0YJvJJZqVvW+7Nu6J~&vsxf_NK;vZtHDDYxJwkAuRjD$Colm+ zB&-BkFjh_|3)G>4@@AkjI!;oNA|dzjLVKer9<4&RXPj#T_;LDk@EgTjeLJP_#a=%Y zsPKM|67kdXaFs*nv)!XKya%M3M@L7Y`MVsbG&D5hC6tdIVSWAjb6r5a!tmV9hg~#<|lmK9>pV$+P}znofLAiOI5I^VT_k4aZ`us|Ixv zEX*pW(~gacoABK4b#he^AfW>+B*LEOof`~^D*aUy`q<@_O;Q!m-wO@&S_+q0_8PAm zC)z&4?nfyvkoz2h`2QoL^XGv_I_JII`!^XXXr4u}f7!tT59>MSwUoT`xdGLICT1-7 ztS}1f{>PsuD(NkBw6lU!Xyj zi8@t&*E57N^>)my%M(0?-YaKfg0Oy`@249JmBWYRzra_;AfkzT7)h1<94SzEJF+mS z-E!|`>yyXC&+qU6bCsCueA_@o0%aMC}GInS;B zvx@1rtyQv=Sl6{nK^jkL?R2CXW)Ya6z6a$JqyecY0ykcPI6zLpieL#$_+~;ewtOl+ zYAoFjJQzpP*8!S|XDVP%-axjUQC$l#?}TM1;}}y2*v(>YO*;}iC_q22aN9LH13N_m ztW?b3(fYB8u-x(ldv(qAMNb~KTx_x}?Ck8YzsbOijf@NlxW>TTl6n(%ak6m_UwlU4 znD<&#T%0=R`w~H;JJy78C6y7+JGaC1w$n-1S6VEyG-VPnti~knt=uQ z6DMrZUAfhgr5aO%_=j}oYQirV`?`ZZYA@`jU*;A|7m8O+0mW3VL8I_~_yp+oBj&y<&0*;0f}cq zn`BCMbU|PCFa_t@+L^Qe)wK}I56@4`Q`yF2tdu+ zb0w6w2{=Kkv7#=08EaKlRRlo$6g zJzZeL7k%!-Z3j%nh+zKhii@*f@h{}uVfTYE^dt`;wrOK=leq~;{DRS1@U|vD%9CCL zB05HFsBjjm=(3^F3l7yBG!hOy4aQ~qfBHIdr>|BI8=AZm{^=`qPyZzA0#aWOe7zc7 z5ZHp9Eu*4$7~pusHQkj0`B~;AE3Xht7a*?kW%`#O(IsfUPZaacc|#8Y5~tWNC7OO> zlYtxMV9PwnuJr@vpes7aK<=4?Z=Ft{+pjp+pt}w!DDXd*bQCO)bz@1%;Qn9T-S@7p z`kU~YXX&zF@T*bKD7tLm2-h{vrNhfCcltmzfIhqj?(@A#gLDWqmXQ*<*BKT<5J$qs z4o*Dg#CHGwKZS>;gs-N!7=gmrEJSYWDEXrG_S1&YrF^$5DU3+9S|mCPK$C8{xuc-^4krZVc~ymg~H;-htj$U_BnQgemw~%J4QG;)}DVFxo_AO zfcZdAjW7UW7U{YHN}YhGFzajJd6!5gvaYL=U?|Avjr4Y0dL|;ftzk|IXe-*~%@U}~$o-@+cv(|DV?*-;jxf6cE!CqKsEs2izBFZ*Q z7~|EW_UPZ=Hwk-ij*h}M+ny{2kkF0tP;#*TiD^Q)%|6a$d*$3kq;{_zyslQtixy&m z(S$-Gc7Aa&=Z$G_@1Jp$xigN1YH2B0uL=HH$C&>w>*z}LAdWc;sE3v40n zAb{y5A|~d(@cT<94(x!2M|f7mW?BDr71pV*ZF1ZrMez3K7>KEdtn65r$g1H-piNEp6--GJ^L^dA^D>2+uJ`wt8o z<2O#3A$7X*=?!Hh)`|tNxHZJwV$+?z8ZZID__Qu*XbR8)h1uF~k8~PUh|iW*p6PhJ zmddt-8$X^e2w+;*I(&DfW?0VjUu!$S4SJzp@6b8)QK0UE@>M&QFHw20h+fLJ#;5ys z%^qYPvzQ?-M3SEW=FX?M;aa|RGOjYQUe&+9*-Scpz;4tcNW!M2(7a0gZ<}t3x#bt) zZofL=9Do4t4It=>n%nL4!K2R8&JTQc75u?=tU&LUDDA#;rI)KqK$jg~S? zZLssCMDu)E)8t};r1s;Scv#4CfI3Raw*+4?(B*EZ#R;}IFi6EBI}MGVWF_hI>@hr1 zd&{O*%luu!)6;XKN9OMevH}T!6{te?ocMOQ|E)kIDl(EQ?>~ECBOqk|S+_;EVSz+U z#suV@fimCc-4@vpeD_|-fdBdRi2^z!5dbU-+AdN^xBD9!=NF@}S3t^;DYpxo@2%)B z4QEb58Z))7~mKVh$WrVG65bi2ve{+>K6GJ_VN zjD}wUlSHHo``FRh`a?{@E<&EeG5>`O3W1n#&Ahxk1~4trb*?QDbACYq4#dI10Rp10 zc6gCPf3b!@^i0Kgoh4Tlqmn8xGu*lTM1Hdh@mPOvC{v+$ z=Nl9&i5g2`Bm7qx9*hS$p(=C){sr2o=fpEOSa+d`XiEy@hNL0jf~s z6nzi**qhZUUSzaGlME?B#aCn|xm!E7*R1ULf7Xr{iem!0|DUy|b{NTaAOU<~u?Ouy z0<|sn5K7~MbBDo5w>Hd{68ZFFf%>H6&LUKB^7mp?JVi)0lBX?KrDOSJ>OT*;+YM|0 zcpiX;cs-LRF#nErA_+pCKM+0_Bm5R=7H%)$`giCK1{8wT07;=0R?^;BcjwO}S5}~s zC1>TMqCv6IgTmW)?g2HVm0LgZ7yj&MGXMM*{f!2VNIgF5{B{mBLPx!)pKQ^nw;}IX z8-A2Pf~mXD(cta9_GT{a5phF0+E_f%qFMzWz!8i}OJg@YnZsq+gtoD=Yb)4$Wgrex~&fKLC$^PQ0AFo3-q9p}jqJt;F(ZWBrFk~D)IDtBg zz*czgq@vKl0K7jhmL2sFP)XxmYu=#ue^-DGg`8luRNJ$rH4xsfq29!ZO=@SleB><0 z2p>fAFcL(e4=@J(9l`K0v!u~D{p=Y-czUqfJ;q?=WenG+j>Az{vq~VW%bUQhNX8H= z#3lj%d8+}(#pYxQJS`13UoH_uLz8JR^pUTI5e|o=Ojj6VC@U*tVq;h1eOsLT`eIE+ z@~TRuu-XX?xKw5cZ*+D6V9Y@vXr0P;al1ozLBHVfgn_`J2l)u%FCsuVk)c0l*EbB^ zDijtPHzMu0|JiK3v#omqbo0k7ndoZ)-dSXtfeeDLXR1#;G>&g?PLg z73Wvu4JIQ?p;JF2S8%F?VWN&3O5hmO9OgFglpCnI`ElU4g+%$o4U5$&YT zgUyH>KK>ZRA89zrwU%#1mi_xq)6RbnrTY&1W*oM(V_2T9i8cKxdYMvgHAt`8>@Tlx zECwV)nUpi^Ld`aho7CYyi!U9kmX30Pj+tj&Mq*-OswI;*tv}wj<2lZgh8y{~indhp zmit_L7l7+{IyJCBHBVI10^AlB*LtNwCHlsgXri9z3k*$_w1%Ugg3yRCF~LtDLk)Q- zYQ5c~kCU?@AUddP&?<|pH0H*r?M~FkBqRC=epe;sjBp5{=*80a`u(5vH2hsMEJ_k@ zK2M9H7YPb|@*Tf7>i$RXc^+fTZYer!VRT)*UPfrL+de%=_6c>yRPu905DhdCCFm=90EIZwh~Lc{KZ$^!QTRay zXt2Fe903WkBopL8Udw3U?=QQW98zVz)lS2V_>068^dRS?=37VvL2BR}3IPW{xKC#=L^ zVn|>|DIm`wY}aR8gpdJClE<{kqm`(%P&Le!{ogYC8x_XA%1i;V61UXy``Ayh6j-=# zbA}tLJ-ugremvO!K3T8W_}Ne(T*8m(<%vI;dHXGqRc|+$IGPLj`a}F8H%?cLNTaNvaH_iuw(U<+~ZpX4|>5KVGr zH7Xgt3o!v?z@E&MG*;@|hu!A3a7tIqortp9mFnOHKf}Xn&PhfeF_1ZaR6H+*yapONdDz3kDv7 z@^tw%XSk%vHD#c|$9@zm+sCoS5#mS~MsL$}(z=0Y+MwJ?PPywcO1BN?!5)z~+Ku~OW zKfEy_hZL_G{DIxAgc1&X%JRrQDGVK6O&R$KlK}j^siUIA7P3uYTkH(a^J#&38jb!`;E9OBPZalZXWvpqf|{8{qlWZq7=E&k8=a+ zF-%GT5uWZ&MtuoldCD9Ph*D@ZPacGZsldpc43fpbqm1ysJe47o6uun)@#E2Sg&~FQ zRH@LV%adC&Nb!n}{ol8wgDaVoqropOE|vf$#S|hJfcMIIus2%0oaIsxHLqG(<@Rn9 z>2%3ba8UDZLNJi!wH#l|joZbwD)c7De)4h>L0Fe3j{fc|GbTYpAjp+Au-0{L_{{uu z-V?<6;acDI>2LDG)gfCO{~u&n;6!_~i{wQy&{H}Clb~V@_}jN{ms(HfGm{R|J!c7z zef;%C5-fnRgu0CR%6EH82Vn$h;)9P*Px~@jeGBqi1AaH@wE7&^X0QyJ0dJ`wm-+WC z70`;QA&(zEjEI#uf35cuNX$eevS}-AeW+$9gRlPbByS&I(|;&%v^oK=NN#`*zMLo85(dv~r?BnB7nGsE1kUlgA9 zbCgt6R2*eozjB}`C@8nLB|^l@^|99E#rPvj0dQ!8@p-8T{{ASj5;&_we^!H_B#YS&I+ciA|sYYmkq9qrI zfbcMJ)d?Vv?L?+f@Qg=x!x{sg@w<{X{~pFc zKG5j0A0b~2Y=5oQNXAuKqwCryoAFQ4UTq=Wz`=a`aYpLzlPVif(S(9KMsdN?DeJu- z9R?0$Bp!g%J?FeP(8&!{JZtOcon`du9Sj4m!nnMi3j>{8TNzsrd*E392h17AX{)Z?8F%Q30HVVk+1LX<>s&*?2sM z)7&OCwMiY>D$KFK_VaCGVr`a+n_GVri*o6uGv$*x75S`&OOLc$2}x5tcIVR5=i&e^ zh;*7cptxNx{|Sp zJ97n%Mg!znYxkqNR`l}p5A=H4KtK}W*n0Al_IY*)I^1Jt_QTCa=B<$QliawUM;qhg z`g2#SwElhP0&{NaMyLRf<&D3;f0b?xKw`^f=#5D1ju8W<;IZ@ysYPPTSNQ(19S5e4 z$OxCQ^r691yNcEC&c**85E?QNBNPI(jmx2Igf7P_CmZ?LG%fa0uxY}Fg%7{EEryY6 z?a5$+0iHvX{yOK;M^KcZyVp(7wt}o0r zXXpbTlcE2l=J`q76$lZ|oD?p%OD&dd*x;w?+Ve=zeFi15PDD`y5)wXJb<>~9%gfykwcFlj46@#r)(3RX zXQ;$D-4S?8*6{E*ngRnN{cW>e=h7DX*S$X)pk zTcDT()&j`0*ZQZ-aft1{{jbj)*N4gNX~;9{N}dSYM2Da3&Sz?q0k-0yOF&s2tF~M! zP$p2kTBz&YhY4a0Aafim%JDj*;RTHDoIHhAgb;~m|{Iu-B{o|rS5tq9Vw?&r$_i6 zW{%iYsvEZN6-UjpEZmI$ry;$dvd56(@;67-k(_d>RqGV zV3vut>*PQp?C~Rr&*}%Ov1!NFx>d0)0N;>Mh%_6Nq(R}-KFoh+8~NH#iwZJQS4T24 z9Z!#s@3!LCem7eHm}W@JF)jM>_*|>+I1oY}R=>p|W2cd2%Jg%|ZOYiYe&Ic+S)!GH zhOqCAdbF`!Gm^2#h?30HfXWVCex9XyPu8@4bIx~M>~uDs4=AD%Yd!1XD%ap*#ef&H zfsxv8bF%&8>3Inoxb^s_t-5Mip(-idtTef8Q}f))R%A<4a&vb?N=@d1Z8E|EuKP)2M_>9Xjv9+L?++S6Pa;)-SVVZY<#24}YkXw4(f=3j7znEK|ChTASfDLPp}o88)IS z6FD-|wlTnVIMUvGiByDR0B<%G;u#g?9HGB{v37o1Z`MpjQ7b78btV8q7P!%J6eNAE)>$xle?}{C&dacskrz-2Bc;BmHv2{sJa+C`l ze&fS`%*ZOCOlSl{8H@9>EbiM9`|ExDMcL#sG7v3v22D>Wkc5vVSZrVBAQvt*I)Iut zbDCJ;_ryM6r}1jw+A+|2IwtZ_tB zQiaQ}6GyMwBp5}_qR}2$vB?#7!aZJ9RF(kQsW*;a*bhSb_o1G1CkkT}nKP!KXYimKB?urY_YFB6aDiaFgw3Ia}h+% zYq*IK*^#xKE{hy$xz#pw`3fJgUc;#78WBBI5I&hP$Jb-X5^RsF0LeyAOppVjj(HCe z0`vJ_9M!rYtOwpkt*8WxDN9_t-Gp%52VzIK#Y1%_gcWT-W1%*vdcBqs1?JCZ`K|xn z8^G64PzKtKV5~CEO0`b_qeZMFNIM?`SJ#+>J@ed|y-HshfzR!I$uNZUJaDI2W~()xv0%$7JT)uN>*fG4CHV zOS`+f$`WmB8MVM{j3pJl4F6{*@7ci`4&fA#%|Cw>Gus#6%8}-+i@;u_#rt!Likmm{ zunF$<)5qok6%8wy_yGtuBh|KR!XIQ1VY+V)l0Z&j6+1zS2^y}K%~ZUw4LIdA)*8)1 z;%qoNS8!PRq-joJE%9O;P`ds}P(rVTOOkD0JeY~l`rWlEI#ZV_f=nWBIow3U5=Iks zxHh5;@CvYG^4j^9E>liDx9J0*?T}R*a4yatno$#0vJ_vD6eRga22Q)`e(2$jsOp>T zvdxo|7}bV)w;385A_40>E%GwK_!KZGCx3n=$68F4>LR4hJr<2UqK%#CNJv<=x$#FH zY9Eoh7Eda>k=YWEMlW3fqer~^TL(zXV2yoPqqp7o5^3SFbgwlW0JIund)?C(5|)*d z>050)V79%FYv9z0e$J&-HM}3GQR}VCGWhV9l`KcFT9wi$qjE-CCe4UZ8Ckih+Gn;* z?U|&^KY~W3uc{<^AFjQ%FSXD}gOObVMf>kZ=ywR`<5gMg*zIdaEE`A8Zlc#*OiaK% zhooCnWYUq&FDpy0{KBO*_}DVybe1=d*~?GmkQS8<%8XO1hO$vMZS)ZuP%YYKCQ?iR z^ixM_u?3Q3VzmLD)8WW2+1jL!*t5%)^(~{*rYqM9#4^%byV2b~OIuBJ^fSLXpFY^1 z;f&3ldPuiI^1Sfjpe%=Y=EX^UYuS#UOw)-|3>KIwCc_pB2$ktTh`?_;_hbp(BC=FN zouC68U0_1IcTgmNxFqJ%nW)Wa?-b0$eD7`4#TL|?Wn*0jsyax**(wNE1ec@uSa&0% zr5;&1+aKG8YG(MK{4jNmIW(J7eOhQhRJBbZQAt0m8fre^FEhh*qgfxfN`V?z$q^nh zkezn+Waa8`gocQLg@(&u(7dz_+EOtIRW3U$J`KA>8of1>+7V#%Uep?`-oBs4seTLB z$Ptyy*mEuDBU80Y5@A!3!>G2Xe3g+j+ekqrTTG8_Xn4+ncJ0B; z;BpkVDw@Z@a@4}`539^{V|}#q1Eq{xBJ&6n<+8P0zd4=Ep@wI@WTurlbebfM?VEoN zPMr;i7i%`j=I^QgVZE_Q&aMUwtIwT#DB(tvo$13NetHhAXm3049!L84LnHaUR=n-* zYw0$?XxYRO6>|SxtLMu#-`6rdjjC+>x02hA@@vH|4J`dEPd7`-2W}g#;l$Mf^S7P& z2P25y8z1wCk)}C-7urVs1Y^~JMc97MQUTx|tBH zPcbNzgrZc_C?t-S!mZrdFvtf?bLsL_%M;Z7?OS34hdx+ke8BJwIEc^0eYM()zv2?e zP+XhlKBb%Jfaji;h$lw@unhK>@F#j8vU6S31aXH41B94aMH2l7rzfjn*m8)4mt|Ez z8|y^?&wP%Vvd}h^=owEErZ{PtUkfI>^cjPs;jx|p&GieYxecO`{8V`6m{13{l|wor z(`q~5TI8uzB@t{oYCQU;%;Grp%i|2d1SWdZ*oh;S5mhvHX@qjHEZxQy%alG>s_B=J z?y=a)$5UBTes9Fs5LSE_{tH1EtdoOF*9k1@2UR4e(f;J4U5t`yRWYXk?KhmjuuebC z_?o>>JR0emu|ZWZDTh$hc-~sJ^sY$=*#Asea_y+1%CzT%iZ?tuE#2YUp~&Rmz!v{v z^<}xH3^78YZ9Kkx3X&Znn?gEeF@X>venL`rve)_7OW{hRFsJ7XM!B2vqjaGvS1K@9 zpv)l&8G~pCy({M3m#VSGzyVA1dd;`_dp8s`aDt$?``w&f&*Io)JZ`T~wJ)NxzStC` zCt=XhHSEur$7%)(6=VkZr1DuQ1q@}!@U=H=$_vR7UCT(Pp5=pCJ73uJ+}zw;!7vlj zyq4abd;AdacoE1D@D7OaoyC(28Hf*K$s{J|UjqZ%2Fzo(az+ZvNe&HbEEN#}gbD9V zUR6Q0fT&$LfE~oFidu9vDCv!dP*FK*1PnwAtIDiM@%exU$6b>2$MXELPhKrI7UnTrJaRcZngaSXjBs zjN98>>~>}w&t1u`lc%fgv}c?Bu1rw#3bm))556+3C5D@QBP?ah$aK+p^XF&XdFq$6 zoDrWgJD#6bd{d&VDbkTvOjAr#VpF0StvS`Yjl$ZZp1=e$1B-|I?Ku0bG;1%7drlpX z$QR2FZY?!9tDhq=krk@o73A>%tauhyb`Qu4V)QxyUUU>wkc+iho^z(l0E_q8li_zL zl4yiLMQ!efIte3qF^cw1T&_j)IQ`p|bYUz<_s4|Rf z(rVyz`_G>tDLO*YcUqxZ1J4tx(BL_-m~&s+tq~}SZRSzN#cQNngj;G3JX5~At@T81 zEHTn1Z-AViH=@MMxNQ2sVA;!kG96PxnwvvUh?~T;3g}l{xx_zV@8Q$Zc)(g=(b(RS zyDfk2^`pXvJ8g10DYh>)T4STILAz|aO8g^Yze;yjHrB}>Ym@gX*5V1L${#XHm%dAyW^Yp2Ow8Pkiv6<$3NTuI#7?i?E6^l zD3qeHa~Om{E!*t5JM2k189#8C{?t|r2<-U=p~)-1V#P145gDqFSR~CX!mIAX2aG0d z`LC^I#I?uS<(T=2-G-{sOdv~VBX7llxjIRH z=Mfk9Crr=8>FQZyp5BA~YGd!T{Z_XrU8@IJ@rkiA#;Q-5do`(MSa!mn z(cnm@uoUz5%)lDAfl#Z0mGrW>#GTZf6=NUpHyXzOMoW`GI)9Sx&$SUsQS0>dHYPy| z7=-x#1&KOuxB%xw%5whqZ?TnYpu{nOE{dQGlL=Rd)>j=bD}fC^Q3`)@da9Z6f|DlF zL{Z3EZPxep=K9={5Kk!0naqF6Cwf2_=~TkLtA_Fv>pS1h7@u(Lav7`RQIIks&Zn>q zdZ5QVZ}+0Kjtuc?D9cdPG;&~IxmwKGGyp8U3mNBCkDsvTnkk`GE`4APk3)ix+0OCL z&Q-m^Hb2E9eT}r@HkmRjfMyP{HP9F79<_|{?RBLfO{D8kcRh2(`sJk~ z4!G|2@kd%9tq;kfOl6j2$M|@%94nE5baOJbxER#%zVp)s9swYikEtE?i8N6g&noSB z=MW%%StE@d=%ddf?R<~PAk8Kc(_2q@!W_(oI42|Z8aR#m<0759l!2%m9K{4DN^$V? z`i#g>mP`)VlA)$yLMtb*KlapNe6$t2yxeK#k`Bwnl#!my(?k8>GV@6%-shV1keP<7 z{LzqL4zX9V$dutLi}+?I$PTzll+Ci#LGq6fFal>xv9Hg8!7T@(diQms07|3;t%G}9#=BWY?udkq?Grw z+}#5{joFebVIUfD`)N~vXdcKeUGiqjr1*uv#*-xkivWftT+_F>t=Bg>t_lESlO^C5 zN3rxNIgsJrvj2>RSzCk@36*S-0K$d96!6J6zVVGvdTb((jQ0Awd*MWoV!XGa`(KD{ zfZ2oR{sY+&rUIOQ1k;?8nu_em5?#$?+$}O)_Hwp$PSVBwee@b#Eb`lDBAf^w+(lg%ERTRz%4^`kuq6r6SoF}G=$J_-9Rb&F83-6#JG4fXkGEo|M8@c2 zMb(N@`GAN6i4mHa&x%h^=b=#Q*YDzSV)e+A)`Wkes2$Y+ygqRY?dfN5uhK zU3>EBWHvP_C6uCv@}lZhz0%Tog~23SY9&+yHIEK)w+d&UkfIixX=_NqtQdo}`)Htk z2#;U&jw9289up->n&p9-gN0)s9{dxPB=Rb(6!CvVrJ>3OR=556@tM6Gkl7lW=MDH!m1K+L^#Q87veErAC+bs<6EUk z`Ce=^)2$G?ir-!xs%z-6>a{LN{}32%UkJv5$sbI+$U<2!qG3F$szp9+7Tpa_z=#wU zNh3nKcOFZJiwQ2wOefmL+U48oR0J%s7VM}wn^lzCLNF8+fH9f6cXMYa##Br12b-ky zqN=}=vx|2*kWo)u(=CxxK7Yhf@ya{HxgFD!bOeItNhhln8a6O;(%Jjy@ZFl#=0uUV zW|>*QK8IepoyJa$pOPKTPK~Zc32dL-6#y*vL~S#-nixbIF78s0Oz z8Mrnp%oQ;GoeAAklc;YopGsRZ>&e6@Dk0v|Ty_@=nR~ zBC9GIkA%~lU*1lZ`P~8(cWbnTzneXwYl$IrX==4Dl?B@ree?#kUi(WVnrU5hy@s`$ z9WT!V2t%Ff*sC3IypWLCV+q@Q zg-ke6-@My=>Ad?;%DtrAkEAcRSS561U<6{DAjs)0dR)+vh0CItMslYZvs*ZPAnh&LQ*g-F(7dVwT zC4OO0Sc%?4W}7l*IaZy1N8qlM5H(Aoq$r5 z-VqR@5PI*@MIJzU?@hX)h2BDvZ-dWy&-tD6{fBoj?7cfXJ9Ayv%vQ&J;9tV-SF&`` z7-eJ7jc{42+?iul9ZnLSecfXmuu&;^#e4PP!;6SwF0yxb!Rhn$L&Z*+cd@-VfY~g- zb$F6Bp`NYIQX%_c{A>{!Pp%gQ?O2B|9|t!qjE8&Wud3(quo-ch{y}lwPl>*>-%8Qna z9Z&Kwk7i^fIDT?2T|W%7RJ2EA6VdE)=fZj7yp64a&Gl#gF(!D}P`;jaq?R`ovXPpvt%Y0#lj1R1Tu7*X+&s1L*oJNB_{ISN!$vA~eiQjw=sAdfjjLv})GM`N1}E0*cCt*DhN zS|LWsz<@(M#lb<>Ji_u!nEG?DF}Nd{$O38KDwejRPP&_m2zzpURzZ~_e?+)#J1uN~ zJap|17J#rJk5(I`x7ZsZLa21>nYEt$!*`vo0h&O~2==@f2sJz&Z&Vu+<%o?A=Yu1d z$JCEJ`uU%`&n{7`1;6f^D+ge*=sgd8 zIYyq#vXb1Qen_tn64~3}jcHw^+YMX0`}MKzie(#lOK7IluLmT&yp81b&p#u{Bg2+Y zO1`M)o6EhTA2->_2R>22BXqSqMlN04_iHp&FtL1Elv>; zNe~g*>mVCC+UBc2Zqv@HY+Hx5_&n@g22qj0vAEv%cSa38OFTwh+|T@_ZWd^f7u5NL zIk6>=Js^k?I0PqDfGPw#;)J|)kvR;xaPwa*7u;rj_buT%=0(5C_88Wz%a6W)U6$>P zE4Mr!X=(75H9-|@M#Mx!Tg3H==gPt$p=B7+ow zwZ(8cxwtIPrRkKJp7FH=o*5u!!F}M?^g+PVsk+;pDM>gVzk3446qGKAE2NX4hg+Hc z^KTI4_v&j^m0;030+mNCwcL}EtPC!{qwckjOyI31ekgh!EPIK07~b)GWGkLNiTFPw zNcA~E5kSnkoqoXL74{Dg$C>tgNsND}6P>A?BHR?9h#(~W9MtCJAUsQ#(yN6LBS#D% z>Hnp>`2rqya>=Qa-SZvNFi0VsEc{ged*07jX=>jeJYX0`_iXAViE;`OMi&!!@WESzJ&P&;e!VXlbf^>mXjI$y#Efzkra$> zVIsHw5_83B$IXNvFd$MQ$aQp`jFO-aiIESQR)IDY=zysD3c>1a)Rb1N-1pU(Y%w5w zg8-#4cW+OsQX00ax9Nm zzUd{AE%?sS`kau1)k@Ep{y!d~MNI-!T~c{#N+eid>WUKb!nNa{weHYGna> zd4M7q(WOiW8oM){Ssi%X$*n3$22AyZa>{?dEaikD!P$&{7nKCrT;Q45On~YG7&}vJ zc7ZZ@v%Dqftuv#!EwKyiBgt+`-W5E~80NW7peo=00EfucIgW&cIYtr=&UDUqUA%3K z)5PCJ2)mUro*-%24yz3TTX;J97C|o+2)_Kk-i3{^6$qvVj$X2+1O8CrfBE_UOuQ1% ziCEIxD7ZZI9g6OJ^WyJL8zETEbcIFhFEFfcxqk&pR1ypzq^{VWANdS8ISSg^|FP3n z!6(C27HvQnx$!-B`M)hE4NMP>y^hwv`3^ZKypi~K z_yoJz*tgjGLmElXl?ywYWJ!tS%jH%?7C_pC`W6IH)~m9X+l>%kD+4$qicpAj5sx zzp=iqXy?A0ycQTKU`-&=hl{j&BErZa`kvkVIeB?jzi`{9(nJ=bMX4ocUPUwfy@bex zNT0n0NERW*<^lx|DNggBEH-MKEsU@85QIR3mkqbxCv~_^0s4IgTv0k`-^P@1+vm@> za__eAz0!pGhXqgehmuA^+fu;r?1w`W&xR-Sj+QVyr%9kM$QmtD;jZ5L=>*vDOfrZU z&os6kok0^06W4bcH{q{n+-l*@1l{YF+ZO7czzRdw(h)8eUzb75Q*3Mx$gE|B}NYCX=kDFzsZ`P=be*nR?aSA;kXya$sDKhiE5zb zhT)fZZau9TvBFAV;Q!HVaRAL$IZ)Z`3Qk2HY)*?@DeDKUViRF%3@}NfS87My#_#;^ zzbF6q?=|9s;MqCHfTnzs;yt2cv44&diH74b{Jl9qkCl;-nZf!ca6LNR)GH4OsmZP48;}?)Y)%B7xl7n5^Ok%D*ho z(1B46LbIP19v%*wF(9Ef6Xj5lN@w!CL^PXKC}mHYzZLCZ*#C+!)$=h zXf{A%;~&8N5~JIk~XU_4^k7^IPKigYRfO)hzcM zn_~af-~qTMp|coNtU}d)qo$Jwf*LTRs5u)I=&r!YgFZEqtX{oT@sr)gc;(O4#Tl(8 zJcRIs$HmVDs8)_w^VCWGg9UhaBE@&ddox{Mx$2+Eu~v#^tJexoryR8k8B1Z}z1{?+ zj8##!=`S3?o~ukS=OY7)-Oj=<8OhgRknSQ!Y~pS(ka-b=TC{Xe%lj`sZ^@pSnK=ua zmcZpiA}3d+pA4Ra`tr3(j#z}grdixG6~95_-v>Q2OE@5R>J}|7yOsQGVF~c(Ny+OblBV?Lw_(i9gbX++@~#QENwuqawf}_iy5V$40foAL z(nasD{k<*ztx$JD@&|#N*ZeSpoamnHVr=E9#ZM*`aImKI%#hlroaE1`P_y{XwjHVg z&mM1un$6JB@}I?_euP!IstST+A`}&bDFJX+zCZe@*mBpp5HOfhitxVqm2VrHvk}1rmlenG)l>; zjB$CMtA|^lm5hwcrY^d!f4xdPT~)Z;F@Nw|bp=K<%z$B1o+&vg~JMRugLCrkGi3DlJJfaEawSoK*A1AsTPKyhkZ z8_TAAQ+ANziWlS(|h(hT-1tWHvDuU-k;<$O6tmp9CVEe3|@p`7ufI%tw+` zJheL`L0k2mno8oD1ic_-o*%&_gP$!2B>S?7B-2kU2B2-;RcA}QaJyXT!E3R}w|A7z zlCRrRHjkKn`)(JQ52?D&@l&SHqe=8Qe^zaE0sgHHR~vz>#PF>&RdIAlpcm zocTW{aPj}O0r>xG0}>+VBhwzMYOrxkfU1L&E;Cs2jQzAT2)XjcQW||$3Tt;9dv&TE ze&Mnmoc_-_qA5ZDbDn}=fQ%M?rtm(WVl$c5*@G9Ltvsu<(x!sN!1@rc7{*9wW60Wb zGb(kHx>n0D{S~mQ;!kGhuaLReD0(xXRWJzslnb7f8R0$Qr-oW9yfCp~#@l1C&jY&{ zz%;IX78P?w99_2Ph`wC9`#>9Fdwh6iP+XJ(PcN8@vHp6N{2<}XXS7!P616@tlxT)M z1ZH5gUHutY5El#KTp4;yneIp6M}9P&Pr^RMU>P8?Vi8lHGr6atgjoRrz;Zc9F)3zX zuS~7&i=nK=&Z%{zWap*ZUPA?N>9ZkImH1(E>~@=T4*TKl&t$F2UXL{l@!!8p@9d21 zDYWJ){qnlsujyP4T-#;lpaE)vi-lUWB1Jz!k%)CA8Esd2_3IhzS@5~sK3I;4=U>Mm+uU(<= zqcDw&I1nonWV(4%aWDcA#RR$YQf7$vzVpM=mWLWH9+mMr%odClXFk-jhWyqBAru2A z_Wr@a^0)L=$9Zr6h`XUs5LndJnL6k6=#GwQ8-CSU)4_*_C-^-B+P@OuPeP}==r&k> zAKM`+pfrG{0+}KKO2=L0@g(>98*lJmD{r4N&tmpU@BsUk33>Vouqv86qeg_6&kJ z7Y2I-L2Nv%0^rcnigM!P@{f{UrcR(-bON5u6INBb1HDKsvuM1K;ZvNRQ*|5)uh z^V-Xu&2?v&%32qA+^(K=I>9(u-O}d!fi8IP_wV0S1xFcB5-C*_8?J?$Eq(j4$!RGe z7P6zPX7=O*92^wxQz@?5_+1OJf_>p9UAWShS`W~IVqmjjG~gWll9Aeq@LhqQ79>)G z)A(z=ga~OQK!jr&97px}VQo5AJwY|x;*uWQEjO|ju5$?wJqkZ@CXto#zIcUj76h^O zty4~*y|TsRl6#u1T!4C;obj7JTbBZ*wgT4}|-FU8^Pda{zIft#cKw}MMKP20!@TmaUvV(-W z%pg{Hx$yyz_3VE+usD1FJ0jm#s>@dz7zTf2qBF+Ly4v4cN%7~>nKT}+&yFV?*o-BZ zd=ge0EiZhy_xNYc^N-d8`B01P&cVg|+zL!FZKJ{h9f$8QpDbm1#WB_f?b&_dhSws* z4#uFyt)Xv5vkeGJMgf}%Xns*k$c?O3wUqSLcO60V)` z)LW-jU1~SU!L(de_zLjEpa34fN7p5iBtmR*0S%ia!3Q%(kQw+mc!R@(TM70}`s3Z7 zoMi@I&PP516?408{0`nHRfP(kK6{ioc?&40_js4+YYp$oY`1bdY-%}N1)fymB)$5D z9$;tJWZgAtS(xCT>v)_W9WM>>I?FjHaAASF4Vvr?q+r-tl{&AbAquWye7d@xPkoJ3 zS@@Tg#jIe!{maqR85FEfV?hf50vfYtTr^_=0`;d|LUw`Pdj4ob%P5gyd#e+0ft-4OsO?e!e$g)rYPD z05M~r0RsR;SDWroBEO4w`?@G64(&YHKpa^OH93eM60_@g*B`zayR08CY>M{+C3(~@ z=zXLH51(KB#~dWOPx38!&la0EYsO3~!~4*5jn~X9$zi>Gs9#9*C3H;ivxfkDT`9&? zQGU8jF|1R%ztrbJw=z>3R$g8`K79VPStLW%iZ zKy&X%eb3d{ZMP!^Rb0zZ(NdfM1}I`kDwlU)k!e1-Pzap!^}aFHUpd)`)NxGCZI$cA%V& z-DFaxtU#yi0e09Bt9g5bt<@gje2c@{%0LbeEYbHPtju@JTvw*Da$0BW?HsphQHYFV%bk?LKm5T@p&f@WFymEr zh9*~dQ{9#UAHa}IVMQ(O0jLSixJck26F?!vY$UF6FM~US+h;o@uE7U?2#2Krg;(5R zP^l`D#K}Lb;=If9FM#deMHAB}M8Qay;dTVuFf2KTlBikEYm7;q-hD;?gy%D^HxK+@ zXstbby<(e1yj08K&om6)tR{(J_m3HNOE)mFz)|Mb|FqCMIa z^gNwro0Z&HX*Xjior zy!xqIiV!$K;5@|VlbC+ESsrHYtz!7=(C8YObMXci)Qb!<*y2=j;P05bzld^q zZ*<@Rih7OHmv? z!r*n&r}0Ak94IGc1&ih5oQ2Pv5tjSu*}1!(jfb9bs4qYugo;*pBsY69QZ)doV${cB zBOQ;ZrW$FJe*u$Nr=HRabX z1;6W6R}qUl!C*LjL86!iq7-Lu8D>|G0VQzG0ug4V zmt?6WPGCj2b99mNZqyPU3*C634aoWp36AP95S9`7Ndi7h*r|5gErV#l?G?W<0GuS` ze!qB6lL7AxvNMHGzj-}dS-v)jP@Lwg%3{A^)XQW)tn&N*eK)MioMp9u5a&P3^s5Uw@hF67mL>Q1@PM z!ORB!Dx{EEPxmjYUSo7jt@y!)EUHy2t7TJF6TZXaGL&CD2OVRkV|P&DFB*|;mx z7(-wX(ztZOsmUV@h^Bs_icXz>5p>@l{&ePhWE*6jt{JKPv+~|L87YaZ z%5wUAmH{E9?>dG|a*VfYQ;U3tJ{NbuU*51E%v3^Q(QvqrP65y|crVwZz3o8Fm-g+_ zqd^#UP*pq3f`B`OK8(yzHSCfR;m0&)tV?SliJxBVJEUlWbN?)+FyBE_%4(~jrw}sM&;yynfPwv=>dr>OTl~Nf4y1i`EU)Q z92SgZIdvCm{g0wx{U!_Q=vLcRW2=nU9mP#yMnOaazg`xU_jLQE_$&MP z;=yw>?kg#9lpSu_ZYRpnzJ(4oVO7*!)oEy3x81t8#0?jkb)I$}&FJKAtn>Q5>2j7n z`(ZHysh))@*j^v2e~1P)+gvi+9c#-vG}YI73UGeb1uObV!prr-dL#5}2Kb*fG6drv zls*oxKmc$*ix8UZrh=lR;@5hlUa8<#*&NzC-_xX)(zAUv@@%GS_yJ;L^XnTBGKd4D z)`=;-=7okqFo;mg%ip#~-x&=(Pzv3Ugq*za@$gbPo#)2A38orI74sw%rJn3%!BQTm z^fdIYm4C+>LohFIzs?oEpG!xOB^+;h&_&)Y-aGDvi%Vssuewaxw`FXFUA!a@>Y{T4 z>R1zu*gzK(7ix1CqVyUPH8U9*UH2|_l-;A_0wezdTE$xe-+9+TmHn-}xRL5{08d>b zz*D{w>44~_zb_6lHaFHTYjl5*U=^`s3wsb3yY(5yi#N5J&`xAjBEoHaes`cV0#@Xpyf3{k_6A`7#~;dt8P+z}Bj|cRL%HZr-MlKwSrx-Ua{y+k7ZVi6$2&$rTlxhZGCgMsyUq8oWBY>$nS+*j9!`ZYz) zGK(dnngL|><=V1upOhl|cpXkx!HxTEm0-o@&`O2^zCM%d~ z09!7#ln9XR%3Qg=#LBfCGZm@*r9PiwYnD~)ngHXJs(+5jtp0}MGh(pgHxrG^%TP?0kaM$< z{R}R}+X6kP^Td<~6CpUrYC;T;8xwifi907V`t$PO5FO|Pv5CN%#8VgE9R6lnqog7I>5fpJ&%7f4JF3%)hb?TB!QJ6^_7^3m1#PC!l)l2i% zodr<*RwIi~6XjwaWB{=)By(u&(JW|(JW=gv=F=a2Uje{j#;CbK&>Kha<*b*ZkDUMR zqq?o1ULqr$9B0bRV+^Iw)(2F6Sx>H${?*-{a)AKWe=9 zOc^w3fv0Hm2}NO6*>1J!6l=|SP14D6`(bn3`q^S$~Y+VF_e{pO!F6(1OO?hvmX zT>PS3F!gk2Zw`S$LGF342*Q%I>~vz#ctK8sIPrH)lRFznrAFwHy=DAiQ-^a2n$mCw zo`)LNsmM%=%VQhPoznQCU3Z-rX?7s0z25O&feE$GY7jf)GGUUFSH_8LkHGO>rW4Z; z@@e|XH;`p`?AL*Dc#=IfKFu$LHPxc9P(BRZ`#n;DnqDzTvDG=8-jkWd=d_oOhYVI^ zHE`5BZFh*W?PJDqJ7T!S47BnM#MXOwTCK*~?Lk%*rA7xJkm!v60u)eVOsK&835|Y( z?^|7a2}NG;Z2>qor568S`egBt1M_pGnfqkPY2-9!V7j+Z8Bv1{EH{}A-$VD*+^x4- zO5WM+SbO#Arnq+MY4BcV4E&B*DHgR?0`bl)eL&3?^5UiHaPId^>LQQ>Fu-}Gz5nIF zNF%S>4k?=fJ=&mU(q(|NslCo``VmdXyZPnIjE8PcF@IY73jtV zMW!`sD>v-Kp|pMOU#1YBt+bm>_1P7K^A(-aj-G;~$OQCOaic4bdIrZIMc_X-;P#7F z#2T<0b}B{Q8&)BkL3J|@om{AswW8ibAUXWD9r#zjGa(BAgwVUbv~MA9P28DPUrsul z_PHR6QcqR}GPva-$H#`9Qk_k)!1-xRRL^rlel~#e}6E)~Vle z+*%)AeD^Nfd)#_j0GrU^} zzG+~_6nY`_c8Xixm0ue)jFSTed2d^H$ksh6Sj7ZTZ4TKwB1Khha9sUuZtNXjA`)`{ z8_d46Gxs$ku1Uxb$C((AGxr&jzM)Wl{vqe2cQ(TaTc-Bz?YE-=7`Dy)4?hKFHNzu> z9m8NAzxS%~Gu%viR#9$g&xcj+;1~ORC*1lt$YbyFRiDcAx%fmrGkK4ioJ&rT-JIG* zC;f8*o4TBuXi<(tq1yX-@bII7pUtD_g1BX0b^*-+0mf@C6Uz)X_Z%aSPV_Ad$oy>v zqCRXJurS4FH-K#4c}+`CQ=#qMuRB4X8_&&+KBKssGHAtO(_c7PGBPwYroewXl&T(V z(Bob1Fc<+pHC`!DOcvleI(*uev!b2<(x^8mFjV|>OR^e!Fu76P^nt8X-*uYqU?z%0 zRyb?YwpK}ALBR$hIO|o$2#)BclJBnM%+>s3GBHMBcj2;{er{wuQ^ZKCwpSd6qNmn6 z)t)I{j@ya~t5*}ge_;Pce9x8nK9qdHAi0PeSDinDjVgGu=&vQPG5aWi`zVT{!(U7P zWV4j)?Ko>5l9^B2LFtF7=kRTYkM2DhQ|+?5lZ7eb``t_ryrAv=k!d!YMA1EVJ=Lxq zeRV!Ik86g@cJom zx#0C;Ll9^_3&XS({FL-iwP?{gp8q+SpK>8!>d|I}=BSi9y2`KULs)x#4?V5kySbwG zn#EtN_}{to3<}ChdB^E@vi3A6Nz-0&Q1(2aNB1_u&CX@8kWxty`DK%U8rvP@lpKjH zdlgcVoS4)jNdh>lU*g0$x>zLC+D-YAOa-o$@{qqfjQAo{K;dhHTvBc~><5eg>-VFd zUj=e=sh?t{6+GI3y)YRSwo{~T{s|AfwOO~TtW)b!aD?@#2Hmml!(fd{u5@&C4hvy| z6YyNF{%17bZg?!MYQlsYB!(a5__!959^^;XNnXAi_z%gxX&C)Li=oDw!b_0Qi#^&O z_)yjJotS*tB3{!*?JW&6*ZF#BVeuj_#=AzOe_#H_Abq9&_~XlZGm z1f@5OjE;r`CPOul2yLu&kS(BFt`)o;l8;(d01aZkgRYLu<((hV(|7Kq>?#RPzvYCX zzIPqnlO-a097(9=00}J3lX-_7E%;ME=!K+vP~W|;$7&0Wb$FFYab3E* zD?aq6?!Pp4g(}}7FZO!ripk||ov!Y!Ee;X4jV-LeF#6+qwJOjre9%UOsOCwqJ1u*+ zmfXOPknp9htirg7Ru50FhKmpO+r#0wE7Imf>}qb(lip4Kp7NblWA0Lym?_pZ@2aG_ zYUg!4KX}grH-Ejdkz%#for3NJ8Trye$3|&cO;=^;b%{#_;fqciS1$(?wkO<}W=Er^ zUnd*5{X*?D_u{G?b%wNE5#PQ&SowKCFT5dg0xSqF)7Iil&I}w*$wexO;DmNplB@8A z^8`ObdKvn8Rk$o;Zb3@*ob0}dbLEb*w2|pQg+CFpeD~cI<5I+9q#UkZp1l{CPHzj! za6RAduMSuK4An9{?lKb}%p`LijtAjXyQa4OaHi7ta|YEO!x7;n)g{uam38czoVdFI zGK+E^l{v3y1q|Qj^PSMIu|HUkGlCahnannspqG&EytaKP<~AA6Ie|5+8K zN_LF#3uS?eDKXCwUty&}7J{uWVvSs}g&i|EOnmKc3YPe0lmMy2iRheeU$U_j%o2{; zopE>0y@znv|X)3YmF(|<9I>=R%Vo8 zbpD)4k5E-|*6TD;GULMV`=X9*dhqyThWK$$pE>xJ<6;eO!kD+KbDHcN^W@eK$gW_+ z1Ii-z39WYy5LdL!W#)iX$3n-TfGMlAZ{R#K`?ZaXxqv%dKO6TuhVy*B zs0wI$J;WHoWgqW$+{?4eL>@OkIe{zw$sXmMU&Bi|>g*ZTJi)fE@uylLjSo5mM|{dl zqXGk*1|uT_1D*-G#@(Y}vv|QivAoGACN>=y??q4LXtT7mRBG0H+Y>3~UGpdobSsdB z5+U`;@=f#Go?D%BGQ=&Q_9m&hz6;S?m^?)@qzHshIE3mjeR_uCFdo>gjWMpJg` zHJA&OBMzom)LzQ29JK^gb;>M3CNaW(1zI0IZaq*#Y%c%*8-W>-T=R3smF_ab>qY4h zKGRS}_>?_0Yw6-rf(a0;9-LlmgK&dp+~H&KH1N6ex?mGSO zeHFHgG-`GP9s)DNnXo6?xOjE*e#73#+{cgJwJNkJcN%6^l3#`9%nY`7GsTkM$nIO^ zqeu3A{dhsh=b#KR{#(k^b}cSX8~eog>d;2Q#D0-1HmFy2#;o*SeZs8Jk_Z1VU+S1CkXD-<35((jk1*tx=Kf}^u6lj#N+sAA>MHB&-VQM8`N}d zRju4R!)BRDrAvmevYLI=pbS(WJ+t@a;KoMk=D{}%fB+D0x98&x84W<&O9xO>7bsAI z-WLb0y^8%<#J*xqBwh6NQ(ifC^QX~?hdb4R>~GPZM!6WX3A?K)F(9z{TD8#!`xZ!; z(v0%@HbAGpXwbiJ;5H7xU}kt#s)+{^nDBhFa@>=kgzYSndvHUZPY(7&K|y# zgKeE}S#pl6e4|n?lxmxLOBcHDQ;n)1Tk77hTCWFfS&H5wGdjyxe3&EHW_kk-DEI!99o!5>)3G6lQCu3u=9q1c_FG^H!?m!|(LWFb#G&rA zH)^Gmx}|xeL>s2Vl)t*@OoU2XvAwGG3bf~ZcX8|~5%3CsF8FO;VMgr+m#uU~Nie@Q zE9||bB6yx+FJ!6NM#0cq6GUzsIe^~j$WD*AIvNT$RwX58mTH=#B^c2a5(9B_Lz4zg zq)$EQR;6=K9Dejpb$?kthr8$o+#vAnb+gv%&*V9y%b&)y%pTs8WN5&@?BZv$->4Xs zmy!yoU*|MD4hGdBo!lgQzJXj&r*C@Y#UE^_c7n7E4fbgmQ;(Na)Rhv~;rrt1=X0hs z(%|w5<)J*9k&jP47WG1-rkbxfe~(lvZu`FZk7JnAZ-ZkOB*c|JEkFMugYD&lml|4H z4?GVyDd?@F?i9R28fBE1Lm3`SG{PIriQ32a$PBs8(N833i4SI zL1{5zcn(H?+TTbMCE!Z*XGmQo&dz&HPk>Q!A2W+Li03x66i23NabZ6%)EOE-)0G5XExYnk{=NF{XCb=M@gue{HfSNBQk+`7R~Jd2gdR z8#UdA7A?_}rIo@MM8m$>xVk#Hp*~zaN;dBAlv4janCq#e-L6rq0k)WPsfw`fKQVF&p?k0RNK?|BQ9=H$o) zQZhUMw{???P?N|S>AVq^C1QW@h@J)f+9%e&sNc_#IvPdp@~dz~la%+(JNLN;{dIr7 z^-r=)LfUGFLA3-w!P+z)m5e9wQ0NOX@XJdZ zeKssaChoyqX3S}xC3$?k6kQusI2|!ck9t_QvmpyR`LLR)l>A;Zq`W3dOX$)x)ED^_ zd0-v&QzmI(7U-smLvUD(f`Ng-7PiS{q(F}qh=hV{MpAiFwRCHi;`OXODd@2WRgD$j zSP$*Ra$v<)Tj)MX$~b^zcF?GZQs+k^S0vBL-lLbr00NPn{;`7qm%9fjNtoan+3kgK z+cg|#I(9SwX?aUi!c%|XacHlBc$P)?{5_K^6s3Q78*`o`pF&)TP$|=pj^PmW$e;ko zofBb^>7I}`vsH%?WcXdz<4z2|yt|E3TshuOkBffBo(vvutAC#_9`<@t5o(m0P?aAW zD3SipH4jUsRJoWe?(cdhOXc3F3y=(jr4_ubdnH@9hNZ{+I^q}nfQWF>>=xD;^1;G-J~DHpSt zn^zd@CO&ns=vDn{*6_{ba|0R`G8~4Of}=7Q*`6Qp{K~lOF7E61>R)($C=zVE)ghRW zd^r8R#W>7K82FoVh^yw^f|t;@zo_)4* zvD(V|_N}QhOv8rVx{d5AZaV@VdtX7f;S<}d;ctCb6^uE72j#*swt`ddK70Y)L|hE< zg(#28>t>fJm{I%_D?q>hJdd}+jKz28_Wg;NZ(%I(d+8E&=Wc>FXE})?uNH3xYDrxB zYYiJ=0FDm z$EB-@xYL4V9I?pyw_~i$3${VJ_iAel3Dev(L7{P%rN3BCQcE~!C2A95T;d|qYwW&@ zT{+psFZOiW`?%tX)ZE>xV+#$r_fMv>+{HEE7)D_y^C9ktQSQp3{QUA>zt!EZH7LHA zH6_>yqeYCnfO?~^5At~6@W47*&@O&M#6?!!I9m1pYNNN`8@|A(_6?c4T1$Bj` z!D(0{{WZPm)4TM%>Ec(Gv&mdSSf%gTY-LJR&x$OrLX$7aRz%z8LQH7=bLwacjS)G9 zv9UrDUf71$24sO&{U~FgAkFVerBPfxl#2QiHEnQSE@*k5-U4xEPZVUR3f*tARUZ{!p)@tq%r;aD-F0Q|+I$kj42B?yCl%YmQ|#x&ib4 z8{3LM?zJa&f3%aquI>)#Qy%>IuLXRAMhlEC-2Jv7$Y`Uc$AJF?7~Oj2cpb6+?!RRIsz?q4%*?1)nT1) z4ZSO-cE-6oV2NK8%kQYm(b3=C>0-V$Kvnw^K19J*T% zL@d3axn|jWonB(V3d#(1|Hs0i!`Jw2OV6Q6Pf*DFr)=<)Hc2xt!*DL%-ciOeaDWXk z_b!^5jd3V@j2E90?=-gQ+j@S+^uN);wXdG5uc&ilk{B?6?-d0t1t{S!&B&~{?`MZB z7SDexebc6!h@A^jn|x_^WpJ^5cQg8Fy}Un>T4V^*nbk#*UISNU0HqfuKjVV8lZegK zlUqXYok6_!sPV={X4H*tZV%M`@oL8`g8@^9*Uuzk9w^gd=a2hrW@1z(eng4i@Mu{| znDhaabMzC6JG;9kJLhkVnJG_xfs(l-u1JGs%(Pwt!_yB$MD%(D0&aO6Zf=NAnE-)o zO=uDW0XN*H{$u{`?v(kexVwy{me?bm01O;tQvlS{h0}a8pvk6`-8isRzthg0=v~_E zOtbtM)n><0d*vus4%}GdIFl@yL_Z?W8}Pv7m6n#N8fOmcapCZTWl*9PrkX)uucWNYdedxq7D64D=OVJv&EK%DdKa6t^5JiZcMXQp92 z#&gRS=jlBDSVWbASl_mRYMO~w_$84AXf(MqG^j#`APc*fX($Z;bPO~%vlA|xb?%iU z(VJ`7{muy%oB9xV2q->fw^2@rkDvIekxWx~?!*MWlHytDtu^fYUBLz1zi^RHkPx2F zv;JQCa1iDxC_mhYx0b(Z7d2(%KCfWMAYo~18J|?3Iq+hbtv>J|8mjItgAaN*Z<_Z2 zgA__fASq6wk4lxQQ}2z{Iqc^m-o5q9omSgN=tOH(>8dyc`CrU9QjGg@O4Bmx8GVtt zBG%!`sLEr=Zbwxa*4%`JV!)iOZ9F(Q*qWJjb(S*A{#V|Git?Q(8q0yf2}6Xq_cPrc zfiDtfqkOLrjFK@Wku2~ZRsvyO)3=>WtlpB! z4A7ckd+#!*HIBrRQ)184y{5Ky?pE(CB?d7np59MhgmzPt%L@L}$$>5pu8OGQ?AGz0 zd4`lqvofDO!&vl+<zBfs2yiz1KMP5qjcS+Y37D>I^o>wR3e1IB4#VcFSuUw{9i^*u@DtS(%$>+qP@NS;|$$`FZiA#Gl%~y^cc1@x<8as zf~I9F#Y-;bo=}zCS?soChAMk||0yrP#v{&z6R)k0%jyd)_M2`g8oO~~e)aPozULe3 zHX=)XC*LoL>^)^h|A4Z|eCoHeJs)_JW?56r!l!9>kH7&%G3S?oL_kLJ`Xq zC1Rs~n_c8Ds+sEQIXEDTqD{t8Zm%1i@6O?7d8 zv#DPanm+Io?OyJ?lBa%?%nR;LY&e=G+WOJnRvDUsxi1Ykem?b1GLiYq&k4_oLtB&^ zpR=20y(gRZ*@&Od)aPJ(bDKoW!`Lc0+~%<%v!fQ@Dv|it#CVT3e))uv4l4>BYQ&fJ z`g>rXowA$>e=@aJBUSs~pBJ=^)gRZi;QlLmr%bx;Jr=^@@=%5>slR@5gQgal0ny$?&WHrl8(Os2sNE()s>qENb`zPxrG6{VW+4*@sOJdrVz~sN+af zTLQc4#hFvnwHVdSfd2Ba&=M$_yk%{S7vaH!_kUfobffV&^=LqL5p|4I<9E=sYM{ex zaO-6<|LNgTKOs7pWc++@aS+(30#263=&t6c&1U|`lqnBxWtH-yhJoymo?a*8Yg|C50L^SR5W_HXSsMglr75tryqnW|Qr{ zGFy)>G0E`%IdI%9+HleWMf+Gf_VrekQ47gcB*?V3AuT7(Fn*E5N>|t9JQHmV2G@VIff=M`=DT{RfxgjN zG-HZWnSj@hSyQ91o*8w9*?^Uy(nAlN5NKQ-%l@H zpuMXi=jy4GvR3^<`n4!uWBpEll88%+_1f)Imp~Z8e#eKGYoh~f>dSAHf6Q5vBBNR5UHY^qRH7qT5fO~L%y;V8V ztN$cWCW&YjjvfK+)2~@3{>_7?A|$jXUQ1sBYSs?4gfVQeZY?9q*ZF6h{|sKJ4jk5q zdgm5%|G|R}2VBSlZbJ@kM&e#`)XW!VCW(rMsf4@*S6{SAadGj{+@j5y-3(zHd70vX zp}so{F^(6({W(F6Lc$5b0zWtO)=Sv@9t>gEN3R-WU#K^`Vww%HBX4Izmw*qea-)StgqD=Jv8ykX2G;C}Cu@06tHe zaG$BD>w!^e+Fp5=f6sq7iTm^_cn4u9pf2)5CMPa)Vq)S^%1ou*lsC#WKPuXDyzS9) zY8bRMk`Ycv*lVYOz>T-@OL7TzEf*?!W1cu=F9i`6QbkPZ9Jkdfth&1`cxVC!{#=Jo zPG0M&Y;>=V^i6J|jIy{5I+*<`w$Ev`cEHm#HfE)So8H%1UpM3R{j?~*ZPZQB7|jv# z;N?)+`ZI||s}?(H6wd=D~y_tphI8vN4{wUM;BY%a(Z#5(|^b3rF*ae?-2jPT* zghh^qJqHIzTlGHeevI+_XMw6`5~?Jz82ig#j97~* zd%r^FJ62beWn!tIsjRcR7XMH0kE`b$MIKiWbpxm?=B*}Mhh$y8o7Y}HSyPr!^t^EF zDM5WrHAMFJp?q?=-fQX=IZ?7q&UQ#JS?Sbi$uw_q6PIB#eu0O_#tYH&U()$#>b>8E z3>y@^)3=euGUrV3dunYfn{8yf^jUU#ED#cXvONLWf4s*fKnD@R(8;2@-P5_#@9rq{ z_4W1FLESqH>$3bX`5(##;>Pdt4jE@>XJ33q&k)B+8>Q}iwtMT^dVq6NWSy3ylhb}g zTK)W#644s`x@#+w8S#D8jcYBg5w8TFd)R)A3+vHCn+&ti19;`PkF!_1MiglMn^zI$ ztT2A9Y22!CrfMy?{ndqKjz@XJv-DxgJOeVAgRs0X#}lmY4oC&(=}PS& zgdNHC$Vf^+GueiXw|?c4VBCd)a&Ie#pUr(5DXH!f;8%o*)suyK=Nbd%lMRS>A!nJp z=VCv20_k&A89HLS^zK~Rm{*NlnDH1*uGU9ktsSlhBT~0dU`%hFt8L$uY85xw?`a8$ z8<#fy0<9)S8OnmeMp_23bUe57`I2N58jB;$Fv+-~!k@fxCP0OTpI@0`%%c5tt!PZI zb;v}rJlp7OClp+HO_o?J-KI~IX+o|NP!`Spm|>1G)r?q$?8J-qw8uJgTkqKUy=J=Z zE;X%l#~4)yjW&~r#BuE*S>!yFK+Qowo9746C`1a{%?nYQwbzL?iEM<0Cy(J0PgRe> z+VT(FIdj2#?d?VpQD4lkI2?E0UhRvw%?~n3F86$J?Ck8`+~Ad-`aSvjS6tDyYVX^&#h-qk*}pqUzNap%tWsj_%^>;K_CeL2~Wgq#UE1 znY2tHlu7En3B%*?in zK(^ArUTnpFXB88ZiJg*^b3@LSQp1w1@k{g8%g9-9;?UcvAAJZ9nqK?Rdz)#NDl+>< zk^KC(6y6R>SBT#f-fi4t|GAn`@wYBe1Fs^hrHY#0(>sg&QDxKR z9v2V6=(!xB3fMO;0b!68#pG=Tk?$;ruX10F?6dlnQqsQ5iQemE>=Ot6qohhv1Bxlt z?u_SGAq(K;!}~fBiqNECGG#=6M+%Wo_ty!cHd2WZhzP^VSQN$MHrm#Jg+TJHXxxKk zlEDcun31H3Q5;;tFbxf@*(IuWDq8!@v2>Zsffae*9^`!+q^2!0Qr#CWIG4_7Yb};j z@>BBs-!yIu_Spt-D~$%!LMbl=0HxcrZTFG4IYCG@24yiA zOgCIpqjh!~y=0C9x+47U<>h4p2TjdB>DeA^^L?QjOY4Zp@1{5%A+6oSWN9)JQQ9*Z z&{X#PD#w1Hby`PHD9IDSQ-uRu9$rOS4!^G1FIKM=L?wHB7k~d;PfzkTGc&t?y_c4e z;9&KsDXJcG8KRaZ5ace6^or4VB{YAwA1h^%p*_Aheb4xuYQ*0{izl49M}OpW^PJBt z7Sh@8%%BFhh#v#Dj^$hSw=WCwElR?E*PO4=e(-rar6Oe0Er5IA1dZ6NmlPgdvx!&d zW&nm*=`k20dQ)q4b(M7MmLU)Ax!?3dHX&&6R>hAu%ako6E}WQh zhGkP%sw|wg9Nu5hm(l!qCD7ToEqoxg*`QKmA~#SJQ;!52d1lH{P#e!7H?Rl{cA;sH z5_0mgFQ~4z@%Q&PV8*%dCRA*qwe#t0=^-H@GB{k-rciqqX)&2e;e>5J7H!V0GbEUw zBF1b9<&=os(4CMOv(xM5=^jYWR+Q&fgNtps<&4KstcR~Iv_su7aXGJUTpAhx{D{01 z4xghHS{9kOo5~sM008Ii?2#qM5phS0ZntK2+zEL*+d`=;5!tmDt!1eD!Z`d+NZl^l z?0{{_yW@z+WkO*=X7$OvSI)8!+Nv+{Q1pt?Dkns?34yz|kyT#x@c<^Sz49qGT(5wW zRkeE~#AMuqsuou6dikZg+g0B{gz6GJRsh0$uSH`s@cu~lK`C?v^AI7d3bYgTOsDQ8D_y#we^^!ZO)*&VBv-L^Gx4et}Z>bxRqQS?bb|0R`^A+1MLycEmuKC{`ZnVJDmA&%a z`vAOd|AV{#Qh^;Zt+LOhBGe23+Oyq)2o-p{_~Gedg8iScbQXekod-7p1D|feKEPry zF7t%NPKn~Kv#Nryg(j~8ti7BVGBFg7vY9AnmDVEz6g;F8fQF4C**6~Sg0Sp9z*v)8 zOCKK6oqT<>SO}u*?i9~_=s$8P4Z}MK(o*JTj_tXDvguHi<=@_e7tv%k18VXeZUAG4 z*+H(qAe$l}(@sPjHV2UPx-ox2wnaeBycI~5hY5ytBkw4lFPSuXXKDd!OMW?fXf8_f zf4WEU@8V5Bqydj<2!UH;4K_JZ+t6VpKxA2Wt0ZATi7};+iMKR)z?i|j&i+yaZkHgR zlx?zyxxmj-cJc!tuxXv^uI*Qe&s>8~G~B}GrVdr@Ze{PA5Vfne6T0Neb2W7%e6Or9 zFE|6^hNFXYe}GnkQwT7)fa6HQY%a>CO^KcP1c>Zees~5p2az@yQVh+p9;C@mg=mT?bQKp8L29+l~uKy324lg1A From 029b7d2e9266246feff2f165a10b16be1d7fe88e Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Sat, 13 Aug 2016 11:58:51 -0500 Subject: [PATCH 367/669] Fixed specs and fixes based on failing specs --- app/controllers/projects/issues_controller.rb | 8 +- app/services/notes/create_service.rb | 23 +- app/services/notes/slash_commands_service.rb | 19 +- .../slash_commands/interpret_service.rb | 79 +++---- .../slash_commands/command_definition.rb | 11 +- lib/gitlab/slash_commands/dsl.rb | 5 +- lib/gitlab/slash_commands/extractor.rb | 12 +- .../slash_commands/command_definition_spec.rb | 143 ++++++++++++ spec/lib/gitlab/slash_commands/dsl_spec.rb | 190 ++++------------ .../gitlab/slash_commands/extractor_spec.rb | 55 +++-- spec/services/notes/create_service_spec.rb | 2 +- .../notes/slash_commands_service_spec.rb | 33 ++- .../slash_commands/interpret_service_spec.rb | 203 +++--------------- 13 files changed, 360 insertions(+), 423 deletions(-) create mode 100644 spec/lib/gitlab/slash_commands/command_definition_spec.rb diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb index c8eda6b27f4..d0cc4b55467 100644 --- a/app/controllers/projects/issues_controller.rb +++ b/app/controllers/projects/issues_controller.rb @@ -176,12 +176,7 @@ class Projects::IssuesController < Projects::ApplicationController protected def issue - @noteable = @issue ||= - begin - @project.issues.find_by!(iid: params[:id]) - rescue ActiveRecord::RecordNotFound - redirect_old - end + @noteable = @issue ||= @project.issues.find_by(iid: params[:id]) || redirect_old end alias_method :subscribable_resource, :issue alias_method :issuable, :issue @@ -225,7 +220,6 @@ class Projects::IssuesController < Projects::ApplicationController if issue redirect_to issue_path(issue) - return else raise ActiveRecord::RecordNotFound.new end diff --git a/app/services/notes/create_service.rb b/app/services/notes/create_service.rb index e9f37e04993..a36008c3ef5 100644 --- a/app/services/notes/create_service.rb +++ b/app/services/notes/create_service.rb @@ -15,20 +15,29 @@ module Notes # **before** we save the note because if the note consists of commands # only, there is no need be create a note! slash_commands_service = SlashCommandsService.new(project, current_user) - content, command_params = slash_commands_service.extract_commands(note) - note.note = content + if slash_commands_service.supported?(note) + content, command_params = slash_commands_service.extract_commands(note) - if note.save + only_commands = content.empty? + + note.note = content + end + + if !only_commands && note.save # Finish the harder work in the background NewNoteWorker.perform_in(2.seconds, note.id, params) todo_service.new_note(note, current_user) end - # We must add the error after we call #save because errors are reset - # when #save is called - if slash_commands_service.execute(command_params, note) && note.note.blank? - note.errors.add(:commands_only, 'Your commands have been executed!') + if command_params && command_params.any? + slash_commands_service.execute(command_params, note) + + # We must add the error after we call #save because errors are reset + # when #save is called + if only_commands + note.errors.add(:commands_only, 'Your commands have been executed!') + end end note diff --git a/app/services/notes/slash_commands_service.rb b/app/services/notes/slash_commands_service.rb index f2c43775b72..4a9a8a64653 100644 --- a/app/services/notes/slash_commands_service.rb +++ b/app/services/notes/slash_commands_service.rb @@ -5,10 +5,13 @@ module Notes 'MergeRequest' => MergeRequests::UpdateService } + def supported?(note) + noteable_update_service(note) && + can?(current_user, :"update_#{note.noteable_type.underscore}", note.noteable) + end + def extract_commands(note) - @noteable_update_service = UPDATE_SERVICES[note.noteable_type] - return [] unless @noteable_update_service - return [] unless can?(current_user, :"update_#{note.noteable_type.underscore}", note.noteable) + return [note.note, {}] unless supported?(note) SlashCommands::InterpretService.new(project, current_user). execute(note.note, note.noteable) @@ -16,9 +19,15 @@ module Notes def execute(command_params, note) return if command_params.empty? + return unless supported?(note) - @noteable_update_service.new(project, current_user, command_params). - execute(note.noteable) + noteable_update_service(note).new(project, current_user, command_params).execute(note.noteable) + end + + private + + def noteable_update_service(note) + UPDATE_SERVICES[note.noteable_type] end end end diff --git a/app/services/slash_commands/interpret_service.rb b/app/services/slash_commands/interpret_service.rb index f7b9547bd2b..126f97b0f9b 100644 --- a/app/services/slash_commands/interpret_service.rb +++ b/app/services/slash_commands/interpret_service.rb @@ -2,16 +2,16 @@ module SlashCommands class InterpretService < BaseService include Gitlab::SlashCommands::Dsl - attr_reader :noteable + attr_reader :issuable # Takes a text and interpret the commands that are extracted from it. # Returns a hash of changes to be applied to a record. - def execute(content, noteable) - @noteable = noteable + def execute(content, issuable) + @issuable = issuable @updates = {} opts = { - noteable: noteable, + issuable: issuable, current_user: current_user, project: project } @@ -35,23 +35,24 @@ module SlashCommands end desc do - "Close this #{noteable.to_ability_name.humanize(capitalize: false)}" + "Close this #{issuable.to_ability_name.humanize(capitalize: false)}" end condition do - noteable.persisted? && - noteable.open? && - current_user.can?(:"update_#{noteable.to_ability_name}", noteable) + issuable.persisted? && + issuable.open? && + current_user.can?(:"update_#{issuable.to_ability_name}", issuable) end command :close do @updates[:state_event] = 'close' end desc do - "Reopen this #{noteable.to_ability_name.humanize(capitalize: false)}" + "Reopen this #{issuable.to_ability_name.humanize(capitalize: false)}" end condition do - noteable.closed? && - current_user.can?(:"update_#{noteable.to_ability_name}", noteable) + issuable.persisted? && + issuable.closed? && + current_user.can?(:"update_#{issuable.to_ability_name}", issuable) end command :reopen, :open do @updates[:state_event] = 'reopen' @@ -60,8 +61,8 @@ module SlashCommands desc 'Change title' params '' condition do - noteable.persisted? && - current_user.can?(:"update_#{noteable.to_ability_name}", noteable) + issuable.persisted? && + current_user.can?(:"update_#{issuable.to_ability_name}", issuable) end command :title do |title_param| @updates[:title] = title_param @@ -70,7 +71,7 @@ module SlashCommands desc 'Assign' params '@user' condition do - current_user.can?(:"admin_#{noteable.to_ability_name}", project) + current_user.can?(:"admin_#{issuable.to_ability_name}", project) end command :assign do |assignee_param| user = extract_references(assignee_param, :user).first @@ -82,8 +83,9 @@ module SlashCommands desc 'Remove assignee' condition do - noteable.assignee_id? && - current_user.can?(:"admin_#{noteable.to_ability_name}", project) + issuable.persisted? && + issuable.assignee_id? && + current_user.can?(:"admin_#{issuable.to_ability_name}", project) end command :unassign, :remove_assignee do @updates[:assignee_id] = nil @@ -92,7 +94,7 @@ module SlashCommands desc 'Set milestone' params '%"milestone"' condition do - current_user.can?(:"admin_#{noteable.to_ability_name}", project) && + current_user.can?(:"admin_#{issuable.to_ability_name}", project) && project.milestones.active.any? end command :milestone do |milestone_param| @@ -104,8 +106,9 @@ module SlashCommands desc 'Remove milestone' condition do - noteable.milestone_id? && - current_user.can?(:"admin_#{noteable.to_ability_name}", project) + issuable.persisted? && + issuable.milestone_id? && + current_user.can?(:"admin_#{issuable.to_ability_name}", project) end command :clear_milestone, :remove_milestone do @updates[:milestone_id] = nil @@ -114,7 +117,7 @@ module SlashCommands desc 'Add label(s)' params '~label1 ~"label 2"' condition do - current_user.can?(:"admin_#{noteable.to_ability_name}", project) && + current_user.can?(:"admin_#{issuable.to_ability_name}", project) && project.labels.any? end command :label, :labels do |labels_param| @@ -126,8 +129,9 @@ module SlashCommands desc 'Remove label(s)' params '~label1 ~"label 2"' condition do - noteable.labels.any? && - current_user.can?(:"admin_#{noteable.to_ability_name}", project) + issuable.persisted? && + issuable.labels.any? && + current_user.can?(:"admin_#{issuable.to_ability_name}", project) end command :unlabel, :remove_label, :remove_labels do |labels_param| label_ids = find_label_ids(labels_param) @@ -137,8 +141,9 @@ module SlashCommands desc 'Remove all labels' condition do - noteable.labels.any? && - current_user.can?(:"admin_#{noteable.to_ability_name}", project) + issuable.persisted? && + issuable.labels.any? && + current_user.can?(:"admin_#{issuable.to_ability_name}", project) end command :clear_labels, :clear_label do @updates[:label_ids] = [] @@ -146,8 +151,8 @@ module SlashCommands desc 'Add a todo' condition do - noteable.persisted? && - !TodoService.new.todo_exist?(noteable, current_user) + issuable.persisted? && + !TodoService.new.todo_exist?(issuable, current_user) end command :todo do @updates[:todo_event] = 'add' @@ -155,7 +160,8 @@ module SlashCommands desc 'Mark todo as done' condition do - TodoService.new.todo_exist?(noteable, current_user) + issuable.persisted? && + TodoService.new.todo_exist?(issuable, current_user) end command :done do @updates[:todo_event] = 'done' @@ -163,8 +169,8 @@ module SlashCommands desc 'Subscribe' condition do - noteable.persisted? && - !noteable.subscribed?(current_user) + issuable.persisted? && + !issuable.subscribed?(current_user) end command :subscribe do @updates[:subscription_event] = 'subscribe' @@ -172,8 +178,8 @@ module SlashCommands desc 'Unsubscribe' condition do - noteable.persisted? && - noteable.subscribed?(current_user) + issuable.persisted? && + issuable.subscribed?(current_user) end command :unsubscribe do @updates[:subscription_event] = 'unsubscribe' @@ -182,8 +188,8 @@ module SlashCommands desc 'Set due date' params '' condition do - noteable.respond_to?(:due_date) && - current_user.can?(:"update_#{noteable.to_ability_name}", noteable) + issuable.respond_to?(:due_date) && + current_user.can?(:"update_#{issuable.to_ability_name}", issuable) end command :due, :due_date do |due_date_param| due_date = Chronic.parse(due_date_param).try(:to_date) @@ -193,9 +199,10 @@ module SlashCommands desc 'Remove due date' condition do - noteable.respond_to?(:due_date) && - noteable.due_date? && - current_user.can?(:"update_#{noteable.to_ability_name}", noteable) + issuable.persisted? && + issuable.respond_to?(:due_date) && + issuable.due_date? && + current_user.can?(:"update_#{issuable.to_ability_name}", issuable) end command :clear_due_date do @updates[:due_date] = nil diff --git a/lib/gitlab/slash_commands/command_definition.rb b/lib/gitlab/slash_commands/command_definition.rb index 5dec6c91869..187c1c9489f 100644 --- a/lib/gitlab/slash_commands/command_definition.rb +++ b/lib/gitlab/slash_commands/command_definition.rb @@ -3,8 +3,8 @@ module Gitlab class CommandDefinition attr_accessor :name, :aliases, :description, :params, :condition_block, :action_block - def valid? - name.present? + def initialize(name) + @name = name end def all_names @@ -22,13 +22,6 @@ module Gitlab context.instance_exec(&condition_block) end - def to_description(opts) - return description unless description.respond_to?(:call) - - context = OpenStruct.new(opts) - context.instance_exec(&description) rescue '' - end - def execute(context, opts, *args) return if noop? || !available?(opts) diff --git a/lib/gitlab/slash_commands/dsl.rb b/lib/gitlab/slash_commands/dsl.rb index 58ba7027f84..7b1a094a7e6 100644 --- a/lib/gitlab/slash_commands/dsl.rb +++ b/lib/gitlab/slash_commands/dsl.rb @@ -73,16 +73,13 @@ module Gitlab def command(*command_names, &block) name, *aliases = command_names - definition = CommandDefinition.new - definition.name = name + definition = CommandDefinition.new(name) definition.aliases = aliases definition.description = @description || '' definition.params = @params || [] definition.condition_block = @condition_block definition.action_block = block - return unless definition.valid? - self.command_definitions << definition definition.all_names.each do |name| diff --git a/lib/gitlab/slash_commands/extractor.rb b/lib/gitlab/slash_commands/extractor.rb index a6838cb5e7c..02c4c8c492e 100644 --- a/lib/gitlab/slash_commands/extractor.rb +++ b/lib/gitlab/slash_commands/extractor.rb @@ -29,8 +29,8 @@ module Gitlab # commands = extractor.extract_commands(msg) #=> [['labels', '~foo ~"bar baz"']] # msg #=> "hello\nworld" # ``` - def extract_commands(content, opts) - return [] unless content + def extract_commands(content, opts = {}) + return [content, []] unless content content = content.dup @@ -107,7 +107,13 @@ module Gitlab # Command not in a blockquote, blockcode, or HTML tag: # /close - ^\/(?#{Regexp.union(names)})(?:$|\ (?[^\/\n]*)$) + ^\/ + (?#{Regexp.union(names)}) + (?: + [ ] + (?[^\/\n]*) + )? + (?:\n|$) ) }mx end diff --git a/spec/lib/gitlab/slash_commands/command_definition_spec.rb b/spec/lib/gitlab/slash_commands/command_definition_spec.rb new file mode 100644 index 00000000000..2a75fab24b0 --- /dev/null +++ b/spec/lib/gitlab/slash_commands/command_definition_spec.rb @@ -0,0 +1,143 @@ +require 'spec_helper' + +describe Gitlab::SlashCommands::CommandDefinition do + subject { described_class.new(:command) } + + describe "#all_names" do + context "when the command has aliases" do + before do + subject.aliases = [:alias1, :alias2] + end + + it "returns an array with the name and aliases" do + expect(subject.all_names).to eq([:command, :alias1, :alias2]) + end + end + + context "when the command doesn't have aliases" do + it "returns an array with the name" do + expect(subject.all_names).to eq([:command]) + end + end + end + + describe "#noop?" do + context "when the command has an action block" do + before do + subject.action_block = -> { } + end + + it "returns false" do + expect(subject.noop?).to be false + end + end + + context "when the command doesn't have an action block" do + it "returns true" do + expect(subject.noop?).to be true + end + end + end + + describe "#available?" do + let(:opts) { { go: false } } + + context "when the command has a condition block" do + before do + subject.condition_block = -> { go } + end + + context "when the condition block returns true" do + before do + opts[:go] = true + end + + it "returns true" do + expect(subject.available?(opts)).to be true + end + end + + context "when the condition block returns false" do + it "returns false" do + expect(subject.available?(opts)).to be false + end + end + end + + context "when the command doesn't have a condition block" do + it "returns true" do + expect(subject.available?(opts)).to be true + end + end + end + + describe "#execute" do + let(:context) { OpenStruct.new(run: false) } + + context "when the command is a noop" do + it "doesn't execute the command" do + expect(context).not_to receive(:instance_exec) + + subject.execute(context, {}) + + expect(context.run).to be false + end + end + + context "when the command is not a noop" do + before do + subject.action_block = -> { self.run = true } + end + + context "when the command is not available" do + before do + subject.condition_block = -> { false } + end + + it "doesn't execute the command" do + subject.execute(context, {}) + + expect(context.run).to be false + end + end + + context "when the command is available" do + context "when the command has an exact number of arguments" do + before do + subject.action_block = ->(arg) { self.run = arg } + end + + context "when the command is provided a wrong number of arguments" do + it "doesn't execute the command" do + subject.execute(context, {}, true, true) + + expect(context.run).to be false + end + end + + context "when the command is provided the right number of arguments" do + it "executes the command" do + subject.execute(context, {}, true) + + expect(context.run).to be true + end + end + end + + context "when the command has a variable number of arguments" do + before do + subject.action_block = ->(*args) { self.run = args.first } + end + + context "when the command is provided any number of arguments" do + it "executes the command" do + subject.execute(context, {}, true, true) + + expect(context.run).to be true + end + end + end + end + end + end +end diff --git a/spec/lib/gitlab/slash_commands/dsl_spec.rb b/spec/lib/gitlab/slash_commands/dsl_spec.rb index 500ff3ca1fe..87be3455baf 100644 --- a/spec/lib/gitlab/slash_commands/dsl_spec.rb +++ b/spec/lib/gitlab/slash_commands/dsl_spec.rb @@ -10,9 +10,9 @@ describe Gitlab::SlashCommands::Dsl do "Hello World!" end - desc 'A command returning a value' + desc { "A command with #{something}" } command :returning do - return 42 + 42 end params 'The first argument' @@ -28,7 +28,7 @@ describe Gitlab::SlashCommands::Dsl do [arg1, arg2] end - command :cc, noop: true + command :cc condition do project == 'foo' @@ -49,182 +49,74 @@ describe Gitlab::SlashCommands::Dsl do { name: :no_args, aliases: [:none], description: 'A command with no args', params: [], - condition_block: nil, action_block: a_kind_of(Proc), - opts: {} + condition_block: nil, action_block: a_kind_of(Proc) }, { name: :returning, aliases: [], description: 'A command returning a value', params: [], - condition_block: nil, action_block: a_kind_of(Proc), - opts: {} + condition_block: nil, action_block: a_kind_of(Proc) }, { name: :one_arg, aliases: [:once, :first], description: '', params: ['The first argument'], - condition_block: nil, action_block: a_kind_of(Proc), - opts: {} + condition_block: nil, action_block: a_kind_of(Proc) }, { name: :two_args, aliases: [], description: '', params: ['The first argument', 'The second argument'], - condition_block: nil, action_block: a_kind_of(Proc), - opts: {} + condition_block: nil, action_block: a_kind_of(Proc) }, { name: :cc, aliases: [], description: '', params: [], - condition_block: nil, action_block: nil, - opts: { noop: true } + condition_block: nil, action_block: nil }, { name: :wildcard, aliases: [], description: '', params: [], - condition_block: nil, action_block: a_kind_of(Proc), - opts: {} + condition_block: nil, action_block: a_kind_of(Proc) } ] end it 'returns an array with commands definitions' do - expect(DummyClass.command_definitions).to match_array base_expected - end + no_args_def, returning_def, one_arg_def, two_args_def, cc_def, cond_action_def, wildcard_def = DummyClass.command_definitions - context 'with options passed' do - context 'when condition is met' do - let(:expected) do - base_expected << { - name: :cond_action, aliases: [], - description: '', params: [], - condition_block: a_kind_of(Proc), action_block: a_kind_of(Proc), - opts: {} - } - end + expect(no_args_def.name).to eq(:no_args) + expect(no_args_def.aliases).to eq([:none]) + expect(no_args_def.description).to eq('A command with no args') + expect(no_args_def.params).to eq([]) + expect(no_args_def.condition_block).to be_nil + expect(no_args_def.action_block).to be_a_kind_of(Proc) - it 'returns an array with commands definitions' do - expect(DummyClass.command_definitions(project: 'foo')).to match_array expected - end - end + expect(returning_def.name).to eq(:returning) + expect(returning_def.aliases).to eq([]) + expect(returning_def.description).to be_a_kind_of(Proc) + expect(returning_def.to_h(something: "a block description")[:description]).to eq('A command with a block description') + expect(returning_def.params).to eq([]) + expect(returning_def.condition_block).to be_nil + expect(returning_def.action_block).to be_a_kind_of(Proc) - context 'when condition is not met' do - it 'returns an array with commands definitions without actions that did not met conditions' do - expect(DummyClass.command_definitions(project: 'bar')).to match_array base_expected - end - end + expect(one_arg_def.name).to eq(:one_arg) + expect(one_arg_def.aliases).to eq([:once, :first]) + expect(one_arg_def.description).to eq('') + expect(one_arg_def.params).to eq(['The first argument']) + expect(one_arg_def.condition_block).to be_nil + expect(one_arg_def.action_block).to be_a_kind_of(Proc) - context 'when description can be generated dynamically' do - it 'returns an array with commands definitions with dynamic descriptions' do - base_expected[3][:description] = 'A dynamic description for MERGE REQUEST' + expect(cc_def.name).to eq(:cc) + expect(cc_def.aliases).to eq([]) + expect(cc_def.description).to eq('') + expect(cc_def.params).to eq([]) + expect(cc_def.condition_block).to be_nil + expect(cc_def.action_block).to be_nil - expect(DummyClass.command_definitions(noteable: 'merge request')).to match_array base_expected - end - end - end - end - - describe '.command_names' do - let(:base_expected) do - [ - :no_args, :none, :returning, :one_arg, - :once, :first, :two_args, :wildcard - ] - end - - it 'returns an array with commands definitions' do - expect(DummyClass.command_names).to eq base_expected - end - - context 'with options passed' do - context 'when condition is met' do - let(:expected) { base_expected << :cond_action } - - it 'returns an array with commands definitions' do - expect(DummyClass.command_names(project: 'foo')).to match_array expected - end - end - - context 'when condition is not met' do - it 'returns an array with commands definitions without action that did not met conditions' do - expect(DummyClass.command_names(project: 'bar')).to match_array base_expected - end - end - end - end - - let(:dummy) { DummyClass.new(nil) } - - describe '#execute_command' do - describe 'command with no args' do - context 'called with no args' do - it 'succeeds' do - expect(dummy.execute_command(:no_args)).to eq 'Hello World!' - end - end - end - - describe 'command with an explicit return' do - context 'called with no args' do - it 'succeeds' do - expect { dummy.execute_command(:returning) }.to raise_error(LocalJumpError) - end - end - end - - describe 'command with one arg' do - context 'called with one arg' do - it 'succeeds' do - expect(dummy.execute_command(:one_arg, 42)).to eq 42 - end - end - end - - describe 'command with two args' do - context 'called with two args' do - it 'succeeds' do - expect(dummy.execute_command(:two_args, 42, 'foo')).to eq [42, 'foo'] - end - end - end - - describe 'noop command' do - it 'returns nil' do - expect(dummy.execute_command(:cc)).to be_nil - end - end - - describe 'command with condition' do - context 'when condition is not met' do - it 'returns nil' do - expect(dummy.execute_command(:cond_action)).to be_nil - end - end - - context 'when condition is met' do - let(:dummy) { DummyClass.new('foo') } - - it 'succeeds' do - expect(dummy.execute_command(:cond_action, 42)).to eq 42 - end - end - end - - describe 'command with wildcard' do - context 'called with no args' do - it 'succeeds' do - expect(dummy.execute_command(:wildcard)).to eq [] - end - end - - context 'called with one arg' do - it 'succeeds' do - expect(dummy.execute_command(:wildcard, 42)).to eq [42] - end - end - - context 'called with two args' do - it 'succeeds' do - expect(dummy.execute_command(:wildcard, 42, 'foo')).to eq [42, 'foo'] - end - end + expect(wildcard_def.name).to eq(:wildcard) + expect(wildcard_def.aliases).to eq([]) + expect(wildcard_def.description).to eq('') + expect(wildcard_def.params).to eq([]) + expect(wildcard_def.condition_block).to be_nil + expect(wildcard_def.action_block).to be_a_kind_of(Proc) end end end diff --git a/spec/lib/gitlab/slash_commands/extractor_spec.rb b/spec/lib/gitlab/slash_commands/extractor_spec.rb index 8a6801205fa..09f909dcdd2 100644 --- a/spec/lib/gitlab/slash_commands/extractor_spec.rb +++ b/spec/lib/gitlab/slash_commands/extractor_spec.rb @@ -1,32 +1,43 @@ require 'spec_helper' describe Gitlab::SlashCommands::Extractor do - let(:extractor) { described_class.new([:open, :assign, :labels, :power]) } + let(:definitions) do + Class.new do + include Gitlab::SlashCommands::Dsl + + command(:reopen, :open) { } + command(:assign) { } + command(:labels) { } + command(:power) { } + end.command_definitions + end + + let(:extractor) { described_class.new(definitions) } shared_examples 'command with no argument' do it 'extracts command' do - commands = extractor.extract_commands(original_msg) + msg, commands = extractor.extract_commands(original_msg) expect(commands).to eq [['open']] - expect(original_msg).to eq final_msg + expect(msg).to eq final_msg end end shared_examples 'command with a single argument' do it 'extracts command' do - commands = extractor.extract_commands(original_msg) + msg, commands = extractor.extract_commands(original_msg) expect(commands).to eq [['assign', '@joe']] - expect(original_msg).to eq final_msg + expect(msg).to eq final_msg end end shared_examples 'command with multiple arguments' do it 'extracts command' do - commands = extractor.extract_commands(original_msg) + msg, commands = extractor.extract_commands(original_msg) expect(commands).to eq [['labels', '~foo ~"bar baz" label']] - expect(original_msg).to eq final_msg + expect(msg).to eq final_msg end end @@ -49,7 +60,7 @@ describe Gitlab::SlashCommands::Extractor do context 'in the middle of a line' do it 'does not extract command' do msg = "hello\nworld /open" - commands = extractor.extract_commands(msg) + msg, commands = extractor.extract_commands(msg) expect(commands).to be_empty expect(msg).to eq "hello\nworld /open" @@ -59,7 +70,7 @@ describe Gitlab::SlashCommands::Extractor do context 'at the end of content' do it_behaves_like 'command with no argument' do let(:original_msg) { "hello\n/open" } - let(:final_msg) { "hello\n" } + let(:final_msg) { "hello" } end end end @@ -82,7 +93,7 @@ describe Gitlab::SlashCommands::Extractor do context 'in the middle of a line' do it 'does not extract command' do msg = "hello\nworld /assign @joe" - commands = extractor.extract_commands(msg) + msg, commands = extractor.extract_commands(msg) expect(commands).to be_empty expect(msg).to eq "hello\nworld /assign @joe" @@ -92,14 +103,14 @@ describe Gitlab::SlashCommands::Extractor do context 'at the end of content' do it_behaves_like 'command with a single argument' do let(:original_msg) { "hello\n/assign @joe" } - let(:final_msg) { "hello\n" } + let(:final_msg) { "hello" } end end context 'when argument is not separated with a space' do it 'does not extract command' do msg = "hello\n/assign@joe\nworld" - commands = extractor.extract_commands(msg) + msg, commands = extractor.extract_commands(msg) expect(commands).to be_empty expect(msg).to eq "hello\n/assign@joe\nworld" @@ -125,7 +136,7 @@ describe Gitlab::SlashCommands::Extractor do context 'in the middle of a line' do it 'does not extract command' do msg = %(hello\nworld /labels ~foo ~"bar baz" label) - commands = extractor.extract_commands(msg) + msg, commands = extractor.extract_commands(msg) expect(commands).to be_empty expect(msg).to eq %(hello\nworld /labels ~foo ~"bar baz" label) @@ -135,14 +146,14 @@ describe Gitlab::SlashCommands::Extractor do context 'at the end of content' do it_behaves_like 'command with multiple arguments' do let(:original_msg) { %(hello\n/labels ~foo ~"bar baz" label) } - let(:final_msg) { "hello\n" } + let(:final_msg) { "hello" } end end context 'when argument is not separated with a space' do it 'does not extract command' do msg = %(hello\n/labels~foo ~"bar baz" label\nworld) - commands = extractor.extract_commands(msg) + msg, commands = extractor.extract_commands(msg) expect(commands).to be_empty expect(msg).to eq %(hello\n/labels~foo ~"bar baz" label\nworld) @@ -152,7 +163,7 @@ describe Gitlab::SlashCommands::Extractor do it 'extracts command with multiple arguments and various prefixes' do msg = %(hello\n/power @user.name %9.10 ~"bar baz.2"\nworld) - commands = extractor.extract_commands(msg) + msg, commands = extractor.extract_commands(msg) expect(commands).to eq [['power', '@user.name %9.10 ~"bar baz.2"']] expect(msg).to eq "hello\nworld" @@ -160,15 +171,15 @@ describe Gitlab::SlashCommands::Extractor do it 'extracts multiple commands' do msg = %(hello\n/power @user.name %9.10 ~"bar baz.2" label\nworld\n/open) - commands = extractor.extract_commands(msg) + msg, commands = extractor.extract_commands(msg) expect(commands).to eq [['power', '@user.name %9.10 ~"bar baz.2" label'], ['open']] - expect(msg).to eq "hello\nworld\n" + expect(msg).to eq "hello\nworld" end it 'does not alter original content if no command is found' do msg = 'Fixes #123' - commands = extractor.extract_commands(msg) + msg, commands = extractor.extract_commands(msg) expect(commands).to be_empty expect(msg).to eq 'Fixes #123' @@ -177,7 +188,7 @@ describe Gitlab::SlashCommands::Extractor do it 'does not extract commands inside a blockcode' do msg = "Hello\r\n```\r\nThis is some text\r\n/close\r\n/assign @user\r\n```\r\n\r\nWorld" expected = msg.delete("\r") - commands = extractor.extract_commands(msg) + msg, commands = extractor.extract_commands(msg) expect(commands).to be_empty expect(msg).to eq expected @@ -186,7 +197,7 @@ describe Gitlab::SlashCommands::Extractor do it 'does not extract commands inside a blockquote' do msg = "Hello\r\n>>>\r\nThis is some text\r\n/close\r\n/assign @user\r\n>>>\r\n\r\nWorld" expected = msg.delete("\r") - commands = extractor.extract_commands(msg) + msg, commands = extractor.extract_commands(msg) expect(commands).to be_empty expect(msg).to eq expected @@ -195,7 +206,7 @@ describe Gitlab::SlashCommands::Extractor do it 'does not extract commands inside a HTML tag' do msg = "Hello\r\n
\r\nThis is some text\r\n/close\r\n/assign @user\r\n
\r\n\r\nWorld" expected = msg.delete("\r") - commands = extractor.extract_commands(msg) + msg, commands = extractor.extract_commands(msg) expect(commands).to be_empty expect(msg).to eq expected diff --git a/spec/services/notes/create_service_spec.rb b/spec/services/notes/create_service_spec.rb index 92dbccf0729..93885c84dc3 100644 --- a/spec/services/notes/create_service_spec.rb +++ b/spec/services/notes/create_service_spec.rb @@ -56,7 +56,7 @@ describe Notes::CreateService, services: true do it "creates regular note if emoji name is invalid" do opts = { - note: ':smile: moretext: ', + note: ':smile: moretext:', noteable_type: 'Issue', noteable_id: issue.id } diff --git a/spec/services/notes/slash_commands_service_spec.rb b/spec/services/notes/slash_commands_service_spec.rb index 5632ec09834..9a262fcf32f 100644 --- a/spec/services/notes/slash_commands_service_spec.rb +++ b/spec/services/notes/slash_commands_service_spec.rb @@ -12,7 +12,6 @@ describe Notes::SlashCommandsService, services: true do before do note.note = note_text - described_class.new(project, master).execute(note) end describe 'note with only command' do @@ -20,7 +19,10 @@ describe Notes::SlashCommandsService, services: true do let(:note_text) { %(/close\n/assign @#{assignee.username}") } it 'saves the note and does not alter the note text' do - expect(note.note).to eq note_text + content, command_params = service.extract_commands(note) + + expect(content).to eq note_text + expect(command_params).to be_empty end end end @@ -30,7 +32,10 @@ describe Notes::SlashCommandsService, services: true do let(:note_text) { %(HELLO\n/close\n/assign @#{assignee.username}\nWORLD) } it 'saves the note and does not alter the note text' do - expect(note.note).to eq note_text + content, command_params = service.extract_commands(note) + + expect(content).to eq note_text + expect(command_params).to be_empty end end end @@ -53,9 +58,10 @@ describe Notes::SlashCommandsService, services: true do end it 'closes noteable, sets labels, assigns, and sets milestone to noteable, and leave no note' do - described_class.new(project, master).execute(note) + content, command_params = service.extract_commands(note) + service.execute(command_params, note) - expect(note.note).to eq '' + expect(content).to eq '' expect(note.noteable).to be_closed expect(note.noteable.labels).to match_array(labels) expect(note.noteable.assignee).to eq(assignee) @@ -71,9 +77,10 @@ describe Notes::SlashCommandsService, services: true do let(:note_text) { '/open' } it 'opens the noteable, and leave no note' do - described_class.new(project, master).execute(note) + content, command_params = service.extract_commands(note) + service.execute(command_params, note) - expect(note.note).to eq '' + expect(content).to eq '' expect(note.noteable).to be_open end end @@ -86,9 +93,10 @@ describe Notes::SlashCommandsService, services: true do end it 'closes noteable, sets labels, assigns, and sets milestone to noteable' do - described_class.new(project, master).execute(note) + content, command_params = service.extract_commands(note) + service.execute(command_params, note) - expect(note.note).to eq "HELLO\nWORLD" + expect(content).to eq "HELLO\nWORLD" expect(note.noteable).to be_closed expect(note.noteable.labels).to match_array(labels) expect(note.noteable.assignee).to eq(assignee) @@ -104,9 +112,10 @@ describe Notes::SlashCommandsService, services: true do let(:note_text) { "HELLO\n/open\nWORLD" } it 'opens the noteable' do - described_class.new(project, master).execute(note) + content, command_params = service.extract_commands(note) + service.execute(command_params, note) - expect(note.note).to eq "HELLO\nWORLD" + expect(content).to eq "HELLO\nWORLD" expect(note.noteable).to be_open end end @@ -114,6 +123,8 @@ describe Notes::SlashCommandsService, services: true do end describe '#execute' do + let(:service) { described_class.new(project, master) } + it_behaves_like 'note on noteable that supports slash commands' do let(:note) { build(:note_on_issue, project: project) } end diff --git a/spec/services/slash_commands/interpret_service_spec.rb b/spec/services/slash_commands/interpret_service_spec.rb index 0cf77e53435..c20aa90ddde 100644 --- a/spec/services/slash_commands/interpret_service_spec.rb +++ b/spec/services/slash_commands/interpret_service_spec.rb @@ -12,141 +12,6 @@ describe SlashCommands::InterpretService, services: true do project.team << [user, :developer] end - describe '#command_names' do - subject do - described_class.command_names( - project: project, - noteable: issue, - current_user: user - ) - end - - it 'returns the basic known commands' do - is_expected.to match_array([ - :close, - :title, - :assign, :reassign, - :todo, - :subscribe, - :due_date, :due - ]) - end - - context 'when noteable is open' do - it 'includes the :close command' do - is_expected.to include(*[:close]) - end - end - - context 'when noteable is closed' do - before do - issue.close! - end - - it 'includes the :open, :reopen commands' do - is_expected.to include(*[:open, :reopen]) - end - end - - context 'when noteable has an assignee' do - before do - issue.update(assignee_id: user.id) - end - - it 'includes the :unassign, :remove_assignee commands' do - is_expected.to include(*[:unassign, :remove_assignee]) - end - end - - context 'when noteable has a milestone' do - before do - issue.update(milestone: milestone) - end - - it 'includes the :clear_milestone, :remove_milestone commands' do - is_expected.to include(*[:milestone, :clear_milestone, :remove_milestone]) - end - end - - context 'when project has a milestone' do - before do - milestone - end - - it 'includes the :milestone command' do - is_expected.to include(*[:milestone]) - end - end - - context 'when noteable has a label' do - before do - issue.update(label_ids: [bug.id]) - end - - it 'includes the :unlabel, :remove_labels, :remove_label, :clear_labels, :clear_label commands' do - is_expected.to include(*[:unlabel, :remove_labels, :remove_label, :clear_labels, :clear_label]) - end - end - - context 'when project has a label' do - before do - inprogress - end - - it 'includes the :labels, :label commands' do - is_expected.to include(*[:labels, :label]) - end - end - - context 'when user has no todo' do - it 'includes the :todo command' do - is_expected.to include(*[:todo]) - end - end - - context 'when user has a todo' do - before do - TodoService.new.mark_todo(issue, user) - end - - it 'includes the :done command' do - is_expected.to include(*[:done]) - end - end - - context 'when user is not subscribed' do - it 'includes the :subscribe command' do - is_expected.to include(*[:subscribe]) - end - end - - context 'when user is subscribed' do - before do - issue.subscribe(user) - end - - it 'includes the :unsubscribe command' do - is_expected.to include(*[:unsubscribe]) - end - end - - context 'when noteable has a no due date' do - it 'includes the :due_date, :due commands' do - is_expected.to include(*[:due_date, :due]) - end - end - - context 'when noteable has a due date' do - before do - issue.update(due_date: Date.today) - end - - it 'includes the :clear_due_date command' do - is_expected.to include(*[:due_date, :due, :clear_due_date]) - end - end - end - describe '#execute' do let(:service) { described_class.new(project, user) } let(:merge_request) { create(:merge_request, source_project: project) } @@ -154,60 +19,60 @@ describe SlashCommands::InterpretService, services: true do shared_examples 'open command' do it 'returns state_event: "open" if content contains /open' do issuable.close! - changes = service.execute(content, issuable) + _, updates = service.execute(content, issuable) - expect(changes).to eq(state_event: 'reopen') + expect(updates).to eq(state_event: 'reopen') end end shared_examples 'close command' do it 'returns state_event: "close" if content contains /open' do - changes = service.execute(content, issuable) + _, updates = service.execute(content, issuable) - expect(changes).to eq(state_event: 'close') + expect(updates).to eq(state_event: 'close') end end shared_examples 'title command' do it 'populates title: "A brand new title" if content contains /title A brand new title' do - changes = service.execute(content, issuable) + _, updates = service.execute(content, issuable) - expect(changes).to eq(title: 'A brand new title') + expect(updates).to eq(title: 'A brand new title') end end shared_examples 'assign command' do it 'fetches assignee and populates assignee_id if content contains /assign' do - changes = service.execute(content, issuable) + _, updates = service.execute(content, issuable) - expect(changes).to eq(assignee_id: user.id) + expect(updates).to eq(assignee_id: user.id) end end shared_examples 'unassign command' do it 'populates assignee_id: nil if content contains /unassign' do issuable.update(assignee_id: user.id) - changes = service.execute(content, issuable) + _, updates = service.execute(content, issuable) - expect(changes).to eq(assignee_id: nil) + expect(updates).to eq(assignee_id: nil) end end shared_examples 'milestone command' do it 'fetches milestone and populates milestone_id if content contains /milestone' do milestone # populate the milestone - changes = service.execute(content, issuable) + _, updates = service.execute(content, issuable) - expect(changes).to eq(milestone_id: milestone.id) + expect(updates).to eq(milestone_id: milestone.id) end end shared_examples 'clear_milestone command' do it 'populates milestone_id: nil if content contains /clear_milestone' do issuable.update(milestone_id: milestone.id) - changes = service.execute(content, issuable) + _, updates = service.execute(content, issuable) - expect(changes).to eq(milestone_id: nil) + expect(updates).to eq(milestone_id: nil) end end @@ -215,86 +80,86 @@ describe SlashCommands::InterpretService, services: true do it 'fetches label ids and populates add_label_ids if content contains /label' do bug # populate the label inprogress # populate the label - changes = service.execute(content, issuable) + _, updates = service.execute(content, issuable) - expect(changes).to eq(add_label_ids: [bug.id, inprogress.id]) + expect(updates).to eq(add_label_ids: [bug.id, inprogress.id]) end end shared_examples 'unlabel command' do it 'fetches label ids and populates remove_label_ids if content contains /unlabel' do issuable.update(label_ids: [inprogress.id]) # populate the label - changes = service.execute(content, issuable) + _, updates = service.execute(content, issuable) - expect(changes).to eq(remove_label_ids: [inprogress.id]) + expect(updates).to eq(remove_label_ids: [inprogress.id]) end end shared_examples 'clear_labels command' do it 'populates label_ids: [] if content contains /clear_labels' do issuable.update(label_ids: [inprogress.id]) # populate the label - changes = service.execute(content, issuable) + _, updates = service.execute(content, issuable) - expect(changes).to eq(label_ids: []) + expect(updates).to eq(label_ids: []) end end shared_examples 'todo command' do it 'populates todo_event: "add" if content contains /todo' do - changes = service.execute(content, issuable) + _, updates = service.execute(content, issuable) - expect(changes).to eq(todo_event: 'add') + expect(updates).to eq(todo_event: 'add') end end shared_examples 'done command' do it 'populates todo_event: "done" if content contains /done' do TodoService.new.mark_todo(issuable, user) - changes = service.execute(content, issuable) + _, updates = service.execute(content, issuable) - expect(changes).to eq(todo_event: 'done') + expect(updates).to eq(todo_event: 'done') end end shared_examples 'subscribe command' do it 'populates subscription_event: "subscribe" if content contains /subscribe' do - changes = service.execute(content, issuable) + _, updates = service.execute(content, issuable) - expect(changes).to eq(subscription_event: 'subscribe') + expect(updates).to eq(subscription_event: 'subscribe') end end shared_examples 'unsubscribe command' do it 'populates subscription_event: "unsubscribe" if content contains /unsubscribe' do issuable.subscribe(user) - changes = service.execute(content, issuable) + _, updates = service.execute(content, issuable) - expect(changes).to eq(subscription_event: 'unsubscribe') + expect(updates).to eq(subscription_event: 'unsubscribe') end end shared_examples 'due_date command' do it 'populates due_date: Date.new(2016, 8, 28) if content contains /due_date 2016-08-28' do - changes = service.execute(content, issuable) + _, updates = service.execute(content, issuable) - expect(changes).to eq(due_date: defined?(expected_date) ? expected_date : Date.new(2016, 8, 28)) + expect(updates).to eq(due_date: defined?(expected_date) ? expected_date : Date.new(2016, 8, 28)) end end shared_examples 'clear_due_date command' do it 'populates due_date: nil if content contains /clear_due_date' do issuable.update(due_date: Date.today) - changes = service.execute(content, issuable) + _, updates = service.execute(content, issuable) - expect(changes).to eq(due_date: nil) + expect(updates).to eq(due_date: nil) end end shared_examples 'empty command' do it 'populates {} if content contains an unsupported command' do - changes = service.execute(content, issuable) + _, updates = service.execute(content, issuable) - expect(changes).to be_empty + expect(updates).to be_empty end end From 5a1eff710dc0483ad510cd49840b2af8e2877a44 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Tue, 16 Aug 2016 17:42:39 -0500 Subject: [PATCH 368/669] Update CHANGELOG for 8.10.6, 8.9.7, and 8.8.8 [ci skip] --- CHANGELOG | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 5fdb4c2ec3a..2a7109b3c2b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -120,8 +120,11 @@ v 8.11.0 (unreleased) - Speed up todos queries by limiting the projects set we join with - Ensure file editing in UI does not overwrite commited changes without warning user -v 8.10.6 (unreleased) - - Fix import/export configuration missing some included attributes +v 8.10.6 + - Upgrade Rails to 4.2.7.1 for security fixes. !5781 + - Restore "Largest repository" sort option on Admin > Projects page. !5797 + - Fix privilege escalation via project export. + - Require administrator privileges to perform a project import. v 8.10.5 - Add a data migration to fix some missing timestamps in the members table. !5670 @@ -337,6 +340,10 @@ v 8.10.0 - Fix migration corrupting import data for old version upgrades - Show tooltip on GitLab export link in new project page +v 8.9.7 + - Upgrade Rails to 4.2.7.1 for security fixes. !5781 + - Require administrator privileges to perform a project import. + v 8.9.6 - Fix importing of events under notes for GitLab projects. !5154 - Fix log statements in import/export. !5129 @@ -602,6 +609,9 @@ v 8.9.0 - Add tooltip to pin/unpin navbar - Add new sub nav style to Wiki and Graphs sub navigation +v 8.8.8 + - Upgrade Rails to 4.2.7.1 for security fixes. !5781 + v 8.8.7 - Fix privilege escalation issue with OAuth external users. - Ensure references to private repos aren't shown to logged-out users. From a3ef844c0a59dd94bf8b8a962a92b6610758d5af Mon Sep 17 00:00:00 2001 From: winniehell Date: Sun, 24 Jul 2016 01:13:13 +0200 Subject: [PATCH 369/669] fix star button icon alignment --- app/views/projects/buttons/_star.html.haml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/views/projects/buttons/_star.html.haml b/app/views/projects/buttons/_star.html.haml index 71cf5582a4c..311583037e5 100644 --- a/app/views/projects/buttons/_star.html.haml +++ b/app/views/projects/buttons/_star.html.haml @@ -1,10 +1,10 @@ - if current_user = link_to toggle_star_namespace_project_path(@project.namespace, @project), { class: 'btn star-btn toggle-star has-tooltip', method: :post, remote: true, title: current_user.starred?(@project) ? 'Unstar project' : 'Star project' } do - if current_user.starred?(@project) - = icon('star fw') + = icon('star') %span.starred Unstar - else - = icon('star-o fw') + = icon('star-o') %span Star %div.count-with-arrow %span.arrow @@ -13,7 +13,7 @@ - else = link_to new_user_session_path, class: 'btn has-tooltip star-btn', title: 'You must sign in to star a project' do - = icon('star fw') + = icon('star') Star %div.count-with-arrow %span.arrow From c4141bac76d4d869054a2c2979af7cf59ed9411f Mon Sep 17 00:00:00 2001 From: winniehell Date: Sun, 24 Jul 2016 01:14:44 +0200 Subject: [PATCH 370/669] fix fork button icon alignment --- CHANGELOG | 1 + app/views/shared/icons/_icon_fork.svg | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 2a7109b3c2b..4289aded1ab 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -42,6 +42,7 @@ v 8.11.0 (unreleased) - Remove unused images (ClemMakesApps) - Get issue and merge request description templates from repositories - Add hover state to todos !5361 (winniehell) + - Fix icon alignment of star and fork buttons !5451 (winniehell) - Limit git rev-list output count to one in forced push check - Show deployment status on merge requests with external URLs - Clean up unused routes (Josef Strzibny) diff --git a/app/views/shared/icons/_icon_fork.svg b/app/views/shared/icons/_icon_fork.svg index a21f8f3a951..fc970e4ce50 100644 --- a/app/views/shared/icons/_icon_fork.svg +++ b/app/views/shared/icons/_icon_fork.svg @@ -1,3 +1,3 @@ - + From 9810c71d9b61983840df61aa662041cffb9c9541 Mon Sep 17 00:00:00 2001 From: winniehell Date: Fri, 5 Aug 2016 00:37:32 +0200 Subject: [PATCH 371/669] add space between icon and button text --- app/assets/stylesheets/framework/buttons.scss | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/assets/stylesheets/framework/buttons.scss b/app/assets/stylesheets/framework/buttons.scss index f1fe1697d30..6c3786b49bb 100644 --- a/app/assets/stylesheets/framework/buttons.scss +++ b/app/assets/stylesheets/framework/buttons.scss @@ -204,6 +204,10 @@ position: relative; top: 2px; } + + svg, .fa { + margin-right: 3px; + } } .btn-lg { From ee7d82285b47e093749cdb895de0d8fc86fbc3d3 Mon Sep 17 00:00:00 2001 From: ernstvn Date: Tue, 16 Aug 2016 16:35:54 -0700 Subject: [PATCH 372/669] remove undefined word Corporation from CCLA --- doc/legal/corporate_contributor_license_agreement.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/legal/corporate_contributor_license_agreement.md b/doc/legal/corporate_contributor_license_agreement.md index edd6c59138f..7f08188bd65 100644 --- a/doc/legal/corporate_contributor_license_agreement.md +++ b/doc/legal/corporate_contributor_license_agreement.md @@ -16,7 +16,7 @@ Subject to the terms and conditions of this Agreement, You hereby grant to GitLa Subject to the terms and conditions of this Agreement, You hereby grant to GitLab B.V. and to recipients of software distributed by GitLab B.V. a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by You that are necessarily infringed by Your Contribution(s) alone or by combination of Your Contribution(s) with the Work to which such Contribution(s) was submitted. If any entity institutes patent litigation against You or any other entity (including a cross-claim or counterclaim in a lawsuit) alleging that your Contribution, or the Work to which you have contributed, constitutes direct or contributory patent infringement, then any patent licenses granted to that entity under this Agreement for that Contribution or Work shall terminate as of the date such litigation is filed. -4. You represent that You are legally entitled to grant the above license. You represent further that each employee of the Corporation is authorized to submit Contributions on behalf of the Corporation, but excluding employees that are designated in writing by You as "Not authorized to submit Contributions on behalf of [name of corporation here]." +4. You represent that You are legally entitled to grant the above license. You represent further that each of Your employees is authorized to submit Contributions on Your behalf, but excluding employees that are designated in writing by You as "Not authorized to submit Contributions on behalf of [name of Your corporation here]." Such designations of exclusion for unauthorized employees are to be submitted via email to legal@gitlab.com. 5. You represent that each of Your Contributions is Your original creation (see section 7 for submissions on behalf of others). @@ -24,6 +24,6 @@ Subject to the terms and conditions of this Agreement, You hereby grant to GitLa 7. Should You wish to submit work that is not Your original creation, You may submit it to GitLab B.V. separately from any Contribution, identifying the complete details of its source and of any license or other restriction (including, but not limited to, related patents, trademarks, and license agreements) of which you are personally aware, and conspicuously marking the work as "Submitted on behalf of a third-party: [named here]". -8. It is your responsibility to notify GitLab B.V. when any change is required to the designation of employees not authorized to submit Contributions on behalf of the Corporation, or to the Corporation's Point of Contact with GitLab B.V.. +8. It is Your responsibility to notify GitLab.com when any change is required to the list of designated employees excluded from submitting Contributions on Your behalf per Section 4. Such notification should be sent via email to legal@gitlab.com. This text is licensed under the [Creative Commons Attribution 3.0 License](https://creativecommons.org/licenses/by/3.0/) and the original source is the Google Open Source Programs Office. From 8d5dc4fa6b0f01dbe46e89105aed5072c60cc102 Mon Sep 17 00:00:00 2001 From: Annabel Dunstone Date: Tue, 16 Aug 2016 19:42:05 -0500 Subject: [PATCH 373/669] Add toggle button to hide graph; set max-height --- app/assets/javascripts/pipeline.js.es6 | 10 ++++ app/assets/stylesheets/pages/pipelines.scss | 43 ++++++++++++++--- app/views/projects/commit/_pipeline.html.haml | 46 ++++++++++--------- 3 files changed, 71 insertions(+), 28 deletions(-) create mode 100644 app/assets/javascripts/pipeline.js.es6 diff --git a/app/assets/javascripts/pipeline.js.es6 b/app/assets/javascripts/pipeline.js.es6 new file mode 100644 index 00000000000..7054199ac89 --- /dev/null +++ b/app/assets/javascripts/pipeline.js.es6 @@ -0,0 +1,10 @@ +function toggleGraph() { + $('.pipeline-graph, .toggle-pipeline-btn').toggleClass('graph-collapsed'); + + const $btnText = $('.toggle-pipeline-btn .btn-text'); + const graphCollapsed = $('.pipeline-graph').hasClass('graph-collapsed'); + + graphCollapsed ? $btnText.text('Expand') : $btnText.text('Hide') +} + +$(document).on('click', '.toggle-pipeline-btn', toggleGraph); diff --git a/app/assets/stylesheets/pages/pipelines.scss b/app/assets/stylesheets/pages/pipelines.scss index ad256e2a728..f35aca193e9 100644 --- a/app/assets/stylesheets/pages/pipelines.scss +++ b/app/assets/stylesheets/pages/pipelines.scss @@ -232,10 +232,35 @@ // Pipeline visualization +.toggle-pipeline-btn { + background-color: $gray-dark; + + .caret { + border-top: none; + border-bottom: 4px solid; + } + + &.graph-collapsed { + background-color: $white-light; + + .caret { + border-bottom: none; + border-top: 4px solid; + } + } +} + .pipeline-graph { width: 100%; overflow: auto; white-space: nowrap; + max-height: 500px; + transition: max-height 0.3s, padding 0.3s; + + &.graph-collapsed { + max-height: 0; + padding: 0 16px; + } } .pipeline-visualization { @@ -315,7 +340,6 @@ right: -20px; border-right: 2px solid $border-color; border-radius: 0 0 50px; - -webkit-border-radius: 0 0 50px; } // Left connecting curves @@ -323,7 +347,6 @@ left: -20px; border-left: 2px solid $border-color; border-radius: 0 0 0 50px; - -webkit-border-radius: 0 0 0 50px; } } @@ -333,11 +356,6 @@ height: 45px; top: -26px; } - &::after { - // border-left: 2px solid $border-color; - border-top-right-radius: -50px; - -webkit-border-top-right-radius: -50px; - } } } @@ -369,3 +387,14 @@ } } } + +.pipeline-actions { + border-bottom: none; +} + +.toggle-pipeline-btn { + + .fa { + color: $dropdown-header-color; + } +} diff --git a/app/views/projects/commit/_pipeline.html.haml b/app/views/projects/commit/_pipeline.html.haml index e2187673da7..eb80aadd524 100644 --- a/app/views/projects/commit/_pipeline.html.haml +++ b/app/views/projects/commit/_pipeline.html.haml @@ -1,25 +1,9 @@ -.row-content-block.build-content.middle-block.pipeline-graph - .pipeline-visualization - %ul.stage-column-list - - pipeline.statuses.stages.each do |stage| - - statuses = pipeline.statuses.where(stage: stage) - - status = statuses.latest.status - %li.stage-column - .stage-name - %a{name: stage} - - if stage - = stage.titleize - .builds-container - %ul - - statuses.each do |build| - %li.build - .build-content - %span{class: "ci-status-link ci-status-icon-#{status}"} - = ci_icon_for_status(status) - = build.name - -.row-content-block.build-content.middle-block.pipeline-graph +.row-content-block.build-content.middle-block.pipeline-actions .pull-right + .btn.btn-grouped.btn-white.toggle-pipeline-btn + %span.btn-text Hide + %span pipeline graph + %span.caret - if can?(current_user, :update_pipeline, pipeline.project) - if pipeline.builds.latest.failed.any?(&:retryable?) = link_to "Retry failed", retry_namespace_project_pipeline_path(pipeline.project.namespace, pipeline.project, pipeline.id), class: 'btn btn-grouped btn-primary', method: :post @@ -43,6 +27,26 @@ in = time_interval_in_words pipeline.duration +.row-content-block.build-content.middle-block.pipeline-graph + .pipeline-visualization + %ul.stage-column-list + - pipeline.statuses.stages.each do |stage| + - statuses = pipeline.statuses.where(stage: stage) + - status = statuses.latest.status + %li.stage-column + .stage-name + %a{name: stage} + - if stage + = stage.titleize + .builds-container + %ul + - statuses.each do |build| + %li.build + .build-content + %span{class: "ci-status-link ci-status-icon-#{status}"} + = ci_icon_for_status(status) + = build.name + - if pipeline.yaml_errors.present? .bs-callout.bs-callout-danger %h4 Found errors in your .gitlab-ci.yml: From b631985ad7a8a85d1350425e6d1cf1cb90c93b5f Mon Sep 17 00:00:00 2001 From: Annabel Dunstone Date: Tue, 16 Aug 2016 19:52:34 -0500 Subject: [PATCH 374/669] Add links to pipeline graph --- app/assets/stylesheets/pages/pipelines.scss | 4 ++++ app/views/projects/commit/_pipeline.html.haml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/app/assets/stylesheets/pages/pipelines.scss b/app/assets/stylesheets/pages/pipelines.scss index f35aca193e9..ce9e3e95d3d 100644 --- a/app/assets/stylesheets/pages/pipelines.scss +++ b/app/assets/stylesheets/pages/pipelines.scss @@ -303,6 +303,10 @@ white-space: nowrap; overflow: hidden; text-overflow: ellipsis; + + a { + color: $layout-link-gray; + } } svg { diff --git a/app/views/projects/commit/_pipeline.html.haml b/app/views/projects/commit/_pipeline.html.haml index eb80aadd524..44250860020 100644 --- a/app/views/projects/commit/_pipeline.html.haml +++ b/app/views/projects/commit/_pipeline.html.haml @@ -45,7 +45,7 @@ .build-content %span{class: "ci-status-link ci-status-icon-#{status}"} = ci_icon_for_status(status) - = build.name + = link_to build.name, namespace_project_build_url(build.project.namespace, build.project, build) - if pipeline.yaml_errors.present? .bs-callout.bs-callout-danger From e5f9fdf90c1d59a07f76919e9d94599b494ac50f Mon Sep 17 00:00:00 2001 From: Annabel Dunstone Date: Tue, 16 Aug 2016 20:34:49 -0500 Subject: [PATCH 375/669] Refactor merge_request-tabs --- app/assets/javascripts/merge_request_tabs.js | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/app/assets/javascripts/merge_request_tabs.js b/app/assets/javascripts/merge_request_tabs.js index a21cdbc8a10..1bba69a255a 100644 --- a/app/assets/javascripts/merge_request_tabs.js +++ b/app/assets/javascripts/merge_request_tabs.js @@ -188,14 +188,12 @@ } return this._get({ url: source + ".json", - success: (function(_this) { - return function(data) { - document.querySelector("div#pipelines").innerHTML = data.html; - gl.utils.localTimeAgo($('.js-timeago', 'div#pipelines')); - _this.pipelinesLoaded = true; - return _this.scrollToElement("#pipelines"); - }; - })(this) + success: function(data) { + $('#pipelines').html(data.html); + gl.utils.localTimeAgo($('.js-timeago', '#pipelines')); + this.pipelinesLoaded = true; + return this.scrollToElement("#pipelines"); + }.bind(this) }); }; From 03386633a42bd56b0b0b31b70eebaaaa33e1494e Mon Sep 17 00:00:00 2001 From: Paco Guzman Date: Fri, 5 Aug 2016 15:29:20 +0200 Subject: [PATCH 376/669] Move to project dropdown with infinite scroll for better performance Use just SQL to check is a user can admin_issue on a project Tradeoff - we duplicate how we check admin_issue in a SQL relation in the Ability class --- CHANGELOG | 1 + app/controllers/autocomplete_controller.rb | 14 +- app/finders/move_to_project_finder.rb | 14 + app/models/project.rb | 2 + app/models/user.rb | 7 + .../autocomplete_controller_spec.rb | 354 +++++++++++------- spec/finders/move_to_project_finder_spec.rb | 75 ++++ spec/models/user_spec.rb | 47 +++ 8 files changed, 371 insertions(+), 143 deletions(-) create mode 100644 app/finders/move_to_project_finder.rb create mode 100644 spec/finders/move_to_project_finder_spec.rb diff --git a/CHANGELOG b/CHANGELOG index e9c8a4895e1..837e9e27aba 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -97,6 +97,7 @@ v 8.11.0 (unreleased) - Add commit stats in commit api. !5517 (dixpac) - Add CI configuration button on project page - Make error pages responsive (Takuya Noguchi) + - The performance of the project dropdown used for moving issues has been improved - Fix skip_repo parameter being ignored when destroying a namespace - Change requests_profiles resource constraint to catch virtually any file - Bump gitlab_git to lazy load compare commits diff --git a/app/controllers/autocomplete_controller.rb b/app/controllers/autocomplete_controller.rb index e1641ba6265..b48668eea87 100644 --- a/app/controllers/autocomplete_controller.rb +++ b/app/controllers/autocomplete_controller.rb @@ -35,19 +35,13 @@ class AutocompleteController < ApplicationController def projects project = Project.find_by_id(params[:project_id]) - - projects = current_user.authorized_projects - projects = projects.search(params[:search]) if params[:search].present? - projects = projects.select do |project| - current_user.can?(:admin_issue, project) - end + projects = projects_finder.execute(project, search: params[:search], offset_id: params[:offset_id]) no_project = { id: 0, name_with_namespace: 'No project', } - projects.unshift(no_project) - projects.delete(project) + projects.unshift(no_project) unless params[:offset_id].present? render json: projects.to_json(only: [:id, :name_with_namespace], methods: :name_with_namespace) end @@ -79,4 +73,8 @@ class AutocompleteController < ApplicationController end end end + + def projects_finder + MoveToProjectFinder.new(current_user) + end end diff --git a/app/finders/move_to_project_finder.rb b/app/finders/move_to_project_finder.rb new file mode 100644 index 00000000000..3334b8556df --- /dev/null +++ b/app/finders/move_to_project_finder.rb @@ -0,0 +1,14 @@ +class MoveToProjectFinder + def initialize(user) + @user = user + end + + def execute(from_project, search: nil, offset_id: nil) + projects = @user.projects_where_can_admin_issues + projects = projects.search(search) if search.present? + projects = projects.excluding_project(from_project) + + # to ask for Project#name_with_namespace + projects.includes(namespace: :owner) + end +end diff --git a/app/models/project.rb b/app/models/project.rb index e0b28160937..eefdae35615 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -197,6 +197,8 @@ class Project < ActiveRecord::Base scope :active, -> { joins(:issues, :notes, :merge_requests).order('issues.created_at, notes.created_at, merge_requests.created_at DESC') } scope :abandoned, -> { where('projects.last_activity_at < ?', 6.months.ago) } + scope :excluding_project, ->(project) { where.not(id: project) } + state_machine :import_status, initial: :none do event :import_start do transition [:none, :finished] => :started diff --git a/app/models/user.rb b/app/models/user.rb index 87a2d999843..48e83ab7e56 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -429,6 +429,13 @@ class User < ActiveRecord::Base owned_groups.select(:id), namespace.id).joins(:namespace) end + # Returns projects which user can admin issues on (for example to move an issue to that project). + # + # This logic is duplicated from `Ability#project_abilities` into a SQL form. + def projects_where_can_admin_issues + authorized_projects(Gitlab::Access::REPORTER).non_archived.where.not(issues_enabled: false) + end + def is_admin? admin end diff --git a/spec/controllers/autocomplete_controller_spec.rb b/spec/controllers/autocomplete_controller_spec.rb index ed0b7f9e240..44128a43362 100644 --- a/spec/controllers/autocomplete_controller_spec.rb +++ b/spec/controllers/autocomplete_controller_spec.rb @@ -2,178 +2,262 @@ require 'spec_helper' describe AutocompleteController do let!(:project) { create(:project) } - let!(:user) { create(:user) } - let!(:user2) { create(:user) } - let!(:non_member) { create(:user) } + let!(:user) { create(:user) } - context 'project members' do - before do - sign_in(user) - project.team << [user, :master] + context 'users and members' do + let!(:user2) { create(:user) } + let!(:non_member) { create(:user) } + + context 'project members' do + before do + sign_in(user) + project.team << [user, :master] + end + + describe 'GET #users with project ID' do + before do + get(:users, project_id: project.id) + end + + let(:body) { JSON.parse(response.body) } + + it { expect(body).to be_kind_of(Array) } + it { expect(body.size).to eq 1 } + it { expect(body.map { |u| u["username"] }).to include(user.username) } + end + + describe 'GET #users with unknown project' do + before do + get(:users, project_id: 'unknown') + end + + it { expect(response).to have_http_status(404) } + end end - describe 'GET #users with project ID' do + context 'group members' do + let(:group) { create(:group) } + before do - get(:users, project_id: project.id) + sign_in(user) + group.add_owner(user) + end + + let(:body) { JSON.parse(response.body) } + + describe 'GET #users with group ID' do + before do + get(:users, group_id: group.id) + end + + it { expect(body).to be_kind_of(Array) } + it { expect(body.size).to eq 1 } + it { expect(body.first["username"]).to eq user.username } + end + + describe 'GET #users with unknown group ID' do + before do + get(:users, group_id: 'unknown') + end + + it { expect(response).to have_http_status(404) } + end + end + + context 'non-member login for public project' do + let!(:project) { create(:project, :public) } + + before do + sign_in(non_member) + project.team << [user, :master] + end + + let(:body) { JSON.parse(response.body) } + + describe 'GET #users with project ID' do + before do + get(:users, project_id: project.id, current_user: true) + end + + it { expect(body).to be_kind_of(Array) } + it { expect(body.size).to eq 2 } + it { expect(body.map { |u| u['username'] }).to match_array([user.username, non_member.username]) } + end + end + + context 'all users' do + before do + sign_in(user) + get(:users) end let(:body) { JSON.parse(response.body) } it { expect(body).to be_kind_of(Array) } - it { expect(body.size).to eq 1 } - it { expect(body.map { |u| u["username"] }).to include(user.username) } + it { expect(body.size).to eq User.count } end - describe 'GET #users with unknown project' do - before do - get(:users, project_id: 'unknown') + context 'unauthenticated user' do + let(:public_project) { create(:project, :public) } + let(:body) { JSON.parse(response.body) } + + describe 'GET #users with public project' do + before do + public_project.team << [user, :guest] + get(:users, project_id: public_project.id) + end + + it { expect(body).to be_kind_of(Array) } + it { expect(body.size).to eq 1 } end - it { expect(response).to have_http_status(404) } + describe 'GET #users with project' do + before do + get(:users, project_id: project.id) + end + + it { expect(response).to have_http_status(404) } + end + + describe 'GET #users with unknown project' do + before do + get(:users, project_id: 'unknown') + end + + it { expect(response).to have_http_status(404) } + end + + describe 'GET #users with inaccessible group' do + before do + project.team << [user, :guest] + get(:users, group_id: user.namespace.id) + end + + it { expect(response).to have_http_status(404) } + end + + describe 'GET #users with no project' do + before do + get(:users) + end + + it { expect(body).to be_kind_of(Array) } + it { expect(body.size).to eq 0 } + end + end + + context 'author of issuable included' do + before do + sign_in(user) + end + + let(:body) { JSON.parse(response.body) } + + it 'includes the author' do + get(:users, author_id: non_member.id) + + expect(body.first["username"]).to eq non_member.username + end + + it 'rejects non existent user ids' do + get(:users, author_id: 99999) + + expect(body.collect { |u| u['id'] }).not_to include(99999) + end + end + + context 'skip_users parameter included' do + before { sign_in(user) } + + it 'skips the user IDs passed' do + get(:users, skip_users: [user, user2].map(&:id)) + + other_user_ids = [non_member, project.owner, project.creator].map(&:id) + response_user_ids = JSON.parse(response.body).map { |user| user['id'] } + + expect(response_user_ids).to contain_exactly(*other_user_ids) + end end end - context 'group members' do - let(:group) { create(:group) } + context 'projects' do + let(:authorized_project) { create(:project) } + let(:authorized_search_project) { create(:project, name: 'rugged') } before do sign_in(user) - group.add_owner(user) - end - - let(:body) { JSON.parse(response.body) } - - describe 'GET #users with group ID' do - before do - get(:users, group_id: group.id) - end - - it { expect(body).to be_kind_of(Array) } - it { expect(body.size).to eq 1 } - it { expect(body.first["username"]).to eq user.username } - end - - describe 'GET #users with unknown group ID' do - before do - get(:users, group_id: 'unknown') - end - - it { expect(response).to have_http_status(404) } - end - end - - context 'non-member login for public project' do - let!(:project) { create(:project, :public) } - - before do - sign_in(non_member) project.team << [user, :master] end - let(:body) { JSON.parse(response.body) } - - describe 'GET #users with project ID' do + context 'authorized projects' do before do - get(:users, project_id: project.id, current_user: true) + authorized_project.team << [user, :master] end - it { expect(body).to be_kind_of(Array) } - it { expect(body.size).to eq 2 } - it { expect(body.map { |u| u['username'] }).to match_array([user.username, non_member.username]) } - end - end + describe 'GET #projects with project ID' do + before do + get(:projects, project_id: project.id) + end - context 'all users' do - before do - sign_in(user) - get(:users) + let(:body) { JSON.parse(response.body) } + + it do + expect(body).to be_kind_of(Array) + expect(body.size).to eq 2 + + expect(body.first['id']).to eq 0 + expect(body.first['name_with_namespace']).to eq 'No project' + + expect(body.last['id']).to eq authorized_project.id + expect(body.last['name_with_namespace']).to eq authorized_project.name_with_namespace + end + end end - let(:body) { JSON.parse(response.body) } - - it { expect(body).to be_kind_of(Array) } - it { expect(body.size).to eq User.count } - end - - context 'unauthenticated user' do - let(:public_project) { create(:project, :public) } - let(:body) { JSON.parse(response.body) } - - describe 'GET #users with public project' do + context 'authorized projects and search' do before do - public_project.team << [user, :guest] - get(:users, project_id: public_project.id) + authorized_project.team << [user, :master] + authorized_search_project.team << [user, :master] end - it { expect(body).to be_kind_of(Array) } - it { expect(body.size).to eq 1 } + describe 'GET #projects with project ID and search' do + before do + get(:projects, project_id: project.id, search: 'rugged') + end + + let(:body) { JSON.parse(response.body) } + + it do + expect(body).to be_kind_of(Array) + expect(body.size).to eq 2 + + expect(body.last['id']).to eq authorized_search_project.id + expect(body.last['name_with_namespace']).to eq authorized_search_project.name_with_namespace + end + end end - describe 'GET #users with project' do - before do - get(:users, project_id: project.id) + context 'authorized projects without admin_issue ability' do + before(:each) do + authorized_project.team << [user, :guest] + + expect(user.can?(:admin_issue, authorized_project)).to eq(false) end - it { expect(response).to have_http_status(404) } - end + describe 'GET #projects with project ID' do + before do + get(:projects, project_id: project.id) + end - describe 'GET #users with unknown project' do - before do - get(:users, project_id: 'unknown') + let(:body) { JSON.parse(response.body) } + + it do + expect(body).to be_kind_of(Array) + expect(body.size).to eq 1 # 'No project' + + expect(body.first['id']).to eq 0 + end end - - it { expect(response).to have_http_status(404) } - end - - describe 'GET #users with inaccessible group' do - before do - project.team << [user, :guest] - get(:users, group_id: user.namespace.id) - end - - it { expect(response).to have_http_status(404) } - end - - describe 'GET #users with no project' do - before do - get(:users) - end - - it { expect(body).to be_kind_of(Array) } - it { expect(body.size).to eq 0 } - end - end - - context 'author of issuable included' do - before do - sign_in(user) - end - - let(:body) { JSON.parse(response.body) } - - it 'includes the author' do - get(:users, author_id: non_member.id) - - expect(body.first["username"]).to eq non_member.username - end - - it 'rejects non existent user ids' do - get(:users, author_id: 99999) - - expect(body.collect { |u| u['id'] }).not_to include(99999) - end - end - - context 'skip_users parameter included' do - before { sign_in(user) } - - it 'skips the user IDs passed' do - get(:users, skip_users: [user, user2].map(&:id)) - - other_user_ids = [non_member, project.owner, project.creator].map(&:id) - response_user_ids = JSON.parse(response.body).map { |user| user['id'] } - - expect(response_user_ids).to contain_exactly(*other_user_ids) end end end diff --git a/spec/finders/move_to_project_finder_spec.rb b/spec/finders/move_to_project_finder_spec.rb new file mode 100644 index 00000000000..4f3304f7b6d --- /dev/null +++ b/spec/finders/move_to_project_finder_spec.rb @@ -0,0 +1,75 @@ +require 'spec_helper' + +describe MoveToProjectFinder do + let(:user) { create(:user) } + let(:project) { create(:project) } + + let(:no_access_project) { create(:project) } + let(:guest_project) { create(:project) } + let(:reporter_project) { create(:project) } + let(:developer_project) { create(:project) } + let(:master_project) { create(:project) } + + subject { described_class.new(user) } + + describe '#execute' do + context 'filter' do + it 'does not return projects under Gitlab::Access::REPORTER' do + guest_project.team << [user, :guest] + + expect(subject.execute(project)).to be_empty + end + + it 'returns projects equal or above Gitlab::Access::REPORTER ordered by id in descending order' do + reporter_project.team << [user, :reporter] + developer_project.team << [user, :developer] + master_project.team << [user, :master] + + expect(subject.execute(project).to_a).to eq([master_project, developer_project, reporter_project]) + end + + it 'does not include the source project' do + project.team << [user, :reporter] + + expect(subject.execute(project).to_a).to be_empty + end + + it 'does not return archived projects' do + reporter_project.team << [user, :reporter] + reporter_project.update_attributes(archived: true) + other_reporter_project = create(:project) + other_reporter_project.team << [user, :reporter] + + expect(subject.execute(project).to_a).to eq([other_reporter_project]) + end + + it 'does not return projects for which issues are disabled' do + reporter_project.team << [user, :reporter] + reporter_project.update_attributes(issues_enabled: false) + other_reporter_project = create(:project) + other_reporter_project.team << [user, :reporter] + + expect(subject.execute(project).to_a).to eq([other_reporter_project]) + end + end + + context 'search' do + it 'uses Project#search' do + expect(user).to receive_message_chain(:projects_where_can_admin_issues, :search) { Project.all } + + subject.execute(project, search: 'wadus') + end + + it 'returns projects matching a search query' do + foo_project = create(:project) + foo_project.team << [user, :master] + + wadus_project = create(:project, name: 'wadus') + wadus_project.team << [user, :master] + + expect(subject.execute(project).to_a).to eq([wadus_project, foo_project]) + expect(subject.execute(project, search: 'wadus').to_a).to eq([wadus_project]) + end + end + end +end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 54505f6b822..51e4780e2b1 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -957,6 +957,53 @@ describe User, models: true do end end + describe '#projects_where_can_admin_issues' do + let(:user) { create(:user) } + + it 'includes projects for which the user access level is above or equal to reporter' do + create(:project) + reporter_project = create(:project) + developer_project = create(:project) + master_project = create(:project) + + reporter_project.team << [user, :reporter] + developer_project.team << [user, :developer] + master_project.team << [user, :master] + + expect(user.projects_where_can_admin_issues.to_a).to eq([master_project, developer_project, reporter_project]) + expect(user.can?(:admin_issue, master_project)).to eq(true) + expect(user.can?(:admin_issue, developer_project)).to eq(true) + expect(user.can?(:admin_issue, reporter_project)).to eq(true) + end + + it 'does not include for which the user access level is below reporter' do + project = create(:project) + guest_project = create(:project) + + guest_project.team << [user, :guest] + + expect(user.projects_where_can_admin_issues.to_a).to be_empty + expect(user.can?(:admin_issue, guest_project)).to eq(false) + expect(user.can?(:admin_issue, project)).to eq(false) + end + + it 'does not include archived projects' do + project = create(:project) + project.update_attributes(archived: true) + + expect(user.projects_where_can_admin_issues.to_a).to be_empty + expect(user.can?(:admin_issue, project)).to eq(false) + end + + it 'does not include projects for which issues are disabled' do + project = create(:project) + project.update_attributes(issues_enabled: false) + + expect(user.projects_where_can_admin_issues.to_a).to be_empty + expect(user.can?(:admin_issue, project)).to eq(false) + end + end + describe '#ci_authorized_runners' do let(:user) { create(:user) } let(:runner) { create(:ci_runner) } From d345591fc80e2181acfa71e9eeec99875c523767 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Tue, 16 Aug 2016 16:18:48 +0200 Subject: [PATCH 377/669] Tracking of custom events GitLab Performance Monitoring is now able to track custom events not directly related to application performance. These events include the number of tags pushed, repositories created, builds registered, etc. The use of these events is to get a better overview of how a GitLab instance is used and how that may affect performance. For example, a large number of Git pushes may have a negative impact on the underlying storage engine. Events are stored in the "events" measurement and are not prefixed with "rails_" or "sidekiq_", this makes it easier to query events with the same name triggered from different parts of the application. All events being stored in the same measurement also makes it easier to downsample data. Currently the following events are tracked: * Creating repositories * Removing repositories * Changing the default branch of a repository * Pushing a new tag * Removing an existing tag * Pushing a commit (along with the branch being pushed to) * Pushing a new branch * Removing an existing branch * Importing a repository (along with the URL we're importing) * Forking a repository (along with the source/target path) * CI builds registered (and when no build could be found) * CI builds being updated * Rails and Sidekiq exceptions Fixes gitlab-org/gitlab-ce#13720 --- CHANGELOG | 1 + app/models/repository.rb | 20 +++++++ app/workers/repository_fork_worker.rb | 4 ++ app/workers/repository_import_worker.rb | 4 ++ doc/monitoring/performance/influxdb_schema.md | 9 +++ lib/ci/api/builds.rb | 8 +++ lib/gitlab/metrics.rb | 9 +++ lib/gitlab/metrics/metric.rb | 9 ++- lib/gitlab/metrics/rack_middleware.rb | 4 ++ lib/gitlab/metrics/sidekiq_middleware.rb | 4 ++ lib/gitlab/metrics/transaction.rb | 21 ++++++- spec/lib/gitlab/metrics/metric_spec.rb | 18 ++++++ .../gitlab/metrics/rack_middleware_spec.rb | 9 +++ .../gitlab/metrics/sidekiq_middleware_spec.rb | 24 +++++++- spec/lib/gitlab/metrics/transaction_spec.rb | 57 +++++++++++++++++++ spec/lib/gitlab/metrics_spec.rb | 24 ++++++++ 16 files changed, 219 insertions(+), 6 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 837e9e27aba..4986ffd7351 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -16,6 +16,7 @@ v 8.11.0 (unreleased) - API: List access requests, request access, approve, and deny access requests to a project or a group. !4833 - Use long options for curl examples in documentation !5703 (winniehell) - Remove magic comments (`# encoding: UTF-8`) from Ruby files. !5456 (winniehell) + - GitLab Performance Monitoring can now track custom events such as the number of tags pushed to a repository - Add support for relative links starting with ./ or / to RelativeLinkFilter (winniehell) - Ignore URLs starting with // in Markdown links !5677 (winniehell) - Fix CI status icon link underline (ClemMakesApps) diff --git a/app/models/repository.rb b/app/models/repository.rb index e56bac509a4..916843dabdd 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -391,6 +391,8 @@ class Repository expire_exists_cache expire_root_ref_cache expire_emptiness_caches + + repository_event(:create_repository) end # Runs code just before a repository is deleted. @@ -407,6 +409,8 @@ class Repository expire_root_ref_cache expire_emptiness_caches expire_exists_cache + + repository_event(:remove_repository) end # Runs code just before the HEAD of a repository is changed. @@ -414,6 +418,8 @@ class Repository # Cached divergent commit counts are based on repository head expire_branch_cache expire_root_ref_cache + + repository_event(:change_default_branch) end # Runs code before pushing (= creating or removing) a tag. @@ -421,12 +427,16 @@ class Repository expire_cache expire_tags_cache expire_tag_count_cache + + repository_event(:push_tag) end # Runs code before removing a tag. def before_remove_tag expire_tags_cache expire_tag_count_cache + + repository_event(:remove_tag) end def before_import @@ -443,6 +453,8 @@ class Repository # Runs code after a new commit has been pushed. def after_push_commit(branch_name, revision) expire_cache(branch_name, revision) + + repository_event(:push_commit, branch: branch_name) end # Runs code after a new branch has been created. @@ -450,11 +462,15 @@ class Repository expire_branches_cache expire_has_visible_content_cache expire_branch_count_cache + + repository_event(:push_branch) end # Runs code before removing an existing branch. def before_remove_branch expire_branches_cache + + repository_event(:remove_branch) end # Runs code after an existing branch has been removed. @@ -1059,4 +1075,8 @@ class Repository def keep_around_ref_name(sha) "refs/keep-around/#{sha}" end + + def repository_event(event, tags = {}) + Gitlab::Metrics.add_event(event, { path: path_with_namespace }.merge(tags)) + end end diff --git a/app/workers/repository_fork_worker.rb b/app/workers/repository_fork_worker.rb index d69d6037053..61ed1c38ac4 100644 --- a/app/workers/repository_fork_worker.rb +++ b/app/workers/repository_fork_worker.rb @@ -5,6 +5,10 @@ class RepositoryForkWorker sidekiq_options queue: :gitlab_shell def perform(project_id, forked_from_repository_storage_path, source_path, target_path) + Gitlab::Metrics.add_event(:fork_repository, + source_path: source_path, + target_path: target_path) + project = Project.find_by_id(project_id) unless project.present? diff --git a/app/workers/repository_import_worker.rb b/app/workers/repository_import_worker.rb index 7d819fe78f8..e6701078f71 100644 --- a/app/workers/repository_import_worker.rb +++ b/app/workers/repository_import_worker.rb @@ -10,6 +10,10 @@ class RepositoryImportWorker @project = Project.find(project_id) @current_user = @project.creator + Gitlab::Metrics.add_event(:import_repository, + import_url: @project.import_url, + path: @project.path_with_namespace) + result = Projects::ImportService.new(project, current_user).execute if result[:status] == :error diff --git a/doc/monitoring/performance/influxdb_schema.md b/doc/monitoring/performance/influxdb_schema.md index 41861860b6d..eff0e29f58d 100644 --- a/doc/monitoring/performance/influxdb_schema.md +++ b/doc/monitoring/performance/influxdb_schema.md @@ -9,6 +9,7 @@ The following measurements are currently stored in InfluxDB: - `PROCESS_object_counts` - `PROCESS_transactions` - `PROCESS_views` +- `events` Here, `PROCESS` is replaced with either `rails` or `sidekiq` depending on the process type. In all series, any form of duration is stored in milliseconds. @@ -78,6 +79,14 @@ following value fields are available: The `action` tag contains the action name of the transaction that rendered the view. +## events + +This measurement is used to store generic events such as the number of Git +pushes, Emails sent, etc. Each point in this measurement has a single value +field called `count`. The value of this field is simply set to `1`. Each point +also has at least one tag: `event`. This tag's value is set to the event name. +Depending on the event type additional tags may be available as well. + --- Read more on: diff --git a/lib/ci/api/builds.rb b/lib/ci/api/builds.rb index 260ac81f5fa..9f3b582a263 100644 --- a/lib/ci/api/builds.rb +++ b/lib/ci/api/builds.rb @@ -20,8 +20,13 @@ module Ci build = Ci::RegisterBuildService.new.execute(current_runner) if build + Gitlab::Metrics.add_event(:build_found, + project: build.project.path_with_namespace) + present build, with: Entities::BuildDetails else + Gitlab::Metrics.add_event(:build_not_found) + not_found! end end @@ -42,6 +47,9 @@ module Ci build.update_attributes(trace: params[:trace]) if params[:trace] + Gitlab::Metrics.add_event(:update_build, + project: build.project.path_with_namespace) + case params[:state].to_s when 'success' build.success diff --git a/lib/gitlab/metrics.rb b/lib/gitlab/metrics.rb index 41fcd971c22..3d1ba33ec68 100644 --- a/lib/gitlab/metrics.rb +++ b/lib/gitlab/metrics.rb @@ -124,6 +124,15 @@ module Gitlab trans.action = action if trans end + # Tracks an event. + # + # See `Gitlab::Metrics::Transaction#add_event` for more details. + def self.add_event(*args) + trans = current_transaction + + trans.add_event(*args) if trans + end + # Returns the prefix to use for the name of a series. def self.series_prefix @series_prefix ||= Sidekiq.server? ? 'sidekiq_' : 'rails_' diff --git a/lib/gitlab/metrics/metric.rb b/lib/gitlab/metrics/metric.rb index f23d67e1e38..bd0afe53c51 100644 --- a/lib/gitlab/metrics/metric.rb +++ b/lib/gitlab/metrics/metric.rb @@ -4,15 +4,20 @@ module Gitlab class Metric JITTER_RANGE = 0.000001..0.001 - attr_reader :series, :values, :tags + attr_reader :series, :values, :tags, :type # series - The name of the series (as a String) to store the metric in. # values - A Hash containing the values to store. # tags - A Hash containing extra tags to add to the metrics. - def initialize(series, values, tags = {}) + def initialize(series, values, tags = {}, type = :metric) @values = values @series = series @tags = tags + @type = type + end + + def event? + type == :event end # Returns a Hash in a format that can be directly written to InfluxDB. diff --git a/lib/gitlab/metrics/rack_middleware.rb b/lib/gitlab/metrics/rack_middleware.rb index e61670f491c..b4493bf44d2 100644 --- a/lib/gitlab/metrics/rack_middleware.rb +++ b/lib/gitlab/metrics/rack_middleware.rb @@ -17,6 +17,10 @@ module Gitlab begin retval = trans.run { @app.call(env) } + rescue Exception => error # rubocop: disable Lint/RescueException + trans.add_event(:rails_exception) + + raise error # Even in the event of an error we want to submit any metrics we # might've gathered up to this point. ensure diff --git a/lib/gitlab/metrics/sidekiq_middleware.rb b/lib/gitlab/metrics/sidekiq_middleware.rb index a1240fd33ee..f9dd8e41912 100644 --- a/lib/gitlab/metrics/sidekiq_middleware.rb +++ b/lib/gitlab/metrics/sidekiq_middleware.rb @@ -11,6 +11,10 @@ module Gitlab # Old gitlad-shell messages don't provide enqueued_at/created_at attributes trans.set(:sidekiq_queue_duration, Time.now.to_f - (message['enqueued_at'] || message['created_at'] || 0)) trans.run { yield } + rescue Exception => error # rubocop: disable Lint/RescueException + trans.add_event(:sidekiq_exception) + + raise error ensure trans.finish end diff --git a/lib/gitlab/metrics/transaction.rb b/lib/gitlab/metrics/transaction.rb index 968f3218950..7bc16181be6 100644 --- a/lib/gitlab/metrics/transaction.rb +++ b/lib/gitlab/metrics/transaction.rb @@ -4,7 +4,10 @@ module Gitlab class Transaction THREAD_KEY = :_gitlab_metrics_transaction - attr_reader :tags, :values, :methods + # The series to store events (e.g. Git pushes) in. + EVENT_SERIES = 'events' + + attr_reader :tags, :values, :method, :metrics attr_accessor :action @@ -55,6 +58,20 @@ module Gitlab @metrics << Metric.new("#{Metrics.series_prefix}#{series}", values, tags) end + # Tracks a business level event + # + # Business level events including events such as Git pushes, Emails being + # sent, etc. + # + # event_name - The name of the event (e.g. "git_push"). + # tags - A set of tags to attach to the event. + def add_event(event_name, tags = {}) + @metrics << Metric.new(EVENT_SERIES, + { count: 1 }, + { event: event_name }.merge(tags), + :event) + end + # Returns a MethodCall object for the given name. def method_call_for(name) unless method = @methods[name] @@ -101,7 +118,7 @@ module Gitlab submit_hashes = submit.map do |metric| hash = metric.to_hash - hash[:tags][:action] ||= @action if @action + hash[:tags][:action] ||= @action if @action && !metric.event? hash end diff --git a/spec/lib/gitlab/metrics/metric_spec.rb b/spec/lib/gitlab/metrics/metric_spec.rb index f718d536130..f26fca52c50 100644 --- a/spec/lib/gitlab/metrics/metric_spec.rb +++ b/spec/lib/gitlab/metrics/metric_spec.rb @@ -23,6 +23,24 @@ describe Gitlab::Metrics::Metric do it { is_expected.to eq({ host: 'localtoast' }) } end + describe '#type' do + subject { metric.type } + + it { is_expected.to eq(:metric) } + end + + describe '#event?' do + it 'returns false for a regular metric' do + expect(metric.event?).to eq(false) + end + + it 'returns true for an event metric' do + expect(metric).to receive(:type).and_return(:event) + + expect(metric.event?).to eq(true) + end + end + describe '#to_hash' do it 'returns a Hash' do expect(metric.to_hash).to be_an_instance_of(Hash) diff --git a/spec/lib/gitlab/metrics/rack_middleware_spec.rb b/spec/lib/gitlab/metrics/rack_middleware_spec.rb index f264ed64029..a30cb2a5e38 100644 --- a/spec/lib/gitlab/metrics/rack_middleware_spec.rb +++ b/spec/lib/gitlab/metrics/rack_middleware_spec.rb @@ -45,6 +45,15 @@ describe Gitlab::Metrics::RackMiddleware do middleware.call(env) end + + it 'tracks any raised exceptions' do + expect(app).to receive(:call).with(env).and_raise(RuntimeError) + + expect_any_instance_of(Gitlab::Metrics::Transaction). + to receive(:add_event).with(:rails_exception) + + expect { middleware.call(env) }.to raise_error(RuntimeError) + end end describe '#transaction_from_env' do diff --git a/spec/lib/gitlab/metrics/sidekiq_middleware_spec.rb b/spec/lib/gitlab/metrics/sidekiq_middleware_spec.rb index 4d2aa03e722..acaba785606 100644 --- a/spec/lib/gitlab/metrics/sidekiq_middleware_spec.rb +++ b/spec/lib/gitlab/metrics/sidekiq_middleware_spec.rb @@ -12,7 +12,9 @@ describe Gitlab::Metrics::SidekiqMiddleware do with('TestWorker#perform'). and_call_original - expect_any_instance_of(Gitlab::Metrics::Transaction).to receive(:set).with(:sidekiq_queue_duration, instance_of(Float)) + expect_any_instance_of(Gitlab::Metrics::Transaction).to receive(:set). + with(:sidekiq_queue_duration, instance_of(Float)) + expect_any_instance_of(Gitlab::Metrics::Transaction).to receive(:finish) middleware.call(worker, message, :test) { nil } @@ -25,10 +27,28 @@ describe Gitlab::Metrics::SidekiqMiddleware do with('TestWorker#perform'). and_call_original - expect_any_instance_of(Gitlab::Metrics::Transaction).to receive(:set).with(:sidekiq_queue_duration, instance_of(Float)) + expect_any_instance_of(Gitlab::Metrics::Transaction).to receive(:set). + with(:sidekiq_queue_duration, instance_of(Float)) + expect_any_instance_of(Gitlab::Metrics::Transaction).to receive(:finish) middleware.call(worker, {}, :test) { nil } end + + it 'tracks any raised exceptions' do + worker = double(:worker, class: double(:class, name: 'TestWorker')) + + expect_any_instance_of(Gitlab::Metrics::Transaction). + to receive(:run).and_raise(RuntimeError) + + expect_any_instance_of(Gitlab::Metrics::Transaction). + to receive(:add_event).with(:sidekiq_exception) + + expect_any_instance_of(Gitlab::Metrics::Transaction). + to receive(:finish) + + expect { middleware.call(worker, message, :test) }. + to raise_error(RuntimeError) + end end end diff --git a/spec/lib/gitlab/metrics/transaction_spec.rb b/spec/lib/gitlab/metrics/transaction_spec.rb index f1a191d9410..3887c04c832 100644 --- a/spec/lib/gitlab/metrics/transaction_spec.rb +++ b/spec/lib/gitlab/metrics/transaction_spec.rb @@ -142,5 +142,62 @@ describe Gitlab::Metrics::Transaction do transaction.submit end + + it 'does not add an action tag for events' do + transaction.action = 'Foo#bar' + transaction.add_event(:meow) + + hash = { + series: 'events', + tags: { event: :meow }, + values: { count: 1 }, + timestamp: an_instance_of(Fixnum) + } + + expect(Gitlab::Metrics).to receive(:submit_metrics). + with([hash]) + + transaction.submit + end + end + + describe '#add_event' do + it 'adds a metric' do + transaction.add_event(:meow) + + expect(transaction.metrics[0]).to be_an_instance_of(Gitlab::Metrics::Metric) + end + + it "does not prefix the metric's series name" do + transaction.add_event(:meow) + + metric = transaction.metrics[0] + + expect(metric.series).to eq(described_class::EVENT_SERIES) + end + + it 'tracks a counter for every event' do + transaction.add_event(:meow) + + metric = transaction.metrics[0] + + expect(metric.values).to eq(count: 1) + end + + it 'tracks the event name' do + transaction.add_event(:meow) + + metric = transaction.metrics[0] + + expect(metric.tags).to eq(event: :meow) + end + + it 'allows tracking of custom tags' do + transaction.add_event(:meow, animal: 'cat') + + metric = transaction.metrics[0] + + expect(metric.tags).to eq(event: :meow, animal: 'cat') + end end end diff --git a/spec/lib/gitlab/metrics_spec.rb b/spec/lib/gitlab/metrics_spec.rb index 84f9475a0f8..ab6e311b1e8 100644 --- a/spec/lib/gitlab/metrics_spec.rb +++ b/spec/lib/gitlab/metrics_spec.rb @@ -153,4 +153,28 @@ describe Gitlab::Metrics do expect(described_class.series_prefix).to be_an_instance_of(String) end end + + describe '.add_event' do + context 'without a transaction' do + it 'does nothing' do + expect_any_instance_of(Gitlab::Metrics::Transaction). + not_to receive(:add_event) + + Gitlab::Metrics.add_event(:meow) + end + end + + context 'with a transaction' do + it 'adds an event' do + transaction = Gitlab::Metrics::Transaction.new + + expect(transaction).to receive(:add_event).with(:meow) + + expect(Gitlab::Metrics).to receive(:current_transaction). + and_return(transaction) + + Gitlab::Metrics.add_event(:meow) + end + end + end end From 2797cfbf604be698f5b0aaf7178a9aad78d2805b Mon Sep 17 00:00:00 2001 From: Nick Thomas Date: Wed, 17 Aug 2016 09:46:13 +0100 Subject: [PATCH 378/669] Fix a rubocop violation --- spec/services/issues/update_service_spec.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/spec/services/issues/update_service_spec.rb b/spec/services/issues/update_service_spec.rb index d36937b6c59..0313f424463 100644 --- a/spec/services/issues/update_service_spec.rb +++ b/spec/services/issues/update_service_spec.rb @@ -324,6 +324,5 @@ describe Issues::UpdateService, services: true do let(:mentionable) { issue } include_examples 'updating mentions', Issues::UpdateService end - end end From fee7992c08c434940f0722886dc96f249a8e7fbf Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Wed, 17 Aug 2016 09:46:34 +0100 Subject: [PATCH 379/669] Fix pipelines visualisation rendering --- app/models/ci/build.rb | 2 +- app/models/ci/pipeline.rb | 4 ++++ app/views/projects/commit/_pipeline.html.haml | 16 ++++++++++------ 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index 08f396210c9..b42977f9ebd 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -102,7 +102,7 @@ module Ci end def playable? - project.builds_enabled? && commands.present? && manual? + project.builds_enabled? && commands.present? && manual? && skipped? end def play(current_user = nil) diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb index bce6a992af6..caf4d25029f 100644 --- a/app/models/ci/pipeline.rb +++ b/app/models/ci/pipeline.rb @@ -34,6 +34,10 @@ module Ci CommitStatus.where(pipeline: pluck(:id)).stages end + def stages + statuses.order(:stage_idx).latest.group_by(&:stage) + end + def project_id project.id end diff --git a/app/views/projects/commit/_pipeline.html.haml b/app/views/projects/commit/_pipeline.html.haml index 0c006656d1d..27501d89dc5 100644 --- a/app/views/projects/commit/_pipeline.html.haml +++ b/app/views/projects/commit/_pipeline.html.haml @@ -1,9 +1,8 @@ .row-content-block.build-content.middle-block.pipeline-graph .pipeline-visualization %ul.stage-column-list - - pipeline.statuses.stages.each do |stage| - - statuses = pipeline.statuses.where(stage: stage) - - status = statuses.latest.status + - stages = pipeline.statuses.latest.order(:stage_idx).group_by(&:stage) + - stages.each do |stage, builds| %li.stage-column .stage-name %a{name: stage} @@ -11,11 +10,16 @@ = stage.titleize .builds-container %ul - - statuses.each do |build| + - builds.each do |build| %li.build .build-content - %span{class: "ci-status-link ci-status-icon-#{status}"} - = ci_icon_for_status(status) + %span{class: "ci-status-link ci-status-icon-#{build.status}"} + - if build.try(:playable?) + = link_to play_namespace_project_build_path(build.project.namespace, build.project, build, return_to: request.original_url), method: :post, title: 'Play' do + = icon('play') + - else + = link_to namespace_project_build_url(build.project.namespace, build.project, build) do + = ci_icon_for_status(build.status) = build.name .row-content-block.build-content.middle-block.pipeline-graph From f52f62d7aec168b3b8c291cdb81f64501bd80e5a Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Tue, 16 Aug 2016 16:18:44 +0200 Subject: [PATCH 380/669] Update fixtures to make development testing easier --- db/fixtures/development/14_builds.rb | 32 ++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/db/fixtures/development/14_builds.rb b/db/fixtures/development/14_builds.rb index e65abe4ef77..3734c861078 100644 --- a/db/fixtures/development/14_builds.rb +++ b/db/fixtures/development/14_builds.rb @@ -28,24 +28,44 @@ class Gitlab::Seeder::Builds build_create!(pipeline, name: 'production', stage: 'deploy', environment: 'production', when: 'manual', status: :success) commit_status_create!(pipeline, name: 'jenkins', status: :success) - print '.' rescue ActiveRecord::RecordInvalid print 'F' + ensure + pipeline.build_updated end end end def pipelines - commits = @project.repository.commits('master', limit: 5) - commits_sha = commits.map { |commit| commit.raw.id } - commits_sha.map do |sha| - @project.ensure_pipeline(sha, 'master') - end + master_pipelines + merge_request_pipelines + end + + def master_pipelines + create_pipelines_for(@project, 'master') rescue [] end + def merge_request_pipelines + @project.merge_requests.last(5).map do |merge_request| + create_pipelines(merge_request.source_project, merge_request.source_branch, merge_request.commits.last(5)) + end.flatten + rescue + [] + end + + def create_pipelines_for(project, ref) + commits = project.repository.commits(ref, limit: 5) + create_pipelines(project, ref, commits) + end + + def create_pipelines(project, ref, commits) + commits.map do |commit| + project.pipelines.create(sha: commit.id, ref: ref) + end + end + def build_create!(pipeline, opts = {}) attributes = build_attributes_for(pipeline, opts) build = Ci::Build.create!(attributes) From 88a0c984fc0bdbe0951b02c4e1d4b749dce88a24 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Wed, 17 Aug 2016 11:49:13 +0200 Subject: [PATCH 381/669] Fixed downtime check label colouring The colours were incorrect: offline was green and online was red, instead of the opposite. --- lib/gitlab/downtime_check/message.rb | 4 ++-- spec/lib/gitlab/downtime_check/message_spec.rb | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/gitlab/downtime_check/message.rb b/lib/gitlab/downtime_check/message.rb index 4446e921e0d..fd85f087c03 100644 --- a/lib/gitlab/downtime_check/message.rb +++ b/lib/gitlab/downtime_check/message.rb @@ -3,8 +3,8 @@ module Gitlab class Message attr_reader :path, :offline, :reason - OFFLINE = "\e[32moffline\e[0m" - ONLINE = "\e[31monline\e[0m" + OFFLINE = "\e[31moffline\e[0m" + ONLINE = "\e[32monline\e[0m" # path - The file path of the migration. # offline - When set to `true` the migration will require downtime. diff --git a/spec/lib/gitlab/downtime_check/message_spec.rb b/spec/lib/gitlab/downtime_check/message_spec.rb index 93094cda776..d467d2cbd18 100644 --- a/spec/lib/gitlab/downtime_check/message_spec.rb +++ b/spec/lib/gitlab/downtime_check/message_spec.rb @@ -5,13 +5,13 @@ describe Gitlab::DowntimeCheck::Message do it 'returns an ANSI formatted String for an offline migration' do message = described_class.new('foo.rb', true, 'hello') - expect(message.to_s).to eq("[\e[32moffline\e[0m]: foo.rb: hello") + expect(message.to_s).to eq("[\e[31moffline\e[0m]: foo.rb: hello") end it 'returns an ANSI formatted String for an online migration' do message = described_class.new('foo.rb') - expect(message.to_s).to eq("[\e[31monline\e[0m]: foo.rb") + expect(message.to_s).to eq("[\e[32monline\e[0m]: foo.rb") end end end From 7cb76ce1c65e9f0b307cc092a1140a744eaa8277 Mon Sep 17 00:00:00 2001 From: Sean McGivern Date: Wed, 17 Aug 2016 11:15:05 +0100 Subject: [PATCH 382/669] Add workaround for JS error in spec These JS errors are only thrown in PhantomJS, and enough of the page is rendered properly that this spec passes. We should remove this in future. --- spec/features/merge_requests/conflicts_spec.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/spec/features/merge_requests/conflicts_spec.rb b/spec/features/merge_requests/conflicts_spec.rb index be27a6ff3fc..930c36ade2b 100644 --- a/spec/features/merge_requests/conflicts_spec.rb +++ b/spec/features/merge_requests/conflicts_spec.rb @@ -30,7 +30,11 @@ feature 'Merge request conflict resolution', js: true, feature: true do before { click_link('conflicts', href: /\/conflicts\Z/) } it 'shows the conflicts' do - expect(find('#conflicts')).to have_content('popen.rb') + begin + expect(find('#conflicts')).to have_content('popen.rb') + rescue Capybara::Poltergeist::JavascriptError + retry + end end end end From fa0624fc6409d84373f3e06275e936c9e5171b79 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Wed, 17 Aug 2016 12:15:20 +0200 Subject: [PATCH 383/669] Better formatting for downtime check messages This removes excessive whitespace from the messages (e.g. leading whitespace) and ensures the message is more clearly visible. --- lib/gitlab/downtime_check/message.rb | 15 ++++++++++-- .../lib/gitlab/downtime_check/message_spec.rb | 24 ++++++++++++++++++- 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/lib/gitlab/downtime_check/message.rb b/lib/gitlab/downtime_check/message.rb index fd85f087c03..40a4815a9a0 100644 --- a/lib/gitlab/downtime_check/message.rb +++ b/lib/gitlab/downtime_check/message.rb @@ -1,7 +1,7 @@ module Gitlab class DowntimeCheck class Message - attr_reader :path, :offline, :reason + attr_reader :path, :offline OFFLINE = "\e[31moffline\e[0m" ONLINE = "\e[32monline\e[0m" @@ -19,10 +19,21 @@ module Gitlab label = offline ? OFFLINE : ONLINE message = "[#{label}]: #{path}" - message += ": #{reason}" if reason + + if reason? + message += ":\n\n#{reason}\n\n" + end message end + + def reason? + @reason.present? + end + + def reason + @reason.strip.lines.map(&:strip).join("\n") + end end end end diff --git a/spec/lib/gitlab/downtime_check/message_spec.rb b/spec/lib/gitlab/downtime_check/message_spec.rb index d467d2cbd18..a5a398abf78 100644 --- a/spec/lib/gitlab/downtime_check/message_spec.rb +++ b/spec/lib/gitlab/downtime_check/message_spec.rb @@ -5,7 +5,7 @@ describe Gitlab::DowntimeCheck::Message do it 'returns an ANSI formatted String for an offline migration' do message = described_class.new('foo.rb', true, 'hello') - expect(message.to_s).to eq("[\e[31moffline\e[0m]: foo.rb: hello") + expect(message.to_s).to eq("[\e[31moffline\e[0m]: foo.rb:\n\nhello\n\n") end it 'returns an ANSI formatted String for an online migration' do @@ -14,4 +14,26 @@ describe Gitlab::DowntimeCheck::Message do expect(message.to_s).to eq("[\e[32monline\e[0m]: foo.rb") end end + + describe '#reason?' do + it 'returns false when no reason is specified' do + message = described_class.new('foo.rb') + + expect(message.reason?).to eq(false) + end + + it 'returns true when a reason is specified' do + message = described_class.new('foo.rb', true, 'hello') + + expect(message.reason?).to eq(true) + end + end + + describe '#reason' do + it 'strips excessive whitespace from the returned String' do + message = described_class.new('foo.rb', true, " hello\n world\n\n foo") + + expect(message.reason).to eq("hello\nworld\n\nfoo") + end + end end From fd09311da93070546c52e65c0c2af9b8566c56b5 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Wed, 17 Aug 2016 11:18:57 +0100 Subject: [PATCH 384/669] Update fixtures to add a created status to pipeline --- db/fixtures/development/14_builds.rb | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/db/fixtures/development/14_builds.rb b/db/fixtures/development/14_builds.rb index 0d493fa1c3c..069d9dd6226 100644 --- a/db/fixtures/development/14_builds.rb +++ b/db/fixtures/development/14_builds.rb @@ -1,9 +1,8 @@ class Gitlab::Seeder::Builds - STAGES = %w[build notify_build test notify_test deploy notify_deploy] + STAGES = %w[build test deploy notify] BUILDS = [ { name: 'build:linux', stage: 'build', status: :success }, { name: 'build:osx', stage: 'build', status: :success }, - { name: 'slack post build', stage: 'notify_build', status: :success }, { name: 'rspec:linux', stage: 'test', status: :success }, { name: 'rspec:windows', stage: 'test', status: :success }, { name: 'rspec:windows', stage: 'test', status: :success }, @@ -12,9 +11,9 @@ class Gitlab::Seeder::Builds { name: 'spinach:osx', stage: 'test', status: :canceled }, { name: 'cucumber:linux', stage: 'test', status: :running }, { name: 'cucumber:osx', stage: 'test', status: :failed }, - { name: 'slack post test', stage: 'notify_test', status: :success }, { name: 'staging', stage: 'deploy', environment: 'staging', status: :success }, - { name: 'production', stage: 'deploy', environment: 'production', when: 'manual', status: :success }, + { name: 'production', stage: 'deploy', environment: 'production', when: 'manual', status: :skipped }, + { name: 'slack', stage: 'notify', when: 'manual', status: :created }, ] def initialize(project) @@ -25,7 +24,7 @@ class Gitlab::Seeder::Builds pipelines.each do |pipeline| begin BUILDS.each { |opts| build_create!(pipeline, opts) } - commit_status_create!(pipeline, name: 'jenkins', status: :success) + commit_status_create!(pipeline, name: 'jenkins', stage: 'test', status: :success) print '.' rescue ActiveRecord::RecordInvalid print 'F' From 1cd9b3b8a0b1024d043b9344869aceeadb9c84f1 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Wed, 17 Aug 2016 11:21:00 +0100 Subject: [PATCH 385/669] Split pipeline status item for Commit Status and Build --- app/models/ci/pipeline.rb | 4 ++-- .../ci/builds/_build_pipeline.html.haml | 12 ++++++++++++ app/views/projects/commit/_pipeline.html.haml | 17 ++++------------- .../_generic_commit_status_pipeline.html.haml | 9 +++++++++ 4 files changed, 27 insertions(+), 15 deletions(-) create mode 100644 app/views/projects/ci/builds/_build_pipeline.html.haml create mode 100644 app/views/projects/generic_commit_statuses/_generic_commit_status_pipeline.html.haml diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb index d3fc5191721..c360a6ff729 100644 --- a/app/models/ci/pipeline.rb +++ b/app/models/ci/pipeline.rb @@ -78,8 +78,8 @@ module Ci CommitStatus.where(pipeline: pluck(:id)).stages end - def stages - statuses.order(:stage_idx).latest.group_by(&:stage) + def stages_with_latest_statuses + statuses.latest.order(:stage_idx).group_by(&:stage) end def project_id diff --git a/app/views/projects/ci/builds/_build_pipeline.html.haml b/app/views/projects/ci/builds/_build_pipeline.html.haml new file mode 100644 index 00000000000..5149d75e5a2 --- /dev/null +++ b/app/views/projects/ci/builds/_build_pipeline.html.haml @@ -0,0 +1,12 @@ +%li.build + .build-content + %span{class: "ci-status-link ci-status-icon-#{subject.status}"} + - if subject.playable? && can?(current_user, :update_build, @project) + = link_to play_namespace_project_build_path(subject.project.namespace, subject.project, subject, return_to: request.original_url), method: :post, title: 'Play' do + = icon('play') + - elsif can?(current_user, :read_build, @project) && subject.started? + = link_to namespace_project_build_path(subject.project.namespace, subject.project, subject) do + = ci_icon_for_status(subject.status) + - else + = ci_icon_for_status(subject.status) + = subject.name diff --git a/app/views/projects/commit/_pipeline.html.haml b/app/views/projects/commit/_pipeline.html.haml index 5c8f40acfe3..7a7f61e9705 100644 --- a/app/views/projects/commit/_pipeline.html.haml +++ b/app/views/projects/commit/_pipeline.html.haml @@ -1,8 +1,8 @@ .row-content-block.build-content.middle-block.pipeline-graph .pipeline-visualization %ul.stage-column-list - - stages = pipeline.statuses.latest.order(:stage_idx).group_by(&:stage) - - stages.each do |stage, builds| + - stages = pipeline.stages_with_latest_statuses + - stages.each do |stage, statuses| %li.stage-column .stage-name %a{name: stage} @@ -10,17 +10,8 @@ = stage.titleize .builds-container %ul - - builds.each do |build| - %li.build - .build-content - %span{class: "ci-status-link ci-status-icon-#{build.status}"} - - if build.try(:playable?) - = link_to play_namespace_project_build_path(build.project.namespace, build.project, build, return_to: request.original_url), method: :post, title: 'Play' do - = icon('play') - - else - = link_to namespace_project_build_url(build.project.namespace, build.project, build) do - = ci_icon_for_status(build.status) - = build.name + - statuses.each do |status| + = render "projects/#{status.to_partial_path}_pipeline", subject: status .row-content-block.build-content.middle-block.pipeline-graph .pull-right diff --git a/app/views/projects/generic_commit_statuses/_generic_commit_status_pipeline.html.haml b/app/views/projects/generic_commit_statuses/_generic_commit_status_pipeline.html.haml new file mode 100644 index 00000000000..760918b18a3 --- /dev/null +++ b/app/views/projects/generic_commit_statuses/_generic_commit_status_pipeline.html.haml @@ -0,0 +1,9 @@ +%li.build + .build-content + %span{class: "ci-status-link ci-status-icon-#{subject.status}"} + - if subject.target_url + - link_to subject.target_url do + = ci_icon_for_status(subject.status) + - else + = ci_icon_for_status(subject.status) + = subject.name From 49e7070adfcb281938a43aceeb52cc0257601e1d Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Wed, 17 Aug 2016 12:08:45 +0100 Subject: [PATCH 386/669] Add support for Play and Created jobs --- app/helpers/ci_status_helper.rb | 26 ++++++++++++------- .../ci/builds/_build_pipeline.html.haml | 22 +++++++++------- app/views/projects/commit/_pipeline.html.haml | 14 ++++------ .../_generic_commit_status_pipeline.html.haml | 14 +++++----- 4 files changed, 41 insertions(+), 35 deletions(-) diff --git a/app/helpers/ci_status_helper.rb b/app/helpers/ci_status_helper.rb index ea2f5f9281a..573cdef767e 100644 --- a/app/helpers/ci_status_helper.rb +++ b/app/helpers/ci_status_helper.rb @@ -38,6 +38,10 @@ module CiStatusHelper 'icon_status_pending' when 'running' 'icon_status_running' + when 'play' + 'icon_status_warning' + when 'created' + 'icon_status_pending' else 'icon_status_cancel' end @@ -48,13 +52,13 @@ module CiStatusHelper def render_commit_status(commit, tooltip_placement: 'auto left') project = commit.project path = builds_namespace_project_commit_path(project.namespace, project, commit) - render_status_with_link('commit', commit.status, path, tooltip_placement) + render_status_with_link('commit', commit.status, path, tooltip_placement: tooltip_placement) end def render_pipeline_status(pipeline, tooltip_placement: 'auto left') project = pipeline.project path = namespace_project_pipeline_path(project.namespace, project, pipeline) - render_status_with_link('pipeline', pipeline.status, path, tooltip_placement) + render_status_with_link('pipeline', pipeline.status, path, tooltip_placement: tooltip_placement) end def no_runners_for_project?(project) @@ -62,13 +66,17 @@ module CiStatusHelper Ci::Runner.shared.blank? end - private + def render_status_with_link(type, status, path = nil, tooltip_placement: 'auto left', cssclass: '') + klass = "ci-status-link ci-status-icon-#{status.dasherize} #{cssclass}" + title = "#{type.titleize}: #{ci_label_for_status(status)}" + data = { toggle: 'tooltip', placement: tooltip_placement } - def render_status_with_link(type, status, path, tooltip_placement, cssclass: '') - link_to ci_icon_for_status(status), - path, - class: "ci-status-link ci-status-icon-#{status.dasherize} #{cssclass}", - title: "#{type.titleize}: #{ci_label_for_status(status)}", - data: { toggle: 'tooltip', placement: tooltip_placement } + if path + link_to ci_icon_for_status(status), path, + class: klass, title: title, data: data + else + content_tag :span, ci_icon_for_status(status), + class: klass, title: title, data: data + end end end diff --git a/app/views/projects/ci/builds/_build_pipeline.html.haml b/app/views/projects/ci/builds/_build_pipeline.html.haml index 5149d75e5a2..8c8e0efc60f 100644 --- a/app/views/projects/ci/builds/_build_pipeline.html.haml +++ b/app/views/projects/ci/builds/_build_pipeline.html.haml @@ -1,12 +1,14 @@ %li.build .build-content - %span{class: "ci-status-link ci-status-icon-#{subject.status}"} - - if subject.playable? && can?(current_user, :update_build, @project) - = link_to play_namespace_project_build_path(subject.project.namespace, subject.project, subject, return_to: request.original_url), method: :post, title: 'Play' do - = icon('play') - - elsif can?(current_user, :read_build, @project) && subject.started? - = link_to namespace_project_build_path(subject.project.namespace, subject.project, subject) do - = ci_icon_for_status(subject.status) - - else - = ci_icon_for_status(subject.status) - = subject.name + - if subject.playable? && can?(current_user, :update_build, @project) + = link_to play_namespace_project_build_path(subject.project.namespace, subject.project, subject, return_to: request.original_url), method: :post, title: 'Play' do + = render_status_with_link('build', 'play') + = subject.name + - elsif can?(current_user, :read_build, @project) + = link_to namespace_project_build_path(subject.project.namespace, subject.project, subject) do + = render_status_with_link('build', subject.status) + = subject.name + - else + = render_status_with_link('build', subject.status) + = ci_icon_for_status(subject.status) + diff --git a/app/views/projects/commit/_pipeline.html.haml b/app/views/projects/commit/_pipeline.html.haml index 44250860020..9fa54057823 100644 --- a/app/views/projects/commit/_pipeline.html.haml +++ b/app/views/projects/commit/_pipeline.html.haml @@ -30,9 +30,8 @@ .row-content-block.build-content.middle-block.pipeline-graph .pipeline-visualization %ul.stage-column-list - - pipeline.statuses.stages.each do |stage| - - statuses = pipeline.statuses.where(stage: stage) - - status = statuses.latest.status + - stages = pipeline.stages_with_latest_statuses + - stages.each do |stage, statuses| %li.stage-column .stage-name %a{name: stage} @@ -40,12 +39,9 @@ = stage.titleize .builds-container %ul - - statuses.each do |build| - %li.build - .build-content - %span{class: "ci-status-link ci-status-icon-#{status}"} - = ci_icon_for_status(status) - = link_to build.name, namespace_project_build_url(build.project.namespace, build.project, build) + - statuses.each do |status| + = render "projects/#{status.to_partial_path}_pipeline", subject: status + - if pipeline.yaml_errors.present? .bs-callout.bs-callout-danger diff --git a/app/views/projects/generic_commit_statuses/_generic_commit_status_pipeline.html.haml b/app/views/projects/generic_commit_statuses/_generic_commit_status_pipeline.html.haml index 760918b18a3..584c0fa18ae 100644 --- a/app/views/projects/generic_commit_statuses/_generic_commit_status_pipeline.html.haml +++ b/app/views/projects/generic_commit_statuses/_generic_commit_status_pipeline.html.haml @@ -1,9 +1,9 @@ %li.build .build-content - %span{class: "ci-status-link ci-status-icon-#{subject.status}"} - - if subject.target_url - - link_to subject.target_url do - = ci_icon_for_status(subject.status) - - else - = ci_icon_for_status(subject.status) - = subject.name + - if subject.target_url + - link_to subject.target_url do + = render_status_with_link('commit status', subject.status) + = subject.name + - else + = render_status_with_link('commit status', subject.status) + = subject.name From bcdc3694919f6cc9777dd982325469fb87468835 Mon Sep 17 00:00:00 2001 From: Jack Davison Date: Mon, 20 Jun 2016 00:06:57 +0100 Subject: [PATCH 387/669] Truncated user list in award emoji tooltips * Only the first 10 names are displayed * Further users are indicated by "and X more." * String "and X more" is appended to the array THEN join is called * An oxford comma seperates the last name from "and X more" * In coffeescript "me" is now always prepended * Tests included --- CHANGELOG | 1 + app/assets/javascripts/awards_handler.js | 2 +- app/helpers/issues_helper.rb | 8 ++++++-- spec/helpers/issues_helper_spec.rb | 16 +++++++++++++++ spec/javascripts/awards_handler_spec.js | 25 ++++++++++++++++++++++++ 5 files changed, 49 insertions(+), 3 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 837e9e27aba..0615a42401c 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -76,6 +76,7 @@ v 8.11.0 (unreleased) - Remove `search_id` of labels dropdown filter to fix 'Missleading URI for labels in Merge Requests and Issues view'. !5368 (Scott Le) - Load project invited groups and members eagerly in `ProjectTeam#fetch_members` - Add pipeline events hook + - Award emoji tooltips containing more than 10 usernames are now truncated !4780 (jlogandavison) - Bump gitlab_git to speedup DiffCollection iterations - Rewrite description of a blocked user in admin settings. (Elias Werberich) - Make branches sortable without push permission !5462 (winniehell) diff --git a/app/assets/javascripts/awards_handler.js b/app/assets/javascripts/awards_handler.js index 2c5b83e4f1e..c753972d171 100644 --- a/app/assets/javascripts/awards_handler.js +++ b/app/assets/javascripts/awards_handler.js @@ -223,7 +223,7 @@ if (origTitle) { users = origTitle.trim().split(', '); } - users.push('me'); + users.unshift('me'); awardBlock.attr('title', users.join(', ')); return this.resetTooltip(awardBlock); }; diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb index 2e82b44437b..15f08fd5918 100644 --- a/app/helpers/issues_helper.rb +++ b/app/helpers/issues_helper.rb @@ -114,9 +114,13 @@ module IssuesHelper end def award_user_list(awards, current_user) - awards.map do |award| + names = awards.first(10).map do |award| award.user == current_user ? 'me' : award.user.name - end.join(', ') + end + + names << "and #{awards.size - names.size} more." if awards.size > names.size + + names.join(', ') end def award_active_class(awards, current_user) diff --git a/spec/helpers/issues_helper_spec.rb b/spec/helpers/issues_helper_spec.rb index 5e4655dfc95..86955329124 100644 --- a/spec/helpers/issues_helper_spec.rb +++ b/spec/helpers/issues_helper_spec.rb @@ -62,6 +62,22 @@ describe IssuesHelper do it { is_expected.to eq("!1, !2, or !3") } end + describe '#award_user_list' do + let!(:awards) { build_list(:award_emoji, 15) } + + it "returns a comma seperated list of 1-10 users" do + expect(award_user_list(awards.first(10), nil)).to eq(awards.first(10).map { |a| a.user.name }.join(', ')) + end + + it "displays the current user's name as 'me'" do + expect(award_user_list(awards.first(1), awards[0].user)).to eq('me') + end + + it "truncates lists of larger than 10 users" do + expect(award_user_list(awards, nil)).to eq(awards.first(10).map { |a| a.user.name }.join(', ') + ", and 5 more.") + end + end + describe '#award_active_class' do let!(:upvote) { create(:award_emoji) } diff --git a/spec/javascripts/awards_handler_spec.js b/spec/javascripts/awards_handler_spec.js index 3ddc163033e..70191026d0e 100644 --- a/spec/javascripts/awards_handler_spec.js +++ b/spec/javascripts/awards_handler_spec.js @@ -143,6 +143,31 @@ return expect($votesBlock.find('[data-emoji=fire]').length).toBe(0); }); }); + describe('::addMeToUserList', function() { + return it('should prepend "me" to the award tooltip', function() { + var $thumbsUpEmoji, $votesBlock, awardUrl; + awardUrl = awardsHandler.getAwardUrl(); + $votesBlock = $('.js-awards-block').eq(0); + $thumbsUpEmoji = $votesBlock.find('[data-emoji=thumbsup]').parent(); + $thumbsUpEmoji.attr('data-title', 'sam, jerry, max, andy'); + awardsHandler.addAward($votesBlock, awardUrl, 'thumbsup', false); + $thumbsUpEmoji.tooltip(); + return expect($thumbsUpEmoji.data("original-title")).toBe('me, sam, jerry, max, andy'); + }); + }); + describe('::removeMeToUserList', function() { + return it('removes "me" from the front of the tooltip', function() { + var $thumbsUpEmoji, $votesBlock, awardUrl; + awardUrl = awardsHandler.getAwardUrl(); + $votesBlock = $('.js-awards-block').eq(0); + $thumbsUpEmoji = $votesBlock.find('[data-emoji=thumbsup]').parent(); + $thumbsUpEmoji.attr('data-title', 'me, sam, jerry, max, andy'); + $thumbsUpEmoji.addClass('active'); + awardsHandler.addAward($votesBlock, awardUrl, 'thumbsup', false); + $thumbsUpEmoji.tooltip(); + return expect($thumbsUpEmoji.data("original-title")).toBe('sam, jerry, max, andy'); + }); + }); describe('search', function() { return it('should filter the emoji', function() { $('.js-add-award').eq(0).click(); From 4fbbb8e76550fcb8103cc1bf5c8536cf598db829 Mon Sep 17 00:00:00 2001 From: Jack Davison Date: Tue, 21 Jun 2016 23:22:03 +0100 Subject: [PATCH 388/669] Truncates 9-10 users with current user in front * If the current user is not in the list output will have 1-9 users * If the current user is in the list output will be "me, " + 0-9 users --- app/helpers/issues_helper.rb | 6 +++++- spec/helpers/issues_helper_spec.rb | 18 ++++++++++++++---- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb index 15f08fd5918..e8081d452c4 100644 --- a/app/helpers/issues_helper.rb +++ b/app/helpers/issues_helper.rb @@ -114,10 +114,14 @@ module IssuesHelper end def award_user_list(awards, current_user) - names = awards.first(10).map do |award| + names = awards.map do |award| award.user == current_user ? 'me' : award.user.name end + # Take first 9 OR current user + first 9 + current_user_name = names.delete('me') + names = names.first(9).insert(0, current_user_name).compact + names << "and #{awards.size - names.size} more." if awards.size > names.size names.join(', ') diff --git a/spec/helpers/issues_helper_spec.rb b/spec/helpers/issues_helper_spec.rb index 86955329124..c4281f8f591 100644 --- a/spec/helpers/issues_helper_spec.rb +++ b/spec/helpers/issues_helper_spec.rb @@ -65,16 +65,26 @@ describe IssuesHelper do describe '#award_user_list' do let!(:awards) { build_list(:award_emoji, 15) } - it "returns a comma seperated list of 1-10 users" do - expect(award_user_list(awards.first(10), nil)).to eq(awards.first(10).map { |a| a.user.name }.join(', ')) + it "returns a comma seperated list of 1-9 users" do + expect(award_user_list(awards.first(9), nil)).to eq(awards.first(9).map { |a| a.user.name }.join(', ')) end it "displays the current user's name as 'me'" do expect(award_user_list(awards.first(1), awards[0].user)).to eq('me') end - it "truncates lists of larger than 10 users" do - expect(award_user_list(awards, nil)).to eq(awards.first(10).map { |a| a.user.name }.join(', ') + ", and 5 more.") + it "truncates lists of larger than 9 users" do + expect(award_user_list(awards, nil)).to eq(awards.first(9).map { |a| a.user.name }.join(', ') + ", and 6 more.") + end + + it "displays the current user in front of 0-9 other users" do + expect(award_user_list(awards, awards[0].user)). + to eq("me, " + awards[1..9].map { |a| a.user.name }.join(', ') + ", and 5 more.") + end + + it "displays the current user in front regardless of position in the list" do + expect(award_user_list(awards, awards[12].user)). + to eq("me, " + awards[0..8].map { |a| a.user.name }.join(', ') + ", and 5 more.") end end From 2257fda38e37f5aa59a9ef83c6c6cff36bbcb182 Mon Sep 17 00:00:00 2001 From: Achilleas Pipinellis Date: Wed, 17 Aug 2016 15:34:53 +0300 Subject: [PATCH 389/669] Reference the version 'UI resolve conflicts' was introduced [ci skip] --- doc/user/project/merge_requests/resolve_conflicts.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/user/project/merge_requests/resolve_conflicts.md b/doc/user/project/merge_requests/resolve_conflicts.md index b355d1a01f1..44b76ffc8e6 100644 --- a/doc/user/project/merge_requests/resolve_conflicts.md +++ b/doc/user/project/merge_requests/resolve_conflicts.md @@ -1,5 +1,7 @@ # Merge conflict resolution +> [Introduced][ce-5479] in GitLab 8.11. + When a merge request has conflicts, GitLab may provide the option to resolve those conflicts in the GitLab UI. (See [conflicts available for resolution](#conflicts-available-for-resolution) for @@ -35,3 +37,5 @@ Additionally, GitLab does not detect conflicts in renames away from a path. For example, this will not create a conflict: on branch `a`, doing `git mv file1 file2`; on branch `b`, doing `git mv file1 file3`. Instead, both files will be present in the branch after the merge request is merged. + +[ce-5479]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/5479 From c0a722a223e50efeab5ed3f10523d83806a09215 Mon Sep 17 00:00:00 2001 From: Luke Bennett Date: Mon, 15 Aug 2016 16:10:22 +0100 Subject: [PATCH 390/669] Removed sleep calls introduced in !5740 --- features/steps/project/issues/issues.rb | 2 -- features/steps/project/merge_requests.rb | 1 - 2 files changed, 3 deletions(-) diff --git a/features/steps/project/issues/issues.rb b/features/steps/project/issues/issues.rb index daee90b3767..35f166c7c08 100644 --- a/features/steps/project/issues/issues.rb +++ b/features/steps/project/issues/issues.rb @@ -354,8 +354,6 @@ class Spinach::Features::ProjectIssues < Spinach::FeatureSteps end def filter_issue(text) - sleep 1 fill_in 'issue_search', with: text - sleep 1 end end diff --git a/features/steps/project/merge_requests.rb b/features/steps/project/merge_requests.rb index 53d1aedf27f..f3d78780da3 100644 --- a/features/steps/project/merge_requests.rb +++ b/features/steps/project/merge_requests.rb @@ -489,7 +489,6 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps end step 'I fill in merge request search with "Fe"' do - sleep 1 fill_in 'issue_search', with: "Fe" end From 8691561016338a58e314cdaa69911523b35c6df4 Mon Sep 17 00:00:00 2001 From: Luke Bennett Date: Wed, 17 Aug 2016 13:33:44 +0100 Subject: [PATCH 391/669] Now waits for All issuables to load when clicked --- features/steps/project/issues/issues.rb | 2 ++ features/steps/project/merge_requests.rb | 2 ++ 2 files changed, 4 insertions(+) diff --git a/features/steps/project/issues/issues.rb b/features/steps/project/issues/issues.rb index 35f166c7c08..056462a7152 100644 --- a/features/steps/project/issues/issues.rb +++ b/features/steps/project/issues/issues.rb @@ -45,6 +45,8 @@ class Spinach::Features::ProjectIssues < Spinach::FeatureSteps step 'I click link "All"' do click_link "All" + # Waits for load + expect(find('.issues-state-filters > .active')).to have_content 'All' end step 'I click link "Release 0.4"' do diff --git a/features/steps/project/merge_requests.rb b/features/steps/project/merge_requests.rb index f3d78780da3..9778ff4a6c7 100644 --- a/features/steps/project/merge_requests.rb +++ b/features/steps/project/merge_requests.rb @@ -22,6 +22,8 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps step 'I click link "All"' do click_link "All" + # Waits for load + expect(find('.issues-state-filters > .active')).to have_content 'All' end step 'I click link "Merged"' do From b73ff13e8a1c406d162721895687659d9e11c7a8 Mon Sep 17 00:00:00 2001 From: Sean McGivern Date: Tue, 26 Jul 2016 12:52:37 +0100 Subject: [PATCH 392/669] Fix Ace syntax highlighting with compiled assets --- CHANGELOG | 1 + Gemfile | 2 +- Gemfile.lock | 4 ++-- app/assets/javascripts/application.js | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 837e9e27aba..f1684e9f3f9 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -59,6 +59,7 @@ v 8.11.0 (unreleased) - Update version_sorter and use new interface for faster tag sorting - Optimize checking if a user has read access to a list of issues !5370 - Store all DB secrets in secrets.yml, under descriptive names !5274 + - Fix syntax highlighting in file editor - Nokogiri's various parsing methods are now instrumented - Add archived badge to project list !5798 - Add simple identifier to public SSH keys (muteor) diff --git a/Gemfile b/Gemfile index 8b44b54e22c..a99865a6f66 100644 --- a/Gemfile +++ b/Gemfile @@ -201,7 +201,7 @@ gem 'licensee', '~> 8.0.0' gem 'rack-attack', '~> 4.3.1' # Ace editor -gem 'ace-rails-ap', '~> 4.0.2' +gem 'ace-rails-ap', '~> 4.1.0' # Keyboard shortcuts gem 'mousetrap-rails', '~> 1.4.6' diff --git a/Gemfile.lock b/Gemfile.lock index 2244c20203b..3c7b3317a10 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -2,7 +2,7 @@ GEM remote: https://rubygems.org/ specs: RedCloth (4.3.2) - ace-rails-ap (4.0.2) + ace-rails-ap (4.1.0) actionmailer (4.2.7.1) actionpack (= 4.2.7.1) actionview (= 4.2.7.1) @@ -796,7 +796,7 @@ PLATFORMS DEPENDENCIES RedCloth (~> 4.3.2) - ace-rails-ap (~> 4.0.2) + ace-rails-ap (~> 4.1.0) activerecord-session_store (~> 1.0.0) acts-as-taggable-on (~> 3.4) addressable (~> 2.3.8) diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index e596b98603b..0d6b7b16002 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -26,7 +26,7 @@ /*= require bootstrap/tooltip */ /*= require bootstrap/popover */ /*= require select2 */ -/*= require ace/ace */ +/*= require ace-rails-ap */ /*= require ace/ext-searchbox */ /*= require underscore */ /*= require dropzone */ From 62e2989bb77ea91f3e0acc81d8720eeaebb6bfd4 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Wed, 17 Aug 2016 14:49:16 +0100 Subject: [PATCH 393/669] Use have_no_link to test presence of button --- spec/features/merge_requests/pipelines_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/features/merge_requests/pipelines_spec.rb b/spec/features/merge_requests/pipelines_spec.rb index eeb898f083e..9c4c0525267 100644 --- a/spec/features/merge_requests/pipelines_spec.rb +++ b/spec/features/merge_requests/pipelines_spec.rb @@ -41,7 +41,7 @@ feature 'Pipelines for Merge Requests', feature: true, js: true do scenario 'user visits merge request page' do page.within('.merge-request-tabs') do - expect(page).not_to have_link('Pipelines') + expect(page).to have_no_link('Pipelines') end end end From 36545f8b9760db072c9c753dcaf77cec2bec14ab Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Wed, 17 Aug 2016 15:37:25 +0100 Subject: [PATCH 394/669] Added VueJS plugin --- .../assets/javascripts/vue-resource.full.js | 1318 ++ vendor/assets/javascripts/vue-resource.js.erb | 2 + vendor/assets/javascripts/vue-resource.min.js | 7 + vendor/assets/javascripts/vue.full.js | 10073 ++++++++++++++++ vendor/assets/javascripts/vue.js.erb | 2 + vendor/assets/javascripts/vue.min.js | 9 + 6 files changed, 11411 insertions(+) create mode 100644 vendor/assets/javascripts/vue-resource.full.js create mode 100644 vendor/assets/javascripts/vue-resource.js.erb create mode 100644 vendor/assets/javascripts/vue-resource.min.js create mode 100644 vendor/assets/javascripts/vue.full.js create mode 100644 vendor/assets/javascripts/vue.js.erb create mode 100644 vendor/assets/javascripts/vue.min.js diff --git a/vendor/assets/javascripts/vue-resource.full.js b/vendor/assets/javascripts/vue-resource.full.js new file mode 100644 index 00000000000..d7981dbec7e --- /dev/null +++ b/vendor/assets/javascripts/vue-resource.full.js @@ -0,0 +1,1318 @@ +/*! + * vue-resource v0.9.3 + * https://github.com/vuejs/vue-resource + * Released under the MIT License. + */ + +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + (global.VueResource = factory()); +}(this, function () { 'use strict'; + + /** + * Promises/A+ polyfill v1.1.4 (https://github.com/bramstein/promis) + */ + + var RESOLVED = 0; + var REJECTED = 1; + var PENDING = 2; + + function Promise$2(executor) { + + this.state = PENDING; + this.value = undefined; + this.deferred = []; + + var promise = this; + + try { + executor(function (x) { + promise.resolve(x); + }, function (r) { + promise.reject(r); + }); + } catch (e) { + promise.reject(e); + } + } + + Promise$2.reject = function (r) { + return new Promise$2(function (resolve, reject) { + reject(r); + }); + }; + + Promise$2.resolve = function (x) { + return new Promise$2(function (resolve, reject) { + resolve(x); + }); + }; + + Promise$2.all = function all(iterable) { + return new Promise$2(function (resolve, reject) { + var count = 0, + result = []; + + if (iterable.length === 0) { + resolve(result); + } + + function resolver(i) { + return function (x) { + result[i] = x; + count += 1; + + if (count === iterable.length) { + resolve(result); + } + }; + } + + for (var i = 0; i < iterable.length; i += 1) { + Promise$2.resolve(iterable[i]).then(resolver(i), reject); + } + }); + }; + + Promise$2.race = function race(iterable) { + return new Promise$2(function (resolve, reject) { + for (var i = 0; i < iterable.length; i += 1) { + Promise$2.resolve(iterable[i]).then(resolve, reject); + } + }); + }; + + var p$1 = Promise$2.prototype; + + p$1.resolve = function resolve(x) { + var promise = this; + + if (promise.state === PENDING) { + if (x === promise) { + throw new TypeError('Promise settled with itself.'); + } + + var called = false; + + try { + var then = x && x['then']; + + if (x !== null && typeof x === 'object' && typeof then === 'function') { + then.call(x, function (x) { + if (!called) { + promise.resolve(x); + } + called = true; + }, function (r) { + if (!called) { + promise.reject(r); + } + called = true; + }); + return; + } + } catch (e) { + if (!called) { + promise.reject(e); + } + return; + } + + promise.state = RESOLVED; + promise.value = x; + promise.notify(); + } + }; + + p$1.reject = function reject(reason) { + var promise = this; + + if (promise.state === PENDING) { + if (reason === promise) { + throw new TypeError('Promise settled with itself.'); + } + + promise.state = REJECTED; + promise.value = reason; + promise.notify(); + } + }; + + p$1.notify = function notify() { + var promise = this; + + nextTick(function () { + if (promise.state !== PENDING) { + while (promise.deferred.length) { + var deferred = promise.deferred.shift(), + onResolved = deferred[0], + onRejected = deferred[1], + resolve = deferred[2], + reject = deferred[3]; + + try { + if (promise.state === RESOLVED) { + if (typeof onResolved === 'function') { + resolve(onResolved.call(undefined, promise.value)); + } else { + resolve(promise.value); + } + } else if (promise.state === REJECTED) { + if (typeof onRejected === 'function') { + resolve(onRejected.call(undefined, promise.value)); + } else { + reject(promise.value); + } + } + } catch (e) { + reject(e); + } + } + } + }); + }; + + p$1.then = function then(onResolved, onRejected) { + var promise = this; + + return new Promise$2(function (resolve, reject) { + promise.deferred.push([onResolved, onRejected, resolve, reject]); + promise.notify(); + }); + }; + + p$1.catch = function (onRejected) { + return this.then(undefined, onRejected); + }; + + var PromiseObj = window.Promise || Promise$2; + + function Promise$1(executor, context) { + + if (executor instanceof PromiseObj) { + this.promise = executor; + } else { + this.promise = new PromiseObj(executor.bind(context)); + } + + this.context = context; + } + + Promise$1.all = function (iterable, context) { + return new Promise$1(PromiseObj.all(iterable), context); + }; + + Promise$1.resolve = function (value, context) { + return new Promise$1(PromiseObj.resolve(value), context); + }; + + Promise$1.reject = function (reason, context) { + return new Promise$1(PromiseObj.reject(reason), context); + }; + + Promise$1.race = function (iterable, context) { + return new Promise$1(PromiseObj.race(iterable), context); + }; + + var p = Promise$1.prototype; + + p.bind = function (context) { + this.context = context; + return this; + }; + + p.then = function (fulfilled, rejected) { + + if (fulfilled && fulfilled.bind && this.context) { + fulfilled = fulfilled.bind(this.context); + } + + if (rejected && rejected.bind && this.context) { + rejected = rejected.bind(this.context); + } + + return new Promise$1(this.promise.then(fulfilled, rejected), this.context); + }; + + p.catch = function (rejected) { + + if (rejected && rejected.bind && this.context) { + rejected = rejected.bind(this.context); + } + + return new Promise$1(this.promise.catch(rejected), this.context); + }; + + p.finally = function (callback) { + + return this.then(function (value) { + callback.call(this); + return value; + }, function (reason) { + callback.call(this); + return PromiseObj.reject(reason); + }); + }; + + var debug = false; + var util = {}; + var array = []; + function Util (Vue) { + util = Vue.util; + debug = Vue.config.debug || !Vue.config.silent; + } + + function warn(msg) { + if (typeof console !== 'undefined' && debug) { + console.warn('[VueResource warn]: ' + msg); + } + } + + function error(msg) { + if (typeof console !== 'undefined') { + console.error(msg); + } + } + + function nextTick(cb, ctx) { + return util.nextTick(cb, ctx); + } + + function trim(str) { + return str.replace(/^\s*|\s*$/g, ''); + } + + var isArray = Array.isArray; + + function isString(val) { + return typeof val === 'string'; + } + + function isBoolean(val) { + return val === true || val === false; + } + + function isFunction(val) { + return typeof val === 'function'; + } + + function isObject(obj) { + return obj !== null && typeof obj === 'object'; + } + + function isPlainObject(obj) { + return isObject(obj) && Object.getPrototypeOf(obj) == Object.prototype; + } + + function isFormData(obj) { + return typeof FormData !== 'undefined' && obj instanceof FormData; + } + + function when(value, fulfilled, rejected) { + + var promise = Promise$1.resolve(value); + + if (arguments.length < 2) { + return promise; + } + + return promise.then(fulfilled, rejected); + } + + function options(fn, obj, opts) { + + opts = opts || {}; + + if (isFunction(opts)) { + opts = opts.call(obj); + } + + return merge(fn.bind({ $vm: obj, $options: opts }), fn, { $options: opts }); + } + + function each(obj, iterator) { + + var i, key; + + if (typeof obj.length == 'number') { + for (i = 0; i < obj.length; i++) { + iterator.call(obj[i], obj[i], i); + } + } else if (isObject(obj)) { + for (key in obj) { + if (obj.hasOwnProperty(key)) { + iterator.call(obj[key], obj[key], key); + } + } + } + + return obj; + } + + var assign = Object.assign || _assign; + + function merge(target) { + + var args = array.slice.call(arguments, 1); + + args.forEach(function (source) { + _merge(target, source, true); + }); + + return target; + } + + function defaults(target) { + + var args = array.slice.call(arguments, 1); + + args.forEach(function (source) { + + for (var key in source) { + if (target[key] === undefined) { + target[key] = source[key]; + } + } + }); + + return target; + } + + function _assign(target) { + + var args = array.slice.call(arguments, 1); + + args.forEach(function (source) { + _merge(target, source); + }); + + return target; + } + + function _merge(target, source, deep) { + for (var key in source) { + if (deep && (isPlainObject(source[key]) || isArray(source[key]))) { + if (isPlainObject(source[key]) && !isPlainObject(target[key])) { + target[key] = {}; + } + if (isArray(source[key]) && !isArray(target[key])) { + target[key] = []; + } + _merge(target[key], source[key], deep); + } else if (source[key] !== undefined) { + target[key] = source[key]; + } + } + } + + function root (options, next) { + + var url = next(options); + + if (isString(options.root) && !url.match(/^(https?:)?\//)) { + url = options.root + '/' + url; + } + + return url; + } + + function query (options, next) { + + var urlParams = Object.keys(Url.options.params), + query = {}, + url = next(options); + + each(options.params, function (value, key) { + if (urlParams.indexOf(key) === -1) { + query[key] = value; + } + }); + + query = Url.params(query); + + if (query) { + url += (url.indexOf('?') == -1 ? '?' : '&') + query; + } + + return url; + } + + /** + * URL Template v2.0.6 (https://github.com/bramstein/url-template) + */ + + function expand(url, params, variables) { + + var tmpl = parse(url), + expanded = tmpl.expand(params); + + if (variables) { + variables.push.apply(variables, tmpl.vars); + } + + return expanded; + } + + function parse(template) { + + var operators = ['+', '#', '.', '/', ';', '?', '&'], + variables = []; + + return { + vars: variables, + expand: function (context) { + return template.replace(/\{([^\{\}]+)\}|([^\{\}]+)/g, function (_, expression, literal) { + if (expression) { + + var operator = null, + values = []; + + if (operators.indexOf(expression.charAt(0)) !== -1) { + operator = expression.charAt(0); + expression = expression.substr(1); + } + + expression.split(/,/g).forEach(function (variable) { + var tmp = /([^:\*]*)(?::(\d+)|(\*))?/.exec(variable); + values.push.apply(values, getValues(context, operator, tmp[1], tmp[2] || tmp[3])); + variables.push(tmp[1]); + }); + + if (operator && operator !== '+') { + + var separator = ','; + + if (operator === '?') { + separator = '&'; + } else if (operator !== '#') { + separator = operator; + } + + return (values.length !== 0 ? operator : '') + values.join(separator); + } else { + return values.join(','); + } + } else { + return encodeReserved(literal); + } + }); + } + }; + } + + function getValues(context, operator, key, modifier) { + + var value = context[key], + result = []; + + if (isDefined(value) && value !== '') { + if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') { + value = value.toString(); + + if (modifier && modifier !== '*') { + value = value.substring(0, parseInt(modifier, 10)); + } + + result.push(encodeValue(operator, value, isKeyOperator(operator) ? key : null)); + } else { + if (modifier === '*') { + if (Array.isArray(value)) { + value.filter(isDefined).forEach(function (value) { + result.push(encodeValue(operator, value, isKeyOperator(operator) ? key : null)); + }); + } else { + Object.keys(value).forEach(function (k) { + if (isDefined(value[k])) { + result.push(encodeValue(operator, value[k], k)); + } + }); + } + } else { + var tmp = []; + + if (Array.isArray(value)) { + value.filter(isDefined).forEach(function (value) { + tmp.push(encodeValue(operator, value)); + }); + } else { + Object.keys(value).forEach(function (k) { + if (isDefined(value[k])) { + tmp.push(encodeURIComponent(k)); + tmp.push(encodeValue(operator, value[k].toString())); + } + }); + } + + if (isKeyOperator(operator)) { + result.push(encodeURIComponent(key) + '=' + tmp.join(',')); + } else if (tmp.length !== 0) { + result.push(tmp.join(',')); + } + } + } + } else { + if (operator === ';') { + result.push(encodeURIComponent(key)); + } else if (value === '' && (operator === '&' || operator === '?')) { + result.push(encodeURIComponent(key) + '='); + } else if (value === '') { + result.push(''); + } + } + + return result; + } + + function isDefined(value) { + return value !== undefined && value !== null; + } + + function isKeyOperator(operator) { + return operator === ';' || operator === '&' || operator === '?'; + } + + function encodeValue(operator, value, key) { + + value = operator === '+' || operator === '#' ? encodeReserved(value) : encodeURIComponent(value); + + if (key) { + return encodeURIComponent(key) + '=' + value; + } else { + return value; + } + } + + function encodeReserved(str) { + return str.split(/(%[0-9A-Fa-f]{2})/g).map(function (part) { + if (!/%[0-9A-Fa-f]/.test(part)) { + part = encodeURI(part); + } + return part; + }).join(''); + } + + function template (options) { + + var variables = [], + url = expand(options.url, options.params, variables); + + variables.forEach(function (key) { + delete options.params[key]; + }); + + return url; + } + + /** + * Service for URL templating. + */ + + var ie = document.documentMode; + var el = document.createElement('a'); + + function Url(url, params) { + + var self = this || {}, + options = url, + transform; + + if (isString(url)) { + options = { url: url, params: params }; + } + + options = merge({}, Url.options, self.$options, options); + + Url.transforms.forEach(function (handler) { + transform = factory(handler, transform, self.$vm); + }); + + return transform(options); + } + + /** + * Url options. + */ + + Url.options = { + url: '', + root: null, + params: {} + }; + + /** + * Url transforms. + */ + + Url.transforms = [template, query, root]; + + /** + * Encodes a Url parameter string. + * + * @param {Object} obj + */ + + Url.params = function (obj) { + + var params = [], + escape = encodeURIComponent; + + params.add = function (key, value) { + + if (isFunction(value)) { + value = value(); + } + + if (value === null) { + value = ''; + } + + this.push(escape(key) + '=' + escape(value)); + }; + + serialize(params, obj); + + return params.join('&').replace(/%20/g, '+'); + }; + + /** + * Parse a URL and return its components. + * + * @param {String} url + */ + + Url.parse = function (url) { + + if (ie) { + el.href = url; + url = el.href; + } + + el.href = url; + + return { + href: el.href, + protocol: el.protocol ? el.protocol.replace(/:$/, '') : '', + port: el.port, + host: el.host, + hostname: el.hostname, + pathname: el.pathname.charAt(0) === '/' ? el.pathname : '/' + el.pathname, + search: el.search ? el.search.replace(/^\?/, '') : '', + hash: el.hash ? el.hash.replace(/^#/, '') : '' + }; + }; + + function factory(handler, next, vm) { + return function (options) { + return handler.call(vm, options, next); + }; + } + + function serialize(params, obj, scope) { + + var array = isArray(obj), + plain = isPlainObject(obj), + hash; + + each(obj, function (value, key) { + + hash = isObject(value) || isArray(value); + + if (scope) { + key = scope + '[' + (plain || hash ? key : '') + ']'; + } + + if (!scope && array) { + params.add(value.name, value.value); + } else if (hash) { + serialize(params, value, key); + } else { + params.add(key, value); + } + }); + } + + function xdrClient (request) { + return new Promise$1(function (resolve) { + + var xdr = new XDomainRequest(), + handler = function (event) { + + var response = request.respondWith(xdr.responseText, { + status: xdr.status, + statusText: xdr.statusText + }); + + resolve(response); + }; + + request.abort = function () { + return xdr.abort(); + }; + + xdr.open(request.method, request.getUrl(), true); + xdr.timeout = 0; + xdr.onload = handler; + xdr.onerror = handler; + xdr.ontimeout = function () {}; + xdr.onprogress = function () {}; + xdr.send(request.getBody()); + }); + } + + var ORIGIN_URL = Url.parse(location.href); + var SUPPORTS_CORS = 'withCredentials' in new XMLHttpRequest(); + + function cors (request, next) { + + if (!isBoolean(request.crossOrigin) && crossOrigin(request)) { + request.crossOrigin = true; + } + + if (request.crossOrigin) { + + if (!SUPPORTS_CORS) { + request.client = xdrClient; + } + + delete request.emulateHTTP; + } + + next(); + } + + function crossOrigin(request) { + + var requestUrl = Url.parse(Url(request)); + + return requestUrl.protocol !== ORIGIN_URL.protocol || requestUrl.host !== ORIGIN_URL.host; + } + + function body (request, next) { + + if (request.emulateJSON && isPlainObject(request.body)) { + request.body = Url.params(request.body); + request.headers['Content-Type'] = 'application/x-www-form-urlencoded'; + } + + if (isFormData(request.body)) { + delete request.headers['Content-Type']; + } + + if (isPlainObject(request.body)) { + request.body = JSON.stringify(request.body); + } + + next(function (response) { + + var contentType = response.headers['Content-Type']; + + if (isString(contentType) && contentType.indexOf('application/json') === 0) { + + try { + response.data = response.json(); + } catch (e) { + response.data = null; + } + } else { + response.data = response.text(); + } + }); + } + + function jsonpClient (request) { + return new Promise$1(function (resolve) { + + var name = request.jsonp || 'callback', + callback = '_jsonp' + Math.random().toString(36).substr(2), + body = null, + handler, + script; + + handler = function (event) { + + var status = 0; + + if (event.type === 'load' && body !== null) { + status = 200; + } else if (event.type === 'error') { + status = 404; + } + + resolve(request.respondWith(body, { status: status })); + + delete window[callback]; + document.body.removeChild(script); + }; + + request.params[name] = callback; + + window[callback] = function (result) { + body = JSON.stringify(result); + }; + + script = document.createElement('script'); + script.src = request.getUrl(); + script.type = 'text/javascript'; + script.async = true; + script.onload = handler; + script.onerror = handler; + + document.body.appendChild(script); + }); + } + + function jsonp (request, next) { + + if (request.method == 'JSONP') { + request.client = jsonpClient; + } + + next(function (response) { + + if (request.method == 'JSONP') { + response.data = response.json(); + } + }); + } + + function before (request, next) { + + if (isFunction(request.before)) { + request.before.call(this, request); + } + + next(); + } + + /** + * HTTP method override Interceptor. + */ + + function method (request, next) { + + if (request.emulateHTTP && /^(PUT|PATCH|DELETE)$/i.test(request.method)) { + request.headers['X-HTTP-Method-Override'] = request.method; + request.method = 'POST'; + } + + next(); + } + + function header (request, next) { + + request.method = request.method.toUpperCase(); + request.headers = assign({}, Http.headers.common, !request.crossOrigin ? Http.headers.custom : {}, Http.headers[request.method.toLowerCase()], request.headers); + + next(); + } + + /** + * Timeout Interceptor. + */ + + function timeout (request, next) { + + var timeout; + + if (request.timeout) { + timeout = setTimeout(function () { + request.abort(); + }, request.timeout); + } + + next(function (response) { + + clearTimeout(timeout); + }); + } + + function xhrClient (request) { + return new Promise$1(function (resolve) { + + var xhr = new XMLHttpRequest(), + handler = function (event) { + + var response = request.respondWith('response' in xhr ? xhr.response : xhr.responseText, { + status: xhr.status === 1223 ? 204 : xhr.status, // IE9 status bug + statusText: xhr.status === 1223 ? 'No Content' : trim(xhr.statusText), + headers: parseHeaders(xhr.getAllResponseHeaders()) + }); + + resolve(response); + }; + + request.abort = function () { + return xhr.abort(); + }; + + xhr.open(request.method, request.getUrl(), true); + xhr.timeout = 0; + xhr.onload = handler; + xhr.onerror = handler; + + if (request.progress) { + if (request.method === 'GET') { + xhr.addEventListener('progress', request.progress); + } else if (/^(POST|PUT)$/i.test(request.method)) { + xhr.upload.addEventListener('progress', request.progress); + } + } + + if (request.credentials === true) { + xhr.withCredentials = true; + } + + each(request.headers || {}, function (value, header) { + xhr.setRequestHeader(header, value); + }); + + xhr.send(request.getBody()); + }); + } + + function parseHeaders(str) { + + var headers = {}, + value, + name, + i; + + each(trim(str).split('\n'), function (row) { + + i = row.indexOf(':'); + name = trim(row.slice(0, i)); + value = trim(row.slice(i + 1)); + + if (headers[name]) { + + if (isArray(headers[name])) { + headers[name].push(value); + } else { + headers[name] = [headers[name], value]; + } + } else { + + headers[name] = value; + } + }); + + return headers; + } + + function Client (context) { + + var reqHandlers = [sendRequest], + resHandlers = [], + handler; + + if (!isObject(context)) { + context = null; + } + + function Client(request) { + return new Promise$1(function (resolve) { + + function exec() { + + handler = reqHandlers.pop(); + + if (isFunction(handler)) { + handler.call(context, request, next); + } else { + warn('Invalid interceptor of type ' + typeof handler + ', must be a function'); + next(); + } + } + + function next(response) { + + if (isFunction(response)) { + + resHandlers.unshift(response); + } else if (isObject(response)) { + + resHandlers.forEach(function (handler) { + response = when(response, function (response) { + return handler.call(context, response) || response; + }); + }); + + when(response, resolve); + + return; + } + + exec(); + } + + exec(); + }, context); + } + + Client.use = function (handler) { + reqHandlers.push(handler); + }; + + return Client; + } + + function sendRequest(request, resolve) { + + var client = request.client || xhrClient; + + resolve(client(request)); + } + + var classCallCheck = function (instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } + }; + + /** + * HTTP Response. + */ + + var Response = function () { + function Response(body, _ref) { + var url = _ref.url; + var headers = _ref.headers; + var status = _ref.status; + var statusText = _ref.statusText; + classCallCheck(this, Response); + + + this.url = url; + this.body = body; + this.headers = headers || {}; + this.status = status || 0; + this.statusText = statusText || ''; + this.ok = status >= 200 && status < 300; + } + + Response.prototype.text = function text() { + return this.body; + }; + + Response.prototype.blob = function blob() { + return new Blob([this.body]); + }; + + Response.prototype.json = function json() { + return JSON.parse(this.body); + }; + + return Response; + }(); + + var Request = function () { + function Request(options) { + classCallCheck(this, Request); + + + this.method = 'GET'; + this.body = null; + this.params = {}; + this.headers = {}; + + assign(this, options); + } + + Request.prototype.getUrl = function getUrl() { + return Url(this); + }; + + Request.prototype.getBody = function getBody() { + return this.body; + }; + + Request.prototype.respondWith = function respondWith(body, options) { + return new Response(body, assign(options || {}, { url: this.getUrl() })); + }; + + return Request; + }(); + + /** + * Service for sending network requests. + */ + + var CUSTOM_HEADERS = { 'X-Requested-With': 'XMLHttpRequest' }; + var COMMON_HEADERS = { 'Accept': 'application/json, text/plain, */*' }; + var JSON_CONTENT_TYPE = { 'Content-Type': 'application/json;charset=utf-8' }; + + function Http(options) { + + var self = this || {}, + client = Client(self.$vm); + + defaults(options || {}, self.$options, Http.options); + + Http.interceptors.forEach(function (handler) { + client.use(handler); + }); + + return client(new Request(options)).then(function (response) { + + return response.ok ? response : Promise$1.reject(response); + }, function (response) { + + if (response instanceof Error) { + error(response); + } + + return Promise$1.reject(response); + }); + } + + Http.options = {}; + + Http.headers = { + put: JSON_CONTENT_TYPE, + post: JSON_CONTENT_TYPE, + patch: JSON_CONTENT_TYPE, + delete: JSON_CONTENT_TYPE, + custom: CUSTOM_HEADERS, + common: COMMON_HEADERS + }; + + Http.interceptors = [before, timeout, method, body, jsonp, header, cors]; + + ['get', 'delete', 'head', 'jsonp'].forEach(function (method) { + + Http[method] = function (url, options) { + return this(assign(options || {}, { url: url, method: method })); + }; + }); + + ['post', 'put', 'patch'].forEach(function (method) { + + Http[method] = function (url, body, options) { + return this(assign(options || {}, { url: url, method: method, body: body })); + }; + }); + + function Resource(url, params, actions, options) { + + var self = this || {}, + resource = {}; + + actions = assign({}, Resource.actions, actions); + + each(actions, function (action, name) { + + action = merge({ url: url, params: params || {} }, options, action); + + resource[name] = function () { + return (self.$http || Http)(opts(action, arguments)); + }; + }); + + return resource; + } + + function opts(action, args) { + + var options = assign({}, action), + params = {}, + body; + + switch (args.length) { + + case 2: + + params = args[0]; + body = args[1]; + + break; + + case 1: + + if (/^(POST|PUT|PATCH)$/i.test(options.method)) { + body = args[0]; + } else { + params = args[0]; + } + + break; + + case 0: + + break; + + default: + + throw 'Expected up to 4 arguments [params, body], got ' + args.length + ' arguments'; + } + + options.body = body; + options.params = assign({}, options.params, params); + + return options; + } + + Resource.actions = { + + get: { method: 'GET' }, + save: { method: 'POST' }, + query: { method: 'GET' }, + update: { method: 'PUT' }, + remove: { method: 'DELETE' }, + delete: { method: 'DELETE' } + + }; + + function plugin(Vue) { + + if (plugin.installed) { + return; + } + + Util(Vue); + + Vue.url = Url; + Vue.http = Http; + Vue.resource = Resource; + Vue.Promise = Promise$1; + + Object.defineProperties(Vue.prototype, { + + $url: { + get: function () { + return options(Vue.url, this, this.$options.url); + } + }, + + $http: { + get: function () { + return options(Vue.http, this, this.$options.http); + } + }, + + $resource: { + get: function () { + return Vue.resource.bind(this); + } + }, + + $promise: { + get: function () { + var _this = this; + + return function (executor) { + return new Vue.Promise(executor, _this); + }; + } + } + + }); + } + + if (typeof window !== 'undefined' && window.Vue) { + window.Vue.use(plugin); + } + + return plugin; + +})); \ No newline at end of file diff --git a/vendor/assets/javascripts/vue-resource.js.erb b/vendor/assets/javascripts/vue-resource.js.erb new file mode 100644 index 00000000000..8001775ce98 --- /dev/null +++ b/vendor/assets/javascripts/vue-resource.js.erb @@ -0,0 +1,2 @@ +<% type = Rails.env.development? ? 'full' : 'min' %> +<%= File.read(Rails.root.join("vendor/assets/javascripts/vue-resource.#{type}.js")) %> diff --git a/vendor/assets/javascripts/vue-resource.min.js b/vendor/assets/javascripts/vue-resource.min.js new file mode 100644 index 00000000000..6bff73a2a67 --- /dev/null +++ b/vendor/assets/javascripts/vue-resource.min.js @@ -0,0 +1,7 @@ +/*! + * vue-resource v0.9.3 + * https://github.com/vuejs/vue-resource + * Released under the MIT License. + */ + +!function(t,n){"object"==typeof exports&&"undefined"!=typeof module?module.exports=n():"function"==typeof define&&define.amd?define(n):t.VueResource=n()}(this,function(){"use strict";function t(t){this.state=Z,this.value=void 0,this.deferred=[];var n=this;try{t(function(t){n.resolve(t)},function(t){n.reject(t)})}catch(e){n.reject(e)}}function n(t,n){t instanceof nt?this.promise=t:this.promise=new nt(t.bind(n)),this.context=n}function e(t){rt=t.util,ot=t.config.debug||!t.config.silent}function o(t){"undefined"!=typeof console&&ot&&console.warn("[VueResource warn]: "+t)}function r(t){"undefined"!=typeof console&&console.error(t)}function i(t,n){return rt.nextTick(t,n)}function u(t){return t.replace(/^\s*|\s*$/g,"")}function s(t){return"string"==typeof t}function c(t){return t===!0||t===!1}function a(t){return"function"==typeof t}function f(t){return null!==t&&"object"==typeof t}function h(t){return f(t)&&Object.getPrototypeOf(t)==Object.prototype}function p(t){return"undefined"!=typeof FormData&&t instanceof FormData}function l(t,e,o){var r=n.resolve(t);return arguments.length<2?r:r.then(e,o)}function d(t,n,e){return e=e||{},a(e)&&(e=e.call(n)),v(t.bind({$vm:n,$options:e}),t,{$options:e})}function m(t,n){var e,o;if("number"==typeof t.length)for(e=0;e=200&&i<300}return t.prototype.text=function(){return this.body},t.prototype.blob=function(){return new Blob([this.body])},t.prototype.json=function(){return JSON.parse(this.body)},t}(),dt=function(){function t(n){pt(this,t),this.method="GET",this.body=null,this.params={},this.headers={},st(this,n)}return t.prototype.getUrl=function(){return R(this)},t.prototype.getBody=function(){return this.body},t.prototype.respondWith=function(t,n){return new lt(t,st(n||{},{url:this.getUrl()}))},t}(),mt={"X-Requested-With":"XMLHttpRequest"},vt={Accept:"application/json, text/plain, */*"},yt={"Content-Type":"application/json;charset=utf-8"};return V.options={},V.headers={put:yt,post:yt,patch:yt,"delete":yt,custom:mt,common:vt},V.interceptors=[D,X,J,L,N,M,H],["get","delete","head","jsonp"].forEach(function(t){V[t]=function(n,e){return this(st(e||{},{url:n,method:t}))}}),["post","put","patch"].forEach(function(t){V[t]=function(n,e,o){return this(st(o||{},{url:n,method:t,body:e}))}}),_.actions={get:{method:"GET"},save:{method:"POST"},query:{method:"GET"},update:{method:"PUT"},remove:{method:"DELETE"},"delete":{method:"DELETE"}},"undefined"!=typeof window&&window.Vue&&window.Vue.use(K),K}); \ No newline at end of file diff --git a/vendor/assets/javascripts/vue.full.js b/vendor/assets/javascripts/vue.full.js new file mode 100644 index 00000000000..7ae95897a01 --- /dev/null +++ b/vendor/assets/javascripts/vue.full.js @@ -0,0 +1,10073 @@ +/*! + * Vue.js v1.0.26 + * (c) 2016 Evan You + * Released under the MIT License. + */ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + (global.Vue = factory()); +}(this, function () { 'use strict'; + + function set(obj, key, val) { + if (hasOwn(obj, key)) { + obj[key] = val; + return; + } + if (obj._isVue) { + set(obj._data, key, val); + return; + } + var ob = obj.__ob__; + if (!ob) { + obj[key] = val; + return; + } + ob.convert(key, val); + ob.dep.notify(); + if (ob.vms) { + var i = ob.vms.length; + while (i--) { + var vm = ob.vms[i]; + vm._proxy(key); + vm._digest(); + } + } + return val; + } + + /** + * Delete a property and trigger change if necessary. + * + * @param {Object} obj + * @param {String} key + */ + + function del(obj, key) { + if (!hasOwn(obj, key)) { + return; + } + delete obj[key]; + var ob = obj.__ob__; + if (!ob) { + if (obj._isVue) { + delete obj._data[key]; + obj._digest(); + } + return; + } + ob.dep.notify(); + if (ob.vms) { + var i = ob.vms.length; + while (i--) { + var vm = ob.vms[i]; + vm._unproxy(key); + vm._digest(); + } + } + } + + var hasOwnProperty = Object.prototype.hasOwnProperty; + /** + * Check whether the object has the property. + * + * @param {Object} obj + * @param {String} key + * @return {Boolean} + */ + + function hasOwn(obj, key) { + return hasOwnProperty.call(obj, key); + } + + /** + * Check if an expression is a literal value. + * + * @param {String} exp + * @return {Boolean} + */ + + var literalValueRE = /^\s?(true|false|-?[\d\.]+|'[^']*'|"[^"]*")\s?$/; + + function isLiteral(exp) { + return literalValueRE.test(exp); + } + + /** + * Check if a string starts with $ or _ + * + * @param {String} str + * @return {Boolean} + */ + + function isReserved(str) { + var c = (str + '').charCodeAt(0); + return c === 0x24 || c === 0x5F; + } + + /** + * Guard text output, make sure undefined outputs + * empty string + * + * @param {*} value + * @return {String} + */ + + function _toString(value) { + return value == null ? '' : value.toString(); + } + + /** + * Check and convert possible numeric strings to numbers + * before setting back to data + * + * @param {*} value + * @return {*|Number} + */ + + function toNumber(value) { + if (typeof value !== 'string') { + return value; + } else { + var parsed = Number(value); + return isNaN(parsed) ? value : parsed; + } + } + + /** + * Convert string boolean literals into real booleans. + * + * @param {*} value + * @return {*|Boolean} + */ + + function toBoolean(value) { + return value === 'true' ? true : value === 'false' ? false : value; + } + + /** + * Strip quotes from a string + * + * @param {String} str + * @return {String | false} + */ + + function stripQuotes(str) { + var a = str.charCodeAt(0); + var b = str.charCodeAt(str.length - 1); + return a === b && (a === 0x22 || a === 0x27) ? str.slice(1, -1) : str; + } + + /** + * Camelize a hyphen-delmited string. + * + * @param {String} str + * @return {String} + */ + + var camelizeRE = /-(\w)/g; + + function camelize(str) { + return str.replace(camelizeRE, toUpper); + } + + function toUpper(_, c) { + return c ? c.toUpperCase() : ''; + } + + /** + * Hyphenate a camelCase string. + * + * @param {String} str + * @return {String} + */ + + var hyphenateRE = /([a-z\d])([A-Z])/g; + + function hyphenate(str) { + return str.replace(hyphenateRE, '$1-$2').toLowerCase(); + } + + /** + * Converts hyphen/underscore/slash delimitered names into + * camelized classNames. + * + * e.g. my-component => MyComponent + * some_else => SomeElse + * some/comp => SomeComp + * + * @param {String} str + * @return {String} + */ + + var classifyRE = /(?:^|[-_\/])(\w)/g; + + function classify(str) { + return str.replace(classifyRE, toUpper); + } + + /** + * Simple bind, faster than native + * + * @param {Function} fn + * @param {Object} ctx + * @return {Function} + */ + + function bind(fn, ctx) { + return function (a) { + var l = arguments.length; + return l ? l > 1 ? fn.apply(ctx, arguments) : fn.call(ctx, a) : fn.call(ctx); + }; + } + + /** + * Convert an Array-like object to a real Array. + * + * @param {Array-like} list + * @param {Number} [start] - start index + * @return {Array} + */ + + function toArray(list, start) { + start = start || 0; + var i = list.length - start; + var ret = new Array(i); + while (i--) { + ret[i] = list[i + start]; + } + return ret; + } + + /** + * Mix properties into target object. + * + * @param {Object} to + * @param {Object} from + */ + + function extend(to, from) { + var keys = Object.keys(from); + var i = keys.length; + while (i--) { + to[keys[i]] = from[keys[i]]; + } + return to; + } + + /** + * Quick object check - this is primarily used to tell + * Objects from primitive values when we know the value + * is a JSON-compliant type. + * + * @param {*} obj + * @return {Boolean} + */ + + function isObject(obj) { + return obj !== null && typeof obj === 'object'; + } + + /** + * Strict object type check. Only returns true + * for plain JavaScript objects. + * + * @param {*} obj + * @return {Boolean} + */ + + var toString = Object.prototype.toString; + var OBJECT_STRING = '[object Object]'; + + function isPlainObject(obj) { + return toString.call(obj) === OBJECT_STRING; + } + + /** + * Array type check. + * + * @param {*} obj + * @return {Boolean} + */ + + var isArray = Array.isArray; + + /** + * Define a property. + * + * @param {Object} obj + * @param {String} key + * @param {*} val + * @param {Boolean} [enumerable] + */ + + function def(obj, key, val, enumerable) { + Object.defineProperty(obj, key, { + value: val, + enumerable: !!enumerable, + writable: true, + configurable: true + }); + } + + /** + * Debounce a function so it only gets called after the + * input stops arriving after the given wait period. + * + * @param {Function} func + * @param {Number} wait + * @return {Function} - the debounced function + */ + + function _debounce(func, wait) { + var timeout, args, context, timestamp, result; + var later = function later() { + var last = Date.now() - timestamp; + if (last < wait && last >= 0) { + timeout = setTimeout(later, wait - last); + } else { + timeout = null; + result = func.apply(context, args); + if (!timeout) context = args = null; + } + }; + return function () { + context = this; + args = arguments; + timestamp = Date.now(); + if (!timeout) { + timeout = setTimeout(later, wait); + } + return result; + }; + } + + /** + * Manual indexOf because it's slightly faster than + * native. + * + * @param {Array} arr + * @param {*} obj + */ + + function indexOf(arr, obj) { + var i = arr.length; + while (i--) { + if (arr[i] === obj) return i; + } + return -1; + } + + /** + * Make a cancellable version of an async callback. + * + * @param {Function} fn + * @return {Function} + */ + + function cancellable(fn) { + var cb = function cb() { + if (!cb.cancelled) { + return fn.apply(this, arguments); + } + }; + cb.cancel = function () { + cb.cancelled = true; + }; + return cb; + } + + /** + * Check if two values are loosely equal - that is, + * if they are plain objects, do they have the same shape? + * + * @param {*} a + * @param {*} b + * @return {Boolean} + */ + + function looseEqual(a, b) { + /* eslint-disable eqeqeq */ + return a == b || (isObject(a) && isObject(b) ? JSON.stringify(a) === JSON.stringify(b) : false); + /* eslint-enable eqeqeq */ + } + + var hasProto = ('__proto__' in {}); + + // Browser environment sniffing + var inBrowser = typeof window !== 'undefined' && Object.prototype.toString.call(window) !== '[object Object]'; + + // detect devtools + var devtools = inBrowser && window.__VUE_DEVTOOLS_GLOBAL_HOOK__; + + // UA sniffing for working around browser-specific quirks + var UA = inBrowser && window.navigator.userAgent.toLowerCase(); + var isIE = UA && UA.indexOf('trident') > 0; + var isIE9 = UA && UA.indexOf('msie 9.0') > 0; + var isAndroid = UA && UA.indexOf('android') > 0; + var isIos = UA && /(iphone|ipad|ipod|ios)/i.test(UA); + var iosVersionMatch = isIos && UA.match(/os ([\d_]+)/); + var iosVersion = iosVersionMatch && iosVersionMatch[1].split('_'); + + // detecting iOS UIWebView by indexedDB + var hasMutationObserverBug = iosVersion && Number(iosVersion[0]) >= 9 && Number(iosVersion[1]) >= 3 && !window.indexedDB; + + var transitionProp = undefined; + var transitionEndEvent = undefined; + var animationProp = undefined; + var animationEndEvent = undefined; + + // Transition property/event sniffing + if (inBrowser && !isIE9) { + var isWebkitTrans = window.ontransitionend === undefined && window.onwebkittransitionend !== undefined; + var isWebkitAnim = window.onanimationend === undefined && window.onwebkitanimationend !== undefined; + transitionProp = isWebkitTrans ? 'WebkitTransition' : 'transition'; + transitionEndEvent = isWebkitTrans ? 'webkitTransitionEnd' : 'transitionend'; + animationProp = isWebkitAnim ? 'WebkitAnimation' : 'animation'; + animationEndEvent = isWebkitAnim ? 'webkitAnimationEnd' : 'animationend'; + } + + /** + * Defer a task to execute it asynchronously. Ideally this + * should be executed as a microtask, so we leverage + * MutationObserver if it's available, and fallback to + * setTimeout(0). + * + * @param {Function} cb + * @param {Object} ctx + */ + + var nextTick = (function () { + var callbacks = []; + var pending = false; + var timerFunc; + function nextTickHandler() { + pending = false; + var copies = callbacks.slice(0); + callbacks = []; + for (var i = 0; i < copies.length; i++) { + copies[i](); + } + } + + /* istanbul ignore if */ + if (typeof MutationObserver !== 'undefined' && !hasMutationObserverBug) { + var counter = 1; + var observer = new MutationObserver(nextTickHandler); + var textNode = document.createTextNode(counter); + observer.observe(textNode, { + characterData: true + }); + timerFunc = function () { + counter = (counter + 1) % 2; + textNode.data = counter; + }; + } else { + // webpack attempts to inject a shim for setImmediate + // if it is used as a global, so we have to work around that to + // avoid bundling unnecessary code. + var context = inBrowser ? window : typeof global !== 'undefined' ? global : {}; + timerFunc = context.setImmediate || setTimeout; + } + return function (cb, ctx) { + var func = ctx ? function () { + cb.call(ctx); + } : cb; + callbacks.push(func); + if (pending) return; + pending = true; + timerFunc(nextTickHandler, 0); + }; + })(); + + var _Set = undefined; + /* istanbul ignore if */ + if (typeof Set !== 'undefined' && Set.toString().match(/native code/)) { + // use native Set when available. + _Set = Set; + } else { + // a non-standard Set polyfill that only works with primitive keys. + _Set = function () { + this.set = Object.create(null); + }; + _Set.prototype.has = function (key) { + return this.set[key] !== undefined; + }; + _Set.prototype.add = function (key) { + this.set[key] = 1; + }; + _Set.prototype.clear = function () { + this.set = Object.create(null); + }; + } + + function Cache(limit) { + this.size = 0; + this.limit = limit; + this.head = this.tail = undefined; + this._keymap = Object.create(null); + } + + var p = Cache.prototype; + + /** + * Put into the cache associated with . + * Returns the entry which was removed to make room for + * the new entry. Otherwise undefined is returned. + * (i.e. if there was enough room already). + * + * @param {String} key + * @param {*} value + * @return {Entry|undefined} + */ + + p.put = function (key, value) { + var removed; + + var entry = this.get(key, true); + if (!entry) { + if (this.size === this.limit) { + removed = this.shift(); + } + entry = { + key: key + }; + this._keymap[key] = entry; + if (this.tail) { + this.tail.newer = entry; + entry.older = this.tail; + } else { + this.head = entry; + } + this.tail = entry; + this.size++; + } + entry.value = value; + + return removed; + }; + + /** + * Purge the least recently used (oldest) entry from the + * cache. Returns the removed entry or undefined if the + * cache was empty. + */ + + p.shift = function () { + var entry = this.head; + if (entry) { + this.head = this.head.newer; + this.head.older = undefined; + entry.newer = entry.older = undefined; + this._keymap[entry.key] = undefined; + this.size--; + } + return entry; + }; + + /** + * Get and register recent use of . Returns the value + * associated with or undefined if not in cache. + * + * @param {String} key + * @param {Boolean} returnEntry + * @return {Entry|*} + */ + + p.get = function (key, returnEntry) { + var entry = this._keymap[key]; + if (entry === undefined) return; + if (entry === this.tail) { + return returnEntry ? entry : entry.value; + } + // HEAD--------------TAIL + // <.older .newer> + // <--- add direction -- + // A B C E + if (entry.newer) { + if (entry === this.head) { + this.head = entry.newer; + } + entry.newer.older = entry.older; // C <-- E. + } + if (entry.older) { + entry.older.newer = entry.newer; // C. --> E + } + entry.newer = undefined; // D --x + entry.older = this.tail; // D. --> E + if (this.tail) { + this.tail.newer = entry; // E. <-- D + } + this.tail = entry; + return returnEntry ? entry : entry.value; + }; + + var cache$1 = new Cache(1000); + var filterTokenRE = /[^\s'"]+|'[^']*'|"[^"]*"/g; + var reservedArgRE = /^in$|^-?\d+/; + + /** + * Parser state + */ + + var str; + var dir; + var c; + var prev; + var i; + var l; + var lastFilterIndex; + var inSingle; + var inDouble; + var curly; + var square; + var paren; + /** + * Push a filter to the current directive object + */ + + function pushFilter() { + var exp = str.slice(lastFilterIndex, i).trim(); + var filter; + if (exp) { + filter = {}; + var tokens = exp.match(filterTokenRE); + filter.name = tokens[0]; + if (tokens.length > 1) { + filter.args = tokens.slice(1).map(processFilterArg); + } + } + if (filter) { + (dir.filters = dir.filters || []).push(filter); + } + lastFilterIndex = i + 1; + } + + /** + * Check if an argument is dynamic and strip quotes. + * + * @param {String} arg + * @return {Object} + */ + + function processFilterArg(arg) { + if (reservedArgRE.test(arg)) { + return { + value: toNumber(arg), + dynamic: false + }; + } else { + var stripped = stripQuotes(arg); + var dynamic = stripped === arg; + return { + value: dynamic ? arg : stripped, + dynamic: dynamic + }; + } + } + + /** + * Parse a directive value and extract the expression + * and its filters into a descriptor. + * + * Example: + * + * "a + 1 | uppercase" will yield: + * { + * expression: 'a + 1', + * filters: [ + * { name: 'uppercase', args: null } + * ] + * } + * + * @param {String} s + * @return {Object} + */ + + function parseDirective(s) { + var hit = cache$1.get(s); + if (hit) { + return hit; + } + + // reset parser state + str = s; + inSingle = inDouble = false; + curly = square = paren = 0; + lastFilterIndex = 0; + dir = {}; + + for (i = 0, l = str.length; i < l; i++) { + prev = c; + c = str.charCodeAt(i); + if (inSingle) { + // check single quote + if (c === 0x27 && prev !== 0x5C) inSingle = !inSingle; + } else if (inDouble) { + // check double quote + if (c === 0x22 && prev !== 0x5C) inDouble = !inDouble; + } else if (c === 0x7C && // pipe + str.charCodeAt(i + 1) !== 0x7C && str.charCodeAt(i - 1) !== 0x7C) { + if (dir.expression == null) { + // first filter, end of expression + lastFilterIndex = i + 1; + dir.expression = str.slice(0, i).trim(); + } else { + // already has filter + pushFilter(); + } + } else { + switch (c) { + case 0x22: + inDouble = true;break; // " + case 0x27: + inSingle = true;break; // ' + case 0x28: + paren++;break; // ( + case 0x29: + paren--;break; // ) + case 0x5B: + square++;break; // [ + case 0x5D: + square--;break; // ] + case 0x7B: + curly++;break; // { + case 0x7D: + curly--;break; // } + } + } + } + + if (dir.expression == null) { + dir.expression = str.slice(0, i).trim(); + } else if (lastFilterIndex !== 0) { + pushFilter(); + } + + cache$1.put(s, dir); + return dir; + } + +var directive = Object.freeze({ + parseDirective: parseDirective + }); + + var regexEscapeRE = /[-.*+?^${}()|[\]\/\\]/g; + var cache = undefined; + var tagRE = undefined; + var htmlRE = undefined; + /** + * Escape a string so it can be used in a RegExp + * constructor. + * + * @param {String} str + */ + + function escapeRegex(str) { + return str.replace(regexEscapeRE, '\\$&'); + } + + function compileRegex() { + var open = escapeRegex(config.delimiters[0]); + var close = escapeRegex(config.delimiters[1]); + var unsafeOpen = escapeRegex(config.unsafeDelimiters[0]); + var unsafeClose = escapeRegex(config.unsafeDelimiters[1]); + tagRE = new RegExp(unsafeOpen + '((?:.|\\n)+?)' + unsafeClose + '|' + open + '((?:.|\\n)+?)' + close, 'g'); + htmlRE = new RegExp('^' + unsafeOpen + '((?:.|\\n)+?)' + unsafeClose + '$'); + // reset cache + cache = new Cache(1000); + } + + /** + * Parse a template text string into an array of tokens. + * + * @param {String} text + * @return {Array | null} + * - {String} type + * - {String} value + * - {Boolean} [html] + * - {Boolean} [oneTime] + */ + + function parseText(text) { + if (!cache) { + compileRegex(); + } + var hit = cache.get(text); + if (hit) { + return hit; + } + if (!tagRE.test(text)) { + return null; + } + var tokens = []; + var lastIndex = tagRE.lastIndex = 0; + var match, index, html, value, first, oneTime; + /* eslint-disable no-cond-assign */ + while (match = tagRE.exec(text)) { + /* eslint-enable no-cond-assign */ + index = match.index; + // push text token + if (index > lastIndex) { + tokens.push({ + value: text.slice(lastIndex, index) + }); + } + // tag token + html = htmlRE.test(match[0]); + value = html ? match[1] : match[2]; + first = value.charCodeAt(0); + oneTime = first === 42; // * + value = oneTime ? value.slice(1) : value; + tokens.push({ + tag: true, + value: value.trim(), + html: html, + oneTime: oneTime + }); + lastIndex = index + match[0].length; + } + if (lastIndex < text.length) { + tokens.push({ + value: text.slice(lastIndex) + }); + } + cache.put(text, tokens); + return tokens; + } + + /** + * Format a list of tokens into an expression. + * e.g. tokens parsed from 'a {{b}} c' can be serialized + * into one single expression as '"a " + b + " c"'. + * + * @param {Array} tokens + * @param {Vue} [vm] + * @return {String} + */ + + function tokensToExp(tokens, vm) { + if (tokens.length > 1) { + return tokens.map(function (token) { + return formatToken(token, vm); + }).join('+'); + } else { + return formatToken(tokens[0], vm, true); + } + } + + /** + * Format a single token. + * + * @param {Object} token + * @param {Vue} [vm] + * @param {Boolean} [single] + * @return {String} + */ + + function formatToken(token, vm, single) { + return token.tag ? token.oneTime && vm ? '"' + vm.$eval(token.value) + '"' : inlineFilters(token.value, single) : '"' + token.value + '"'; + } + + /** + * For an attribute with multiple interpolation tags, + * e.g. attr="some-{{thing | filter}}", in order to combine + * the whole thing into a single watchable expression, we + * have to inline those filters. This function does exactly + * that. This is a bit hacky but it avoids heavy changes + * to directive parser and watcher mechanism. + * + * @param {String} exp + * @param {Boolean} single + * @return {String} + */ + + var filterRE = /[^|]\|[^|]/; + function inlineFilters(exp, single) { + if (!filterRE.test(exp)) { + return single ? exp : '(' + exp + ')'; + } else { + var dir = parseDirective(exp); + if (!dir.filters) { + return '(' + exp + ')'; + } else { + return 'this._applyFilters(' + dir.expression + // value + ',null,' + // oldValue (null for read) + JSON.stringify(dir.filters) + // filter descriptors + ',false)'; // write? + } + } + } + +var text = Object.freeze({ + compileRegex: compileRegex, + parseText: parseText, + tokensToExp: tokensToExp + }); + + var delimiters = ['{{', '}}']; + var unsafeDelimiters = ['{{{', '}}}']; + + var config = Object.defineProperties({ + + /** + * Whether to print debug messages. + * Also enables stack trace for warnings. + * + * @type {Boolean} + */ + + debug: false, + + /** + * Whether to suppress warnings. + * + * @type {Boolean} + */ + + silent: false, + + /** + * Whether to use async rendering. + */ + + async: true, + + /** + * Whether to warn against errors caught when evaluating + * expressions. + */ + + warnExpressionErrors: true, + + /** + * Whether to allow devtools inspection. + * Disabled by default in production builds. + */ + + devtools: 'development' !== 'production', + + /** + * Internal flag to indicate the delimiters have been + * changed. + * + * @type {Boolean} + */ + + _delimitersChanged: true, + + /** + * List of asset types that a component can own. + * + * @type {Array} + */ + + _assetTypes: ['component', 'directive', 'elementDirective', 'filter', 'transition', 'partial'], + + /** + * prop binding modes + */ + + _propBindingModes: { + ONE_WAY: 0, + TWO_WAY: 1, + ONE_TIME: 2 + }, + + /** + * Max circular updates allowed in a batcher flush cycle. + */ + + _maxUpdateCount: 100 + + }, { + delimiters: { /** + * Interpolation delimiters. Changing these would trigger + * the text parser to re-compile the regular expressions. + * + * @type {Array} + */ + + get: function get() { + return delimiters; + }, + set: function set(val) { + delimiters = val; + compileRegex(); + }, + configurable: true, + enumerable: true + }, + unsafeDelimiters: { + get: function get() { + return unsafeDelimiters; + }, + set: function set(val) { + unsafeDelimiters = val; + compileRegex(); + }, + configurable: true, + enumerable: true + } + }); + + var warn = undefined; + var formatComponentName = undefined; + + if ('development' !== 'production') { + (function () { + var hasConsole = typeof console !== 'undefined'; + + warn = function (msg, vm) { + if (hasConsole && !config.silent) { + console.error('[Vue warn]: ' + msg + (vm ? formatComponentName(vm) : '')); + } + }; + + formatComponentName = function (vm) { + var name = vm._isVue ? vm.$options.name : vm.name; + return name ? ' (found in component: <' + hyphenate(name) + '>)' : ''; + }; + })(); + } + + /** + * Append with transition. + * + * @param {Element} el + * @param {Element} target + * @param {Vue} vm + * @param {Function} [cb] + */ + + function appendWithTransition(el, target, vm, cb) { + applyTransition(el, 1, function () { + target.appendChild(el); + }, vm, cb); + } + + /** + * InsertBefore with transition. + * + * @param {Element} el + * @param {Element} target + * @param {Vue} vm + * @param {Function} [cb] + */ + + function beforeWithTransition(el, target, vm, cb) { + applyTransition(el, 1, function () { + before(el, target); + }, vm, cb); + } + + /** + * Remove with transition. + * + * @param {Element} el + * @param {Vue} vm + * @param {Function} [cb] + */ + + function removeWithTransition(el, vm, cb) { + applyTransition(el, -1, function () { + remove(el); + }, vm, cb); + } + + /** + * Apply transitions with an operation callback. + * + * @param {Element} el + * @param {Number} direction + * 1: enter + * -1: leave + * @param {Function} op - the actual DOM operation + * @param {Vue} vm + * @param {Function} [cb] + */ + + function applyTransition(el, direction, op, vm, cb) { + var transition = el.__v_trans; + if (!transition || + // skip if there are no js hooks and CSS transition is + // not supported + !transition.hooks && !transitionEndEvent || + // skip transitions for initial compile + !vm._isCompiled || + // if the vm is being manipulated by a parent directive + // during the parent's compilation phase, skip the + // animation. + vm.$parent && !vm.$parent._isCompiled) { + op(); + if (cb) cb(); + return; + } + var action = direction > 0 ? 'enter' : 'leave'; + transition[action](op, cb); + } + +var transition = Object.freeze({ + appendWithTransition: appendWithTransition, + beforeWithTransition: beforeWithTransition, + removeWithTransition: removeWithTransition, + applyTransition: applyTransition + }); + + /** + * Query an element selector if it's not an element already. + * + * @param {String|Element} el + * @return {Element} + */ + + function query(el) { + if (typeof el === 'string') { + var selector = el; + el = document.querySelector(el); + if (!el) { + 'development' !== 'production' && warn('Cannot find element: ' + selector); + } + } + return el; + } + + /** + * Check if a node is in the document. + * Note: document.documentElement.contains should work here + * but always returns false for comment nodes in phantomjs, + * making unit tests difficult. This is fixed by doing the + * contains() check on the node's parentNode instead of + * the node itself. + * + * @param {Node} node + * @return {Boolean} + */ + + function inDoc(node) { + if (!node) return false; + var doc = node.ownerDocument.documentElement; + var parent = node.parentNode; + return doc === node || doc === parent || !!(parent && parent.nodeType === 1 && doc.contains(parent)); + } + + /** + * Get and remove an attribute from a node. + * + * @param {Node} node + * @param {String} _attr + */ + + function getAttr(node, _attr) { + var val = node.getAttribute(_attr); + if (val !== null) { + node.removeAttribute(_attr); + } + return val; + } + + /** + * Get an attribute with colon or v-bind: prefix. + * + * @param {Node} node + * @param {String} name + * @return {String|null} + */ + + function getBindAttr(node, name) { + var val = getAttr(node, ':' + name); + if (val === null) { + val = getAttr(node, 'v-bind:' + name); + } + return val; + } + + /** + * Check the presence of a bind attribute. + * + * @param {Node} node + * @param {String} name + * @return {Boolean} + */ + + function hasBindAttr(node, name) { + return node.hasAttribute(name) || node.hasAttribute(':' + name) || node.hasAttribute('v-bind:' + name); + } + + /** + * Insert el before target + * + * @param {Element} el + * @param {Element} target + */ + + function before(el, target) { + target.parentNode.insertBefore(el, target); + } + + /** + * Insert el after target + * + * @param {Element} el + * @param {Element} target + */ + + function after(el, target) { + if (target.nextSibling) { + before(el, target.nextSibling); + } else { + target.parentNode.appendChild(el); + } + } + + /** + * Remove el from DOM + * + * @param {Element} el + */ + + function remove(el) { + el.parentNode.removeChild(el); + } + + /** + * Prepend el to target + * + * @param {Element} el + * @param {Element} target + */ + + function prepend(el, target) { + if (target.firstChild) { + before(el, target.firstChild); + } else { + target.appendChild(el); + } + } + + /** + * Replace target with el + * + * @param {Element} target + * @param {Element} el + */ + + function replace(target, el) { + var parent = target.parentNode; + if (parent) { + parent.replaceChild(el, target); + } + } + + /** + * Add event listener shorthand. + * + * @param {Element} el + * @param {String} event + * @param {Function} cb + * @param {Boolean} [useCapture] + */ + + function on(el, event, cb, useCapture) { + el.addEventListener(event, cb, useCapture); + } + + /** + * Remove event listener shorthand. + * + * @param {Element} el + * @param {String} event + * @param {Function} cb + */ + + function off(el, event, cb) { + el.removeEventListener(event, cb); + } + + /** + * For IE9 compat: when both class and :class are present + * getAttribute('class') returns wrong value... + * + * @param {Element} el + * @return {String} + */ + + function getClass(el) { + var classname = el.className; + if (typeof classname === 'object') { + classname = classname.baseVal || ''; + } + return classname; + } + + /** + * In IE9, setAttribute('class') will result in empty class + * if the element also has the :class attribute; However in + * PhantomJS, setting `className` does not work on SVG elements... + * So we have to do a conditional check here. + * + * @param {Element} el + * @param {String} cls + */ + + function setClass(el, cls) { + /* istanbul ignore if */ + if (isIE9 && !/svg$/.test(el.namespaceURI)) { + el.className = cls; + } else { + el.setAttribute('class', cls); + } + } + + /** + * Add class with compatibility for IE & SVG + * + * @param {Element} el + * @param {String} cls + */ + + function addClass(el, cls) { + if (el.classList) { + el.classList.add(cls); + } else { + var cur = ' ' + getClass(el) + ' '; + if (cur.indexOf(' ' + cls + ' ') < 0) { + setClass(el, (cur + cls).trim()); + } + } + } + + /** + * Remove class with compatibility for IE & SVG + * + * @param {Element} el + * @param {String} cls + */ + + function removeClass(el, cls) { + if (el.classList) { + el.classList.remove(cls); + } else { + var cur = ' ' + getClass(el) + ' '; + var tar = ' ' + cls + ' '; + while (cur.indexOf(tar) >= 0) { + cur = cur.replace(tar, ' '); + } + setClass(el, cur.trim()); + } + if (!el.className) { + el.removeAttribute('class'); + } + } + + /** + * Extract raw content inside an element into a temporary + * container div + * + * @param {Element} el + * @param {Boolean} asFragment + * @return {Element|DocumentFragment} + */ + + function extractContent(el, asFragment) { + var child; + var rawContent; + /* istanbul ignore if */ + if (isTemplate(el) && isFragment(el.content)) { + el = el.content; + } + if (el.hasChildNodes()) { + trimNode(el); + rawContent = asFragment ? document.createDocumentFragment() : document.createElement('div'); + /* eslint-disable no-cond-assign */ + while (child = el.firstChild) { + /* eslint-enable no-cond-assign */ + rawContent.appendChild(child); + } + } + return rawContent; + } + + /** + * Trim possible empty head/tail text and comment + * nodes inside a parent. + * + * @param {Node} node + */ + + function trimNode(node) { + var child; + /* eslint-disable no-sequences */ + while ((child = node.firstChild, isTrimmable(child))) { + node.removeChild(child); + } + while ((child = node.lastChild, isTrimmable(child))) { + node.removeChild(child); + } + /* eslint-enable no-sequences */ + } + + function isTrimmable(node) { + return node && (node.nodeType === 3 && !node.data.trim() || node.nodeType === 8); + } + + /** + * Check if an element is a template tag. + * Note if the template appears inside an SVG its tagName + * will be in lowercase. + * + * @param {Element} el + */ + + function isTemplate(el) { + return el.tagName && el.tagName.toLowerCase() === 'template'; + } + + /** + * Create an "anchor" for performing dom insertion/removals. + * This is used in a number of scenarios: + * - fragment instance + * - v-html + * - v-if + * - v-for + * - component + * + * @param {String} content + * @param {Boolean} persist - IE trashes empty textNodes on + * cloneNode(true), so in certain + * cases the anchor needs to be + * non-empty to be persisted in + * templates. + * @return {Comment|Text} + */ + + function createAnchor(content, persist) { + var anchor = config.debug ? document.createComment(content) : document.createTextNode(persist ? ' ' : ''); + anchor.__v_anchor = true; + return anchor; + } + + /** + * Find a component ref attribute that starts with $. + * + * @param {Element} node + * @return {String|undefined} + */ + + var refRE = /^v-ref:/; + + function findRef(node) { + if (node.hasAttributes()) { + var attrs = node.attributes; + for (var i = 0, l = attrs.length; i < l; i++) { + var name = attrs[i].name; + if (refRE.test(name)) { + return camelize(name.replace(refRE, '')); + } + } + } + } + + /** + * Map a function to a range of nodes . + * + * @param {Node} node + * @param {Node} end + * @param {Function} op + */ + + function mapNodeRange(node, end, op) { + var next; + while (node !== end) { + next = node.nextSibling; + op(node); + node = next; + } + op(end); + } + + /** + * Remove a range of nodes with transition, store + * the nodes in a fragment with correct ordering, + * and call callback when done. + * + * @param {Node} start + * @param {Node} end + * @param {Vue} vm + * @param {DocumentFragment} frag + * @param {Function} cb + */ + + function removeNodeRange(start, end, vm, frag, cb) { + var done = false; + var removed = 0; + var nodes = []; + mapNodeRange(start, end, function (node) { + if (node === end) done = true; + nodes.push(node); + removeWithTransition(node, vm, onRemoved); + }); + function onRemoved() { + removed++; + if (done && removed >= nodes.length) { + for (var i = 0; i < nodes.length; i++) { + frag.appendChild(nodes[i]); + } + cb && cb(); + } + } + } + + /** + * Check if a node is a DocumentFragment. + * + * @param {Node} node + * @return {Boolean} + */ + + function isFragment(node) { + return node && node.nodeType === 11; + } + + /** + * Get outerHTML of elements, taking care + * of SVG elements in IE as well. + * + * @param {Element} el + * @return {String} + */ + + function getOuterHTML(el) { + if (el.outerHTML) { + return el.outerHTML; + } else { + var container = document.createElement('div'); + container.appendChild(el.cloneNode(true)); + return container.innerHTML; + } + } + + var commonTagRE = /^(div|p|span|img|a|b|i|br|ul|ol|li|h1|h2|h3|h4|h5|h6|code|pre|table|th|td|tr|form|label|input|select|option|nav|article|section|header|footer)$/i; + var reservedTagRE = /^(slot|partial|component)$/i; + + var isUnknownElement = undefined; + if ('development' !== 'production') { + isUnknownElement = function (el, tag) { + if (tag.indexOf('-') > -1) { + // http://stackoverflow.com/a/28210364/1070244 + return el.constructor === window.HTMLUnknownElement || el.constructor === window.HTMLElement; + } else { + return (/HTMLUnknownElement/.test(el.toString()) && + // Chrome returns unknown for several HTML5 elements. + // https://code.google.com/p/chromium/issues/detail?id=540526 + // Firefox returns unknown for some "Interactive elements." + !/^(data|time|rtc|rb|details|dialog|summary)$/.test(tag) + ); + } + }; + } + + /** + * Check if an element is a component, if yes return its + * component id. + * + * @param {Element} el + * @param {Object} options + * @return {Object|undefined} + */ + + function checkComponentAttr(el, options) { + var tag = el.tagName.toLowerCase(); + var hasAttrs = el.hasAttributes(); + if (!commonTagRE.test(tag) && !reservedTagRE.test(tag)) { + if (resolveAsset(options, 'components', tag)) { + return { id: tag }; + } else { + var is = hasAttrs && getIsBinding(el, options); + if (is) { + return is; + } else if ('development' !== 'production') { + var expectedTag = options._componentNameMap && options._componentNameMap[tag]; + if (expectedTag) { + warn('Unknown custom element: <' + tag + '> - ' + 'did you mean <' + expectedTag + '>? ' + 'HTML is case-insensitive, remember to use kebab-case in templates.'); + } else if (isUnknownElement(el, tag)) { + warn('Unknown custom element: <' + tag + '> - did you ' + 'register the component correctly? For recursive components, ' + 'make sure to provide the "name" option.'); + } + } + } + } else if (hasAttrs) { + return getIsBinding(el, options); + } + } + + /** + * Get "is" binding from an element. + * + * @param {Element} el + * @param {Object} options + * @return {Object|undefined} + */ + + function getIsBinding(el, options) { + // dynamic syntax + var exp = el.getAttribute('is'); + if (exp != null) { + if (resolveAsset(options, 'components', exp)) { + el.removeAttribute('is'); + return { id: exp }; + } + } else { + exp = getBindAttr(el, 'is'); + if (exp != null) { + return { id: exp, dynamic: true }; + } + } + } + + /** + * Option overwriting strategies are functions that handle + * how to merge a parent option value and a child option + * value into the final value. + * + * All strategy functions follow the same signature: + * + * @param {*} parentVal + * @param {*} childVal + * @param {Vue} [vm] + */ + + var strats = config.optionMergeStrategies = Object.create(null); + + /** + * Helper that recursively merges two data objects together. + */ + + function mergeData(to, from) { + var key, toVal, fromVal; + for (key in from) { + toVal = to[key]; + fromVal = from[key]; + if (!hasOwn(to, key)) { + set(to, key, fromVal); + } else if (isObject(toVal) && isObject(fromVal)) { + mergeData(toVal, fromVal); + } + } + return to; + } + + /** + * Data + */ + + strats.data = function (parentVal, childVal, vm) { + if (!vm) { + // in a Vue.extend merge, both should be functions + if (!childVal) { + return parentVal; + } + if (typeof childVal !== 'function') { + 'development' !== 'production' && warn('The "data" option should be a function ' + 'that returns a per-instance value in component ' + 'definitions.', vm); + return parentVal; + } + if (!parentVal) { + return childVal; + } + // when parentVal & childVal are both present, + // we need to return a function that returns the + // merged result of both functions... no need to + // check if parentVal is a function here because + // it has to be a function to pass previous merges. + return function mergedDataFn() { + return mergeData(childVal.call(this), parentVal.call(this)); + }; + } else if (parentVal || childVal) { + return function mergedInstanceDataFn() { + // instance merge + var instanceData = typeof childVal === 'function' ? childVal.call(vm) : childVal; + var defaultData = typeof parentVal === 'function' ? parentVal.call(vm) : undefined; + if (instanceData) { + return mergeData(instanceData, defaultData); + } else { + return defaultData; + } + }; + } + }; + + /** + * El + */ + + strats.el = function (parentVal, childVal, vm) { + if (!vm && childVal && typeof childVal !== 'function') { + 'development' !== 'production' && warn('The "el" option should be a function ' + 'that returns a per-instance value in component ' + 'definitions.', vm); + return; + } + var ret = childVal || parentVal; + // invoke the element factory if this is instance merge + return vm && typeof ret === 'function' ? ret.call(vm) : ret; + }; + + /** + * Hooks and param attributes are merged as arrays. + */ + + strats.init = strats.created = strats.ready = strats.attached = strats.detached = strats.beforeCompile = strats.compiled = strats.beforeDestroy = strats.destroyed = strats.activate = function (parentVal, childVal) { + return childVal ? parentVal ? parentVal.concat(childVal) : isArray(childVal) ? childVal : [childVal] : parentVal; + }; + + /** + * Assets + * + * When a vm is present (instance creation), we need to do + * a three-way merge between constructor options, instance + * options and parent options. + */ + + function mergeAssets(parentVal, childVal) { + var res = Object.create(parentVal || null); + return childVal ? extend(res, guardArrayAssets(childVal)) : res; + } + + config._assetTypes.forEach(function (type) { + strats[type + 's'] = mergeAssets; + }); + + /** + * Events & Watchers. + * + * Events & watchers hashes should not overwrite one + * another, so we merge them as arrays. + */ + + strats.watch = strats.events = function (parentVal, childVal) { + if (!childVal) return parentVal; + if (!parentVal) return childVal; + var ret = {}; + extend(ret, parentVal); + for (var key in childVal) { + var parent = ret[key]; + var child = childVal[key]; + if (parent && !isArray(parent)) { + parent = [parent]; + } + ret[key] = parent ? parent.concat(child) : [child]; + } + return ret; + }; + + /** + * Other object hashes. + */ + + strats.props = strats.methods = strats.computed = function (parentVal, childVal) { + if (!childVal) return parentVal; + if (!parentVal) return childVal; + var ret = Object.create(null); + extend(ret, parentVal); + extend(ret, childVal); + return ret; + }; + + /** + * Default strategy. + */ + + var defaultStrat = function defaultStrat(parentVal, childVal) { + return childVal === undefined ? parentVal : childVal; + }; + + /** + * Make sure component options get converted to actual + * constructors. + * + * @param {Object} options + */ + + function guardComponents(options) { + if (options.components) { + var components = options.components = guardArrayAssets(options.components); + var ids = Object.keys(components); + var def; + if ('development' !== 'production') { + var map = options._componentNameMap = {}; + } + for (var i = 0, l = ids.length; i < l; i++) { + var key = ids[i]; + if (commonTagRE.test(key) || reservedTagRE.test(key)) { + 'development' !== 'production' && warn('Do not use built-in or reserved HTML elements as component ' + 'id: ' + key); + continue; + } + // record a all lowercase <-> kebab-case mapping for + // possible custom element case error warning + if ('development' !== 'production') { + map[key.replace(/-/g, '').toLowerCase()] = hyphenate(key); + } + def = components[key]; + if (isPlainObject(def)) { + components[key] = Vue.extend(def); + } + } + } + } + + /** + * Ensure all props option syntax are normalized into the + * Object-based format. + * + * @param {Object} options + */ + + function guardProps(options) { + var props = options.props; + var i, val; + if (isArray(props)) { + options.props = {}; + i = props.length; + while (i--) { + val = props[i]; + if (typeof val === 'string') { + options.props[val] = null; + } else if (val.name) { + options.props[val.name] = val; + } + } + } else if (isPlainObject(props)) { + var keys = Object.keys(props); + i = keys.length; + while (i--) { + val = props[keys[i]]; + if (typeof val === 'function') { + props[keys[i]] = { type: val }; + } + } + } + } + + /** + * Guard an Array-format assets option and converted it + * into the key-value Object format. + * + * @param {Object|Array} assets + * @return {Object} + */ + + function guardArrayAssets(assets) { + if (isArray(assets)) { + var res = {}; + var i = assets.length; + var asset; + while (i--) { + asset = assets[i]; + var id = typeof asset === 'function' ? asset.options && asset.options.name || asset.id : asset.name || asset.id; + if (!id) { + 'development' !== 'production' && warn('Array-syntax assets must provide a "name" or "id" field.'); + } else { + res[id] = asset; + } + } + return res; + } + return assets; + } + + /** + * Merge two option objects into a new one. + * Core utility used in both instantiation and inheritance. + * + * @param {Object} parent + * @param {Object} child + * @param {Vue} [vm] - if vm is present, indicates this is + * an instantiation merge. + */ + + function mergeOptions(parent, child, vm) { + guardComponents(child); + guardProps(child); + if ('development' !== 'production') { + if (child.propsData && !vm) { + warn('propsData can only be used as an instantiation option.'); + } + } + var options = {}; + var key; + if (child['extends']) { + parent = typeof child['extends'] === 'function' ? mergeOptions(parent, child['extends'].options, vm) : mergeOptions(parent, child['extends'], vm); + } + if (child.mixins) { + for (var i = 0, l = child.mixins.length; i < l; i++) { + var mixin = child.mixins[i]; + var mixinOptions = mixin.prototype instanceof Vue ? mixin.options : mixin; + parent = mergeOptions(parent, mixinOptions, vm); + } + } + for (key in parent) { + mergeField(key); + } + for (key in child) { + if (!hasOwn(parent, key)) { + mergeField(key); + } + } + function mergeField(key) { + var strat = strats[key] || defaultStrat; + options[key] = strat(parent[key], child[key], vm, key); + } + return options; + } + + /** + * Resolve an asset. + * This function is used because child instances need access + * to assets defined in its ancestor chain. + * + * @param {Object} options + * @param {String} type + * @param {String} id + * @param {Boolean} warnMissing + * @return {Object|Function} + */ + + function resolveAsset(options, type, id, warnMissing) { + /* istanbul ignore if */ + if (typeof id !== 'string') { + return; + } + var assets = options[type]; + var camelizedId; + var res = assets[id] || + // camelCase ID + assets[camelizedId = camelize(id)] || + // Pascal Case ID + assets[camelizedId.charAt(0).toUpperCase() + camelizedId.slice(1)]; + if ('development' !== 'production' && warnMissing && !res) { + warn('Failed to resolve ' + type.slice(0, -1) + ': ' + id, options); + } + return res; + } + + var uid$1 = 0; + + /** + * A dep is an observable that can have multiple + * directives subscribing to it. + * + * @constructor + */ + function Dep() { + this.id = uid$1++; + this.subs = []; + } + + // the current target watcher being evaluated. + // this is globally unique because there could be only one + // watcher being evaluated at any time. + Dep.target = null; + + /** + * Add a directive subscriber. + * + * @param {Directive} sub + */ + + Dep.prototype.addSub = function (sub) { + this.subs.push(sub); + }; + + /** + * Remove a directive subscriber. + * + * @param {Directive} sub + */ + + Dep.prototype.removeSub = function (sub) { + this.subs.$remove(sub); + }; + + /** + * Add self as a dependency to the target watcher. + */ + + Dep.prototype.depend = function () { + Dep.target.addDep(this); + }; + + /** + * Notify all subscribers of a new value. + */ + + Dep.prototype.notify = function () { + // stablize the subscriber list first + var subs = toArray(this.subs); + for (var i = 0, l = subs.length; i < l; i++) { + subs[i].update(); + } + }; + + var arrayProto = Array.prototype; + var arrayMethods = Object.create(arrayProto) + + /** + * Intercept mutating methods and emit events + */ + + ;['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse'].forEach(function (method) { + // cache original method + var original = arrayProto[method]; + def(arrayMethods, method, function mutator() { + // avoid leaking arguments: + // http://jsperf.com/closure-with-arguments + var i = arguments.length; + var args = new Array(i); + while (i--) { + args[i] = arguments[i]; + } + var result = original.apply(this, args); + var ob = this.__ob__; + var inserted; + switch (method) { + case 'push': + inserted = args; + break; + case 'unshift': + inserted = args; + break; + case 'splice': + inserted = args.slice(2); + break; + } + if (inserted) ob.observeArray(inserted); + // notify change + ob.dep.notify(); + return result; + }); + }); + + /** + * Swap the element at the given index with a new value + * and emits corresponding event. + * + * @param {Number} index + * @param {*} val + * @return {*} - replaced element + */ + + def(arrayProto, '$set', function $set(index, val) { + if (index >= this.length) { + this.length = Number(index) + 1; + } + return this.splice(index, 1, val)[0]; + }); + + /** + * Convenience method to remove the element at given index or target element reference. + * + * @param {*} item + */ + + def(arrayProto, '$remove', function $remove(item) { + /* istanbul ignore if */ + if (!this.length) return; + var index = indexOf(this, item); + if (index > -1) { + return this.splice(index, 1); + } + }); + + var arrayKeys = Object.getOwnPropertyNames(arrayMethods); + + /** + * By default, when a reactive property is set, the new value is + * also converted to become reactive. However in certain cases, e.g. + * v-for scope alias and props, we don't want to force conversion + * because the value may be a nested value under a frozen data structure. + * + * So whenever we want to set a reactive property without forcing + * conversion on the new value, we wrap that call inside this function. + */ + + var shouldConvert = true; + + function withoutConversion(fn) { + shouldConvert = false; + fn(); + shouldConvert = true; + } + + /** + * Observer class that are attached to each observed + * object. Once attached, the observer converts target + * object's property keys into getter/setters that + * collect dependencies and dispatches updates. + * + * @param {Array|Object} value + * @constructor + */ + + function Observer(value) { + this.value = value; + this.dep = new Dep(); + def(value, '__ob__', this); + if (isArray(value)) { + var augment = hasProto ? protoAugment : copyAugment; + augment(value, arrayMethods, arrayKeys); + this.observeArray(value); + } else { + this.walk(value); + } + } + + // Instance methods + + /** + * Walk through each property and convert them into + * getter/setters. This method should only be called when + * value type is Object. + * + * @param {Object} obj + */ + + Observer.prototype.walk = function (obj) { + var keys = Object.keys(obj); + for (var i = 0, l = keys.length; i < l; i++) { + this.convert(keys[i], obj[keys[i]]); + } + }; + + /** + * Observe a list of Array items. + * + * @param {Array} items + */ + + Observer.prototype.observeArray = function (items) { + for (var i = 0, l = items.length; i < l; i++) { + observe(items[i]); + } + }; + + /** + * Convert a property into getter/setter so we can emit + * the events when the property is accessed/changed. + * + * @param {String} key + * @param {*} val + */ + + Observer.prototype.convert = function (key, val) { + defineReactive(this.value, key, val); + }; + + /** + * Add an owner vm, so that when $set/$delete mutations + * happen we can notify owner vms to proxy the keys and + * digest the watchers. This is only called when the object + * is observed as an instance's root $data. + * + * @param {Vue} vm + */ + + Observer.prototype.addVm = function (vm) { + (this.vms || (this.vms = [])).push(vm); + }; + + /** + * Remove an owner vm. This is called when the object is + * swapped out as an instance's $data object. + * + * @param {Vue} vm + */ + + Observer.prototype.removeVm = function (vm) { + this.vms.$remove(vm); + }; + + // helpers + + /** + * Augment an target Object or Array by intercepting + * the prototype chain using __proto__ + * + * @param {Object|Array} target + * @param {Object} src + */ + + function protoAugment(target, src) { + /* eslint-disable no-proto */ + target.__proto__ = src; + /* eslint-enable no-proto */ + } + + /** + * Augment an target Object or Array by defining + * hidden properties. + * + * @param {Object|Array} target + * @param {Object} proto + */ + + function copyAugment(target, src, keys) { + for (var i = 0, l = keys.length; i < l; i++) { + var key = keys[i]; + def(target, key, src[key]); + } + } + + /** + * Attempt to create an observer instance for a value, + * returns the new observer if successfully observed, + * or the existing observer if the value already has one. + * + * @param {*} value + * @param {Vue} [vm] + * @return {Observer|undefined} + * @static + */ + + function observe(value, vm) { + if (!value || typeof value !== 'object') { + return; + } + var ob; + if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) { + ob = value.__ob__; + } else if (shouldConvert && (isArray(value) || isPlainObject(value)) && Object.isExtensible(value) && !value._isVue) { + ob = new Observer(value); + } + if (ob && vm) { + ob.addVm(vm); + } + return ob; + } + + /** + * Define a reactive property on an Object. + * + * @param {Object} obj + * @param {String} key + * @param {*} val + */ + + function defineReactive(obj, key, val) { + var dep = new Dep(); + + var property = Object.getOwnPropertyDescriptor(obj, key); + if (property && property.configurable === false) { + return; + } + + // cater for pre-defined getter/setters + var getter = property && property.get; + var setter = property && property.set; + + var childOb = observe(val); + Object.defineProperty(obj, key, { + enumerable: true, + configurable: true, + get: function reactiveGetter() { + var value = getter ? getter.call(obj) : val; + if (Dep.target) { + dep.depend(); + if (childOb) { + childOb.dep.depend(); + } + if (isArray(value)) { + for (var e, i = 0, l = value.length; i < l; i++) { + e = value[i]; + e && e.__ob__ && e.__ob__.dep.depend(); + } + } + } + return value; + }, + set: function reactiveSetter(newVal) { + var value = getter ? getter.call(obj) : val; + if (newVal === value) { + return; + } + if (setter) { + setter.call(obj, newVal); + } else { + val = newVal; + } + childOb = observe(newVal); + dep.notify(); + } + }); + } + + + + var util = Object.freeze({ + defineReactive: defineReactive, + set: set, + del: del, + hasOwn: hasOwn, + isLiteral: isLiteral, + isReserved: isReserved, + _toString: _toString, + toNumber: toNumber, + toBoolean: toBoolean, + stripQuotes: stripQuotes, + camelize: camelize, + hyphenate: hyphenate, + classify: classify, + bind: bind, + toArray: toArray, + extend: extend, + isObject: isObject, + isPlainObject: isPlainObject, + def: def, + debounce: _debounce, + indexOf: indexOf, + cancellable: cancellable, + looseEqual: looseEqual, + isArray: isArray, + hasProto: hasProto, + inBrowser: inBrowser, + devtools: devtools, + isIE: isIE, + isIE9: isIE9, + isAndroid: isAndroid, + isIos: isIos, + iosVersionMatch: iosVersionMatch, + iosVersion: iosVersion, + hasMutationObserverBug: hasMutationObserverBug, + get transitionProp () { return transitionProp; }, + get transitionEndEvent () { return transitionEndEvent; }, + get animationProp () { return animationProp; }, + get animationEndEvent () { return animationEndEvent; }, + nextTick: nextTick, + get _Set () { return _Set; }, + query: query, + inDoc: inDoc, + getAttr: getAttr, + getBindAttr: getBindAttr, + hasBindAttr: hasBindAttr, + before: before, + after: after, + remove: remove, + prepend: prepend, + replace: replace, + on: on, + off: off, + setClass: setClass, + addClass: addClass, + removeClass: removeClass, + extractContent: extractContent, + trimNode: trimNode, + isTemplate: isTemplate, + createAnchor: createAnchor, + findRef: findRef, + mapNodeRange: mapNodeRange, + removeNodeRange: removeNodeRange, + isFragment: isFragment, + getOuterHTML: getOuterHTML, + mergeOptions: mergeOptions, + resolveAsset: resolveAsset, + checkComponentAttr: checkComponentAttr, + commonTagRE: commonTagRE, + reservedTagRE: reservedTagRE, + get warn () { return warn; } + }); + + var uid = 0; + + function initMixin (Vue) { + /** + * The main init sequence. This is called for every + * instance, including ones that are created from extended + * constructors. + * + * @param {Object} options - this options object should be + * the result of merging class + * options and the options passed + * in to the constructor. + */ + + Vue.prototype._init = function (options) { + options = options || {}; + + this.$el = null; + this.$parent = options.parent; + this.$root = this.$parent ? this.$parent.$root : this; + this.$children = []; + this.$refs = {}; // child vm references + this.$els = {}; // element references + this._watchers = []; // all watchers as an array + this._directives = []; // all directives + + // a uid + this._uid = uid++; + + // a flag to avoid this being observed + this._isVue = true; + + // events bookkeeping + this._events = {}; // registered callbacks + this._eventsCount = {}; // for $broadcast optimization + + // fragment instance properties + this._isFragment = false; + this._fragment = // @type {DocumentFragment} + this._fragmentStart = // @type {Text|Comment} + this._fragmentEnd = null; // @type {Text|Comment} + + // lifecycle state + this._isCompiled = this._isDestroyed = this._isReady = this._isAttached = this._isBeingDestroyed = this._vForRemoving = false; + this._unlinkFn = null; + + // context: + // if this is a transcluded component, context + // will be the common parent vm of this instance + // and its host. + this._context = options._context || this.$parent; + + // scope: + // if this is inside an inline v-for, the scope + // will be the intermediate scope created for this + // repeat fragment. this is used for linking props + // and container directives. + this._scope = options._scope; + + // fragment: + // if this instance is compiled inside a Fragment, it + // needs to reigster itself as a child of that fragment + // for attach/detach to work properly. + this._frag = options._frag; + if (this._frag) { + this._frag.children.push(this); + } + + // push self into parent / transclusion host + if (this.$parent) { + this.$parent.$children.push(this); + } + + // merge options. + options = this.$options = mergeOptions(this.constructor.options, options, this); + + // set ref + this._updateRef(); + + // initialize data as empty object. + // it will be filled up in _initData(). + this._data = {}; + + // call init hook + this._callHook('init'); + + // initialize data observation and scope inheritance. + this._initState(); + + // setup event system and option events. + this._initEvents(); + + // call created hook + this._callHook('created'); + + // if `el` option is passed, start compilation. + if (options.el) { + this.$mount(options.el); + } + }; + } + + var pathCache = new Cache(1000); + + // actions + var APPEND = 0; + var PUSH = 1; + var INC_SUB_PATH_DEPTH = 2; + var PUSH_SUB_PATH = 3; + + // states + var BEFORE_PATH = 0; + var IN_PATH = 1; + var BEFORE_IDENT = 2; + var IN_IDENT = 3; + var IN_SUB_PATH = 4; + var IN_SINGLE_QUOTE = 5; + var IN_DOUBLE_QUOTE = 6; + var AFTER_PATH = 7; + var ERROR = 8; + + var pathStateMachine = []; + + pathStateMachine[BEFORE_PATH] = { + 'ws': [BEFORE_PATH], + 'ident': [IN_IDENT, APPEND], + '[': [IN_SUB_PATH], + 'eof': [AFTER_PATH] + }; + + pathStateMachine[IN_PATH] = { + 'ws': [IN_PATH], + '.': [BEFORE_IDENT], + '[': [IN_SUB_PATH], + 'eof': [AFTER_PATH] + }; + + pathStateMachine[BEFORE_IDENT] = { + 'ws': [BEFORE_IDENT], + 'ident': [IN_IDENT, APPEND] + }; + + pathStateMachine[IN_IDENT] = { + 'ident': [IN_IDENT, APPEND], + '0': [IN_IDENT, APPEND], + 'number': [IN_IDENT, APPEND], + 'ws': [IN_PATH, PUSH], + '.': [BEFORE_IDENT, PUSH], + '[': [IN_SUB_PATH, PUSH], + 'eof': [AFTER_PATH, PUSH] + }; + + pathStateMachine[IN_SUB_PATH] = { + "'": [IN_SINGLE_QUOTE, APPEND], + '"': [IN_DOUBLE_QUOTE, APPEND], + '[': [IN_SUB_PATH, INC_SUB_PATH_DEPTH], + ']': [IN_PATH, PUSH_SUB_PATH], + 'eof': ERROR, + 'else': [IN_SUB_PATH, APPEND] + }; + + pathStateMachine[IN_SINGLE_QUOTE] = { + "'": [IN_SUB_PATH, APPEND], + 'eof': ERROR, + 'else': [IN_SINGLE_QUOTE, APPEND] + }; + + pathStateMachine[IN_DOUBLE_QUOTE] = { + '"': [IN_SUB_PATH, APPEND], + 'eof': ERROR, + 'else': [IN_DOUBLE_QUOTE, APPEND] + }; + + /** + * Determine the type of a character in a keypath. + * + * @param {Char} ch + * @return {String} type + */ + + function getPathCharType(ch) { + if (ch === undefined) { + return 'eof'; + } + + var code = ch.charCodeAt(0); + + switch (code) { + case 0x5B: // [ + case 0x5D: // ] + case 0x2E: // . + case 0x22: // " + case 0x27: // ' + case 0x30: + // 0 + return ch; + + case 0x5F: // _ + case 0x24: + // $ + return 'ident'; + + case 0x20: // Space + case 0x09: // Tab + case 0x0A: // Newline + case 0x0D: // Return + case 0xA0: // No-break space + case 0xFEFF: // Byte Order Mark + case 0x2028: // Line Separator + case 0x2029: + // Paragraph Separator + return 'ws'; + } + + // a-z, A-Z + if (code >= 0x61 && code <= 0x7A || code >= 0x41 && code <= 0x5A) { + return 'ident'; + } + + // 1-9 + if (code >= 0x31 && code <= 0x39) { + return 'number'; + } + + return 'else'; + } + + /** + * Format a subPath, return its plain form if it is + * a literal string or number. Otherwise prepend the + * dynamic indicator (*). + * + * @param {String} path + * @return {String} + */ + + function formatSubPath(path) { + var trimmed = path.trim(); + // invalid leading 0 + if (path.charAt(0) === '0' && isNaN(path)) { + return false; + } + return isLiteral(trimmed) ? stripQuotes(trimmed) : '*' + trimmed; + } + + /** + * Parse a string path into an array of segments + * + * @param {String} path + * @return {Array|undefined} + */ + + function parse(path) { + var keys = []; + var index = -1; + var mode = BEFORE_PATH; + var subPathDepth = 0; + var c, newChar, key, type, transition, action, typeMap; + + var actions = []; + + actions[PUSH] = function () { + if (key !== undefined) { + keys.push(key); + key = undefined; + } + }; + + actions[APPEND] = function () { + if (key === undefined) { + key = newChar; + } else { + key += newChar; + } + }; + + actions[INC_SUB_PATH_DEPTH] = function () { + actions[APPEND](); + subPathDepth++; + }; + + actions[PUSH_SUB_PATH] = function () { + if (subPathDepth > 0) { + subPathDepth--; + mode = IN_SUB_PATH; + actions[APPEND](); + } else { + subPathDepth = 0; + key = formatSubPath(key); + if (key === false) { + return false; + } else { + actions[PUSH](); + } + } + }; + + function maybeUnescapeQuote() { + var nextChar = path[index + 1]; + if (mode === IN_SINGLE_QUOTE && nextChar === "'" || mode === IN_DOUBLE_QUOTE && nextChar === '"') { + index++; + newChar = '\\' + nextChar; + actions[APPEND](); + return true; + } + } + + while (mode != null) { + index++; + c = path[index]; + + if (c === '\\' && maybeUnescapeQuote()) { + continue; + } + + type = getPathCharType(c); + typeMap = pathStateMachine[mode]; + transition = typeMap[type] || typeMap['else'] || ERROR; + + if (transition === ERROR) { + return; // parse error + } + + mode = transition[0]; + action = actions[transition[1]]; + if (action) { + newChar = transition[2]; + newChar = newChar === undefined ? c : newChar; + if (action() === false) { + return; + } + } + + if (mode === AFTER_PATH) { + keys.raw = path; + return keys; + } + } + } + + /** + * External parse that check for a cache hit first + * + * @param {String} path + * @return {Array|undefined} + */ + + function parsePath(path) { + var hit = pathCache.get(path); + if (!hit) { + hit = parse(path); + if (hit) { + pathCache.put(path, hit); + } + } + return hit; + } + + /** + * Get from an object from a path string + * + * @param {Object} obj + * @param {String} path + */ + + function getPath(obj, path) { + return parseExpression(path).get(obj); + } + + /** + * Warn against setting non-existent root path on a vm. + */ + + var warnNonExistent; + if ('development' !== 'production') { + warnNonExistent = function (path, vm) { + warn('You are setting a non-existent path "' + path.raw + '" ' + 'on a vm instance. Consider pre-initializing the property ' + 'with the "data" option for more reliable reactivity ' + 'and better performance.', vm); + }; + } + + /** + * Set on an object from a path + * + * @param {Object} obj + * @param {String | Array} path + * @param {*} val + */ + + function setPath(obj, path, val) { + var original = obj; + if (typeof path === 'string') { + path = parse(path); + } + if (!path || !isObject(obj)) { + return false; + } + var last, key; + for (var i = 0, l = path.length; i < l; i++) { + last = obj; + key = path[i]; + if (key.charAt(0) === '*') { + key = parseExpression(key.slice(1)).get.call(original, original); + } + if (i < l - 1) { + obj = obj[key]; + if (!isObject(obj)) { + obj = {}; + if ('development' !== 'production' && last._isVue) { + warnNonExistent(path, last); + } + set(last, key, obj); + } + } else { + if (isArray(obj)) { + obj.$set(key, val); + } else if (key in obj) { + obj[key] = val; + } else { + if ('development' !== 'production' && obj._isVue) { + warnNonExistent(path, obj); + } + set(obj, key, val); + } + } + } + return true; + } + +var path = Object.freeze({ + parsePath: parsePath, + getPath: getPath, + setPath: setPath + }); + + var expressionCache = new Cache(1000); + + var allowedKeywords = 'Math,Date,this,true,false,null,undefined,Infinity,NaN,' + 'isNaN,isFinite,decodeURI,decodeURIComponent,encodeURI,' + 'encodeURIComponent,parseInt,parseFloat'; + var allowedKeywordsRE = new RegExp('^(' + allowedKeywords.replace(/,/g, '\\b|') + '\\b)'); + + // keywords that don't make sense inside expressions + var improperKeywords = 'break,case,class,catch,const,continue,debugger,default,' + 'delete,do,else,export,extends,finally,for,function,if,' + 'import,in,instanceof,let,return,super,switch,throw,try,' + 'var,while,with,yield,enum,await,implements,package,' + 'protected,static,interface,private,public'; + var improperKeywordsRE = new RegExp('^(' + improperKeywords.replace(/,/g, '\\b|') + '\\b)'); + + var wsRE = /\s/g; + var newlineRE = /\n/g; + var saveRE = /[\{,]\s*[\w\$_]+\s*:|('(?:[^'\\]|\\.)*'|"(?:[^"\\]|\\.)*"|`(?:[^`\\]|\\.)*\$\{|\}(?:[^`\\]|\\.)*`|`(?:[^`\\]|\\.)*`)|new |typeof |void /g; + var restoreRE = /"(\d+)"/g; + var pathTestRE = /^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*|\['.*?'\]|\[".*?"\]|\[\d+\]|\[[A-Za-z_$][\w$]*\])*$/; + var identRE = /[^\w$\.](?:[A-Za-z_$][\w$]*)/g; + var literalValueRE$1 = /^(?:true|false|null|undefined|Infinity|NaN)$/; + + function noop() {} + + /** + * Save / Rewrite / Restore + * + * When rewriting paths found in an expression, it is + * possible for the same letter sequences to be found in + * strings and Object literal property keys. Therefore we + * remove and store these parts in a temporary array, and + * restore them after the path rewrite. + */ + + var saved = []; + + /** + * Save replacer + * + * The save regex can match two possible cases: + * 1. An opening object literal + * 2. A string + * If matched as a plain string, we need to escape its + * newlines, since the string needs to be preserved when + * generating the function body. + * + * @param {String} str + * @param {String} isString - str if matched as a string + * @return {String} - placeholder with index + */ + + function save(str, isString) { + var i = saved.length; + saved[i] = isString ? str.replace(newlineRE, '\\n') : str; + return '"' + i + '"'; + } + + /** + * Path rewrite replacer + * + * @param {String} raw + * @return {String} + */ + + function rewrite(raw) { + var c = raw.charAt(0); + var path = raw.slice(1); + if (allowedKeywordsRE.test(path)) { + return raw; + } else { + path = path.indexOf('"') > -1 ? path.replace(restoreRE, restore) : path; + return c + 'scope.' + path; + } + } + + /** + * Restore replacer + * + * @param {String} str + * @param {String} i - matched save index + * @return {String} + */ + + function restore(str, i) { + return saved[i]; + } + + /** + * Rewrite an expression, prefixing all path accessors with + * `scope.` and generate getter/setter functions. + * + * @param {String} exp + * @return {Function} + */ + + function compileGetter(exp) { + if (improperKeywordsRE.test(exp)) { + 'development' !== 'production' && warn('Avoid using reserved keywords in expression: ' + exp); + } + // reset state + saved.length = 0; + // save strings and object literal keys + var body = exp.replace(saveRE, save).replace(wsRE, ''); + // rewrite all paths + // pad 1 space here because the regex matches 1 extra char + body = (' ' + body).replace(identRE, rewrite).replace(restoreRE, restore); + return makeGetterFn(body); + } + + /** + * Build a getter function. Requires eval. + * + * We isolate the try/catch so it doesn't affect the + * optimization of the parse function when it is not called. + * + * @param {String} body + * @return {Function|undefined} + */ + + function makeGetterFn(body) { + try { + /* eslint-disable no-new-func */ + return new Function('scope', 'return ' + body + ';'); + /* eslint-enable no-new-func */ + } catch (e) { + if ('development' !== 'production') { + /* istanbul ignore if */ + if (e.toString().match(/unsafe-eval|CSP/)) { + warn('It seems you are using the default build of Vue.js in an environment ' + 'with Content Security Policy that prohibits unsafe-eval. ' + 'Use the CSP-compliant build instead: ' + 'http://vuejs.org/guide/installation.html#CSP-compliant-build'); + } else { + warn('Invalid expression. ' + 'Generated function body: ' + body); + } + } + return noop; + } + } + + /** + * Compile a setter function for the expression. + * + * @param {String} exp + * @return {Function|undefined} + */ + + function compileSetter(exp) { + var path = parsePath(exp); + if (path) { + return function (scope, val) { + setPath(scope, path, val); + }; + } else { + 'development' !== 'production' && warn('Invalid setter expression: ' + exp); + } + } + + /** + * Parse an expression into re-written getter/setters. + * + * @param {String} exp + * @param {Boolean} needSet + * @return {Function} + */ + + function parseExpression(exp, needSet) { + exp = exp.trim(); + // try cache + var hit = expressionCache.get(exp); + if (hit) { + if (needSet && !hit.set) { + hit.set = compileSetter(hit.exp); + } + return hit; + } + var res = { exp: exp }; + res.get = isSimplePath(exp) && exp.indexOf('[') < 0 + // optimized super simple getter + ? makeGetterFn('scope.' + exp) + // dynamic getter + : compileGetter(exp); + if (needSet) { + res.set = compileSetter(exp); + } + expressionCache.put(exp, res); + return res; + } + + /** + * Check if an expression is a simple path. + * + * @param {String} exp + * @return {Boolean} + */ + + function isSimplePath(exp) { + return pathTestRE.test(exp) && + // don't treat literal values as paths + !literalValueRE$1.test(exp) && + // Math constants e.g. Math.PI, Math.E etc. + exp.slice(0, 5) !== 'Math.'; + } + +var expression = Object.freeze({ + parseExpression: parseExpression, + isSimplePath: isSimplePath + }); + + // we have two separate queues: one for directive updates + // and one for user watcher registered via $watch(). + // we want to guarantee directive updates to be called + // before user watchers so that when user watchers are + // triggered, the DOM would have already been in updated + // state. + + var queue = []; + var userQueue = []; + var has = {}; + var circular = {}; + var waiting = false; + + /** + * Reset the batcher's state. + */ + + function resetBatcherState() { + queue.length = 0; + userQueue.length = 0; + has = {}; + circular = {}; + waiting = false; + } + + /** + * Flush both queues and run the watchers. + */ + + function flushBatcherQueue() { + var _again = true; + + _function: while (_again) { + _again = false; + + runBatcherQueue(queue); + runBatcherQueue(userQueue); + // user watchers triggered more watchers, + // keep flushing until it depletes + if (queue.length) { + _again = true; + continue _function; + } + // dev tool hook + /* istanbul ignore if */ + if (devtools && config.devtools) { + devtools.emit('flush'); + } + resetBatcherState(); + } + } + + /** + * Run the watchers in a single queue. + * + * @param {Array} queue + */ + + function runBatcherQueue(queue) { + // do not cache length because more watchers might be pushed + // as we run existing watchers + for (var i = 0; i < queue.length; i++) { + var watcher = queue[i]; + var id = watcher.id; + has[id] = null; + watcher.run(); + // in dev build, check and stop circular updates. + if ('development' !== 'production' && has[id] != null) { + circular[id] = (circular[id] || 0) + 1; + if (circular[id] > config._maxUpdateCount) { + warn('You may have an infinite update loop for watcher ' + 'with expression "' + watcher.expression + '"', watcher.vm); + break; + } + } + } + queue.length = 0; + } + + /** + * Push a watcher into the watcher queue. + * Jobs with duplicate IDs will be skipped unless it's + * pushed when the queue is being flushed. + * + * @param {Watcher} watcher + * properties: + * - {Number} id + * - {Function} run + */ + + function pushWatcher(watcher) { + var id = watcher.id; + if (has[id] == null) { + // push watcher into appropriate queue + var q = watcher.user ? userQueue : queue; + has[id] = q.length; + q.push(watcher); + // queue the flush + if (!waiting) { + waiting = true; + nextTick(flushBatcherQueue); + } + } + } + + var uid$2 = 0; + + /** + * A watcher parses an expression, collects dependencies, + * and fires callback when the expression value changes. + * This is used for both the $watch() api and directives. + * + * @param {Vue} vm + * @param {String|Function} expOrFn + * @param {Function} cb + * @param {Object} options + * - {Array} filters + * - {Boolean} twoWay + * - {Boolean} deep + * - {Boolean} user + * - {Boolean} sync + * - {Boolean} lazy + * - {Function} [preProcess] + * - {Function} [postProcess] + * @constructor + */ + function Watcher(vm, expOrFn, cb, options) { + // mix in options + if (options) { + extend(this, options); + } + var isFn = typeof expOrFn === 'function'; + this.vm = vm; + vm._watchers.push(this); + this.expression = expOrFn; + this.cb = cb; + this.id = ++uid$2; // uid for batching + this.active = true; + this.dirty = this.lazy; // for lazy watchers + this.deps = []; + this.newDeps = []; + this.depIds = new _Set(); + this.newDepIds = new _Set(); + this.prevError = null; // for async error stacks + // parse expression for getter/setter + if (isFn) { + this.getter = expOrFn; + this.setter = undefined; + } else { + var res = parseExpression(expOrFn, this.twoWay); + this.getter = res.get; + this.setter = res.set; + } + this.value = this.lazy ? undefined : this.get(); + // state for avoiding false triggers for deep and Array + // watchers during vm._digest() + this.queued = this.shallow = false; + } + + /** + * Evaluate the getter, and re-collect dependencies. + */ + + Watcher.prototype.get = function () { + this.beforeGet(); + var scope = this.scope || this.vm; + var value; + try { + value = this.getter.call(scope, scope); + } catch (e) { + if ('development' !== 'production' && config.warnExpressionErrors) { + warn('Error when evaluating expression ' + '"' + this.expression + '": ' + e.toString(), this.vm); + } + } + // "touch" every property so they are all tracked as + // dependencies for deep watching + if (this.deep) { + traverse(value); + } + if (this.preProcess) { + value = this.preProcess(value); + } + if (this.filters) { + value = scope._applyFilters(value, null, this.filters, false); + } + if (this.postProcess) { + value = this.postProcess(value); + } + this.afterGet(); + return value; + }; + + /** + * Set the corresponding value with the setter. + * + * @param {*} value + */ + + Watcher.prototype.set = function (value) { + var scope = this.scope || this.vm; + if (this.filters) { + value = scope._applyFilters(value, this.value, this.filters, true); + } + try { + this.setter.call(scope, scope, value); + } catch (e) { + if ('development' !== 'production' && config.warnExpressionErrors) { + warn('Error when evaluating setter ' + '"' + this.expression + '": ' + e.toString(), this.vm); + } + } + // two-way sync for v-for alias + var forContext = scope.$forContext; + if (forContext && forContext.alias === this.expression) { + if (forContext.filters) { + 'development' !== 'production' && warn('It seems you are using two-way binding on ' + 'a v-for alias (' + this.expression + '), and the ' + 'v-for has filters. This will not work properly. ' + 'Either remove the filters or use an array of ' + 'objects and bind to object properties instead.', this.vm); + return; + } + forContext._withLock(function () { + if (scope.$key) { + // original is an object + forContext.rawValue[scope.$key] = value; + } else { + forContext.rawValue.$set(scope.$index, value); + } + }); + } + }; + + /** + * Prepare for dependency collection. + */ + + Watcher.prototype.beforeGet = function () { + Dep.target = this; + }; + + /** + * Add a dependency to this directive. + * + * @param {Dep} dep + */ + + Watcher.prototype.addDep = function (dep) { + var id = dep.id; + if (!this.newDepIds.has(id)) { + this.newDepIds.add(id); + this.newDeps.push(dep); + if (!this.depIds.has(id)) { + dep.addSub(this); + } + } + }; + + /** + * Clean up for dependency collection. + */ + + Watcher.prototype.afterGet = function () { + Dep.target = null; + var i = this.deps.length; + while (i--) { + var dep = this.deps[i]; + if (!this.newDepIds.has(dep.id)) { + dep.removeSub(this); + } + } + var tmp = this.depIds; + this.depIds = this.newDepIds; + this.newDepIds = tmp; + this.newDepIds.clear(); + tmp = this.deps; + this.deps = this.newDeps; + this.newDeps = tmp; + this.newDeps.length = 0; + }; + + /** + * Subscriber interface. + * Will be called when a dependency changes. + * + * @param {Boolean} shallow + */ + + Watcher.prototype.update = function (shallow) { + if (this.lazy) { + this.dirty = true; + } else if (this.sync || !config.async) { + this.run(); + } else { + // if queued, only overwrite shallow with non-shallow, + // but not the other way around. + this.shallow = this.queued ? shallow ? this.shallow : false : !!shallow; + this.queued = true; + // record before-push error stack in debug mode + /* istanbul ignore if */ + if ('development' !== 'production' && config.debug) { + this.prevError = new Error('[vue] async stack trace'); + } + pushWatcher(this); + } + }; + + /** + * Batcher job interface. + * Will be called by the batcher. + */ + + Watcher.prototype.run = function () { + if (this.active) { + var value = this.get(); + if (value !== this.value || + // Deep watchers and watchers on Object/Arrays should fire even + // when the value is the same, because the value may + // have mutated; but only do so if this is a + // non-shallow update (caused by a vm digest). + (isObject(value) || this.deep) && !this.shallow) { + // set new value + var oldValue = this.value; + this.value = value; + // in debug + async mode, when a watcher callbacks + // throws, we also throw the saved before-push error + // so the full cross-tick stack trace is available. + var prevError = this.prevError; + /* istanbul ignore if */ + if ('development' !== 'production' && config.debug && prevError) { + this.prevError = null; + try { + this.cb.call(this.vm, value, oldValue); + } catch (e) { + nextTick(function () { + throw prevError; + }, 0); + throw e; + } + } else { + this.cb.call(this.vm, value, oldValue); + } + } + this.queued = this.shallow = false; + } + }; + + /** + * Evaluate the value of the watcher. + * This only gets called for lazy watchers. + */ + + Watcher.prototype.evaluate = function () { + // avoid overwriting another watcher that is being + // collected. + var current = Dep.target; + this.value = this.get(); + this.dirty = false; + Dep.target = current; + }; + + /** + * Depend on all deps collected by this watcher. + */ + + Watcher.prototype.depend = function () { + var i = this.deps.length; + while (i--) { + this.deps[i].depend(); + } + }; + + /** + * Remove self from all dependencies' subcriber list. + */ + + Watcher.prototype.teardown = function () { + if (this.active) { + // remove self from vm's watcher list + // this is a somewhat expensive operation so we skip it + // if the vm is being destroyed or is performing a v-for + // re-render (the watcher list is then filtered by v-for). + if (!this.vm._isBeingDestroyed && !this.vm._vForRemoving) { + this.vm._watchers.$remove(this); + } + var i = this.deps.length; + while (i--) { + this.deps[i].removeSub(this); + } + this.active = false; + this.vm = this.cb = this.value = null; + } + }; + + /** + * Recrusively traverse an object to evoke all converted + * getters, so that every nested property inside the object + * is collected as a "deep" dependency. + * + * @param {*} val + */ + + var seenObjects = new _Set(); + function traverse(val, seen) { + var i = undefined, + keys = undefined; + if (!seen) { + seen = seenObjects; + seen.clear(); + } + var isA = isArray(val); + var isO = isObject(val); + if ((isA || isO) && Object.isExtensible(val)) { + if (val.__ob__) { + var depId = val.__ob__.dep.id; + if (seen.has(depId)) { + return; + } else { + seen.add(depId); + } + } + if (isA) { + i = val.length; + while (i--) traverse(val[i], seen); + } else if (isO) { + keys = Object.keys(val); + i = keys.length; + while (i--) traverse(val[keys[i]], seen); + } + } + } + + var text$1 = { + + bind: function bind() { + this.attr = this.el.nodeType === 3 ? 'data' : 'textContent'; + }, + + update: function update(value) { + this.el[this.attr] = _toString(value); + } + }; + + var templateCache = new Cache(1000); + var idSelectorCache = new Cache(1000); + + var map = { + efault: [0, '', ''], + legend: [1, '
', '
'], + tr: [2, '
', '
'], + col: [2, '', '
'] + }; + + map.td = map.th = [3, '', '
']; + + map.option = map.optgroup = [1, '']; + + map.thead = map.tbody = map.colgroup = map.caption = map.tfoot = [1, '', '
']; + + map.g = map.defs = map.symbol = map.use = map.image = map.text = map.circle = map.ellipse = map.line = map.path = map.polygon = map.polyline = map.rect = [1, '', '']; + + /** + * Check if a node is a supported template node with a + * DocumentFragment content. + * + * @param {Node} node + * @return {Boolean} + */ + + function isRealTemplate(node) { + return isTemplate(node) && isFragment(node.content); + } + + var tagRE$1 = /<([\w:-]+)/; + var entityRE = /&#?\w+?;/; + var commentRE = / E - } - entry.newer = undefined; // D --x - entry.older = this.tail; // D. --> E - if (this.tail) { - this.tail.newer = entry; // E. <-- D - } - this.tail = entry; - return returnEntry ? entry : entry.value; - }; - - var cache$1 = new Cache(1000); - var filterTokenRE = /[^\s'"]+|'[^']*'|"[^"]*"/g; - var reservedArgRE = /^in$|^-?\d+/; - - /** - * Parser state - */ - - var str; - var dir; - var c; - var prev; - var i; - var l; - var lastFilterIndex; - var inSingle; - var inDouble; - var curly; - var square; - var paren; - /** - * Push a filter to the current directive object - */ - - function pushFilter() { - var exp = str.slice(lastFilterIndex, i).trim(); - var filter; - if (exp) { - filter = {}; - var tokens = exp.match(filterTokenRE); - filter.name = tokens[0]; - if (tokens.length > 1) { - filter.args = tokens.slice(1).map(processFilterArg); - } - } - if (filter) { - (dir.filters = dir.filters || []).push(filter); - } - lastFilterIndex = i + 1; - } - - /** - * Check if an argument is dynamic and strip quotes. - * - * @param {String} arg - * @return {Object} - */ - - function processFilterArg(arg) { - if (reservedArgRE.test(arg)) { - return { - value: toNumber(arg), - dynamic: false - }; - } else { - var stripped = stripQuotes(arg); - var dynamic = stripped === arg; - return { - value: dynamic ? arg : stripped, - dynamic: dynamic - }; - } - } - - /** - * Parse a directive value and extract the expression - * and its filters into a descriptor. - * - * Example: - * - * "a + 1 | uppercase" will yield: - * { - * expression: 'a + 1', - * filters: [ - * { name: 'uppercase', args: null } - * ] - * } - * - * @param {String} s - * @return {Object} - */ - - function parseDirective(s) { - var hit = cache$1.get(s); - if (hit) { - return hit; - } - - // reset parser state - str = s; - inSingle = inDouble = false; - curly = square = paren = 0; - lastFilterIndex = 0; - dir = {}; - - for (i = 0, l = str.length; i < l; i++) { - prev = c; - c = str.charCodeAt(i); - if (inSingle) { - // check single quote - if (c === 0x27 && prev !== 0x5C) inSingle = !inSingle; - } else if (inDouble) { - // check double quote - if (c === 0x22 && prev !== 0x5C) inDouble = !inDouble; - } else if (c === 0x7C && // pipe - str.charCodeAt(i + 1) !== 0x7C && str.charCodeAt(i - 1) !== 0x7C) { - if (dir.expression == null) { - // first filter, end of expression - lastFilterIndex = i + 1; - dir.expression = str.slice(0, i).trim(); - } else { - // already has filter - pushFilter(); - } - } else { - switch (c) { - case 0x22: - inDouble = true;break; // " - case 0x27: - inSingle = true;break; // ' - case 0x28: - paren++;break; // ( - case 0x29: - paren--;break; // ) - case 0x5B: - square++;break; // [ - case 0x5D: - square--;break; // ] - case 0x7B: - curly++;break; // { - case 0x7D: - curly--;break; // } - } - } - } - - if (dir.expression == null) { - dir.expression = str.slice(0, i).trim(); - } else if (lastFilterIndex !== 0) { - pushFilter(); - } - - cache$1.put(s, dir); - return dir; - } - -var directive = Object.freeze({ - parseDirective: parseDirective - }); - - var regexEscapeRE = /[-.*+?^${}()|[\]\/\\]/g; - var cache = undefined; - var tagRE = undefined; - var htmlRE = undefined; - /** - * Escape a string so it can be used in a RegExp - * constructor. - * - * @param {String} str - */ - - function escapeRegex(str) { - return str.replace(regexEscapeRE, '\\$&'); - } - - function compileRegex() { - var open = escapeRegex(config.delimiters[0]); - var close = escapeRegex(config.delimiters[1]); - var unsafeOpen = escapeRegex(config.unsafeDelimiters[0]); - var unsafeClose = escapeRegex(config.unsafeDelimiters[1]); - tagRE = new RegExp(unsafeOpen + '((?:.|\\n)+?)' + unsafeClose + '|' + open + '((?:.|\\n)+?)' + close, 'g'); - htmlRE = new RegExp('^' + unsafeOpen + '((?:.|\\n)+?)' + unsafeClose + '$'); - // reset cache - cache = new Cache(1000); - } - - /** - * Parse a template text string into an array of tokens. - * - * @param {String} text - * @return {Array | null} - * - {String} type - * - {String} value - * - {Boolean} [html] - * - {Boolean} [oneTime] - */ - - function parseText(text) { - if (!cache) { - compileRegex(); - } - var hit = cache.get(text); - if (hit) { - return hit; - } - if (!tagRE.test(text)) { - return null; - } - var tokens = []; - var lastIndex = tagRE.lastIndex = 0; - var match, index, html, value, first, oneTime; - /* eslint-disable no-cond-assign */ - while (match = tagRE.exec(text)) { - /* eslint-enable no-cond-assign */ - index = match.index; - // push text token - if (index > lastIndex) { - tokens.push({ - value: text.slice(lastIndex, index) - }); - } - // tag token - html = htmlRE.test(match[0]); - value = html ? match[1] : match[2]; - first = value.charCodeAt(0); - oneTime = first === 42; // * - value = oneTime ? value.slice(1) : value; - tokens.push({ - tag: true, - value: value.trim(), - html: html, - oneTime: oneTime - }); - lastIndex = index + match[0].length; - } - if (lastIndex < text.length) { - tokens.push({ - value: text.slice(lastIndex) - }); - } - cache.put(text, tokens); - return tokens; - } - - /** - * Format a list of tokens into an expression. - * e.g. tokens parsed from 'a {{b}} c' can be serialized - * into one single expression as '"a " + b + " c"'. - * - * @param {Array} tokens - * @param {Vue} [vm] - * @return {String} - */ - - function tokensToExp(tokens, vm) { - if (tokens.length > 1) { - return tokens.map(function (token) { - return formatToken(token, vm); - }).join('+'); - } else { - return formatToken(tokens[0], vm, true); - } - } - - /** - * Format a single token. - * - * @param {Object} token - * @param {Vue} [vm] - * @param {Boolean} [single] - * @return {String} - */ - - function formatToken(token, vm, single) { - return token.tag ? token.oneTime && vm ? '"' + vm.$eval(token.value) + '"' : inlineFilters(token.value, single) : '"' + token.value + '"'; - } - - /** - * For an attribute with multiple interpolation tags, - * e.g. attr="some-{{thing | filter}}", in order to combine - * the whole thing into a single watchable expression, we - * have to inline those filters. This function does exactly - * that. This is a bit hacky but it avoids heavy changes - * to directive parser and watcher mechanism. - * - * @param {String} exp - * @param {Boolean} single - * @return {String} - */ - - var filterRE = /[^|]\|[^|]/; - function inlineFilters(exp, single) { - if (!filterRE.test(exp)) { - return single ? exp : '(' + exp + ')'; - } else { - var dir = parseDirective(exp); - if (!dir.filters) { - return '(' + exp + ')'; - } else { - return 'this._applyFilters(' + dir.expression + // value - ',null,' + // oldValue (null for read) - JSON.stringify(dir.filters) + // filter descriptors - ',false)'; // write? - } - } - } - -var text = Object.freeze({ - compileRegex: compileRegex, - parseText: parseText, - tokensToExp: tokensToExp - }); - - var delimiters = ['{{', '}}']; - var unsafeDelimiters = ['{{{', '}}}']; - - var config = Object.defineProperties({ - - /** - * Whether to print debug messages. - * Also enables stack trace for warnings. - * - * @type {Boolean} - */ - - debug: false, - - /** - * Whether to suppress warnings. - * - * @type {Boolean} - */ - - silent: false, - - /** - * Whether to use async rendering. - */ - - async: true, - - /** - * Whether to warn against errors caught when evaluating - * expressions. - */ - - warnExpressionErrors: true, - - /** - * Whether to allow devtools inspection. - * Disabled by default in production builds. - */ - - devtools: 'development' !== 'production', - - /** - * Internal flag to indicate the delimiters have been - * changed. - * - * @type {Boolean} - */ - - _delimitersChanged: true, - - /** - * List of asset types that a component can own. - * - * @type {Array} - */ - - _assetTypes: ['component', 'directive', 'elementDirective', 'filter', 'transition', 'partial'], - - /** - * prop binding modes - */ - - _propBindingModes: { - ONE_WAY: 0, - TWO_WAY: 1, - ONE_TIME: 2 - }, - - /** - * Max circular updates allowed in a batcher flush cycle. - */ - - _maxUpdateCount: 100 - - }, { - delimiters: { /** - * Interpolation delimiters. Changing these would trigger - * the text parser to re-compile the regular expressions. - * - * @type {Array} - */ - - get: function get() { - return delimiters; - }, - set: function set(val) { - delimiters = val; - compileRegex(); - }, - configurable: true, - enumerable: true - }, - unsafeDelimiters: { - get: function get() { - return unsafeDelimiters; - }, - set: function set(val) { - unsafeDelimiters = val; - compileRegex(); - }, - configurable: true, - enumerable: true - } - }); - - var warn = undefined; - var formatComponentName = undefined; - - if ('development' !== 'production') { - (function () { - var hasConsole = typeof console !== 'undefined'; - - warn = function (msg, vm) { - if (hasConsole && !config.silent) { - console.error('[Vue warn]: ' + msg + (vm ? formatComponentName(vm) : '')); - } - }; - - formatComponentName = function (vm) { - var name = vm._isVue ? vm.$options.name : vm.name; - return name ? ' (found in component: <' + hyphenate(name) + '>)' : ''; - }; - })(); - } - - /** - * Append with transition. - * - * @param {Element} el - * @param {Element} target - * @param {Vue} vm - * @param {Function} [cb] - */ - - function appendWithTransition(el, target, vm, cb) { - applyTransition(el, 1, function () { - target.appendChild(el); - }, vm, cb); - } - - /** - * InsertBefore with transition. - * - * @param {Element} el - * @param {Element} target - * @param {Vue} vm - * @param {Function} [cb] - */ - - function beforeWithTransition(el, target, vm, cb) { - applyTransition(el, 1, function () { - before(el, target); - }, vm, cb); - } - - /** - * Remove with transition. - * - * @param {Element} el - * @param {Vue} vm - * @param {Function} [cb] - */ - - function removeWithTransition(el, vm, cb) { - applyTransition(el, -1, function () { - remove(el); - }, vm, cb); - } - - /** - * Apply transitions with an operation callback. - * - * @param {Element} el - * @param {Number} direction - * 1: enter - * -1: leave - * @param {Function} op - the actual DOM operation - * @param {Vue} vm - * @param {Function} [cb] - */ - - function applyTransition(el, direction, op, vm, cb) { - var transition = el.__v_trans; - if (!transition || - // skip if there are no js hooks and CSS transition is - // not supported - !transition.hooks && !transitionEndEvent || - // skip transitions for initial compile - !vm._isCompiled || - // if the vm is being manipulated by a parent directive - // during the parent's compilation phase, skip the - // animation. - vm.$parent && !vm.$parent._isCompiled) { - op(); - if (cb) cb(); - return; - } - var action = direction > 0 ? 'enter' : 'leave'; - transition[action](op, cb); - } - -var transition = Object.freeze({ - appendWithTransition: appendWithTransition, - beforeWithTransition: beforeWithTransition, - removeWithTransition: removeWithTransition, - applyTransition: applyTransition - }); - - /** - * Query an element selector if it's not an element already. - * - * @param {String|Element} el - * @return {Element} - */ - - function query(el) { - if (typeof el === 'string') { - var selector = el; - el = document.querySelector(el); - if (!el) { - 'development' !== 'production' && warn('Cannot find element: ' + selector); - } - } - return el; - } - - /** - * Check if a node is in the document. - * Note: document.documentElement.contains should work here - * but always returns false for comment nodes in phantomjs, - * making unit tests difficult. This is fixed by doing the - * contains() check on the node's parentNode instead of - * the node itself. - * - * @param {Node} node - * @return {Boolean} - */ - - function inDoc(node) { - if (!node) return false; - var doc = node.ownerDocument.documentElement; - var parent = node.parentNode; - return doc === node || doc === parent || !!(parent && parent.nodeType === 1 && doc.contains(parent)); - } - - /** - * Get and remove an attribute from a node. - * - * @param {Node} node - * @param {String} _attr - */ - - function getAttr(node, _attr) { - var val = node.getAttribute(_attr); - if (val !== null) { - node.removeAttribute(_attr); - } - return val; - } - - /** - * Get an attribute with colon or v-bind: prefix. - * - * @param {Node} node - * @param {String} name - * @return {String|null} - */ - - function getBindAttr(node, name) { - var val = getAttr(node, ':' + name); - if (val === null) { - val = getAttr(node, 'v-bind:' + name); - } - return val; - } - - /** - * Check the presence of a bind attribute. - * - * @param {Node} node - * @param {String} name - * @return {Boolean} - */ - - function hasBindAttr(node, name) { - return node.hasAttribute(name) || node.hasAttribute(':' + name) || node.hasAttribute('v-bind:' + name); - } - - /** - * Insert el before target - * - * @param {Element} el - * @param {Element} target - */ - - function before(el, target) { - target.parentNode.insertBefore(el, target); - } - - /** - * Insert el after target - * - * @param {Element} el - * @param {Element} target - */ - - function after(el, target) { - if (target.nextSibling) { - before(el, target.nextSibling); - } else { - target.parentNode.appendChild(el); - } - } - - /** - * Remove el from DOM - * - * @param {Element} el - */ - - function remove(el) { - el.parentNode.removeChild(el); - } - - /** - * Prepend el to target - * - * @param {Element} el - * @param {Element} target - */ - - function prepend(el, target) { - if (target.firstChild) { - before(el, target.firstChild); - } else { - target.appendChild(el); - } - } - - /** - * Replace target with el - * - * @param {Element} target - * @param {Element} el - */ - - function replace(target, el) { - var parent = target.parentNode; - if (parent) { - parent.replaceChild(el, target); - } - } - - /** - * Add event listener shorthand. - * - * @param {Element} el - * @param {String} event - * @param {Function} cb - * @param {Boolean} [useCapture] - */ - - function on(el, event, cb, useCapture) { - el.addEventListener(event, cb, useCapture); - } - - /** - * Remove event listener shorthand. - * - * @param {Element} el - * @param {String} event - * @param {Function} cb - */ - - function off(el, event, cb) { - el.removeEventListener(event, cb); - } - - /** - * For IE9 compat: when both class and :class are present - * getAttribute('class') returns wrong value... - * - * @param {Element} el - * @return {String} - */ - - function getClass(el) { - var classname = el.className; - if (typeof classname === 'object') { - classname = classname.baseVal || ''; - } - return classname; - } - - /** - * In IE9, setAttribute('class') will result in empty class - * if the element also has the :class attribute; However in - * PhantomJS, setting `className` does not work on SVG elements... - * So we have to do a conditional check here. - * - * @param {Element} el - * @param {String} cls - */ - - function setClass(el, cls) { - /* istanbul ignore if */ - if (isIE9 && !/svg$/.test(el.namespaceURI)) { - el.className = cls; - } else { - el.setAttribute('class', cls); - } - } - - /** - * Add class with compatibility for IE & SVG - * - * @param {Element} el - * @param {String} cls - */ - - function addClass(el, cls) { - if (el.classList) { - el.classList.add(cls); - } else { - var cur = ' ' + getClass(el) + ' '; - if (cur.indexOf(' ' + cls + ' ') < 0) { - setClass(el, (cur + cls).trim()); - } - } - } - - /** - * Remove class with compatibility for IE & SVG - * - * @param {Element} el - * @param {String} cls - */ - - function removeClass(el, cls) { - if (el.classList) { - el.classList.remove(cls); - } else { - var cur = ' ' + getClass(el) + ' '; - var tar = ' ' + cls + ' '; - while (cur.indexOf(tar) >= 0) { - cur = cur.replace(tar, ' '); - } - setClass(el, cur.trim()); - } - if (!el.className) { - el.removeAttribute('class'); - } - } - - /** - * Extract raw content inside an element into a temporary - * container div - * - * @param {Element} el - * @param {Boolean} asFragment - * @return {Element|DocumentFragment} - */ - - function extractContent(el, asFragment) { - var child; - var rawContent; - /* istanbul ignore if */ - if (isTemplate(el) && isFragment(el.content)) { - el = el.content; - } - if (el.hasChildNodes()) { - trimNode(el); - rawContent = asFragment ? document.createDocumentFragment() : document.createElement('div'); - /* eslint-disable no-cond-assign */ - while (child = el.firstChild) { - /* eslint-enable no-cond-assign */ - rawContent.appendChild(child); - } - } - return rawContent; - } - - /** - * Trim possible empty head/tail text and comment - * nodes inside a parent. - * - * @param {Node} node - */ - - function trimNode(node) { - var child; - /* eslint-disable no-sequences */ - while ((child = node.firstChild, isTrimmable(child))) { - node.removeChild(child); - } - while ((child = node.lastChild, isTrimmable(child))) { - node.removeChild(child); - } - /* eslint-enable no-sequences */ - } - - function isTrimmable(node) { - return node && (node.nodeType === 3 && !node.data.trim() || node.nodeType === 8); - } - - /** - * Check if an element is a template tag. - * Note if the template appears inside an SVG its tagName - * will be in lowercase. - * - * @param {Element} el - */ - - function isTemplate(el) { - return el.tagName && el.tagName.toLowerCase() === 'template'; - } - - /** - * Create an "anchor" for performing dom insertion/removals. - * This is used in a number of scenarios: - * - fragment instance - * - v-html - * - v-if - * - v-for - * - component - * - * @param {String} content - * @param {Boolean} persist - IE trashes empty textNodes on - * cloneNode(true), so in certain - * cases the anchor needs to be - * non-empty to be persisted in - * templates. - * @return {Comment|Text} - */ - - function createAnchor(content, persist) { - var anchor = config.debug ? document.createComment(content) : document.createTextNode(persist ? ' ' : ''); - anchor.__v_anchor = true; - return anchor; - } - - /** - * Find a component ref attribute that starts with $. - * - * @param {Element} node - * @return {String|undefined} - */ - - var refRE = /^v-ref:/; - - function findRef(node) { - if (node.hasAttributes()) { - var attrs = node.attributes; - for (var i = 0, l = attrs.length; i < l; i++) { - var name = attrs[i].name; - if (refRE.test(name)) { - return camelize(name.replace(refRE, '')); - } - } - } - } - - /** - * Map a function to a range of nodes . - * - * @param {Node} node - * @param {Node} end - * @param {Function} op - */ - - function mapNodeRange(node, end, op) { - var next; - while (node !== end) { - next = node.nextSibling; - op(node); - node = next; - } - op(end); - } - - /** - * Remove a range of nodes with transition, store - * the nodes in a fragment with correct ordering, - * and call callback when done. - * - * @param {Node} start - * @param {Node} end - * @param {Vue} vm - * @param {DocumentFragment} frag - * @param {Function} cb - */ - - function removeNodeRange(start, end, vm, frag, cb) { - var done = false; - var removed = 0; - var nodes = []; - mapNodeRange(start, end, function (node) { - if (node === end) done = true; - nodes.push(node); - removeWithTransition(node, vm, onRemoved); - }); - function onRemoved() { - removed++; - if (done && removed >= nodes.length) { - for (var i = 0; i < nodes.length; i++) { - frag.appendChild(nodes[i]); - } - cb && cb(); - } - } - } - - /** - * Check if a node is a DocumentFragment. - * - * @param {Node} node - * @return {Boolean} - */ - - function isFragment(node) { - return node && node.nodeType === 11; - } - - /** - * Get outerHTML of elements, taking care - * of SVG elements in IE as well. - * - * @param {Element} el - * @return {String} - */ - - function getOuterHTML(el) { - if (el.outerHTML) { - return el.outerHTML; - } else { - var container = document.createElement('div'); - container.appendChild(el.cloneNode(true)); - return container.innerHTML; - } - } - - var commonTagRE = /^(div|p|span|img|a|b|i|br|ul|ol|li|h1|h2|h3|h4|h5|h6|code|pre|table|th|td|tr|form|label|input|select|option|nav|article|section|header|footer)$/i; - var reservedTagRE = /^(slot|partial|component)$/i; - - var isUnknownElement = undefined; - if ('development' !== 'production') { - isUnknownElement = function (el, tag) { - if (tag.indexOf('-') > -1) { - // http://stackoverflow.com/a/28210364/1070244 - return el.constructor === window.HTMLUnknownElement || el.constructor === window.HTMLElement; - } else { - return (/HTMLUnknownElement/.test(el.toString()) && - // Chrome returns unknown for several HTML5 elements. - // https://code.google.com/p/chromium/issues/detail?id=540526 - // Firefox returns unknown for some "Interactive elements." - !/^(data|time|rtc|rb|details|dialog|summary)$/.test(tag) - ); - } - }; - } - - /** - * Check if an element is a component, if yes return its - * component id. - * - * @param {Element} el - * @param {Object} options - * @return {Object|undefined} - */ - - function checkComponentAttr(el, options) { - var tag = el.tagName.toLowerCase(); - var hasAttrs = el.hasAttributes(); - if (!commonTagRE.test(tag) && !reservedTagRE.test(tag)) { - if (resolveAsset(options, 'components', tag)) { - return { id: tag }; - } else { - var is = hasAttrs && getIsBinding(el, options); - if (is) { - return is; - } else if ('development' !== 'production') { - var expectedTag = options._componentNameMap && options._componentNameMap[tag]; - if (expectedTag) { - warn('Unknown custom element: <' + tag + '> - ' + 'did you mean <' + expectedTag + '>? ' + 'HTML is case-insensitive, remember to use kebab-case in templates.'); - } else if (isUnknownElement(el, tag)) { - warn('Unknown custom element: <' + tag + '> - did you ' + 'register the component correctly? For recursive components, ' + 'make sure to provide the "name" option.'); - } - } - } - } else if (hasAttrs) { - return getIsBinding(el, options); - } - } - - /** - * Get "is" binding from an element. - * - * @param {Element} el - * @param {Object} options - * @return {Object|undefined} - */ - - function getIsBinding(el, options) { - // dynamic syntax - var exp = el.getAttribute('is'); - if (exp != null) { - if (resolveAsset(options, 'components', exp)) { - el.removeAttribute('is'); - return { id: exp }; - } - } else { - exp = getBindAttr(el, 'is'); - if (exp != null) { - return { id: exp, dynamic: true }; - } - } - } - - /** - * Option overwriting strategies are functions that handle - * how to merge a parent option value and a child option - * value into the final value. - * - * All strategy functions follow the same signature: - * - * @param {*} parentVal - * @param {*} childVal - * @param {Vue} [vm] - */ - - var strats = config.optionMergeStrategies = Object.create(null); - - /** - * Helper that recursively merges two data objects together. - */ - - function mergeData(to, from) { - var key, toVal, fromVal; - for (key in from) { - toVal = to[key]; - fromVal = from[key]; - if (!hasOwn(to, key)) { - set(to, key, fromVal); - } else if (isObject(toVal) && isObject(fromVal)) { - mergeData(toVal, fromVal); - } - } - return to; - } - - /** - * Data - */ - - strats.data = function (parentVal, childVal, vm) { - if (!vm) { - // in a Vue.extend merge, both should be functions - if (!childVal) { - return parentVal; - } - if (typeof childVal !== 'function') { - 'development' !== 'production' && warn('The "data" option should be a function ' + 'that returns a per-instance value in component ' + 'definitions.', vm); - return parentVal; - } - if (!parentVal) { - return childVal; - } - // when parentVal & childVal are both present, - // we need to return a function that returns the - // merged result of both functions... no need to - // check if parentVal is a function here because - // it has to be a function to pass previous merges. - return function mergedDataFn() { - return mergeData(childVal.call(this), parentVal.call(this)); - }; - } else if (parentVal || childVal) { - return function mergedInstanceDataFn() { - // instance merge - var instanceData = typeof childVal === 'function' ? childVal.call(vm) : childVal; - var defaultData = typeof parentVal === 'function' ? parentVal.call(vm) : undefined; - if (instanceData) { - return mergeData(instanceData, defaultData); - } else { - return defaultData; - } - }; - } - }; - - /** - * El - */ - - strats.el = function (parentVal, childVal, vm) { - if (!vm && childVal && typeof childVal !== 'function') { - 'development' !== 'production' && warn('The "el" option should be a function ' + 'that returns a per-instance value in component ' + 'definitions.', vm); - return; - } - var ret = childVal || parentVal; - // invoke the element factory if this is instance merge - return vm && typeof ret === 'function' ? ret.call(vm) : ret; - }; - - /** - * Hooks and param attributes are merged as arrays. - */ - - strats.init = strats.created = strats.ready = strats.attached = strats.detached = strats.beforeCompile = strats.compiled = strats.beforeDestroy = strats.destroyed = strats.activate = function (parentVal, childVal) { - return childVal ? parentVal ? parentVal.concat(childVal) : isArray(childVal) ? childVal : [childVal] : parentVal; - }; - - /** - * Assets - * - * When a vm is present (instance creation), we need to do - * a three-way merge between constructor options, instance - * options and parent options. - */ - - function mergeAssets(parentVal, childVal) { - var res = Object.create(parentVal || null); - return childVal ? extend(res, guardArrayAssets(childVal)) : res; - } - - config._assetTypes.forEach(function (type) { - strats[type + 's'] = mergeAssets; - }); - - /** - * Events & Watchers. - * - * Events & watchers hashes should not overwrite one - * another, so we merge them as arrays. - */ - - strats.watch = strats.events = function (parentVal, childVal) { - if (!childVal) return parentVal; - if (!parentVal) return childVal; - var ret = {}; - extend(ret, parentVal); - for (var key in childVal) { - var parent = ret[key]; - var child = childVal[key]; - if (parent && !isArray(parent)) { - parent = [parent]; - } - ret[key] = parent ? parent.concat(child) : [child]; - } - return ret; - }; - - /** - * Other object hashes. - */ - - strats.props = strats.methods = strats.computed = function (parentVal, childVal) { - if (!childVal) return parentVal; - if (!parentVal) return childVal; - var ret = Object.create(null); - extend(ret, parentVal); - extend(ret, childVal); - return ret; - }; - - /** - * Default strategy. - */ - - var defaultStrat = function defaultStrat(parentVal, childVal) { - return childVal === undefined ? parentVal : childVal; - }; - - /** - * Make sure component options get converted to actual - * constructors. - * - * @param {Object} options - */ - - function guardComponents(options) { - if (options.components) { - var components = options.components = guardArrayAssets(options.components); - var ids = Object.keys(components); - var def; - if ('development' !== 'production') { - var map = options._componentNameMap = {}; - } - for (var i = 0, l = ids.length; i < l; i++) { - var key = ids[i]; - if (commonTagRE.test(key) || reservedTagRE.test(key)) { - 'development' !== 'production' && warn('Do not use built-in or reserved HTML elements as component ' + 'id: ' + key); - continue; - } - // record a all lowercase <-> kebab-case mapping for - // possible custom element case error warning - if ('development' !== 'production') { - map[key.replace(/-/g, '').toLowerCase()] = hyphenate(key); - } - def = components[key]; - if (isPlainObject(def)) { - components[key] = Vue.extend(def); - } - } - } - } - - /** - * Ensure all props option syntax are normalized into the - * Object-based format. - * - * @param {Object} options - */ - - function guardProps(options) { - var props = options.props; - var i, val; - if (isArray(props)) { - options.props = {}; - i = props.length; - while (i--) { - val = props[i]; - if (typeof val === 'string') { - options.props[val] = null; - } else if (val.name) { - options.props[val.name] = val; - } - } - } else if (isPlainObject(props)) { - var keys = Object.keys(props); - i = keys.length; - while (i--) { - val = props[keys[i]]; - if (typeof val === 'function') { - props[keys[i]] = { type: val }; - } - } - } - } - - /** - * Guard an Array-format assets option and converted it - * into the key-value Object format. - * - * @param {Object|Array} assets - * @return {Object} - */ - - function guardArrayAssets(assets) { - if (isArray(assets)) { - var res = {}; - var i = assets.length; - var asset; - while (i--) { - asset = assets[i]; - var id = typeof asset === 'function' ? asset.options && asset.options.name || asset.id : asset.name || asset.id; - if (!id) { - 'development' !== 'production' && warn('Array-syntax assets must provide a "name" or "id" field.'); - } else { - res[id] = asset; - } - } - return res; - } - return assets; - } - - /** - * Merge two option objects into a new one. - * Core utility used in both instantiation and inheritance. - * - * @param {Object} parent - * @param {Object} child - * @param {Vue} [vm] - if vm is present, indicates this is - * an instantiation merge. - */ - - function mergeOptions(parent, child, vm) { - guardComponents(child); - guardProps(child); - if ('development' !== 'production') { - if (child.propsData && !vm) { - warn('propsData can only be used as an instantiation option.'); - } - } - var options = {}; - var key; - if (child['extends']) { - parent = typeof child['extends'] === 'function' ? mergeOptions(parent, child['extends'].options, vm) : mergeOptions(parent, child['extends'], vm); - } - if (child.mixins) { - for (var i = 0, l = child.mixins.length; i < l; i++) { - var mixin = child.mixins[i]; - var mixinOptions = mixin.prototype instanceof Vue ? mixin.options : mixin; - parent = mergeOptions(parent, mixinOptions, vm); - } - } - for (key in parent) { - mergeField(key); - } - for (key in child) { - if (!hasOwn(parent, key)) { - mergeField(key); - } - } - function mergeField(key) { - var strat = strats[key] || defaultStrat; - options[key] = strat(parent[key], child[key], vm, key); - } - return options; - } - - /** - * Resolve an asset. - * This function is used because child instances need access - * to assets defined in its ancestor chain. - * - * @param {Object} options - * @param {String} type - * @param {String} id - * @param {Boolean} warnMissing - * @return {Object|Function} - */ - - function resolveAsset(options, type, id, warnMissing) { - /* istanbul ignore if */ - if (typeof id !== 'string') { - return; - } - var assets = options[type]; - var camelizedId; - var res = assets[id] || - // camelCase ID - assets[camelizedId = camelize(id)] || - // Pascal Case ID - assets[camelizedId.charAt(0).toUpperCase() + camelizedId.slice(1)]; - if ('development' !== 'production' && warnMissing && !res) { - warn('Failed to resolve ' + type.slice(0, -1) + ': ' + id, options); - } - return res; - } - - var uid$1 = 0; - - /** - * A dep is an observable that can have multiple - * directives subscribing to it. - * - * @constructor - */ - function Dep() { - this.id = uid$1++; - this.subs = []; - } - - // the current target watcher being evaluated. - // this is globally unique because there could be only one - // watcher being evaluated at any time. - Dep.target = null; - - /** - * Add a directive subscriber. - * - * @param {Directive} sub - */ - - Dep.prototype.addSub = function (sub) { - this.subs.push(sub); - }; - - /** - * Remove a directive subscriber. - * - * @param {Directive} sub - */ - - Dep.prototype.removeSub = function (sub) { - this.subs.$remove(sub); - }; - - /** - * Add self as a dependency to the target watcher. - */ - - Dep.prototype.depend = function () { - Dep.target.addDep(this); - }; - - /** - * Notify all subscribers of a new value. - */ - - Dep.prototype.notify = function () { - // stablize the subscriber list first - var subs = toArray(this.subs); - for (var i = 0, l = subs.length; i < l; i++) { - subs[i].update(); - } - }; - - var arrayProto = Array.prototype; - var arrayMethods = Object.create(arrayProto) - - /** - * Intercept mutating methods and emit events - */ - - ;['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse'].forEach(function (method) { - // cache original method - var original = arrayProto[method]; - def(arrayMethods, method, function mutator() { - // avoid leaking arguments: - // http://jsperf.com/closure-with-arguments - var i = arguments.length; - var args = new Array(i); - while (i--) { - args[i] = arguments[i]; - } - var result = original.apply(this, args); - var ob = this.__ob__; - var inserted; - switch (method) { - case 'push': - inserted = args; - break; - case 'unshift': - inserted = args; - break; - case 'splice': - inserted = args.slice(2); - break; - } - if (inserted) ob.observeArray(inserted); - // notify change - ob.dep.notify(); - return result; - }); - }); - - /** - * Swap the element at the given index with a new value - * and emits corresponding event. - * - * @param {Number} index - * @param {*} val - * @return {*} - replaced element - */ - - def(arrayProto, '$set', function $set(index, val) { - if (index >= this.length) { - this.length = Number(index) + 1; - } - return this.splice(index, 1, val)[0]; - }); - - /** - * Convenience method to remove the element at given index or target element reference. - * - * @param {*} item - */ - - def(arrayProto, '$remove', function $remove(item) { - /* istanbul ignore if */ - if (!this.length) return; - var index = indexOf(this, item); - if (index > -1) { - return this.splice(index, 1); - } - }); - - var arrayKeys = Object.getOwnPropertyNames(arrayMethods); - - /** - * By default, when a reactive property is set, the new value is - * also converted to become reactive. However in certain cases, e.g. - * v-for scope alias and props, we don't want to force conversion - * because the value may be a nested value under a frozen data structure. - * - * So whenever we want to set a reactive property without forcing - * conversion on the new value, we wrap that call inside this function. - */ - - var shouldConvert = true; - - function withoutConversion(fn) { - shouldConvert = false; - fn(); - shouldConvert = true; - } - - /** - * Observer class that are attached to each observed - * object. Once attached, the observer converts target - * object's property keys into getter/setters that - * collect dependencies and dispatches updates. - * - * @param {Array|Object} value - * @constructor - */ - - function Observer(value) { - this.value = value; - this.dep = new Dep(); - def(value, '__ob__', this); - if (isArray(value)) { - var augment = hasProto ? protoAugment : copyAugment; - augment(value, arrayMethods, arrayKeys); - this.observeArray(value); - } else { - this.walk(value); - } - } - - // Instance methods - - /** - * Walk through each property and convert them into - * getter/setters. This method should only be called when - * value type is Object. - * - * @param {Object} obj - */ - - Observer.prototype.walk = function (obj) { - var keys = Object.keys(obj); - for (var i = 0, l = keys.length; i < l; i++) { - this.convert(keys[i], obj[keys[i]]); - } - }; - - /** - * Observe a list of Array items. - * - * @param {Array} items - */ - - Observer.prototype.observeArray = function (items) { - for (var i = 0, l = items.length; i < l; i++) { - observe(items[i]); - } - }; - - /** - * Convert a property into getter/setter so we can emit - * the events when the property is accessed/changed. - * - * @param {String} key - * @param {*} val - */ - - Observer.prototype.convert = function (key, val) { - defineReactive(this.value, key, val); - }; - - /** - * Add an owner vm, so that when $set/$delete mutations - * happen we can notify owner vms to proxy the keys and - * digest the watchers. This is only called when the object - * is observed as an instance's root $data. - * - * @param {Vue} vm - */ - - Observer.prototype.addVm = function (vm) { - (this.vms || (this.vms = [])).push(vm); - }; - - /** - * Remove an owner vm. This is called when the object is - * swapped out as an instance's $data object. - * - * @param {Vue} vm - */ - - Observer.prototype.removeVm = function (vm) { - this.vms.$remove(vm); - }; - - // helpers - - /** - * Augment an target Object or Array by intercepting - * the prototype chain using __proto__ - * - * @param {Object|Array} target - * @param {Object} src - */ - - function protoAugment(target, src) { - /* eslint-disable no-proto */ - target.__proto__ = src; - /* eslint-enable no-proto */ - } - - /** - * Augment an target Object or Array by defining - * hidden properties. - * - * @param {Object|Array} target - * @param {Object} proto - */ - - function copyAugment(target, src, keys) { - for (var i = 0, l = keys.length; i < l; i++) { - var key = keys[i]; - def(target, key, src[key]); - } - } - - /** - * Attempt to create an observer instance for a value, - * returns the new observer if successfully observed, - * or the existing observer if the value already has one. - * - * @param {*} value - * @param {Vue} [vm] - * @return {Observer|undefined} - * @static - */ - - function observe(value, vm) { - if (!value || typeof value !== 'object') { - return; - } - var ob; - if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) { - ob = value.__ob__; - } else if (shouldConvert && (isArray(value) || isPlainObject(value)) && Object.isExtensible(value) && !value._isVue) { - ob = new Observer(value); - } - if (ob && vm) { - ob.addVm(vm); - } - return ob; - } - - /** - * Define a reactive property on an Object. - * - * @param {Object} obj - * @param {String} key - * @param {*} val - */ - - function defineReactive(obj, key, val) { - var dep = new Dep(); - - var property = Object.getOwnPropertyDescriptor(obj, key); - if (property && property.configurable === false) { - return; - } - - // cater for pre-defined getter/setters - var getter = property && property.get; - var setter = property && property.set; - - var childOb = observe(val); - Object.defineProperty(obj, key, { - enumerable: true, - configurable: true, - get: function reactiveGetter() { - var value = getter ? getter.call(obj) : val; - if (Dep.target) { - dep.depend(); - if (childOb) { - childOb.dep.depend(); - } - if (isArray(value)) { - for (var e, i = 0, l = value.length; i < l; i++) { - e = value[i]; - e && e.__ob__ && e.__ob__.dep.depend(); - } - } - } - return value; - }, - set: function reactiveSetter(newVal) { - var value = getter ? getter.call(obj) : val; - if (newVal === value) { - return; - } - if (setter) { - setter.call(obj, newVal); - } else { - val = newVal; - } - childOb = observe(newVal); - dep.notify(); - } - }); - } - - - - var util = Object.freeze({ - defineReactive: defineReactive, - set: set, - del: del, - hasOwn: hasOwn, - isLiteral: isLiteral, - isReserved: isReserved, - _toString: _toString, - toNumber: toNumber, - toBoolean: toBoolean, - stripQuotes: stripQuotes, - camelize: camelize, - hyphenate: hyphenate, - classify: classify, - bind: bind, - toArray: toArray, - extend: extend, - isObject: isObject, - isPlainObject: isPlainObject, - def: def, - debounce: _debounce, - indexOf: indexOf, - cancellable: cancellable, - looseEqual: looseEqual, - isArray: isArray, - hasProto: hasProto, - inBrowser: inBrowser, - devtools: devtools, - isIE: isIE, - isIE9: isIE9, - isAndroid: isAndroid, - isIos: isIos, - iosVersionMatch: iosVersionMatch, - iosVersion: iosVersion, - hasMutationObserverBug: hasMutationObserverBug, - get transitionProp () { return transitionProp; }, - get transitionEndEvent () { return transitionEndEvent; }, - get animationProp () { return animationProp; }, - get animationEndEvent () { return animationEndEvent; }, - nextTick: nextTick, - get _Set () { return _Set; }, - query: query, - inDoc: inDoc, - getAttr: getAttr, - getBindAttr: getBindAttr, - hasBindAttr: hasBindAttr, - before: before, - after: after, - remove: remove, - prepend: prepend, - replace: replace, - on: on, - off: off, - setClass: setClass, - addClass: addClass, - removeClass: removeClass, - extractContent: extractContent, - trimNode: trimNode, - isTemplate: isTemplate, - createAnchor: createAnchor, - findRef: findRef, - mapNodeRange: mapNodeRange, - removeNodeRange: removeNodeRange, - isFragment: isFragment, - getOuterHTML: getOuterHTML, - mergeOptions: mergeOptions, - resolveAsset: resolveAsset, - checkComponentAttr: checkComponentAttr, - commonTagRE: commonTagRE, - reservedTagRE: reservedTagRE, - get warn () { return warn; } - }); - - var uid = 0; - - function initMixin (Vue) { - /** - * The main init sequence. This is called for every - * instance, including ones that are created from extended - * constructors. - * - * @param {Object} options - this options object should be - * the result of merging class - * options and the options passed - * in to the constructor. - */ - - Vue.prototype._init = function (options) { - options = options || {}; - - this.$el = null; - this.$parent = options.parent; - this.$root = this.$parent ? this.$parent.$root : this; - this.$children = []; - this.$refs = {}; // child vm references - this.$els = {}; // element references - this._watchers = []; // all watchers as an array - this._directives = []; // all directives - - // a uid - this._uid = uid++; - - // a flag to avoid this being observed - this._isVue = true; - - // events bookkeeping - this._events = {}; // registered callbacks - this._eventsCount = {}; // for $broadcast optimization - - // fragment instance properties - this._isFragment = false; - this._fragment = // @type {DocumentFragment} - this._fragmentStart = // @type {Text|Comment} - this._fragmentEnd = null; // @type {Text|Comment} - - // lifecycle state - this._isCompiled = this._isDestroyed = this._isReady = this._isAttached = this._isBeingDestroyed = this._vForRemoving = false; - this._unlinkFn = null; - - // context: - // if this is a transcluded component, context - // will be the common parent vm of this instance - // and its host. - this._context = options._context || this.$parent; - - // scope: - // if this is inside an inline v-for, the scope - // will be the intermediate scope created for this - // repeat fragment. this is used for linking props - // and container directives. - this._scope = options._scope; - - // fragment: - // if this instance is compiled inside a Fragment, it - // needs to reigster itself as a child of that fragment - // for attach/detach to work properly. - this._frag = options._frag; - if (this._frag) { - this._frag.children.push(this); - } - - // push self into parent / transclusion host - if (this.$parent) { - this.$parent.$children.push(this); - } - - // merge options. - options = this.$options = mergeOptions(this.constructor.options, options, this); - - // set ref - this._updateRef(); - - // initialize data as empty object. - // it will be filled up in _initData(). - this._data = {}; - - // call init hook - this._callHook('init'); - - // initialize data observation and scope inheritance. - this._initState(); - - // setup event system and option events. - this._initEvents(); - - // call created hook - this._callHook('created'); - - // if `el` option is passed, start compilation. - if (options.el) { - this.$mount(options.el); - } - }; - } - - var pathCache = new Cache(1000); - - // actions - var APPEND = 0; - var PUSH = 1; - var INC_SUB_PATH_DEPTH = 2; - var PUSH_SUB_PATH = 3; - - // states - var BEFORE_PATH = 0; - var IN_PATH = 1; - var BEFORE_IDENT = 2; - var IN_IDENT = 3; - var IN_SUB_PATH = 4; - var IN_SINGLE_QUOTE = 5; - var IN_DOUBLE_QUOTE = 6; - var AFTER_PATH = 7; - var ERROR = 8; - - var pathStateMachine = []; - - pathStateMachine[BEFORE_PATH] = { - 'ws': [BEFORE_PATH], - 'ident': [IN_IDENT, APPEND], - '[': [IN_SUB_PATH], - 'eof': [AFTER_PATH] - }; - - pathStateMachine[IN_PATH] = { - 'ws': [IN_PATH], - '.': [BEFORE_IDENT], - '[': [IN_SUB_PATH], - 'eof': [AFTER_PATH] - }; - - pathStateMachine[BEFORE_IDENT] = { - 'ws': [BEFORE_IDENT], - 'ident': [IN_IDENT, APPEND] - }; - - pathStateMachine[IN_IDENT] = { - 'ident': [IN_IDENT, APPEND], - '0': [IN_IDENT, APPEND], - 'number': [IN_IDENT, APPEND], - 'ws': [IN_PATH, PUSH], - '.': [BEFORE_IDENT, PUSH], - '[': [IN_SUB_PATH, PUSH], - 'eof': [AFTER_PATH, PUSH] - }; - - pathStateMachine[IN_SUB_PATH] = { - "'": [IN_SINGLE_QUOTE, APPEND], - '"': [IN_DOUBLE_QUOTE, APPEND], - '[': [IN_SUB_PATH, INC_SUB_PATH_DEPTH], - ']': [IN_PATH, PUSH_SUB_PATH], - 'eof': ERROR, - 'else': [IN_SUB_PATH, APPEND] - }; - - pathStateMachine[IN_SINGLE_QUOTE] = { - "'": [IN_SUB_PATH, APPEND], - 'eof': ERROR, - 'else': [IN_SINGLE_QUOTE, APPEND] - }; - - pathStateMachine[IN_DOUBLE_QUOTE] = { - '"': [IN_SUB_PATH, APPEND], - 'eof': ERROR, - 'else': [IN_DOUBLE_QUOTE, APPEND] - }; - - /** - * Determine the type of a character in a keypath. - * - * @param {Char} ch - * @return {String} type - */ - - function getPathCharType(ch) { - if (ch === undefined) { - return 'eof'; - } - - var code = ch.charCodeAt(0); - - switch (code) { - case 0x5B: // [ - case 0x5D: // ] - case 0x2E: // . - case 0x22: // " - case 0x27: // ' - case 0x30: - // 0 - return ch; - - case 0x5F: // _ - case 0x24: - // $ - return 'ident'; - - case 0x20: // Space - case 0x09: // Tab - case 0x0A: // Newline - case 0x0D: // Return - case 0xA0: // No-break space - case 0xFEFF: // Byte Order Mark - case 0x2028: // Line Separator - case 0x2029: - // Paragraph Separator - return 'ws'; - } - - // a-z, A-Z - if (code >= 0x61 && code <= 0x7A || code >= 0x41 && code <= 0x5A) { - return 'ident'; - } - - // 1-9 - if (code >= 0x31 && code <= 0x39) { - return 'number'; - } - - return 'else'; - } - - /** - * Format a subPath, return its plain form if it is - * a literal string or number. Otherwise prepend the - * dynamic indicator (*). - * - * @param {String} path - * @return {String} - */ - - function formatSubPath(path) { - var trimmed = path.trim(); - // invalid leading 0 - if (path.charAt(0) === '0' && isNaN(path)) { - return false; - } - return isLiteral(trimmed) ? stripQuotes(trimmed) : '*' + trimmed; - } - - /** - * Parse a string path into an array of segments - * - * @param {String} path - * @return {Array|undefined} - */ - - function parse(path) { - var keys = []; - var index = -1; - var mode = BEFORE_PATH; - var subPathDepth = 0; - var c, newChar, key, type, transition, action, typeMap; - - var actions = []; - - actions[PUSH] = function () { - if (key !== undefined) { - keys.push(key); - key = undefined; - } - }; - - actions[APPEND] = function () { - if (key === undefined) { - key = newChar; - } else { - key += newChar; - } - }; - - actions[INC_SUB_PATH_DEPTH] = function () { - actions[APPEND](); - subPathDepth++; - }; - - actions[PUSH_SUB_PATH] = function () { - if (subPathDepth > 0) { - subPathDepth--; - mode = IN_SUB_PATH; - actions[APPEND](); - } else { - subPathDepth = 0; - key = formatSubPath(key); - if (key === false) { - return false; - } else { - actions[PUSH](); - } - } - }; - - function maybeUnescapeQuote() { - var nextChar = path[index + 1]; - if (mode === IN_SINGLE_QUOTE && nextChar === "'" || mode === IN_DOUBLE_QUOTE && nextChar === '"') { - index++; - newChar = '\\' + nextChar; - actions[APPEND](); - return true; - } - } - - while (mode != null) { - index++; - c = path[index]; - - if (c === '\\' && maybeUnescapeQuote()) { - continue; - } - - type = getPathCharType(c); - typeMap = pathStateMachine[mode]; - transition = typeMap[type] || typeMap['else'] || ERROR; - - if (transition === ERROR) { - return; // parse error - } - - mode = transition[0]; - action = actions[transition[1]]; - if (action) { - newChar = transition[2]; - newChar = newChar === undefined ? c : newChar; - if (action() === false) { - return; - } - } - - if (mode === AFTER_PATH) { - keys.raw = path; - return keys; - } - } - } - - /** - * External parse that check for a cache hit first - * - * @param {String} path - * @return {Array|undefined} - */ - - function parsePath(path) { - var hit = pathCache.get(path); - if (!hit) { - hit = parse(path); - if (hit) { - pathCache.put(path, hit); - } - } - return hit; - } - - /** - * Get from an object from a path string - * - * @param {Object} obj - * @param {String} path - */ - - function getPath(obj, path) { - return parseExpression(path).get(obj); - } - - /** - * Warn against setting non-existent root path on a vm. - */ - - var warnNonExistent; - if ('development' !== 'production') { - warnNonExistent = function (path, vm) { - warn('You are setting a non-existent path "' + path.raw + '" ' + 'on a vm instance. Consider pre-initializing the property ' + 'with the "data" option for more reliable reactivity ' + 'and better performance.', vm); - }; - } - - /** - * Set on an object from a path - * - * @param {Object} obj - * @param {String | Array} path - * @param {*} val - */ - - function setPath(obj, path, val) { - var original = obj; - if (typeof path === 'string') { - path = parse(path); - } - if (!path || !isObject(obj)) { - return false; - } - var last, key; - for (var i = 0, l = path.length; i < l; i++) { - last = obj; - key = path[i]; - if (key.charAt(0) === '*') { - key = parseExpression(key.slice(1)).get.call(original, original); - } - if (i < l - 1) { - obj = obj[key]; - if (!isObject(obj)) { - obj = {}; - if ('development' !== 'production' && last._isVue) { - warnNonExistent(path, last); - } - set(last, key, obj); - } - } else { - if (isArray(obj)) { - obj.$set(key, val); - } else if (key in obj) { - obj[key] = val; - } else { - if ('development' !== 'production' && obj._isVue) { - warnNonExistent(path, obj); - } - set(obj, key, val); - } - } - } - return true; - } - -var path = Object.freeze({ - parsePath: parsePath, - getPath: getPath, - setPath: setPath - }); - - var expressionCache = new Cache(1000); - - var allowedKeywords = 'Math,Date,this,true,false,null,undefined,Infinity,NaN,' + 'isNaN,isFinite,decodeURI,decodeURIComponent,encodeURI,' + 'encodeURIComponent,parseInt,parseFloat'; - var allowedKeywordsRE = new RegExp('^(' + allowedKeywords.replace(/,/g, '\\b|') + '\\b)'); - - // keywords that don't make sense inside expressions - var improperKeywords = 'break,case,class,catch,const,continue,debugger,default,' + 'delete,do,else,export,extends,finally,for,function,if,' + 'import,in,instanceof,let,return,super,switch,throw,try,' + 'var,while,with,yield,enum,await,implements,package,' + 'protected,static,interface,private,public'; - var improperKeywordsRE = new RegExp('^(' + improperKeywords.replace(/,/g, '\\b|') + '\\b)'); - - var wsRE = /\s/g; - var newlineRE = /\n/g; - var saveRE = /[\{,]\s*[\w\$_]+\s*:|('(?:[^'\\]|\\.)*'|"(?:[^"\\]|\\.)*"|`(?:[^`\\]|\\.)*\$\{|\}(?:[^`\\]|\\.)*`|`(?:[^`\\]|\\.)*`)|new |typeof |void /g; - var restoreRE = /"(\d+)"/g; - var pathTestRE = /^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*|\['.*?'\]|\[".*?"\]|\[\d+\]|\[[A-Za-z_$][\w$]*\])*$/; - var identRE = /[^\w$\.](?:[A-Za-z_$][\w$]*)/g; - var literalValueRE$1 = /^(?:true|false|null|undefined|Infinity|NaN)$/; - - function noop() {} - - /** - * Save / Rewrite / Restore - * - * When rewriting paths found in an expression, it is - * possible for the same letter sequences to be found in - * strings and Object literal property keys. Therefore we - * remove and store these parts in a temporary array, and - * restore them after the path rewrite. - */ - - var saved = []; - - /** - * Save replacer - * - * The save regex can match two possible cases: - * 1. An opening object literal - * 2. A string - * If matched as a plain string, we need to escape its - * newlines, since the string needs to be preserved when - * generating the function body. - * - * @param {String} str - * @param {String} isString - str if matched as a string - * @return {String} - placeholder with index - */ - - function save(str, isString) { - var i = saved.length; - saved[i] = isString ? str.replace(newlineRE, '\\n') : str; - return '"' + i + '"'; - } - - /** - * Path rewrite replacer - * - * @param {String} raw - * @return {String} - */ - - function rewrite(raw) { - var c = raw.charAt(0); - var path = raw.slice(1); - if (allowedKeywordsRE.test(path)) { - return raw; - } else { - path = path.indexOf('"') > -1 ? path.replace(restoreRE, restore) : path; - return c + 'scope.' + path; - } - } - - /** - * Restore replacer - * - * @param {String} str - * @param {String} i - matched save index - * @return {String} - */ - - function restore(str, i) { - return saved[i]; - } - - /** - * Rewrite an expression, prefixing all path accessors with - * `scope.` and generate getter/setter functions. - * - * @param {String} exp - * @return {Function} - */ - - function compileGetter(exp) { - if (improperKeywordsRE.test(exp)) { - 'development' !== 'production' && warn('Avoid using reserved keywords in expression: ' + exp); - } - // reset state - saved.length = 0; - // save strings and object literal keys - var body = exp.replace(saveRE, save).replace(wsRE, ''); - // rewrite all paths - // pad 1 space here because the regex matches 1 extra char - body = (' ' + body).replace(identRE, rewrite).replace(restoreRE, restore); - return makeGetterFn(body); - } - - /** - * Build a getter function. Requires eval. - * - * We isolate the try/catch so it doesn't affect the - * optimization of the parse function when it is not called. - * - * @param {String} body - * @return {Function|undefined} - */ - - function makeGetterFn(body) { - try { - /* eslint-disable no-new-func */ - return new Function('scope', 'return ' + body + ';'); - /* eslint-enable no-new-func */ - } catch (e) { - if ('development' !== 'production') { - /* istanbul ignore if */ - if (e.toString().match(/unsafe-eval|CSP/)) { - warn('It seems you are using the default build of Vue.js in an environment ' + 'with Content Security Policy that prohibits unsafe-eval. ' + 'Use the CSP-compliant build instead: ' + 'http://vuejs.org/guide/installation.html#CSP-compliant-build'); - } else { - warn('Invalid expression. ' + 'Generated function body: ' + body); - } - } - return noop; - } - } - - /** - * Compile a setter function for the expression. - * - * @param {String} exp - * @return {Function|undefined} - */ - - function compileSetter(exp) { - var path = parsePath(exp); - if (path) { - return function (scope, val) { - setPath(scope, path, val); - }; - } else { - 'development' !== 'production' && warn('Invalid setter expression: ' + exp); - } - } - - /** - * Parse an expression into re-written getter/setters. - * - * @param {String} exp - * @param {Boolean} needSet - * @return {Function} - */ - - function parseExpression(exp, needSet) { - exp = exp.trim(); - // try cache - var hit = expressionCache.get(exp); - if (hit) { - if (needSet && !hit.set) { - hit.set = compileSetter(hit.exp); - } - return hit; - } - var res = { exp: exp }; - res.get = isSimplePath(exp) && exp.indexOf('[') < 0 - // optimized super simple getter - ? makeGetterFn('scope.' + exp) - // dynamic getter - : compileGetter(exp); - if (needSet) { - res.set = compileSetter(exp); - } - expressionCache.put(exp, res); - return res; - } - - /** - * Check if an expression is a simple path. - * - * @param {String} exp - * @return {Boolean} - */ - - function isSimplePath(exp) { - return pathTestRE.test(exp) && - // don't treat literal values as paths - !literalValueRE$1.test(exp) && - // Math constants e.g. Math.PI, Math.E etc. - exp.slice(0, 5) !== 'Math.'; - } - -var expression = Object.freeze({ - parseExpression: parseExpression, - isSimplePath: isSimplePath - }); - - // we have two separate queues: one for directive updates - // and one for user watcher registered via $watch(). - // we want to guarantee directive updates to be called - // before user watchers so that when user watchers are - // triggered, the DOM would have already been in updated - // state. - - var queue = []; - var userQueue = []; - var has = {}; - var circular = {}; - var waiting = false; - - /** - * Reset the batcher's state. - */ - - function resetBatcherState() { - queue.length = 0; - userQueue.length = 0; - has = {}; - circular = {}; - waiting = false; - } - - /** - * Flush both queues and run the watchers. - */ - - function flushBatcherQueue() { - var _again = true; - - _function: while (_again) { - _again = false; - - runBatcherQueue(queue); - runBatcherQueue(userQueue); - // user watchers triggered more watchers, - // keep flushing until it depletes - if (queue.length) { - _again = true; - continue _function; - } - // dev tool hook - /* istanbul ignore if */ - if (devtools && config.devtools) { - devtools.emit('flush'); - } - resetBatcherState(); - } - } - - /** - * Run the watchers in a single queue. - * - * @param {Array} queue - */ - - function runBatcherQueue(queue) { - // do not cache length because more watchers might be pushed - // as we run existing watchers - for (var i = 0; i < queue.length; i++) { - var watcher = queue[i]; - var id = watcher.id; - has[id] = null; - watcher.run(); - // in dev build, check and stop circular updates. - if ('development' !== 'production' && has[id] != null) { - circular[id] = (circular[id] || 0) + 1; - if (circular[id] > config._maxUpdateCount) { - warn('You may have an infinite update loop for watcher ' + 'with expression "' + watcher.expression + '"', watcher.vm); - break; - } - } - } - queue.length = 0; - } - - /** - * Push a watcher into the watcher queue. - * Jobs with duplicate IDs will be skipped unless it's - * pushed when the queue is being flushed. - * - * @param {Watcher} watcher - * properties: - * - {Number} id - * - {Function} run - */ - - function pushWatcher(watcher) { - var id = watcher.id; - if (has[id] == null) { - // push watcher into appropriate queue - var q = watcher.user ? userQueue : queue; - has[id] = q.length; - q.push(watcher); - // queue the flush - if (!waiting) { - waiting = true; - nextTick(flushBatcherQueue); - } - } - } - - var uid$2 = 0; - - /** - * A watcher parses an expression, collects dependencies, - * and fires callback when the expression value changes. - * This is used for both the $watch() api and directives. - * - * @param {Vue} vm - * @param {String|Function} expOrFn - * @param {Function} cb - * @param {Object} options - * - {Array} filters - * - {Boolean} twoWay - * - {Boolean} deep - * - {Boolean} user - * - {Boolean} sync - * - {Boolean} lazy - * - {Function} [preProcess] - * - {Function} [postProcess] - * @constructor - */ - function Watcher(vm, expOrFn, cb, options) { - // mix in options - if (options) { - extend(this, options); - } - var isFn = typeof expOrFn === 'function'; - this.vm = vm; - vm._watchers.push(this); - this.expression = expOrFn; - this.cb = cb; - this.id = ++uid$2; // uid for batching - this.active = true; - this.dirty = this.lazy; // for lazy watchers - this.deps = []; - this.newDeps = []; - this.depIds = new _Set(); - this.newDepIds = new _Set(); - this.prevError = null; // for async error stacks - // parse expression for getter/setter - if (isFn) { - this.getter = expOrFn; - this.setter = undefined; - } else { - var res = parseExpression(expOrFn, this.twoWay); - this.getter = res.get; - this.setter = res.set; - } - this.value = this.lazy ? undefined : this.get(); - // state for avoiding false triggers for deep and Array - // watchers during vm._digest() - this.queued = this.shallow = false; - } - - /** - * Evaluate the getter, and re-collect dependencies. - */ - - Watcher.prototype.get = function () { - this.beforeGet(); - var scope = this.scope || this.vm; - var value; - try { - value = this.getter.call(scope, scope); - } catch (e) { - if ('development' !== 'production' && config.warnExpressionErrors) { - warn('Error when evaluating expression ' + '"' + this.expression + '": ' + e.toString(), this.vm); - } - } - // "touch" every property so they are all tracked as - // dependencies for deep watching - if (this.deep) { - traverse(value); - } - if (this.preProcess) { - value = this.preProcess(value); - } - if (this.filters) { - value = scope._applyFilters(value, null, this.filters, false); - } - if (this.postProcess) { - value = this.postProcess(value); - } - this.afterGet(); - return value; - }; - - /** - * Set the corresponding value with the setter. - * - * @param {*} value - */ - - Watcher.prototype.set = function (value) { - var scope = this.scope || this.vm; - if (this.filters) { - value = scope._applyFilters(value, this.value, this.filters, true); - } - try { - this.setter.call(scope, scope, value); - } catch (e) { - if ('development' !== 'production' && config.warnExpressionErrors) { - warn('Error when evaluating setter ' + '"' + this.expression + '": ' + e.toString(), this.vm); - } - } - // two-way sync for v-for alias - var forContext = scope.$forContext; - if (forContext && forContext.alias === this.expression) { - if (forContext.filters) { - 'development' !== 'production' && warn('It seems you are using two-way binding on ' + 'a v-for alias (' + this.expression + '), and the ' + 'v-for has filters. This will not work properly. ' + 'Either remove the filters or use an array of ' + 'objects and bind to object properties instead.', this.vm); - return; - } - forContext._withLock(function () { - if (scope.$key) { - // original is an object - forContext.rawValue[scope.$key] = value; - } else { - forContext.rawValue.$set(scope.$index, value); - } - }); - } - }; - - /** - * Prepare for dependency collection. - */ - - Watcher.prototype.beforeGet = function () { - Dep.target = this; - }; - - /** - * Add a dependency to this directive. - * - * @param {Dep} dep - */ - - Watcher.prototype.addDep = function (dep) { - var id = dep.id; - if (!this.newDepIds.has(id)) { - this.newDepIds.add(id); - this.newDeps.push(dep); - if (!this.depIds.has(id)) { - dep.addSub(this); - } - } - }; - - /** - * Clean up for dependency collection. - */ - - Watcher.prototype.afterGet = function () { - Dep.target = null; - var i = this.deps.length; - while (i--) { - var dep = this.deps[i]; - if (!this.newDepIds.has(dep.id)) { - dep.removeSub(this); - } - } - var tmp = this.depIds; - this.depIds = this.newDepIds; - this.newDepIds = tmp; - this.newDepIds.clear(); - tmp = this.deps; - this.deps = this.newDeps; - this.newDeps = tmp; - this.newDeps.length = 0; - }; - - /** - * Subscriber interface. - * Will be called when a dependency changes. - * - * @param {Boolean} shallow - */ - - Watcher.prototype.update = function (shallow) { - if (this.lazy) { - this.dirty = true; - } else if (this.sync || !config.async) { - this.run(); - } else { - // if queued, only overwrite shallow with non-shallow, - // but not the other way around. - this.shallow = this.queued ? shallow ? this.shallow : false : !!shallow; - this.queued = true; - // record before-push error stack in debug mode - /* istanbul ignore if */ - if ('development' !== 'production' && config.debug) { - this.prevError = new Error('[vue] async stack trace'); - } - pushWatcher(this); - } - }; - - /** - * Batcher job interface. - * Will be called by the batcher. - */ - - Watcher.prototype.run = function () { - if (this.active) { - var value = this.get(); - if (value !== this.value || - // Deep watchers and watchers on Object/Arrays should fire even - // when the value is the same, because the value may - // have mutated; but only do so if this is a - // non-shallow update (caused by a vm digest). - (isObject(value) || this.deep) && !this.shallow) { - // set new value - var oldValue = this.value; - this.value = value; - // in debug + async mode, when a watcher callbacks - // throws, we also throw the saved before-push error - // so the full cross-tick stack trace is available. - var prevError = this.prevError; - /* istanbul ignore if */ - if ('development' !== 'production' && config.debug && prevError) { - this.prevError = null; - try { - this.cb.call(this.vm, value, oldValue); - } catch (e) { - nextTick(function () { - throw prevError; - }, 0); - throw e; - } - } else { - this.cb.call(this.vm, value, oldValue); - } - } - this.queued = this.shallow = false; - } - }; - - /** - * Evaluate the value of the watcher. - * This only gets called for lazy watchers. - */ - - Watcher.prototype.evaluate = function () { - // avoid overwriting another watcher that is being - // collected. - var current = Dep.target; - this.value = this.get(); - this.dirty = false; - Dep.target = current; - }; - - /** - * Depend on all deps collected by this watcher. - */ - - Watcher.prototype.depend = function () { - var i = this.deps.length; - while (i--) { - this.deps[i].depend(); - } - }; - - /** - * Remove self from all dependencies' subcriber list. - */ - - Watcher.prototype.teardown = function () { - if (this.active) { - // remove self from vm's watcher list - // this is a somewhat expensive operation so we skip it - // if the vm is being destroyed or is performing a v-for - // re-render (the watcher list is then filtered by v-for). - if (!this.vm._isBeingDestroyed && !this.vm._vForRemoving) { - this.vm._watchers.$remove(this); - } - var i = this.deps.length; - while (i--) { - this.deps[i].removeSub(this); - } - this.active = false; - this.vm = this.cb = this.value = null; - } - }; - - /** - * Recrusively traverse an object to evoke all converted - * getters, so that every nested property inside the object - * is collected as a "deep" dependency. - * - * @param {*} val - */ - - var seenObjects = new _Set(); - function traverse(val, seen) { - var i = undefined, - keys = undefined; - if (!seen) { - seen = seenObjects; - seen.clear(); - } - var isA = isArray(val); - var isO = isObject(val); - if ((isA || isO) && Object.isExtensible(val)) { - if (val.__ob__) { - var depId = val.__ob__.dep.id; - if (seen.has(depId)) { - return; - } else { - seen.add(depId); - } - } - if (isA) { - i = val.length; - while (i--) traverse(val[i], seen); - } else if (isO) { - keys = Object.keys(val); - i = keys.length; - while (i--) traverse(val[keys[i]], seen); - } - } - } - - var text$1 = { - - bind: function bind() { - this.attr = this.el.nodeType === 3 ? 'data' : 'textContent'; - }, - - update: function update(value) { - this.el[this.attr] = _toString(value); - } - }; - - var templateCache = new Cache(1000); - var idSelectorCache = new Cache(1000); - - var map = { - efault: [0, '', ''], - legend: [1, '
', '
'], - tr: [2, '', '
'], - col: [2, '', '
'] - }; - - map.td = map.th = [3, '', '
']; - - map.option = map.optgroup = [1, '']; - - map.thead = map.tbody = map.colgroup = map.caption = map.tfoot = [1, '', '
']; - - map.g = map.defs = map.symbol = map.use = map.image = map.text = map.circle = map.ellipse = map.line = map.path = map.polygon = map.polyline = map.rect = [1, '', '']; - - /** - * Check if a node is a supported template node with a - * DocumentFragment content. - * - * @param {Node} node - * @return {Boolean} - */ - - function isRealTemplate(node) { - return isTemplate(node) && isFragment(node.content); - } - - var tagRE$1 = /<([\w:-]+)/; - var entityRE = /&#?\w+?;/; - var commentRE = / E + } + entry.newer = undefined; // D --x + entry.older = this.tail; // D. --> E + if (this.tail) { + this.tail.newer = entry; // E. <-- D + } + this.tail = entry; + return returnEntry ? entry : entry.value; + }; + + var cache$1 = new Cache(1000); + var filterTokenRE = /[^\s'"]+|'[^']*'|"[^"]*"/g; + var reservedArgRE = /^in$|^-?\d+/; + + /** + * Parser state + */ + + var str; + var dir; + var c; + var prev; + var i; + var l; + var lastFilterIndex; + var inSingle; + var inDouble; + var curly; + var square; + var paren; + /** + * Push a filter to the current directive object + */ + + function pushFilter() { + var exp = str.slice(lastFilterIndex, i).trim(); + var filter; + if (exp) { + filter = {}; + var tokens = exp.match(filterTokenRE); + filter.name = tokens[0]; + if (tokens.length > 1) { + filter.args = tokens.slice(1).map(processFilterArg); + } + } + if (filter) { + (dir.filters = dir.filters || []).push(filter); + } + lastFilterIndex = i + 1; + } + + /** + * Check if an argument is dynamic and strip quotes. + * + * @param {String} arg + * @return {Object} + */ + + function processFilterArg(arg) { + if (reservedArgRE.test(arg)) { + return { + value: toNumber(arg), + dynamic: false + }; + } else { + var stripped = stripQuotes(arg); + var dynamic = stripped === arg; + return { + value: dynamic ? arg : stripped, + dynamic: dynamic + }; + } + } + + /** + * Parse a directive value and extract the expression + * and its filters into a descriptor. + * + * Example: + * + * "a + 1 | uppercase" will yield: + * { + * expression: 'a + 1', + * filters: [ + * { name: 'uppercase', args: null } + * ] + * } + * + * @param {String} s + * @return {Object} + */ + + function parseDirective(s) { + var hit = cache$1.get(s); + if (hit) { + return hit; + } + + // reset parser state + str = s; + inSingle = inDouble = false; + curly = square = paren = 0; + lastFilterIndex = 0; + dir = {}; + + for (i = 0, l = str.length; i < l; i++) { + prev = c; + c = str.charCodeAt(i); + if (inSingle) { + // check single quote + if (c === 0x27 && prev !== 0x5C) inSingle = !inSingle; + } else if (inDouble) { + // check double quote + if (c === 0x22 && prev !== 0x5C) inDouble = !inDouble; + } else if (c === 0x7C && // pipe + str.charCodeAt(i + 1) !== 0x7C && str.charCodeAt(i - 1) !== 0x7C) { + if (dir.expression == null) { + // first filter, end of expression + lastFilterIndex = i + 1; + dir.expression = str.slice(0, i).trim(); + } else { + // already has filter + pushFilter(); + } + } else { + switch (c) { + case 0x22: + inDouble = true;break; // " + case 0x27: + inSingle = true;break; // ' + case 0x28: + paren++;break; // ( + case 0x29: + paren--;break; // ) + case 0x5B: + square++;break; // [ + case 0x5D: + square--;break; // ] + case 0x7B: + curly++;break; // { + case 0x7D: + curly--;break; // } + } + } + } + + if (dir.expression == null) { + dir.expression = str.slice(0, i).trim(); + } else if (lastFilterIndex !== 0) { + pushFilter(); + } + + cache$1.put(s, dir); + return dir; + } + +var directive = Object.freeze({ + parseDirective: parseDirective + }); + + var regexEscapeRE = /[-.*+?^${}()|[\]\/\\]/g; + var cache = undefined; + var tagRE = undefined; + var htmlRE = undefined; + /** + * Escape a string so it can be used in a RegExp + * constructor. + * + * @param {String} str + */ + + function escapeRegex(str) { + return str.replace(regexEscapeRE, '\\$&'); + } + + function compileRegex() { + var open = escapeRegex(config.delimiters[0]); + var close = escapeRegex(config.delimiters[1]); + var unsafeOpen = escapeRegex(config.unsafeDelimiters[0]); + var unsafeClose = escapeRegex(config.unsafeDelimiters[1]); + tagRE = new RegExp(unsafeOpen + '((?:.|\\n)+?)' + unsafeClose + '|' + open + '((?:.|\\n)+?)' + close, 'g'); + htmlRE = new RegExp('^' + unsafeOpen + '((?:.|\\n)+?)' + unsafeClose + '$'); + // reset cache + cache = new Cache(1000); + } + + /** + * Parse a template text string into an array of tokens. + * + * @param {String} text + * @return {Array | null} + * - {String} type + * - {String} value + * - {Boolean} [html] + * - {Boolean} [oneTime] + */ + + function parseText(text) { + if (!cache) { + compileRegex(); + } + var hit = cache.get(text); + if (hit) { + return hit; + } + if (!tagRE.test(text)) { + return null; + } + var tokens = []; + var lastIndex = tagRE.lastIndex = 0; + var match, index, html, value, first, oneTime; + /* eslint-disable no-cond-assign */ + while (match = tagRE.exec(text)) { + /* eslint-enable no-cond-assign */ + index = match.index; + // push text token + if (index > lastIndex) { + tokens.push({ + value: text.slice(lastIndex, index) + }); + } + // tag token + html = htmlRE.test(match[0]); + value = html ? match[1] : match[2]; + first = value.charCodeAt(0); + oneTime = first === 42; // * + value = oneTime ? value.slice(1) : value; + tokens.push({ + tag: true, + value: value.trim(), + html: html, + oneTime: oneTime + }); + lastIndex = index + match[0].length; + } + if (lastIndex < text.length) { + tokens.push({ + value: text.slice(lastIndex) + }); + } + cache.put(text, tokens); + return tokens; + } + + /** + * Format a list of tokens into an expression. + * e.g. tokens parsed from 'a {{b}} c' can be serialized + * into one single expression as '"a " + b + " c"'. + * + * @param {Array} tokens + * @param {Vue} [vm] + * @return {String} + */ + + function tokensToExp(tokens, vm) { + if (tokens.length > 1) { + return tokens.map(function (token) { + return formatToken(token, vm); + }).join('+'); + } else { + return formatToken(tokens[0], vm, true); + } + } + + /** + * Format a single token. + * + * @param {Object} token + * @param {Vue} [vm] + * @param {Boolean} [single] + * @return {String} + */ + + function formatToken(token, vm, single) { + return token.tag ? token.oneTime && vm ? '"' + vm.$eval(token.value) + '"' : inlineFilters(token.value, single) : '"' + token.value + '"'; + } + + /** + * For an attribute with multiple interpolation tags, + * e.g. attr="some-{{thing | filter}}", in order to combine + * the whole thing into a single watchable expression, we + * have to inline those filters. This function does exactly + * that. This is a bit hacky but it avoids heavy changes + * to directive parser and watcher mechanism. + * + * @param {String} exp + * @param {Boolean} single + * @return {String} + */ + + var filterRE = /[^|]\|[^|]/; + function inlineFilters(exp, single) { + if (!filterRE.test(exp)) { + return single ? exp : '(' + exp + ')'; + } else { + var dir = parseDirective(exp); + if (!dir.filters) { + return '(' + exp + ')'; + } else { + return 'this._applyFilters(' + dir.expression + // value + ',null,' + // oldValue (null for read) + JSON.stringify(dir.filters) + // filter descriptors + ',false)'; // write? + } + } + } + +var text = Object.freeze({ + compileRegex: compileRegex, + parseText: parseText, + tokensToExp: tokensToExp + }); + + var delimiters = ['{{', '}}']; + var unsafeDelimiters = ['{{{', '}}}']; + + var config = Object.defineProperties({ + + /** + * Whether to print debug messages. + * Also enables stack trace for warnings. + * + * @type {Boolean} + */ + + debug: false, + + /** + * Whether to suppress warnings. + * + * @type {Boolean} + */ + + silent: false, + + /** + * Whether to use async rendering. + */ + + async: true, + + /** + * Whether to warn against errors caught when evaluating + * expressions. + */ + + warnExpressionErrors: true, + + /** + * Whether to allow devtools inspection. + * Disabled by default in production builds. + */ + + devtools: 'development' !== 'production', + + /** + * Internal flag to indicate the delimiters have been + * changed. + * + * @type {Boolean} + */ + + _delimitersChanged: true, + + /** + * List of asset types that a component can own. + * + * @type {Array} + */ + + _assetTypes: ['component', 'directive', 'elementDirective', 'filter', 'transition', 'partial'], + + /** + * prop binding modes + */ + + _propBindingModes: { + ONE_WAY: 0, + TWO_WAY: 1, + ONE_TIME: 2 + }, + + /** + * Max circular updates allowed in a batcher flush cycle. + */ + + _maxUpdateCount: 100 + + }, { + delimiters: { /** + * Interpolation delimiters. Changing these would trigger + * the text parser to re-compile the regular expressions. + * + * @type {Array} + */ + + get: function get() { + return delimiters; + }, + set: function set(val) { + delimiters = val; + compileRegex(); + }, + configurable: true, + enumerable: true + }, + unsafeDelimiters: { + get: function get() { + return unsafeDelimiters; + }, + set: function set(val) { + unsafeDelimiters = val; + compileRegex(); + }, + configurable: true, + enumerable: true + } + }); + + var warn = undefined; + var formatComponentName = undefined; + + if ('development' !== 'production') { + (function () { + var hasConsole = typeof console !== 'undefined'; + + warn = function (msg, vm) { + if (hasConsole && !config.silent) { + console.error('[Vue warn]: ' + msg + (vm ? formatComponentName(vm) : '')); + } + }; + + formatComponentName = function (vm) { + var name = vm._isVue ? vm.$options.name : vm.name; + return name ? ' (found in component: <' + hyphenate(name) + '>)' : ''; + }; + })(); + } + + /** + * Append with transition. + * + * @param {Element} el + * @param {Element} target + * @param {Vue} vm + * @param {Function} [cb] + */ + + function appendWithTransition(el, target, vm, cb) { + applyTransition(el, 1, function () { + target.appendChild(el); + }, vm, cb); + } + + /** + * InsertBefore with transition. + * + * @param {Element} el + * @param {Element} target + * @param {Vue} vm + * @param {Function} [cb] + */ + + function beforeWithTransition(el, target, vm, cb) { + applyTransition(el, 1, function () { + before(el, target); + }, vm, cb); + } + + /** + * Remove with transition. + * + * @param {Element} el + * @param {Vue} vm + * @param {Function} [cb] + */ + + function removeWithTransition(el, vm, cb) { + applyTransition(el, -1, function () { + remove(el); + }, vm, cb); + } + + /** + * Apply transitions with an operation callback. + * + * @param {Element} el + * @param {Number} direction + * 1: enter + * -1: leave + * @param {Function} op - the actual DOM operation + * @param {Vue} vm + * @param {Function} [cb] + */ + + function applyTransition(el, direction, op, vm, cb) { + var transition = el.__v_trans; + if (!transition || + // skip if there are no js hooks and CSS transition is + // not supported + !transition.hooks && !transitionEndEvent || + // skip transitions for initial compile + !vm._isCompiled || + // if the vm is being manipulated by a parent directive + // during the parent's compilation phase, skip the + // animation. + vm.$parent && !vm.$parent._isCompiled) { + op(); + if (cb) cb(); + return; + } + var action = direction > 0 ? 'enter' : 'leave'; + transition[action](op, cb); + } + +var transition = Object.freeze({ + appendWithTransition: appendWithTransition, + beforeWithTransition: beforeWithTransition, + removeWithTransition: removeWithTransition, + applyTransition: applyTransition + }); + + /** + * Query an element selector if it's not an element already. + * + * @param {String|Element} el + * @return {Element} + */ + + function query(el) { + if (typeof el === 'string') { + var selector = el; + el = document.querySelector(el); + if (!el) { + 'development' !== 'production' && warn('Cannot find element: ' + selector); + } + } + return el; + } + + /** + * Check if a node is in the document. + * Note: document.documentElement.contains should work here + * but always returns false for comment nodes in phantomjs, + * making unit tests difficult. This is fixed by doing the + * contains() check on the node's parentNode instead of + * the node itself. + * + * @param {Node} node + * @return {Boolean} + */ + + function inDoc(node) { + if (!node) return false; + var doc = node.ownerDocument.documentElement; + var parent = node.parentNode; + return doc === node || doc === parent || !!(parent && parent.nodeType === 1 && doc.contains(parent)); + } + + /** + * Get and remove an attribute from a node. + * + * @param {Node} node + * @param {String} _attr + */ + + function getAttr(node, _attr) { + var val = node.getAttribute(_attr); + if (val !== null) { + node.removeAttribute(_attr); + } + return val; + } + + /** + * Get an attribute with colon or v-bind: prefix. + * + * @param {Node} node + * @param {String} name + * @return {String|null} + */ + + function getBindAttr(node, name) { + var val = getAttr(node, ':' + name); + if (val === null) { + val = getAttr(node, 'v-bind:' + name); + } + return val; + } + + /** + * Check the presence of a bind attribute. + * + * @param {Node} node + * @param {String} name + * @return {Boolean} + */ + + function hasBindAttr(node, name) { + return node.hasAttribute(name) || node.hasAttribute(':' + name) || node.hasAttribute('v-bind:' + name); + } + + /** + * Insert el before target + * + * @param {Element} el + * @param {Element} target + */ + + function before(el, target) { + target.parentNode.insertBefore(el, target); + } + + /** + * Insert el after target + * + * @param {Element} el + * @param {Element} target + */ + + function after(el, target) { + if (target.nextSibling) { + before(el, target.nextSibling); + } else { + target.parentNode.appendChild(el); + } + } + + /** + * Remove el from DOM + * + * @param {Element} el + */ + + function remove(el) { + el.parentNode.removeChild(el); + } + + /** + * Prepend el to target + * + * @param {Element} el + * @param {Element} target + */ + + function prepend(el, target) { + if (target.firstChild) { + before(el, target.firstChild); + } else { + target.appendChild(el); + } + } + + /** + * Replace target with el + * + * @param {Element} target + * @param {Element} el + */ + + function replace(target, el) { + var parent = target.parentNode; + if (parent) { + parent.replaceChild(el, target); + } + } + + /** + * Add event listener shorthand. + * + * @param {Element} el + * @param {String} event + * @param {Function} cb + * @param {Boolean} [useCapture] + */ + + function on(el, event, cb, useCapture) { + el.addEventListener(event, cb, useCapture); + } + + /** + * Remove event listener shorthand. + * + * @param {Element} el + * @param {String} event + * @param {Function} cb + */ + + function off(el, event, cb) { + el.removeEventListener(event, cb); + } + + /** + * For IE9 compat: when both class and :class are present + * getAttribute('class') returns wrong value... + * + * @param {Element} el + * @return {String} + */ + + function getClass(el) { + var classname = el.className; + if (typeof classname === 'object') { + classname = classname.baseVal || ''; + } + return classname; + } + + /** + * In IE9, setAttribute('class') will result in empty class + * if the element also has the :class attribute; However in + * PhantomJS, setting `className` does not work on SVG elements... + * So we have to do a conditional check here. + * + * @param {Element} el + * @param {String} cls + */ + + function setClass(el, cls) { + /* istanbul ignore if */ + if (isIE9 && !/svg$/.test(el.namespaceURI)) { + el.className = cls; + } else { + el.setAttribute('class', cls); + } + } + + /** + * Add class with compatibility for IE & SVG + * + * @param {Element} el + * @param {String} cls + */ + + function addClass(el, cls) { + if (el.classList) { + el.classList.add(cls); + } else { + var cur = ' ' + getClass(el) + ' '; + if (cur.indexOf(' ' + cls + ' ') < 0) { + setClass(el, (cur + cls).trim()); + } + } + } + + /** + * Remove class with compatibility for IE & SVG + * + * @param {Element} el + * @param {String} cls + */ + + function removeClass(el, cls) { + if (el.classList) { + el.classList.remove(cls); + } else { + var cur = ' ' + getClass(el) + ' '; + var tar = ' ' + cls + ' '; + while (cur.indexOf(tar) >= 0) { + cur = cur.replace(tar, ' '); + } + setClass(el, cur.trim()); + } + if (!el.className) { + el.removeAttribute('class'); + } + } + + /** + * Extract raw content inside an element into a temporary + * container div + * + * @param {Element} el + * @param {Boolean} asFragment + * @return {Element|DocumentFragment} + */ + + function extractContent(el, asFragment) { + var child; + var rawContent; + /* istanbul ignore if */ + if (isTemplate(el) && isFragment(el.content)) { + el = el.content; + } + if (el.hasChildNodes()) { + trimNode(el); + rawContent = asFragment ? document.createDocumentFragment() : document.createElement('div'); + /* eslint-disable no-cond-assign */ + while (child = el.firstChild) { + /* eslint-enable no-cond-assign */ + rawContent.appendChild(child); + } + } + return rawContent; + } + + /** + * Trim possible empty head/tail text and comment + * nodes inside a parent. + * + * @param {Node} node + */ + + function trimNode(node) { + var child; + /* eslint-disable no-sequences */ + while ((child = node.firstChild, isTrimmable(child))) { + node.removeChild(child); + } + while ((child = node.lastChild, isTrimmable(child))) { + node.removeChild(child); + } + /* eslint-enable no-sequences */ + } + + function isTrimmable(node) { + return node && (node.nodeType === 3 && !node.data.trim() || node.nodeType === 8); + } + + /** + * Check if an element is a template tag. + * Note if the template appears inside an SVG its tagName + * will be in lowercase. + * + * @param {Element} el + */ + + function isTemplate(el) { + return el.tagName && el.tagName.toLowerCase() === 'template'; + } + + /** + * Create an "anchor" for performing dom insertion/removals. + * This is used in a number of scenarios: + * - fragment instance + * - v-html + * - v-if + * - v-for + * - component + * + * @param {String} content + * @param {Boolean} persist - IE trashes empty textNodes on + * cloneNode(true), so in certain + * cases the anchor needs to be + * non-empty to be persisted in + * templates. + * @return {Comment|Text} + */ + + function createAnchor(content, persist) { + var anchor = config.debug ? document.createComment(content) : document.createTextNode(persist ? ' ' : ''); + anchor.__v_anchor = true; + return anchor; + } + + /** + * Find a component ref attribute that starts with $. + * + * @param {Element} node + * @return {String|undefined} + */ + + var refRE = /^v-ref:/; + + function findRef(node) { + if (node.hasAttributes()) { + var attrs = node.attributes; + for (var i = 0, l = attrs.length; i < l; i++) { + var name = attrs[i].name; + if (refRE.test(name)) { + return camelize(name.replace(refRE, '')); + } + } + } + } + + /** + * Map a function to a range of nodes . + * + * @param {Node} node + * @param {Node} end + * @param {Function} op + */ + + function mapNodeRange(node, end, op) { + var next; + while (node !== end) { + next = node.nextSibling; + op(node); + node = next; + } + op(end); + } + + /** + * Remove a range of nodes with transition, store + * the nodes in a fragment with correct ordering, + * and call callback when done. + * + * @param {Node} start + * @param {Node} end + * @param {Vue} vm + * @param {DocumentFragment} frag + * @param {Function} cb + */ + + function removeNodeRange(start, end, vm, frag, cb) { + var done = false; + var removed = 0; + var nodes = []; + mapNodeRange(start, end, function (node) { + if (node === end) done = true; + nodes.push(node); + removeWithTransition(node, vm, onRemoved); + }); + function onRemoved() { + removed++; + if (done && removed >= nodes.length) { + for (var i = 0; i < nodes.length; i++) { + frag.appendChild(nodes[i]); + } + cb && cb(); + } + } + } + + /** + * Check if a node is a DocumentFragment. + * + * @param {Node} node + * @return {Boolean} + */ + + function isFragment(node) { + return node && node.nodeType === 11; + } + + /** + * Get outerHTML of elements, taking care + * of SVG elements in IE as well. + * + * @param {Element} el + * @return {String} + */ + + function getOuterHTML(el) { + if (el.outerHTML) { + return el.outerHTML; + } else { + var container = document.createElement('div'); + container.appendChild(el.cloneNode(true)); + return container.innerHTML; + } + } + + var commonTagRE = /^(div|p|span|img|a|b|i|br|ul|ol|li|h1|h2|h3|h4|h5|h6|code|pre|table|th|td|tr|form|label|input|select|option|nav|article|section|header|footer)$/i; + var reservedTagRE = /^(slot|partial|component)$/i; + + var isUnknownElement = undefined; + if ('development' !== 'production') { + isUnknownElement = function (el, tag) { + if (tag.indexOf('-') > -1) { + // http://stackoverflow.com/a/28210364/1070244 + return el.constructor === window.HTMLUnknownElement || el.constructor === window.HTMLElement; + } else { + return (/HTMLUnknownElement/.test(el.toString()) && + // Chrome returns unknown for several HTML5 elements. + // https://code.google.com/p/chromium/issues/detail?id=540526 + // Firefox returns unknown for some "Interactive elements." + !/^(data|time|rtc|rb|details|dialog|summary)$/.test(tag) + ); + } + }; + } + + /** + * Check if an element is a component, if yes return its + * component id. + * + * @param {Element} el + * @param {Object} options + * @return {Object|undefined} + */ + + function checkComponentAttr(el, options) { + var tag = el.tagName.toLowerCase(); + var hasAttrs = el.hasAttributes(); + if (!commonTagRE.test(tag) && !reservedTagRE.test(tag)) { + if (resolveAsset(options, 'components', tag)) { + return { id: tag }; + } else { + var is = hasAttrs && getIsBinding(el, options); + if (is) { + return is; + } else if ('development' !== 'production') { + var expectedTag = options._componentNameMap && options._componentNameMap[tag]; + if (expectedTag) { + warn('Unknown custom element: <' + tag + '> - ' + 'did you mean <' + expectedTag + '>? ' + 'HTML is case-insensitive, remember to use kebab-case in templates.'); + } else if (isUnknownElement(el, tag)) { + warn('Unknown custom element: <' + tag + '> - did you ' + 'register the component correctly? For recursive components, ' + 'make sure to provide the "name" option.'); + } + } + } + } else if (hasAttrs) { + return getIsBinding(el, options); + } + } + + /** + * Get "is" binding from an element. + * + * @param {Element} el + * @param {Object} options + * @return {Object|undefined} + */ + + function getIsBinding(el, options) { + // dynamic syntax + var exp = el.getAttribute('is'); + if (exp != null) { + if (resolveAsset(options, 'components', exp)) { + el.removeAttribute('is'); + return { id: exp }; + } + } else { + exp = getBindAttr(el, 'is'); + if (exp != null) { + return { id: exp, dynamic: true }; + } + } + } + + /** + * Option overwriting strategies are functions that handle + * how to merge a parent option value and a child option + * value into the final value. + * + * All strategy functions follow the same signature: + * + * @param {*} parentVal + * @param {*} childVal + * @param {Vue} [vm] + */ + + var strats = config.optionMergeStrategies = Object.create(null); + + /** + * Helper that recursively merges two data objects together. + */ + + function mergeData(to, from) { + var key, toVal, fromVal; + for (key in from) { + toVal = to[key]; + fromVal = from[key]; + if (!hasOwn(to, key)) { + set(to, key, fromVal); + } else if (isObject(toVal) && isObject(fromVal)) { + mergeData(toVal, fromVal); + } + } + return to; + } + + /** + * Data + */ + + strats.data = function (parentVal, childVal, vm) { + if (!vm) { + // in a Vue.extend merge, both should be functions + if (!childVal) { + return parentVal; + } + if (typeof childVal !== 'function') { + 'development' !== 'production' && warn('The "data" option should be a function ' + 'that returns a per-instance value in component ' + 'definitions.', vm); + return parentVal; + } + if (!parentVal) { + return childVal; + } + // when parentVal & childVal are both present, + // we need to return a function that returns the + // merged result of both functions... no need to + // check if parentVal is a function here because + // it has to be a function to pass previous merges. + return function mergedDataFn() { + return mergeData(childVal.call(this), parentVal.call(this)); + }; + } else if (parentVal || childVal) { + return function mergedInstanceDataFn() { + // instance merge + var instanceData = typeof childVal === 'function' ? childVal.call(vm) : childVal; + var defaultData = typeof parentVal === 'function' ? parentVal.call(vm) : undefined; + if (instanceData) { + return mergeData(instanceData, defaultData); + } else { + return defaultData; + } + }; + } + }; + + /** + * El + */ + + strats.el = function (parentVal, childVal, vm) { + if (!vm && childVal && typeof childVal !== 'function') { + 'development' !== 'production' && warn('The "el" option should be a function ' + 'that returns a per-instance value in component ' + 'definitions.', vm); + return; + } + var ret = childVal || parentVal; + // invoke the element factory if this is instance merge + return vm && typeof ret === 'function' ? ret.call(vm) : ret; + }; + + /** + * Hooks and param attributes are merged as arrays. + */ + + strats.init = strats.created = strats.ready = strats.attached = strats.detached = strats.beforeCompile = strats.compiled = strats.beforeDestroy = strats.destroyed = strats.activate = function (parentVal, childVal) { + return childVal ? parentVal ? parentVal.concat(childVal) : isArray(childVal) ? childVal : [childVal] : parentVal; + }; + + /** + * Assets + * + * When a vm is present (instance creation), we need to do + * a three-way merge between constructor options, instance + * options and parent options. + */ + + function mergeAssets(parentVal, childVal) { + var res = Object.create(parentVal || null); + return childVal ? extend(res, guardArrayAssets(childVal)) : res; + } + + config._assetTypes.forEach(function (type) { + strats[type + 's'] = mergeAssets; + }); + + /** + * Events & Watchers. + * + * Events & watchers hashes should not overwrite one + * another, so we merge them as arrays. + */ + + strats.watch = strats.events = function (parentVal, childVal) { + if (!childVal) return parentVal; + if (!parentVal) return childVal; + var ret = {}; + extend(ret, parentVal); + for (var key in childVal) { + var parent = ret[key]; + var child = childVal[key]; + if (parent && !isArray(parent)) { + parent = [parent]; + } + ret[key] = parent ? parent.concat(child) : [child]; + } + return ret; + }; + + /** + * Other object hashes. + */ + + strats.props = strats.methods = strats.computed = function (parentVal, childVal) { + if (!childVal) return parentVal; + if (!parentVal) return childVal; + var ret = Object.create(null); + extend(ret, parentVal); + extend(ret, childVal); + return ret; + }; + + /** + * Default strategy. + */ + + var defaultStrat = function defaultStrat(parentVal, childVal) { + return childVal === undefined ? parentVal : childVal; + }; + + /** + * Make sure component options get converted to actual + * constructors. + * + * @param {Object} options + */ + + function guardComponents(options) { + if (options.components) { + var components = options.components = guardArrayAssets(options.components); + var ids = Object.keys(components); + var def; + if ('development' !== 'production') { + var map = options._componentNameMap = {}; + } + for (var i = 0, l = ids.length; i < l; i++) { + var key = ids[i]; + if (commonTagRE.test(key) || reservedTagRE.test(key)) { + 'development' !== 'production' && warn('Do not use built-in or reserved HTML elements as component ' + 'id: ' + key); + continue; + } + // record a all lowercase <-> kebab-case mapping for + // possible custom element case error warning + if ('development' !== 'production') { + map[key.replace(/-/g, '').toLowerCase()] = hyphenate(key); + } + def = components[key]; + if (isPlainObject(def)) { + components[key] = Vue.extend(def); + } + } + } + } + + /** + * Ensure all props option syntax are normalized into the + * Object-based format. + * + * @param {Object} options + */ + + function guardProps(options) { + var props = options.props; + var i, val; + if (isArray(props)) { + options.props = {}; + i = props.length; + while (i--) { + val = props[i]; + if (typeof val === 'string') { + options.props[val] = null; + } else if (val.name) { + options.props[val.name] = val; + } + } + } else if (isPlainObject(props)) { + var keys = Object.keys(props); + i = keys.length; + while (i--) { + val = props[keys[i]]; + if (typeof val === 'function') { + props[keys[i]] = { type: val }; + } + } + } + } + + /** + * Guard an Array-format assets option and converted it + * into the key-value Object format. + * + * @param {Object|Array} assets + * @return {Object} + */ + + function guardArrayAssets(assets) { + if (isArray(assets)) { + var res = {}; + var i = assets.length; + var asset; + while (i--) { + asset = assets[i]; + var id = typeof asset === 'function' ? asset.options && asset.options.name || asset.id : asset.name || asset.id; + if (!id) { + 'development' !== 'production' && warn('Array-syntax assets must provide a "name" or "id" field.'); + } else { + res[id] = asset; + } + } + return res; + } + return assets; + } + + /** + * Merge two option objects into a new one. + * Core utility used in both instantiation and inheritance. + * + * @param {Object} parent + * @param {Object} child + * @param {Vue} [vm] - if vm is present, indicates this is + * an instantiation merge. + */ + + function mergeOptions(parent, child, vm) { + guardComponents(child); + guardProps(child); + if ('development' !== 'production') { + if (child.propsData && !vm) { + warn('propsData can only be used as an instantiation option.'); + } + } + var options = {}; + var key; + if (child['extends']) { + parent = typeof child['extends'] === 'function' ? mergeOptions(parent, child['extends'].options, vm) : mergeOptions(parent, child['extends'], vm); + } + if (child.mixins) { + for (var i = 0, l = child.mixins.length; i < l; i++) { + var mixin = child.mixins[i]; + var mixinOptions = mixin.prototype instanceof Vue ? mixin.options : mixin; + parent = mergeOptions(parent, mixinOptions, vm); + } + } + for (key in parent) { + mergeField(key); + } + for (key in child) { + if (!hasOwn(parent, key)) { + mergeField(key); + } + } + function mergeField(key) { + var strat = strats[key] || defaultStrat; + options[key] = strat(parent[key], child[key], vm, key); + } + return options; + } + + /** + * Resolve an asset. + * This function is used because child instances need access + * to assets defined in its ancestor chain. + * + * @param {Object} options + * @param {String} type + * @param {String} id + * @param {Boolean} warnMissing + * @return {Object|Function} + */ + + function resolveAsset(options, type, id, warnMissing) { + /* istanbul ignore if */ + if (typeof id !== 'string') { + return; + } + var assets = options[type]; + var camelizedId; + var res = assets[id] || + // camelCase ID + assets[camelizedId = camelize(id)] || + // Pascal Case ID + assets[camelizedId.charAt(0).toUpperCase() + camelizedId.slice(1)]; + if ('development' !== 'production' && warnMissing && !res) { + warn('Failed to resolve ' + type.slice(0, -1) + ': ' + id, options); + } + return res; + } + + var uid$1 = 0; + + /** + * A dep is an observable that can have multiple + * directives subscribing to it. + * + * @constructor + */ + function Dep() { + this.id = uid$1++; + this.subs = []; + } + + // the current target watcher being evaluated. + // this is globally unique because there could be only one + // watcher being evaluated at any time. + Dep.target = null; + + /** + * Add a directive subscriber. + * + * @param {Directive} sub + */ + + Dep.prototype.addSub = function (sub) { + this.subs.push(sub); + }; + + /** + * Remove a directive subscriber. + * + * @param {Directive} sub + */ + + Dep.prototype.removeSub = function (sub) { + this.subs.$remove(sub); + }; + + /** + * Add self as a dependency to the target watcher. + */ + + Dep.prototype.depend = function () { + Dep.target.addDep(this); + }; + + /** + * Notify all subscribers of a new value. + */ + + Dep.prototype.notify = function () { + // stablize the subscriber list first + var subs = toArray(this.subs); + for (var i = 0, l = subs.length; i < l; i++) { + subs[i].update(); + } + }; + + var arrayProto = Array.prototype; + var arrayMethods = Object.create(arrayProto) + + /** + * Intercept mutating methods and emit events + */ + + ;['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse'].forEach(function (method) { + // cache original method + var original = arrayProto[method]; + def(arrayMethods, method, function mutator() { + // avoid leaking arguments: + // http://jsperf.com/closure-with-arguments + var i = arguments.length; + var args = new Array(i); + while (i--) { + args[i] = arguments[i]; + } + var result = original.apply(this, args); + var ob = this.__ob__; + var inserted; + switch (method) { + case 'push': + inserted = args; + break; + case 'unshift': + inserted = args; + break; + case 'splice': + inserted = args.slice(2); + break; + } + if (inserted) ob.observeArray(inserted); + // notify change + ob.dep.notify(); + return result; + }); + }); + + /** + * Swap the element at the given index with a new value + * and emits corresponding event. + * + * @param {Number} index + * @param {*} val + * @return {*} - replaced element + */ + + def(arrayProto, '$set', function $set(index, val) { + if (index >= this.length) { + this.length = Number(index) + 1; + } + return this.splice(index, 1, val)[0]; + }); + + /** + * Convenience method to remove the element at given index or target element reference. + * + * @param {*} item + */ + + def(arrayProto, '$remove', function $remove(item) { + /* istanbul ignore if */ + if (!this.length) return; + var index = indexOf(this, item); + if (index > -1) { + return this.splice(index, 1); + } + }); + + var arrayKeys = Object.getOwnPropertyNames(arrayMethods); + + /** + * By default, when a reactive property is set, the new value is + * also converted to become reactive. However in certain cases, e.g. + * v-for scope alias and props, we don't want to force conversion + * because the value may be a nested value under a frozen data structure. + * + * So whenever we want to set a reactive property without forcing + * conversion on the new value, we wrap that call inside this function. + */ + + var shouldConvert = true; + + function withoutConversion(fn) { + shouldConvert = false; + fn(); + shouldConvert = true; + } + + /** + * Observer class that are attached to each observed + * object. Once attached, the observer converts target + * object's property keys into getter/setters that + * collect dependencies and dispatches updates. + * + * @param {Array|Object} value + * @constructor + */ + + function Observer(value) { + this.value = value; + this.dep = new Dep(); + def(value, '__ob__', this); + if (isArray(value)) { + var augment = hasProto ? protoAugment : copyAugment; + augment(value, arrayMethods, arrayKeys); + this.observeArray(value); + } else { + this.walk(value); + } + } + + // Instance methods + + /** + * Walk through each property and convert them into + * getter/setters. This method should only be called when + * value type is Object. + * + * @param {Object} obj + */ + + Observer.prototype.walk = function (obj) { + var keys = Object.keys(obj); + for (var i = 0, l = keys.length; i < l; i++) { + this.convert(keys[i], obj[keys[i]]); + } + }; + + /** + * Observe a list of Array items. + * + * @param {Array} items + */ + + Observer.prototype.observeArray = function (items) { + for (var i = 0, l = items.length; i < l; i++) { + observe(items[i]); + } + }; + + /** + * Convert a property into getter/setter so we can emit + * the events when the property is accessed/changed. + * + * @param {String} key + * @param {*} val + */ + + Observer.prototype.convert = function (key, val) { + defineReactive(this.value, key, val); + }; + + /** + * Add an owner vm, so that when $set/$delete mutations + * happen we can notify owner vms to proxy the keys and + * digest the watchers. This is only called when the object + * is observed as an instance's root $data. + * + * @param {Vue} vm + */ + + Observer.prototype.addVm = function (vm) { + (this.vms || (this.vms = [])).push(vm); + }; + + /** + * Remove an owner vm. This is called when the object is + * swapped out as an instance's $data object. + * + * @param {Vue} vm + */ + + Observer.prototype.removeVm = function (vm) { + this.vms.$remove(vm); + }; + + // helpers + + /** + * Augment an target Object or Array by intercepting + * the prototype chain using __proto__ + * + * @param {Object|Array} target + * @param {Object} src + */ + + function protoAugment(target, src) { + /* eslint-disable no-proto */ + target.__proto__ = src; + /* eslint-enable no-proto */ + } + + /** + * Augment an target Object or Array by defining + * hidden properties. + * + * @param {Object|Array} target + * @param {Object} proto + */ + + function copyAugment(target, src, keys) { + for (var i = 0, l = keys.length; i < l; i++) { + var key = keys[i]; + def(target, key, src[key]); + } + } + + /** + * Attempt to create an observer instance for a value, + * returns the new observer if successfully observed, + * or the existing observer if the value already has one. + * + * @param {*} value + * @param {Vue} [vm] + * @return {Observer|undefined} + * @static + */ + + function observe(value, vm) { + if (!value || typeof value !== 'object') { + return; + } + var ob; + if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) { + ob = value.__ob__; + } else if (shouldConvert && (isArray(value) || isPlainObject(value)) && Object.isExtensible(value) && !value._isVue) { + ob = new Observer(value); + } + if (ob && vm) { + ob.addVm(vm); + } + return ob; + } + + /** + * Define a reactive property on an Object. + * + * @param {Object} obj + * @param {String} key + * @param {*} val + */ + + function defineReactive(obj, key, val) { + var dep = new Dep(); + + var property = Object.getOwnPropertyDescriptor(obj, key); + if (property && property.configurable === false) { + return; + } + + // cater for pre-defined getter/setters + var getter = property && property.get; + var setter = property && property.set; + + var childOb = observe(val); + Object.defineProperty(obj, key, { + enumerable: true, + configurable: true, + get: function reactiveGetter() { + var value = getter ? getter.call(obj) : val; + if (Dep.target) { + dep.depend(); + if (childOb) { + childOb.dep.depend(); + } + if (isArray(value)) { + for (var e, i = 0, l = value.length; i < l; i++) { + e = value[i]; + e && e.__ob__ && e.__ob__.dep.depend(); + } + } + } + return value; + }, + set: function reactiveSetter(newVal) { + var value = getter ? getter.call(obj) : val; + if (newVal === value) { + return; + } + if (setter) { + setter.call(obj, newVal); + } else { + val = newVal; + } + childOb = observe(newVal); + dep.notify(); + } + }); + } + + + + var util = Object.freeze({ + defineReactive: defineReactive, + set: set, + del: del, + hasOwn: hasOwn, + isLiteral: isLiteral, + isReserved: isReserved, + _toString: _toString, + toNumber: toNumber, + toBoolean: toBoolean, + stripQuotes: stripQuotes, + camelize: camelize, + hyphenate: hyphenate, + classify: classify, + bind: bind, + toArray: toArray, + extend: extend, + isObject: isObject, + isPlainObject: isPlainObject, + def: def, + debounce: _debounce, + indexOf: indexOf, + cancellable: cancellable, + looseEqual: looseEqual, + isArray: isArray, + hasProto: hasProto, + inBrowser: inBrowser, + devtools: devtools, + isIE: isIE, + isIE9: isIE9, + isAndroid: isAndroid, + isIos: isIos, + iosVersionMatch: iosVersionMatch, + iosVersion: iosVersion, + hasMutationObserverBug: hasMutationObserverBug, + get transitionProp () { return transitionProp; }, + get transitionEndEvent () { return transitionEndEvent; }, + get animationProp () { return animationProp; }, + get animationEndEvent () { return animationEndEvent; }, + nextTick: nextTick, + get _Set () { return _Set; }, + query: query, + inDoc: inDoc, + getAttr: getAttr, + getBindAttr: getBindAttr, + hasBindAttr: hasBindAttr, + before: before, + after: after, + remove: remove, + prepend: prepend, + replace: replace, + on: on, + off: off, + setClass: setClass, + addClass: addClass, + removeClass: removeClass, + extractContent: extractContent, + trimNode: trimNode, + isTemplate: isTemplate, + createAnchor: createAnchor, + findRef: findRef, + mapNodeRange: mapNodeRange, + removeNodeRange: removeNodeRange, + isFragment: isFragment, + getOuterHTML: getOuterHTML, + mergeOptions: mergeOptions, + resolveAsset: resolveAsset, + checkComponentAttr: checkComponentAttr, + commonTagRE: commonTagRE, + reservedTagRE: reservedTagRE, + get warn () { return warn; } + }); + + var uid = 0; + + function initMixin (Vue) { + /** + * The main init sequence. This is called for every + * instance, including ones that are created from extended + * constructors. + * + * @param {Object} options - this options object should be + * the result of merging class + * options and the options passed + * in to the constructor. + */ + + Vue.prototype._init = function (options) { + options = options || {}; + + this.$el = null; + this.$parent = options.parent; + this.$root = this.$parent ? this.$parent.$root : this; + this.$children = []; + this.$refs = {}; // child vm references + this.$els = {}; // element references + this._watchers = []; // all watchers as an array + this._directives = []; // all directives + + // a uid + this._uid = uid++; + + // a flag to avoid this being observed + this._isVue = true; + + // events bookkeeping + this._events = {}; // registered callbacks + this._eventsCount = {}; // for $broadcast optimization + + // fragment instance properties + this._isFragment = false; + this._fragment = // @type {DocumentFragment} + this._fragmentStart = // @type {Text|Comment} + this._fragmentEnd = null; // @type {Text|Comment} + + // lifecycle state + this._isCompiled = this._isDestroyed = this._isReady = this._isAttached = this._isBeingDestroyed = this._vForRemoving = false; + this._unlinkFn = null; + + // context: + // if this is a transcluded component, context + // will be the common parent vm of this instance + // and its host. + this._context = options._context || this.$parent; + + // scope: + // if this is inside an inline v-for, the scope + // will be the intermediate scope created for this + // repeat fragment. this is used for linking props + // and container directives. + this._scope = options._scope; + + // fragment: + // if this instance is compiled inside a Fragment, it + // needs to reigster itself as a child of that fragment + // for attach/detach to work properly. + this._frag = options._frag; + if (this._frag) { + this._frag.children.push(this); + } + + // push self into parent / transclusion host + if (this.$parent) { + this.$parent.$children.push(this); + } + + // merge options. + options = this.$options = mergeOptions(this.constructor.options, options, this); + + // set ref + this._updateRef(); + + // initialize data as empty object. + // it will be filled up in _initData(). + this._data = {}; + + // call init hook + this._callHook('init'); + + // initialize data observation and scope inheritance. + this._initState(); + + // setup event system and option events. + this._initEvents(); + + // call created hook + this._callHook('created'); + + // if `el` option is passed, start compilation. + if (options.el) { + this.$mount(options.el); + } + }; + } + + var pathCache = new Cache(1000); + + // actions + var APPEND = 0; + var PUSH = 1; + var INC_SUB_PATH_DEPTH = 2; + var PUSH_SUB_PATH = 3; + + // states + var BEFORE_PATH = 0; + var IN_PATH = 1; + var BEFORE_IDENT = 2; + var IN_IDENT = 3; + var IN_SUB_PATH = 4; + var IN_SINGLE_QUOTE = 5; + var IN_DOUBLE_QUOTE = 6; + var AFTER_PATH = 7; + var ERROR = 8; + + var pathStateMachine = []; + + pathStateMachine[BEFORE_PATH] = { + 'ws': [BEFORE_PATH], + 'ident': [IN_IDENT, APPEND], + '[': [IN_SUB_PATH], + 'eof': [AFTER_PATH] + }; + + pathStateMachine[IN_PATH] = { + 'ws': [IN_PATH], + '.': [BEFORE_IDENT], + '[': [IN_SUB_PATH], + 'eof': [AFTER_PATH] + }; + + pathStateMachine[BEFORE_IDENT] = { + 'ws': [BEFORE_IDENT], + 'ident': [IN_IDENT, APPEND] + }; + + pathStateMachine[IN_IDENT] = { + 'ident': [IN_IDENT, APPEND], + '0': [IN_IDENT, APPEND], + 'number': [IN_IDENT, APPEND], + 'ws': [IN_PATH, PUSH], + '.': [BEFORE_IDENT, PUSH], + '[': [IN_SUB_PATH, PUSH], + 'eof': [AFTER_PATH, PUSH] + }; + + pathStateMachine[IN_SUB_PATH] = { + "'": [IN_SINGLE_QUOTE, APPEND], + '"': [IN_DOUBLE_QUOTE, APPEND], + '[': [IN_SUB_PATH, INC_SUB_PATH_DEPTH], + ']': [IN_PATH, PUSH_SUB_PATH], + 'eof': ERROR, + 'else': [IN_SUB_PATH, APPEND] + }; + + pathStateMachine[IN_SINGLE_QUOTE] = { + "'": [IN_SUB_PATH, APPEND], + 'eof': ERROR, + 'else': [IN_SINGLE_QUOTE, APPEND] + }; + + pathStateMachine[IN_DOUBLE_QUOTE] = { + '"': [IN_SUB_PATH, APPEND], + 'eof': ERROR, + 'else': [IN_DOUBLE_QUOTE, APPEND] + }; + + /** + * Determine the type of a character in a keypath. + * + * @param {Char} ch + * @return {String} type + */ + + function getPathCharType(ch) { + if (ch === undefined) { + return 'eof'; + } + + var code = ch.charCodeAt(0); + + switch (code) { + case 0x5B: // [ + case 0x5D: // ] + case 0x2E: // . + case 0x22: // " + case 0x27: // ' + case 0x30: + // 0 + return ch; + + case 0x5F: // _ + case 0x24: + // $ + return 'ident'; + + case 0x20: // Space + case 0x09: // Tab + case 0x0A: // Newline + case 0x0D: // Return + case 0xA0: // No-break space + case 0xFEFF: // Byte Order Mark + case 0x2028: // Line Separator + case 0x2029: + // Paragraph Separator + return 'ws'; + } + + // a-z, A-Z + if (code >= 0x61 && code <= 0x7A || code >= 0x41 && code <= 0x5A) { + return 'ident'; + } + + // 1-9 + if (code >= 0x31 && code <= 0x39) { + return 'number'; + } + + return 'else'; + } + + /** + * Format a subPath, return its plain form if it is + * a literal string or number. Otherwise prepend the + * dynamic indicator (*). + * + * @param {String} path + * @return {String} + */ + + function formatSubPath(path) { + var trimmed = path.trim(); + // invalid leading 0 + if (path.charAt(0) === '0' && isNaN(path)) { + return false; + } + return isLiteral(trimmed) ? stripQuotes(trimmed) : '*' + trimmed; + } + + /** + * Parse a string path into an array of segments + * + * @param {String} path + * @return {Array|undefined} + */ + + function parse(path) { + var keys = []; + var index = -1; + var mode = BEFORE_PATH; + var subPathDepth = 0; + var c, newChar, key, type, transition, action, typeMap; + + var actions = []; + + actions[PUSH] = function () { + if (key !== undefined) { + keys.push(key); + key = undefined; + } + }; + + actions[APPEND] = function () { + if (key === undefined) { + key = newChar; + } else { + key += newChar; + } + }; + + actions[INC_SUB_PATH_DEPTH] = function () { + actions[APPEND](); + subPathDepth++; + }; + + actions[PUSH_SUB_PATH] = function () { + if (subPathDepth > 0) { + subPathDepth--; + mode = IN_SUB_PATH; + actions[APPEND](); + } else { + subPathDepth = 0; + key = formatSubPath(key); + if (key === false) { + return false; + } else { + actions[PUSH](); + } + } + }; + + function maybeUnescapeQuote() { + var nextChar = path[index + 1]; + if (mode === IN_SINGLE_QUOTE && nextChar === "'" || mode === IN_DOUBLE_QUOTE && nextChar === '"') { + index++; + newChar = '\\' + nextChar; + actions[APPEND](); + return true; + } + } + + while (mode != null) { + index++; + c = path[index]; + + if (c === '\\' && maybeUnescapeQuote()) { + continue; + } + + type = getPathCharType(c); + typeMap = pathStateMachine[mode]; + transition = typeMap[type] || typeMap['else'] || ERROR; + + if (transition === ERROR) { + return; // parse error + } + + mode = transition[0]; + action = actions[transition[1]]; + if (action) { + newChar = transition[2]; + newChar = newChar === undefined ? c : newChar; + if (action() === false) { + return; + } + } + + if (mode === AFTER_PATH) { + keys.raw = path; + return keys; + } + } + } + + /** + * External parse that check for a cache hit first + * + * @param {String} path + * @return {Array|undefined} + */ + + function parsePath(path) { + var hit = pathCache.get(path); + if (!hit) { + hit = parse(path); + if (hit) { + pathCache.put(path, hit); + } + } + return hit; + } + + /** + * Get from an object from a path string + * + * @param {Object} obj + * @param {String} path + */ + + function getPath(obj, path) { + return parseExpression(path).get(obj); + } + + /** + * Warn against setting non-existent root path on a vm. + */ + + var warnNonExistent; + if ('development' !== 'production') { + warnNonExistent = function (path, vm) { + warn('You are setting a non-existent path "' + path.raw + '" ' + 'on a vm instance. Consider pre-initializing the property ' + 'with the "data" option for more reliable reactivity ' + 'and better performance.', vm); + }; + } + + /** + * Set on an object from a path + * + * @param {Object} obj + * @param {String | Array} path + * @param {*} val + */ + + function setPath(obj, path, val) { + var original = obj; + if (typeof path === 'string') { + path = parse(path); + } + if (!path || !isObject(obj)) { + return false; + } + var last, key; + for (var i = 0, l = path.length; i < l; i++) { + last = obj; + key = path[i]; + if (key.charAt(0) === '*') { + key = parseExpression(key.slice(1)).get.call(original, original); + } + if (i < l - 1) { + obj = obj[key]; + if (!isObject(obj)) { + obj = {}; + if ('development' !== 'production' && last._isVue) { + warnNonExistent(path, last); + } + set(last, key, obj); + } + } else { + if (isArray(obj)) { + obj.$set(key, val); + } else if (key in obj) { + obj[key] = val; + } else { + if ('development' !== 'production' && obj._isVue) { + warnNonExistent(path, obj); + } + set(obj, key, val); + } + } + } + return true; + } + +var path = Object.freeze({ + parsePath: parsePath, + getPath: getPath, + setPath: setPath + }); + + var expressionCache = new Cache(1000); + + var allowedKeywords = 'Math,Date,this,true,false,null,undefined,Infinity,NaN,' + 'isNaN,isFinite,decodeURI,decodeURIComponent,encodeURI,' + 'encodeURIComponent,parseInt,parseFloat'; + var allowedKeywordsRE = new RegExp('^(' + allowedKeywords.replace(/,/g, '\\b|') + '\\b)'); + + // keywords that don't make sense inside expressions + var improperKeywords = 'break,case,class,catch,const,continue,debugger,default,' + 'delete,do,else,export,extends,finally,for,function,if,' + 'import,in,instanceof,let,return,super,switch,throw,try,' + 'var,while,with,yield,enum,await,implements,package,' + 'protected,static,interface,private,public'; + var improperKeywordsRE = new RegExp('^(' + improperKeywords.replace(/,/g, '\\b|') + '\\b)'); + + var wsRE = /\s/g; + var newlineRE = /\n/g; + var saveRE = /[\{,]\s*[\w\$_]+\s*:|('(?:[^'\\]|\\.)*'|"(?:[^"\\]|\\.)*"|`(?:[^`\\]|\\.)*\$\{|\}(?:[^`\\]|\\.)*`|`(?:[^`\\]|\\.)*`)|new |typeof |void /g; + var restoreRE = /"(\d+)"/g; + var pathTestRE = /^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*|\['.*?'\]|\[".*?"\]|\[\d+\]|\[[A-Za-z_$][\w$]*\])*$/; + var identRE = /[^\w$\.](?:[A-Za-z_$][\w$]*)/g; + var literalValueRE$1 = /^(?:true|false|null|undefined|Infinity|NaN)$/; + + function noop() {} + + /** + * Save / Rewrite / Restore + * + * When rewriting paths found in an expression, it is + * possible for the same letter sequences to be found in + * strings and Object literal property keys. Therefore we + * remove and store these parts in a temporary array, and + * restore them after the path rewrite. + */ + + var saved = []; + + /** + * Save replacer + * + * The save regex can match two possible cases: + * 1. An opening object literal + * 2. A string + * If matched as a plain string, we need to escape its + * newlines, since the string needs to be preserved when + * generating the function body. + * + * @param {String} str + * @param {String} isString - str if matched as a string + * @return {String} - placeholder with index + */ + + function save(str, isString) { + var i = saved.length; + saved[i] = isString ? str.replace(newlineRE, '\\n') : str; + return '"' + i + '"'; + } + + /** + * Path rewrite replacer + * + * @param {String} raw + * @return {String} + */ + + function rewrite(raw) { + var c = raw.charAt(0); + var path = raw.slice(1); + if (allowedKeywordsRE.test(path)) { + return raw; + } else { + path = path.indexOf('"') > -1 ? path.replace(restoreRE, restore) : path; + return c + 'scope.' + path; + } + } + + /** + * Restore replacer + * + * @param {String} str + * @param {String} i - matched save index + * @return {String} + */ + + function restore(str, i) { + return saved[i]; + } + + /** + * Rewrite an expression, prefixing all path accessors with + * `scope.` and generate getter/setter functions. + * + * @param {String} exp + * @return {Function} + */ + + function compileGetter(exp) { + if (improperKeywordsRE.test(exp)) { + 'development' !== 'production' && warn('Avoid using reserved keywords in expression: ' + exp); + } + // reset state + saved.length = 0; + // save strings and object literal keys + var body = exp.replace(saveRE, save).replace(wsRE, ''); + // rewrite all paths + // pad 1 space here because the regex matches 1 extra char + body = (' ' + body).replace(identRE, rewrite).replace(restoreRE, restore); + return makeGetterFn(body); + } + + /** + * Build a getter function. Requires eval. + * + * We isolate the try/catch so it doesn't affect the + * optimization of the parse function when it is not called. + * + * @param {String} body + * @return {Function|undefined} + */ + + function makeGetterFn(body) { + try { + /* eslint-disable no-new-func */ + return new Function('scope', 'return ' + body + ';'); + /* eslint-enable no-new-func */ + } catch (e) { + if ('development' !== 'production') { + /* istanbul ignore if */ + if (e.toString().match(/unsafe-eval|CSP/)) { + warn('It seems you are using the default build of Vue.js in an environment ' + 'with Content Security Policy that prohibits unsafe-eval. ' + 'Use the CSP-compliant build instead: ' + 'http://vuejs.org/guide/installation.html#CSP-compliant-build'); + } else { + warn('Invalid expression. ' + 'Generated function body: ' + body); + } + } + return noop; + } + } + + /** + * Compile a setter function for the expression. + * + * @param {String} exp + * @return {Function|undefined} + */ + + function compileSetter(exp) { + var path = parsePath(exp); + if (path) { + return function (scope, val) { + setPath(scope, path, val); + }; + } else { + 'development' !== 'production' && warn('Invalid setter expression: ' + exp); + } + } + + /** + * Parse an expression into re-written getter/setters. + * + * @param {String} exp + * @param {Boolean} needSet + * @return {Function} + */ + + function parseExpression(exp, needSet) { + exp = exp.trim(); + // try cache + var hit = expressionCache.get(exp); + if (hit) { + if (needSet && !hit.set) { + hit.set = compileSetter(hit.exp); + } + return hit; + } + var res = { exp: exp }; + res.get = isSimplePath(exp) && exp.indexOf('[') < 0 + // optimized super simple getter + ? makeGetterFn('scope.' + exp) + // dynamic getter + : compileGetter(exp); + if (needSet) { + res.set = compileSetter(exp); + } + expressionCache.put(exp, res); + return res; + } + + /** + * Check if an expression is a simple path. + * + * @param {String} exp + * @return {Boolean} + */ + + function isSimplePath(exp) { + return pathTestRE.test(exp) && + // don't treat literal values as paths + !literalValueRE$1.test(exp) && + // Math constants e.g. Math.PI, Math.E etc. + exp.slice(0, 5) !== 'Math.'; + } + +var expression = Object.freeze({ + parseExpression: parseExpression, + isSimplePath: isSimplePath + }); + + // we have two separate queues: one for directive updates + // and one for user watcher registered via $watch(). + // we want to guarantee directive updates to be called + // before user watchers so that when user watchers are + // triggered, the DOM would have already been in updated + // state. + + var queue = []; + var userQueue = []; + var has = {}; + var circular = {}; + var waiting = false; + + /** + * Reset the batcher's state. + */ + + function resetBatcherState() { + queue.length = 0; + userQueue.length = 0; + has = {}; + circular = {}; + waiting = false; + } + + /** + * Flush both queues and run the watchers. + */ + + function flushBatcherQueue() { + var _again = true; + + _function: while (_again) { + _again = false; + + runBatcherQueue(queue); + runBatcherQueue(userQueue); + // user watchers triggered more watchers, + // keep flushing until it depletes + if (queue.length) { + _again = true; + continue _function; + } + // dev tool hook + /* istanbul ignore if */ + if (devtools && config.devtools) { + devtools.emit('flush'); + } + resetBatcherState(); + } + } + + /** + * Run the watchers in a single queue. + * + * @param {Array} queue + */ + + function runBatcherQueue(queue) { + // do not cache length because more watchers might be pushed + // as we run existing watchers + for (var i = 0; i < queue.length; i++) { + var watcher = queue[i]; + var id = watcher.id; + has[id] = null; + watcher.run(); + // in dev build, check and stop circular updates. + if ('development' !== 'production' && has[id] != null) { + circular[id] = (circular[id] || 0) + 1; + if (circular[id] > config._maxUpdateCount) { + warn('You may have an infinite update loop for watcher ' + 'with expression "' + watcher.expression + '"', watcher.vm); + break; + } + } + } + queue.length = 0; + } + + /** + * Push a watcher into the watcher queue. + * Jobs with duplicate IDs will be skipped unless it's + * pushed when the queue is being flushed. + * + * @param {Watcher} watcher + * properties: + * - {Number} id + * - {Function} run + */ + + function pushWatcher(watcher) { + var id = watcher.id; + if (has[id] == null) { + // push watcher into appropriate queue + var q = watcher.user ? userQueue : queue; + has[id] = q.length; + q.push(watcher); + // queue the flush + if (!waiting) { + waiting = true; + nextTick(flushBatcherQueue); + } + } + } + + var uid$2 = 0; + + /** + * A watcher parses an expression, collects dependencies, + * and fires callback when the expression value changes. + * This is used for both the $watch() api and directives. + * + * @param {Vue} vm + * @param {String|Function} expOrFn + * @param {Function} cb + * @param {Object} options + * - {Array} filters + * - {Boolean} twoWay + * - {Boolean} deep + * - {Boolean} user + * - {Boolean} sync + * - {Boolean} lazy + * - {Function} [preProcess] + * - {Function} [postProcess] + * @constructor + */ + function Watcher(vm, expOrFn, cb, options) { + // mix in options + if (options) { + extend(this, options); + } + var isFn = typeof expOrFn === 'function'; + this.vm = vm; + vm._watchers.push(this); + this.expression = expOrFn; + this.cb = cb; + this.id = ++uid$2; // uid for batching + this.active = true; + this.dirty = this.lazy; // for lazy watchers + this.deps = []; + this.newDeps = []; + this.depIds = new _Set(); + this.newDepIds = new _Set(); + this.prevError = null; // for async error stacks + // parse expression for getter/setter + if (isFn) { + this.getter = expOrFn; + this.setter = undefined; + } else { + var res = parseExpression(expOrFn, this.twoWay); + this.getter = res.get; + this.setter = res.set; + } + this.value = this.lazy ? undefined : this.get(); + // state for avoiding false triggers for deep and Array + // watchers during vm._digest() + this.queued = this.shallow = false; + } + + /** + * Evaluate the getter, and re-collect dependencies. + */ + + Watcher.prototype.get = function () { + this.beforeGet(); + var scope = this.scope || this.vm; + var value; + try { + value = this.getter.call(scope, scope); + } catch (e) { + if ('development' !== 'production' && config.warnExpressionErrors) { + warn('Error when evaluating expression ' + '"' + this.expression + '": ' + e.toString(), this.vm); + } + } + // "touch" every property so they are all tracked as + // dependencies for deep watching + if (this.deep) { + traverse(value); + } + if (this.preProcess) { + value = this.preProcess(value); + } + if (this.filters) { + value = scope._applyFilters(value, null, this.filters, false); + } + if (this.postProcess) { + value = this.postProcess(value); + } + this.afterGet(); + return value; + }; + + /** + * Set the corresponding value with the setter. + * + * @param {*} value + */ + + Watcher.prototype.set = function (value) { + var scope = this.scope || this.vm; + if (this.filters) { + value = scope._applyFilters(value, this.value, this.filters, true); + } + try { + this.setter.call(scope, scope, value); + } catch (e) { + if ('development' !== 'production' && config.warnExpressionErrors) { + warn('Error when evaluating setter ' + '"' + this.expression + '": ' + e.toString(), this.vm); + } + } + // two-way sync for v-for alias + var forContext = scope.$forContext; + if (forContext && forContext.alias === this.expression) { + if (forContext.filters) { + 'development' !== 'production' && warn('It seems you are using two-way binding on ' + 'a v-for alias (' + this.expression + '), and the ' + 'v-for has filters. This will not work properly. ' + 'Either remove the filters or use an array of ' + 'objects and bind to object properties instead.', this.vm); + return; + } + forContext._withLock(function () { + if (scope.$key) { + // original is an object + forContext.rawValue[scope.$key] = value; + } else { + forContext.rawValue.$set(scope.$index, value); + } + }); + } + }; + + /** + * Prepare for dependency collection. + */ + + Watcher.prototype.beforeGet = function () { + Dep.target = this; + }; + + /** + * Add a dependency to this directive. + * + * @param {Dep} dep + */ + + Watcher.prototype.addDep = function (dep) { + var id = dep.id; + if (!this.newDepIds.has(id)) { + this.newDepIds.add(id); + this.newDeps.push(dep); + if (!this.depIds.has(id)) { + dep.addSub(this); + } + } + }; + + /** + * Clean up for dependency collection. + */ + + Watcher.prototype.afterGet = function () { + Dep.target = null; + var i = this.deps.length; + while (i--) { + var dep = this.deps[i]; + if (!this.newDepIds.has(dep.id)) { + dep.removeSub(this); + } + } + var tmp = this.depIds; + this.depIds = this.newDepIds; + this.newDepIds = tmp; + this.newDepIds.clear(); + tmp = this.deps; + this.deps = this.newDeps; + this.newDeps = tmp; + this.newDeps.length = 0; + }; + + /** + * Subscriber interface. + * Will be called when a dependency changes. + * + * @param {Boolean} shallow + */ + + Watcher.prototype.update = function (shallow) { + if (this.lazy) { + this.dirty = true; + } else if (this.sync || !config.async) { + this.run(); + } else { + // if queued, only overwrite shallow with non-shallow, + // but not the other way around. + this.shallow = this.queued ? shallow ? this.shallow : false : !!shallow; + this.queued = true; + // record before-push error stack in debug mode + /* istanbul ignore if */ + if ('development' !== 'production' && config.debug) { + this.prevError = new Error('[vue] async stack trace'); + } + pushWatcher(this); + } + }; + + /** + * Batcher job interface. + * Will be called by the batcher. + */ + + Watcher.prototype.run = function () { + if (this.active) { + var value = this.get(); + if (value !== this.value || + // Deep watchers and watchers on Object/Arrays should fire even + // when the value is the same, because the value may + // have mutated; but only do so if this is a + // non-shallow update (caused by a vm digest). + (isObject(value) || this.deep) && !this.shallow) { + // set new value + var oldValue = this.value; + this.value = value; + // in debug + async mode, when a watcher callbacks + // throws, we also throw the saved before-push error + // so the full cross-tick stack trace is available. + var prevError = this.prevError; + /* istanbul ignore if */ + if ('development' !== 'production' && config.debug && prevError) { + this.prevError = null; + try { + this.cb.call(this.vm, value, oldValue); + } catch (e) { + nextTick(function () { + throw prevError; + }, 0); + throw e; + } + } else { + this.cb.call(this.vm, value, oldValue); + } + } + this.queued = this.shallow = false; + } + }; + + /** + * Evaluate the value of the watcher. + * This only gets called for lazy watchers. + */ + + Watcher.prototype.evaluate = function () { + // avoid overwriting another watcher that is being + // collected. + var current = Dep.target; + this.value = this.get(); + this.dirty = false; + Dep.target = current; + }; + + /** + * Depend on all deps collected by this watcher. + */ + + Watcher.prototype.depend = function () { + var i = this.deps.length; + while (i--) { + this.deps[i].depend(); + } + }; + + /** + * Remove self from all dependencies' subcriber list. + */ + + Watcher.prototype.teardown = function () { + if (this.active) { + // remove self from vm's watcher list + // this is a somewhat expensive operation so we skip it + // if the vm is being destroyed or is performing a v-for + // re-render (the watcher list is then filtered by v-for). + if (!this.vm._isBeingDestroyed && !this.vm._vForRemoving) { + this.vm._watchers.$remove(this); + } + var i = this.deps.length; + while (i--) { + this.deps[i].removeSub(this); + } + this.active = false; + this.vm = this.cb = this.value = null; + } + }; + + /** + * Recrusively traverse an object to evoke all converted + * getters, so that every nested property inside the object + * is collected as a "deep" dependency. + * + * @param {*} val + */ + + var seenObjects = new _Set(); + function traverse(val, seen) { + var i = undefined, + keys = undefined; + if (!seen) { + seen = seenObjects; + seen.clear(); + } + var isA = isArray(val); + var isO = isObject(val); + if ((isA || isO) && Object.isExtensible(val)) { + if (val.__ob__) { + var depId = val.__ob__.dep.id; + if (seen.has(depId)) { + return; + } else { + seen.add(depId); + } + } + if (isA) { + i = val.length; + while (i--) traverse(val[i], seen); + } else if (isO) { + keys = Object.keys(val); + i = keys.length; + while (i--) traverse(val[keys[i]], seen); + } + } + } + + var text$1 = { + + bind: function bind() { + this.attr = this.el.nodeType === 3 ? 'data' : 'textContent'; + }, + + update: function update(value) { + this.el[this.attr] = _toString(value); + } + }; + + var templateCache = new Cache(1000); + var idSelectorCache = new Cache(1000); + + var map = { + efault: [0, '', ''], + legend: [1, '
', '
'], + tr: [2, '', '
'], + col: [2, '', '
'] + }; + + map.td = map.th = [3, '', '
']; + + map.option = map.optgroup = [1, '']; + + map.thead = map.tbody = map.colgroup = map.caption = map.tfoot = [1, '', '
']; + + map.g = map.defs = map.symbol = map.use = map.image = map.text = map.circle = map.ellipse = map.line = map.path = map.polygon = map.polyline = map.rect = [1, '', '']; + + /** + * Check if a node is a supported template node with a + * DocumentFragment content. + * + * @param {Node} node + * @return {Boolean} + */ + + function isRealTemplate(node) { + return isTemplate(node) && isFragment(node.content); + } + + var tagRE$1 = /<([\w:-]+)/; + var entityRE = /&#?\w+?;/; + var commentRE = / E - } - entry.newer = undefined; // D --x - entry.older = this.tail; // D. --> E - if (this.tail) { - this.tail.newer = entry; // E. <-- D - } - this.tail = entry; - return returnEntry ? entry : entry.value; - }; - - var cache$1 = new Cache(1000); - var filterTokenRE = /[^\s'"]+|'[^']*'|"[^"]*"/g; - var reservedArgRE = /^in$|^-?\d+/; - - /** - * Parser state - */ - - var str; - var dir; - var c; - var prev; - var i; - var l; - var lastFilterIndex; - var inSingle; - var inDouble; - var curly; - var square; - var paren; - /** - * Push a filter to the current directive object - */ - - function pushFilter() { - var exp = str.slice(lastFilterIndex, i).trim(); - var filter; - if (exp) { - filter = {}; - var tokens = exp.match(filterTokenRE); - filter.name = tokens[0]; - if (tokens.length > 1) { - filter.args = tokens.slice(1).map(processFilterArg); - } - } - if (filter) { - (dir.filters = dir.filters || []).push(filter); - } - lastFilterIndex = i + 1; - } - - /** - * Check if an argument is dynamic and strip quotes. - * - * @param {String} arg - * @return {Object} - */ - - function processFilterArg(arg) { - if (reservedArgRE.test(arg)) { - return { - value: toNumber(arg), - dynamic: false - }; - } else { - var stripped = stripQuotes(arg); - var dynamic = stripped === arg; - return { - value: dynamic ? arg : stripped, - dynamic: dynamic - }; - } - } - - /** - * Parse a directive value and extract the expression - * and its filters into a descriptor. - * - * Example: - * - * "a + 1 | uppercase" will yield: - * { - * expression: 'a + 1', - * filters: [ - * { name: 'uppercase', args: null } - * ] - * } - * - * @param {String} s - * @return {Object} - */ - - function parseDirective(s) { - var hit = cache$1.get(s); - if (hit) { - return hit; - } - - // reset parser state - str = s; - inSingle = inDouble = false; - curly = square = paren = 0; - lastFilterIndex = 0; - dir = {}; - - for (i = 0, l = str.length; i < l; i++) { - prev = c; - c = str.charCodeAt(i); - if (inSingle) { - // check single quote - if (c === 0x27 && prev !== 0x5C) inSingle = !inSingle; - } else if (inDouble) { - // check double quote - if (c === 0x22 && prev !== 0x5C) inDouble = !inDouble; - } else if (c === 0x7C && // pipe - str.charCodeAt(i + 1) !== 0x7C && str.charCodeAt(i - 1) !== 0x7C) { - if (dir.expression == null) { - // first filter, end of expression - lastFilterIndex = i + 1; - dir.expression = str.slice(0, i).trim(); - } else { - // already has filter - pushFilter(); - } - } else { - switch (c) { - case 0x22: - inDouble = true;break; // " - case 0x27: - inSingle = true;break; // ' - case 0x28: - paren++;break; // ( - case 0x29: - paren--;break; // ) - case 0x5B: - square++;break; // [ - case 0x5D: - square--;break; // ] - case 0x7B: - curly++;break; // { - case 0x7D: - curly--;break; // } - } - } - } - - if (dir.expression == null) { - dir.expression = str.slice(0, i).trim(); - } else if (lastFilterIndex !== 0) { - pushFilter(); - } - - cache$1.put(s, dir); - return dir; - } - -var directive = Object.freeze({ - parseDirective: parseDirective - }); - - var regexEscapeRE = /[-.*+?^${}()|[\]\/\\]/g; - var cache = undefined; - var tagRE = undefined; - var htmlRE = undefined; - /** - * Escape a string so it can be used in a RegExp - * constructor. - * - * @param {String} str - */ - - function escapeRegex(str) { - return str.replace(regexEscapeRE, '\\$&'); - } - - function compileRegex() { - var open = escapeRegex(config.delimiters[0]); - var close = escapeRegex(config.delimiters[1]); - var unsafeOpen = escapeRegex(config.unsafeDelimiters[0]); - var unsafeClose = escapeRegex(config.unsafeDelimiters[1]); - tagRE = new RegExp(unsafeOpen + '((?:.|\\n)+?)' + unsafeClose + '|' + open + '((?:.|\\n)+?)' + close, 'g'); - htmlRE = new RegExp('^' + unsafeOpen + '((?:.|\\n)+?)' + unsafeClose + '$'); - // reset cache - cache = new Cache(1000); - } - - /** - * Parse a template text string into an array of tokens. - * - * @param {String} text - * @return {Array | null} - * - {String} type - * - {String} value - * - {Boolean} [html] - * - {Boolean} [oneTime] - */ - - function parseText(text) { - if (!cache) { - compileRegex(); - } - var hit = cache.get(text); - if (hit) { - return hit; - } - if (!tagRE.test(text)) { - return null; - } - var tokens = []; - var lastIndex = tagRE.lastIndex = 0; - var match, index, html, value, first, oneTime; - /* eslint-disable no-cond-assign */ - while (match = tagRE.exec(text)) { - /* eslint-enable no-cond-assign */ - index = match.index; - // push text token - if (index > lastIndex) { - tokens.push({ - value: text.slice(lastIndex, index) - }); - } - // tag token - html = htmlRE.test(match[0]); - value = html ? match[1] : match[2]; - first = value.charCodeAt(0); - oneTime = first === 42; // * - value = oneTime ? value.slice(1) : value; - tokens.push({ - tag: true, - value: value.trim(), - html: html, - oneTime: oneTime - }); - lastIndex = index + match[0].length; - } - if (lastIndex < text.length) { - tokens.push({ - value: text.slice(lastIndex) - }); - } - cache.put(text, tokens); - return tokens; - } - - /** - * Format a list of tokens into an expression. - * e.g. tokens parsed from 'a {{b}} c' can be serialized - * into one single expression as '"a " + b + " c"'. - * - * @param {Array} tokens - * @param {Vue} [vm] - * @return {String} - */ - - function tokensToExp(tokens, vm) { - if (tokens.length > 1) { - return tokens.map(function (token) { - return formatToken(token, vm); - }).join('+'); - } else { - return formatToken(tokens[0], vm, true); - } - } - - /** - * Format a single token. - * - * @param {Object} token - * @param {Vue} [vm] - * @param {Boolean} [single] - * @return {String} - */ - - function formatToken(token, vm, single) { - return token.tag ? token.oneTime && vm ? '"' + vm.$eval(token.value) + '"' : inlineFilters(token.value, single) : '"' + token.value + '"'; - } - - /** - * For an attribute with multiple interpolation tags, - * e.g. attr="some-{{thing | filter}}", in order to combine - * the whole thing into a single watchable expression, we - * have to inline those filters. This function does exactly - * that. This is a bit hacky but it avoids heavy changes - * to directive parser and watcher mechanism. - * - * @param {String} exp - * @param {Boolean} single - * @return {String} - */ - - var filterRE = /[^|]\|[^|]/; - function inlineFilters(exp, single) { - if (!filterRE.test(exp)) { - return single ? exp : '(' + exp + ')'; - } else { - var dir = parseDirective(exp); - if (!dir.filters) { - return '(' + exp + ')'; - } else { - return 'this._applyFilters(' + dir.expression + // value - ',null,' + // oldValue (null for read) - JSON.stringify(dir.filters) + // filter descriptors - ',false)'; // write? - } - } - } - -var text = Object.freeze({ - compileRegex: compileRegex, - parseText: parseText, - tokensToExp: tokensToExp - }); - - var delimiters = ['{{', '}}']; - var unsafeDelimiters = ['{{{', '}}}']; - - var config = Object.defineProperties({ - - /** - * Whether to print debug messages. - * Also enables stack trace for warnings. - * - * @type {Boolean} - */ - - debug: false, - - /** - * Whether to suppress warnings. - * - * @type {Boolean} - */ - - silent: false, - - /** - * Whether to use async rendering. - */ - - async: true, - - /** - * Whether to warn against errors caught when evaluating - * expressions. - */ - - warnExpressionErrors: true, - - /** - * Whether to allow devtools inspection. - * Disabled by default in production builds. - */ - - devtools: 'development' !== 'production', - - /** - * Internal flag to indicate the delimiters have been - * changed. - * - * @type {Boolean} - */ - - _delimitersChanged: true, - - /** - * List of asset types that a component can own. - * - * @type {Array} - */ - - _assetTypes: ['component', 'directive', 'elementDirective', 'filter', 'transition', 'partial'], - - /** - * prop binding modes - */ - - _propBindingModes: { - ONE_WAY: 0, - TWO_WAY: 1, - ONE_TIME: 2 - }, - - /** - * Max circular updates allowed in a batcher flush cycle. - */ - - _maxUpdateCount: 100 - - }, { - delimiters: { /** - * Interpolation delimiters. Changing these would trigger - * the text parser to re-compile the regular expressions. - * - * @type {Array} - */ - - get: function get() { - return delimiters; - }, - set: function set(val) { - delimiters = val; - compileRegex(); - }, - configurable: true, - enumerable: true - }, - unsafeDelimiters: { - get: function get() { - return unsafeDelimiters; - }, - set: function set(val) { - unsafeDelimiters = val; - compileRegex(); - }, - configurable: true, - enumerable: true - } - }); - - var warn = undefined; - var formatComponentName = undefined; - - if ('development' !== 'production') { - (function () { - var hasConsole = typeof console !== 'undefined'; - - warn = function (msg, vm) { - if (hasConsole && !config.silent) { - console.error('[Vue warn]: ' + msg + (vm ? formatComponentName(vm) : '')); - } - }; - - formatComponentName = function (vm) { - var name = vm._isVue ? vm.$options.name : vm.name; - return name ? ' (found in component: <' + hyphenate(name) + '>)' : ''; - }; - })(); - } - - /** - * Append with transition. - * - * @param {Element} el - * @param {Element} target - * @param {Vue} vm - * @param {Function} [cb] - */ - - function appendWithTransition(el, target, vm, cb) { - applyTransition(el, 1, function () { - target.appendChild(el); - }, vm, cb); - } - - /** - * InsertBefore with transition. - * - * @param {Element} el - * @param {Element} target - * @param {Vue} vm - * @param {Function} [cb] - */ - - function beforeWithTransition(el, target, vm, cb) { - applyTransition(el, 1, function () { - before(el, target); - }, vm, cb); - } - - /** - * Remove with transition. - * - * @param {Element} el - * @param {Vue} vm - * @param {Function} [cb] - */ - - function removeWithTransition(el, vm, cb) { - applyTransition(el, -1, function () { - remove(el); - }, vm, cb); - } - - /** - * Apply transitions with an operation callback. - * - * @param {Element} el - * @param {Number} direction - * 1: enter - * -1: leave - * @param {Function} op - the actual DOM operation - * @param {Vue} vm - * @param {Function} [cb] - */ - - function applyTransition(el, direction, op, vm, cb) { - var transition = el.__v_trans; - if (!transition || - // skip if there are no js hooks and CSS transition is - // not supported - !transition.hooks && !transitionEndEvent || - // skip transitions for initial compile - !vm._isCompiled || - // if the vm is being manipulated by a parent directive - // during the parent's compilation phase, skip the - // animation. - vm.$parent && !vm.$parent._isCompiled) { - op(); - if (cb) cb(); - return; - } - var action = direction > 0 ? 'enter' : 'leave'; - transition[action](op, cb); - } - -var transition = Object.freeze({ - appendWithTransition: appendWithTransition, - beforeWithTransition: beforeWithTransition, - removeWithTransition: removeWithTransition, - applyTransition: applyTransition - }); - - /** - * Query an element selector if it's not an element already. - * - * @param {String|Element} el - * @return {Element} - */ - - function query(el) { - if (typeof el === 'string') { - var selector = el; - el = document.querySelector(el); - if (!el) { - 'development' !== 'production' && warn('Cannot find element: ' + selector); - } - } - return el; - } - - /** - * Check if a node is in the document. - * Note: document.documentElement.contains should work here - * but always returns false for comment nodes in phantomjs, - * making unit tests difficult. This is fixed by doing the - * contains() check on the node's parentNode instead of - * the node itself. - * - * @param {Node} node - * @return {Boolean} - */ - - function inDoc(node) { - if (!node) return false; - var doc = node.ownerDocument.documentElement; - var parent = node.parentNode; - return doc === node || doc === parent || !!(parent && parent.nodeType === 1 && doc.contains(parent)); - } - - /** - * Get and remove an attribute from a node. - * - * @param {Node} node - * @param {String} _attr - */ - - function getAttr(node, _attr) { - var val = node.getAttribute(_attr); - if (val !== null) { - node.removeAttribute(_attr); - } - return val; - } - - /** - * Get an attribute with colon or v-bind: prefix. - * - * @param {Node} node - * @param {String} name - * @return {String|null} - */ - - function getBindAttr(node, name) { - var val = getAttr(node, ':' + name); - if (val === null) { - val = getAttr(node, 'v-bind:' + name); - } - return val; - } - - /** - * Check the presence of a bind attribute. - * - * @param {Node} node - * @param {String} name - * @return {Boolean} - */ - - function hasBindAttr(node, name) { - return node.hasAttribute(name) || node.hasAttribute(':' + name) || node.hasAttribute('v-bind:' + name); - } - - /** - * Insert el before target - * - * @param {Element} el - * @param {Element} target - */ - - function before(el, target) { - target.parentNode.insertBefore(el, target); - } - - /** - * Insert el after target - * - * @param {Element} el - * @param {Element} target - */ - - function after(el, target) { - if (target.nextSibling) { - before(el, target.nextSibling); - } else { - target.parentNode.appendChild(el); - } - } - - /** - * Remove el from DOM - * - * @param {Element} el - */ - - function remove(el) { - el.parentNode.removeChild(el); - } - - /** - * Prepend el to target - * - * @param {Element} el - * @param {Element} target - */ - - function prepend(el, target) { - if (target.firstChild) { - before(el, target.firstChild); - } else { - target.appendChild(el); - } - } - - /** - * Replace target with el - * - * @param {Element} target - * @param {Element} el - */ - - function replace(target, el) { - var parent = target.parentNode; - if (parent) { - parent.replaceChild(el, target); - } - } - - /** - * Add event listener shorthand. - * - * @param {Element} el - * @param {String} event - * @param {Function} cb - * @param {Boolean} [useCapture] - */ - - function on(el, event, cb, useCapture) { - el.addEventListener(event, cb, useCapture); - } - - /** - * Remove event listener shorthand. - * - * @param {Element} el - * @param {String} event - * @param {Function} cb - */ - - function off(el, event, cb) { - el.removeEventListener(event, cb); - } - - /** - * For IE9 compat: when both class and :class are present - * getAttribute('class') returns wrong value... - * - * @param {Element} el - * @return {String} - */ - - function getClass(el) { - var classname = el.className; - if (typeof classname === 'object') { - classname = classname.baseVal || ''; - } - return classname; - } - - /** - * In IE9, setAttribute('class') will result in empty class - * if the element also has the :class attribute; However in - * PhantomJS, setting `className` does not work on SVG elements... - * So we have to do a conditional check here. - * - * @param {Element} el - * @param {String} cls - */ - - function setClass(el, cls) { - /* istanbul ignore if */ - if (isIE9 && !/svg$/.test(el.namespaceURI)) { - el.className = cls; - } else { - el.setAttribute('class', cls); - } - } - - /** - * Add class with compatibility for IE & SVG - * - * @param {Element} el - * @param {String} cls - */ - - function addClass(el, cls) { - if (el.classList) { - el.classList.add(cls); - } else { - var cur = ' ' + getClass(el) + ' '; - if (cur.indexOf(' ' + cls + ' ') < 0) { - setClass(el, (cur + cls).trim()); - } - } - } - - /** - * Remove class with compatibility for IE & SVG - * - * @param {Element} el - * @param {String} cls - */ - - function removeClass(el, cls) { - if (el.classList) { - el.classList.remove(cls); - } else { - var cur = ' ' + getClass(el) + ' '; - var tar = ' ' + cls + ' '; - while (cur.indexOf(tar) >= 0) { - cur = cur.replace(tar, ' '); - } - setClass(el, cur.trim()); - } - if (!el.className) { - el.removeAttribute('class'); - } - } - - /** - * Extract raw content inside an element into a temporary - * container div - * - * @param {Element} el - * @param {Boolean} asFragment - * @return {Element|DocumentFragment} - */ - - function extractContent(el, asFragment) { - var child; - var rawContent; - /* istanbul ignore if */ - if (isTemplate(el) && isFragment(el.content)) { - el = el.content; - } - if (el.hasChildNodes()) { - trimNode(el); - rawContent = asFragment ? document.createDocumentFragment() : document.createElement('div'); - /* eslint-disable no-cond-assign */ - while (child = el.firstChild) { - /* eslint-enable no-cond-assign */ - rawContent.appendChild(child); - } - } - return rawContent; - } - - /** - * Trim possible empty head/tail text and comment - * nodes inside a parent. - * - * @param {Node} node - */ - - function trimNode(node) { - var child; - /* eslint-disable no-sequences */ - while ((child = node.firstChild, isTrimmable(child))) { - node.removeChild(child); - } - while ((child = node.lastChild, isTrimmable(child))) { - node.removeChild(child); - } - /* eslint-enable no-sequences */ - } - - function isTrimmable(node) { - return node && (node.nodeType === 3 && !node.data.trim() || node.nodeType === 8); - } - - /** - * Check if an element is a template tag. - * Note if the template appears inside an SVG its tagName - * will be in lowercase. - * - * @param {Element} el - */ - - function isTemplate(el) { - return el.tagName && el.tagName.toLowerCase() === 'template'; - } - - /** - * Create an "anchor" for performing dom insertion/removals. - * This is used in a number of scenarios: - * - fragment instance - * - v-html - * - v-if - * - v-for - * - component - * - * @param {String} content - * @param {Boolean} persist - IE trashes empty textNodes on - * cloneNode(true), so in certain - * cases the anchor needs to be - * non-empty to be persisted in - * templates. - * @return {Comment|Text} - */ - - function createAnchor(content, persist) { - var anchor = config.debug ? document.createComment(content) : document.createTextNode(persist ? ' ' : ''); - anchor.__v_anchor = true; - return anchor; - } - - /** - * Find a component ref attribute that starts with $. - * - * @param {Element} node - * @return {String|undefined} - */ - - var refRE = /^v-ref:/; - - function findRef(node) { - if (node.hasAttributes()) { - var attrs = node.attributes; - for (var i = 0, l = attrs.length; i < l; i++) { - var name = attrs[i].name; - if (refRE.test(name)) { - return camelize(name.replace(refRE, '')); - } - } - } - } - - /** - * Map a function to a range of nodes . - * - * @param {Node} node - * @param {Node} end - * @param {Function} op - */ - - function mapNodeRange(node, end, op) { - var next; - while (node !== end) { - next = node.nextSibling; - op(node); - node = next; - } - op(end); - } - - /** - * Remove a range of nodes with transition, store - * the nodes in a fragment with correct ordering, - * and call callback when done. - * - * @param {Node} start - * @param {Node} end - * @param {Vue} vm - * @param {DocumentFragment} frag - * @param {Function} cb - */ - - function removeNodeRange(start, end, vm, frag, cb) { - var done = false; - var removed = 0; - var nodes = []; - mapNodeRange(start, end, function (node) { - if (node === end) done = true; - nodes.push(node); - removeWithTransition(node, vm, onRemoved); - }); - function onRemoved() { - removed++; - if (done && removed >= nodes.length) { - for (var i = 0; i < nodes.length; i++) { - frag.appendChild(nodes[i]); - } - cb && cb(); - } - } - } - - /** - * Check if a node is a DocumentFragment. - * - * @param {Node} node - * @return {Boolean} - */ - - function isFragment(node) { - return node && node.nodeType === 11; - } - - /** - * Get outerHTML of elements, taking care - * of SVG elements in IE as well. - * - * @param {Element} el - * @return {String} - */ - - function getOuterHTML(el) { - if (el.outerHTML) { - return el.outerHTML; - } else { - var container = document.createElement('div'); - container.appendChild(el.cloneNode(true)); - return container.innerHTML; - } - } - - var commonTagRE = /^(div|p|span|img|a|b|i|br|ul|ol|li|h1|h2|h3|h4|h5|h6|code|pre|table|th|td|tr|form|label|input|select|option|nav|article|section|header|footer)$/i; - var reservedTagRE = /^(slot|partial|component)$/i; - - var isUnknownElement = undefined; - if ('development' !== 'production') { - isUnknownElement = function (el, tag) { - if (tag.indexOf('-') > -1) { - // http://stackoverflow.com/a/28210364/1070244 - return el.constructor === window.HTMLUnknownElement || el.constructor === window.HTMLElement; - } else { - return (/HTMLUnknownElement/.test(el.toString()) && - // Chrome returns unknown for several HTML5 elements. - // https://code.google.com/p/chromium/issues/detail?id=540526 - // Firefox returns unknown for some "Interactive elements." - !/^(data|time|rtc|rb|details|dialog|summary)$/.test(tag) - ); - } - }; - } - - /** - * Check if an element is a component, if yes return its - * component id. - * - * @param {Element} el - * @param {Object} options - * @return {Object|undefined} - */ - - function checkComponentAttr(el, options) { - var tag = el.tagName.toLowerCase(); - var hasAttrs = el.hasAttributes(); - if (!commonTagRE.test(tag) && !reservedTagRE.test(tag)) { - if (resolveAsset(options, 'components', tag)) { - return { id: tag }; - } else { - var is = hasAttrs && getIsBinding(el, options); - if (is) { - return is; - } else if ('development' !== 'production') { - var expectedTag = options._componentNameMap && options._componentNameMap[tag]; - if (expectedTag) { - warn('Unknown custom element: <' + tag + '> - ' + 'did you mean <' + expectedTag + '>? ' + 'HTML is case-insensitive, remember to use kebab-case in templates.'); - } else if (isUnknownElement(el, tag)) { - warn('Unknown custom element: <' + tag + '> - did you ' + 'register the component correctly? For recursive components, ' + 'make sure to provide the "name" option.'); - } - } - } - } else if (hasAttrs) { - return getIsBinding(el, options); - } - } - - /** - * Get "is" binding from an element. - * - * @param {Element} el - * @param {Object} options - * @return {Object|undefined} - */ - - function getIsBinding(el, options) { - // dynamic syntax - var exp = el.getAttribute('is'); - if (exp != null) { - if (resolveAsset(options, 'components', exp)) { - el.removeAttribute('is'); - return { id: exp }; - } - } else { - exp = getBindAttr(el, 'is'); - if (exp != null) { - return { id: exp, dynamic: true }; - } - } - } - - /** - * Option overwriting strategies are functions that handle - * how to merge a parent option value and a child option - * value into the final value. - * - * All strategy functions follow the same signature: - * - * @param {*} parentVal - * @param {*} childVal - * @param {Vue} [vm] - */ - - var strats = config.optionMergeStrategies = Object.create(null); - - /** - * Helper that recursively merges two data objects together. - */ - - function mergeData(to, from) { - var key, toVal, fromVal; - for (key in from) { - toVal = to[key]; - fromVal = from[key]; - if (!hasOwn(to, key)) { - set(to, key, fromVal); - } else if (isObject(toVal) && isObject(fromVal)) { - mergeData(toVal, fromVal); - } - } - return to; - } - - /** - * Data - */ - - strats.data = function (parentVal, childVal, vm) { - if (!vm) { - // in a Vue.extend merge, both should be functions - if (!childVal) { - return parentVal; - } - if (typeof childVal !== 'function') { - 'development' !== 'production' && warn('The "data" option should be a function ' + 'that returns a per-instance value in component ' + 'definitions.', vm); - return parentVal; - } - if (!parentVal) { - return childVal; - } - // when parentVal & childVal are both present, - // we need to return a function that returns the - // merged result of both functions... no need to - // check if parentVal is a function here because - // it has to be a function to pass previous merges. - return function mergedDataFn() { - return mergeData(childVal.call(this), parentVal.call(this)); - }; - } else if (parentVal || childVal) { - return function mergedInstanceDataFn() { - // instance merge - var instanceData = typeof childVal === 'function' ? childVal.call(vm) : childVal; - var defaultData = typeof parentVal === 'function' ? parentVal.call(vm) : undefined; - if (instanceData) { - return mergeData(instanceData, defaultData); - } else { - return defaultData; - } - }; - } - }; - - /** - * El - */ - - strats.el = function (parentVal, childVal, vm) { - if (!vm && childVal && typeof childVal !== 'function') { - 'development' !== 'production' && warn('The "el" option should be a function ' + 'that returns a per-instance value in component ' + 'definitions.', vm); - return; - } - var ret = childVal || parentVal; - // invoke the element factory if this is instance merge - return vm && typeof ret === 'function' ? ret.call(vm) : ret; - }; - - /** - * Hooks and param attributes are merged as arrays. - */ - - strats.init = strats.created = strats.ready = strats.attached = strats.detached = strats.beforeCompile = strats.compiled = strats.beforeDestroy = strats.destroyed = strats.activate = function (parentVal, childVal) { - return childVal ? parentVal ? parentVal.concat(childVal) : isArray(childVal) ? childVal : [childVal] : parentVal; - }; - - /** - * Assets - * - * When a vm is present (instance creation), we need to do - * a three-way merge between constructor options, instance - * options and parent options. - */ - - function mergeAssets(parentVal, childVal) { - var res = Object.create(parentVal || null); - return childVal ? extend(res, guardArrayAssets(childVal)) : res; - } - - config._assetTypes.forEach(function (type) { - strats[type + 's'] = mergeAssets; - }); - - /** - * Events & Watchers. - * - * Events & watchers hashes should not overwrite one - * another, so we merge them as arrays. - */ - - strats.watch = strats.events = function (parentVal, childVal) { - if (!childVal) return parentVal; - if (!parentVal) return childVal; - var ret = {}; - extend(ret, parentVal); - for (var key in childVal) { - var parent = ret[key]; - var child = childVal[key]; - if (parent && !isArray(parent)) { - parent = [parent]; - } - ret[key] = parent ? parent.concat(child) : [child]; - } - return ret; - }; - - /** - * Other object hashes. - */ - - strats.props = strats.methods = strats.computed = function (parentVal, childVal) { - if (!childVal) return parentVal; - if (!parentVal) return childVal; - var ret = Object.create(null); - extend(ret, parentVal); - extend(ret, childVal); - return ret; - }; - - /** - * Default strategy. - */ - - var defaultStrat = function defaultStrat(parentVal, childVal) { - return childVal === undefined ? parentVal : childVal; - }; - - /** - * Make sure component options get converted to actual - * constructors. - * - * @param {Object} options - */ - - function guardComponents(options) { - if (options.components) { - var components = options.components = guardArrayAssets(options.components); - var ids = Object.keys(components); - var def; - if ('development' !== 'production') { - var map = options._componentNameMap = {}; - } - for (var i = 0, l = ids.length; i < l; i++) { - var key = ids[i]; - if (commonTagRE.test(key) || reservedTagRE.test(key)) { - 'development' !== 'production' && warn('Do not use built-in or reserved HTML elements as component ' + 'id: ' + key); - continue; - } - // record a all lowercase <-> kebab-case mapping for - // possible custom element case error warning - if ('development' !== 'production') { - map[key.replace(/-/g, '').toLowerCase()] = hyphenate(key); - } - def = components[key]; - if (isPlainObject(def)) { - components[key] = Vue.extend(def); - } - } - } - } - - /** - * Ensure all props option syntax are normalized into the - * Object-based format. - * - * @param {Object} options - */ - - function guardProps(options) { - var props = options.props; - var i, val; - if (isArray(props)) { - options.props = {}; - i = props.length; - while (i--) { - val = props[i]; - if (typeof val === 'string') { - options.props[val] = null; - } else if (val.name) { - options.props[val.name] = val; - } - } - } else if (isPlainObject(props)) { - var keys = Object.keys(props); - i = keys.length; - while (i--) { - val = props[keys[i]]; - if (typeof val === 'function') { - props[keys[i]] = { type: val }; - } - } - } - } - - /** - * Guard an Array-format assets option and converted it - * into the key-value Object format. - * - * @param {Object|Array} assets - * @return {Object} - */ - - function guardArrayAssets(assets) { - if (isArray(assets)) { - var res = {}; - var i = assets.length; - var asset; - while (i--) { - asset = assets[i]; - var id = typeof asset === 'function' ? asset.options && asset.options.name || asset.id : asset.name || asset.id; - if (!id) { - 'development' !== 'production' && warn('Array-syntax assets must provide a "name" or "id" field.'); - } else { - res[id] = asset; - } - } - return res; - } - return assets; - } - - /** - * Merge two option objects into a new one. - * Core utility used in both instantiation and inheritance. - * - * @param {Object} parent - * @param {Object} child - * @param {Vue} [vm] - if vm is present, indicates this is - * an instantiation merge. - */ - - function mergeOptions(parent, child, vm) { - guardComponents(child); - guardProps(child); - if ('development' !== 'production') { - if (child.propsData && !vm) { - warn('propsData can only be used as an instantiation option.'); - } - } - var options = {}; - var key; - if (child['extends']) { - parent = typeof child['extends'] === 'function' ? mergeOptions(parent, child['extends'].options, vm) : mergeOptions(parent, child['extends'], vm); - } - if (child.mixins) { - for (var i = 0, l = child.mixins.length; i < l; i++) { - var mixin = child.mixins[i]; - var mixinOptions = mixin.prototype instanceof Vue ? mixin.options : mixin; - parent = mergeOptions(parent, mixinOptions, vm); - } - } - for (key in parent) { - mergeField(key); - } - for (key in child) { - if (!hasOwn(parent, key)) { - mergeField(key); - } - } - function mergeField(key) { - var strat = strats[key] || defaultStrat; - options[key] = strat(parent[key], child[key], vm, key); - } - return options; - } - - /** - * Resolve an asset. - * This function is used because child instances need access - * to assets defined in its ancestor chain. - * - * @param {Object} options - * @param {String} type - * @param {String} id - * @param {Boolean} warnMissing - * @return {Object|Function} - */ - - function resolveAsset(options, type, id, warnMissing) { - /* istanbul ignore if */ - if (typeof id !== 'string') { - return; - } - var assets = options[type]; - var camelizedId; - var res = assets[id] || - // camelCase ID - assets[camelizedId = camelize(id)] || - // Pascal Case ID - assets[camelizedId.charAt(0).toUpperCase() + camelizedId.slice(1)]; - if ('development' !== 'production' && warnMissing && !res) { - warn('Failed to resolve ' + type.slice(0, -1) + ': ' + id, options); - } - return res; - } - - var uid$1 = 0; - - /** - * A dep is an observable that can have multiple - * directives subscribing to it. - * - * @constructor - */ - function Dep() { - this.id = uid$1++; - this.subs = []; - } - - // the current target watcher being evaluated. - // this is globally unique because there could be only one - // watcher being evaluated at any time. - Dep.target = null; - - /** - * Add a directive subscriber. - * - * @param {Directive} sub - */ - - Dep.prototype.addSub = function (sub) { - this.subs.push(sub); - }; - - /** - * Remove a directive subscriber. - * - * @param {Directive} sub - */ - - Dep.prototype.removeSub = function (sub) { - this.subs.$remove(sub); - }; - - /** - * Add self as a dependency to the target watcher. - */ - - Dep.prototype.depend = function () { - Dep.target.addDep(this); - }; - - /** - * Notify all subscribers of a new value. - */ - - Dep.prototype.notify = function () { - // stablize the subscriber list first - var subs = toArray(this.subs); - for (var i = 0, l = subs.length; i < l; i++) { - subs[i].update(); - } - }; - - var arrayProto = Array.prototype; - var arrayMethods = Object.create(arrayProto) - - /** - * Intercept mutating methods and emit events - */ - - ;['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse'].forEach(function (method) { - // cache original method - var original = arrayProto[method]; - def(arrayMethods, method, function mutator() { - // avoid leaking arguments: - // http://jsperf.com/closure-with-arguments - var i = arguments.length; - var args = new Array(i); - while (i--) { - args[i] = arguments[i]; - } - var result = original.apply(this, args); - var ob = this.__ob__; - var inserted; - switch (method) { - case 'push': - inserted = args; - break; - case 'unshift': - inserted = args; - break; - case 'splice': - inserted = args.slice(2); - break; - } - if (inserted) ob.observeArray(inserted); - // notify change - ob.dep.notify(); - return result; - }); - }); - - /** - * Swap the element at the given index with a new value - * and emits corresponding event. - * - * @param {Number} index - * @param {*} val - * @return {*} - replaced element - */ - - def(arrayProto, '$set', function $set(index, val) { - if (index >= this.length) { - this.length = Number(index) + 1; - } - return this.splice(index, 1, val)[0]; - }); - - /** - * Convenience method to remove the element at given index or target element reference. - * - * @param {*} item - */ - - def(arrayProto, '$remove', function $remove(item) { - /* istanbul ignore if */ - if (!this.length) return; - var index = indexOf(this, item); - if (index > -1) { - return this.splice(index, 1); - } - }); - - var arrayKeys = Object.getOwnPropertyNames(arrayMethods); - - /** - * By default, when a reactive property is set, the new value is - * also converted to become reactive. However in certain cases, e.g. - * v-for scope alias and props, we don't want to force conversion - * because the value may be a nested value under a frozen data structure. - * - * So whenever we want to set a reactive property without forcing - * conversion on the new value, we wrap that call inside this function. - */ - - var shouldConvert = true; - - function withoutConversion(fn) { - shouldConvert = false; - fn(); - shouldConvert = true; - } - - /** - * Observer class that are attached to each observed - * object. Once attached, the observer converts target - * object's property keys into getter/setters that - * collect dependencies and dispatches updates. - * - * @param {Array|Object} value - * @constructor - */ - - function Observer(value) { - this.value = value; - this.dep = new Dep(); - def(value, '__ob__', this); - if (isArray(value)) { - var augment = hasProto ? protoAugment : copyAugment; - augment(value, arrayMethods, arrayKeys); - this.observeArray(value); - } else { - this.walk(value); - } - } - - // Instance methods - - /** - * Walk through each property and convert them into - * getter/setters. This method should only be called when - * value type is Object. - * - * @param {Object} obj - */ - - Observer.prototype.walk = function (obj) { - var keys = Object.keys(obj); - for (var i = 0, l = keys.length; i < l; i++) { - this.convert(keys[i], obj[keys[i]]); - } - }; - - /** - * Observe a list of Array items. - * - * @param {Array} items - */ - - Observer.prototype.observeArray = function (items) { - for (var i = 0, l = items.length; i < l; i++) { - observe(items[i]); - } - }; - - /** - * Convert a property into getter/setter so we can emit - * the events when the property is accessed/changed. - * - * @param {String} key - * @param {*} val - */ - - Observer.prototype.convert = function (key, val) { - defineReactive(this.value, key, val); - }; - - /** - * Add an owner vm, so that when $set/$delete mutations - * happen we can notify owner vms to proxy the keys and - * digest the watchers. This is only called when the object - * is observed as an instance's root $data. - * - * @param {Vue} vm - */ - - Observer.prototype.addVm = function (vm) { - (this.vms || (this.vms = [])).push(vm); - }; - - /** - * Remove an owner vm. This is called when the object is - * swapped out as an instance's $data object. - * - * @param {Vue} vm - */ - - Observer.prototype.removeVm = function (vm) { - this.vms.$remove(vm); - }; - - // helpers - - /** - * Augment an target Object or Array by intercepting - * the prototype chain using __proto__ - * - * @param {Object|Array} target - * @param {Object} src - */ - - function protoAugment(target, src) { - /* eslint-disable no-proto */ - target.__proto__ = src; - /* eslint-enable no-proto */ - } - - /** - * Augment an target Object or Array by defining - * hidden properties. - * - * @param {Object|Array} target - * @param {Object} proto - */ - - function copyAugment(target, src, keys) { - for (var i = 0, l = keys.length; i < l; i++) { - var key = keys[i]; - def(target, key, src[key]); - } - } - - /** - * Attempt to create an observer instance for a value, - * returns the new observer if successfully observed, - * or the existing observer if the value already has one. - * - * @param {*} value - * @param {Vue} [vm] - * @return {Observer|undefined} - * @static - */ - - function observe(value, vm) { - if (!value || typeof value !== 'object') { - return; - } - var ob; - if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) { - ob = value.__ob__; - } else if (shouldConvert && (isArray(value) || isPlainObject(value)) && Object.isExtensible(value) && !value._isVue) { - ob = new Observer(value); - } - if (ob && vm) { - ob.addVm(vm); - } - return ob; - } - - /** - * Define a reactive property on an Object. - * - * @param {Object} obj - * @param {String} key - * @param {*} val - */ - - function defineReactive(obj, key, val) { - var dep = new Dep(); - - var property = Object.getOwnPropertyDescriptor(obj, key); - if (property && property.configurable === false) { - return; - } - - // cater for pre-defined getter/setters - var getter = property && property.get; - var setter = property && property.set; - - var childOb = observe(val); - Object.defineProperty(obj, key, { - enumerable: true, - configurable: true, - get: function reactiveGetter() { - var value = getter ? getter.call(obj) : val; - if (Dep.target) { - dep.depend(); - if (childOb) { - childOb.dep.depend(); - } - if (isArray(value)) { - for (var e, i = 0, l = value.length; i < l; i++) { - e = value[i]; - e && e.__ob__ && e.__ob__.dep.depend(); - } - } - } - return value; - }, - set: function reactiveSetter(newVal) { - var value = getter ? getter.call(obj) : val; - if (newVal === value) { - return; - } - if (setter) { - setter.call(obj, newVal); - } else { - val = newVal; - } - childOb = observe(newVal); - dep.notify(); - } - }); - } - - - - var util = Object.freeze({ - defineReactive: defineReactive, - set: set, - del: del, - hasOwn: hasOwn, - isLiteral: isLiteral, - isReserved: isReserved, - _toString: _toString, - toNumber: toNumber, - toBoolean: toBoolean, - stripQuotes: stripQuotes, - camelize: camelize, - hyphenate: hyphenate, - classify: classify, - bind: bind, - toArray: toArray, - extend: extend, - isObject: isObject, - isPlainObject: isPlainObject, - def: def, - debounce: _debounce, - indexOf: indexOf, - cancellable: cancellable, - looseEqual: looseEqual, - isArray: isArray, - hasProto: hasProto, - inBrowser: inBrowser, - devtools: devtools, - isIE: isIE, - isIE9: isIE9, - isAndroid: isAndroid, - isIos: isIos, - iosVersionMatch: iosVersionMatch, - iosVersion: iosVersion, - hasMutationObserverBug: hasMutationObserverBug, - get transitionProp () { return transitionProp; }, - get transitionEndEvent () { return transitionEndEvent; }, - get animationProp () { return animationProp; }, - get animationEndEvent () { return animationEndEvent; }, - nextTick: nextTick, - get _Set () { return _Set; }, - query: query, - inDoc: inDoc, - getAttr: getAttr, - getBindAttr: getBindAttr, - hasBindAttr: hasBindAttr, - before: before, - after: after, - remove: remove, - prepend: prepend, - replace: replace, - on: on, - off: off, - setClass: setClass, - addClass: addClass, - removeClass: removeClass, - extractContent: extractContent, - trimNode: trimNode, - isTemplate: isTemplate, - createAnchor: createAnchor, - findRef: findRef, - mapNodeRange: mapNodeRange, - removeNodeRange: removeNodeRange, - isFragment: isFragment, - getOuterHTML: getOuterHTML, - mergeOptions: mergeOptions, - resolveAsset: resolveAsset, - checkComponentAttr: checkComponentAttr, - commonTagRE: commonTagRE, - reservedTagRE: reservedTagRE, - get warn () { return warn; } - }); - - var uid = 0; - - function initMixin (Vue) { - /** - * The main init sequence. This is called for every - * instance, including ones that are created from extended - * constructors. - * - * @param {Object} options - this options object should be - * the result of merging class - * options and the options passed - * in to the constructor. - */ - - Vue.prototype._init = function (options) { - options = options || {}; - - this.$el = null; - this.$parent = options.parent; - this.$root = this.$parent ? this.$parent.$root : this; - this.$children = []; - this.$refs = {}; // child vm references - this.$els = {}; // element references - this._watchers = []; // all watchers as an array - this._directives = []; // all directives - - // a uid - this._uid = uid++; - - // a flag to avoid this being observed - this._isVue = true; - - // events bookkeeping - this._events = {}; // registered callbacks - this._eventsCount = {}; // for $broadcast optimization - - // fragment instance properties - this._isFragment = false; - this._fragment = // @type {DocumentFragment} - this._fragmentStart = // @type {Text|Comment} - this._fragmentEnd = null; // @type {Text|Comment} - - // lifecycle state - this._isCompiled = this._isDestroyed = this._isReady = this._isAttached = this._isBeingDestroyed = this._vForRemoving = false; - this._unlinkFn = null; - - // context: - // if this is a transcluded component, context - // will be the common parent vm of this instance - // and its host. - this._context = options._context || this.$parent; - - // scope: - // if this is inside an inline v-for, the scope - // will be the intermediate scope created for this - // repeat fragment. this is used for linking props - // and container directives. - this._scope = options._scope; - - // fragment: - // if this instance is compiled inside a Fragment, it - // needs to reigster itself as a child of that fragment - // for attach/detach to work properly. - this._frag = options._frag; - if (this._frag) { - this._frag.children.push(this); - } - - // push self into parent / transclusion host - if (this.$parent) { - this.$parent.$children.push(this); - } - - // merge options. - options = this.$options = mergeOptions(this.constructor.options, options, this); - - // set ref - this._updateRef(); - - // initialize data as empty object. - // it will be filled up in _initData(). - this._data = {}; - - // call init hook - this._callHook('init'); - - // initialize data observation and scope inheritance. - this._initState(); - - // setup event system and option events. - this._initEvents(); - - // call created hook - this._callHook('created'); - - // if `el` option is passed, start compilation. - if (options.el) { - this.$mount(options.el); - } - }; - } - - var pathCache = new Cache(1000); - - // actions - var APPEND = 0; - var PUSH = 1; - var INC_SUB_PATH_DEPTH = 2; - var PUSH_SUB_PATH = 3; - - // states - var BEFORE_PATH = 0; - var IN_PATH = 1; - var BEFORE_IDENT = 2; - var IN_IDENT = 3; - var IN_SUB_PATH = 4; - var IN_SINGLE_QUOTE = 5; - var IN_DOUBLE_QUOTE = 6; - var AFTER_PATH = 7; - var ERROR = 8; - - var pathStateMachine = []; - - pathStateMachine[BEFORE_PATH] = { - 'ws': [BEFORE_PATH], - 'ident': [IN_IDENT, APPEND], - '[': [IN_SUB_PATH], - 'eof': [AFTER_PATH] - }; - - pathStateMachine[IN_PATH] = { - 'ws': [IN_PATH], - '.': [BEFORE_IDENT], - '[': [IN_SUB_PATH], - 'eof': [AFTER_PATH] - }; - - pathStateMachine[BEFORE_IDENT] = { - 'ws': [BEFORE_IDENT], - 'ident': [IN_IDENT, APPEND] - }; - - pathStateMachine[IN_IDENT] = { - 'ident': [IN_IDENT, APPEND], - '0': [IN_IDENT, APPEND], - 'number': [IN_IDENT, APPEND], - 'ws': [IN_PATH, PUSH], - '.': [BEFORE_IDENT, PUSH], - '[': [IN_SUB_PATH, PUSH], - 'eof': [AFTER_PATH, PUSH] - }; - - pathStateMachine[IN_SUB_PATH] = { - "'": [IN_SINGLE_QUOTE, APPEND], - '"': [IN_DOUBLE_QUOTE, APPEND], - '[': [IN_SUB_PATH, INC_SUB_PATH_DEPTH], - ']': [IN_PATH, PUSH_SUB_PATH], - 'eof': ERROR, - 'else': [IN_SUB_PATH, APPEND] - }; - - pathStateMachine[IN_SINGLE_QUOTE] = { - "'": [IN_SUB_PATH, APPEND], - 'eof': ERROR, - 'else': [IN_SINGLE_QUOTE, APPEND] - }; - - pathStateMachine[IN_DOUBLE_QUOTE] = { - '"': [IN_SUB_PATH, APPEND], - 'eof': ERROR, - 'else': [IN_DOUBLE_QUOTE, APPEND] - }; - - /** - * Determine the type of a character in a keypath. - * - * @param {Char} ch - * @return {String} type - */ - - function getPathCharType(ch) { - if (ch === undefined) { - return 'eof'; - } - - var code = ch.charCodeAt(0); - - switch (code) { - case 0x5B: // [ - case 0x5D: // ] - case 0x2E: // . - case 0x22: // " - case 0x27: // ' - case 0x30: - // 0 - return ch; - - case 0x5F: // _ - case 0x24: - // $ - return 'ident'; - - case 0x20: // Space - case 0x09: // Tab - case 0x0A: // Newline - case 0x0D: // Return - case 0xA0: // No-break space - case 0xFEFF: // Byte Order Mark - case 0x2028: // Line Separator - case 0x2029: - // Paragraph Separator - return 'ws'; - } - - // a-z, A-Z - if (code >= 0x61 && code <= 0x7A || code >= 0x41 && code <= 0x5A) { - return 'ident'; - } - - // 1-9 - if (code >= 0x31 && code <= 0x39) { - return 'number'; - } - - return 'else'; - } - - /** - * Format a subPath, return its plain form if it is - * a literal string or number. Otherwise prepend the - * dynamic indicator (*). - * - * @param {String} path - * @return {String} - */ - - function formatSubPath(path) { - var trimmed = path.trim(); - // invalid leading 0 - if (path.charAt(0) === '0' && isNaN(path)) { - return false; - } - return isLiteral(trimmed) ? stripQuotes(trimmed) : '*' + trimmed; - } - - /** - * Parse a string path into an array of segments - * - * @param {String} path - * @return {Array|undefined} - */ - - function parse(path) { - var keys = []; - var index = -1; - var mode = BEFORE_PATH; - var subPathDepth = 0; - var c, newChar, key, type, transition, action, typeMap; - - var actions = []; - - actions[PUSH] = function () { - if (key !== undefined) { - keys.push(key); - key = undefined; - } - }; - - actions[APPEND] = function () { - if (key === undefined) { - key = newChar; - } else { - key += newChar; - } - }; - - actions[INC_SUB_PATH_DEPTH] = function () { - actions[APPEND](); - subPathDepth++; - }; - - actions[PUSH_SUB_PATH] = function () { - if (subPathDepth > 0) { - subPathDepth--; - mode = IN_SUB_PATH; - actions[APPEND](); - } else { - subPathDepth = 0; - key = formatSubPath(key); - if (key === false) { - return false; - } else { - actions[PUSH](); - } - } - }; - - function maybeUnescapeQuote() { - var nextChar = path[index + 1]; - if (mode === IN_SINGLE_QUOTE && nextChar === "'" || mode === IN_DOUBLE_QUOTE && nextChar === '"') { - index++; - newChar = '\\' + nextChar; - actions[APPEND](); - return true; - } - } - - while (mode != null) { - index++; - c = path[index]; - - if (c === '\\' && maybeUnescapeQuote()) { - continue; - } - - type = getPathCharType(c); - typeMap = pathStateMachine[mode]; - transition = typeMap[type] || typeMap['else'] || ERROR; - - if (transition === ERROR) { - return; // parse error - } - - mode = transition[0]; - action = actions[transition[1]]; - if (action) { - newChar = transition[2]; - newChar = newChar === undefined ? c : newChar; - if (action() === false) { - return; - } - } - - if (mode === AFTER_PATH) { - keys.raw = path; - return keys; - } - } - } - - /** - * External parse that check for a cache hit first - * - * @param {String} path - * @return {Array|undefined} - */ - - function parsePath(path) { - var hit = pathCache.get(path); - if (!hit) { - hit = parse(path); - if (hit) { - pathCache.put(path, hit); - } - } - return hit; - } - - /** - * Get from an object from a path string - * - * @param {Object} obj - * @param {String} path - */ - - function getPath(obj, path) { - return parseExpression(path).get(obj); - } - - /** - * Warn against setting non-existent root path on a vm. - */ - - var warnNonExistent; - if ('development' !== 'production') { - warnNonExistent = function (path, vm) { - warn('You are setting a non-existent path "' + path.raw + '" ' + 'on a vm instance. Consider pre-initializing the property ' + 'with the "data" option for more reliable reactivity ' + 'and better performance.', vm); - }; - } - - /** - * Set on an object from a path - * - * @param {Object} obj - * @param {String | Array} path - * @param {*} val - */ - - function setPath(obj, path, val) { - var original = obj; - if (typeof path === 'string') { - path = parse(path); - } - if (!path || !isObject(obj)) { - return false; - } - var last, key; - for (var i = 0, l = path.length; i < l; i++) { - last = obj; - key = path[i]; - if (key.charAt(0) === '*') { - key = parseExpression(key.slice(1)).get.call(original, original); - } - if (i < l - 1) { - obj = obj[key]; - if (!isObject(obj)) { - obj = {}; - if ('development' !== 'production' && last._isVue) { - warnNonExistent(path, last); - } - set(last, key, obj); - } - } else { - if (isArray(obj)) { - obj.$set(key, val); - } else if (key in obj) { - obj[key] = val; - } else { - if ('development' !== 'production' && obj._isVue) { - warnNonExistent(path, obj); - } - set(obj, key, val); - } - } - } - return true; - } - -var path = Object.freeze({ - parsePath: parsePath, - getPath: getPath, - setPath: setPath - }); - - var expressionCache = new Cache(1000); - - var allowedKeywords = 'Math,Date,this,true,false,null,undefined,Infinity,NaN,' + 'isNaN,isFinite,decodeURI,decodeURIComponent,encodeURI,' + 'encodeURIComponent,parseInt,parseFloat'; - var allowedKeywordsRE = new RegExp('^(' + allowedKeywords.replace(/,/g, '\\b|') + '\\b)'); - - // keywords that don't make sense inside expressions - var improperKeywords = 'break,case,class,catch,const,continue,debugger,default,' + 'delete,do,else,export,extends,finally,for,function,if,' + 'import,in,instanceof,let,return,super,switch,throw,try,' + 'var,while,with,yield,enum,await,implements,package,' + 'protected,static,interface,private,public'; - var improperKeywordsRE = new RegExp('^(' + improperKeywords.replace(/,/g, '\\b|') + '\\b)'); - - var wsRE = /\s/g; - var newlineRE = /\n/g; - var saveRE = /[\{,]\s*[\w\$_]+\s*:|('(?:[^'\\]|\\.)*'|"(?:[^"\\]|\\.)*"|`(?:[^`\\]|\\.)*\$\{|\}(?:[^`\\]|\\.)*`|`(?:[^`\\]|\\.)*`)|new |typeof |void /g; - var restoreRE = /"(\d+)"/g; - var pathTestRE = /^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*|\['.*?'\]|\[".*?"\]|\[\d+\]|\[[A-Za-z_$][\w$]*\])*$/; - var identRE = /[^\w$\.](?:[A-Za-z_$][\w$]*)/g; - var literalValueRE$1 = /^(?:true|false|null|undefined|Infinity|NaN)$/; - - function noop() {} - - /** - * Save / Rewrite / Restore - * - * When rewriting paths found in an expression, it is - * possible for the same letter sequences to be found in - * strings and Object literal property keys. Therefore we - * remove and store these parts in a temporary array, and - * restore them after the path rewrite. - */ - - var saved = []; - - /** - * Save replacer - * - * The save regex can match two possible cases: - * 1. An opening object literal - * 2. A string - * If matched as a plain string, we need to escape its - * newlines, since the string needs to be preserved when - * generating the function body. - * - * @param {String} str - * @param {String} isString - str if matched as a string - * @return {String} - placeholder with index - */ - - function save(str, isString) { - var i = saved.length; - saved[i] = isString ? str.replace(newlineRE, '\\n') : str; - return '"' + i + '"'; - } - - /** - * Path rewrite replacer - * - * @param {String} raw - * @return {String} - */ - - function rewrite(raw) { - var c = raw.charAt(0); - var path = raw.slice(1); - if (allowedKeywordsRE.test(path)) { - return raw; - } else { - path = path.indexOf('"') > -1 ? path.replace(restoreRE, restore) : path; - return c + 'scope.' + path; - } - } - - /** - * Restore replacer - * - * @param {String} str - * @param {String} i - matched save index - * @return {String} - */ - - function restore(str, i) { - return saved[i]; - } - - /** - * Rewrite an expression, prefixing all path accessors with - * `scope.` and generate getter/setter functions. - * - * @param {String} exp - * @return {Function} - */ - - function compileGetter(exp) { - if (improperKeywordsRE.test(exp)) { - 'development' !== 'production' && warn('Avoid using reserved keywords in expression: ' + exp); - } - // reset state - saved.length = 0; - // save strings and object literal keys - var body = exp.replace(saveRE, save).replace(wsRE, ''); - // rewrite all paths - // pad 1 space here because the regex matches 1 extra char - body = (' ' + body).replace(identRE, rewrite).replace(restoreRE, restore); - return makeGetterFn(body); - } - - /** - * Build a getter function. Requires eval. - * - * We isolate the try/catch so it doesn't affect the - * optimization of the parse function when it is not called. - * - * @param {String} body - * @return {Function|undefined} - */ - - function makeGetterFn(body) { - try { - /* eslint-disable no-new-func */ - return new Function('scope', 'return ' + body + ';'); - /* eslint-enable no-new-func */ - } catch (e) { - if ('development' !== 'production') { - /* istanbul ignore if */ - if (e.toString().match(/unsafe-eval|CSP/)) { - warn('It seems you are using the default build of Vue.js in an environment ' + 'with Content Security Policy that prohibits unsafe-eval. ' + 'Use the CSP-compliant build instead: ' + 'http://vuejs.org/guide/installation.html#CSP-compliant-build'); - } else { - warn('Invalid expression. ' + 'Generated function body: ' + body); - } - } - return noop; - } - } - - /** - * Compile a setter function for the expression. - * - * @param {String} exp - * @return {Function|undefined} - */ - - function compileSetter(exp) { - var path = parsePath(exp); - if (path) { - return function (scope, val) { - setPath(scope, path, val); - }; - } else { - 'development' !== 'production' && warn('Invalid setter expression: ' + exp); - } - } - - /** - * Parse an expression into re-written getter/setters. - * - * @param {String} exp - * @param {Boolean} needSet - * @return {Function} - */ - - function parseExpression(exp, needSet) { - exp = exp.trim(); - // try cache - var hit = expressionCache.get(exp); - if (hit) { - if (needSet && !hit.set) { - hit.set = compileSetter(hit.exp); - } - return hit; - } - var res = { exp: exp }; - res.get = isSimplePath(exp) && exp.indexOf('[') < 0 - // optimized super simple getter - ? makeGetterFn('scope.' + exp) - // dynamic getter - : compileGetter(exp); - if (needSet) { - res.set = compileSetter(exp); - } - expressionCache.put(exp, res); - return res; - } - - /** - * Check if an expression is a simple path. - * - * @param {String} exp - * @return {Boolean} - */ - - function isSimplePath(exp) { - return pathTestRE.test(exp) && - // don't treat literal values as paths - !literalValueRE$1.test(exp) && - // Math constants e.g. Math.PI, Math.E etc. - exp.slice(0, 5) !== 'Math.'; - } - -var expression = Object.freeze({ - parseExpression: parseExpression, - isSimplePath: isSimplePath - }); - - // we have two separate queues: one for directive updates - // and one for user watcher registered via $watch(). - // we want to guarantee directive updates to be called - // before user watchers so that when user watchers are - // triggered, the DOM would have already been in updated - // state. - - var queue = []; - var userQueue = []; - var has = {}; - var circular = {}; - var waiting = false; - - /** - * Reset the batcher's state. - */ - - function resetBatcherState() { - queue.length = 0; - userQueue.length = 0; - has = {}; - circular = {}; - waiting = false; - } - - /** - * Flush both queues and run the watchers. - */ - - function flushBatcherQueue() { - var _again = true; - - _function: while (_again) { - _again = false; - - runBatcherQueue(queue); - runBatcherQueue(userQueue); - // user watchers triggered more watchers, - // keep flushing until it depletes - if (queue.length) { - _again = true; - continue _function; - } - // dev tool hook - /* istanbul ignore if */ - if (devtools && config.devtools) { - devtools.emit('flush'); - } - resetBatcherState(); - } - } - - /** - * Run the watchers in a single queue. - * - * @param {Array} queue - */ - - function runBatcherQueue(queue) { - // do not cache length because more watchers might be pushed - // as we run existing watchers - for (var i = 0; i < queue.length; i++) { - var watcher = queue[i]; - var id = watcher.id; - has[id] = null; - watcher.run(); - // in dev build, check and stop circular updates. - if ('development' !== 'production' && has[id] != null) { - circular[id] = (circular[id] || 0) + 1; - if (circular[id] > config._maxUpdateCount) { - warn('You may have an infinite update loop for watcher ' + 'with expression "' + watcher.expression + '"', watcher.vm); - break; - } - } - } - queue.length = 0; - } - - /** - * Push a watcher into the watcher queue. - * Jobs with duplicate IDs will be skipped unless it's - * pushed when the queue is being flushed. - * - * @param {Watcher} watcher - * properties: - * - {Number} id - * - {Function} run - */ - - function pushWatcher(watcher) { - var id = watcher.id; - if (has[id] == null) { - // push watcher into appropriate queue - var q = watcher.user ? userQueue : queue; - has[id] = q.length; - q.push(watcher); - // queue the flush - if (!waiting) { - waiting = true; - nextTick(flushBatcherQueue); - } - } - } - - var uid$2 = 0; - - /** - * A watcher parses an expression, collects dependencies, - * and fires callback when the expression value changes. - * This is used for both the $watch() api and directives. - * - * @param {Vue} vm - * @param {String|Function} expOrFn - * @param {Function} cb - * @param {Object} options - * - {Array} filters - * - {Boolean} twoWay - * - {Boolean} deep - * - {Boolean} user - * - {Boolean} sync - * - {Boolean} lazy - * - {Function} [preProcess] - * - {Function} [postProcess] - * @constructor - */ - function Watcher(vm, expOrFn, cb, options) { - // mix in options - if (options) { - extend(this, options); - } - var isFn = typeof expOrFn === 'function'; - this.vm = vm; - vm._watchers.push(this); - this.expression = expOrFn; - this.cb = cb; - this.id = ++uid$2; // uid for batching - this.active = true; - this.dirty = this.lazy; // for lazy watchers - this.deps = []; - this.newDeps = []; - this.depIds = new _Set(); - this.newDepIds = new _Set(); - this.prevError = null; // for async error stacks - // parse expression for getter/setter - if (isFn) { - this.getter = expOrFn; - this.setter = undefined; - } else { - var res = parseExpression(expOrFn, this.twoWay); - this.getter = res.get; - this.setter = res.set; - } - this.value = this.lazy ? undefined : this.get(); - // state for avoiding false triggers for deep and Array - // watchers during vm._digest() - this.queued = this.shallow = false; - } - - /** - * Evaluate the getter, and re-collect dependencies. - */ - - Watcher.prototype.get = function () { - this.beforeGet(); - var scope = this.scope || this.vm; - var value; - try { - value = this.getter.call(scope, scope); - } catch (e) { - if ('development' !== 'production' && config.warnExpressionErrors) { - warn('Error when evaluating expression ' + '"' + this.expression + '": ' + e.toString(), this.vm); - } - } - // "touch" every property so they are all tracked as - // dependencies for deep watching - if (this.deep) { - traverse(value); - } - if (this.preProcess) { - value = this.preProcess(value); - } - if (this.filters) { - value = scope._applyFilters(value, null, this.filters, false); - } - if (this.postProcess) { - value = this.postProcess(value); - } - this.afterGet(); - return value; - }; - - /** - * Set the corresponding value with the setter. - * - * @param {*} value - */ - - Watcher.prototype.set = function (value) { - var scope = this.scope || this.vm; - if (this.filters) { - value = scope._applyFilters(value, this.value, this.filters, true); - } - try { - this.setter.call(scope, scope, value); - } catch (e) { - if ('development' !== 'production' && config.warnExpressionErrors) { - warn('Error when evaluating setter ' + '"' + this.expression + '": ' + e.toString(), this.vm); - } - } - // two-way sync for v-for alias - var forContext = scope.$forContext; - if (forContext && forContext.alias === this.expression) { - if (forContext.filters) { - 'development' !== 'production' && warn('It seems you are using two-way binding on ' + 'a v-for alias (' + this.expression + '), and the ' + 'v-for has filters. This will not work properly. ' + 'Either remove the filters or use an array of ' + 'objects and bind to object properties instead.', this.vm); - return; - } - forContext._withLock(function () { - if (scope.$key) { - // original is an object - forContext.rawValue[scope.$key] = value; - } else { - forContext.rawValue.$set(scope.$index, value); - } - }); - } - }; - - /** - * Prepare for dependency collection. - */ - - Watcher.prototype.beforeGet = function () { - Dep.target = this; - }; - - /** - * Add a dependency to this directive. - * - * @param {Dep} dep - */ - - Watcher.prototype.addDep = function (dep) { - var id = dep.id; - if (!this.newDepIds.has(id)) { - this.newDepIds.add(id); - this.newDeps.push(dep); - if (!this.depIds.has(id)) { - dep.addSub(this); - } - } - }; - - /** - * Clean up for dependency collection. - */ - - Watcher.prototype.afterGet = function () { - Dep.target = null; - var i = this.deps.length; - while (i--) { - var dep = this.deps[i]; - if (!this.newDepIds.has(dep.id)) { - dep.removeSub(this); - } - } - var tmp = this.depIds; - this.depIds = this.newDepIds; - this.newDepIds = tmp; - this.newDepIds.clear(); - tmp = this.deps; - this.deps = this.newDeps; - this.newDeps = tmp; - this.newDeps.length = 0; - }; - - /** - * Subscriber interface. - * Will be called when a dependency changes. - * - * @param {Boolean} shallow - */ - - Watcher.prototype.update = function (shallow) { - if (this.lazy) { - this.dirty = true; - } else if (this.sync || !config.async) { - this.run(); - } else { - // if queued, only overwrite shallow with non-shallow, - // but not the other way around. - this.shallow = this.queued ? shallow ? this.shallow : false : !!shallow; - this.queued = true; - // record before-push error stack in debug mode - /* istanbul ignore if */ - if ('development' !== 'production' && config.debug) { - this.prevError = new Error('[vue] async stack trace'); - } - pushWatcher(this); - } - }; - - /** - * Batcher job interface. - * Will be called by the batcher. - */ - - Watcher.prototype.run = function () { - if (this.active) { - var value = this.get(); - if (value !== this.value || - // Deep watchers and watchers on Object/Arrays should fire even - // when the value is the same, because the value may - // have mutated; but only do so if this is a - // non-shallow update (caused by a vm digest). - (isObject(value) || this.deep) && !this.shallow) { - // set new value - var oldValue = this.value; - this.value = value; - // in debug + async mode, when a watcher callbacks - // throws, we also throw the saved before-push error - // so the full cross-tick stack trace is available. - var prevError = this.prevError; - /* istanbul ignore if */ - if ('development' !== 'production' && config.debug && prevError) { - this.prevError = null; - try { - this.cb.call(this.vm, value, oldValue); - } catch (e) { - nextTick(function () { - throw prevError; - }, 0); - throw e; - } - } else { - this.cb.call(this.vm, value, oldValue); - } - } - this.queued = this.shallow = false; - } - }; - - /** - * Evaluate the value of the watcher. - * This only gets called for lazy watchers. - */ - - Watcher.prototype.evaluate = function () { - // avoid overwriting another watcher that is being - // collected. - var current = Dep.target; - this.value = this.get(); - this.dirty = false; - Dep.target = current; - }; - - /** - * Depend on all deps collected by this watcher. - */ - - Watcher.prototype.depend = function () { - var i = this.deps.length; - while (i--) { - this.deps[i].depend(); - } - }; - - /** - * Remove self from all dependencies' subcriber list. - */ - - Watcher.prototype.teardown = function () { - if (this.active) { - // remove self from vm's watcher list - // this is a somewhat expensive operation so we skip it - // if the vm is being destroyed or is performing a v-for - // re-render (the watcher list is then filtered by v-for). - if (!this.vm._isBeingDestroyed && !this.vm._vForRemoving) { - this.vm._watchers.$remove(this); - } - var i = this.deps.length; - while (i--) { - this.deps[i].removeSub(this); - } - this.active = false; - this.vm = this.cb = this.value = null; - } - }; - - /** - * Recrusively traverse an object to evoke all converted - * getters, so that every nested property inside the object - * is collected as a "deep" dependency. - * - * @param {*} val - */ - - var seenObjects = new _Set(); - function traverse(val, seen) { - var i = undefined, - keys = undefined; - if (!seen) { - seen = seenObjects; - seen.clear(); - } - var isA = isArray(val); - var isO = isObject(val); - if ((isA || isO) && Object.isExtensible(val)) { - if (val.__ob__) { - var depId = val.__ob__.dep.id; - if (seen.has(depId)) { - return; - } else { - seen.add(depId); - } - } - if (isA) { - i = val.length; - while (i--) traverse(val[i], seen); - } else if (isO) { - keys = Object.keys(val); - i = keys.length; - while (i--) traverse(val[keys[i]], seen); - } - } - } - - var text$1 = { - - bind: function bind() { - this.attr = this.el.nodeType === 3 ? 'data' : 'textContent'; - }, - - update: function update(value) { - this.el[this.attr] = _toString(value); - } - }; - - var templateCache = new Cache(1000); - var idSelectorCache = new Cache(1000); - - var map = { - efault: [0, '', ''], - legend: [1, '
', '
'], - tr: [2, '', '
'], - col: [2, '', '
'] - }; - - map.td = map.th = [3, '', '
']; - - map.option = map.optgroup = [1, '']; - - map.thead = map.tbody = map.colgroup = map.caption = map.tfoot = [1, '', '
']; - - map.g = map.defs = map.symbol = map.use = map.image = map.text = map.circle = map.ellipse = map.line = map.path = map.polygon = map.polyline = map.rect = [1, '', '']; - - /** - * Check if a node is a supported template node with a - * DocumentFragment content. - * - * @param {Node} node - * @return {Boolean} - */ - - function isRealTemplate(node) { - return isTemplate(node) && isFragment(node.content); - } - - var tagRE$1 = /<([\w:-]+)/; - var entityRE = /&#?\w+?;/; - var commentRE = / E - } - entry.newer = undefined; // D --x - entry.older = this.tail; // D. --> E - if (this.tail) { - this.tail.newer = entry; // E. <-- D - } - this.tail = entry; - return returnEntry ? entry : entry.value; - }; - - var cache$1 = new Cache(1000); - var filterTokenRE = /[^\s'"]+|'[^']*'|"[^"]*"/g; - var reservedArgRE = /^in$|^-?\d+/; - - /** - * Parser state - */ - - var str; - var dir; - var c; - var prev; - var i; - var l; - var lastFilterIndex; - var inSingle; - var inDouble; - var curly; - var square; - var paren; - /** - * Push a filter to the current directive object - */ - - function pushFilter() { - var exp = str.slice(lastFilterIndex, i).trim(); - var filter; - if (exp) { - filter = {}; - var tokens = exp.match(filterTokenRE); - filter.name = tokens[0]; - if (tokens.length > 1) { - filter.args = tokens.slice(1).map(processFilterArg); - } - } - if (filter) { - (dir.filters = dir.filters || []).push(filter); - } - lastFilterIndex = i + 1; - } - - /** - * Check if an argument is dynamic and strip quotes. - * - * @param {String} arg - * @return {Object} - */ - - function processFilterArg(arg) { - if (reservedArgRE.test(arg)) { - return { - value: toNumber(arg), - dynamic: false - }; - } else { - var stripped = stripQuotes(arg); - var dynamic = stripped === arg; - return { - value: dynamic ? arg : stripped, - dynamic: dynamic - }; - } - } - - /** - * Parse a directive value and extract the expression - * and its filters into a descriptor. - * - * Example: - * - * "a + 1 | uppercase" will yield: - * { - * expression: 'a + 1', - * filters: [ - * { name: 'uppercase', args: null } - * ] - * } - * - * @param {String} s - * @return {Object} - */ - - function parseDirective(s) { - var hit = cache$1.get(s); - if (hit) { - return hit; - } - - // reset parser state - str = s; - inSingle = inDouble = false; - curly = square = paren = 0; - lastFilterIndex = 0; - dir = {}; - - for (i = 0, l = str.length; i < l; i++) { - prev = c; - c = str.charCodeAt(i); - if (inSingle) { - // check single quote - if (c === 0x27 && prev !== 0x5C) inSingle = !inSingle; - } else if (inDouble) { - // check double quote - if (c === 0x22 && prev !== 0x5C) inDouble = !inDouble; - } else if (c === 0x7C && // pipe - str.charCodeAt(i + 1) !== 0x7C && str.charCodeAt(i - 1) !== 0x7C) { - if (dir.expression == null) { - // first filter, end of expression - lastFilterIndex = i + 1; - dir.expression = str.slice(0, i).trim(); - } else { - // already has filter - pushFilter(); - } - } else { - switch (c) { - case 0x22: - inDouble = true;break; // " - case 0x27: - inSingle = true;break; // ' - case 0x28: - paren++;break; // ( - case 0x29: - paren--;break; // ) - case 0x5B: - square++;break; // [ - case 0x5D: - square--;break; // ] - case 0x7B: - curly++;break; // { - case 0x7D: - curly--;break; // } - } - } - } - - if (dir.expression == null) { - dir.expression = str.slice(0, i).trim(); - } else if (lastFilterIndex !== 0) { - pushFilter(); - } - - cache$1.put(s, dir); - return dir; - } - -var directive = Object.freeze({ - parseDirective: parseDirective - }); - - var regexEscapeRE = /[-.*+?^${}()|[\]\/\\]/g; - var cache = undefined; - var tagRE = undefined; - var htmlRE = undefined; - /** - * Escape a string so it can be used in a RegExp - * constructor. - * - * @param {String} str - */ - - function escapeRegex(str) { - return str.replace(regexEscapeRE, '\\$&'); - } - - function compileRegex() { - var open = escapeRegex(config.delimiters[0]); - var close = escapeRegex(config.delimiters[1]); - var unsafeOpen = escapeRegex(config.unsafeDelimiters[0]); - var unsafeClose = escapeRegex(config.unsafeDelimiters[1]); - tagRE = new RegExp(unsafeOpen + '((?:.|\\n)+?)' + unsafeClose + '|' + open + '((?:.|\\n)+?)' + close, 'g'); - htmlRE = new RegExp('^' + unsafeOpen + '((?:.|\\n)+?)' + unsafeClose + '$'); - // reset cache - cache = new Cache(1000); - } - - /** - * Parse a template text string into an array of tokens. - * - * @param {String} text - * @return {Array | null} - * - {String} type - * - {String} value - * - {Boolean} [html] - * - {Boolean} [oneTime] - */ - - function parseText(text) { - if (!cache) { - compileRegex(); - } - var hit = cache.get(text); - if (hit) { - return hit; - } - if (!tagRE.test(text)) { - return null; - } - var tokens = []; - var lastIndex = tagRE.lastIndex = 0; - var match, index, html, value, first, oneTime; - /* eslint-disable no-cond-assign */ - while (match = tagRE.exec(text)) { - /* eslint-enable no-cond-assign */ - index = match.index; - // push text token - if (index > lastIndex) { - tokens.push({ - value: text.slice(lastIndex, index) - }); - } - // tag token - html = htmlRE.test(match[0]); - value = html ? match[1] : match[2]; - first = value.charCodeAt(0); - oneTime = first === 42; // * - value = oneTime ? value.slice(1) : value; - tokens.push({ - tag: true, - value: value.trim(), - html: html, - oneTime: oneTime - }); - lastIndex = index + match[0].length; - } - if (lastIndex < text.length) { - tokens.push({ - value: text.slice(lastIndex) - }); - } - cache.put(text, tokens); - return tokens; - } - - /** - * Format a list of tokens into an expression. - * e.g. tokens parsed from 'a {{b}} c' can be serialized - * into one single expression as '"a " + b + " c"'. - * - * @param {Array} tokens - * @param {Vue} [vm] - * @return {String} - */ - - function tokensToExp(tokens, vm) { - if (tokens.length > 1) { - return tokens.map(function (token) { - return formatToken(token, vm); - }).join('+'); - } else { - return formatToken(tokens[0], vm, true); - } - } - - /** - * Format a single token. - * - * @param {Object} token - * @param {Vue} [vm] - * @param {Boolean} [single] - * @return {String} - */ - - function formatToken(token, vm, single) { - return token.tag ? token.oneTime && vm ? '"' + vm.$eval(token.value) + '"' : inlineFilters(token.value, single) : '"' + token.value + '"'; - } - - /** - * For an attribute with multiple interpolation tags, - * e.g. attr="some-{{thing | filter}}", in order to combine - * the whole thing into a single watchable expression, we - * have to inline those filters. This function does exactly - * that. This is a bit hacky but it avoids heavy changes - * to directive parser and watcher mechanism. - * - * @param {String} exp - * @param {Boolean} single - * @return {String} - */ - - var filterRE = /[^|]\|[^|]/; - function inlineFilters(exp, single) { - if (!filterRE.test(exp)) { - return single ? exp : '(' + exp + ')'; - } else { - var dir = parseDirective(exp); - if (!dir.filters) { - return '(' + exp + ')'; - } else { - return 'this._applyFilters(' + dir.expression + // value - ',null,' + // oldValue (null for read) - JSON.stringify(dir.filters) + // filter descriptors - ',false)'; // write? - } - } - } - -var text = Object.freeze({ - compileRegex: compileRegex, - parseText: parseText, - tokensToExp: tokensToExp - }); - - var delimiters = ['{{', '}}']; - var unsafeDelimiters = ['{{{', '}}}']; - - var config = Object.defineProperties({ - - /** - * Whether to print debug messages. - * Also enables stack trace for warnings. - * - * @type {Boolean} - */ - - debug: false, - - /** - * Whether to suppress warnings. - * - * @type {Boolean} - */ - - silent: false, - - /** - * Whether to use async rendering. - */ - - async: true, - - /** - * Whether to warn against errors caught when evaluating - * expressions. - */ - - warnExpressionErrors: true, - - /** - * Whether to allow devtools inspection. - * Disabled by default in production builds. - */ - - devtools: 'development' !== 'production', - - /** - * Internal flag to indicate the delimiters have been - * changed. - * - * @type {Boolean} - */ - - _delimitersChanged: true, - - /** - * List of asset types that a component can own. - * - * @type {Array} - */ - - _assetTypes: ['component', 'directive', 'elementDirective', 'filter', 'transition', 'partial'], - - /** - * prop binding modes - */ - - _propBindingModes: { - ONE_WAY: 0, - TWO_WAY: 1, - ONE_TIME: 2 - }, - - /** - * Max circular updates allowed in a batcher flush cycle. - */ - - _maxUpdateCount: 100 - - }, { - delimiters: { /** - * Interpolation delimiters. Changing these would trigger - * the text parser to re-compile the regular expressions. - * - * @type {Array} - */ - - get: function get() { - return delimiters; - }, - set: function set(val) { - delimiters = val; - compileRegex(); - }, - configurable: true, - enumerable: true - }, - unsafeDelimiters: { - get: function get() { - return unsafeDelimiters; - }, - set: function set(val) { - unsafeDelimiters = val; - compileRegex(); - }, - configurable: true, - enumerable: true - } - }); - - var warn = undefined; - var formatComponentName = undefined; - - if ('development' !== 'production') { - (function () { - var hasConsole = typeof console !== 'undefined'; - - warn = function (msg, vm) { - if (hasConsole && !config.silent) { - console.error('[Vue warn]: ' + msg + (vm ? formatComponentName(vm) : '')); - } - }; - - formatComponentName = function (vm) { - var name = vm._isVue ? vm.$options.name : vm.name; - return name ? ' (found in component: <' + hyphenate(name) + '>)' : ''; - }; - })(); - } - - /** - * Append with transition. - * - * @param {Element} el - * @param {Element} target - * @param {Vue} vm - * @param {Function} [cb] - */ - - function appendWithTransition(el, target, vm, cb) { - applyTransition(el, 1, function () { - target.appendChild(el); - }, vm, cb); - } - - /** - * InsertBefore with transition. - * - * @param {Element} el - * @param {Element} target - * @param {Vue} vm - * @param {Function} [cb] - */ - - function beforeWithTransition(el, target, vm, cb) { - applyTransition(el, 1, function () { - before(el, target); - }, vm, cb); - } - - /** - * Remove with transition. - * - * @param {Element} el - * @param {Vue} vm - * @param {Function} [cb] - */ - - function removeWithTransition(el, vm, cb) { - applyTransition(el, -1, function () { - remove(el); - }, vm, cb); - } - - /** - * Apply transitions with an operation callback. - * - * @param {Element} el - * @param {Number} direction - * 1: enter - * -1: leave - * @param {Function} op - the actual DOM operation - * @param {Vue} vm - * @param {Function} [cb] - */ - - function applyTransition(el, direction, op, vm, cb) { - var transition = el.__v_trans; - if (!transition || - // skip if there are no js hooks and CSS transition is - // not supported - !transition.hooks && !transitionEndEvent || - // skip transitions for initial compile - !vm._isCompiled || - // if the vm is being manipulated by a parent directive - // during the parent's compilation phase, skip the - // animation. - vm.$parent && !vm.$parent._isCompiled) { - op(); - if (cb) cb(); - return; - } - var action = direction > 0 ? 'enter' : 'leave'; - transition[action](op, cb); - } - -var transition = Object.freeze({ - appendWithTransition: appendWithTransition, - beforeWithTransition: beforeWithTransition, - removeWithTransition: removeWithTransition, - applyTransition: applyTransition - }); - - /** - * Query an element selector if it's not an element already. - * - * @param {String|Element} el - * @return {Element} - */ - - function query(el) { - if (typeof el === 'string') { - var selector = el; - el = document.querySelector(el); - if (!el) { - 'development' !== 'production' && warn('Cannot find element: ' + selector); - } - } - return el; - } - - /** - * Check if a node is in the document. - * Note: document.documentElement.contains should work here - * but always returns false for comment nodes in phantomjs, - * making unit tests difficult. This is fixed by doing the - * contains() check on the node's parentNode instead of - * the node itself. - * - * @param {Node} node - * @return {Boolean} - */ - - function inDoc(node) { - if (!node) return false; - var doc = node.ownerDocument.documentElement; - var parent = node.parentNode; - return doc === node || doc === parent || !!(parent && parent.nodeType === 1 && doc.contains(parent)); - } - - /** - * Get and remove an attribute from a node. - * - * @param {Node} node - * @param {String} _attr - */ - - function getAttr(node, _attr) { - var val = node.getAttribute(_attr); - if (val !== null) { - node.removeAttribute(_attr); - } - return val; - } - - /** - * Get an attribute with colon or v-bind: prefix. - * - * @param {Node} node - * @param {String} name - * @return {String|null} - */ - - function getBindAttr(node, name) { - var val = getAttr(node, ':' + name); - if (val === null) { - val = getAttr(node, 'v-bind:' + name); - } - return val; - } - - /** - * Check the presence of a bind attribute. - * - * @param {Node} node - * @param {String} name - * @return {Boolean} - */ - - function hasBindAttr(node, name) { - return node.hasAttribute(name) || node.hasAttribute(':' + name) || node.hasAttribute('v-bind:' + name); - } - - /** - * Insert el before target - * - * @param {Element} el - * @param {Element} target - */ - - function before(el, target) { - target.parentNode.insertBefore(el, target); - } - - /** - * Insert el after target - * - * @param {Element} el - * @param {Element} target - */ - - function after(el, target) { - if (target.nextSibling) { - before(el, target.nextSibling); - } else { - target.parentNode.appendChild(el); - } - } - - /** - * Remove el from DOM - * - * @param {Element} el - */ - - function remove(el) { - el.parentNode.removeChild(el); - } - - /** - * Prepend el to target - * - * @param {Element} el - * @param {Element} target - */ - - function prepend(el, target) { - if (target.firstChild) { - before(el, target.firstChild); - } else { - target.appendChild(el); - } - } - - /** - * Replace target with el - * - * @param {Element} target - * @param {Element} el - */ - - function replace(target, el) { - var parent = target.parentNode; - if (parent) { - parent.replaceChild(el, target); - } - } - - /** - * Add event listener shorthand. - * - * @param {Element} el - * @param {String} event - * @param {Function} cb - * @param {Boolean} [useCapture] - */ - - function on(el, event, cb, useCapture) { - el.addEventListener(event, cb, useCapture); - } - - /** - * Remove event listener shorthand. - * - * @param {Element} el - * @param {String} event - * @param {Function} cb - */ - - function off(el, event, cb) { - el.removeEventListener(event, cb); - } - - /** - * For IE9 compat: when both class and :class are present - * getAttribute('class') returns wrong value... - * - * @param {Element} el - * @return {String} - */ - - function getClass(el) { - var classname = el.className; - if (typeof classname === 'object') { - classname = classname.baseVal || ''; - } - return classname; - } - - /** - * In IE9, setAttribute('class') will result in empty class - * if the element also has the :class attribute; However in - * PhantomJS, setting `className` does not work on SVG elements... - * So we have to do a conditional check here. - * - * @param {Element} el - * @param {String} cls - */ - - function setClass(el, cls) { - /* istanbul ignore if */ - if (isIE9 && !/svg$/.test(el.namespaceURI)) { - el.className = cls; - } else { - el.setAttribute('class', cls); - } - } - - /** - * Add class with compatibility for IE & SVG - * - * @param {Element} el - * @param {String} cls - */ - - function addClass(el, cls) { - if (el.classList) { - el.classList.add(cls); - } else { - var cur = ' ' + getClass(el) + ' '; - if (cur.indexOf(' ' + cls + ' ') < 0) { - setClass(el, (cur + cls).trim()); - } - } - } - - /** - * Remove class with compatibility for IE & SVG - * - * @param {Element} el - * @param {String} cls - */ - - function removeClass(el, cls) { - if (el.classList) { - el.classList.remove(cls); - } else { - var cur = ' ' + getClass(el) + ' '; - var tar = ' ' + cls + ' '; - while (cur.indexOf(tar) >= 0) { - cur = cur.replace(tar, ' '); - } - setClass(el, cur.trim()); - } - if (!el.className) { - el.removeAttribute('class'); - } - } - - /** - * Extract raw content inside an element into a temporary - * container div - * - * @param {Element} el - * @param {Boolean} asFragment - * @return {Element|DocumentFragment} - */ - - function extractContent(el, asFragment) { - var child; - var rawContent; - /* istanbul ignore if */ - if (isTemplate(el) && isFragment(el.content)) { - el = el.content; - } - if (el.hasChildNodes()) { - trimNode(el); - rawContent = asFragment ? document.createDocumentFragment() : document.createElement('div'); - /* eslint-disable no-cond-assign */ - while (child = el.firstChild) { - /* eslint-enable no-cond-assign */ - rawContent.appendChild(child); - } - } - return rawContent; - } - - /** - * Trim possible empty head/tail text and comment - * nodes inside a parent. - * - * @param {Node} node - */ - - function trimNode(node) { - var child; - /* eslint-disable no-sequences */ - while ((child = node.firstChild, isTrimmable(child))) { - node.removeChild(child); - } - while ((child = node.lastChild, isTrimmable(child))) { - node.removeChild(child); - } - /* eslint-enable no-sequences */ - } - - function isTrimmable(node) { - return node && (node.nodeType === 3 && !node.data.trim() || node.nodeType === 8); - } - - /** - * Check if an element is a template tag. - * Note if the template appears inside an SVG its tagName - * will be in lowercase. - * - * @param {Element} el - */ - - function isTemplate(el) { - return el.tagName && el.tagName.toLowerCase() === 'template'; - } - - /** - * Create an "anchor" for performing dom insertion/removals. - * This is used in a number of scenarios: - * - fragment instance - * - v-html - * - v-if - * - v-for - * - component - * - * @param {String} content - * @param {Boolean} persist - IE trashes empty textNodes on - * cloneNode(true), so in certain - * cases the anchor needs to be - * non-empty to be persisted in - * templates. - * @return {Comment|Text} - */ - - function createAnchor(content, persist) { - var anchor = config.debug ? document.createComment(content) : document.createTextNode(persist ? ' ' : ''); - anchor.__v_anchor = true; - return anchor; - } - - /** - * Find a component ref attribute that starts with $. - * - * @param {Element} node - * @return {String|undefined} - */ - - var refRE = /^v-ref:/; - - function findRef(node) { - if (node.hasAttributes()) { - var attrs = node.attributes; - for (var i = 0, l = attrs.length; i < l; i++) { - var name = attrs[i].name; - if (refRE.test(name)) { - return camelize(name.replace(refRE, '')); - } - } - } - } - - /** - * Map a function to a range of nodes . - * - * @param {Node} node - * @param {Node} end - * @param {Function} op - */ - - function mapNodeRange(node, end, op) { - var next; - while (node !== end) { - next = node.nextSibling; - op(node); - node = next; - } - op(end); - } - - /** - * Remove a range of nodes with transition, store - * the nodes in a fragment with correct ordering, - * and call callback when done. - * - * @param {Node} start - * @param {Node} end - * @param {Vue} vm - * @param {DocumentFragment} frag - * @param {Function} cb - */ - - function removeNodeRange(start, end, vm, frag, cb) { - var done = false; - var removed = 0; - var nodes = []; - mapNodeRange(start, end, function (node) { - if (node === end) done = true; - nodes.push(node); - removeWithTransition(node, vm, onRemoved); - }); - function onRemoved() { - removed++; - if (done && removed >= nodes.length) { - for (var i = 0; i < nodes.length; i++) { - frag.appendChild(nodes[i]); - } - cb && cb(); - } - } - } - - /** - * Check if a node is a DocumentFragment. - * - * @param {Node} node - * @return {Boolean} - */ - - function isFragment(node) { - return node && node.nodeType === 11; - } - - /** - * Get outerHTML of elements, taking care - * of SVG elements in IE as well. - * - * @param {Element} el - * @return {String} - */ - - function getOuterHTML(el) { - if (el.outerHTML) { - return el.outerHTML; - } else { - var container = document.createElement('div'); - container.appendChild(el.cloneNode(true)); - return container.innerHTML; - } - } - - var commonTagRE = /^(div|p|span|img|a|b|i|br|ul|ol|li|h1|h2|h3|h4|h5|h6|code|pre|table|th|td|tr|form|label|input|select|option|nav|article|section|header|footer)$/i; - var reservedTagRE = /^(slot|partial|component)$/i; - - var isUnknownElement = undefined; - if ('development' !== 'production') { - isUnknownElement = function (el, tag) { - if (tag.indexOf('-') > -1) { - // http://stackoverflow.com/a/28210364/1070244 - return el.constructor === window.HTMLUnknownElement || el.constructor === window.HTMLElement; - } else { - return (/HTMLUnknownElement/.test(el.toString()) && - // Chrome returns unknown for several HTML5 elements. - // https://code.google.com/p/chromium/issues/detail?id=540526 - // Firefox returns unknown for some "Interactive elements." - !/^(data|time|rtc|rb|details|dialog|summary)$/.test(tag) - ); - } - }; - } - - /** - * Check if an element is a component, if yes return its - * component id. - * - * @param {Element} el - * @param {Object} options - * @return {Object|undefined} - */ - - function checkComponentAttr(el, options) { - var tag = el.tagName.toLowerCase(); - var hasAttrs = el.hasAttributes(); - if (!commonTagRE.test(tag) && !reservedTagRE.test(tag)) { - if (resolveAsset(options, 'components', tag)) { - return { id: tag }; - } else { - var is = hasAttrs && getIsBinding(el, options); - if (is) { - return is; - } else if ('development' !== 'production') { - var expectedTag = options._componentNameMap && options._componentNameMap[tag]; - if (expectedTag) { - warn('Unknown custom element: <' + tag + '> - ' + 'did you mean <' + expectedTag + '>? ' + 'HTML is case-insensitive, remember to use kebab-case in templates.'); - } else if (isUnknownElement(el, tag)) { - warn('Unknown custom element: <' + tag + '> - did you ' + 'register the component correctly? For recursive components, ' + 'make sure to provide the "name" option.'); - } - } - } - } else if (hasAttrs) { - return getIsBinding(el, options); - } - } - - /** - * Get "is" binding from an element. - * - * @param {Element} el - * @param {Object} options - * @return {Object|undefined} - */ - - function getIsBinding(el, options) { - // dynamic syntax - var exp = el.getAttribute('is'); - if (exp != null) { - if (resolveAsset(options, 'components', exp)) { - el.removeAttribute('is'); - return { id: exp }; - } - } else { - exp = getBindAttr(el, 'is'); - if (exp != null) { - return { id: exp, dynamic: true }; - } - } - } - - /** - * Option overwriting strategies are functions that handle - * how to merge a parent option value and a child option - * value into the final value. - * - * All strategy functions follow the same signature: - * - * @param {*} parentVal - * @param {*} childVal - * @param {Vue} [vm] - */ - - var strats = config.optionMergeStrategies = Object.create(null); - - /** - * Helper that recursively merges two data objects together. - */ - - function mergeData(to, from) { - var key, toVal, fromVal; - for (key in from) { - toVal = to[key]; - fromVal = from[key]; - if (!hasOwn(to, key)) { - set(to, key, fromVal); - } else if (isObject(toVal) && isObject(fromVal)) { - mergeData(toVal, fromVal); - } - } - return to; - } - - /** - * Data - */ - - strats.data = function (parentVal, childVal, vm) { - if (!vm) { - // in a Vue.extend merge, both should be functions - if (!childVal) { - return parentVal; - } - if (typeof childVal !== 'function') { - 'development' !== 'production' && warn('The "data" option should be a function ' + 'that returns a per-instance value in component ' + 'definitions.', vm); - return parentVal; - } - if (!parentVal) { - return childVal; - } - // when parentVal & childVal are both present, - // we need to return a function that returns the - // merged result of both functions... no need to - // check if parentVal is a function here because - // it has to be a function to pass previous merges. - return function mergedDataFn() { - return mergeData(childVal.call(this), parentVal.call(this)); - }; - } else if (parentVal || childVal) { - return function mergedInstanceDataFn() { - // instance merge - var instanceData = typeof childVal === 'function' ? childVal.call(vm) : childVal; - var defaultData = typeof parentVal === 'function' ? parentVal.call(vm) : undefined; - if (instanceData) { - return mergeData(instanceData, defaultData); - } else { - return defaultData; - } - }; - } - }; - - /** - * El - */ - - strats.el = function (parentVal, childVal, vm) { - if (!vm && childVal && typeof childVal !== 'function') { - 'development' !== 'production' && warn('The "el" option should be a function ' + 'that returns a per-instance value in component ' + 'definitions.', vm); - return; - } - var ret = childVal || parentVal; - // invoke the element factory if this is instance merge - return vm && typeof ret === 'function' ? ret.call(vm) : ret; - }; - - /** - * Hooks and param attributes are merged as arrays. - */ - - strats.init = strats.created = strats.ready = strats.attached = strats.detached = strats.beforeCompile = strats.compiled = strats.beforeDestroy = strats.destroyed = strats.activate = function (parentVal, childVal) { - return childVal ? parentVal ? parentVal.concat(childVal) : isArray(childVal) ? childVal : [childVal] : parentVal; - }; - - /** - * Assets - * - * When a vm is present (instance creation), we need to do - * a three-way merge between constructor options, instance - * options and parent options. - */ - - function mergeAssets(parentVal, childVal) { - var res = Object.create(parentVal || null); - return childVal ? extend(res, guardArrayAssets(childVal)) : res; - } - - config._assetTypes.forEach(function (type) { - strats[type + 's'] = mergeAssets; - }); - - /** - * Events & Watchers. - * - * Events & watchers hashes should not overwrite one - * another, so we merge them as arrays. - */ - - strats.watch = strats.events = function (parentVal, childVal) { - if (!childVal) return parentVal; - if (!parentVal) return childVal; - var ret = {}; - extend(ret, parentVal); - for (var key in childVal) { - var parent = ret[key]; - var child = childVal[key]; - if (parent && !isArray(parent)) { - parent = [parent]; - } - ret[key] = parent ? parent.concat(child) : [child]; - } - return ret; - }; - - /** - * Other object hashes. - */ - - strats.props = strats.methods = strats.computed = function (parentVal, childVal) { - if (!childVal) return parentVal; - if (!parentVal) return childVal; - var ret = Object.create(null); - extend(ret, parentVal); - extend(ret, childVal); - return ret; - }; - - /** - * Default strategy. - */ - - var defaultStrat = function defaultStrat(parentVal, childVal) { - return childVal === undefined ? parentVal : childVal; - }; - - /** - * Make sure component options get converted to actual - * constructors. - * - * @param {Object} options - */ - - function guardComponents(options) { - if (options.components) { - var components = options.components = guardArrayAssets(options.components); - var ids = Object.keys(components); - var def; - if ('development' !== 'production') { - var map = options._componentNameMap = {}; - } - for (var i = 0, l = ids.length; i < l; i++) { - var key = ids[i]; - if (commonTagRE.test(key) || reservedTagRE.test(key)) { - 'development' !== 'production' && warn('Do not use built-in or reserved HTML elements as component ' + 'id: ' + key); - continue; - } - // record a all lowercase <-> kebab-case mapping for - // possible custom element case error warning - if ('development' !== 'production') { - map[key.replace(/-/g, '').toLowerCase()] = hyphenate(key); - } - def = components[key]; - if (isPlainObject(def)) { - components[key] = Vue.extend(def); - } - } - } - } - - /** - * Ensure all props option syntax are normalized into the - * Object-based format. - * - * @param {Object} options - */ - - function guardProps(options) { - var props = options.props; - var i, val; - if (isArray(props)) { - options.props = {}; - i = props.length; - while (i--) { - val = props[i]; - if (typeof val === 'string') { - options.props[val] = null; - } else if (val.name) { - options.props[val.name] = val; - } - } - } else if (isPlainObject(props)) { - var keys = Object.keys(props); - i = keys.length; - while (i--) { - val = props[keys[i]]; - if (typeof val === 'function') { - props[keys[i]] = { type: val }; - } - } - } - } - - /** - * Guard an Array-format assets option and converted it - * into the key-value Object format. - * - * @param {Object|Array} assets - * @return {Object} - */ - - function guardArrayAssets(assets) { - if (isArray(assets)) { - var res = {}; - var i = assets.length; - var asset; - while (i--) { - asset = assets[i]; - var id = typeof asset === 'function' ? asset.options && asset.options.name || asset.id : asset.name || asset.id; - if (!id) { - 'development' !== 'production' && warn('Array-syntax assets must provide a "name" or "id" field.'); - } else { - res[id] = asset; - } - } - return res; - } - return assets; - } - - /** - * Merge two option objects into a new one. - * Core utility used in both instantiation and inheritance. - * - * @param {Object} parent - * @param {Object} child - * @param {Vue} [vm] - if vm is present, indicates this is - * an instantiation merge. - */ - - function mergeOptions(parent, child, vm) { - guardComponents(child); - guardProps(child); - if ('development' !== 'production') { - if (child.propsData && !vm) { - warn('propsData can only be used as an instantiation option.'); - } - } - var options = {}; - var key; - if (child['extends']) { - parent = typeof child['extends'] === 'function' ? mergeOptions(parent, child['extends'].options, vm) : mergeOptions(parent, child['extends'], vm); - } - if (child.mixins) { - for (var i = 0, l = child.mixins.length; i < l; i++) { - var mixin = child.mixins[i]; - var mixinOptions = mixin.prototype instanceof Vue ? mixin.options : mixin; - parent = mergeOptions(parent, mixinOptions, vm); - } - } - for (key in parent) { - mergeField(key); - } - for (key in child) { - if (!hasOwn(parent, key)) { - mergeField(key); - } - } - function mergeField(key) { - var strat = strats[key] || defaultStrat; - options[key] = strat(parent[key], child[key], vm, key); - } - return options; - } - - /** - * Resolve an asset. - * This function is used because child instances need access - * to assets defined in its ancestor chain. - * - * @param {Object} options - * @param {String} type - * @param {String} id - * @param {Boolean} warnMissing - * @return {Object|Function} - */ - - function resolveAsset(options, type, id, warnMissing) { - /* istanbul ignore if */ - if (typeof id !== 'string') { - return; - } - var assets = options[type]; - var camelizedId; - var res = assets[id] || - // camelCase ID - assets[camelizedId = camelize(id)] || - // Pascal Case ID - assets[camelizedId.charAt(0).toUpperCase() + camelizedId.slice(1)]; - if ('development' !== 'production' && warnMissing && !res) { - warn('Failed to resolve ' + type.slice(0, -1) + ': ' + id, options); - } - return res; - } - - var uid$1 = 0; - - /** - * A dep is an observable that can have multiple - * directives subscribing to it. - * - * @constructor - */ - function Dep() { - this.id = uid$1++; - this.subs = []; - } - - // the current target watcher being evaluated. - // this is globally unique because there could be only one - // watcher being evaluated at any time. - Dep.target = null; - - /** - * Add a directive subscriber. - * - * @param {Directive} sub - */ - - Dep.prototype.addSub = function (sub) { - this.subs.push(sub); - }; - - /** - * Remove a directive subscriber. - * - * @param {Directive} sub - */ - - Dep.prototype.removeSub = function (sub) { - this.subs.$remove(sub); - }; - - /** - * Add self as a dependency to the target watcher. - */ - - Dep.prototype.depend = function () { - Dep.target.addDep(this); - }; - - /** - * Notify all subscribers of a new value. - */ - - Dep.prototype.notify = function () { - // stablize the subscriber list first - var subs = toArray(this.subs); - for (var i = 0, l = subs.length; i < l; i++) { - subs[i].update(); - } - }; - - var arrayProto = Array.prototype; - var arrayMethods = Object.create(arrayProto) - - /** - * Intercept mutating methods and emit events - */ - - ;['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse'].forEach(function (method) { - // cache original method - var original = arrayProto[method]; - def(arrayMethods, method, function mutator() { - // avoid leaking arguments: - // http://jsperf.com/closure-with-arguments - var i = arguments.length; - var args = new Array(i); - while (i--) { - args[i] = arguments[i]; - } - var result = original.apply(this, args); - var ob = this.__ob__; - var inserted; - switch (method) { - case 'push': - inserted = args; - break; - case 'unshift': - inserted = args; - break; - case 'splice': - inserted = args.slice(2); - break; - } - if (inserted) ob.observeArray(inserted); - // notify change - ob.dep.notify(); - return result; - }); - }); - - /** - * Swap the element at the given index with a new value - * and emits corresponding event. - * - * @param {Number} index - * @param {*} val - * @return {*} - replaced element - */ - - def(arrayProto, '$set', function $set(index, val) { - if (index >= this.length) { - this.length = Number(index) + 1; - } - return this.splice(index, 1, val)[0]; - }); - - /** - * Convenience method to remove the element at given index or target element reference. - * - * @param {*} item - */ - - def(arrayProto, '$remove', function $remove(item) { - /* istanbul ignore if */ - if (!this.length) return; - var index = indexOf(this, item); - if (index > -1) { - return this.splice(index, 1); - } - }); - - var arrayKeys = Object.getOwnPropertyNames(arrayMethods); - - /** - * By default, when a reactive property is set, the new value is - * also converted to become reactive. However in certain cases, e.g. - * v-for scope alias and props, we don't want to force conversion - * because the value may be a nested value under a frozen data structure. - * - * So whenever we want to set a reactive property without forcing - * conversion on the new value, we wrap that call inside this function. - */ - - var shouldConvert = true; - - function withoutConversion(fn) { - shouldConvert = false; - fn(); - shouldConvert = true; - } - - /** - * Observer class that are attached to each observed - * object. Once attached, the observer converts target - * object's property keys into getter/setters that - * collect dependencies and dispatches updates. - * - * @param {Array|Object} value - * @constructor - */ - - function Observer(value) { - this.value = value; - this.dep = new Dep(); - def(value, '__ob__', this); - if (isArray(value)) { - var augment = hasProto ? protoAugment : copyAugment; - augment(value, arrayMethods, arrayKeys); - this.observeArray(value); - } else { - this.walk(value); - } - } - - // Instance methods - - /** - * Walk through each property and convert them into - * getter/setters. This method should only be called when - * value type is Object. - * - * @param {Object} obj - */ - - Observer.prototype.walk = function (obj) { - var keys = Object.keys(obj); - for (var i = 0, l = keys.length; i < l; i++) { - this.convert(keys[i], obj[keys[i]]); - } - }; - - /** - * Observe a list of Array items. - * - * @param {Array} items - */ - - Observer.prototype.observeArray = function (items) { - for (var i = 0, l = items.length; i < l; i++) { - observe(items[i]); - } - }; - - /** - * Convert a property into getter/setter so we can emit - * the events when the property is accessed/changed. - * - * @param {String} key - * @param {*} val - */ - - Observer.prototype.convert = function (key, val) { - defineReactive(this.value, key, val); - }; - - /** - * Add an owner vm, so that when $set/$delete mutations - * happen we can notify owner vms to proxy the keys and - * digest the watchers. This is only called when the object - * is observed as an instance's root $data. - * - * @param {Vue} vm - */ - - Observer.prototype.addVm = function (vm) { - (this.vms || (this.vms = [])).push(vm); - }; - - /** - * Remove an owner vm. This is called when the object is - * swapped out as an instance's $data object. - * - * @param {Vue} vm - */ - - Observer.prototype.removeVm = function (vm) { - this.vms.$remove(vm); - }; - - // helpers - - /** - * Augment an target Object or Array by intercepting - * the prototype chain using __proto__ - * - * @param {Object|Array} target - * @param {Object} src - */ - - function protoAugment(target, src) { - /* eslint-disable no-proto */ - target.__proto__ = src; - /* eslint-enable no-proto */ - } - - /** - * Augment an target Object or Array by defining - * hidden properties. - * - * @param {Object|Array} target - * @param {Object} proto - */ - - function copyAugment(target, src, keys) { - for (var i = 0, l = keys.length; i < l; i++) { - var key = keys[i]; - def(target, key, src[key]); - } - } - - /** - * Attempt to create an observer instance for a value, - * returns the new observer if successfully observed, - * or the existing observer if the value already has one. - * - * @param {*} value - * @param {Vue} [vm] - * @return {Observer|undefined} - * @static - */ - - function observe(value, vm) { - if (!value || typeof value !== 'object') { - return; - } - var ob; - if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) { - ob = value.__ob__; - } else if (shouldConvert && (isArray(value) || isPlainObject(value)) && Object.isExtensible(value) && !value._isVue) { - ob = new Observer(value); - } - if (ob && vm) { - ob.addVm(vm); - } - return ob; - } - - /** - * Define a reactive property on an Object. - * - * @param {Object} obj - * @param {String} key - * @param {*} val - */ - - function defineReactive(obj, key, val) { - var dep = new Dep(); - - var property = Object.getOwnPropertyDescriptor(obj, key); - if (property && property.configurable === false) { - return; - } - - // cater for pre-defined getter/setters - var getter = property && property.get; - var setter = property && property.set; - - var childOb = observe(val); - Object.defineProperty(obj, key, { - enumerable: true, - configurable: true, - get: function reactiveGetter() { - var value = getter ? getter.call(obj) : val; - if (Dep.target) { - dep.depend(); - if (childOb) { - childOb.dep.depend(); - } - if (isArray(value)) { - for (var e, i = 0, l = value.length; i < l; i++) { - e = value[i]; - e && e.__ob__ && e.__ob__.dep.depend(); - } - } - } - return value; - }, - set: function reactiveSetter(newVal) { - var value = getter ? getter.call(obj) : val; - if (newVal === value) { - return; - } - if (setter) { - setter.call(obj, newVal); - } else { - val = newVal; - } - childOb = observe(newVal); - dep.notify(); - } - }); - } - - - - var util = Object.freeze({ - defineReactive: defineReactive, - set: set, - del: del, - hasOwn: hasOwn, - isLiteral: isLiteral, - isReserved: isReserved, - _toString: _toString, - toNumber: toNumber, - toBoolean: toBoolean, - stripQuotes: stripQuotes, - camelize: camelize, - hyphenate: hyphenate, - classify: classify, - bind: bind, - toArray: toArray, - extend: extend, - isObject: isObject, - isPlainObject: isPlainObject, - def: def, - debounce: _debounce, - indexOf: indexOf, - cancellable: cancellable, - looseEqual: looseEqual, - isArray: isArray, - hasProto: hasProto, - inBrowser: inBrowser, - devtools: devtools, - isIE: isIE, - isIE9: isIE9, - isAndroid: isAndroid, - isIos: isIos, - iosVersionMatch: iosVersionMatch, - iosVersion: iosVersion, - hasMutationObserverBug: hasMutationObserverBug, - get transitionProp () { return transitionProp; }, - get transitionEndEvent () { return transitionEndEvent; }, - get animationProp () { return animationProp; }, - get animationEndEvent () { return animationEndEvent; }, - nextTick: nextTick, - get _Set () { return _Set; }, - query: query, - inDoc: inDoc, - getAttr: getAttr, - getBindAttr: getBindAttr, - hasBindAttr: hasBindAttr, - before: before, - after: after, - remove: remove, - prepend: prepend, - replace: replace, - on: on, - off: off, - setClass: setClass, - addClass: addClass, - removeClass: removeClass, - extractContent: extractContent, - trimNode: trimNode, - isTemplate: isTemplate, - createAnchor: createAnchor, - findRef: findRef, - mapNodeRange: mapNodeRange, - removeNodeRange: removeNodeRange, - isFragment: isFragment, - getOuterHTML: getOuterHTML, - mergeOptions: mergeOptions, - resolveAsset: resolveAsset, - checkComponentAttr: checkComponentAttr, - commonTagRE: commonTagRE, - reservedTagRE: reservedTagRE, - get warn () { return warn; } - }); - - var uid = 0; - - function initMixin (Vue) { - /** - * The main init sequence. This is called for every - * instance, including ones that are created from extended - * constructors. - * - * @param {Object} options - this options object should be - * the result of merging class - * options and the options passed - * in to the constructor. - */ - - Vue.prototype._init = function (options) { - options = options || {}; - - this.$el = null; - this.$parent = options.parent; - this.$root = this.$parent ? this.$parent.$root : this; - this.$children = []; - this.$refs = {}; // child vm references - this.$els = {}; // element references - this._watchers = []; // all watchers as an array - this._directives = []; // all directives - - // a uid - this._uid = uid++; - - // a flag to avoid this being observed - this._isVue = true; - - // events bookkeeping - this._events = {}; // registered callbacks - this._eventsCount = {}; // for $broadcast optimization - - // fragment instance properties - this._isFragment = false; - this._fragment = // @type {DocumentFragment} - this._fragmentStart = // @type {Text|Comment} - this._fragmentEnd = null; // @type {Text|Comment} - - // lifecycle state - this._isCompiled = this._isDestroyed = this._isReady = this._isAttached = this._isBeingDestroyed = this._vForRemoving = false; - this._unlinkFn = null; - - // context: - // if this is a transcluded component, context - // will be the common parent vm of this instance - // and its host. - this._context = options._context || this.$parent; - - // scope: - // if this is inside an inline v-for, the scope - // will be the intermediate scope created for this - // repeat fragment. this is used for linking props - // and container directives. - this._scope = options._scope; - - // fragment: - // if this instance is compiled inside a Fragment, it - // needs to reigster itself as a child of that fragment - // for attach/detach to work properly. - this._frag = options._frag; - if (this._frag) { - this._frag.children.push(this); - } - - // push self into parent / transclusion host - if (this.$parent) { - this.$parent.$children.push(this); - } - - // merge options. - options = this.$options = mergeOptions(this.constructor.options, options, this); - - // set ref - this._updateRef(); - - // initialize data as empty object. - // it will be filled up in _initData(). - this._data = {}; - - // call init hook - this._callHook('init'); - - // initialize data observation and scope inheritance. - this._initState(); - - // setup event system and option events. - this._initEvents(); - - // call created hook - this._callHook('created'); - - // if `el` option is passed, start compilation. - if (options.el) { - this.$mount(options.el); - } - }; - } - - var pathCache = new Cache(1000); - - // actions - var APPEND = 0; - var PUSH = 1; - var INC_SUB_PATH_DEPTH = 2; - var PUSH_SUB_PATH = 3; - - // states - var BEFORE_PATH = 0; - var IN_PATH = 1; - var BEFORE_IDENT = 2; - var IN_IDENT = 3; - var IN_SUB_PATH = 4; - var IN_SINGLE_QUOTE = 5; - var IN_DOUBLE_QUOTE = 6; - var AFTER_PATH = 7; - var ERROR = 8; - - var pathStateMachine = []; - - pathStateMachine[BEFORE_PATH] = { - 'ws': [BEFORE_PATH], - 'ident': [IN_IDENT, APPEND], - '[': [IN_SUB_PATH], - 'eof': [AFTER_PATH] - }; - - pathStateMachine[IN_PATH] = { - 'ws': [IN_PATH], - '.': [BEFORE_IDENT], - '[': [IN_SUB_PATH], - 'eof': [AFTER_PATH] - }; - - pathStateMachine[BEFORE_IDENT] = { - 'ws': [BEFORE_IDENT], - 'ident': [IN_IDENT, APPEND] - }; - - pathStateMachine[IN_IDENT] = { - 'ident': [IN_IDENT, APPEND], - '0': [IN_IDENT, APPEND], - 'number': [IN_IDENT, APPEND], - 'ws': [IN_PATH, PUSH], - '.': [BEFORE_IDENT, PUSH], - '[': [IN_SUB_PATH, PUSH], - 'eof': [AFTER_PATH, PUSH] - }; - - pathStateMachine[IN_SUB_PATH] = { - "'": [IN_SINGLE_QUOTE, APPEND], - '"': [IN_DOUBLE_QUOTE, APPEND], - '[': [IN_SUB_PATH, INC_SUB_PATH_DEPTH], - ']': [IN_PATH, PUSH_SUB_PATH], - 'eof': ERROR, - 'else': [IN_SUB_PATH, APPEND] - }; - - pathStateMachine[IN_SINGLE_QUOTE] = { - "'": [IN_SUB_PATH, APPEND], - 'eof': ERROR, - 'else': [IN_SINGLE_QUOTE, APPEND] - }; - - pathStateMachine[IN_DOUBLE_QUOTE] = { - '"': [IN_SUB_PATH, APPEND], - 'eof': ERROR, - 'else': [IN_DOUBLE_QUOTE, APPEND] - }; - - /** - * Determine the type of a character in a keypath. - * - * @param {Char} ch - * @return {String} type - */ - - function getPathCharType(ch) { - if (ch === undefined) { - return 'eof'; - } - - var code = ch.charCodeAt(0); - - switch (code) { - case 0x5B: // [ - case 0x5D: // ] - case 0x2E: // . - case 0x22: // " - case 0x27: // ' - case 0x30: - // 0 - return ch; - - case 0x5F: // _ - case 0x24: - // $ - return 'ident'; - - case 0x20: // Space - case 0x09: // Tab - case 0x0A: // Newline - case 0x0D: // Return - case 0xA0: // No-break space - case 0xFEFF: // Byte Order Mark - case 0x2028: // Line Separator - case 0x2029: - // Paragraph Separator - return 'ws'; - } - - // a-z, A-Z - if (code >= 0x61 && code <= 0x7A || code >= 0x41 && code <= 0x5A) { - return 'ident'; - } - - // 1-9 - if (code >= 0x31 && code <= 0x39) { - return 'number'; - } - - return 'else'; - } - - /** - * Format a subPath, return its plain form if it is - * a literal string or number. Otherwise prepend the - * dynamic indicator (*). - * - * @param {String} path - * @return {String} - */ - - function formatSubPath(path) { - var trimmed = path.trim(); - // invalid leading 0 - if (path.charAt(0) === '0' && isNaN(path)) { - return false; - } - return isLiteral(trimmed) ? stripQuotes(trimmed) : '*' + trimmed; - } - - /** - * Parse a string path into an array of segments - * - * @param {String} path - * @return {Array|undefined} - */ - - function parse(path) { - var keys = []; - var index = -1; - var mode = BEFORE_PATH; - var subPathDepth = 0; - var c, newChar, key, type, transition, action, typeMap; - - var actions = []; - - actions[PUSH] = function () { - if (key !== undefined) { - keys.push(key); - key = undefined; - } - }; - - actions[APPEND] = function () { - if (key === undefined) { - key = newChar; - } else { - key += newChar; - } - }; - - actions[INC_SUB_PATH_DEPTH] = function () { - actions[APPEND](); - subPathDepth++; - }; - - actions[PUSH_SUB_PATH] = function () { - if (subPathDepth > 0) { - subPathDepth--; - mode = IN_SUB_PATH; - actions[APPEND](); - } else { - subPathDepth = 0; - key = formatSubPath(key); - if (key === false) { - return false; - } else { - actions[PUSH](); - } - } - }; - - function maybeUnescapeQuote() { - var nextChar = path[index + 1]; - if (mode === IN_SINGLE_QUOTE && nextChar === "'" || mode === IN_DOUBLE_QUOTE && nextChar === '"') { - index++; - newChar = '\\' + nextChar; - actions[APPEND](); - return true; - } - } - - while (mode != null) { - index++; - c = path[index]; - - if (c === '\\' && maybeUnescapeQuote()) { - continue; - } - - type = getPathCharType(c); - typeMap = pathStateMachine[mode]; - transition = typeMap[type] || typeMap['else'] || ERROR; - - if (transition === ERROR) { - return; // parse error - } - - mode = transition[0]; - action = actions[transition[1]]; - if (action) { - newChar = transition[2]; - newChar = newChar === undefined ? c : newChar; - if (action() === false) { - return; - } - } - - if (mode === AFTER_PATH) { - keys.raw = path; - return keys; - } - } - } - - /** - * External parse that check for a cache hit first - * - * @param {String} path - * @return {Array|undefined} - */ - - function parsePath(path) { - var hit = pathCache.get(path); - if (!hit) { - hit = parse(path); - if (hit) { - pathCache.put(path, hit); - } - } - return hit; - } - - /** - * Get from an object from a path string - * - * @param {Object} obj - * @param {String} path - */ - - function getPath(obj, path) { - return parseExpression(path).get(obj); - } - - /** - * Warn against setting non-existent root path on a vm. - */ - - var warnNonExistent; - if ('development' !== 'production') { - warnNonExistent = function (path, vm) { - warn('You are setting a non-existent path "' + path.raw + '" ' + 'on a vm instance. Consider pre-initializing the property ' + 'with the "data" option for more reliable reactivity ' + 'and better performance.', vm); - }; - } - - /** - * Set on an object from a path - * - * @param {Object} obj - * @param {String | Array} path - * @param {*} val - */ - - function setPath(obj, path, val) { - var original = obj; - if (typeof path === 'string') { - path = parse(path); - } - if (!path || !isObject(obj)) { - return false; - } - var last, key; - for (var i = 0, l = path.length; i < l; i++) { - last = obj; - key = path[i]; - if (key.charAt(0) === '*') { - key = parseExpression(key.slice(1)).get.call(original, original); - } - if (i < l - 1) { - obj = obj[key]; - if (!isObject(obj)) { - obj = {}; - if ('development' !== 'production' && last._isVue) { - warnNonExistent(path, last); - } - set(last, key, obj); - } - } else { - if (isArray(obj)) { - obj.$set(key, val); - } else if (key in obj) { - obj[key] = val; - } else { - if ('development' !== 'production' && obj._isVue) { - warnNonExistent(path, obj); - } - set(obj, key, val); - } - } - } - return true; - } - -var path = Object.freeze({ - parsePath: parsePath, - getPath: getPath, - setPath: setPath - }); - - var expressionCache = new Cache(1000); - - var allowedKeywords = 'Math,Date,this,true,false,null,undefined,Infinity,NaN,' + 'isNaN,isFinite,decodeURI,decodeURIComponent,encodeURI,' + 'encodeURIComponent,parseInt,parseFloat'; - var allowedKeywordsRE = new RegExp('^(' + allowedKeywords.replace(/,/g, '\\b|') + '\\b)'); - - // keywords that don't make sense inside expressions - var improperKeywords = 'break,case,class,catch,const,continue,debugger,default,' + 'delete,do,else,export,extends,finally,for,function,if,' + 'import,in,instanceof,let,return,super,switch,throw,try,' + 'var,while,with,yield,enum,await,implements,package,' + 'protected,static,interface,private,public'; - var improperKeywordsRE = new RegExp('^(' + improperKeywords.replace(/,/g, '\\b|') + '\\b)'); - - var wsRE = /\s/g; - var newlineRE = /\n/g; - var saveRE = /[\{,]\s*[\w\$_]+\s*:|('(?:[^'\\]|\\.)*'|"(?:[^"\\]|\\.)*"|`(?:[^`\\]|\\.)*\$\{|\}(?:[^`\\]|\\.)*`|`(?:[^`\\]|\\.)*`)|new |typeof |void /g; - var restoreRE = /"(\d+)"/g; - var pathTestRE = /^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*|\['.*?'\]|\[".*?"\]|\[\d+\]|\[[A-Za-z_$][\w$]*\])*$/; - var identRE = /[^\w$\.](?:[A-Za-z_$][\w$]*)/g; - var literalValueRE$1 = /^(?:true|false|null|undefined|Infinity|NaN)$/; - - function noop() {} - - /** - * Save / Rewrite / Restore - * - * When rewriting paths found in an expression, it is - * possible for the same letter sequences to be found in - * strings and Object literal property keys. Therefore we - * remove and store these parts in a temporary array, and - * restore them after the path rewrite. - */ - - var saved = []; - - /** - * Save replacer - * - * The save regex can match two possible cases: - * 1. An opening object literal - * 2. A string - * If matched as a plain string, we need to escape its - * newlines, since the string needs to be preserved when - * generating the function body. - * - * @param {String} str - * @param {String} isString - str if matched as a string - * @return {String} - placeholder with index - */ - - function save(str, isString) { - var i = saved.length; - saved[i] = isString ? str.replace(newlineRE, '\\n') : str; - return '"' + i + '"'; - } - - /** - * Path rewrite replacer - * - * @param {String} raw - * @return {String} - */ - - function rewrite(raw) { - var c = raw.charAt(0); - var path = raw.slice(1); - if (allowedKeywordsRE.test(path)) { - return raw; - } else { - path = path.indexOf('"') > -1 ? path.replace(restoreRE, restore) : path; - return c + 'scope.' + path; - } - } - - /** - * Restore replacer - * - * @param {String} str - * @param {String} i - matched save index - * @return {String} - */ - - function restore(str, i) { - return saved[i]; - } - - /** - * Rewrite an expression, prefixing all path accessors with - * `scope.` and generate getter/setter functions. - * - * @param {String} exp - * @return {Function} - */ - - function compileGetter(exp) { - if (improperKeywordsRE.test(exp)) { - 'development' !== 'production' && warn('Avoid using reserved keywords in expression: ' + exp); - } - // reset state - saved.length = 0; - // save strings and object literal keys - var body = exp.replace(saveRE, save).replace(wsRE, ''); - // rewrite all paths - // pad 1 space here because the regex matches 1 extra char - body = (' ' + body).replace(identRE, rewrite).replace(restoreRE, restore); - return makeGetterFn(body); - } - - /** - * Build a getter function. Requires eval. - * - * We isolate the try/catch so it doesn't affect the - * optimization of the parse function when it is not called. - * - * @param {String} body - * @return {Function|undefined} - */ - - function makeGetterFn(body) { - try { - /* eslint-disable no-new-func */ - return new Function('scope', 'return ' + body + ';'); - /* eslint-enable no-new-func */ - } catch (e) { - if ('development' !== 'production') { - /* istanbul ignore if */ - if (e.toString().match(/unsafe-eval|CSP/)) { - warn('It seems you are using the default build of Vue.js in an environment ' + 'with Content Security Policy that prohibits unsafe-eval. ' + 'Use the CSP-compliant build instead: ' + 'http://vuejs.org/guide/installation.html#CSP-compliant-build'); - } else { - warn('Invalid expression. ' + 'Generated function body: ' + body); - } - } - return noop; - } - } - - /** - * Compile a setter function for the expression. - * - * @param {String} exp - * @return {Function|undefined} - */ - - function compileSetter(exp) { - var path = parsePath(exp); - if (path) { - return function (scope, val) { - setPath(scope, path, val); - }; - } else { - 'development' !== 'production' && warn('Invalid setter expression: ' + exp); - } - } - - /** - * Parse an expression into re-written getter/setters. - * - * @param {String} exp - * @param {Boolean} needSet - * @return {Function} - */ - - function parseExpression(exp, needSet) { - exp = exp.trim(); - // try cache - var hit = expressionCache.get(exp); - if (hit) { - if (needSet && !hit.set) { - hit.set = compileSetter(hit.exp); - } - return hit; - } - var res = { exp: exp }; - res.get = isSimplePath(exp) && exp.indexOf('[') < 0 - // optimized super simple getter - ? makeGetterFn('scope.' + exp) - // dynamic getter - : compileGetter(exp); - if (needSet) { - res.set = compileSetter(exp); - } - expressionCache.put(exp, res); - return res; - } - - /** - * Check if an expression is a simple path. - * - * @param {String} exp - * @return {Boolean} - */ - - function isSimplePath(exp) { - return pathTestRE.test(exp) && - // don't treat literal values as paths - !literalValueRE$1.test(exp) && - // Math constants e.g. Math.PI, Math.E etc. - exp.slice(0, 5) !== 'Math.'; - } - -var expression = Object.freeze({ - parseExpression: parseExpression, - isSimplePath: isSimplePath - }); - - // we have two separate queues: one for directive updates - // and one for user watcher registered via $watch(). - // we want to guarantee directive updates to be called - // before user watchers so that when user watchers are - // triggered, the DOM would have already been in updated - // state. - - var queue = []; - var userQueue = []; - var has = {}; - var circular = {}; - var waiting = false; - - /** - * Reset the batcher's state. - */ - - function resetBatcherState() { - queue.length = 0; - userQueue.length = 0; - has = {}; - circular = {}; - waiting = false; - } - - /** - * Flush both queues and run the watchers. - */ - - function flushBatcherQueue() { - var _again = true; - - _function: while (_again) { - _again = false; - - runBatcherQueue(queue); - runBatcherQueue(userQueue); - // user watchers triggered more watchers, - // keep flushing until it depletes - if (queue.length) { - _again = true; - continue _function; - } - // dev tool hook - /* istanbul ignore if */ - if (devtools && config.devtools) { - devtools.emit('flush'); - } - resetBatcherState(); - } - } - - /** - * Run the watchers in a single queue. - * - * @param {Array} queue - */ - - function runBatcherQueue(queue) { - // do not cache length because more watchers might be pushed - // as we run existing watchers - for (var i = 0; i < queue.length; i++) { - var watcher = queue[i]; - var id = watcher.id; - has[id] = null; - watcher.run(); - // in dev build, check and stop circular updates. - if ('development' !== 'production' && has[id] != null) { - circular[id] = (circular[id] || 0) + 1; - if (circular[id] > config._maxUpdateCount) { - warn('You may have an infinite update loop for watcher ' + 'with expression "' + watcher.expression + '"', watcher.vm); - break; - } - } - } - queue.length = 0; - } - - /** - * Push a watcher into the watcher queue. - * Jobs with duplicate IDs will be skipped unless it's - * pushed when the queue is being flushed. - * - * @param {Watcher} watcher - * properties: - * - {Number} id - * - {Function} run - */ - - function pushWatcher(watcher) { - var id = watcher.id; - if (has[id] == null) { - // push watcher into appropriate queue - var q = watcher.user ? userQueue : queue; - has[id] = q.length; - q.push(watcher); - // queue the flush - if (!waiting) { - waiting = true; - nextTick(flushBatcherQueue); - } - } - } - - var uid$2 = 0; - - /** - * A watcher parses an expression, collects dependencies, - * and fires callback when the expression value changes. - * This is used for both the $watch() api and directives. - * - * @param {Vue} vm - * @param {String|Function} expOrFn - * @param {Function} cb - * @param {Object} options - * - {Array} filters - * - {Boolean} twoWay - * - {Boolean} deep - * - {Boolean} user - * - {Boolean} sync - * - {Boolean} lazy - * - {Function} [preProcess] - * - {Function} [postProcess] - * @constructor - */ - function Watcher(vm, expOrFn, cb, options) { - // mix in options - if (options) { - extend(this, options); - } - var isFn = typeof expOrFn === 'function'; - this.vm = vm; - vm._watchers.push(this); - this.expression = expOrFn; - this.cb = cb; - this.id = ++uid$2; // uid for batching - this.active = true; - this.dirty = this.lazy; // for lazy watchers - this.deps = []; - this.newDeps = []; - this.depIds = new _Set(); - this.newDepIds = new _Set(); - this.prevError = null; // for async error stacks - // parse expression for getter/setter - if (isFn) { - this.getter = expOrFn; - this.setter = undefined; - } else { - var res = parseExpression(expOrFn, this.twoWay); - this.getter = res.get; - this.setter = res.set; - } - this.value = this.lazy ? undefined : this.get(); - // state for avoiding false triggers for deep and Array - // watchers during vm._digest() - this.queued = this.shallow = false; - } - - /** - * Evaluate the getter, and re-collect dependencies. - */ - - Watcher.prototype.get = function () { - this.beforeGet(); - var scope = this.scope || this.vm; - var value; - try { - value = this.getter.call(scope, scope); - } catch (e) { - if ('development' !== 'production' && config.warnExpressionErrors) { - warn('Error when evaluating expression ' + '"' + this.expression + '": ' + e.toString(), this.vm); - } - } - // "touch" every property so they are all tracked as - // dependencies for deep watching - if (this.deep) { - traverse(value); - } - if (this.preProcess) { - value = this.preProcess(value); - } - if (this.filters) { - value = scope._applyFilters(value, null, this.filters, false); - } - if (this.postProcess) { - value = this.postProcess(value); - } - this.afterGet(); - return value; - }; - - /** - * Set the corresponding value with the setter. - * - * @param {*} value - */ - - Watcher.prototype.set = function (value) { - var scope = this.scope || this.vm; - if (this.filters) { - value = scope._applyFilters(value, this.value, this.filters, true); - } - try { - this.setter.call(scope, scope, value); - } catch (e) { - if ('development' !== 'production' && config.warnExpressionErrors) { - warn('Error when evaluating setter ' + '"' + this.expression + '": ' + e.toString(), this.vm); - } - } - // two-way sync for v-for alias - var forContext = scope.$forContext; - if (forContext && forContext.alias === this.expression) { - if (forContext.filters) { - 'development' !== 'production' && warn('It seems you are using two-way binding on ' + 'a v-for alias (' + this.expression + '), and the ' + 'v-for has filters. This will not work properly. ' + 'Either remove the filters or use an array of ' + 'objects and bind to object properties instead.', this.vm); - return; - } - forContext._withLock(function () { - if (scope.$key) { - // original is an object - forContext.rawValue[scope.$key] = value; - } else { - forContext.rawValue.$set(scope.$index, value); - } - }); - } - }; - - /** - * Prepare for dependency collection. - */ - - Watcher.prototype.beforeGet = function () { - Dep.target = this; - }; - - /** - * Add a dependency to this directive. - * - * @param {Dep} dep - */ - - Watcher.prototype.addDep = function (dep) { - var id = dep.id; - if (!this.newDepIds.has(id)) { - this.newDepIds.add(id); - this.newDeps.push(dep); - if (!this.depIds.has(id)) { - dep.addSub(this); - } - } - }; - - /** - * Clean up for dependency collection. - */ - - Watcher.prototype.afterGet = function () { - Dep.target = null; - var i = this.deps.length; - while (i--) { - var dep = this.deps[i]; - if (!this.newDepIds.has(dep.id)) { - dep.removeSub(this); - } - } - var tmp = this.depIds; - this.depIds = this.newDepIds; - this.newDepIds = tmp; - this.newDepIds.clear(); - tmp = this.deps; - this.deps = this.newDeps; - this.newDeps = tmp; - this.newDeps.length = 0; - }; - - /** - * Subscriber interface. - * Will be called when a dependency changes. - * - * @param {Boolean} shallow - */ - - Watcher.prototype.update = function (shallow) { - if (this.lazy) { - this.dirty = true; - } else if (this.sync || !config.async) { - this.run(); - } else { - // if queued, only overwrite shallow with non-shallow, - // but not the other way around. - this.shallow = this.queued ? shallow ? this.shallow : false : !!shallow; - this.queued = true; - // record before-push error stack in debug mode - /* istanbul ignore if */ - if ('development' !== 'production' && config.debug) { - this.prevError = new Error('[vue] async stack trace'); - } - pushWatcher(this); - } - }; - - /** - * Batcher job interface. - * Will be called by the batcher. - */ - - Watcher.prototype.run = function () { - if (this.active) { - var value = this.get(); - if (value !== this.value || - // Deep watchers and watchers on Object/Arrays should fire even - // when the value is the same, because the value may - // have mutated; but only do so if this is a - // non-shallow update (caused by a vm digest). - (isObject(value) || this.deep) && !this.shallow) { - // set new value - var oldValue = this.value; - this.value = value; - // in debug + async mode, when a watcher callbacks - // throws, we also throw the saved before-push error - // so the full cross-tick stack trace is available. - var prevError = this.prevError; - /* istanbul ignore if */ - if ('development' !== 'production' && config.debug && prevError) { - this.prevError = null; - try { - this.cb.call(this.vm, value, oldValue); - } catch (e) { - nextTick(function () { - throw prevError; - }, 0); - throw e; - } - } else { - this.cb.call(this.vm, value, oldValue); - } - } - this.queued = this.shallow = false; - } - }; - - /** - * Evaluate the value of the watcher. - * This only gets called for lazy watchers. - */ - - Watcher.prototype.evaluate = function () { - // avoid overwriting another watcher that is being - // collected. - var current = Dep.target; - this.value = this.get(); - this.dirty = false; - Dep.target = current; - }; - - /** - * Depend on all deps collected by this watcher. - */ - - Watcher.prototype.depend = function () { - var i = this.deps.length; - while (i--) { - this.deps[i].depend(); - } - }; - - /** - * Remove self from all dependencies' subcriber list. - */ - - Watcher.prototype.teardown = function () { - if (this.active) { - // remove self from vm's watcher list - // this is a somewhat expensive operation so we skip it - // if the vm is being destroyed or is performing a v-for - // re-render (the watcher list is then filtered by v-for). - if (!this.vm._isBeingDestroyed && !this.vm._vForRemoving) { - this.vm._watchers.$remove(this); - } - var i = this.deps.length; - while (i--) { - this.deps[i].removeSub(this); - } - this.active = false; - this.vm = this.cb = this.value = null; - } - }; - - /** - * Recrusively traverse an object to evoke all converted - * getters, so that every nested property inside the object - * is collected as a "deep" dependency. - * - * @param {*} val - */ - - var seenObjects = new _Set(); - function traverse(val, seen) { - var i = undefined, - keys = undefined; - if (!seen) { - seen = seenObjects; - seen.clear(); - } - var isA = isArray(val); - var isO = isObject(val); - if ((isA || isO) && Object.isExtensible(val)) { - if (val.__ob__) { - var depId = val.__ob__.dep.id; - if (seen.has(depId)) { - return; - } else { - seen.add(depId); - } - } - if (isA) { - i = val.length; - while (i--) traverse(val[i], seen); - } else if (isO) { - keys = Object.keys(val); - i = keys.length; - while (i--) traverse(val[keys[i]], seen); - } - } - } - - var text$1 = { - - bind: function bind() { - this.attr = this.el.nodeType === 3 ? 'data' : 'textContent'; - }, - - update: function update(value) { - this.el[this.attr] = _toString(value); - } - }; - - var templateCache = new Cache(1000); - var idSelectorCache = new Cache(1000); - - var map = { - efault: [0, '', ''], - legend: [1, '
', '
'], - tr: [2, '', '
'], - col: [2, '', '
'] - }; - - map.td = map.th = [3, '', '
']; - - map.option = map.optgroup = [1, '']; - - map.thead = map.tbody = map.colgroup = map.caption = map.tfoot = [1, '', '
']; - - map.g = map.defs = map.symbol = map.use = map.image = map.text = map.circle = map.ellipse = map.line = map.path = map.polygon = map.polyline = map.rect = [1, '', '']; - - /** - * Check if a node is a supported template node with a - * DocumentFragment content. - * - * @param {Node} node - * @return {Boolean} - */ - - function isRealTemplate(node) { - return isTemplate(node) && isFragment(node.content); - } - - var tagRE$1 = /<([\w:-]+)/; - var entityRE = /&#?\w+?;/; - var commentRE = /