diff --git a/frontend/karma.conf.js b/frontend/karma.conf.js index 397158de6..a0293106a 100644 --- a/frontend/karma.conf.js +++ b/frontend/karma.conf.js @@ -24,7 +24,7 @@ module.exports = (config) => { files: [ {pattern: "tests/unit/**/*_test.js", watched: false}, - 'node_modules/@babel/polyfill/dist/polyfill.js', + "node_modules/@babel/polyfill/dist/polyfill.js", ], // Preprocess through webpack diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 16dcf15b7..82b2be775 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -5,9 +5,9 @@ "requires": true, "dependencies": { "@babel/cli": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.7.4.tgz", - "integrity": "sha512-O7mmzaWdm+VabWQmxuM8hqNrWGGihN83KfhPUzp2lAW4kzIMwBxujXkZbD4fMwKMYY9FXTbDvXsJqU+5XHXi4A==", + "version": "7.7.5", + "resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.7.5.tgz", + "integrity": "sha512-y2YrMGXM3NUyu1Myg0pxg+Lx6g8XhEyvLHYNRwTBV6fDek3H7Io6b7N/LXscLs4HWn4HxMdy7f2rM1rTMp2mFg==", "requires": { "chokidar": "^2.1.8", "commander": "^4.0.1", @@ -36,14 +36,14 @@ } }, "@babel/core": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.7.4.tgz", - "integrity": "sha512-+bYbx56j4nYBmpsWtnPUsKW3NdnYxbqyfrP2w9wILBuHzdfIKz9prieZK0DFPyIzkjYVUe4QkusGL07r5pXznQ==", + "version": "7.7.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.7.5.tgz", + "integrity": "sha512-M42+ScN4+1S9iB6f+TL7QBpoQETxbclx+KNoKJABghnKYE+fMzSGqst0BZJc8CpI625bwPwYgUyRvxZ+0mZzpw==", "requires": { "@babel/code-frame": "^7.5.5", "@babel/generator": "^7.7.4", "@babel/helpers": "^7.7.4", - "@babel/parser": "^7.7.4", + "@babel/parser": "^7.7.5", "@babel/template": "^7.7.4", "@babel/traverse": "^7.7.4", "@babel/types": "^7.7.4", @@ -102,9 +102,9 @@ } }, "@babel/parser": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.4.tgz", - "integrity": "sha512-jIwvLO0zCL+O/LmEJQjWA75MQTWwx3c3u2JOTDK5D3/9egrWRRA0/0hk9XXywYnXZVVpzrBYeIQTmhwUaePI9g==" + "version": "7.7.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.5.tgz", + "integrity": "sha512-KNlOe9+/nk4i29g0VXgl8PEXIRms5xKLJeuZ6UptN0fHv+jDiriG+y94X6qAgWTR0h3KaoM1wK5G5h7MHFRSig==" }, "@babel/template": { "version": "7.7.4", @@ -274,9 +274,9 @@ } }, "@babel/parser": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.4.tgz", - "integrity": "sha512-jIwvLO0zCL+O/LmEJQjWA75MQTWwx3c3u2JOTDK5D3/9egrWRRA0/0hk9XXywYnXZVVpzrBYeIQTmhwUaePI9g==" + "version": "7.7.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.5.tgz", + "integrity": "sha512-KNlOe9+/nk4i29g0VXgl8PEXIRms5xKLJeuZ6UptN0fHv+jDiriG+y94X6qAgWTR0h3KaoM1wK5G5h7MHFRSig==" }, "@babel/template": { "version": "7.7.4", @@ -367,9 +367,9 @@ } }, "@babel/parser": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.4.tgz", - "integrity": "sha512-jIwvLO0zCL+O/LmEJQjWA75MQTWwx3c3u2JOTDK5D3/9egrWRRA0/0hk9XXywYnXZVVpzrBYeIQTmhwUaePI9g==" + "version": "7.7.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.5.tgz", + "integrity": "sha512-KNlOe9+/nk4i29g0VXgl8PEXIRms5xKLJeuZ6UptN0fHv+jDiriG+y94X6qAgWTR0h3KaoM1wK5G5h7MHFRSig==" }, "@babel/template": { "version": "7.7.4", @@ -448,9 +448,9 @@ } }, "@babel/parser": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.4.tgz", - "integrity": "sha512-jIwvLO0zCL+O/LmEJQjWA75MQTWwx3c3u2JOTDK5D3/9egrWRRA0/0hk9XXywYnXZVVpzrBYeIQTmhwUaePI9g==" + "version": "7.7.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.5.tgz", + "integrity": "sha512-KNlOe9+/nk4i29g0VXgl8PEXIRms5xKLJeuZ6UptN0fHv+jDiriG+y94X6qAgWTR0h3KaoM1wK5G5h7MHFRSig==" }, "@babel/template": { "version": "7.7.4", @@ -582,9 +582,9 @@ } }, "@babel/helper-module-transforms": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.7.4.tgz", - "integrity": "sha512-ehGBu4mXrhs0FxAqN8tWkzF8GSIGAiEumu4ONZ/hD9M88uHcD+Yu2ttKfOCgwzoesJOJrtQh7trI5YPbRtMmnA==", + "version": "7.7.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.7.5.tgz", + "integrity": "sha512-A7pSxyJf1gN5qXVcidwLWydjftUN878VkalhXX5iQDuGyiGK3sOrrKKHF4/A4fwHtnsotv/NipwAeLzY4KQPvw==", "requires": { "@babel/helper-module-imports": "^7.7.4", "@babel/helper-simple-access": "^7.7.4", @@ -603,9 +603,9 @@ } }, "@babel/parser": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.4.tgz", - "integrity": "sha512-jIwvLO0zCL+O/LmEJQjWA75MQTWwx3c3u2JOTDK5D3/9egrWRRA0/0hk9XXywYnXZVVpzrBYeIQTmhwUaePI9g==" + "version": "7.7.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.5.tgz", + "integrity": "sha512-KNlOe9+/nk4i29g0VXgl8PEXIRms5xKLJeuZ6UptN0fHv+jDiriG+y94X6qAgWTR0h3KaoM1wK5G5h7MHFRSig==" }, "@babel/template": { "version": "7.7.4", @@ -712,9 +712,9 @@ } }, "@babel/parser": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.4.tgz", - "integrity": "sha512-jIwvLO0zCL+O/LmEJQjWA75MQTWwx3c3u2JOTDK5D3/9egrWRRA0/0hk9XXywYnXZVVpzrBYeIQTmhwUaePI9g==" + "version": "7.7.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.5.tgz", + "integrity": "sha512-KNlOe9+/nk4i29g0VXgl8PEXIRms5xKLJeuZ6UptN0fHv+jDiriG+y94X6qAgWTR0h3KaoM1wK5G5h7MHFRSig==" }, "@babel/template": { "version": "7.7.4", @@ -834,9 +834,9 @@ } }, "@babel/parser": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.4.tgz", - "integrity": "sha512-jIwvLO0zCL+O/LmEJQjWA75MQTWwx3c3u2JOTDK5D3/9egrWRRA0/0hk9XXywYnXZVVpzrBYeIQTmhwUaePI9g==" + "version": "7.7.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.5.tgz", + "integrity": "sha512-KNlOe9+/nk4i29g0VXgl8PEXIRms5xKLJeuZ6UptN0fHv+jDiriG+y94X6qAgWTR0h3KaoM1wK5G5h7MHFRSig==" }, "@babel/template": { "version": "7.7.4", @@ -899,9 +899,9 @@ }, "dependencies": { "@babel/parser": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.4.tgz", - "integrity": "sha512-jIwvLO0zCL+O/LmEJQjWA75MQTWwx3c3u2JOTDK5D3/9egrWRRA0/0hk9XXywYnXZVVpzrBYeIQTmhwUaePI9g==" + "version": "7.7.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.5.tgz", + "integrity": "sha512-KNlOe9+/nk4i29g0VXgl8PEXIRms5xKLJeuZ6UptN0fHv+jDiriG+y94X6qAgWTR0h3KaoM1wK5G5h7MHFRSig==" }, "@babel/template": { "version": "7.7.4", @@ -982,9 +982,9 @@ } }, "@babel/parser": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.4.tgz", - "integrity": "sha512-jIwvLO0zCL+O/LmEJQjWA75MQTWwx3c3u2JOTDK5D3/9egrWRRA0/0hk9XXywYnXZVVpzrBYeIQTmhwUaePI9g==" + "version": "7.7.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.5.tgz", + "integrity": "sha512-KNlOe9+/nk4i29g0VXgl8PEXIRms5xKLJeuZ6UptN0fHv+jDiriG+y94X6qAgWTR0h3KaoM1wK5G5h7MHFRSig==" }, "@babel/template": { "version": "7.7.4", @@ -1095,9 +1095,9 @@ } }, "@babel/parser": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.4.tgz", - "integrity": "sha512-jIwvLO0zCL+O/LmEJQjWA75MQTWwx3c3u2JOTDK5D3/9egrWRRA0/0hk9XXywYnXZVVpzrBYeIQTmhwUaePI9g==" + "version": "7.7.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.5.tgz", + "integrity": "sha512-KNlOe9+/nk4i29g0VXgl8PEXIRms5xKLJeuZ6UptN0fHv+jDiriG+y94X6qAgWTR0h3KaoM1wK5G5h7MHFRSig==" }, "@babel/template": { "version": "7.7.4", @@ -1367,9 +1367,9 @@ } }, "@babel/parser": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.4.tgz", - "integrity": "sha512-jIwvLO0zCL+O/LmEJQjWA75MQTWwx3c3u2JOTDK5D3/9egrWRRA0/0hk9XXywYnXZVVpzrBYeIQTmhwUaePI9g==" + "version": "7.7.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.5.tgz", + "integrity": "sha512-KNlOe9+/nk4i29g0VXgl8PEXIRms5xKLJeuZ6UptN0fHv+jDiriG+y94X6qAgWTR0h3KaoM1wK5G5h7MHFRSig==" }, "@babel/template": { "version": "7.7.4", @@ -1471,9 +1471,9 @@ } }, "@babel/parser": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.4.tgz", - "integrity": "sha512-jIwvLO0zCL+O/LmEJQjWA75MQTWwx3c3u2JOTDK5D3/9egrWRRA0/0hk9XXywYnXZVVpzrBYeIQTmhwUaePI9g==" + "version": "7.7.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.5.tgz", + "integrity": "sha512-KNlOe9+/nk4i29g0VXgl8PEXIRms5xKLJeuZ6UptN0fHv+jDiriG+y94X6qAgWTR0h3KaoM1wK5G5h7MHFRSig==" }, "@babel/template": { "version": "7.7.4", @@ -1514,21 +1514,21 @@ } }, "@babel/plugin-transform-modules-amd": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.7.4.tgz", - "integrity": "sha512-/542/5LNA18YDtg1F+QHvvUSlxdvjZoD/aldQwkq+E3WCkbEjNSN9zdrOXaSlfg3IfGi22ijzecklF/A7kVZFQ==", + "version": "7.7.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.7.5.tgz", + "integrity": "sha512-CT57FG4A2ZUNU1v+HdvDSDrjNWBrtCmSH6YbbgN3Lrf0Di/q/lWRxZrE72p3+HCCz9UjfZOEBdphgC0nzOS6DQ==", "requires": { - "@babel/helper-module-transforms": "^7.7.4", + "@babel/helper-module-transforms": "^7.7.5", "@babel/helper-plugin-utils": "^7.0.0", "babel-plugin-dynamic-import-node": "^2.3.0" } }, "@babel/plugin-transform-modules-commonjs": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.7.4.tgz", - "integrity": "sha512-k8iVS7Jhc367IcNF53KCwIXtKAH7czev866ThsTgy8CwlXjnKZna2VHwChglzLleYrcHz1eQEIJlGRQxB53nqA==", + "version": "7.7.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.7.5.tgz", + "integrity": "sha512-9Cq4zTFExwFhQI6MT1aFxgqhIsMWQWDVwOgLzl7PTWJHsNaqFvklAU+Oz6AQLAS0dJKTwZSOCo20INwktxpi3Q==", "requires": { - "@babel/helper-module-transforms": "^7.7.4", + "@babel/helper-module-transforms": "^7.7.5", "@babel/helper-plugin-utils": "^7.0.0", "@babel/helper-simple-access": "^7.7.4", "babel-plugin-dynamic-import-node": "^2.3.0" @@ -1617,9 +1617,9 @@ } }, "@babel/plugin-transform-regenerator": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.7.4.tgz", - "integrity": "sha512-e7MWl5UJvmPEwFJTwkBlPmqixCtr9yAASBqff4ggXTNicZiwbF8Eefzm6NVgfiBp7JdAGItecnctKTgH44q2Jw==", + "version": "7.7.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.7.5.tgz", + "integrity": "sha512-/8I8tPvX2FkuEyWbjRCt4qTAgZK0DVy8QRguhA524UH48RfGJy94On2ri+dCuwOpcerPRl9O4ebQkRcVzIaGBw==", "requires": { "regenerator-transform": "^0.14.0" } @@ -1633,9 +1633,9 @@ } }, "@babel/plugin-transform-runtime": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.7.4.tgz", - "integrity": "sha512-O8kSkS5fP74Ad/8pfsCMGa8sBRdLxYoSReaARRNSz3FbFQj3z/QUvoUmJ28gn9BO93YfnXc3j+Xyaqe8cKDNBQ==", + "version": "7.7.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.7.6.tgz", + "integrity": "sha512-tajQY+YmXR7JjTwRvwL4HePqoL3DYxpYXIHKVvrOIvJmeHe2y1w4tz5qz9ObUDC9m76rCzIMPyn4eERuwA4a4A==", "requires": { "@babel/helper-module-imports": "^7.7.4", "@babel/helper-plugin-utils": "^7.0.0", @@ -1711,9 +1711,9 @@ } }, "@babel/preset-env": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.7.4.tgz", - "integrity": "sha512-Dg+ciGJjwvC1NIe/DGblMbcGq1HOtKbw8RLl4nIjlfcILKEOkWT/vRqPpumswABEBVudii6dnVwrBtzD7ibm4g==", + "version": "7.7.6", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.7.6.tgz", + "integrity": "sha512-k5hO17iF/Q7tR9Jv8PdNBZWYW6RofxhnxKjBMc0nG4JTaWvOTiPoO/RLFwAKcA4FpmuBFm6jkoqaRJLGi0zdaQ==", "requires": { "@babel/helper-module-imports": "^7.7.4", "@babel/helper-plugin-utils": "^7.0.0", @@ -1743,8 +1743,8 @@ "@babel/plugin-transform-function-name": "^7.7.4", "@babel/plugin-transform-literals": "^7.7.4", "@babel/plugin-transform-member-expression-literals": "^7.7.4", - "@babel/plugin-transform-modules-amd": "^7.7.4", - "@babel/plugin-transform-modules-commonjs": "^7.7.4", + "@babel/plugin-transform-modules-amd": "^7.7.5", + "@babel/plugin-transform-modules-commonjs": "^7.7.5", "@babel/plugin-transform-modules-systemjs": "^7.7.4", "@babel/plugin-transform-modules-umd": "^7.7.4", "@babel/plugin-transform-named-capturing-groups-regex": "^7.7.4", @@ -1752,7 +1752,7 @@ "@babel/plugin-transform-object-super": "^7.7.4", "@babel/plugin-transform-parameters": "^7.7.4", "@babel/plugin-transform-property-literals": "^7.7.4", - "@babel/plugin-transform-regenerator": "^7.7.4", + "@babel/plugin-transform-regenerator": "^7.7.5", "@babel/plugin-transform-reserved-words": "^7.7.4", "@babel/plugin-transform-shorthand-properties": "^7.7.4", "@babel/plugin-transform-spread": "^7.7.4", @@ -1762,7 +1762,7 @@ "@babel/plugin-transform-unicode-regex": "^7.7.4", "@babel/types": "^7.7.4", "browserslist": "^4.6.0", - "core-js-compat": "^3.1.1", + "core-js-compat": "^3.4.7", "invariant": "^2.2.2", "js-levenshtein": "^1.1.3", "semver": "^5.5.0" @@ -2017,19 +2017,19 @@ } }, "@vue/component-compiler-utils": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@vue/component-compiler-utils/-/component-compiler-utils-1.3.1.tgz", - "integrity": "sha512-IyjJW6ToMitgAhp3xh22QiEW8JvHfLyzlyY/J+GjJ71miod9tNsy6xT2ckm/VirlhPMfeM43kgYZe34jhmmzpw==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@vue/component-compiler-utils/-/component-compiler-utils-2.6.0.tgz", + "integrity": "sha512-IHjxt7LsOFYc0DkTncB7OXJL7UzwOLPPQCfEUNyxL2qt+tF12THV+EO33O1G2Uk4feMSWua3iD39Itszx0f0bw==", "requires": { "consolidate": "^0.15.1", "hash-sum": "^1.0.2", "lru-cache": "^4.1.2", "merge-source-map": "^1.1.0", - "postcss": "^6.0.20", - "postcss-selector-parser": "^3.1.1", - "prettier": "^1.13.0", - "source-map": "^0.5.6", - "vue-template-es2015-compiler": "^1.6.0" + "postcss": "^7.0.14", + "postcss-selector-parser": "^5.0.0", + "prettier": "1.16.3", + "source-map": "~0.6.1", + "vue-template-es2015-compiler": "^1.9.0" }, "dependencies": { "consolidate": { @@ -2040,32 +2040,30 @@ "bluebird": "^3.1.1" } }, - "postcss": { - "version": "6.0.23", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz", - "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==", - "requires": { - "chalk": "^2.4.1", - "source-map": "^0.6.1", - "supports-color": "^5.4.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } + "cssesc": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-2.0.0.tgz", + "integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==" }, "postcss-selector-parser": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.1.tgz", - "integrity": "sha1-T4dfSvsMllc9XPTXQBGu4lCn6GU=", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz", + "integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==", "requires": { - "dot-prop": "^4.1.1", + "cssesc": "^2.0.0", "indexes-of": "^1.0.1", "uniq": "^1.0.1" } + }, + "prettier": { + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.16.3.tgz", + "integrity": "sha512-kn/GU6SMRYPxUakNXhpP0EedT/KmaPzr0H5lIsDogrykbaxOpOfAFfk5XA7DZrJyMAv1wlMV3CPcZruGXVVUZw==" + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" } } }, @@ -2252,49 +2250,27 @@ "integrity": "sha512-gac8OEcQ2Li1dxIEWGZzsp2BitJxwkwcOm0zHAJLcPJaVvm58FRnk6RkuLRpU1EujipU2ZFODv2P9DLMfnV8mw==" }, "acorn-bigint": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/acorn-bigint/-/acorn-bigint-0.2.0.tgz", - "integrity": "sha1-D0WlKQU3eZo7BwhWiaGGiBy1N4Q=", - "requires": { - "acorn": "^5.2.1" - }, - "dependencies": { - "acorn": { - "version": "5.7.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", - "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==" - } - } + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/acorn-bigint/-/acorn-bigint-0.3.1.tgz", + "integrity": "sha512-WT9LheDC4/d/sD/jgC6L5UMq4U9X3KNMy0JrXp/MdJL83ZqcuPQuMkj50beOX0dMub8IoZUYycfN7bIVZuU5zg==" }, "acorn-class-fields": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/acorn-class-fields/-/acorn-class-fields-0.1.2.tgz", - "integrity": "sha1-IHgvMEr0Ilf+/1vUpcM1KRRzv1g=", + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/acorn-class-fields/-/acorn-class-fields-0.3.1.tgz", + "integrity": "sha512-X/8hSJuregAnrvfV1Y80VJNfeJx1uhw7yskOwvL631ygYeCGVLPumCnnPDHYZ8acV3ytHhg53K171H3tAemgiw==", "requires": { - "acorn": "^5.3.0" - }, - "dependencies": { - "acorn": { - "version": "5.7.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", - "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==" - } + "acorn-private-class-elements": "^0.1.1" } }, "acorn-dynamic-import": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-3.0.0.tgz", - "integrity": "sha512-zVWV8Z8lislJoOKKqdNMOB+s6+XV5WERty8MnKBeFgwA+19XJjJHs2RP5dzM57FftIs+jQnRToLiWazKr6sSWg==", - "requires": { - "acorn": "^5.0.0" - }, - "dependencies": { - "acorn": { - "version": "5.7.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", - "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==" - } - } + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-4.0.0.tgz", + "integrity": "sha512-d3OEjQV4ROpoflsnUA8HozoIR504TFxNivYEUi6uwz0IYhBkTDXGuWlNdMtybRt3nqVx/L6XqMt0FxkXuWKZhw==" + }, + "acorn-export-ns-from": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/acorn-export-ns-from/-/acorn-export-ns-from-0.1.0.tgz", + "integrity": "sha512-QDQJBe2DfxNBIMxs+19XY2i/XXilJn+kPgX30HWNYK4IXoNj3ACNSWPU7szL0SzqjFyOG4zoZxG9P7JfNw5g7A==" }, "acorn-globals": { "version": "3.1.0", @@ -2312,106 +2288,110 @@ } }, "acorn-import-meta": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/acorn-import-meta/-/acorn-import-meta-0.2.1.tgz", - "integrity": "sha512-+KB5Q0P0Q/XpsPHgnLx4XbCGqMogw4yiJJjYsbzPCNrE/IoX+c6J4C+BFcwdWh3CD1zLzMxPITN1jzHd+NiS3w==", - "requires": { - "acorn": "^5.4.1" - }, - "dependencies": { - "acorn": { - "version": "5.7.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", - "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==" - } - } - }, - "acorn-json-superset": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/acorn-json-superset/-/acorn-json-superset-0.1.1.tgz", - "integrity": "sha512-fhvg6mWlulil3spkNL0UQtym0pLAaKsKWmDGuTKlP5PVQwv9DlR1avvnnwl2YT9A61AH5j0idgv5/h9Rdkaqyg==", - "requires": { - "acorn": "^5.4.1" - }, - "dependencies": { - "acorn": { - "version": "5.7.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", - "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==" - } - } + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/acorn-import-meta/-/acorn-import-meta-1.0.0.tgz", + "integrity": "sha512-yX652u86bKzuM+mzEHV84T0R+srQwTOmprUiFC3zlhlc02lBQzqxkB/H/7jexX9vlz/TRuQiZs9mKEDK3bbmhw==" }, "acorn-jsx": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.1.0.tgz", "integrity": "sha512-tMUqwBWfLFbJbizRmEcWSLw6HnFzfdJs2sOJEOwwtVPMoH/0Ay+E703oZz78VSXZiiDcZrQ5XKjPIUQixhmgVw==" }, - "acorn-numeric-separator": { + "acorn-private-class-elements": { "version": "0.1.1", - "resolved": "https://registry.npmjs.org/acorn-numeric-separator/-/acorn-numeric-separator-0.1.1.tgz", - "integrity": "sha1-qkVaHZWuiHIx3pfgaBq74osGXo0=", + "resolved": "https://registry.npmjs.org/acorn-private-class-elements/-/acorn-private-class-elements-0.1.1.tgz", + "integrity": "sha512-bZpmSnaOsK3jkF7J8xaLJ05f008vapPX+XliIv8+jjkclvDR+M4OnTHLhFnCCSeJ0fMwRKjbY+BXsglSNpVZtw==", "requires": { - "acorn": "^5.2.1" + "mocha": "^5.2.0" }, "dependencies": { - "acorn": { - "version": "5.7.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", - "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==" - } - } - }, - "acorn-optional-catch-binding": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/acorn-optional-catch-binding/-/acorn-optional-catch-binding-0.1.1.tgz", - "integrity": "sha512-LJn5iDpAU1Zah1sdG2pY4rwv7kSe7ykbKpYrwbw5Igfn3OgPyjSD5f0JPboA1xITYpENS9rtNgN7PaAtTsvI/g==", - "requires": { - "acorn": "^5.2.1" - }, - "dependencies": { - "acorn": { - "version": "5.7.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", - "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==" + "commander": { + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", + "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==" + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "he": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", + "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=" + }, + "mocha": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-5.2.0.tgz", + "integrity": "sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ==", + "requires": { + "browser-stdout": "1.3.1", + "commander": "2.15.1", + "debug": "3.1.0", + "diff": "3.5.0", + "escape-string-regexp": "1.0.5", + "glob": "7.1.2", + "growl": "1.10.5", + "he": "1.1.1", + "minimatch": "3.0.4", + "mkdirp": "0.5.1", + "supports-color": "5.4.0" + } + }, + "supports-color": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", + "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", + "requires": { + "has-flag": "^3.0.0" + } } } }, "acorn-private-methods": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/acorn-private-methods/-/acorn-private-methods-0.1.1.tgz", - "integrity": "sha1-MsE88k0Fvxyb4EkUtBSRxZ11oZU=", + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/acorn-private-methods/-/acorn-private-methods-0.3.0.tgz", + "integrity": "sha512-+gWTjSA+13lsv1mwCPosSrLzEyghYtWgrr/1Ck7i7Pu5iK7Ke0hOgw3IW1RUxhc4qS2QTQBQx2+qHYqsa4Qlqw==", "requires": { - "acorn": "^5.4.0" - }, - "dependencies": { - "acorn": { - "version": "5.7.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", - "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==" - } + "acorn-private-class-elements": "^0.1.0" } }, "acorn-stage3": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/acorn-stage3/-/acorn-stage3-0.6.0.tgz", - "integrity": "sha512-/CZrHonJfg5OSTkZ71w4L4JnpsqZyDIXaSot5gUpQriTUavjiuAjkJBxxNGtxTlGBVtOBtYwzqxLDUSOD3amDQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/acorn-stage3/-/acorn-stage3-2.0.0.tgz", + "integrity": "sha512-1Li6EwvFv/O0rZMDduZY2lOly9fyXanmIsyqe26NppIszWhEQlb7IbUrjFGWyRVjQg3H8k7rO0I/tbAr6dORoQ==", "requires": { - "acorn": "^5.5.0", - "acorn-bigint": "^0.2.0", - "acorn-class-fields": "^0.1.1", - "acorn-dynamic-import": "^3.0.0", - "acorn-import-meta": "^0.2.1", - "acorn-json-superset": "^0.1.0", - "acorn-numeric-separator": "^0.1.1", - "acorn-optional-catch-binding": "^0.1.0", - "acorn-private-methods": "^0.1.1" - }, - "dependencies": { - "acorn": { - "version": "5.7.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", - "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==" - } + "acorn-bigint": "^0.3.1", + "acorn-class-fields": "^0.3.1", + "acorn-dynamic-import": "^4.0.0", + "acorn-export-ns-from": "^0.1.0", + "acorn-import-meta": "^1.0.0", + "acorn-private-methods": "^0.3.0", + "acorn-static-class-features": "^0.2.0" + } + }, + "acorn-static-class-features": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/acorn-static-class-features/-/acorn-static-class-features-0.2.0.tgz", + "integrity": "sha512-46IooHSRsvgSi+t36Wx9iPfF9BKFKVDcAWELXVqvKHmZogSCk11iUCi2FiZmLeTaM0hlJ3EYDyYiVmHRUGPzWA==", + "requires": { + "acorn-private-class-elements": "^0.1.0" } }, "acorn-walk": { @@ -3291,19 +3271,19 @@ } }, "browserslist": { - "version": "4.8.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.8.0.tgz", - "integrity": "sha512-HYnxc/oLRWvJ3TsGegR0SRL/UDnknGq2s/a8dYYEO+kOQ9m9apKoS5oiathLKZdh/e9uE+/J3j92qPlGD/vTqA==", + "version": "4.8.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.8.2.tgz", + "integrity": "sha512-+M4oeaTplPm/f1pXDw84YohEv7B1i/2Aisei8s4s6k3QsoSHa7i5sz8u/cGQkkatCPxMASKxPualR4wwYgVboA==", "requires": { - "caniuse-lite": "^1.0.30001012", - "electron-to-chromium": "^1.3.317", - "node-releases": "^1.1.41" + "caniuse-lite": "^1.0.30001015", + "electron-to-chromium": "^1.3.322", + "node-releases": "^1.1.42" }, "dependencies": { "caniuse-lite": { - "version": "1.0.30001012", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001012.tgz", - "integrity": "sha512-7RR4Uh04t9K1uYRWzOJmzplgEOAXbfK72oVNokCdMzA67trrhPzy93ahKk1AWHiA0c58tD2P+NHqxrA8FZ+Trg==" + "version": "1.0.30001015", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001015.tgz", + "integrity": "sha512-/xL2AbW/XWHNu1gnIrO8UitBGoFthcsDgU9VLK1/dpsoxbaD5LscHozKze05R6WLsBvLhqv78dAPozMFQBYLbQ==" } } }, @@ -4040,16 +4020,16 @@ } }, "core-js": { - "version": "3.4.7", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.4.7.tgz", - "integrity": "sha512-qaPVGw30J1wQ0GR3GvoPqlGf9GZfKKF4kFC7kiHlcsPTqH3txrs9crCp3ZiMAXuSenhz89Jnl4GZs/67S5VOSg==" + "version": "3.4.8", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.4.8.tgz", + "integrity": "sha512-b+BBmCZmVgho8KnBUOXpvlqEMguko+0P+kXCwD4vIprsXC6ht1qgPxtb1OK6XgSlrySF71wkwBQ0Hv695bk9gQ==" }, "core-js-compat": { - "version": "3.4.5", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.4.5.tgz", - "integrity": "sha512-rYVvzvKJDKoefdAC+q6VP63vp5hMmeVONCi9pVUbU1qRrtVrmAk/nPhnRg+i+XFd775m1hpG2Yd5RY3X45ccuw==", + "version": "3.4.8", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.4.8.tgz", + "integrity": "sha512-l3WTmnXHV2Sfu5VuD7EHE2w7y+K68+kULKt5RJg8ZJk3YhHF1qLD4O8v8AmNq+8vbOwnPFFDvds25/AoEvMqlQ==", "requires": { - "browserslist": "^4.7.3", + "browserslist": "^4.8.2", "semver": "^6.3.0" }, "dependencies": { @@ -4706,25 +4686,22 @@ } }, "easygettext": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/easygettext/-/easygettext-2.7.0.tgz", - "integrity": "sha512-BaoyxsZtre7Ndvgz3utjrE/6Yo8Txsc4m33ehQ0pBNX3HjcjGQozDhnpqSRhaeD8PQAk0Rgq3vhI+YJvQu0vUQ==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/easygettext/-/easygettext-2.8.0.tgz", + "integrity": "sha512-tzEoAL7Er6wtljz9yGh2RShLZtoGj9Yl1icV+oEY0aeSIr8R//t4GdZHjyhQJLuE9i0CntYGbT95SNh3yOoHNA==", "requires": { - "@vue/component-compiler-utils": "^1.2.1", - "acorn": "^5.5.3", - "acorn-stage3": "^0.6.0", - "cheerio": "^1.0.0-rc.2", + "@vue/component-compiler-utils": "^2.6.0", + "acorn": "^6.4.0", + "acorn-stage3": "^2.0.0", + "acorn-walk": "^6.2.0", + "cheerio": "^1.0.0-rc.3", + "flow-remove-types": "^1.2.3", "minimist": "^1.2.0", - "pofile": "^1.0.10", - "pug": "^2.0.3", - "vue-template-compiler": "^2.5.16" + "pofile": "^1.1.0", + "pug": "^2.0.4", + "vue-template-compiler": "^2.6.10" }, "dependencies": { - "acorn": { - "version": "5.7.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", - "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==" - }, "minimist": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", @@ -4743,9 +4720,9 @@ "integrity": "sha512-kS/gEPzZs3Y1rRsbGX4UOSjtP/CeJP0CxSNZHYxGfVM/VgLcv0ZqM7C45YyTj2DI2g7+P9Dd24C+IMIg6D0nYQ==" }, "electron-to-chromium": { - "version": "1.3.319", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.319.tgz", - "integrity": "sha512-t/lYNZPwS9jLJ9SBLGd6ERYtCtsYPAXzsE1VYLshrUWpQCTAswO1pERZV4iOZipW2uVsGQrJtm2iWiYVp1zTZw==" + "version": "1.3.322", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.322.tgz", + "integrity": "sha512-Tc8JQEfGQ1MzfSzI/bTlSr7btJv/FFO7Yh6tanqVmIWOuNCu6/D1MilIEgLtmWqIrsv+o4IjpLAhgMBr/ncNAA==" }, "elliptic": { "version": "6.5.1", @@ -5782,6 +5759,15 @@ "resolved": "https://registry.npmjs.org/flatten/-/flatten-1.0.2.tgz", "integrity": "sha1-2uRqnXj74lKSJYzB54CkHZXAN4I=" }, + "flow-remove-types": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/flow-remove-types/-/flow-remove-types-1.2.3.tgz", + "integrity": "sha512-ypq/U3V+t9atYiOuSJd40tekCra03EHKoRsiK/wXGrsZimuum0kdwVY7Yv0HTaoXgHW1WiayomYd+Q3kkvPl9Q==", + "requires": { + "babylon": "^6.15.0", + "vlq": "^0.2.1" + } + }, "flush-write-stream": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", @@ -8619,9 +8605,9 @@ "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=" }, "node-releases": { - "version": "1.1.41", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.41.tgz", - "integrity": "sha512-+IctMa7wIs8Cfsa8iYzeaLTFwv5Y4r5jZud+4AnfymzeEXKBCavFX0KBgzVaPVqf0ywa6PrO8/b+bPqdwjGBSg==", + "version": "1.1.42", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.42.tgz", + "integrity": "sha512-OQ/ESmUqGawI2PRX+XIRao44qWYBBfN54ImQYdWVTQqUckuejOg76ysSqDBK8NG3zwySRVnX36JwDQ6x+9GxzA==", "requires": { "semver": "^6.3.0" }, @@ -9205,9 +9191,9 @@ "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=" }, "postcss": { - "version": "7.0.23", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.23.tgz", - "integrity": "sha512-hOlMf3ouRIFXD+j2VJecwssTwbvsPGJVMzupptg+85WA+i7MwyrydmQAgY3R+m0Bc0exunhbJmijy8u8+vufuQ==", + "version": "7.0.24", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.24.tgz", + "integrity": "sha512-Xl0XvdNWg+CblAXzNvbSOUvgJXwSjmbAKORqyw9V2AlHrm1js2gFw9y3jibBAhpKZi8b5JzJCVh/FyzPsTtgTA==", "requires": { "chalk": "^2.4.2", "source-map": "^0.6.1", @@ -12416,6 +12402,11 @@ "resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.2.tgz", "integrity": "sha512-w/hry/368nO21AN9QljsaIhb9ZiZtZARoVH5f3CsFbawdLdayCgKRPup7CggujvySMxx0I91NOyxdVENohprLQ==" }, + "vlq": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/vlq/-/vlq-0.2.3.tgz", + "integrity": "sha512-DRibZL6DsNhIgYQ+wNdWDL2SL3bKPlVrRiBqV5yuMm++op8W4kGFtaQfCs4KEJn0wBZcHVHJ3eoywX8983k1ow==" + }, "vm-browserify": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", diff --git a/frontend/package.json b/frontend/package.json index f42ccfca0..5d6930fd2 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -16,11 +16,11 @@ "gettext-compile": "gettext-compile --output src/resources/translations.json src/resources/*.po" }, "dependencies": { - "@babel/cli": "^7.7.4", - "@babel/core": "^7.7.4", - "@babel/plugin-transform-runtime": "^7.7.4", + "@babel/cli": "^7.7.5", + "@babel/core": "^7.7.5", + "@babel/plugin-transform-runtime": "^7.7.6", "@babel/polyfill": "^7.7.0", - "@babel/preset-env": "^7.7.4", + "@babel/preset-env": "^7.7.6", "@babel/register": "^7.7.4", "@fortawesome/fontawesome-free": "^5.11.2", "@types/leaflet": "^1.5.6", @@ -32,7 +32,7 @@ "babel-eslint": "^10.0.3", "babel-loader": "^8.0.6", "babel-plugin-istanbul": "^5.2.0", - "browserslist": "^4.8.0", + "browserslist": "^4.8.2", "chai": "^4.2.0", "chalk": "^2.4.2", "chart.js": "^2.9.3", @@ -40,12 +40,12 @@ "clean-webpack-plugin": "^3.0.0", "connect-history-api-fallback": "^1.3.0", "copy-webpack-plugin": "^5.0.5", - "core-js": "^3.4.7", + "core-js": "^3.4.8", "cross-env": "^5.2.1", "crypto-random-string": "^3.0.1", "css-loader": "^2.1.1", "cssnano": "^4.1.10", - "easygettext": "^2.7.0", + "easygettext": "^2.8.0", "eslint": "^6.7.2", "eslint-config-standard": "^13.0.1", "eslint-formatter-pretty": "^2.1.1", @@ -79,7 +79,7 @@ "ora": "^3.4.0", "photoswipe": "^4.1.3", "pluralize": "^8.0.0", - "postcss": "^7.0.23", + "postcss": "^7.0.24", "postcss-browser-reporter": "^0.6.0", "postcss-import": "^12.0.1", "postcss-loader": "^3.0.0", diff --git a/frontend/src/common/config.js b/frontend/src/common/config.js index ce2d100f1..ca3cb3aab 100644 --- a/frontend/src/common/config.js +++ b/frontend/src/common/config.js @@ -15,7 +15,7 @@ class Config { this.values = values; this.debug = !!values.debug; this.page = { - title: "PhotoPrism" + title: "PhotoPrism", }; this.subscriptionId = Event.subscribe("config.updated", (ev, data) => this.setValues(data)); diff --git a/frontend/src/common/util.js b/frontend/src/common/util.js index b083ec1ff..b214746e8 100644 --- a/frontend/src/common/util.js +++ b/frontend/src/common/util.js @@ -14,7 +14,7 @@ export default class Util { IX: 9, V: 5, IV: 4, - I: 1 + I: 1, }; let a; if (number < 1 || number > 3999) diff --git a/frontend/src/component/p-photo-details.vue b/frontend/src/component/p-photo-details.vue index 7d8915fd7..d5949ea57 100644 --- a/frontend/src/component/p-photo-details.vue +++ b/frontend/src/component/p-photo-details.vue @@ -42,17 +42,17 @@ icon large absolute class="p-photo-select" @click.stop.prevent="$clipboard.toggle(photo)"> - check_circle - radio_button_off + check_circle + radio_button_off - favorite + favorite - favorite_border + favorite_border diff --git a/frontend/src/component/p-photo-mosaic.vue b/frontend/src/component/p-photo-mosaic.vue index 3e75c75e5..7c0dcd823 100644 --- a/frontend/src/component/p-photo-mosaic.vue +++ b/frontend/src/component/p-photo-mosaic.vue @@ -41,16 +41,16 @@ icon small absolute class="p-photo-select" @click.stop.prevent="$clipboard.toggle(photo)"> - check_circle - radio_button_off + check_circle + radio_button_off - favorite - favorite_border + favorite + favorite_border diff --git a/frontend/src/component/p-photo-tiles.vue b/frontend/src/component/p-photo-tiles.vue index 3ce0917f3..2c734fafc 100644 --- a/frontend/src/component/p-photo-tiles.vue +++ b/frontend/src/component/p-photo-tiles.vue @@ -41,16 +41,16 @@ icon large absolute class="p-photo-select" @click.stop.prevent="$clipboard.toggle(photo)"> - check_circle - radio_button_off + check_circle + radio_button_off - favorite - favorite_border + favorite + favorite_border diff --git a/frontend/src/pages/library/index.vue b/frontend/src/pages/library/index.vue index c98bdf37b..e162cf2ec 100644 --- a/frontend/src/pages/library/index.vue +++ b/frontend/src/pages/library/index.vue @@ -4,12 +4,21 @@

Indexing {{ fileName }}... - Re-indexing existing files and photos... + Indexing photos and sidecar files... Done. - Press button to re-index existing files and photos... + Press button to start indexing...

- +

+ +

+ + (confidence / 3) { - results = append(results, label) - } - } - - elapsed := time.Since(start) - - log.Debugf("finding %+v labels for %s took %s", results, jpeg.Filename(), elapsed) - - return results -} - -func (i *Indexer) indexMediaFile(mediaFile *MediaFile) string { - var photo models.Photo - var file, primaryFile models.File - var isPrimary = false - var exifData *Exif - var photoQuery, fileQuery *gorm.DB - var keywords []string - - labels := Labels{} - fileBase := mediaFile.Basename() - filePath := mediaFile.RelativePath(i.originalsPath()) - fileName := mediaFile.RelativeFilename(i.originalsPath()) - fileHash := mediaFile.Hash() - - event.Publish("index.file", event.Data{ - "fileHash": fileHash, - "fileName": fileName, - "baseName": filepath.Base(fileName), - }) - - exifData, err := mediaFile.Exif() - - if err != nil { - log.Debug(err) - } - - fileQuery = i.db.Unscoped().First(&file, "file_hash = ? OR file_name = ?", fileHash, fileName) - - if fileQuery.Error != nil { - photoQuery = i.db.Unscoped().First(&photo, "photo_path = ? AND photo_name = ?", filePath, fileBase) - - if photoQuery.Error != nil && mediaFile.HasTimeAndPlace() { - photoQuery = i.db.Unscoped().First(&photo, "photo_lat = ? AND photo_long = ? AND taken_at = ?", exifData.Lat, exifData.Long, exifData.TakenAt) - } - } else { - photoQuery = i.db.Unscoped().First(&photo, "id = ?", file.PhotoID) - } - - photo.PhotoPath = filePath - photo.PhotoName = fileBase - - if jpeg, err := mediaFile.Jpeg(); err == nil { - // Image classification labels - labels = i.classifyImage(jpeg) - - // Read Exif data - if exifData, err := jpeg.Exif(); err == nil { - photo.PhotoLat = exifData.Lat - photo.PhotoLong = exifData.Long - photo.TakenAt = exifData.TakenAt - photo.TakenAtLocal = exifData.TakenAtLocal - photo.TimeZone = exifData.TimeZone - photo.PhotoAltitude = exifData.Altitude - photo.PhotoArtist = exifData.Artist - - if exifData.UUID != "" { - log.Debugf("photo uuid: %s", exifData.UUID) - photo.PhotoUUID = exifData.UUID - } else { - log.Debug("no photo uuid") - } - } - - // Set Camera, Lens, Focal Length and F Number - photo.Camera = models.NewCamera(mediaFile.CameraModel(), mediaFile.CameraMake()).FirstOrCreate(i.db) - photo.Lens = models.NewLens(mediaFile.LensModel(), mediaFile.LensMake()).FirstOrCreate(i.db) - photo.PhotoFocalLength = mediaFile.FocalLength() - photo.PhotoFNumber = mediaFile.FNumber() - photo.PhotoIso = mediaFile.Iso() - photo.PhotoExposure = mediaFile.Exposure() - } - - if photo.TakenAt.IsZero() || photo.TakenAtLocal.IsZero() { - photo.TakenAt = mediaFile.DateCreated() - photo.TakenAtLocal = photo.TakenAt - } - - if location, err := mediaFile.Location(); err == nil { - i.db.FirstOrCreate(location, "id = ?", location.ID) - photo.Location = location - photo.LocationEstimated = false - - photo.Country = models.NewCountry(location.LocCountryCode, location.LocCountry).FirstOrCreate(i.db) - - keywords = append(keywords, util.Keywords(location.LocDisplayName)...) - - // Append labels from OpenStreetMap - if location.LocCity != "" { - labels = append(labels, NewLocationLabel(location.LocCity, 0, -2)) - } - - if location.LocCountry != "" { - labels = append(labels, NewLocationLabel(location.LocCountry, 0, -2)) - } - - if location.LocCategory != "" { - labels = append(labels, NewLocationLabel(location.LocCategory, 0, -2)) - } - - if location.LocType != "" { - labels = append(labels, NewLocationLabel(location.LocType, 0, -1)) - } - - // Sort by priority and uncertainty - sort.Sort(labels) - - if photo.PhotoTitleChanged == false { - log.Infof("setting title based on the following labels: %#v", labels) - if len(labels) > 0 && labels[0].Priority >= -1 && labels[0].Uncertainty <= 60 && labels[0].Name != "" { // TODO: User defined title format - log.Infof("label for title: %#v", labels[0]) - if location.LocCity == "" || len(location.LocCity) > 16 || strings.Contains(labels[0].Name, location.LocCity) { - photo.PhotoTitle = fmt.Sprintf("%s / %s / %s", util.Title(labels[0].Name), location.LocCountry, photo.TakenAt.Format("2006")) - } else { - photo.PhotoTitle = fmt.Sprintf("%s / %s / %s", util.Title(labels[0].Name), location.LocCity, photo.TakenAt.Format("2006")) - } - } else if location.LocName != "" && location.LocCity != "" { - if len(location.LocName) > 45 { - photo.PhotoTitle = util.Title(location.LocName) - } else if len(location.LocName) > 20 || len(location.LocCity) > 16 || strings.Contains(location.LocName, location.LocCity) { - photo.PhotoTitle = fmt.Sprintf("%s / %s", util.Title(location.LocName), photo.TakenAt.Format("2006")) - } else { - photo.PhotoTitle = fmt.Sprintf("%s / %s / %s", util.Title(location.LocName), location.LocCity, photo.TakenAt.Format("2006")) - } - } else if location.LocCity != "" && location.LocCountry != "" { - if len(location.LocCity) > 20 { - photo.PhotoTitle = fmt.Sprintf("%s / %s", location.LocCity, photo.TakenAt.Format("2006")) - } else { - photo.PhotoTitle = fmt.Sprintf("%s / %s / %s", location.LocCity, location.LocCountry, photo.TakenAt.Format("2006")) - } - } else if location.LocCounty != "" && location.LocCountry != "" { - if len(location.LocCounty) > 20 { - photo.PhotoTitle = fmt.Sprintf("%s / %s", location.LocCounty, photo.TakenAt.Format("2006")) - } else { - photo.PhotoTitle = fmt.Sprintf("%s / %s / %s", location.LocCounty, location.LocCountry, photo.TakenAt.Format("2006")) - } - } - } - } else { - log.Debugf("location cannot be determined precisely: %s", err) - } - - if photo.PhotoTitleChanged == false && photo.PhotoTitle == "" { - if len(labels) > 0 && labels[0].Priority >= -1 && labels[0].Uncertainty <= 85 && labels[0].Name != "" { - photo.PhotoTitle = fmt.Sprintf("%s / %s", util.Title(labels[0].Name), mediaFile.DateCreated().Format("2006")) - } else if !photo.TakenAtLocal.IsZero() { - var daytimeString string - hour := photo.TakenAtLocal.Hour() - - switch { - case hour < 17: - daytimeString = "Unknown" - case hour < 20: - daytimeString = "Sunset" - default: - daytimeString = "Unknown" - } - - photo.PhotoTitle = fmt.Sprintf("%s / %s", daytimeString, photo.TakenAtLocal.Format("2006")) - } - } - - log.Debugf("title: \"%s\"", photo.PhotoTitle) - - if photoQuery.Error != nil { - photo.PhotoFavorite = false - - i.db.Create(&photo) - } else { - // Estimate location - if photo.LocationID == 0 { - var recentPhoto models.Photo - - if result := i.db.Unscoped().Order(gorm.Expr("ABS(DATEDIFF(taken_at, ?)) ASC", photo.TakenAt)).Preload("Country").First(&recentPhoto); result.Error == nil { - if recentPhoto.Country != nil { - photo.Country = recentPhoto.Country - photo.LocationEstimated = true - log.Debugf("approximate location: %s", recentPhoto.Country.CountryName) - } - } - } - - i.db.Unscoped().Save(&photo) - } - - log.Infof("adding labels: %+v", labels) - - for _, label := range labels { - lm := models.NewLabel(label.Name, label.Priority).FirstOrCreate(i.db) - - if lm.LabelPriority != label.Priority { - lm.LabelPriority = label.Priority - i.db.Save(&lm) - } - - plm := models.NewPhotoLabel(photo.ID, lm.ID, label.Uncertainty, label.Source).FirstOrCreate(i.db) - - // Add categories - for _, category := range label.Categories { - sn := models.NewLabel(category, -1).FirstOrCreate(i.db) - i.db.Model(&lm).Association("LabelCategories").Append(sn) - } - - if plm.LabelUncertainty > label.Uncertainty { - plm.LabelUncertainty = label.Uncertainty - plm.LabelSource = label.Source - i.db.Save(&plm) - } - } - - if result := i.db.Where("file_type = 'jpg' AND file_primary = 1 AND photo_id = ?", photo.ID).First(&primaryFile); result.Error != nil { - isPrimary = mediaFile.IsJpeg() - } else { - isPrimary = mediaFile.IsJpeg() && (fileName == primaryFile.FileName || fileHash == primaryFile.FileHash) - } - - if isPrimary { - photo.IndexKeywords(keywords, i.db) - } - - file.PhotoID = photo.ID - file.PhotoUUID = photo.PhotoUUID - file.FilePrimary = isPrimary - file.FileMissing = false - file.FileName = fileName - file.FileHash = fileHash - file.FileType = mediaFile.Type() - file.FileMime = mediaFile.MimeType() - file.FileOrientation = mediaFile.Orientation() - - // Color information - if p, err := mediaFile.Colors(i.thumbnailsPath()); err == nil { - file.FileMainColor = p.MainColor.Name() - file.FileColors = p.Colors.Hex() - file.FileLuminance = p.Luminance.Hex() - file.FileChroma = p.Chroma.Uint() - } - - if mediaFile.Width() > 0 && mediaFile.Height() > 0 { - file.FileWidth = mediaFile.Width() - file.FileHeight = mediaFile.Height() - file.FileAspectRatio = mediaFile.AspectRatio() - file.FilePortrait = mediaFile.Width() < mediaFile.Height() - } - - if fileQuery.Error == nil { - i.db.Unscoped().Save(&file) - return indexResultUpdated - } - - i.db.Create(&file) - return indexResultAdded -} - // IndexRelated will index all mediafiles which has relate to a given mediafile. -func (i *Indexer) IndexRelated(mediaFile *MediaFile) map[string]bool { +func (i *Indexer) IndexRelated(mediaFile *MediaFile, o IndexerOptions) map[string]bool { indexed := make(map[string]bool) relatedFiles, mainFile, err := mediaFile.RelatedFiles() @@ -366,7 +48,7 @@ func (i *Indexer) IndexRelated(mediaFile *MediaFile) map[string]bool { return indexed } - mainIndexResult := i.indexMediaFile(mainFile) + mainIndexResult := i.indexMediaFile(mainFile, o) indexed[mainFile.Filename()] = true log.Infof("%s main %s file \"%s\"", mainIndexResult, mainFile.Type(), mainFile.RelativeFilename(i.originalsPath())) @@ -376,7 +58,7 @@ func (i *Indexer) IndexRelated(mediaFile *MediaFile) map[string]bool { continue } - indexResult := i.indexMediaFile(relatedMediaFile) + indexResult := i.indexMediaFile(relatedMediaFile, o) indexed[relatedMediaFile.Filename()] = true log.Infof("%s related %s file \"%s\"", indexResult, relatedMediaFile.Type(), relatedMediaFile.RelativeFilename(i.originalsPath())) @@ -385,8 +67,8 @@ func (i *Indexer) IndexRelated(mediaFile *MediaFile) map[string]bool { return indexed } -// IndexAll will index all mediafiles. -func (i *Indexer) IndexAll() map[string]bool { +// IndexOriginals will index mediafiles in the originals directory. +func (i *Indexer) IndexOriginals(o IndexerOptions) map[string]bool { indexed := make(map[string]bool) err := filepath.Walk(i.originalsPath(), func(filename string, fileInfo os.FileInfo, err error) error { @@ -409,7 +91,7 @@ func (i *Indexer) IndexAll() map[string]bool { return nil } - for relatedFilename := range i.IndexRelated(mediaFile) { + for relatedFilename := range i.IndexRelated(mediaFile, o) { indexed[relatedFilename] = true } diff --git a/internal/photoprism/indexer_mediafile.go b/internal/photoprism/indexer_mediafile.go new file mode 100644 index 000000000..85dd58749 --- /dev/null +++ b/internal/photoprism/indexer_mediafile.go @@ -0,0 +1,361 @@ +package photoprism + +import ( + "fmt" + "path/filepath" + "sort" + "strings" + "time" + + "github.com/jinzhu/gorm" + "github.com/photoprism/photoprism/internal/event" + "github.com/photoprism/photoprism/internal/models" + "github.com/photoprism/photoprism/internal/util" +) + +const ( + indexResultUpdated IndexResult = "updated" + indexResultAdded IndexResult = "added" + indexResultSkipped IndexResult = "skipped" +) + +type IndexResult string + +// classifyImage returns all matching labels for a media file. +func (i *Indexer) classifyImage(jpeg *MediaFile) (results Labels) { + start := time.Now() + + var thumbs []string + + if jpeg.AspectRatio() == 1 { + thumbs = []string{"tile_224"} + } else { + thumbs = []string{"tile_224", "left_224", "right_224"} + } + + var labels Labels + + for _, thumb := range thumbs { + filename, err := jpeg.Thumbnail(i.thumbnailsPath(), thumb) + + if err != nil { + log.Error(err) + continue + } + + imageLabels, err := i.tensorFlow.LabelsFromFile(filename) + + if err != nil { + log.Error(err) + continue + } + + labels = append(labels, imageLabels...) + } + + // Sort by priority and uncertainty + sort.Sort(labels) + + var confidence int + + for _, label := range labels { + if confidence == 0 { + confidence = 100 - label.Uncertainty + } + + if (100 - label.Uncertainty) > (confidence / 3) { + results = append(results, label) + } + } + + elapsed := time.Since(start) + + log.Debugf("finding %+v labels for %s took %s", results, jpeg.Filename(), elapsed) + + return results +} + +func (i *Indexer) indexMediaFile(mediaFile *MediaFile, o IndexerOptions) IndexResult { + var photo models.Photo + var file, primaryFile models.File + var isPrimary = false + var exifData *Exif + var photoQuery, fileQuery *gorm.DB + var keywords []string + + labels := Labels{} + fileBase := mediaFile.Basename() + filePath := mediaFile.RelativePath(i.originalsPath()) + fileName := mediaFile.RelativeFilename(i.originalsPath()) + fileHash := mediaFile.Hash() + fileExists := false + photoExists := false + exists := false + isNew := true + + event.Publish("index.file", event.Data{ + "fileHash": fileHash, + "fileName": fileName, + "baseName": filepath.Base(fileName), + }) + + exifData, err := mediaFile.Exif() + + if err != nil { + log.Debug(err) + } + + fileQuery = i.db.Unscoped().First(&file, "file_hash = ? OR file_name = ?", fileHash, fileName) + fileExists = fileQuery.Error == nil + + if !fileExists { + photoQuery = i.db.Unscoped().First(&photo, "photo_path = ? AND photo_name = ?", filePath, fileBase) + + if photoQuery.Error != nil && mediaFile.HasTimeAndPlace() { + photoQuery = i.db.Unscoped().First(&photo, "photo_lat = ? AND photo_long = ? AND taken_at = ?", exifData.Lat, exifData.Long, exifData.TakenAt) + } + } else { + photoQuery = i.db.Unscoped().First(&photo, "id = ?", file.PhotoID) + } + + photoExists = photoQuery.Error == nil + + exists = fileExists && photoExists + isNew = !exists + + if exists && o.SkipExisting() { + return indexResultSkipped + } + + photo.PhotoPath = filePath + photo.PhotoName = fileBase + + if jpeg, err := mediaFile.Jpeg(); err == nil { + + if isNew || o.UpdateLabels { + // Image classification labels + labels = i.classifyImage(jpeg) + } + + if isNew || o.UpdateExif { + // Read UpdateExif data + if exifData, err := jpeg.Exif(); err == nil { + photo.PhotoLat = exifData.Lat + photo.PhotoLong = exifData.Long + photo.TakenAt = exifData.TakenAt + photo.TakenAtLocal = exifData.TakenAtLocal + photo.TimeZone = exifData.TimeZone + photo.PhotoAltitude = exifData.Altitude + photo.PhotoArtist = exifData.Artist + + if exifData.UUID != "" { + log.Debugf("photo uuid: %s", exifData.UUID) + photo.PhotoUUID = exifData.UUID + } else { + log.Debug("no photo uuid") + } + } + } + + if isNew || o.UpdateCamera { + // Set UpdateCamera, Lens, Focal Length and F Number + photo.Camera = models.NewCamera(mediaFile.CameraModel(), mediaFile.CameraMake()).FirstOrCreate(i.db) + photo.Lens = models.NewLens(mediaFile.LensModel(), mediaFile.LensMake()).FirstOrCreate(i.db) + photo.PhotoFocalLength = mediaFile.FocalLength() + photo.PhotoFNumber = mediaFile.FNumber() + photo.PhotoIso = mediaFile.Iso() + photo.PhotoExposure = mediaFile.Exposure() + } + } + + if isNew || o.UpdateDate { + if photo.TakenAt.IsZero() || photo.TakenAtLocal.IsZero() { + photo.TakenAt = mediaFile.DateCreated() + photo.TakenAtLocal = photo.TakenAt + } + } + + if isNew || o.UpdateLocation { + if location, err := mediaFile.Location(); err == nil { + i.db.FirstOrCreate(location, "id = ?", location.ID) + photo.Location = location + photo.LocationEstimated = false + + photo.Country = models.NewCountry(location.LocCountryCode, location.LocCountry).FirstOrCreate(i.db) + + keywords = append(keywords, util.Keywords(location.LocDisplayName)...) + + // Append labels from OpenStreetMap + if location.LocCity != "" { + labels = append(labels, NewLocationLabel(location.LocCity, 0, -2)) + } + + if location.LocCountry != "" { + labels = append(labels, NewLocationLabel(location.LocCountry, 0, -2)) + } + + if location.LocCategory != "" { + labels = append(labels, NewLocationLabel(location.LocCategory, 0, -2)) + } + + if location.LocType != "" { + labels = append(labels, NewLocationLabel(location.LocType, 0, -1)) + } + + // Sort by priority and uncertainty + sort.Sort(labels) + + + if (isNew || o.UpdateTitle) && photo.PhotoTitleChanged == false { + log.Infof("setting title based on the following labels: %#v", labels) + if len(labels) > 0 && labels[0].Priority >= -1 && labels[0].Uncertainty <= 60 && labels[0].Name != "" { // TODO: User defined title format + log.Infof("label for title: %#v", labels[0]) + if location.LocCity == "" || len(location.LocCity) > 16 || strings.Contains(labels[0].Name, location.LocCity) { + photo.PhotoTitle = fmt.Sprintf("%s / %s / %s", util.Title(labels[0].Name), location.LocCountry, photo.TakenAt.Format("2006")) + } else { + photo.PhotoTitle = fmt.Sprintf("%s / %s / %s", util.Title(labels[0].Name), location.LocCity, photo.TakenAt.Format("2006")) + } + } else if location.LocName != "" && location.LocCity != "" { + if len(location.LocName) > 45 { + photo.PhotoTitle = util.Title(location.LocName) + } else if len(location.LocName) > 20 || len(location.LocCity) > 16 || strings.Contains(location.LocName, location.LocCity) { + photo.PhotoTitle = fmt.Sprintf("%s / %s", util.Title(location.LocName), photo.TakenAt.Format("2006")) + } else { + photo.PhotoTitle = fmt.Sprintf("%s / %s / %s", util.Title(location.LocName), location.LocCity, photo.TakenAt.Format("2006")) + } + } else if location.LocCity != "" && location.LocCountry != "" { + if len(location.LocCity) > 20 { + photo.PhotoTitle = fmt.Sprintf("%s / %s", location.LocCity, photo.TakenAt.Format("2006")) + } else { + photo.PhotoTitle = fmt.Sprintf("%s / %s / %s", location.LocCity, location.LocCountry, photo.TakenAt.Format("2006")) + } + } else if location.LocCounty != "" && location.LocCountry != "" { + if len(location.LocCounty) > 20 { + photo.PhotoTitle = fmt.Sprintf("%s / %s", location.LocCounty, photo.TakenAt.Format("2006")) + } else { + photo.PhotoTitle = fmt.Sprintf("%s / %s / %s", location.LocCounty, location.LocCountry, photo.TakenAt.Format("2006")) + } + } + } + } else { + log.Debugf("location cannot be determined precisely: %s", err) + } + } + + if (isNew || o.UpdateTitle) && photo.PhotoTitleChanged == false && photo.PhotoTitle == "" { + if len(labels) > 0 && labels[0].Priority >= -1 && labels[0].Uncertainty <= 85 && labels[0].Name != "" { + photo.PhotoTitle = fmt.Sprintf("%s / %s", util.Title(labels[0].Name), mediaFile.DateCreated().Format("2006")) + } else if !photo.TakenAtLocal.IsZero() { + var daytimeString string + hour := photo.TakenAtLocal.Hour() + + switch { + case hour < 17: + daytimeString = "Unknown" + case hour < 20: + daytimeString = "Sunset" + default: + daytimeString = "Unknown" + } + + photo.PhotoTitle = fmt.Sprintf("%s / %s", daytimeString, photo.TakenAtLocal.Format("2006")) + } + } + + log.Debugf("title: \"%s\"", photo.PhotoTitle) + + if photoExists { + // Estimate location + if o.UpdateLocation && photo.LocationID == 0 { + var recentPhoto models.Photo + + if result := i.db.Unscoped().Order(gorm.Expr("ABS(DATEDIFF(taken_at, ?)) ASC", photo.TakenAt)).Preload("Country").First(&recentPhoto); result.Error == nil { + if recentPhoto.Country != nil { + photo.Country = recentPhoto.Country + photo.LocationEstimated = true + log.Debugf("approximate location: %s", recentPhoto.Country.CountryName) + } + } + } + + i.db.Unscoped().Save(&photo) + } else { + photo.PhotoFavorite = false + + i.db.Create(&photo) + } + + log.Infof("adding labels: %+v", labels) + + if isNew || o.UpdateLabels { + for _, label := range labels { + lm := models.NewLabel(label.Name, label.Priority).FirstOrCreate(i.db) + + if lm.LabelPriority != label.Priority { + lm.LabelPriority = label.Priority + i.db.Save(&lm) + } + + plm := models.NewPhotoLabel(photo.ID, lm.ID, label.Uncertainty, label.Source).FirstOrCreate(i.db) + + // Add categories + for _, category := range label.Categories { + sn := models.NewLabel(category, -1).FirstOrCreate(i.db) + i.db.Model(&lm).Association("LabelCategories").Append(sn) + } + + if plm.LabelUncertainty > label.Uncertainty { + plm.LabelUncertainty = label.Uncertainty + plm.LabelSource = label.Source + i.db.Save(&plm) + } + } + } + + if result := i.db.Where("file_type = 'jpg' AND file_primary = 1 AND photo_id = ?", photo.ID).First(&primaryFile); result.Error != nil { + isPrimary = mediaFile.IsJpeg() + } else { + isPrimary = mediaFile.IsJpeg() && (fileName == primaryFile.FileName || fileHash == primaryFile.FileHash) + } + + if (isNew || o.UpdateKeywords) && isPrimary { + photo.IndexKeywords(keywords, i.db) + } + + file.PhotoID = photo.ID + file.PhotoUUID = photo.PhotoUUID + file.FilePrimary = isPrimary + file.FileMissing = false + file.FileName = fileName + file.FileHash = fileHash + file.FileType = mediaFile.Type() + file.FileMime = mediaFile.MimeType() + file.FileOrientation = mediaFile.Orientation() + + if isNew || o.UpdateColors { + // Color information + if p, err := mediaFile.Colors(i.thumbnailsPath()); err == nil { + file.FileMainColor = p.MainColor.Name() + file.FileColors = p.Colors.Hex() + file.FileLuminance = p.Luminance.Hex() + file.FileChroma = p.Chroma.Uint() + } + } + + if isNew || o.UpdateSize { + if mediaFile.Width() > 0 && mediaFile.Height() > 0 { + file.FileWidth = mediaFile.Width() + file.FileHeight = mediaFile.Height() + file.FileAspectRatio = mediaFile.AspectRatio() + file.FilePortrait = mediaFile.Width() < mediaFile.Height() + } + } + + if fileQuery.Error == nil { + i.db.Unscoped().Save(&file) + return indexResultUpdated + } + + i.db.Create(&file) + return indexResultAdded +} diff --git a/internal/photoprism/indexer_options.go b/internal/photoprism/indexer_options.go new file mode 100644 index 000000000..3cded86cd --- /dev/null +++ b/internal/photoprism/indexer_options.go @@ -0,0 +1,59 @@ +package photoprism + +import ( + "reflect" +) + +type IndexerOptions struct { + UpdateDate bool + UpdateColors bool + UpdateSize bool + UpdateTitle bool + UpdateLocation bool + UpdateCamera bool + UpdateLabels bool + UpdateKeywords bool + UpdateXMP bool + UpdateExif bool +} + +func (o *IndexerOptions) UpdateAny() bool { + v := reflect.ValueOf(o).Elem() + + for i := 0; i < v.NumField(); i++ { + if v.Field(i).Bool() { + return true + } + } + + return false +} + +func (o *IndexerOptions) SkipExisting() bool { + return !o.UpdateAny() +} + +// IndexerOptionsAll returns new indexer options with all options set to true. +func IndexerOptionsAll() IndexerOptions { + instance := IndexerOptions{ + UpdateDate: true, + UpdateColors: true, + UpdateSize: true, + UpdateTitle: true, + UpdateLocation: true, + UpdateCamera: true, + UpdateLabels: true, + UpdateKeywords: true, + UpdateXMP: true, + UpdateExif: true, + } + + return instance +} + +// IndexerOptionsNone returns new indexer options with all options set to false. +func IndexerOptionsNone() IndexerOptions { + instance := IndexerOptions{} + + return instance +} diff --git a/internal/photoprism/indexer_test.go b/internal/photoprism/indexer_test.go index b05138ac0..a7854e3d2 100644 --- a/internal/photoprism/indexer_test.go +++ b/internal/photoprism/indexer_test.go @@ -24,5 +24,7 @@ func TestIndexer_IndexAll(t *testing.T) { importer.ImportPhotosFromDirectory(conf.ImportPath()) - indexer.IndexAll() + options := IndexerOptionsAll() + + indexer.IndexOriginals(options) }