From 138f82f4bbcd256269ca7b594a1f1c62e07856ac Mon Sep 17 00:00:00 2001 From: Nero Ignis Date: Tue, 24 Aug 2021 22:43:24 +0200 Subject: [PATCH] first commit --- css/app.css | 130 + img/favicon.ico | Bin 0 -> 3638 bytes img/google.webp | Bin 0 -> 9834 bytes img/logo.png | Bin 0 -> 3238 bytes img/redmine.png | Bin 0 -> 18564 bytes img/search.png | Bin 0 -> 8276 bytes img/stackoverflow.png | Bin 0 -> 3445 bytes index.html | 372 ++ js/app.js | 284 + js/vue.js | 11965 ++++++++++++++++++++++++++++++++++++++++ 10 files changed, 12751 insertions(+) create mode 100644 css/app.css create mode 100644 img/favicon.ico create mode 100644 img/google.webp create mode 100644 img/logo.png create mode 100644 img/redmine.png create mode 100644 img/search.png create mode 100644 img/stackoverflow.png create mode 100644 index.html create mode 100644 js/app.js create mode 100644 js/vue.js diff --git a/css/app.css b/css/app.css new file mode 100644 index 0000000..07c44e7 --- /dev/null +++ b/css/app.css @@ -0,0 +1,130 @@ +body { + background-color: #e7e7e7; + overflow-y: auto; +} + +.container { + margin: 20px auto 20px auto; +} + +.add-button { + padding: 1px 5px 1px 5px; +} + +.ticket-action-button { + margin-top: 10px; + padding: 1px 5px 1px 5px; + width: 100%; +} + +.delete-ticket-button { + margin-top: 10px; + margin-bottom: 15px; + padding: 1px 5px 1px 5px; + width: 100%; +} + +.side-button-right { + position: absolute; + right: 30px; + + height: 60px; + width: 60px; + + font-size: 1.7em; +} + +.add-tracker-button { + position: absolute; + left: 30px; + bottom: 30px; + + height: 60px; + width: 60px; + + font-size: 1.7em; +} + +.first-button { + bottom: 30px; +} + +.second-button { + bottom: 110px; + padding-left: 16px; +} + +.third-button { + bottom: 190px; + padding-left: 16px; +} + +.fourth-button { + bottom: 270px; + padding-left: 16px; +} + +.navbar-brand { + width: 100%; +} + +.logo-nav { + max-height: 35px; + margin: 5px; +} + +nav { + border-radius: 45px; +} + +nav, .card { + margin-bottom: 20px; +} + +.modal-content { + max-width: 1000px; +} + +.btn-full-width { + width: 100%; +} + +.timeTracking { + height: 635px; + overflow-y: scroll; + margin-bottom: 0; + padding-bottom: 0; +} + +.ticket-history { + list-style: none; + padding-left: 0; +} + +.trackingNameField { + max-height: 1em; + margin-bottom: 1px; +} + +#showTrackedTicketsModal .showTrackedTicketsModalDialog, +#showArchivedTicketsModal .showArchivedTicketsModalDialog{ + max-width: 900px; +} + +.btn { + text-transform: initial !important; +} + +.ticket-time-info { + margin-top: 1em; + clear: both; +} + +.brand-title { + margin-left: 2em; + margin-top: 0.5em; +} + +#settingsModal .form-group { + margin-bottom: 0.5em; +} \ No newline at end of file diff --git a/img/favicon.ico b/img/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..4b03e6e0764193b1b9c98a5399dc59bdc4c8ca8d GIT binary patch literal 3638 zcmeHJJ8#oa7(LFbdDVF}sS}dajT74`NhuEjV_AU-Iw4>{6{=Ve69}m&5<9;G38aEh z2Yx^jhaeCbNT}3@m>_fkb?HL*Y_J{SC{!RoLO#-UzVm(eyS_fYJ_^9Vg=iEymb`#S z5zl|)cm2Q}%E?5vDO#EVB?j^mwGY&@ zVY{!Ba1?M9_{R#Qxk1Dc41`k#A^{G;gm2t{Kf;0YvW$VKmv|~^P-Y^fakt4ce}a2M z=K5oF|6t7HHsA{r4@?@{PbFyouEEFS(m$$Qqr|TcvQ6D*d0JzhhT*d{50N3ze0Jfq zs{1UTY(RangR4txI4r%x(MlVa&UK*FKVkp0g1ORb?CySnm~GR0IW8p@qc@ z9Tdp7<$RO)6Po{u=Dwkx%^^E?QjP+S0>7iczM1R@$T5_q5txt>7DhnI?yWxMu_2)? z`@KKpFWTTrT6H#JTCW+5r$n=#&6sH`h_Y5aZl%pA;M5KM+5cT1uld%kVA6X3qAzHJ xI~_95kH95tDDl?$6ohFz2F|w@4#m&EpTbyp1oFAPctedQ{q3Rci~e`?zXB<((a!(? literal 0 HcmV?d00001 diff --git a/img/google.webp b/img/google.webp new file mode 100644 index 0000000000000000000000000000000000000000..1ca2abf0cdabcc36817c31f951b1640039b11407 GIT binary patch literal 9834 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 literal 0 HcmV?d00001 diff --git a/img/logo.png b/img/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..53ccbd4deb696859cbe7821f2e45cbcf42127da7 GIT binary patch literal 3238 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 literal 0 HcmV?d00001 diff --git a/img/redmine.png b/img/redmine.png new file mode 100644 index 0000000000000000000000000000000000000000..330931fd292124ab5d11c37d542713801179effb GIT binary patch literal 18564 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

r{n*`1K52-n^E=e(? zxBjBN#*WBfU-zvQWS#aqH}cpN3vmDm z&%DS&gSPAvHwIOGT@Y4Sv^79I-awnhc=!KJ+r!>ayW_=p9T7f=?2V=q(K<>q*R)jO zHn-8C=QDNV?Qgq@#uQp`s{F~?`%Dxn8#Qy+6*86Do&cFGhJ#sUMlwE!h=Bm$i3s@= zJHH?+gBhG=0eW^_&feiu`7mrlBjicels@62k^Bf76KZ~;+J&e8P3`TC?YS98V@w!G zs;Mz{W;boKz&9>xa;zD-J?iW-IJ4%LxKDN01!Y%p^19g^ZajYO-lrLHG*`-XrFRVA~IOAEp-nU zhh5^leUX_WtB0@oX`x$vv03 zHj4wqcO;lCbF0GJL5w7%=xD$NsvUfsgz7`aMQmXm)+}vJqPW*dOZ>>>Az#6Ec;Vsn zX=vMUZGj4<`JEJ^bIx~3M$A*9kqp+qWsB1wZ_uZu`>>7xryyeAonf>OGg=LvPJ*)Z zx$4-uq`siM!52$k<<;p)rL%T=lG1(Gm+Y1I&lMV-*cXU;A_`+2#35dA;f7g`A9!Dg zS+rEC5gq48MncnHaGf(zR6?)_Mv8VmK8jTYt5-v(2Ry67R+pOKY^$Mi(m7o`%t) zH>ns9lIK@tzdrO-S8=?owdCANUOenJEw4QOY;AZCh5rnXWwPDvopJ=NuoqW9eUjFt z4Z^>ys5@3HkpEJFKkEtupFa)#%ovOGhE~4AW^jI57LM_>sP7TbBuDx$R}SLJJZ>qZ zFnmhatyp{i!9<$t{TvZs;3q;R!OHh`!oGQ{?M=7cMM#&-vmke;isnK?_j@ z9=l`gkjh%~bbT-rSGR}{!;g3uc2E`O4I<>B`bdJDEZskSgvhNsL*K2Kv&dY`7N?#y z;j5l~c=E9U3R>t+D|WCX3CO_~8u4n-`)|tQNvv=u%w9HKE=dqM{+;1lhCT(as-WwE78pJ`~;k}7pIUjv^rUvCs&Y=TA%z1@9mMH2;#zK%?YwJ|j= z;3KHgayCvDL;3sm4Zy?Lv-AUeIus3;n5OcoVp9=EoJjDy=Z|^2{)0;J)(XTm<-c^N zM-NafOcw;KMYRr!(w(%lh@{7RHCGQw|2X2?>haWDuP=y1F50;~n0uN%@GKRXL?PfI z$AzNl069;dv%0Uij$nd#vGA@)9@~2$7CqW>!u^Cba}@aqm~)!kCgt8%%Y;TMFwT?H z9W;i%4=p2-QG=EeNTvVLp7`2%DWF5L(lV8iK4 zWdahZ@y}x=I~AH84#IV+4!&CVknWbt!cF9Bg_(loiDHCHC#WFPzxmjSrR!ZAkkjb0 zhX(7WeDLK(?Jwj0S5 z2kfIj@l%sRWsACz2*ZZ=s@#RMS9|erW!TybDP&J}ufCUG}D)R&HKum`bD(tC>UMLqpw0}~jV)^P)-1&MAMXm@O ziif0_Zs|_1qqjyt%`IR=riYkGa;{|6Q`q1pc`+Bq>lXoM@cgCcpv07(5wq>Ta4n8Y=10Iaj7hk2A-p0hALiqB zBm09i?r!kDh72(%%&0fUnX08SJDGZhQ?jx@aB&|JLwsE$eJPy zg$YKprkGW{(WWZjCnOs}c1x~M0yKqE!&?pZ{5xsXm)W`Kw-S>&pi$SJXenQ(318sDJw}=X^CDQIV@CFuhWk z9l|yeAWVPQz?vJ9onJ@apuq1`Q_!)=sv5Ls%^gKd}~i@M0U<# z><<07P}hCl7C9B;&>6}70}XFFXt>zseC zLUYUE#;7O3KlgG@i>&*3V7umLQJ?*9iiKRP%3jqn3L<~>3LSve7(PYZs8Hm{=;_f zB{c)jZQkdzq1IjCXRxQy+90I|QaL<}z8my>5^0#Xc6I#HBwMMCk8V87cWV9bW2Njk zQ=41)V+@CALG0}w)^>p%Esl~sr+!!g``vfAZf%@-Ex;n+leL1@r(mDLiaiS!{5tk` z-ha2anmMjNrg-m?i7X1;mmqrZ$McI{gfl<(7W2M&?c`(n=hJjK3&9stJWqXXUAbmC zAKxv($W0Da7vt_{`=`ul%QO=H^N@%4dzj45FPVFyAM#zEu2VJT=Pdn~Gd?ONOkb9< z>r!g2VRYuE?IDwZ>kri@7QFa=*vIsK>sH?Gy9-_VGBTGOZk#v!aSC!c=t>%2=+9^T;Ct{3-# z!TX?I(#%^wnu~I#obs9o+|g2@ro<=vxFm*s=iGk(&#GHP1a;RM7CBw#;7|3KacF&@ z+1y)ox2CSS(s6q63)7%aj1P++h<+j(*m7WOYcx%f|;=%p`Ag;)F{D-1Sr zE#7`y>X$&pu``^P*FIhqqSSuieDj-aE3dxVvE$~E%ZzpXk3auo)%mHa^yjWat+D$(#ZPG8>yRr1Z4m)8FqxYPD9_)TPb-|~V-@ojsGT!>kGTMLXryJoq?lFz6 zJm#xs#7vtAo;Yc9C4avY<@vx{?faPZLO-Qu!Fp3MV`2W9{>DvY`u{~wLV}%$zUHx3vIVCg! E0QIq}ng9R* literal 0 HcmV?d00001 diff --git a/img/search.png b/img/search.png new file mode 100644 index 0000000000000000000000000000000000000000..fb116117bafbfcc9db5c0c17b6057079a4031c64 GIT binary patch literal 8276 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 PkC45!lhu6-kGTH;mfIZT literal 0 HcmV?d00001 diff --git a/index.html b/index.html new file mode 100644 index 0000000..f8b61fc --- /dev/null +++ b/index.html @@ -0,0 +1,372 @@ + + + + + + + vDash + + + + +

+ + + +
+
+
+
+
+
+
+ + +
+
+
+
+ Tracking... +
+ Tracking +
+
+
+ +
+ {{ getTrackingStartTime(ticket) }} + Gestartet: +
+ {{ currentTrackingRunningFor(ticket) }} + Läuft seit: +
+ +
+ {{ getTotalTime(ticket) }} + Gesamt: +
+ + {{ getTotalTimeToday(ticket) }} + Heute: + +
+
+ +
+ +
+ +
+
+
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + \ No newline at end of file diff --git a/js/app.js b/js/app.js new file mode 100644 index 0000000..31a81a0 --- /dev/null +++ b/js/app.js @@ -0,0 +1,284 @@ +let tab = new Vue({ + el: '#root', + data: { + theme: 'quartz', + themes: null, + dashboardLogo: 'img/logo.png', + ticketSystemUrl: '', + showPT: true, + linkTarget: '_blank', + inputs: { + importJson: '' + }, + trackedTickets: [], + selectedTicket: null + }, + mounted() { + let vue = this; + + this.loadStorage(); + this.fetchThemes(); + moment.locale('de'); + + setInterval(() => { + vue.$forceUpdate(); + }, 1000 * 60) + }, + methods: { + loadStorage() { + let storedTrackedTickets = JSON.parse(localStorage.getItem('trackedTickets')); + this.trackedTickets = storedTrackedTickets == null ? [] : storedTrackedTickets; + + let storedticketSystemUrl = localStorage.getItem('ticketSystemUrl'); + this.ticketSystemUrl = storedticketSystemUrl == null ? '' : storedticketSystemUrl; + + let storedShowPT = localStorage.getItem('showPT'); + this.showPT = storedShowPT == null ? true : storedShowPT; + + let storedTheme = localStorage.getItem('theme'); + this.theme = storedTheme == null ? 'materia' : storedTheme; + }, + updateStorage() { + localStorage.setItem('trackedTickets', JSON.stringify(this.trackedTickets)); + localStorage.setItem('ticketSystemUrl', this.ticketSystemUrl); + localStorage.setItem('showPT', this.showPT); + localStorage.setItem('theme', this.theme); + }, + resetToDefault() { + this.updateStorage(); + }, + addTrackedTicket() { + let newTicket = { + archived: false, + tracking: false, + number: '#', + trackingStarted: null, + trackingStopped: null, + history: [] + }; + + this.trackedTickets.push(newTicket); + this.updateStorage(); + }, + startTracking(ticket) { + this.stopTrackingTicket(); + ticket.trackingStarted = moment(); + ticket.tracking = true; + + this.$forceUpdate(); + this.updateStorage(); + }, + stopTracking(ticket) { + ticket.trackingStopped = moment(); + ticket.tracking = false; + + let minutesSpent = moment.duration( + ticket.trackingStopped.diff(ticket.trackingStarted) + ).as('minutes'); + + + ticket.history.push({ + trackingStarted: ticket.trackingStarted, + trackingStopped: ticket.trackingStopped, + manually: false, + minutes: Math.round(minutesSpent) + }); + + ticket.trackingStarted = null; + ticket.trackingStopped = null; + + this.$forceUpdate(); + this.updateStorage(); + }, + formattedDate(date) { + return moment(date).format('llll'); + }, + exactTimestamp(date) { + return moment(date).format('LTS'); + }, + currentTrackingRunningFor(ticket) { + return this.timeWithPostFix(Math.round(moment.duration(moment().diff(ticket.trackingStarted)).as('minutes'))); + }, + getTotalTime(ticket) { + let totalTime = 0; + + if (ticket.history.length > 0) { + ticket.history.forEach(function (historyEntry) { + totalTime += Math.round(historyEntry.minutes); + }); + } + + if (ticket.tracking) { + totalTime += Math.round(moment.duration(moment().diff(ticket.trackingStarted)).as('minutes')); + } + + return this.timeWithPostFix(totalTime); + }, + getTotalTimeToday(ticket) { + let totalTime = 0; + + if (ticket.history.length > 0) { + ticket.history.forEach(function (historyEntry) { + if (moment(historyEntry.trackingStarted).format("MMM Do YY") === moment().format("MMM Do YY")) { + totalTime += Math.round(historyEntry.minutes); + } + }); + } + + if (ticket.tracking) { + totalTime += Math.round(moment.duration(moment().diff(ticket.trackingStarted)).as('minutes')); + } + + return this.timeWithPostFix(totalTime); + }, + timeWithPostFix(time) { + let postFix = ' Minute'; + + if (time >= 480 && this.showPT) { + postFix = ' PT'; + time = (time / 480).toFixed(1); + } else if (time >= 60) { + postFix = ' Stunde'; + time = (time / 60).toFixed(2); + } + + let plural = ''; + + if ((time > 1 || time <= 0) && postFix !== ' PT') { + plural = 'n' + } + + return time + postFix + plural; + }, + stopTrackingTicket() { + let vue = this; + + vue.trackedTickets.forEach(function (ticket) { + if (ticket.tracking === true) { + vue.stopTracking(ticket); + } + }) + }, + getTrackingStartTime(ticket) { + return moment(ticket.trackingStarted).format('LT'); + }, + isTicketNumber(number) { + return number.indexOf('#') >= 0; + }, + deleteTicket(index) { + this.trackedTickets.splice(index, 1); + this.updateStorage(); + }, + archiveTicket(ticket) { + ticket.archived = true; + if (ticket.tracking) { + this.stopTrackingTicket(); + } + this.updateStorage(); + this.$forceUpdate(); + }, + reactivateTicket(ticket) { + ticket.archived = false; + this.updateStorage(); + }, + deleteHistoryEntry(ticketIndex, historyIndex) { + if (ticketIndex) { + this.trackedTickets[ticketIndex].history.splice(historyIndex, 1); + } else { + this.selectedTicket.history.splice(historyIndex, 1); + } + this.updateStorage(); + }, + bookTimeManually(ticket, minutes) { + ticket.history.push({ + trackingStarted: moment(), + trackingStopped: moment(), + manually: true, + minutes: Math.round(minutes) + }); + + this.updateStorage(); + }, + importData() { + let json = JSON.parse(this.inputs.importJson); + + this.trackedTickets = json.trackedTickets; + this.ticketSystemUrl = json.ticketSystemUrl; + this.showPT = json.showPT; + this.theme = json.theme; + this.updateStorage(); + location.reload(); + }, + copy2Clipboard() { + let copyText = document.getElementById("exportJsonInput"); + + copyText.select(); + copyText.setSelectionRange(0, 99999); + + document.execCommand("copy"); + + alert('Text kopiert!'); + }, + fetchThemes() { + let vue = this; + + axios.get( + 'https://bootswatch.com/api/5.json' + ).then((response) => { + vue.themes = response.data.themes; + }).catch((error) => { + console.log(error); + }); + }, + showHistoryForTicket(ticket) { + this.selectedTicket = ticket; + this.$forceUpdate(); + setTimeout(() => { + let historyModal = new bootstrap.Modal(document.getElementById('historyModal')); + historyModal.toggle(); + }, 50) + } + }, + watch: { + showPT() { + this.updateStorage(); + this.$forceUpdate(); + }, + theme() { + this.updateStorage(); + this.$forceUpdate(); + } + }, + computed: { + exportJson() { + return JSON.stringify({ + trackedTickets: this.trackedTickets, + ticketSystemUrl: this.ticketSystemUrl, + showPT: this.showPT, + theme: this.theme + }); + }, + archivedTrackers() { + let vue = this; + let count = 0; + + this.trackedTickets.forEach((ticket) => { + count += (ticket.archived ? 1 : 0); + }) + + return count; + }, + activeTrackers() { + let vue = this; + let count = 0; + + this.trackedTickets.forEach((ticket) => { + count += (ticket.archived ? 0 : 1); + }) + + return count; + } + }, + created() { + } +}); diff --git a/js/vue.js b/js/vue.js new file mode 100644 index 0000000..e22cf13 --- /dev/null +++ b/js/vue.js @@ -0,0 +1,11965 @@ +/*! + * Vue.js v2.6.11 + * (c) 2014-2019 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 = global || self, global.Vue = factory()); +}(this, function () { 'use strict'; + + /* */ + + var emptyObject = Object.freeze({}); + + // These helpers produce better VM code in JS engines due to their + // explicitness and function inlining. + function isUndef (v) { + return v === undefined || v === null + } + + function isDef (v) { + return v !== undefined && v !== null + } + + function isTrue (v) { + return v === true + } + + function isFalse (v) { + return v === false + } + + /** + * Check if value is primitive. + */ + function isPrimitive (value) { + return ( + typeof value === 'string' || + typeof value === 'number' || + // $flow-disable-line + typeof value === 'symbol' || + typeof value === 'boolean' + ) + } + + /** + * Quick object check - this is primarily used to tell + * Objects from primitive values when we know the value + * is a JSON-compliant type. + */ + function isObject (obj) { + return obj !== null && typeof obj === 'object' + } + + /** + * Get the raw type string of a value, e.g., [object Object]. + */ + var _toString = Object.prototype.toString; + + function toRawType (value) { + return _toString.call(value).slice(8, -1) + } + + /** + * Strict object type check. Only returns true + * for plain JavaScript objects. + */ + function isPlainObject (obj) { + return _toString.call(obj) === '[object Object]' + } + + function isRegExp (v) { + return _toString.call(v) === '[object RegExp]' + } + + /** + * Check if val is a valid array index. + */ + function isValidArrayIndex (val) { + var n = parseFloat(String(val)); + return n >= 0 && Math.floor(n) === n && isFinite(val) + } + + function isPromise (val) { + return ( + isDef(val) && + typeof val.then === 'function' && + typeof val.catch === 'function' + ) + } + + /** + * Convert a value to a string that is actually rendered. + */ + function toString (val) { + return val == null + ? '' + : Array.isArray(val) || (isPlainObject(val) && val.toString === _toString) + ? JSON.stringify(val, null, 2) + : String(val) + } + + /** + * Convert an input value to a number for persistence. + * If the conversion fails, return original string. + */ + function toNumber (val) { + var n = parseFloat(val); + return isNaN(n) ? val : n + } + + /** + * Make a map and return a function for checking if a key + * is in that map. + */ + function makeMap ( + str, + expectsLowerCase + ) { + var map = Object.create(null); + var list = str.split(','); + for (var i = 0; i < list.length; i++) { + map[list[i]] = true; + } + return expectsLowerCase + ? function (val) { return map[val.toLowerCase()]; } + : function (val) { return map[val]; } + } + + /** + * Check if a tag is a built-in tag. + */ + var isBuiltInTag = makeMap('slot,component', true); + + /** + * Check if an attribute is a reserved attribute. + */ + var isReservedAttribute = makeMap('key,ref,slot,slot-scope,is'); + + /** + * Remove an item from an array. + */ + function remove (arr, item) { + if (arr.length) { + var index = arr.indexOf(item); + if (index > -1) { + return arr.splice(index, 1) + } + } + } + + /** + * Check whether an object has the property. + */ + var hasOwnProperty = Object.prototype.hasOwnProperty; + function hasOwn (obj, key) { + return hasOwnProperty.call(obj, key) + } + + /** + * Create a cached version of a pure function. + */ + function cached (fn) { + var cache = Object.create(null); + return (function cachedFn (str) { + var hit = cache[str]; + return hit || (cache[str] = fn(str)) + }) + } + + /** + * Camelize a hyphen-delimited string. + */ + var camelizeRE = /-(\w)/g; + var camelize = cached(function (str) { + return str.replace(camelizeRE, function (_, c) { return c ? c.toUpperCase() : ''; }) + }); + + /** + * Capitalize a string. + */ + var capitalize = cached(function (str) { + return str.charAt(0).toUpperCase() + str.slice(1) + }); + + /** + * Hyphenate a camelCase string. + */ + var hyphenateRE = /\B([A-Z])/g; + var hyphenate = cached(function (str) { + return str.replace(hyphenateRE, '-$1').toLowerCase() + }); + + /** + * Simple bind polyfill for environments that do not support it, + * e.g., PhantomJS 1.x. Technically, we don't need this anymore + * since native bind is now performant enough in most browsers. + * But removing it would mean breaking code that was able to run in + * PhantomJS 1.x, so this must be kept for backward compatibility. + */ + + /* istanbul ignore next */ + function polyfillBind (fn, ctx) { + function boundFn (a) { + var l = arguments.length; + return l + ? l > 1 + ? fn.apply(ctx, arguments) + : fn.call(ctx, a) + : fn.call(ctx) + } + + boundFn._length = fn.length; + return boundFn + } + + function nativeBind (fn, ctx) { + return fn.bind(ctx) + } + + var bind = Function.prototype.bind + ? nativeBind + : polyfillBind; + + /** + * Convert an Array-like object to a real 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. + */ + function extend (to, _from) { + for (var key in _from) { + to[key] = _from[key]; + } + return to + } + + /** + * Merge an Array of Objects into a single Object. + */ + function toObject (arr) { + var res = {}; + for (var i = 0; i < arr.length; i++) { + if (arr[i]) { + extend(res, arr[i]); + } + } + return res + } + + /* eslint-disable no-unused-vars */ + + /** + * Perform no operation. + * Stubbing args to make Flow happy without leaving useless transpiled code + * with ...rest (https://flow.org/blog/2017/05/07/Strict-Function-Call-Arity/). + */ + function noop (a, b, c) {} + + /** + * Always return false. + */ + var no = function (a, b, c) { return false; }; + + /* eslint-enable no-unused-vars */ + + /** + * Return the same value. + */ + var identity = function (_) { return _; }; + + /** + * Generate a string containing static keys from compiler modules. + */ + function genStaticKeys (modules) { + return modules.reduce(function (keys, m) { + return keys.concat(m.staticKeys || []) + }, []).join(',') + } + + /** + * Check if two values are loosely equal - that is, + * if they are plain objects, do they have the same shape? + */ + function looseEqual (a, b) { + if (a === b) { return true } + var isObjectA = isObject(a); + var isObjectB = isObject(b); + if (isObjectA && isObjectB) { + try { + var isArrayA = Array.isArray(a); + var isArrayB = Array.isArray(b); + if (isArrayA && isArrayB) { + return a.length === b.length && a.every(function (e, i) { + return looseEqual(e, b[i]) + }) + } else if (a instanceof Date && b instanceof Date) { + return a.getTime() === b.getTime() + } else if (!isArrayA && !isArrayB) { + var keysA = Object.keys(a); + var keysB = Object.keys(b); + return keysA.length === keysB.length && keysA.every(function (key) { + return looseEqual(a[key], b[key]) + }) + } else { + /* istanbul ignore next */ + return false + } + } catch (e) { + /* istanbul ignore next */ + return false + } + } else if (!isObjectA && !isObjectB) { + return String(a) === String(b) + } else { + return false + } + } + + /** + * Return the first index at which a loosely equal value can be + * found in the array (if value is a plain object, the array must + * contain an object of the same shape), or -1 if it is not present. + */ + function looseIndexOf (arr, val) { + for (var i = 0; i < arr.length; i++) { + if (looseEqual(arr[i], val)) { return i } + } + return -1 + } + + /** + * Ensure a function is called only once. + */ + function once (fn) { + var called = false; + return function () { + if (!called) { + called = true; + fn.apply(this, arguments); + } + } + } + + var SSR_ATTR = 'data-server-rendered'; + + var ASSET_TYPES = [ + 'component', + 'directive', + 'filter' + ]; + + var LIFECYCLE_HOOKS = [ + 'beforeCreate', + 'created', + 'beforeMount', + 'mounted', + 'beforeUpdate', + 'updated', + 'beforeDestroy', + 'destroyed', + 'activated', + 'deactivated', + 'errorCaptured', + 'serverPrefetch' + ]; + + /* */ + + + + var config = ({ + /** + * Option merge strategies (used in core/util/options) + */ + // $flow-disable-line + optionMergeStrategies: Object.create(null), + + /** + * Whether to suppress warnings. + */ + silent: false, + + /** + * Show production mode tip message on boot? + */ + productionTip: "development" !== 'production', + + /** + * Whether to enable devtools + */ + devtools: "development" !== 'production', + + /** + * Whether to record perf + */ + performance: false, + + /** + * Error handler for watcher errors + */ + errorHandler: null, + + /** + * Warn handler for watcher warns + */ + warnHandler: null, + + /** + * Ignore certain custom elements + */ + ignoredElements: [], + + /** + * Custom user key aliases for v-on + */ + // $flow-disable-line + keyCodes: Object.create(null), + + /** + * Check if a tag is reserved so that it cannot be registered as a + * component. This is platform-dependent and may be overwritten. + */ + isReservedTag: no, + + /** + * Check if an attribute is reserved so that it cannot be used as a component + * prop. This is platform-dependent and may be overwritten. + */ + isReservedAttr: no, + + /** + * Check if a tag is an unknown element. + * Platform-dependent. + */ + isUnknownElement: no, + + /** + * Get the namespace of an element + */ + getTagNamespace: noop, + + /** + * Parse the real tag name for the specific platform. + */ + parsePlatformTagName: identity, + + /** + * Check if an attribute must be bound using property, e.g. value + * Platform-dependent. + */ + mustUseProp: no, + + /** + * Perform updates asynchronously. Intended to be used by Vue Test Utils + * This will significantly reduce performance if set to false. + */ + async: true, + + /** + * Exposed for legacy reasons + */ + _lifecycleHooks: LIFECYCLE_HOOKS + }); + + /* */ + + /** + * unicode letters used for parsing html tags, component names and property paths. + * using https://www.w3.org/TR/html53/semantics-scripting.html#potentialcustomelementname + * skipping \u10000-\uEFFFF due to it freezing up PhantomJS + */ + var unicodeRegExp = /a-zA-Z\u00B7\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u037D\u037F-\u1FFF\u200C-\u200D\u203F-\u2040\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD/; + + /** + * Check if a string starts with $ or _ + */ + function isReserved (str) { + var c = (str + '').charCodeAt(0); + return c === 0x24 || c === 0x5F + } + + /** + * Define a property. + */ + function def (obj, key, val, enumerable) { + Object.defineProperty(obj, key, { + value: val, + enumerable: !!enumerable, + writable: true, + configurable: true + }); + } + + /** + * Parse simple path. + */ + var bailRE = new RegExp(("[^" + (unicodeRegExp.source) + ".$_\\d]")); + function parsePath (path) { + if (bailRE.test(path)) { + return + } + var segments = path.split('.'); + return function (obj) { + for (var i = 0; i < segments.length; i++) { + if (!obj) { return } + obj = obj[segments[i]]; + } + return obj + } + } + + /* */ + + // can we use __proto__? + var hasProto = '__proto__' in {}; + + // Browser environment sniffing + var inBrowser = typeof window !== 'undefined'; + var inWeex = typeof WXEnvironment !== 'undefined' && !!WXEnvironment.platform; + var weexPlatform = inWeex && WXEnvironment.platform.toLowerCase(); + var UA = inBrowser && window.navigator.userAgent.toLowerCase(); + var isIE = UA && /msie|trident/.test(UA); + var isIE9 = UA && UA.indexOf('msie 9.0') > 0; + var isEdge = UA && UA.indexOf('edge/') > 0; + var isAndroid = (UA && UA.indexOf('android') > 0) || (weexPlatform === 'android'); + var isIOS = (UA && /iphone|ipad|ipod|ios/.test(UA)) || (weexPlatform === 'ios'); + var isChrome = UA && /chrome\/\d+/.test(UA) && !isEdge; + var isPhantomJS = UA && /phantomjs/.test(UA); + var isFF = UA && UA.match(/firefox\/(\d+)/); + + // Firefox has a "watch" function on Object.prototype... + var nativeWatch = ({}).watch; + + var supportsPassive = false; + if (inBrowser) { + try { + var opts = {}; + Object.defineProperty(opts, 'passive', ({ + get: function get () { + /* istanbul ignore next */ + supportsPassive = true; + } + })); // https://github.com/facebook/flow/issues/285 + window.addEventListener('test-passive', null, opts); + } catch (e) {} + } + + // this needs to be lazy-evaled because vue may be required before + // vue-server-renderer can set VUE_ENV + var _isServer; + var isServerRendering = function () { + if (_isServer === undefined) { + /* istanbul ignore if */ + if (!inBrowser && !inWeex && typeof global !== 'undefined') { + // detect presence of vue-server-renderer and avoid + // Webpack shimming the process + _isServer = global['process'] && global['process'].env.VUE_ENV === 'server'; + } else { + _isServer = false; + } + } + return _isServer + }; + + // detect devtools + var devtools = inBrowser && window.__VUE_DEVTOOLS_GLOBAL_HOOK__; + + /* istanbul ignore next */ + function isNative (Ctor) { + return typeof Ctor === 'function' && /native code/.test(Ctor.toString()) + } + + var hasSymbol = + typeof Symbol !== 'undefined' && isNative(Symbol) && + typeof Reflect !== 'undefined' && isNative(Reflect.ownKeys); + + var _Set; + /* istanbul ignore if */ // $flow-disable-line + if (typeof Set !== 'undefined' && isNative(Set)) { + // use native Set when available. + _Set = Set; + } else { + // a non-standard Set polyfill that only works with primitive keys. + _Set = /*@__PURE__*/(function () { + function Set () { + this.set = Object.create(null); + } + Set.prototype.has = function has (key) { + return this.set[key] === true + }; + Set.prototype.add = function add (key) { + this.set[key] = true; + }; + Set.prototype.clear = function clear () { + this.set = Object.create(null); + }; + + return Set; + }()); + } + + /* */ + + var warn = noop; + var tip = noop; + var generateComponentTrace = (noop); // work around flow check + var formatComponentName = (noop); + + { + var hasConsole = typeof console !== 'undefined'; + var classifyRE = /(?:^|[-_])(\w)/g; + var classify = function (str) { return str + .replace(classifyRE, function (c) { return c.toUpperCase(); }) + .replace(/[-_]/g, ''); }; + + warn = function (msg, vm) { + var trace = vm ? generateComponentTrace(vm) : ''; + + if (config.warnHandler) { + config.warnHandler.call(null, msg, vm, trace); + } else if (hasConsole && (!config.silent)) { + console.error(("[Vue warn]: " + msg + trace)); + } + }; + + tip = function (msg, vm) { + if (hasConsole && (!config.silent)) { + console.warn("[Vue tip]: " + msg + ( + vm ? generateComponentTrace(vm) : '' + )); + } + }; + + formatComponentName = function (vm, includeFile) { + if (vm.$root === vm) { + return '' + } + var options = typeof vm === 'function' && vm.cid != null + ? vm.options + : vm._isVue + ? vm.$options || vm.constructor.options + : vm; + var name = options.name || options._componentTag; + var file = options.__file; + if (!name && file) { + var match = file.match(/([^/\\]+)\.vue$/); + name = match && match[1]; + } + + return ( + (name ? ("<" + (classify(name)) + ">") : "") + + (file && includeFile !== false ? (" at " + file) : '') + ) + }; + + var repeat = function (str, n) { + var res = ''; + while (n) { + if (n % 2 === 1) { res += str; } + if (n > 1) { str += str; } + n >>= 1; + } + return res + }; + + generateComponentTrace = function (vm) { + if (vm._isVue && vm.$parent) { + var tree = []; + var currentRecursiveSequence = 0; + while (vm) { + if (tree.length > 0) { + var last = tree[tree.length - 1]; + if (last.constructor === vm.constructor) { + currentRecursiveSequence++; + vm = vm.$parent; + continue + } else if (currentRecursiveSequence > 0) { + tree[tree.length - 1] = [last, currentRecursiveSequence]; + currentRecursiveSequence = 0; + } + } + tree.push(vm); + vm = vm.$parent; + } + return '\n\nfound in\n\n' + tree + .map(function (vm, i) { return ("" + (i === 0 ? '---> ' : repeat(' ', 5 + i * 2)) + (Array.isArray(vm) + ? ((formatComponentName(vm[0])) + "... (" + (vm[1]) + " recursive calls)") + : formatComponentName(vm))); }) + .join('\n') + } else { + return ("\n\n(found in " + (formatComponentName(vm)) + ")") + } + }; + } + + /* */ + + var uid = 0; + + /** + * A dep is an observable that can have multiple + * directives subscribing to it. + */ + var Dep = function Dep () { + this.id = uid++; + this.subs = []; + }; + + Dep.prototype.addSub = function addSub (sub) { + this.subs.push(sub); + }; + + Dep.prototype.removeSub = function removeSub (sub) { + remove(this.subs, sub); + }; + + Dep.prototype.depend = function depend () { + if (Dep.target) { + Dep.target.addDep(this); + } + }; + + Dep.prototype.notify = function notify () { + // stabilize the subscriber list first + var subs = this.subs.slice(); + if (!config.async) { + // subs aren't sorted in scheduler if not running async + // we need to sort them now to make sure they fire in correct + // order + subs.sort(function (a, b) { return a.id - b.id; }); + } + for (var i = 0, l = subs.length; i < l; i++) { + subs[i].update(); + } + }; + + // The current target watcher being evaluated. + // This is globally unique because only one watcher + // can be evaluated at a time. + Dep.target = null; + var targetStack = []; + + function pushTarget (target) { + targetStack.push(target); + Dep.target = target; + } + + function popTarget () { + targetStack.pop(); + Dep.target = targetStack[targetStack.length - 1]; + } + + /* */ + + var VNode = function VNode ( + tag, + data, + children, + text, + elm, + context, + componentOptions, + asyncFactory + ) { + this.tag = tag; + this.data = data; + this.children = children; + this.text = text; + this.elm = elm; + this.ns = undefined; + this.context = context; + this.fnContext = undefined; + this.fnOptions = undefined; + this.fnScopeId = undefined; + this.key = data && data.key; + this.componentOptions = componentOptions; + this.componentInstance = undefined; + this.parent = undefined; + this.raw = false; + this.isStatic = false; + this.isRootInsert = true; + this.isComment = false; + this.isCloned = false; + this.isOnce = false; + this.asyncFactory = asyncFactory; + this.asyncMeta = undefined; + this.isAsyncPlaceholder = false; + }; + + var prototypeAccessors = { child: { configurable: true } }; + + // DEPRECATED: alias for componentInstance for backwards compat. + /* istanbul ignore next */ + prototypeAccessors.child.get = function () { + return this.componentInstance + }; + + Object.defineProperties( VNode.prototype, prototypeAccessors ); + + var createEmptyVNode = function (text) { + if ( text === void 0 ) text = ''; + + var node = new VNode(); + node.text = text; + node.isComment = true; + return node + }; + + function createTextVNode (val) { + return new VNode(undefined, undefined, undefined, String(val)) + } + + // optimized shallow clone + // used for static nodes and slot nodes because they may be reused across + // multiple renders, cloning them avoids errors when DOM manipulations rely + // on their elm reference. + function cloneVNode (vnode) { + var cloned = new VNode( + vnode.tag, + vnode.data, + // #7975 + // clone children array to avoid mutating original in case of cloning + // a child. + vnode.children && vnode.children.slice(), + vnode.text, + vnode.elm, + vnode.context, + vnode.componentOptions, + vnode.asyncFactory + ); + cloned.ns = vnode.ns; + cloned.isStatic = vnode.isStatic; + cloned.key = vnode.key; + cloned.isComment = vnode.isComment; + cloned.fnContext = vnode.fnContext; + cloned.fnOptions = vnode.fnOptions; + cloned.fnScopeId = vnode.fnScopeId; + cloned.asyncMeta = vnode.asyncMeta; + cloned.isCloned = true; + return cloned + } + + /* + * not type checking this file because flow doesn't play well with + * dynamically accessing methods on Array prototype + */ + + var arrayProto = Array.prototype; + var arrayMethods = Object.create(arrayProto); + + var methodsToPatch = [ + 'push', + 'pop', + 'shift', + 'unshift', + 'splice', + 'sort', + 'reverse' + ]; + + /** + * Intercept mutating methods and emit events + */ + methodsToPatch.forEach(function (method) { + // cache original method + var original = arrayProto[method]; + def(arrayMethods, method, function mutator () { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + var result = original.apply(this, args); + var ob = this.__ob__; + var inserted; + switch (method) { + case 'push': + case 'unshift': + inserted = args; + break + case 'splice': + inserted = args.slice(2); + break + } + if (inserted) { ob.observeArray(inserted); } + // notify change + ob.dep.notify(); + return result + }); + }); + + /* */ + + var arrayKeys = Object.getOwnPropertyNames(arrayMethods); + + /** + * In some cases we may want to disable observation inside a component's + * update computation. + */ + var shouldObserve = true; + + function toggleObserving (value) { + shouldObserve = value; + } + + /** + * Observer class that is attached to each observed + * object. Once attached, the observer converts the target + * object's property keys into getter/setters that + * collect dependencies and dispatch updates. + */ + var Observer = function Observer (value) { + this.value = value; + this.dep = new Dep(); + this.vmCount = 0; + def(value, '__ob__', this); + if (Array.isArray(value)) { + if (hasProto) { + protoAugment(value, arrayMethods); + } else { + copyAugment(value, arrayMethods, arrayKeys); + } + this.observeArray(value); + } else { + this.walk(value); + } + }; + + /** + * Walk through all properties and convert them into + * getter/setters. This method should only be called when + * value type is Object. + */ + Observer.prototype.walk = function walk (obj) { + var keys = Object.keys(obj); + for (var i = 0; i < keys.length; i++) { + defineReactive$$1(obj, keys[i]); + } + }; + + /** + * Observe a list of Array items. + */ + Observer.prototype.observeArray = function observeArray (items) { + for (var i = 0, l = items.length; i < l; i++) { + observe(items[i]); + } + }; + + // helpers + + /** + * Augment a target Object or Array by intercepting + * the prototype chain using __proto__ + */ + function protoAugment (target, src) { + /* eslint-disable no-proto */ + target.__proto__ = src; + /* eslint-enable no-proto */ + } + + /** + * Augment a target Object or Array by defining + * hidden properties. + */ + /* istanbul ignore next */ + 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. + */ + function observe (value, asRootData) { + if (!isObject(value) || value instanceof VNode) { + return + } + var ob; + if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) { + ob = value.__ob__; + } else if ( + shouldObserve && + !isServerRendering() && + (Array.isArray(value) || isPlainObject(value)) && + Object.isExtensible(value) && + !value._isVue + ) { + ob = new Observer(value); + } + if (asRootData && ob) { + ob.vmCount++; + } + return ob + } + + /** + * Define a reactive property on an Object. + */ + function defineReactive$$1 ( + obj, + key, + val, + customSetter, + shallow + ) { + 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; + if ((!getter || setter) && arguments.length === 2) { + val = obj[key]; + } + + var childOb = !shallow && 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 (Array.isArray(value)) { + dependArray(value); + } + } + } + return value + }, + set: function reactiveSetter (newVal) { + var value = getter ? getter.call(obj) : val; + /* eslint-disable no-self-compare */ + if (newVal === value || (newVal !== newVal && value !== value)) { + return + } + /* eslint-enable no-self-compare */ + if (customSetter) { + customSetter(); + } + // #7981: for accessor properties without setter + if (getter && !setter) { return } + if (setter) { + setter.call(obj, newVal); + } else { + val = newVal; + } + childOb = !shallow && observe(newVal); + dep.notify(); + } + }); + } + + /** + * Set a property on an object. Adds the new property and + * triggers change notification if the property doesn't + * already exist. + */ + function set (target, key, val) { + if (isUndef(target) || isPrimitive(target) + ) { + warn(("Cannot set reactive property on undefined, null, or primitive value: " + ((target)))); + } + if (Array.isArray(target) && isValidArrayIndex(key)) { + target.length = Math.max(target.length, key); + target.splice(key, 1, val); + return val + } + if (key in target && !(key in Object.prototype)) { + target[key] = val; + return val + } + var ob = (target).__ob__; + if (target._isVue || (ob && ob.vmCount)) { + warn( + 'Avoid adding reactive properties to a Vue instance or its root $data ' + + 'at runtime - declare it upfront in the data option.' + ); + return val + } + if (!ob) { + target[key] = val; + return val + } + defineReactive$$1(ob.value, key, val); + ob.dep.notify(); + return val + } + + /** + * Delete a property and trigger change if necessary. + */ + function del (target, key) { + if (isUndef(target) || isPrimitive(target) + ) { + warn(("Cannot delete reactive property on undefined, null, or primitive value: " + ((target)))); + } + if (Array.isArray(target) && isValidArrayIndex(key)) { + target.splice(key, 1); + return + } + var ob = (target).__ob__; + if (target._isVue || (ob && ob.vmCount)) { + warn( + 'Avoid deleting properties on a Vue instance or its root $data ' + + '- just set it to null.' + ); + return + } + if (!hasOwn(target, key)) { + return + } + delete target[key]; + if (!ob) { + return + } + ob.dep.notify(); + } + + /** + * Collect dependencies on array elements when the array is touched, since + * we cannot intercept array element access like property getters. + */ + function dependArray (value) { + for (var e = (void 0), i = 0, l = value.length; i < l; i++) { + e = value[i]; + e && e.__ob__ && e.__ob__.dep.depend(); + if (Array.isArray(e)) { + dependArray(e); + } + } + } + + /* */ + + /** + * Option overwriting strategies are functions that handle + * how to merge a parent option value and a child option + * value into the final value. + */ + var strats = config.optionMergeStrategies; + + /** + * Options with restrictions + */ + { + strats.el = strats.propsData = function (parent, child, vm, key) { + if (!vm) { + warn( + "option \"" + key + "\" can only be used during instance " + + 'creation with the `new` keyword.' + ); + } + return defaultStrat(parent, child) + }; + } + + /** + * Helper that recursively merges two data objects together. + */ + function mergeData (to, from) { + if (!from) { return to } + var key, toVal, fromVal; + + var keys = hasSymbol + ? Reflect.ownKeys(from) + : Object.keys(from); + + for (var i = 0; i < keys.length; i++) { + key = keys[i]; + // in case the object is already observed... + if (key === '__ob__') { continue } + toVal = to[key]; + fromVal = from[key]; + if (!hasOwn(to, key)) { + set(to, key, fromVal); + } else if ( + toVal !== fromVal && + isPlainObject(toVal) && + isPlainObject(fromVal) + ) { + mergeData(toVal, fromVal); + } + } + return to + } + + /** + * Data + */ + function mergeDataOrFn ( + parentVal, + childVal, + vm + ) { + if (!vm) { + // in a Vue.extend merge, both should be functions + if (!childVal) { + 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( + typeof childVal === 'function' ? childVal.call(this, this) : childVal, + typeof parentVal === 'function' ? parentVal.call(this, this) : parentVal + ) + } + } else { + return function mergedInstanceDataFn () { + // instance merge + var instanceData = typeof childVal === 'function' + ? childVal.call(vm, vm) + : childVal; + var defaultData = typeof parentVal === 'function' + ? parentVal.call(vm, vm) + : parentVal; + if (instanceData) { + return mergeData(instanceData, defaultData) + } else { + return defaultData + } + } + } + } + + strats.data = function ( + parentVal, + childVal, + vm + ) { + if (!vm) { + if (childVal && typeof childVal !== 'function') { + warn( + 'The "data" option should be a function ' + + 'that returns a per-instance value in component ' + + 'definitions.', + vm + ); + + return parentVal + } + return mergeDataOrFn(parentVal, childVal) + } + + return mergeDataOrFn(parentVal, childVal, vm) + }; + + /** + * Hooks and props are merged as arrays. + */ + function mergeHook ( + parentVal, + childVal + ) { + var res = childVal + ? parentVal + ? parentVal.concat(childVal) + : Array.isArray(childVal) + ? childVal + : [childVal] + : parentVal; + return res + ? dedupeHooks(res) + : res + } + + function dedupeHooks (hooks) { + var res = []; + for (var i = 0; i < hooks.length; i++) { + if (res.indexOf(hooks[i]) === -1) { + res.push(hooks[i]); + } + } + return res + } + + LIFECYCLE_HOOKS.forEach(function (hook) { + strats[hook] = mergeHook; + }); + + /** + * 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, + vm, + key + ) { + var res = Object.create(parentVal || null); + if (childVal) { + assertObjectType(key, childVal, vm); + return extend(res, childVal) + } else { + return res + } + } + + ASSET_TYPES.forEach(function (type) { + strats[type + 's'] = mergeAssets; + }); + + /** + * Watchers. + * + * Watchers hashes should not overwrite one + * another, so we merge them as arrays. + */ + strats.watch = function ( + parentVal, + childVal, + vm, + key + ) { + // work around Firefox's Object.prototype.watch... + if (parentVal === nativeWatch) { parentVal = undefined; } + if (childVal === nativeWatch) { childVal = undefined; } + /* istanbul ignore if */ + if (!childVal) { return Object.create(parentVal || null) } + { + assertObjectType(key, childVal, vm); + } + if (!parentVal) { return childVal } + var ret = {}; + extend(ret, parentVal); + for (var key$1 in childVal) { + var parent = ret[key$1]; + var child = childVal[key$1]; + if (parent && !Array.isArray(parent)) { + parent = [parent]; + } + ret[key$1] = parent + ? parent.concat(child) + : Array.isArray(child) ? child : [child]; + } + return ret + }; + + /** + * Other object hashes. + */ + strats.props = + strats.methods = + strats.inject = + strats.computed = function ( + parentVal, + childVal, + vm, + key + ) { + if (childVal && "development" !== 'production') { + assertObjectType(key, childVal, vm); + } + if (!parentVal) { return childVal } + var ret = Object.create(null); + extend(ret, parentVal); + if (childVal) { extend(ret, childVal); } + return ret + }; + strats.provide = mergeDataOrFn; + + /** + * Default strategy. + */ + var defaultStrat = function (parentVal, childVal) { + return childVal === undefined + ? parentVal + : childVal + }; + + /** + * Validate component names + */ + function checkComponents (options) { + for (var key in options.components) { + validateComponentName(key); + } + } + + function validateComponentName (name) { + if (!new RegExp(("^[a-zA-Z][\\-\\.0-9_" + (unicodeRegExp.source) + "]*$")).test(name)) { + warn( + 'Invalid component name: "' + name + '". Component names ' + + 'should conform to valid custom element name in html5 specification.' + ); + } + if (isBuiltInTag(name) || config.isReservedTag(name)) { + warn( + 'Do not use built-in or reserved HTML elements as component ' + + 'id: ' + name + ); + } + } + + /** + * Ensure all props option syntax are normalized into the + * Object-based format. + */ + function normalizeProps (options, vm) { + var props = options.props; + if (!props) { return } + var res = {}; + var i, val, name; + if (Array.isArray(props)) { + i = props.length; + while (i--) { + val = props[i]; + if (typeof val === 'string') { + name = camelize(val); + res[name] = { type: null }; + } else { + warn('props must be strings when using array syntax.'); + } + } + } else if (isPlainObject(props)) { + for (var key in props) { + val = props[key]; + name = camelize(key); + res[name] = isPlainObject(val) + ? val + : { type: val }; + } + } else { + warn( + "Invalid value for option \"props\": expected an Array or an Object, " + + "but got " + (toRawType(props)) + ".", + vm + ); + } + options.props = res; + } + + /** + * Normalize all injections into Object-based format + */ + function normalizeInject (options, vm) { + var inject = options.inject; + if (!inject) { return } + var normalized = options.inject = {}; + if (Array.isArray(inject)) { + for (var i = 0; i < inject.length; i++) { + normalized[inject[i]] = { from: inject[i] }; + } + } else if (isPlainObject(inject)) { + for (var key in inject) { + var val = inject[key]; + normalized[key] = isPlainObject(val) + ? extend({ from: key }, val) + : { from: val }; + } + } else { + warn( + "Invalid value for option \"inject\": expected an Array or an Object, " + + "but got " + (toRawType(inject)) + ".", + vm + ); + } + } + + /** + * Normalize raw function directives into object format. + */ + function normalizeDirectives (options) { + var dirs = options.directives; + if (dirs) { + for (var key in dirs) { + var def$$1 = dirs[key]; + if (typeof def$$1 === 'function') { + dirs[key] = { bind: def$$1, update: def$$1 }; + } + } + } + } + + function assertObjectType (name, value, vm) { + if (!isPlainObject(value)) { + warn( + "Invalid value for option \"" + name + "\": expected an Object, " + + "but got " + (toRawType(value)) + ".", + vm + ); + } + } + + /** + * Merge two option objects into a new one. + * Core utility used in both instantiation and inheritance. + */ + function mergeOptions ( + parent, + child, + vm + ) { + { + checkComponents(child); + } + + if (typeof child === 'function') { + child = child.options; + } + + normalizeProps(child, vm); + normalizeInject(child, vm); + normalizeDirectives(child); + + // Apply extends and mixins on the child options, + // but only if it is a raw options object that isn't + // the result of another mergeOptions call. + // Only merged options has the _base property. + if (!child._base) { + if (child.extends) { + parent = mergeOptions(parent, child.extends, vm); + } + if (child.mixins) { + for (var i = 0, l = child.mixins.length; i < l; i++) { + parent = mergeOptions(parent, child.mixins[i], vm); + } + } + } + + var options = {}; + var key; + 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. + */ + function resolveAsset ( + options, + type, + id, + warnMissing + ) { + /* istanbul ignore if */ + if (typeof id !== 'string') { + return + } + var assets = options[type]; + // check local registration variations first + if (hasOwn(assets, id)) { return assets[id] } + var camelizedId = camelize(id); + if (hasOwn(assets, camelizedId)) { return assets[camelizedId] } + var PascalCaseId = capitalize(camelizedId); + if (hasOwn(assets, PascalCaseId)) { return assets[PascalCaseId] } + // fallback to prototype chain + var res = assets[id] || assets[camelizedId] || assets[PascalCaseId]; + if (warnMissing && !res) { + warn( + 'Failed to resolve ' + type.slice(0, -1) + ': ' + id, + options + ); + } + return res + } + + /* */ + + + + function validateProp ( + key, + propOptions, + propsData, + vm + ) { + var prop = propOptions[key]; + var absent = !hasOwn(propsData, key); + var value = propsData[key]; + // boolean casting + var booleanIndex = getTypeIndex(Boolean, prop.type); + if (booleanIndex > -1) { + if (absent && !hasOwn(prop, 'default')) { + value = false; + } else if (value === '' || value === hyphenate(key)) { + // only cast empty string / same name to boolean if + // boolean has higher priority + var stringIndex = getTypeIndex(String, prop.type); + if (stringIndex < 0 || booleanIndex < stringIndex) { + value = true; + } + } + } + // check default value + if (value === undefined) { + value = getPropDefaultValue(vm, prop, key); + // since the default value is a fresh copy, + // make sure to observe it. + var prevShouldObserve = shouldObserve; + toggleObserving(true); + observe(value); + toggleObserving(prevShouldObserve); + } + { + assertProp(prop, key, value, vm, absent); + } + return value + } + + /** + * Get the default value of a prop. + */ + function getPropDefaultValue (vm, prop, key) { + // no default, return undefined + if (!hasOwn(prop, 'default')) { + return undefined + } + var def = prop.default; + // warn against non-factory defaults for Object & Array + if (isObject(def)) { + warn( + 'Invalid default value for prop "' + key + '": ' + + 'Props with type Object/Array must use a factory function ' + + 'to return the default value.', + vm + ); + } + // the raw prop value was also undefined from previous render, + // return previous default value to avoid unnecessary watcher trigger + if (vm && vm.$options.propsData && + vm.$options.propsData[key] === undefined && + vm._props[key] !== undefined + ) { + return vm._props[key] + } + // call factory function for non-Function types + // a value is Function if its prototype is function even across different execution context + return typeof def === 'function' && getType(prop.type) !== 'Function' + ? def.call(vm) + : def + } + + /** + * Assert whether a prop is valid. + */ + function assertProp ( + prop, + name, + value, + vm, + absent + ) { + if (prop.required && absent) { + warn( + 'Missing required prop: "' + name + '"', + vm + ); + return + } + if (value == null && !prop.required) { + return + } + var type = prop.type; + var valid = !type || type === true; + var expectedTypes = []; + if (type) { + if (!Array.isArray(type)) { + type = [type]; + } + for (var i = 0; i < type.length && !valid; i++) { + var assertedType = assertType(value, type[i]); + expectedTypes.push(assertedType.expectedType || ''); + valid = assertedType.valid; + } + } + + if (!valid) { + warn( + getInvalidTypeMessage(name, value, expectedTypes), + vm + ); + return + } + var validator = prop.validator; + if (validator) { + if (!validator(value)) { + warn( + 'Invalid prop: custom validator check failed for prop "' + name + '".', + vm + ); + } + } + } + + var simpleCheckRE = /^(String|Number|Boolean|Function|Symbol)$/; + + function assertType (value, type) { + var valid; + var expectedType = getType(type); + if (simpleCheckRE.test(expectedType)) { + var t = typeof value; + valid = t === expectedType.toLowerCase(); + // for primitive wrapper objects + if (!valid && t === 'object') { + valid = value instanceof type; + } + } else if (expectedType === 'Object') { + valid = isPlainObject(value); + } else if (expectedType === 'Array') { + valid = Array.isArray(value); + } else { + valid = value instanceof type; + } + return { + valid: valid, + expectedType: expectedType + } + } + + /** + * Use function string name to check built-in types, + * because a simple equality check will fail when running + * across different vms / iframes. + */ + function getType (fn) { + var match = fn && fn.toString().match(/^\s*function (\w+)/); + return match ? match[1] : '' + } + + function isSameType (a, b) { + return getType(a) === getType(b) + } + + function getTypeIndex (type, expectedTypes) { + if (!Array.isArray(expectedTypes)) { + return isSameType(expectedTypes, type) ? 0 : -1 + } + for (var i = 0, len = expectedTypes.length; i < len; i++) { + if (isSameType(expectedTypes[i], type)) { + return i + } + } + return -1 + } + + function getInvalidTypeMessage (name, value, expectedTypes) { + var message = "Invalid prop: type check failed for prop \"" + name + "\"." + + " Expected " + (expectedTypes.map(capitalize).join(', ')); + var expectedType = expectedTypes[0]; + var receivedType = toRawType(value); + var expectedValue = styleValue(value, expectedType); + var receivedValue = styleValue(value, receivedType); + // check if we need to specify expected value + if (expectedTypes.length === 1 && + isExplicable(expectedType) && + !isBoolean(expectedType, receivedType)) { + message += " with value " + expectedValue; + } + message += ", got " + receivedType + " "; + // check if we need to specify received value + if (isExplicable(receivedType)) { + message += "with value " + receivedValue + "."; + } + return message + } + + function styleValue (value, type) { + if (type === 'String') { + return ("\"" + value + "\"") + } else if (type === 'Number') { + return ("" + (Number(value))) + } else { + return ("" + value) + } + } + + function isExplicable (value) { + var explicitTypes = ['string', 'number', 'boolean']; + return explicitTypes.some(function (elem) { return value.toLowerCase() === elem; }) + } + + function isBoolean () { + var args = [], len = arguments.length; + while ( len-- ) args[ len ] = arguments[ len ]; + + return args.some(function (elem) { return elem.toLowerCase() === 'boolean'; }) + } + + /* */ + + function handleError (err, vm, info) { + // Deactivate deps tracking while processing error handler to avoid possible infinite rendering. + // See: https://github.com/vuejs/vuex/issues/1505 + pushTarget(); + try { + if (vm) { + var cur = vm; + while ((cur = cur.$parent)) { + var hooks = cur.$options.errorCaptured; + if (hooks) { + for (var i = 0; i < hooks.length; i++) { + try { + var capture = hooks[i].call(cur, err, vm, info) === false; + if (capture) { return } + } catch (e) { + globalHandleError(e, cur, 'errorCaptured hook'); + } + } + } + } + } + globalHandleError(err, vm, info); + } finally { + popTarget(); + } + } + + function invokeWithErrorHandling ( + handler, + context, + args, + vm, + info + ) { + var res; + try { + res = args ? handler.apply(context, args) : handler.call(context); + if (res && !res._isVue && isPromise(res) && !res._handled) { + res.catch(function (e) { return handleError(e, vm, info + " (Promise/async)"); }); + // issue #9511 + // avoid catch triggering multiple times when nested calls + res._handled = true; + } + } catch (e) { + handleError(e, vm, info); + } + return res + } + + function globalHandleError (err, vm, info) { + if (config.errorHandler) { + try { + return config.errorHandler.call(null, err, vm, info) + } catch (e) { + // if the user intentionally throws the original error in the handler, + // do not log it twice + if (e !== err) { + logError(e, null, 'config.errorHandler'); + } + } + } + logError(err, vm, info); + } + + function logError (err, vm, info) { + { + warn(("Error in " + info + ": \"" + (err.toString()) + "\""), vm); + } + /* istanbul ignore else */ + if ((inBrowser || inWeex) && typeof console !== 'undefined') { + console.error(err); + } else { + throw err + } + } + + /* */ + + var isUsingMicroTask = false; + + var callbacks = []; + var pending = false; + + function flushCallbacks () { + pending = false; + var copies = callbacks.slice(0); + callbacks.length = 0; + for (var i = 0; i < copies.length; i++) { + copies[i](); + } + } + + // Here we have async deferring wrappers using microtasks. + // In 2.5 we used (macro) tasks (in combination with microtasks). + // However, it has subtle problems when state is changed right before repaint + // (e.g. #6813, out-in transitions). + // Also, using (macro) tasks in event handler would cause some weird behaviors + // that cannot be circumvented (e.g. #7109, #7153, #7546, #7834, #8109). + // So we now use microtasks everywhere, again. + // A major drawback of this tradeoff is that there are some scenarios + // where microtasks have too high a priority and fire in between supposedly + // sequential events (e.g. #4521, #6690, which have workarounds) + // or even between bubbling of the same event (#6566). + var timerFunc; + + // The nextTick behavior leverages the microtask queue, which can be accessed + // via either native Promise.then or MutationObserver. + // MutationObserver has wider support, however it is seriously bugged in + // UIWebView in iOS >= 9.3.3 when triggered in touch event handlers. It + // completely stops working after triggering a few times... so, if native + // Promise is available, we will use it: + /* istanbul ignore next, $flow-disable-line */ + if (typeof Promise !== 'undefined' && isNative(Promise)) { + var p = Promise.resolve(); + timerFunc = function () { + p.then(flushCallbacks); + // In problematic UIWebViews, Promise.then doesn't completely break, but + // it can get stuck in a weird state where callbacks are pushed into the + // microtask queue but the queue isn't being flushed, until the browser + // needs to do some other work, e.g. handle a timer. Therefore we can + // "force" the microtask queue to be flushed by adding an empty timer. + if (isIOS) { setTimeout(noop); } + }; + isUsingMicroTask = true; + } else if (!isIE && typeof MutationObserver !== 'undefined' && ( + isNative(MutationObserver) || + // PhantomJS and iOS 7.x + MutationObserver.toString() === '[object MutationObserverConstructor]' + )) { + // Use MutationObserver where native Promise is not available, + // e.g. PhantomJS, iOS7, Android 4.4 + // (#6466 MutationObserver is unreliable in IE11) + var counter = 1; + var observer = new MutationObserver(flushCallbacks); + var textNode = document.createTextNode(String(counter)); + observer.observe(textNode, { + characterData: true + }); + timerFunc = function () { + counter = (counter + 1) % 2; + textNode.data = String(counter); + }; + isUsingMicroTask = true; + } else if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) { + // Fallback to setImmediate. + // Technically it leverages the (macro) task queue, + // but it is still a better choice than setTimeout. + timerFunc = function () { + setImmediate(flushCallbacks); + }; + } else { + // Fallback to setTimeout. + timerFunc = function () { + setTimeout(flushCallbacks, 0); + }; + } + + function nextTick (cb, ctx) { + var _resolve; + callbacks.push(function () { + if (cb) { + try { + cb.call(ctx); + } catch (e) { + handleError(e, ctx, 'nextTick'); + } + } else if (_resolve) { + _resolve(ctx); + } + }); + if (!pending) { + pending = true; + timerFunc(); + } + // $flow-disable-line + if (!cb && typeof Promise !== 'undefined') { + return new Promise(function (resolve) { + _resolve = resolve; + }) + } + } + + /* */ + + var mark; + var measure; + + { + var perf = inBrowser && window.performance; + /* istanbul ignore if */ + if ( + perf && + perf.mark && + perf.measure && + perf.clearMarks && + perf.clearMeasures + ) { + mark = function (tag) { return perf.mark(tag); }; + measure = function (name, startTag, endTag) { + perf.measure(name, startTag, endTag); + perf.clearMarks(startTag); + perf.clearMarks(endTag); + // perf.clearMeasures(name) + }; + } + } + + /* not type checking this file because flow doesn't play well with Proxy */ + + var initProxy; + + { + var allowedGlobals = makeMap( + 'Infinity,undefined,NaN,isFinite,isNaN,' + + 'parseFloat,parseInt,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,' + + 'Math,Number,Date,Array,Object,Boolean,String,RegExp,Map,Set,JSON,Intl,' + + 'require' // for Webpack/Browserify + ); + + var warnNonPresent = function (target, key) { + warn( + "Property or method \"" + key + "\" is not defined on the instance but " + + 'referenced during render. Make sure that this property is reactive, ' + + 'either in the data option, or for class-based components, by ' + + 'initializing the property. ' + + 'See: https://vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties.', + target + ); + }; + + var warnReservedPrefix = function (target, key) { + warn( + "Property \"" + key + "\" must be accessed with \"$data." + key + "\" because " + + 'properties starting with "$" or "_" are not proxied in the Vue instance to ' + + 'prevent conflicts with Vue internals. ' + + 'See: https://vuejs.org/v2/api/#data', + target + ); + }; + + var hasProxy = + typeof Proxy !== 'undefined' && isNative(Proxy); + + if (hasProxy) { + var isBuiltInModifier = makeMap('stop,prevent,self,ctrl,shift,alt,meta,exact'); + config.keyCodes = new Proxy(config.keyCodes, { + set: function set (target, key, value) { + if (isBuiltInModifier(key)) { + warn(("Avoid overwriting built-in modifier in config.keyCodes: ." + key)); + return false + } else { + target[key] = value; + return true + } + } + }); + } + + var hasHandler = { + has: function has (target, key) { + var has = key in target; + var isAllowed = allowedGlobals(key) || + (typeof key === 'string' && key.charAt(0) === '_' && !(key in target.$data)); + if (!has && !isAllowed) { + if (key in target.$data) { warnReservedPrefix(target, key); } + else { warnNonPresent(target, key); } + } + return has || !isAllowed + } + }; + + var getHandler = { + get: function get (target, key) { + if (typeof key === 'string' && !(key in target)) { + if (key in target.$data) { warnReservedPrefix(target, key); } + else { warnNonPresent(target, key); } + } + return target[key] + } + }; + + initProxy = function initProxy (vm) { + if (hasProxy) { + // determine which proxy handler to use + var options = vm.$options; + var handlers = options.render && options.render._withStripped + ? getHandler + : hasHandler; + vm._renderProxy = new Proxy(vm, handlers); + } else { + vm._renderProxy = vm; + } + }; + } + + /* */ + + var seenObjects = new _Set(); + + /** + * Recursively traverse an object to evoke all converted + * getters, so that every nested property inside the object + * is collected as a "deep" dependency. + */ + function traverse (val) { + _traverse(val, seenObjects); + seenObjects.clear(); + } + + function _traverse (val, seen) { + var i, keys; + var isA = Array.isArray(val); + if ((!isA && !isObject(val)) || Object.isFrozen(val) || val instanceof VNode) { + return + } + if (val.__ob__) { + var depId = val.__ob__.dep.id; + if (seen.has(depId)) { + return + } + seen.add(depId); + } + if (isA) { + i = val.length; + while (i--) { _traverse(val[i], seen); } + } else { + keys = Object.keys(val); + i = keys.length; + while (i--) { _traverse(val[keys[i]], seen); } + } + } + + /* */ + + var normalizeEvent = cached(function (name) { + var passive = name.charAt(0) === '&'; + name = passive ? name.slice(1) : name; + var once$$1 = name.charAt(0) === '~'; // Prefixed last, checked first + name = once$$1 ? name.slice(1) : name; + var capture = name.charAt(0) === '!'; + name = capture ? name.slice(1) : name; + return { + name: name, + once: once$$1, + capture: capture, + passive: passive + } + }); + + function createFnInvoker (fns, vm) { + function invoker () { + var arguments$1 = arguments; + + var fns = invoker.fns; + if (Array.isArray(fns)) { + var cloned = fns.slice(); + for (var i = 0; i < cloned.length; i++) { + invokeWithErrorHandling(cloned[i], null, arguments$1, vm, "v-on handler"); + } + } else { + // return handler return value for single handlers + return invokeWithErrorHandling(fns, null, arguments, vm, "v-on handler") + } + } + invoker.fns = fns; + return invoker + } + + function updateListeners ( + on, + oldOn, + add, + remove$$1, + createOnceHandler, + vm + ) { + var name, def$$1, cur, old, event; + for (name in on) { + def$$1 = cur = on[name]; + old = oldOn[name]; + event = normalizeEvent(name); + if (isUndef(cur)) { + warn( + "Invalid handler for event \"" + (event.name) + "\": got " + String(cur), + vm + ); + } else if (isUndef(old)) { + if (isUndef(cur.fns)) { + cur = on[name] = createFnInvoker(cur, vm); + } + if (isTrue(event.once)) { + cur = on[name] = createOnceHandler(event.name, cur, event.capture); + } + add(event.name, cur, event.capture, event.passive, event.params); + } else if (cur !== old) { + old.fns = cur; + on[name] = old; + } + } + for (name in oldOn) { + if (isUndef(on[name])) { + event = normalizeEvent(name); + remove$$1(event.name, oldOn[name], event.capture); + } + } + } + + /* */ + + function mergeVNodeHook (def, hookKey, hook) { + if (def instanceof VNode) { + def = def.data.hook || (def.data.hook = {}); + } + var invoker; + var oldHook = def[hookKey]; + + function wrappedHook () { + hook.apply(this, arguments); + // important: remove merged hook to ensure it's called only once + // and prevent memory leak + remove(invoker.fns, wrappedHook); + } + + if (isUndef(oldHook)) { + // no existing hook + invoker = createFnInvoker([wrappedHook]); + } else { + /* istanbul ignore if */ + if (isDef(oldHook.fns) && isTrue(oldHook.merged)) { + // already a merged invoker + invoker = oldHook; + invoker.fns.push(wrappedHook); + } else { + // existing plain hook + invoker = createFnInvoker([oldHook, wrappedHook]); + } + } + + invoker.merged = true; + def[hookKey] = invoker; + } + + /* */ + + function extractPropsFromVNodeData ( + data, + Ctor, + tag + ) { + // we are only extracting raw values here. + // validation and default values are handled in the child + // component itself. + var propOptions = Ctor.options.props; + if (isUndef(propOptions)) { + return + } + var res = {}; + var attrs = data.attrs; + var props = data.props; + if (isDef(attrs) || isDef(props)) { + for (var key in propOptions) { + var altKey = hyphenate(key); + { + var keyInLowerCase = key.toLowerCase(); + if ( + key !== keyInLowerCase && + attrs && hasOwn(attrs, keyInLowerCase) + ) { + tip( + "Prop \"" + keyInLowerCase + "\" is passed to component " + + (formatComponentName(tag || Ctor)) + ", but the declared prop name is" + + " \"" + key + "\". " + + "Note that HTML attributes are case-insensitive and camelCased " + + "props need to use their kebab-case equivalents when using in-DOM " + + "templates. You should probably use \"" + altKey + "\" instead of \"" + key + "\"." + ); + } + } + checkProp(res, props, key, altKey, true) || + checkProp(res, attrs, key, altKey, false); + } + } + return res + } + + function checkProp ( + res, + hash, + key, + altKey, + preserve + ) { + if (isDef(hash)) { + if (hasOwn(hash, key)) { + res[key] = hash[key]; + if (!preserve) { + delete hash[key]; + } + return true + } else if (hasOwn(hash, altKey)) { + res[key] = hash[altKey]; + if (!preserve) { + delete hash[altKey]; + } + return true + } + } + return false + } + + /* */ + + // The template compiler attempts to minimize the need for normalization by + // statically analyzing the template at compile time. + // + // For plain HTML markup, normalization can be completely skipped because the + // generated render function is guaranteed to return Array. There are + // two cases where extra normalization is needed: + + // 1. When the children contains components - because a functional component + // may return an Array instead of a single root. In this case, just a simple + // normalization is needed - if any child is an Array, we flatten the whole + // thing with Array.prototype.concat. It is guaranteed to be only 1-level deep + // because functional components already normalize their own children. + function simpleNormalizeChildren (children) { + for (var i = 0; i < children.length; i++) { + if (Array.isArray(children[i])) { + return Array.prototype.concat.apply([], children) + } + } + return children + } + + // 2. When the children contains constructs that always generated nested Arrays, + // e.g.