rindy 2 gadi atpakaļ
vecāks
revīzija
1ef94f82d9
7 mainītis faili ar 442 papildinājumiem un 42 dzēšanām
  1. 1 0
      package.json
  2. 19 0
      public/smart-sviewer.html
  3. 1 1
      public/smart-viewer.html
  4. 351 0
      src/pages/SViewer.vue
  5. 41 0
      src/pages/sviewer.js
  6. 1 0
      vue.config.js
  7. 28 41
      yarn.lock

+ 1 - 0
package.json

@@ -9,6 +9,7 @@
   "dependencies": {
     "axios": "^0.21.1",
     "core-js": "^3.6.5",
+    "vant": "^3.6.4",
     "vue": "^3.2.26",
     "vue-i18n": "9",
     "vue-router": "4.0.12",

+ 19 - 0
public/smart-sviewer.html

@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html lang="en">
+    <head>
+        <title></title>
+        <meta charset="utf-8" />
+        <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0" />
+        <link rel="stylesheet" href="<%= VUE_APP_STATIC_DIR %>/lib/iconfont/iconfont.css" />
+        <link rel="stylesheet" href="//at.alicdn.com/t/c/font_3693743_qnz6eozqyvk.css" />
+        <script src="<%= VUE_APP_STATIC_DIR %>/lib/three.js/build/three.min.js"></script>
+        <script src="<%= VUE_APP_STATIC_DIR %>/lib/base64.min.js"></script>
+    </head>
+    <body>
+        <noscript>
+            <strong>We're sorry but doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
+        </noscript>
+        <div id="app"></div>
+    </body>
+ 
+</html>

+ 1 - 1
public/smart-viewer.html

@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html lang="en">
     <head>
-        <title>BIM</title>
+        <title></title>
         <meta charset="utf-8" />
         <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0" />
         <link rel="stylesheet" href="<%= VUE_APP_STATIC_DIR %>/lib/iconfont/iconfont.css" />

+ 351 - 0
src/pages/SViewer.vue

@@ -0,0 +1,351 @@
+<template>
+    <main>
+        <van-datetime-picker v-model="sourceDate" :filter="onFilter" type="date" title="选择年月日" />
+    </main>
+</template>
+
+<script setup>
+import { ref, onMounted, computed, nextTick } from 'vue'
+import { http } from '@/utils/request'
+import browser from '@/utils/browser'
+import sync, { loadSourceScene, loadTargetScene } from '@/utils/sync'
+
+// 是否校准模式
+const showSplit = ref(browser.urlHasValue('split'))
+const showAdjust = ref(browser.urlHasValue('adjust'))
+
+const bimChecked = ref(null)
+const dbsChecked = ref(null)
+const fscChecked = ref(null)
+
+const datepickName = ref(null)
+
+const sourceFrame = ref(null)
+const targetFrame = ref(null)
+
+const mode = ref(0)
+const source = ref(null)
+const target = ref(null)
+const project = ref(null)
+const points = ref({ p1: false, p2: false })
+
+const scenes = computed(() => {
+    if (!project.value) {
+        return []
+    }
+    return project.value.sceneList.map(item => {
+        return {
+            num: item.num,
+            type: item.type,
+            createTime: item.createTime,
+        }
+    })
+})
+const sourceURL = computed(() => {
+    if (bimChecked.value && !dbsChecked.value) {
+        return `smart-bim.html?m=${source.value.num}`
+    }
+
+    if (source.value.type < 2) {
+        // 看看、看见场景
+        return `smart-kankan.html?m=${source.value.num}&dev`
+    } else {
+        // 深时场景
+        return `smart-laser.html?m=${source.value.num}&dev`
+    }
+})
+const targetURL = computed(() => {
+    if (bimChecked.value) {
+        return `smart-bim.html?m=${target.value.num}`
+    }
+
+    if (source.value.type < 2) {
+        // 看看、看见场景
+        return `smart-kankan.html?m=${target.value.num}&dev`
+    } else {
+        // 深时场景
+        return `smart-laser.html?m=${target.value.num}&dev`
+    }
+})
+const sourceDate = computed(() => {
+    if (source.value) {
+        return source.value.createTime.toDate()
+    }
+})
+
+const targetDate = computed(() => {
+    if (target.value) {
+        return target.value.createTime.toDate()
+    }
+})
+
+const sourceDays = computed(() => {
+    let dates = []
+    if (datepickName.value == 'source') {
+        if (dbsChecked.value) {
+            // 分屏模式
+            if (bimChecked.value) {
+                // BIM模式
+                dates = scenes.value.map(item => item.createTime.toDate())
+            } else {
+                // 非BIM模式
+                dates = scenes.value.filter(item => item.createTime != target.value.createTime).map(item => item.createTime.toDate())
+            }
+        } else {
+            // 非分屏模式
+            dates = scenes.value.map(item => item.createTime.toDate())
+        }
+    }
+    return {
+        dates: dates,
+    }
+})
+
+const targetDays = computed(() => {
+    let dates = []
+    if (datepickName.value == 'target') {
+        dates = scenes.value.filter(item => item.createTime != source.value.createTime).map(item => item.createTime.toDate())
+    }
+    return {
+        dates: dates,
+    }
+})
+const onFilter = (type, options)=> {
+    console.log(type,options)
+}
+const onLoadSource = () => {
+    if (bimChecked.value && !dbsChecked.value) {
+        // BIM单屏模式
+        return
+    }
+
+    loadSourceScene(sourceFrame, source.value.type < 2 ? 'kankan' : 'laser')
+}
+const onLoadTarget = () => {
+    if (bimChecked.value) {
+        loadTargetScene(targetFrame, 'bim')
+    } else {
+        loadTargetScene(targetFrame, target.value.type < 2 ? 'kankan' : 'laser', mode.value)
+    }
+}
+
+const onModeChange = targetMode => {
+    if (sync.sourceInst) {
+        sync.sourceInst.loaded.then(sdk => sdk.scene.changeMode(targetMode))
+        mode.value = targetMode
+    }
+}
+const onPickDate = name => {
+    datepickName.value = name
+}
+
+const onSelected = data => {
+    if (!data.payload) {
+        return
+    }
+    let { name, payload } = data
+    let date = payload.format('YYYY-mm-dd')
+    let dates = (name == 'source' ? sourceDays : targetDays).value.dates.map(item => item.format('YYYY-mm-dd'))
+
+    if (dates.indexOf(date) != -1) {
+        let time = payload.format('YYYY-mm-dd HH:MM')
+        let find = scenes.value.find(c => c.createTime.indexOf(time) != -1)
+        if (find) {
+            if (name == 'source') {
+                if (find.num != source.value.num) {
+                    source.value = find
+                }
+            } else {
+                if (find.num != target.value.num) {
+                    target.value = find
+                }
+            }
+        }
+    }
+
+    datepickName.value = null
+}
+
+const onPrevDate = name => {
+    let scene = null
+    if (name == 'source') {
+        scene = source
+    } else {
+        scene = target
+    }
+    let index = scenes.value.findIndex(item => item.num == scene.value.num)
+    if (index == -1) {
+        return
+    }
+    if (--index == -1) {
+        index = scenes.value.length - 1
+    }
+
+    if (target.value) {
+        // 分屏模式判断
+        if (name == 'source') {
+            if (scenes.value[index].createTime == target.value.createTime) {
+                index--
+            }
+        } else {
+            if (scenes.value[index].createTime == source.value.createTime) {
+                index--
+            }
+        }
+        if (index == -1) {
+            index = scenes.value.length - 1
+        }
+    }
+
+    scene.value = scenes.value[index]
+}
+const onNextDate = name => {
+    let scene = null
+    if (name == 'source') {
+        scene = source
+    } else {
+        scene = target
+    }
+    let index = scenes.value.findIndex(item => item.num == scene.value.num)
+    if (index == -1) {
+        return
+    }
+    if (++index > scenes.value.length - 1) {
+        index = 0
+    }
+
+    if (target.value) {
+        // 分屏模式判断
+        if (name == 'source') {
+            if (scenes.value[index].createTime == target.value.createTime) {
+                index++
+            }
+        } else {
+            if (scenes.value[index].createTime == source.value.createTime) {
+                index++
+            }
+        }
+
+        if (index > scenes.value.length - 1) {
+            index = 0
+        }
+    }
+
+    scene.value = scenes.value[index]
+}
+
+// bim点击
+const onBimChecked = () => {
+    if (bimChecked.value) {
+        bimChecked.value = false
+        if (dbsChecked.value) {
+            // 判断是否分屏状态
+            let index = scenes.value.findIndex(item => item.num == source.value.num)
+            if (index == -1) {
+                return
+            }
+            if (++index > scenes.value.length - 1) {
+                index = 0
+            }
+            target.value = scenes.value[index]
+        }
+    } else {
+        bimChecked.value = true
+    }
+}
+
+// 分屏点击
+const onDbsChecked = () => {
+    dbsChecked.value = !dbsChecked.value
+    if (dbsChecked.value) {
+        if (bimChecked.value) {
+            // BIM分屏
+            source.value = scenes.value[0]
+            target.value = project.value.bimData
+        } else {
+            // 四维看看、激光场景分屏
+            let index = scenes.value.findIndex(item => item.num == source.value.num)
+            if (index == -1) {
+                return
+            }
+            if (++index > scenes.value.length - 1) {
+                index = 0
+            }
+            target.value = scenes.value[index]
+        }
+    } else {
+        target.value = null
+        targetApp = null
+        views.clear()
+    }
+}
+
+// 全屏点击
+const onFscChecked = () => {
+    let element = document.documentElement
+
+    fscChecked.value = !fscChecked.value
+
+    if (fscChecked.value) {
+        if (element.requestFullscreen) {
+            element.requestFullscreen()
+        } else if (element.webkitRequestFullScreen) {
+            element.webkitRequestFullScreen()
+        } else if (element.mozRequestFullScreen) {
+            element.mozRequestFullScreen()
+        } else if (element.msRequestFullscreen) {
+            element.msRequestFullscreen()
+        }
+    } else {
+        if (document.exitFullscreen) {
+            document.exitFullscreen()
+        } else if (document.webkitCancelFullScreen) {
+            document.webkitCancelFullScreen()
+        } else if (document.mozCancelFullScreen) {
+            document.mozCancelFullScreen()
+        } else if (document.msExitFullscreen) {
+            document.msExitFullscreen()
+        }
+    }
+}
+
+const onPointsUpdate = type => {
+    points.value[type] = true
+}
+
+onMounted(() => {
+    const projectId = browser.valueFromUrl('projectId') || 1
+    http.get(`smart-site/project/info?projectId=${projectId}`)
+        .then(response => {
+            if (response.success) {
+                project.value = response.data
+                if (project.value.sceneList.length) {
+                    source.value = project.value.sceneList[0]
+                    if (showAdjust.value || showSplit.value) {
+                        onBimChecked()
+                        nextTick(() => onDbsChecked())
+                    }
+                }
+            } else {
+                alert('获取数据失败')
+            }
+        })
+        .catch(() => {
+            alert('服务器连接失败')
+        })
+})
+</script>
+
+<style lang="scss" scoped>
+main{
+    width: 100%;
+    height: 100%;
+}
+</style>
+<style lang="scss">
+#app {
+    background-color: rgba(0, 0, 0, 0.8);
+    display: flex;
+    flex-direction: column;
+}
+</style>

+ 41 - 0
src/pages/sviewer.js

@@ -0,0 +1,41 @@
+import '../assets/index.scss'
+import 'vant/lib/index.css';
+import { createApp } from 'vue'
+import { DatetimePicker } from 'vant';
+import { setup } from '../utils/request'
+import App from './SViewer.vue'
+
+Date.prototype.format = function(fmt = 'YYYY-mm-dd HH:MM:SS') {
+    var res = ''
+    try {
+        var date = this
+        var opt = {
+            'Y+': date.getFullYear().toString(), // 年
+            'm+': (date.getMonth() + 1).toString(), // 月
+            'd+': date.getDate().toString(), // 日
+            'H+': date.getHours().toString(), // 时
+            'M+': date.getMinutes().toString(), // 分
+            'S+': date.getSeconds().toString() // 秒
+        }
+        for (var k in opt) {
+            var ret = new RegExp('(' + k + ')').exec(fmt)
+            if (ret) {
+                fmt = fmt.replace(ret[1], ret[1].length == 1 ? opt[k] : opt[k].padStart(ret[1].length, '0'))
+            }
+        }
+        res = fmt
+    } catch (error) {
+        logger.warn('ERROR formatDate', error)
+    }
+    return res
+}
+
+String.prototype.toDate = function() {
+    if (!this) {
+        return null
+    }
+    return new Date(this.replace(/\//g, '-').replace(' ', 'T'))
+}
+
+setup()
+createApp(App).use(DatetimePicker).mount('#app')

+ 1 - 0
vue.config.js

@@ -36,6 +36,7 @@ const config = {
         'smart-kankan': 'src/pages/kankan.js',
         'smart-laser': 'src/pages/laser.js',
         'smart-viewer': 'src/pages/viewer.js',
+        'smart-sviewer': 'src/pages/sviewer.js',
     },
     css: {
         extract: false,

+ 28 - 41
yarn.lock

@@ -1284,6 +1284,21 @@
     anymatch "^3.0.0"
     source-map "^0.6.0"
 
+"@vant/icons@^1.8.0":
+  version "1.8.0"
+  resolved "https://registry.npmmirror.com/@vant/icons/-/icons-1.8.0.tgz#36b13f2e628b533f6523a93a168cf02f07056674"
+  integrity sha512-sKfEUo2/CkQFuERxvkuF6mGQZDKu3IQdj5rV9Fm0weJXtchDSSQ+zt8qPCNUEhh9Y8shy5PzxbvAfOOkCwlCXg==
+
+"@vant/popperjs@^1.2.1":
+  version "1.3.0"
+  resolved "https://registry.npmmirror.com/@vant/popperjs/-/popperjs-1.3.0.tgz#e0eff017124b5b2352ef3b36a6df06277f4400f2"
+  integrity sha512-hB+czUG+aHtjhaEmCJDuXOep0YTZjdlRR+4MSmIFnkCQIxJaXLQdSsR90XWvAI2yvKUI7TCGqR8pQg2RtvkMHw==
+
+"@vant/use@^1.4.2":
+  version "1.4.3"
+  resolved "https://registry.npmmirror.com/@vant/use/-/use-1.4.3.tgz#0c542fe01a1439878e4aa8779d1791e189610d30"
+  integrity sha512-rSnETN7P9qT1WbItMpQxBqe3cHeK2ZFYp1sCxWUXaTeI71TqA8sOdzC36ledZ36NQgFNTch9fsRPYOkrCgZfQA==
+
 "@vue/babel-helper-vue-jsx-merge-props@^1.4.0":
   version "1.4.0"
   resolved "https://registry.npmmirror.com/@vue/babel-helper-vue-jsx-merge-props/-/babel-helper-vue-jsx-merge-props-1.4.0.tgz#8d53a1e21347db8edbe54d339902583176de09f2"
@@ -6105,7 +6120,7 @@ picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1:
   resolved "https://registry.npmmirror.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
   integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
 
-pify@^2.0.0, pify@^2.3.0:
+pify@^2.0.0:
   version "2.3.0"
   resolved "https://registry.npmmirror.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
   integrity sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==
@@ -6223,15 +6238,6 @@ postcss-discard-overridden@^4.0.1:
   dependencies:
     postcss "^7.0.0"
 
-postcss-import@^15.0.0:
-  version "15.0.0"
-  resolved "https://registry.npmmirror.com/postcss-import/-/postcss-import-15.0.0.tgz#0b66c25fdd9c0d19576e63c803cf39e4bad08822"
-  integrity sha512-Y20shPQ07RitgBGv2zvkEAu9bqvrD77C9axhj/aA1BQj4czape2MdClCExvB27EwYEJdGgKZBpKanb0t1rK2Kg==
-  dependencies:
-    postcss-value-parser "^4.0.0"
-    read-cache "^1.0.0"
-    resolve "^1.1.7"
-
 postcss-load-config@^2.0.0:
   version "2.1.2"
   resolved "https://registry.npmmirror.com/postcss-load-config/-/postcss-load-config-2.1.2.tgz#c5ea504f2c4aef33c7359a34de3573772ad7502a"
@@ -6345,13 +6351,6 @@ postcss-modules-values@^3.0.0:
     icss-utils "^4.0.0"
     postcss "^7.0.6"
 
-postcss-nested@^6.0.0:
-  version "6.0.0"
-  resolved "https://registry.npmmirror.com/postcss-nested/-/postcss-nested-6.0.0.tgz#1572f1984736578f360cffc7eb7dca69e30d1735"
-  integrity sha512-0DkamqrPcmkBDsLn+vQDIrtkSbNkv5AD/M322ySo9kqFkCIYklym2xEmWkwo+Y3/qZo34tzEPNUw4y7yMCdv5w==
-  dependencies:
-    postcss-selector-parser "^6.0.10"
-
 postcss-normalize-charset@^4.0.1:
   version "4.0.1"
   resolved "https://registry.npmmirror.com/postcss-normalize-charset/-/postcss-normalize-charset-4.0.1.tgz#8b35add3aee83a136b0471e0d59be58a50285dd4"
@@ -6471,7 +6470,7 @@ postcss-selector-parser@^3.0.0:
     indexes-of "^1.0.1"
     uniq "^1.0.1"
 
-postcss-selector-parser@^6.0.0, postcss-selector-parser@^6.0.10, postcss-selector-parser@^6.0.2:
+postcss-selector-parser@^6.0.0, postcss-selector-parser@^6.0.2:
   version "6.0.10"
   resolved "https://registry.npmmirror.com/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz#79b61e2c0d1bfc2602d549e11d0876256f8df88d"
   integrity sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==
@@ -6479,11 +6478,6 @@ postcss-selector-parser@^6.0.0, postcss-selector-parser@^6.0.10, postcss-selecto
     cssesc "^3.0.0"
     util-deprecate "^1.0.2"
 
-postcss-simple-vars@^7.0.0:
-  version "7.0.0"
-  resolved "https://registry.npmmirror.com/postcss-simple-vars/-/postcss-simple-vars-7.0.0.tgz#f1d10a979762aa4e7e3450a35a32885112893d1b"
-  integrity sha512-SPSkKQK7mKjD/tqcTbZkDi3KP+C/cTGXnKQmSt3AisJtnZE6ZxHEUoOGRfpV0B5dW1Y36EETfRHx10WLHpXThA==
-
 postcss-svgo@^4.0.3:
   version "4.0.3"
   resolved "https://registry.npmmirror.com/postcss-svgo/-/postcss-svgo-4.0.3.tgz#343a2cdbac9505d416243d496f724f38894c941e"
@@ -6507,7 +6501,7 @@ postcss-value-parser@^3.0.0:
   resolved "https://registry.npmmirror.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz#9ff822547e2893213cf1c30efa51ac5fd1ba8281"
   integrity sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==
 
-postcss-value-parser@^4.0.0, postcss-value-parser@^4.0.2, postcss-value-parser@^4.1.0:
+postcss-value-parser@^4.0.2, postcss-value-parser@^4.1.0:
   version "4.2.0"
   resolved "https://registry.npmmirror.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514"
   integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==
@@ -6529,15 +6523,6 @@ postcss@^8.1.10:
     picocolors "^1.0.0"
     source-map-js "^1.0.2"
 
-postcss@^8.4.17:
-  version "8.4.17"
-  resolved "https://registry.npmmirror.com/postcss/-/postcss-8.4.17.tgz#f87863ec7cd353f81f7ab2dec5d67d861bbb1be5"
-  integrity sha512-UNxNOLQydcOFi41yHNMcKRZ39NeXlr8AxGuZJsdub8vIb12fHzcq37DTU/QtbI6WLxNg2gF9Z+8qtRwTj1UI1Q==
-  dependencies:
-    nanoid "^3.3.4"
-    picocolors "^1.0.0"
-    source-map-js "^1.0.2"
-
 prepend-http@^1.0.0:
   version "1.0.4"
   resolved "https://registry.npmmirror.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc"
@@ -6721,13 +6706,6 @@ raw-body@2.5.1:
     iconv-lite "0.4.24"
     unpipe "1.0.0"
 
-read-cache@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.npmmirror.com/read-cache/-/read-cache-1.0.0.tgz#e664ef31161166c9751cdbe8dbcf86b5fb58f774"
-  integrity sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==
-  dependencies:
-    pify "^2.3.0"
-
 read-pkg@^5.1.1:
   version "5.2.0"
   resolved "https://registry.npmmirror.com/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc"
@@ -6930,7 +6908,7 @@ resolve-url@^0.2.1:
   resolved "https://registry.npmmirror.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
   integrity sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==
 
-resolve@^1.1.7, resolve@^1.10.0, resolve@^1.14.2:
+resolve@^1.10.0, resolve@^1.14.2:
   version "1.22.1"
   resolved "https://registry.npmmirror.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177"
   integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==
@@ -8041,6 +8019,15 @@ validate-npm-package-license@^3.0.1:
     spdx-correct "^3.0.0"
     spdx-expression-parse "^3.0.0"
 
+vant@^3.6.4:
+  version "3.6.4"
+  resolved "https://registry.npmmirror.com/vant/-/vant-3.6.4.tgz#939a0101a2938479ef77c121b21ba98ac31285a2"
+  integrity sha512-IgPzekX7YGoqf7h/jx75F087lsBEWA/cQfRqPVgiR6cyqrmi8+dfpfFTz2OcPZ755avTzKk3L0WaclXIbHnVeQ==
+  dependencies:
+    "@vant/icons" "^1.8.0"
+    "@vant/popperjs" "^1.2.1"
+    "@vant/use" "^1.4.2"
+
 vary@~1.1.2:
   version "1.1.2"
   resolved "https://registry.npmmirror.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"