Compare commits
	
		
			160 Commits
		
	
	
		
			feature/ev
			...
			develop
		
	
	| Author | SHA1 | Date | 
|---|---|---|
| 
							
							
								
								 | 
						e8c0001d17 | |
| 
							
							
								
								 | 
						5c8637965a | |
| 
							
							
								
								 | 
						308d348755 | |
| 
							
							
								
								 | 
						2425e6cf2f | |
| 
							
							
								
								 | 
						a9edc12494 | |
| 
							
							
								
								 | 
						1525de1469 | |
| 
							
							
								
								 | 
						6a75d1bf51 | |
| 
							
							
								
								 | 
						f9f66e7172 | |
| 
							
							
								
								 | 
						e9c0086859 | |
| 
							
							
								
								 | 
						b2c70a6657 | |
| 
							
							
								
								 | 
						f27212f60e | |
| 
							
							
								
								 | 
						9eb5412c14 | |
| 
							
							
								
								 | 
						8e552ba508 | |
| 
							
							
								
								 | 
						49c3ec74ba | |
| 
							
							
								
								 | 
						83f32ea82a | |
| 
							
							
								
								 | 
						656d7a9e3c | |
| 
							
							
								
								 | 
						8fca175d39 | |
| 
							
							
								
								 | 
						6c219c5226 | |
| 
							
							
								
								 | 
						cb43b8a39b | |
| 
							
							
								
									
								
								 | 
						acf1816b55 | |
| 
							
							
								
								 | 
						02f60335d4 | |
| 
							
							
								
								 | 
						d9267bcc0a | |
| 
							
							
								
								 | 
						6732921ff7 | |
| 
							
							
								
								 | 
						7a705d5f9a | |
| 
							
							
								
								 | 
						368ca23c56 | |
| 
							
							
								
									
								
								 | 
						d82e025700 | |
| 
							
							
								
									
								
								 | 
						07e1966471 | |
| 
							
							
								
								 | 
						29c085bd2c | |
| 
							
							
								
								 | 
						1b152b52f5 | |
| 
							
							
								
								 | 
						6769e18ffa | |
| 
							
							
								
								 | 
						88dd96c937 | |
| 
							
							
								
								 | 
						4887bc261b | |
| 
							
							
								
								 | 
						d516839ad4 | |
| 
							
							
								
								 | 
						c9df257bbf | |
| 
							
							
								
									
								
								 | 
						053fdae384 | |
| 
							
							
								
								 | 
						6fd3f045f8 | |
| 
							
							
								
								 | 
						2d167ebbae | |
| 
							
							
								
								 | 
						a8578e2803 | |
| 
							
							
								
								 | 
						e4889ddac2 | |
| 
							
							
								
								 | 
						664def40fc | |
| 
							
							
								
								 | 
						ade6d06eb6 | |
| 
							
							
								
									
								
								 | 
						53f053a294 | |
| 
							
							
								
									
								
								 | 
						cc29893e04 | |
| 
							
							
								
								 | 
						42800a9d99 | |
| 
							
							
								
								 | 
						f4650ffdeb | |
| 
							
							
								
								 | 
						1158525abb | |
| 
							
							
								
								 | 
						04e3c57397 | |
| 
							
							
								
									
								
								 | 
						2fc411d51d | |
| 
							
							
								
									
								
								 | 
						6061b37887 | |
| 
							
							
								
									
								
								 | 
						efde9a2ee7 | |
| 
							
							
								
									
								
								 | 
						e96d15bc66 | |
| 
							
							
								
									
								
								 | 
						dad88ec766 | |
| 
							
							
								
								 | 
						3e091fd02b | |
| 
							
							
								
								 | 
						fca79c36ef | |
| 
							
							
								
								 | 
						34fcdbdb7f | |
| 
							
							
								
								 | 
						d84796b09d | |
| 
							
							
								
								 | 
						62af4f5026 | |
| 
							
							
								
									
								
								 | 
						36d6fdfb94 | |
| 
							
							
								
								 | 
						a30da50b1d | |
| 
							
							
								
								 | 
						53951daa25 | |
| 
							
							
								
								 | 
						59920e23a5 | |
| 
							
							
								
								 | 
						5952c9b7f2 | |
| 
							
							
								
								 | 
						73f50e9f4f | |
| 
							
							
								
								 | 
						dfb924bb3f | |
| 
							
							
								
								 | 
						bc9dba1c7b | |
| 
							
							
								
								 | 
						1132bfd129 | |
| 
							
							
								
								 | 
						fe1fae10f5 | |
| 
							
							
								
								 | 
						1c36399ac0 | |
| 
							
							
								
									
								
								 | 
						a38954cf70 | |
| 
							
							
								
								 | 
						35d8433e23 | |
| 
							
							
								
								 | 
						731cc20a06 | |
| 
							
							
								
								 | 
						c38032085f | |
| 
							
							
								
								 | 
						22f47bd34e | |
| 
							
							
								
									
								
								 | 
						16fd9201ae | |
| 
							
							
								
								 | 
						873fee3301 | |
| 
							
							
								
								 | 
						1802081ad2 | |
| 
							
							
								
								 | 
						631e78acb3 | |
| 
							
							
								
								 | 
						d422380adc | |
| 
							
							
								
								 | 
						0c279289b2 | |
| 
							
							
								
								 | 
						979eab05af | |
| 
							
							
								
								 | 
						fd918f5bb7 | |
| 
							
							
								
								 | 
						068dbdcc7b | |
| 
							
							
								
								 | 
						8c9db67b95 | |
| 
							
							
								
								 | 
						86bad83e53 | |
| 
							
							
								
								 | 
						625ac55b0a | |
| 
							
							
								
								 | 
						9940589d1a | |
| 
							
							
								
								 | 
						f2b7f3a3b4 | |
| 
							
							
								
								 | 
						f9c9f6efbe | |
| 
							
							
								
								 | 
						0873b2da22 | |
| 
							
							
								
								 | 
						734a3e51c9 | |
| 
							
							
								
								 | 
						cf1a5cc922 | |
| 
							
							
								
								 | 
						6e503ed38f | |
| 
							
							
								
								 | 
						4cbff6b077 | |
| 
							
							
								
								 | 
						2b42dad617 | |
| 
							
							
								
								 | 
						8b6c400689 | |
| 
							
							
								
									
								
								 | 
						5174e7fea3 | |
| 
							
							
								
									
								
								 | 
						95867428a8 | |
| 
							
							
								
									
								
								 | 
						3c7d711f59 | |
| 
							
							
								
									
								
								 | 
						81c5b10101 | |
| 
							
							
								
									
								
								 | 
						a8a6cd8814 | |
| 
							
							
								
									
								
								 | 
						18d0098bb3 | |
| 
							
							
								
									
								
								 | 
						be347225c4 | |
| 
							
							
								
									
								
								 | 
						e2b46d96b9 | |
| 
							
							
								
									
								
								 | 
						6e74105f38 | |
| 
							
							
								
									
								
								 | 
						ae5212bbfc | |
| 
							
							
								
									
								
								 | 
						2a11964c4b | |
| 
							
							
								
									
								
								 | 
						e0bf8f77bf | |
| 
							
							
								
									
								
								 | 
						c76da59290 | |
| 
							
							
								
									
								
								 | 
						52ae8fce29 | |
| 
							
							
								
									
								
								 | 
						f7a6f3fbe1 | |
| 
							
							
								
									
								
								 | 
						8ee5c891a5 | |
| 
							
							
								
									
								
								 | 
						479dfd658a | |
| 
							
							
								
									
								
								 | 
						97dcc8e602 | |
| 
							
							
								
									
								
								 | 
						a376fd7cc2 | |
| 
							
							
								
									
								
								 | 
						8b21ccf978 | |
| 
							
							
								
									
								
								 | 
						cee6eda585 | |
| 
							
							
								
									
								
								 | 
						dc948e6f11 | |
| 
							
							
								
									
								
								 | 
						86bb722623 | |
| 
							
							
								
									
								
								 | 
						0df2677b1b | |
| 
							
							
								
									
								
								 | 
						43397fe3a7 | |
| 
							
							
								
									
								
								 | 
						851c5a0588 | |
| 
							
							
								
									
								
								 | 
						0626cf993f | |
| 
							
							
								
									
								
								 | 
						9b0679278c | |
| 
							
							
								
									
								
								 | 
						b40b1064e7 | |
| 
							
							
								
									
								
								 | 
						06256f651a | |
| 
							
							
								
									
								
								 | 
						e90dc4c306 | |
| 
							
							
								
									
								
								 | 
						8c321fb8ca | |
| 
							
							
								
									
								
								 | 
						459a9fea08 | |
| 
							
							
								
									
								
								 | 
						7a3a151688 | |
| 
							
							
								
									
								
								 | 
						1c64dbbaf6 | |
| 
							
							
								
								 | 
						4e340e5bea | |
| 
							
							
								
									
								
								 | 
						89cd109587 | |
| 
							
							
								
								 | 
						010ad6e107 | |
| 
							
							
								
									
								
								 | 
						f5b370e743 | |
| 
							
							
								
									
								
								 | 
						741216ac3e | |
| 
							
							
								
									
								
								 | 
						284652b002 | |
| 
							
							
								
									
								
								 | 
						736ea04b4a | |
| 
							
							
								
									
								
								 | 
						5d1df48b9a | |
| 
							
							
								
									
								
								 | 
						7289a1724d | |
| 
							
							
								
									
								
								 | 
						909275727a | |
| 
							
							
								
									
								
								 | 
						8ecbddc6ca | |
| 
							
							
								
									
								
								 | 
						f25651a71e | |
| 
							
							
								
									
								
								 | 
						fb14df0c43 | |
| 
							
							
								
									
								
								 | 
						6cdc143aa9 | |
| 
							
							
								
									
								
								 | 
						7089ee4d62 | |
| 
							
							
								
									
								
								 | 
						aadfca2d31 | |
| 
							
							
								
									
								
								 | 
						a7d32d6f7c | |
| 
							
							
								
									
								
								 | 
						1b478d7680 | |
| 
							
							
								
									
								
								 | 
						d185b84823 | |
| 
							
							
								
									
								
								 | 
						0d044b505a | |
| 
							
							
								
									
								
								 | 
						3eea079871 | |
| 
							
							
								
									
								
								 | 
						30e101c364 | |
| 
							
							
								
									
								
								 | 
						cf0f453b7c | |
| 
							
							
								
									
								
								 | 
						24aec1a98c | |
| 
							
							
								
									
								
								 | 
						8eecb70df0 | |
| 
							
							
								
									
								
								 | 
						59d6023462 | |
| 
							
							
								
									
								
								 | 
						f58e0c382c | |
| 
							
							
								
									
								
								 | 
						3d20292898 | |
| 
							
							
								
									
								
								 | 
						aa82b9029a | |
| 
							
							
								
									
								
								 | 
						d42c6dcce1 | 
							
								
								
									
										31
									
								
								.eslintrc.js
								
								
								
								
							
							
						
						| 
						 | 
				
			
			@ -17,11 +17,11 @@ module.exports = {
 | 
			
		|||
    project: resolve(__dirname, './tsconfig.json'),
 | 
			
		||||
    tsconfigRootDir: __dirname,
 | 
			
		||||
    ecmaVersion: 2019, // Allows for the parsing of modern ECMAScript features
 | 
			
		||||
    sourceType: 'module' // Allows for the use of imports
 | 
			
		||||
    sourceType: 'module', // Allows for the use of imports
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  env: {
 | 
			
		||||
    browser: true
 | 
			
		||||
    browser: true,
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  // Rules order is important, please avoid shuffling them
 | 
			
		||||
| 
						 | 
				
			
			@ -44,7 +44,7 @@ module.exports = {
 | 
			
		|||
 | 
			
		||||
    // https://github.com/prettier/eslint-config-prettier#installation
 | 
			
		||||
    // usage with Prettier, provided by 'eslint-config-prettier'.
 | 
			
		||||
    'prettier', //'plugin:prettier/recommended'
 | 
			
		||||
    'plugin:prettier/recommended',
 | 
			
		||||
  ],
 | 
			
		||||
 | 
			
		||||
  plugins: [
 | 
			
		||||
| 
						 | 
				
			
			@ -54,10 +54,6 @@ module.exports = {
 | 
			
		|||
    // https://eslint.vuejs.org/user-guide/#why-doesn-t-it-work-on-vue-file
 | 
			
		||||
    // required to lint *.vue files
 | 
			
		||||
    'vue',
 | 
			
		||||
 | 
			
		||||
    // https://github.com/typescript-eslint/typescript-eslint/issues/389#issuecomment-509292674
 | 
			
		||||
    // Prettier has not been included as plugin to avoid performance impact
 | 
			
		||||
    // add it as an extension for your IDE
 | 
			
		||||
  ],
 | 
			
		||||
 | 
			
		||||
  globals: {
 | 
			
		||||
| 
						 | 
				
			
			@ -70,19 +66,26 @@ module.exports = {
 | 
			
		|||
    __QUASAR_SSR_PWA__: true,
 | 
			
		||||
    process: true,
 | 
			
		||||
    Capacitor: true,
 | 
			
		||||
    chrome: true
 | 
			
		||||
    chrome: true,
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  // add your custom rules here
 | 
			
		||||
  rules: {
 | 
			
		||||
    'prefer-promise-reject-errors': 'off',
 | 
			
		||||
    // VueStuff
 | 
			
		||||
    // Defaults to error on eslint-plugin-vue 8.0.3, but let us be not too strict with names
 | 
			
		||||
    'vue/multi-word-component-names': 'off',
 | 
			
		||||
 | 
			
		||||
    // TypeScript
 | 
			
		||||
    quotes: ['warn', 'single', { avoidEscape: true }],
 | 
			
		||||
    // Rejects on promises should always be of the Error type (and allow empty rejects as well)
 | 
			
		||||
    'prefer-promise-reject-errors': ['error', { allowEmptyReject: true }],
 | 
			
		||||
 | 
			
		||||
    // Allow " if ' is contained inside the string, so we can avoid escaping
 | 
			
		||||
    quotes: ['error', 'single', { avoidEscape: true }],
 | 
			
		||||
 | 
			
		||||
    // TypeScript, let us be not too strict
 | 
			
		||||
    '@typescript-eslint/explicit-function-return-type': 'off',
 | 
			
		||||
    '@typescript-eslint/explicit-module-boundary-types': 'off',
 | 
			
		||||
 | 
			
		||||
    // allow debugger during development only
 | 
			
		||||
    'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off'
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
    'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,6 +4,7 @@ node_modules
 | 
			
		|||
 | 
			
		||||
# We use yarn, so ignore npm
 | 
			
		||||
package-lock.json
 | 
			
		||||
yarn.lock
 | 
			
		||||
 | 
			
		||||
# Quasar core related directories
 | 
			
		||||
.quasar
 | 
			
		||||
| 
						 | 
				
			
			@ -17,6 +18,8 @@ package-lock.json
 | 
			
		|||
 | 
			
		||||
# Capacitor related directories and files
 | 
			
		||||
/src-capacitor/www
 | 
			
		||||
/src-capacitor/android
 | 
			
		||||
/src-capacitor/ios
 | 
			
		||||
/src-capacitor/node_modules
 | 
			
		||||
 | 
			
		||||
# BEX related directories and files
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +0,0 @@
 | 
			
		|||
[submodule "deps/quasar-ui-qcalendar"]
 | 
			
		||||
	path = deps/quasar-ui-qcalendar
 | 
			
		||||
	url = https://github.com/susnux/quasar-ui-qcalendar
 | 
			
		||||
	branch = quasar2
 | 
			
		||||
| 
						 | 
				
			
			@ -3,6 +3,6 @@
 | 
			
		|||
module.exports = {
 | 
			
		||||
  plugins: [
 | 
			
		||||
    // to edit target browsers: use "browserslist" field in package.json
 | 
			
		||||
    require('autoprefixer')
 | 
			
		||||
  ]
 | 
			
		||||
}
 | 
			
		||||
    require('autoprefixer'),
 | 
			
		||||
  ],
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,16 @@
 | 
			
		|||
pipeline:
 | 
			
		||||
  install:
 | 
			
		||||
    image: node:lts-alpine
 | 
			
		||||
    commands:
 | 
			
		||||
      - yarn install
 | 
			
		||||
  lint:
 | 
			
		||||
    image: node:lts-alpine
 | 
			
		||||
    commands:
 | 
			
		||||
      - yarn lint
 | 
			
		||||
 | 
			
		||||
  build:
 | 
			
		||||
    image: node:lts-alpine
 | 
			
		||||
    commands:
 | 
			
		||||
      - yarn quasar build
 | 
			
		||||
 | 
			
		||||
branches: [main, develop]
 | 
			
		||||
							
								
								
									
										106
									
								
								README.md
								
								
								
								
							
							
						
						| 
						 | 
				
			
			@ -1,62 +1,88 @@
 | 
			
		|||
# Flaschengeist (frontend)
 | 
			
		||||
 | 
			
		||||

 | 
			
		||||
 | 
			
		||||
Modular student club administration system, licensed under the MIT license.
 | 
			
		||||
 | 
			
		||||
## Installation
 | 
			
		||||
 | 
			
		||||
### Requirements
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
 "engines": {
 | 
			
		||||
    "node": ">= 14.18.1",
 | 
			
		||||
    "npm": ">= 6.14.12",
 | 
			
		||||
    "yarn": ">= 1.22.0"
 | 
			
		||||
 }
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
So on debian (buster and bullseye) you will need to install node.js and yarn beside the debian packages to meet the needed versions.
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
pushd ~/opt
 | 
			
		||||
wget https://nodejs.org/dist/latest-v16.x/node-v16.13.0-linux-x64.tar.xz
 | 
			
		||||
tar -xJf node-v16.13.0-linux-x64.tar.xz
 | 
			
		||||
export PATH="$(pwd)/node-v16.13.0-linux-x64/bin":"$PATH"
 | 
			
		||||
npm i -g yarn
 | 
			
		||||
npm i -g @quasar/cli
 | 
			
		||||
popd
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Install the dependencies
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
yarn install
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Be aware npm might not work.
 | 
			
		||||
 | 
			
		||||
### Configure Plugins
 | 
			
		||||
 | 
			
		||||
You can activate and deactive Plugins in `src/boot/plugins.ts`.
 | 
			
		||||
You have to set the name of the Plugin into `config.loadModules`.
 | 
			
		||||
#### Installing a plugin
 | 
			
		||||
 | 
			
		||||
Simply add it as a dependency and install it, for example installing the `pricelist`-plugin:
 | 
			
		||||
 | 
			
		||||
```sh
 | 
			
		||||
yarn add '@flaschengeist/pricelist'
 | 
			
		||||
yarn install
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
#### Enable / Disable a plugin
 | 
			
		||||
 | 
			
		||||
After installing a plugin you will have to enable it,
 | 
			
		||||
this is done by adding it to the `plugin.config.js` file.
 | 
			
		||||
For the example above the file should look like:
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
module.exports = [
 | 
			
		||||
  // pricelist plugin:
 | 
			
		||||
  '@flaschengeist/pricelist',
 | 
			
		||||
];
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Remember to rebuild the project
 | 
			
		||||
 | 
			
		||||
### Configure Backend
 | 
			
		||||
 | 
			
		||||
The application is using the API of [the backend](https://flaschengeist.dev/Flaschengeist/flaschengeist)
 | 
			
		||||
This access needs to be configured in `src/config.ts'->config.baseURL
 | 
			
		||||
 | 
			
		||||
- either you do have a proxy webserver that maps the '/api' to the backend (http://localhost:5000) or
 | 
			
		||||
- you do directly configure the backend there:`baseURL: 'http://localhost:5000'`. Be aware not committing this configuration.
 | 
			
		||||
 | 
			
		||||
### Build the application
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
```sh
 | 
			
		||||
yarn quasar build
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Notes on mobile apps (Cordova)
 | 
			
		||||
 | 
			
		||||
For mobile applications older web engines should or must be supported,
 | 
			
		||||
as manufaturer often do not update their phones, so for building cordova apps set the `BROWSERSLIST_ENV` environment variable to
 | 
			
		||||
`BROWSERSLIST_ENV=cordova`.
 | 
			
		||||
This will produce ECDMAscript compatible with iOS 13+ and Android Webview 76 (relased October 2019).
 | 
			
		||||
 | 
			
		||||
## Development
 | 
			
		||||
 | 
			
		||||
### Icons used
 | 
			
		||||
 | 
			
		||||
We are using the `mdi-v5` icon set, so feel free to use any icon from it.
 | 
			
		||||
A list can be found [here](https://materialdesignicons.com/)
 | 
			
		||||
 | 
			
		||||
### Commands useful for development
 | 
			
		||||
 | 
			
		||||
#### Start the app in development mode
 | 
			
		||||
 | 
			
		||||
Provides hot-code reloading, error reporting, etc.
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
yarn quasar dev
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
#### File linting
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
yarn run lint
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Plugins
 | 
			
		||||
 | 
			
		||||
#### Build a Plugin
 | 
			
		||||
 | 
			
		||||
A Flaschengeist-Frontend-Plugin should be placed in `src/plugins`.
 | 
			
		||||
It needs a `plugin.ts` File which exports a plugin with the following interface:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
name: string;
 | 
			
		||||
mainRoutes?: PluginRouteConfig[];
 | 
			
		||||
outRoutes?: PluginRouteConfig[];
 | 
			
		||||
requiredModules: string[];
 | 
			
		||||
version: string;
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
You have to import `FG_Plugin` from `plugins.d.ts`.
 | 
			
		||||
Please refer to our [development wiki](https://flaschengeist.dev/Flaschengeist/flaschengeist/wiki/Development).
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -40,7 +40,7 @@
 | 
			
		|||
<script lang="ts">
 | 
			
		||||
import { computed, defineComponent, PropType } from 'vue';
 | 
			
		||||
import { date as q_date } from 'quasar';
 | 
			
		||||
import { stringIsDate, stringIsTime, stringIsDateTime, Validator } from 'src/utils/validators';
 | 
			
		||||
import { stringIsDate, stringIsTime, stringIsDateTime, Validator } from '..';
 | 
			
		||||
 | 
			
		||||
export default defineComponent({
 | 
			
		||||
  name: 'IsoDateInput',
 | 
			
		||||
| 
						 | 
				
			
			@ -54,7 +54,7 @@ export default defineComponent({
 | 
			
		|||
    label: { type: String, default: 'Datum' },
 | 
			
		||||
    readonly: Boolean,
 | 
			
		||||
    rules: {
 | 
			
		||||
      type: Array as PropType<Validator[]>,
 | 
			
		||||
      type: Array as PropType<Validator<Date>[]>,
 | 
			
		||||
      default: () => [],
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
| 
						 | 
				
			
			@ -62,7 +62,22 @@ export default defineComponent({
 | 
			
		|||
  setup(props, { emit, attrs }) {
 | 
			
		||||
    const customRules = computed(() => [
 | 
			
		||||
      props.type == 'date' ? stringIsDate : props.type == 'time' ? stringIsTime : stringIsDateTime,
 | 
			
		||||
      ...props.rules,
 | 
			
		||||
      (value?: string) => {
 | 
			
		||||
        if (props.rules.length > 0 && !!value) {
 | 
			
		||||
          let date: Date | undefined = undefined;
 | 
			
		||||
          if (props.type == 'date') date = modifyDate(value);
 | 
			
		||||
          else if (props.type == 'time') date = modifyTime(value);
 | 
			
		||||
          else {
 | 
			
		||||
            const split = value.split(' ');
 | 
			
		||||
            date = modifyTime(split[1], modifyDate(split[0]));
 | 
			
		||||
          }
 | 
			
		||||
          for (const rule of props.rules) {
 | 
			
		||||
            const r = rule(date);
 | 
			
		||||
            if (typeof r === 'string') return r;
 | 
			
		||||
          }
 | 
			
		||||
          return true;
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
    ]);
 | 
			
		||||
 | 
			
		||||
    const clearable = computed(() =>
 | 
			
		||||
| 
						 | 
				
			
			@ -44,4 +44,4 @@ export default defineComponent({
 | 
			
		|||
    };
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,46 @@
 | 
			
		|||
<template>
 | 
			
		||||
  <q-avatar>
 | 
			
		||||
    <slot :avatarURL="avatarURL(modelValue)">
 | 
			
		||||
      <q-img :src="avatarURL(modelValue)" style="min-width: 100%; min-height: 100%">
 | 
			
		||||
        <template #error>
 | 
			
		||||
          <img :src="fallback" style="height: 100%" />
 | 
			
		||||
        </template>
 | 
			
		||||
      </q-img>
 | 
			
		||||
    </slot>
 | 
			
		||||
  </q-avatar>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import { PropType, defineComponent } from 'vue';
 | 
			
		||||
import { avatarURL } from '@flaschengeist/api';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Display an avatar for an user
 | 
			
		||||
 *
 | 
			
		||||
 * Slots:
 | 
			
		||||
 *  default - scope: {avatarURL}
 | 
			
		||||
 */
 | 
			
		||||
export default defineComponent({
 | 
			
		||||
  name: 'UserAvatar',
 | 
			
		||||
  props: {
 | 
			
		||||
    modelValue: {
 | 
			
		||||
      type: [Object, String] as PropType<FG.User | string>,
 | 
			
		||||
      required: true,
 | 
			
		||||
    },
 | 
			
		||||
    showZoom: {
 | 
			
		||||
      type: Boolean,
 | 
			
		||||
      default: false,
 | 
			
		||||
    },
 | 
			
		||||
    fallback: {
 | 
			
		||||
      type: String,
 | 
			
		||||
      default: 'no-image.svg',
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  emits: ['error'],
 | 
			
		||||
  setup() {
 | 
			
		||||
    return {
 | 
			
		||||
      avatarURL,
 | 
			
		||||
    };
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,5 @@
 | 
			
		|||
import IsoDateInput from './IsoDateInput.vue';
 | 
			
		||||
import PasswordInput from './PasswordInput.vue';
 | 
			
		||||
import UserAvatar from './UserAvatar.vue';
 | 
			
		||||
 | 
			
		||||
export { IsoDateInput, PasswordInput, UserAvatar };
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,10 @@
 | 
			
		|||
export { api, pinia } from './src/internal';
 | 
			
		||||
 | 
			
		||||
export * from './src/stores/';
 | 
			
		||||
 | 
			
		||||
export * from './src/utils/datetime';
 | 
			
		||||
export * from './src/utils/permission';
 | 
			
		||||
export * from './src/utils/persistent';
 | 
			
		||||
export * from './src/utils/user';
 | 
			
		||||
export * from './src/utils/validators';
 | 
			
		||||
export * from './src/utils/misc';
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,28 @@
 | 
			
		|||
{
 | 
			
		||||
  "license": "MIT",
 | 
			
		||||
  "version": "1.0.0-alpha.7",
 | 
			
		||||
  "name": "@flaschengeist/api",
 | 
			
		||||
  "author": "Tim Gröger <flaschengeist@wu5.de>",
 | 
			
		||||
  "homepage": "https://flaschengeist.dev/Flaschengeist",
 | 
			
		||||
  "description": "Modular student club administration system",
 | 
			
		||||
  "bugs": {
 | 
			
		||||
    "url": "https://flaschengeist.dev/Flaschengeist/flaschengeist/issues"
 | 
			
		||||
  },
 | 
			
		||||
  "main": "./src/index.ts",
 | 
			
		||||
  "peerDependencies": {
 | 
			
		||||
    "@quasar/app": "^3.2.4",
 | 
			
		||||
    "flaschengeist": "^2.0.0-alpha.1",
 | 
			
		||||
    "pinia": "^2.0.6"
 | 
			
		||||
  },
 | 
			
		||||
  "devDependencies": {
 | 
			
		||||
    "@flaschengeist/types": "^1.0.0-alpha.10",
 | 
			
		||||
    "@types/node": "^14.18.00",
 | 
			
		||||
    "typescript": "^4.5.2"
 | 
			
		||||
  },
 | 
			
		||||
  "prettier": {
 | 
			
		||||
    "singleQuote": true,
 | 
			
		||||
    "semi": true,
 | 
			
		||||
    "printWidth": 100,
 | 
			
		||||
    "arrowParens": "always"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,6 @@
 | 
			
		|||
//https://github.com/vuejs/vue-next/issues/3130
 | 
			
		||||
declare module '*.vue' {
 | 
			
		||||
  import { ComponentOptions } from 'vue';
 | 
			
		||||
  const component: ComponentOptions;
 | 
			
		||||
  export default component;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,6 @@
 | 
			
		|||
import axios from 'axios';
 | 
			
		||||
import { createPinia } from 'pinia';
 | 
			
		||||
 | 
			
		||||
export const api = axios.create();
 | 
			
		||||
 | 
			
		||||
export const pinia = createPinia();
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,23 @@
 | 
			
		|||
import { AxiosError } from 'axios';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Check if error is an AxiosError, and optional if a specific status was returned
 | 
			
		||||
 *
 | 
			
		||||
 * @param error Thrown error to check
 | 
			
		||||
 * @param status If set, check if this error has set thouse status code
 | 
			
		||||
 */
 | 
			
		||||
export function isAxiosError(error: unknown, status?: number) {
 | 
			
		||||
  // Check if it is an axios error (with axios 1.0 `error instanceof AxiosError` will be possible)
 | 
			
		||||
  if (typeof error !== 'object' || !error || !('isAxiosError' in error)) return false;
 | 
			
		||||
  // Check status code if status was given
 | 
			
		||||
  if (status !== undefined)
 | 
			
		||||
    return (
 | 
			
		||||
      (<AxiosError>error).response !== undefined && (<AxiosError>error).response?.status === status
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export * from './main';
 | 
			
		||||
export * from './session';
 | 
			
		||||
export * from './user';
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,161 @@
 | 
			
		|||
import { FG_Plugin } from '@flaschengeist/types';
 | 
			
		||||
import { fixSession, useSessionStore, useUserStore } from '.';
 | 
			
		||||
import { AxiosResponse } from 'axios';
 | 
			
		||||
import { api } from '../internal';
 | 
			
		||||
import { defineStore } from 'pinia';
 | 
			
		||||
import { PersistentStorage } from '../utils/persistent';
 | 
			
		||||
 | 
			
		||||
function reviveSession() {
 | 
			
		||||
  return PersistentStorage.get<FG.Session>('fg_session').then((s) => fixSession(s || undefined));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function clearPersistant() {
 | 
			
		||||
  void PersistentStorage.remove('fg_session');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function saveSession(session?: FG.Session) {
 | 
			
		||||
  if (session === undefined) return clearPersistant();
 | 
			
		||||
  PersistentStorage.set('fg_session', session).catch(() =>
 | 
			
		||||
    console.error('Could not save token to storage')
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const useMainStore = defineStore({
 | 
			
		||||
  id: 'main',
 | 
			
		||||
 | 
			
		||||
  state: () => ({
 | 
			
		||||
    session: undefined as FG.Session | undefined,
 | 
			
		||||
    user: undefined as FG.User | undefined,
 | 
			
		||||
    notifications: [] as Array<FG_Plugin.Notification>,
 | 
			
		||||
    shortcuts: [] as Array<FG_Plugin.MenuLink>,
 | 
			
		||||
  }),
 | 
			
		||||
 | 
			
		||||
  getters: {
 | 
			
		||||
    loggedIn(): boolean {
 | 
			
		||||
      return this.session !== undefined;
 | 
			
		||||
    },
 | 
			
		||||
    currentUser(): FG.User {
 | 
			
		||||
      if (this.user === undefined) throw 'Not logged in, this should not be called';
 | 
			
		||||
      return this.user;
 | 
			
		||||
    },
 | 
			
		||||
    currentSession(): FG.Session {
 | 
			
		||||
      if (this.session === undefined) throw 'Not logged in, this should not be called';
 | 
			
		||||
      return this.session;
 | 
			
		||||
    },
 | 
			
		||||
    permissions(): string[] {
 | 
			
		||||
      return this.user?.permissions || [];
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  actions: {
 | 
			
		||||
    /** Ininitalize store from saved session
 | 
			
		||||
     *  Updates session and loads current user
 | 
			
		||||
     */
 | 
			
		||||
    async init() {
 | 
			
		||||
      const sessionStore = useSessionStore();
 | 
			
		||||
      const userStore = useUserStore();
 | 
			
		||||
 | 
			
		||||
      try {
 | 
			
		||||
        this.session = await reviveSession();
 | 
			
		||||
        if (this.session !== undefined) {
 | 
			
		||||
          this.session = await sessionStore.getSession(this.session.token);
 | 
			
		||||
          if (this.session !== undefined) this.user = await userStore.getUser(this.session.userid);
 | 
			
		||||
        }
 | 
			
		||||
      } catch (error) {
 | 
			
		||||
        console.warn('Could not load token from storage', error);
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    async login(userid: string, password: string) {
 | 
			
		||||
      const userStore = useUserStore();
 | 
			
		||||
      try {
 | 
			
		||||
        const { data } = await api.post<FG.Session>('/auth', { userid, password });
 | 
			
		||||
        this.session = fixSession(data);
 | 
			
		||||
        this.user = await userStore.getUser(data.userid, true);
 | 
			
		||||
        return true;
 | 
			
		||||
      } catch ({ response }) {
 | 
			
		||||
        this.handleLoggedOut();
 | 
			
		||||
        return (<AxiosResponse | undefined>response)?.status || false;
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    async logout() {
 | 
			
		||||
      if (!this.session || !this.session.token) return false;
 | 
			
		||||
 | 
			
		||||
      try {
 | 
			
		||||
        const token = this.session.token;
 | 
			
		||||
        await api.delete(`/auth/${token}`);
 | 
			
		||||
      } catch (error) {
 | 
			
		||||
        return false;
 | 
			
		||||
      } finally {
 | 
			
		||||
        this.handleLoggedOut();
 | 
			
		||||
      }
 | 
			
		||||
      return true;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    async requestReset(userid: string) {
 | 
			
		||||
      return await api
 | 
			
		||||
        .post('/auth/reset', { userid })
 | 
			
		||||
        .then(() => true)
 | 
			
		||||
        .catch(() => false);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    async resetPassword(token: string, password: string) {
 | 
			
		||||
      return await api
 | 
			
		||||
        .post('/auth/reset', { token, password })
 | 
			
		||||
        .then(() => true)
 | 
			
		||||
        .catch(({ response }) =>
 | 
			
		||||
          response && 'status' in response ? (<AxiosResponse>response).status : false
 | 
			
		||||
        );
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    async loadNotifications(flaschengeist: FG_Plugin.Flaschengeist) {
 | 
			
		||||
      const { data } = await api.get<FG.Notification[]>('/notifications', {
 | 
			
		||||
        params:
 | 
			
		||||
          this.notifications.length > 0
 | 
			
		||||
            ? { from: this.notifications[this.notifications.length - 1].time }
 | 
			
		||||
            : {},
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      const notes = [] as FG_Plugin.Notification[];
 | 
			
		||||
      data.forEach((n) => {
 | 
			
		||||
        n.time = new Date(n.time);
 | 
			
		||||
        const plugin = flaschengeist?.plugins.filter((p) => p.id === n.plugin)[0];
 | 
			
		||||
        if (!plugin) console.debug('Could not find a parser for this notification', n);
 | 
			
		||||
        else notes.push(plugin.notification(n));
 | 
			
		||||
      });
 | 
			
		||||
      this.notifications.push(...notes);
 | 
			
		||||
      return notes;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    async removeNotification(id: number) {
 | 
			
		||||
      const idx = this.notifications.findIndex((n) => n.id === id);
 | 
			
		||||
      if (idx >= 0)
 | 
			
		||||
        try {
 | 
			
		||||
          this.notifications.splice(idx, 1);
 | 
			
		||||
          await api.delete(`/notifications/${id}`);
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
          if (this.notifications.length > idx)
 | 
			
		||||
            this.notifications.splice(idx, this.notifications.length - idx - 1);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    async getShortcuts() {
 | 
			
		||||
      const { data } = await api.get<Array<FG_Plugin.MenuLink>>(
 | 
			
		||||
        `users/${this.currentUser.userid}/shortcuts`
 | 
			
		||||
      );
 | 
			
		||||
      this.shortcuts = data;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    async setShortcuts() {
 | 
			
		||||
      await api.put(`users/${this.currentUser.userid}/shortcuts`, this.shortcuts);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    handleLoggedOut() {
 | 
			
		||||
      this.$reset();
 | 
			
		||||
      void clearPersistant();
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
export default () => useMainStore;
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,71 @@
 | 
			
		|||
import { AxiosResponse } from 'axios';
 | 
			
		||||
import { defineStore } from 'pinia';
 | 
			
		||||
import { api } from '../internal';
 | 
			
		||||
import { isAxiosError, useMainStore } from '.';
 | 
			
		||||
 | 
			
		||||
export function fixSession(s?: FG.Session) {
 | 
			
		||||
  return !s ? s : Object.assign(s, { expires: new Date(s.expires) });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const useSessionStore = defineStore({
 | 
			
		||||
  id: 'sessions',
 | 
			
		||||
 | 
			
		||||
  state: () => ({}),
 | 
			
		||||
 | 
			
		||||
  getters: {},
 | 
			
		||||
 | 
			
		||||
  actions: {
 | 
			
		||||
    async getSession(token: string) {
 | 
			
		||||
      return await api
 | 
			
		||||
        .get(`/auth/${token}`)
 | 
			
		||||
        .then(({ data }: AxiosResponse<FG.Session>) => data)
 | 
			
		||||
        .catch(() => undefined);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    async getSessions() {
 | 
			
		||||
      try {
 | 
			
		||||
        const { data } = await api.get<FG.Session[]>('/auth');
 | 
			
		||||
        data.forEach(fixSession);
 | 
			
		||||
 | 
			
		||||
        const mainStore = useMainStore();
 | 
			
		||||
        const currentSession = data.find((session) => {
 | 
			
		||||
          return session.token === mainStore.session?.token;
 | 
			
		||||
        });
 | 
			
		||||
        if (currentSession) {
 | 
			
		||||
          mainStore.session = currentSession;
 | 
			
		||||
        }
 | 
			
		||||
        return data;
 | 
			
		||||
      } catch (error) {
 | 
			
		||||
        return [] as FG.Session[];
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    async deleteSession(token: string) {
 | 
			
		||||
      const mainStore = useMainStore();
 | 
			
		||||
      if (token === mainStore.session?.token) return mainStore.logout();
 | 
			
		||||
 | 
			
		||||
      try {
 | 
			
		||||
        await api.delete(`/auth/${token}`);
 | 
			
		||||
        return true;
 | 
			
		||||
      } catch (error) {
 | 
			
		||||
        // Ignore 401, as this means we are already logged out, throw all other
 | 
			
		||||
        if (!isAxiosError(error, 401)) throw error;
 | 
			
		||||
      }
 | 
			
		||||
      return false;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    async updateSession(lifetime: number, token: string) {
 | 
			
		||||
      try {
 | 
			
		||||
        const { data } = await api.put<FG.Session>(`auth/${token}`, { value: lifetime });
 | 
			
		||||
        fixSession(data);
 | 
			
		||||
 | 
			
		||||
        const mainStore = useMainStore();
 | 
			
		||||
        if (mainStore.session?.token == data.token) mainStore.session = data;
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
      } catch (error) {
 | 
			
		||||
        return false;
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,211 @@
 | 
			
		|||
import { defineStore } from 'pinia';
 | 
			
		||||
import { api } from '../internal';
 | 
			
		||||
import { isAxiosError, useMainStore } from '.';
 | 
			
		||||
 | 
			
		||||
export function fixUser(u?: FG.User) {
 | 
			
		||||
  return !u ? u : Object.assign(u, { birthday: u.birthday ? new Date(u.birthday) : undefined });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Check if state is outdated / dirty
 | 
			
		||||
 * Value is considered outdated after 15 minutes
 | 
			
		||||
 * @param updated Time of last updated (in milliseconds see Date.now())
 | 
			
		||||
 * @returns True if outdated, false otherwise
 | 
			
		||||
 */
 | 
			
		||||
function isDirty(updated: number) {
 | 
			
		||||
  return Date.now() - updated > 15 * 60 * 1000;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const useUserStore = defineStore({
 | 
			
		||||
  id: 'users',
 | 
			
		||||
 | 
			
		||||
  state: () => ({
 | 
			
		||||
    roles: [] as FG.Role[],
 | 
			
		||||
    permissions: [] as FG.Permission[],
 | 
			
		||||
    // list of all users, include deleted ones, use `users` getter for list of active ones
 | 
			
		||||
    _users: [] as FG.User[],
 | 
			
		||||
    // Internal flags for deciding if lists need to force-loaded
 | 
			
		||||
    _dirty_users: 0,
 | 
			
		||||
    _dirty_roles: 0,
 | 
			
		||||
  }),
 | 
			
		||||
 | 
			
		||||
  getters: {
 | 
			
		||||
    users(state) {
 | 
			
		||||
      return state._users.filter((u) => !u.deleted);
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  actions: {
 | 
			
		||||
    /** Simply filter all users by ID */
 | 
			
		||||
    findUser(userid: string) {
 | 
			
		||||
      return this._users.find((user) => user.userid === userid);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    /** Retrieve user by ID
 | 
			
		||||
     * @param userid ID of user to retrieve
 | 
			
		||||
     * @param force If set to true the user is loaded from backend even when a local copy is available
 | 
			
		||||
     * @returns Retrieved user (Promise) or raise an error
 | 
			
		||||
     * @throws Probably an AxiosError if loading failed
 | 
			
		||||
     */
 | 
			
		||||
    async getUser(userid: string, force = false) {
 | 
			
		||||
      const idx = this._users.findIndex((user) => user.userid === userid);
 | 
			
		||||
      if (force || idx === -1 || isDirty(this._dirty_users)) {
 | 
			
		||||
        try {
 | 
			
		||||
          const { data } = await api.get<FG.User>(`/users/${userid}`);
 | 
			
		||||
          fixUser(data);
 | 
			
		||||
          if (idx === -1) this._users.push(data);
 | 
			
		||||
          else this._users[idx] = data;
 | 
			
		||||
          return data;
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
          // Ignore 404, throw all other
 | 
			
		||||
          if (!isAxiosError(error, 404)) throw error;
 | 
			
		||||
        }
 | 
			
		||||
      } else {
 | 
			
		||||
        return this._users[idx];
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    /** Retrieve list of all users
 | 
			
		||||
     * @param force If set to true a fresh users list is loaded from backend even when a local copy is available
 | 
			
		||||
     * @returns Array of retrieved users (Promise)
 | 
			
		||||
     * @throws Probably an AxiosError if loading failed
 | 
			
		||||
     */
 | 
			
		||||
    async getUsers(force = false) {
 | 
			
		||||
      if (force || isDirty(this._dirty_users)) {
 | 
			
		||||
        const { data } = await api.get<FG.User[]>('/users');
 | 
			
		||||
        data.forEach(fixUser);
 | 
			
		||||
        this._users = data;
 | 
			
		||||
        this._dirty_users = Date.now();
 | 
			
		||||
      }
 | 
			
		||||
      return this._users;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    /** Save modifications of user on backend
 | 
			
		||||
     * @param user Modified user to save
 | 
			
		||||
     * @throws Probably an AxiosError if request failed (404 = Invalid userid, 400 = Invalid data)
 | 
			
		||||
     */
 | 
			
		||||
    async updateUser(user: FG.User) {
 | 
			
		||||
      await api.put(`/users/${user.userid}`, user);
 | 
			
		||||
      // Modifcation accepted by backend
 | 
			
		||||
      // Save modifications back to our users list
 | 
			
		||||
      const idx = this._users.findIndex((u) => u.userid === user.userid);
 | 
			
		||||
      if (idx > -1) this._users[idx] = user;
 | 
			
		||||
      // If user was current user, save modifications back to the main store
 | 
			
		||||
      const mainStore = useMainStore();
 | 
			
		||||
      if (user.userid === mainStore.user?.userid) mainStore.user = user;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    /** Register a new user
 | 
			
		||||
     * @param user User to register (id not set)
 | 
			
		||||
     * @returns The registered user (id set)
 | 
			
		||||
     * @throws Probably an AxiosError if request failed
 | 
			
		||||
     */
 | 
			
		||||
    async createUser(user: FG.User) {
 | 
			
		||||
      const { data } = await api.post<FG.User>('/users', user);
 | 
			
		||||
      this._users.push(<FG.User>fixUser(data));
 | 
			
		||||
      return data;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    /** Delete an user
 | 
			
		||||
     * Throws if failed and resolves void if succeed
 | 
			
		||||
     *
 | 
			
		||||
     * @param user User or ID of user to delete
 | 
			
		||||
     * @throws Probably an AxiosError if request failed
 | 
			
		||||
     */
 | 
			
		||||
    async deleteUser(user: FG.User | string) {
 | 
			
		||||
      if (typeof user === 'object') user = user.userid;
 | 
			
		||||
 | 
			
		||||
      await api.delete(`/users/${user}`);
 | 
			
		||||
      this._users = this._users.filter((u) => u.userid != user);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    /** Upload an avatar for an user
 | 
			
		||||
     * Throws if failed and resolves void if succeed
 | 
			
		||||
     *
 | 
			
		||||
     * @param user User or ID of user
 | 
			
		||||
     * @param file Avatar file to upload
 | 
			
		||||
     * @throws Probably an AxiosError if request failed
 | 
			
		||||
     */
 | 
			
		||||
    async uploadAvatar(user: FG.User | string, file: string | File) {
 | 
			
		||||
      if (typeof user === 'object') user = user.userid;
 | 
			
		||||
 | 
			
		||||
      const formData = new FormData();
 | 
			
		||||
      formData.append('file', file);
 | 
			
		||||
      await api.post(`/users/${user}/avatar`, formData, {
 | 
			
		||||
        headers: {
 | 
			
		||||
          'Content-Type': 'multipart/form-data',
 | 
			
		||||
        },
 | 
			
		||||
      });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    /** Delete avatar of an user
 | 
			
		||||
     * @param user User or ID of user
 | 
			
		||||
     * @throws Probably an AxiosError if request failed
 | 
			
		||||
     */
 | 
			
		||||
    async deleteAvatar(user: FG.User | string) {
 | 
			
		||||
      if (typeof user === 'object') user = user.userid;
 | 
			
		||||
 | 
			
		||||
      await api.delete(`/users/${user}/avatar`);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    /** Retrieve list of all permissions
 | 
			
		||||
     * @param force If set to true a fresh list is loaded from backend even when a local copy is available
 | 
			
		||||
     * @returns Array of retrieved permissions (Promise)
 | 
			
		||||
     * @throws Probably an AxiosError if request failed
 | 
			
		||||
     */
 | 
			
		||||
    async getPermissions(force = false) {
 | 
			
		||||
      if (force || this.permissions.length === 0) {
 | 
			
		||||
        const { data } = await api.get<FG.Permission[]>('/roles/permissions');
 | 
			
		||||
        this.permissions = data;
 | 
			
		||||
      }
 | 
			
		||||
      return this.permissions;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    /** Retrieve list of all roles
 | 
			
		||||
     * @param force If set to true a fresh list is loaded from backend even when a local copy is available
 | 
			
		||||
     * @returns Array of retrieved roles (Promise)
 | 
			
		||||
     * @throws Probably an AxiosError if request failed
 | 
			
		||||
     */
 | 
			
		||||
    async getRoles(force = false) {
 | 
			
		||||
      if (force || isDirty(this._dirty_roles)) {
 | 
			
		||||
        const { data } = await api.get<FG.Role[]>('/roles');
 | 
			
		||||
        this.roles = data;
 | 
			
		||||
        this._dirty_roles = Date.now();
 | 
			
		||||
      }
 | 
			
		||||
      return this.roles;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    /** Save modifications of role on the backend
 | 
			
		||||
     * @param role role to save
 | 
			
		||||
     * @throws Probably an AxiosError if request failed
 | 
			
		||||
     */
 | 
			
		||||
    async updateRole(role: FG.Role) {
 | 
			
		||||
      await api.put(`/roles/${role.id}`, role);
 | 
			
		||||
 | 
			
		||||
      const idx = this.roles.findIndex((r) => r.id === role.id);
 | 
			
		||||
      if (idx != -1) this.roles[idx] = role;
 | 
			
		||||
      else this._dirty_roles = 0;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    /** Create a new role
 | 
			
		||||
     * @param role Role to create (ID not set)
 | 
			
		||||
     * @returns Created role (ID set)
 | 
			
		||||
     * @throws Probably an AxiosError if request failed
 | 
			
		||||
     */
 | 
			
		||||
    async newRole(role: FG.Role) {
 | 
			
		||||
      const { data } = await api.post<FG.Role>('/roles', role);
 | 
			
		||||
      this.roles.push(data);
 | 
			
		||||
      return data;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    /** Delete a role
 | 
			
		||||
     * @param role Role or ID of role to delete
 | 
			
		||||
     * @throws Probably an AxiosError if request failed (409 if role still in use)
 | 
			
		||||
     */
 | 
			
		||||
    async deleteRole(role: FG.Role | number) {
 | 
			
		||||
      if (typeof role === 'object') role = role.id;
 | 
			
		||||
      await api.delete(`/roles/${role}`);
 | 
			
		||||
      this.roles = this.roles.filter((r) => r.id !== role);
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			@ -17,12 +17,23 @@ export function formatDateTime(
 | 
			
		|||
  return dateTimeFormat.format(date);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function asDate(date?: Date) {
 | 
			
		||||
  return date ? formatDateTime(date, true) : '';
 | 
			
		||||
export function asDate(date?: Date, placeholder = '') {
 | 
			
		||||
  return date ? formatDateTime(date, true) : placeholder;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function asHour(date?: Date) {
 | 
			
		||||
  return date ? formatDateTime(date, false, true) : '';
 | 
			
		||||
export function asHour(date?: Date, placeholder = '') {
 | 
			
		||||
  return date ? formatDateTime(date, false, true) : placeholder;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function formatStartEnd(start: Date, end?: Date) {
 | 
			
		||||
  const today = asDate(new Date());
 | 
			
		||||
  const startDate = asDate(start);
 | 
			
		||||
  const endDate = end ? asDate(end) : '';
 | 
			
		||||
  return (
 | 
			
		||||
    (today !== startDate ? `${startDate}, ` : '') +
 | 
			
		||||
    asHour(start) +
 | 
			
		||||
    (end ? ' - ' + (endDate !== startDate ? `${endDate}, ` : '') + asHour(end) : '')
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function startOfWeek(date: Date, startMonday = true) {
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,3 @@
 | 
			
		|||
export function clone<T>(o: T): T {
 | 
			
		||||
  return <T>JSON.parse(JSON.stringify(o));
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,4 +1,4 @@
 | 
			
		|||
import { useMainStore } from 'src/stores';
 | 
			
		||||
import { useMainStore } from '../stores';
 | 
			
		||||
 | 
			
		||||
export function hasPermission(permission: string) {
 | 
			
		||||
  const store = useMainStore();
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,35 @@
 | 
			
		|||
import { LocalStorage, Platform } from 'quasar';
 | 
			
		||||
import { Storage } from '@capacitor/storage';
 | 
			
		||||
 | 
			
		||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
 | 
			
		||||
type PersitentTypes = Date | RegExp | number | boolean | string | object;
 | 
			
		||||
 | 
			
		||||
export class PersistentStorage {
 | 
			
		||||
  static clear() {
 | 
			
		||||
    if (Platform.is.capacitor) return Storage.clear();
 | 
			
		||||
    else return Promise.resolve(LocalStorage.clear());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static remove(key: string) {
 | 
			
		||||
    if (Platform.is.capacitor) return Storage.remove({ key: key });
 | 
			
		||||
    else return Promise.resolve(LocalStorage.remove(key));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static set(key: string, value: PersitentTypes) {
 | 
			
		||||
    if (Platform.is.capacitor) return Storage.set({ key, value: JSON.stringify(value) });
 | 
			
		||||
    else return Promise.resolve(LocalStorage.set(key, value));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static get<T extends PersitentTypes>(key: string) {
 | 
			
		||||
    if (Platform.is.capacitor)
 | 
			
		||||
      return Storage.get({ key }).then((v) =>
 | 
			
		||||
        v.value === null ? null : (JSON.parse(v.value) as T)
 | 
			
		||||
      );
 | 
			
		||||
    else return Promise.resolve(LocalStorage.getItem<T>(key));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static keys() {
 | 
			
		||||
    if (Platform.is.capacitor) return Storage.keys().then((v) => v.keys);
 | 
			
		||||
    else return Promise.resolve(LocalStorage.getAllKeys());
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,6 @@
 | 
			
		|||
import { api } from '../internal';
 | 
			
		||||
 | 
			
		||||
export function avatarURL(user: FG.User | string, thumbnail = true) {
 | 
			
		||||
  if (typeof user === 'object') user = user.userid;
 | 
			
		||||
  return `${api.defaults?.baseURL || ''}/users/${user}/avatar${thumbnail ? '?thumbnail' : ''}`;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,4 +1,4 @@
 | 
			
		|||
export type Validator = (value: unknown) => boolean | string;
 | 
			
		||||
export type Validator<T = unknown> = (value?: T | null) => boolean | string;
 | 
			
		||||
 | 
			
		||||
export function notEmpty(val: unknown) {
 | 
			
		||||
  return !!val || 'Feld darf nicht leer sein!';
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,16 @@
 | 
			
		|||
{
 | 
			
		||||
  "extends": "@quasar/app/tsconfig-preset",
 | 
			
		||||
  "target": "esnext",
 | 
			
		||||
  "compilerOptions": {
 | 
			
		||||
    "baseUrl": "./",
 | 
			
		||||
    "lib": [
 | 
			
		||||
      "es2020",
 | 
			
		||||
      "dom"
 | 
			
		||||
    ],
 | 
			
		||||
    "types": [
 | 
			
		||||
      "@flaschengeist/types",
 | 
			
		||||
      "@quasar/app",
 | 
			
		||||
      "node"
 | 
			
		||||
    ]
 | 
			
		||||
 }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,6 +1,4 @@
 | 
			
		|||
/* eslint-env node */
 | 
			
		||||
module.exports = {
 | 
			
		||||
  presets: [
 | 
			
		||||
    '@quasar/babel-preset-app'
 | 
			
		||||
  ]
 | 
			
		||||
}
 | 
			
		||||
  presets: ['@quasar/babel-preset-app'],
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1 +0,0 @@
 | 
			
		|||
Subproject commit 000c043ce6cb4a082d8bde4ff2b8c955eade10a4
 | 
			
		||||
							
								
								
									
										84
									
								
								package.json
								
								
								
								
							
							
						
						| 
						 | 
				
			
			@ -2,39 +2,45 @@
 | 
			
		|||
  "private": true,
 | 
			
		||||
  "license": "MIT",
 | 
			
		||||
  "version": "2.0.0-alpha.1",
 | 
			
		||||
  "productName": "Flaschengeist",
 | 
			
		||||
  "name": "flaschengeist-frontend",
 | 
			
		||||
  "productName": "flaschengeist-frontend",
 | 
			
		||||
  "name": "flaschengeist",
 | 
			
		||||
  "author": "Tim Gröger <flaschengeist@wu5.de>",
 | 
			
		||||
  "homepage": "https://flaschengeist.dev/Flaschengeist",
 | 
			
		||||
  "description": "Modular student club administration system",
 | 
			
		||||
  "bugs": {
 | 
			
		||||
    "url" : "https://flaschengeist.dev/Flaschengeist/flaschengeist-frontend/issues"
 | 
			
		||||
    "url": "https://flaschengeist.dev/Flaschengeist/flaschengeist/issues"
 | 
			
		||||
  },
 | 
			
		||||
  "scripts": {
 | 
			
		||||
    "format": "prettier --config ./package.json  --write '{,!(node_modules)/**/}*.ts'",
 | 
			
		||||
    "lint": "eslint --ext .js,.ts,.vue ./src"
 | 
			
		||||
    "format": "prettier --config ./package.json  --write '{,!(node_modules|dist|.*)/**/}*.{js,ts,vue}'",
 | 
			
		||||
    "lint": "eslint --ext .js,.ts,.vue ./src ./api"
 | 
			
		||||
  },
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
    "axios": "^0.21.1",
 | 
			
		||||
    "cordova": "^10.0.0",
 | 
			
		||||
    "pinia": "^2.0.0-alpha.10",
 | 
			
		||||
    "quasar": "^2.0.0-beta.11"
 | 
			
		||||
    "@flaschengeist/api": "file:./api",
 | 
			
		||||
    "@flaschengeist/users": "^1.0.0-alpha.3",
 | 
			
		||||
    "axios": "^0.24.0",
 | 
			
		||||
    "pinia": "^2.0.6",
 | 
			
		||||
    "quasar": "^2.3.3"
 | 
			
		||||
  },
 | 
			
		||||
  "devDependencies": {
 | 
			
		||||
    "@quasar/app": "^3.0.0-beta.10",
 | 
			
		||||
    "@quasar/extras": "^1.10.2",
 | 
			
		||||
    "@quasar/quasar-app-extension-qcalendar": "file:deps/quasar-ui-qcalendar/app-extension",
 | 
			
		||||
    "@types/node": "^12.20.7",
 | 
			
		||||
    "@types/webpack": "^4.41.27",
 | 
			
		||||
    "@types/webpack-env": "^1.16.0",
 | 
			
		||||
    "@typescript-eslint/eslint-plugin": "^4.20.0",
 | 
			
		||||
    "@typescript-eslint/parser": "^4.20.0",
 | 
			
		||||
    "eslint": "^7.23.0",
 | 
			
		||||
    "eslint-config-prettier": "^8.1.0",
 | 
			
		||||
    "eslint-plugin-vue": "^7.8.0",
 | 
			
		||||
    "eslint-webpack-plugin": "^2.5.3",
 | 
			
		||||
    "prettier": "^2.2.1",
 | 
			
		||||
    "typescript": "^4.2.3"
 | 
			
		||||
    "@capacitor/core": "^3.3.2",
 | 
			
		||||
    "@capacitor/storage": "^1.2.3",
 | 
			
		||||
    "@flaschengeist/types": "^1.0.0-alpha.10",
 | 
			
		||||
    "@quasar/app": "^3.2.4",
 | 
			
		||||
    "@quasar/extras": "^1.12.2",
 | 
			
		||||
    "@types/node": "^14.18.0",
 | 
			
		||||
    "@types/webpack": "^5.28.0",
 | 
			
		||||
    "@types/webpack-env": "^1.16.3",
 | 
			
		||||
    "@typescript-eslint/eslint-plugin": "^5.5.0",
 | 
			
		||||
    "@typescript-eslint/parser": "^5.5.0",
 | 
			
		||||
    "eslint": "^8.4.0",
 | 
			
		||||
    "eslint-config-prettier": "^8.3.0",
 | 
			
		||||
    "eslint-plugin-prettier": "^4.0.0",
 | 
			
		||||
    "eslint-plugin-vue": "^8.1.1",
 | 
			
		||||
    "eslint-webpack-plugin": "^3.1.1",
 | 
			
		||||
    "modify-source-webpack-plugin": "^3.0.0",
 | 
			
		||||
    "prettier": "^2.5.1",
 | 
			
		||||
    "typescript": "^4.5.2",
 | 
			
		||||
    "vuedraggable": "^4.1.0"
 | 
			
		||||
  },
 | 
			
		||||
  "prettier": {
 | 
			
		||||
    "singleQuote": true,
 | 
			
		||||
| 
						 | 
				
			
			@ -42,19 +48,25 @@
 | 
			
		|||
    "printWidth": 100,
 | 
			
		||||
    "arrowParens": "always"
 | 
			
		||||
  },
 | 
			
		||||
  "browserslist": [
 | 
			
		||||
    "last 10 Chrome versions",
 | 
			
		||||
    "last 10 Firefox versions",
 | 
			
		||||
    "last 4 Edge versions",
 | 
			
		||||
    "last 4 Safari versions",
 | 
			
		||||
    "last 8 Android versions",
 | 
			
		||||
    "last 1 ChromeAndroid versions",
 | 
			
		||||
    "last 1 FirefoxAndroid versions",
 | 
			
		||||
    "last 6 iOS versions"
 | 
			
		||||
  ],
 | 
			
		||||
  "browserslist": {
 | 
			
		||||
    "defaults": [
 | 
			
		||||
      "Firefox esr",
 | 
			
		||||
      "last 6 Chrome versions",
 | 
			
		||||
      "last 4 Firefox versions",
 | 
			
		||||
      "last 4 Edge versions",
 | 
			
		||||
      "last 4 Safari versions",
 | 
			
		||||
      "last 4 ChromeAndroid versions",
 | 
			
		||||
      "last 1 FirefoxAndroid versions"
 | 
			
		||||
    ],
 | 
			
		||||
    "cordova": [
 | 
			
		||||
      "iOS >= 13.0",
 | 
			
		||||
      "Android >= 76",
 | 
			
		||||
      "ChromeAndroid >= 76"
 | 
			
		||||
    ]
 | 
			
		||||
  },
 | 
			
		||||
  "engines": {
 | 
			
		||||
    "node": ">= 12.0.0",
 | 
			
		||||
    "npm": ">= 6.13.4",
 | 
			
		||||
    "yarn": ">= 1.21.1"
 | 
			
		||||
    "node": ">= 14.18.1",
 | 
			
		||||
    "npm": ">= 6.14.12",
 | 
			
		||||
    "yarn": ">= 1.22.0"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,6 @@
 | 
			
		|||
// You can add your plugins here
 | 
			
		||||
module.exports = [
 | 
			
		||||
//  '@flaschengeist/balance',
 | 
			
		||||
//  '@flaschengeist/schedule',
 | 
			
		||||
//  '@flaschengeist/pricelist',
 | 
			
		||||
]
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,168 @@
 | 
			
		|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
 | 
			
		||||
<svg
 | 
			
		||||
   xmlns:dc="http://purl.org/dc/elements/1.1/"
 | 
			
		||||
   xmlns:cc="http://creativecommons.org/ns#"
 | 
			
		||||
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
 | 
			
		||||
   xmlns:svg="http://www.w3.org/2000/svg"
 | 
			
		||||
   xmlns="http://www.w3.org/2000/svg"
 | 
			
		||||
   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
 | 
			
		||||
   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
 | 
			
		||||
   width="1024"
 | 
			
		||||
   height="1024"
 | 
			
		||||
   viewBox="0 0 270.93333 270.93334"
 | 
			
		||||
   version="1.1"
 | 
			
		||||
   id="svg37"
 | 
			
		||||
   inkscape:version="1.0.2 (e86c8708, 2021-01-15)"
 | 
			
		||||
   sodipodi:docname="no-image.svg">
 | 
			
		||||
  <defs
 | 
			
		||||
     id="defs31">
 | 
			
		||||
    <rect
 | 
			
		||||
       x="-328.72475"
 | 
			
		||||
       y="24.854798"
 | 
			
		||||
       width="167.56944"
 | 
			
		||||
       height="62.537879"
 | 
			
		||||
       id="rect1100" />
 | 
			
		||||
  </defs>
 | 
			
		||||
  <sodipodi:namedview
 | 
			
		||||
     id="base"
 | 
			
		||||
     pagecolor="#ffffff"
 | 
			
		||||
     bordercolor="#666666"
 | 
			
		||||
     borderopacity="1.0"
 | 
			
		||||
     inkscape:pageopacity="0.0"
 | 
			
		||||
     inkscape:pageshadow="2"
 | 
			
		||||
     inkscape:zoom="0.66"
 | 
			
		||||
     inkscape:cx="-222.85714"
 | 
			
		||||
     inkscape:cy="248.57143"
 | 
			
		||||
     inkscape:document-units="mm"
 | 
			
		||||
     inkscape:current-layer="layer1"
 | 
			
		||||
     inkscape:document-rotation="0"
 | 
			
		||||
     showgrid="false"
 | 
			
		||||
     units="px"
 | 
			
		||||
     inkscape:window-width="2560"
 | 
			
		||||
     inkscape:window-height="1303"
 | 
			
		||||
     inkscape:window-x="0"
 | 
			
		||||
     inkscape:window-y="25"
 | 
			
		||||
     inkscape:window-maximized="1" />
 | 
			
		||||
  <metadata
 | 
			
		||||
     id="metadata34">
 | 
			
		||||
    <rdf:RDF>
 | 
			
		||||
      <cc:Work
 | 
			
		||||
         rdf:about="">
 | 
			
		||||
        <dc:format>image/svg+xml</dc:format>
 | 
			
		||||
        <dc:type
 | 
			
		||||
           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
 | 
			
		||||
        <dc:title></dc:title>
 | 
			
		||||
      </cc:Work>
 | 
			
		||||
    </rdf:RDF>
 | 
			
		||||
  </metadata>
 | 
			
		||||
  <g
 | 
			
		||||
     inkscape:label="Ebene 1"
 | 
			
		||||
     inkscape:groupmode="layer"
 | 
			
		||||
     id="layer1">
 | 
			
		||||
    <circle
 | 
			
		||||
       id="path10"
 | 
			
		||||
       cx="135.46666"
 | 
			
		||||
       cy="135.46666"
 | 
			
		||||
       style="fill:#1976d2;fill-opacity:1;stroke-width:0.265065;opacity:1"
 | 
			
		||||
       r="135.46666" />
 | 
			
		||||
    <path
 | 
			
		||||
       id="path897"
 | 
			
		||||
       style="opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#1976d2;stroke-width:2.4226772;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
 | 
			
		||||
       d="M 443.15234 56.630859 A 66.428573 82.142858 16.845913 0 0 371.42188 118.32031 A 66.428573 82.142858 16.845913 0 0 411.19531 216.18945 A 66.428573 82.142858 16.845913 0 0 417.72266 217.72852 C 381.34438 302.48672 370.45756 410.53422 348.14648 499.98438 C 297.07736 687.66963 128.47878 622.66455 146.45508 716.38281 C 160.50823 789.6481 350.53291 863.07431 404.40039 881.20117 C 404.36927 881.70781 404.3327 882.22702 404.30664 882.7207 C 402.76028 912.46642 410.7207 918.72461 410.7207 918.72461 L 432.67188 918.59766 C 432.67187 918.59766 438.27004 922.75802 441.00195 922.53125 C 443.73387 922.30455 446.94531 918.40625 446.94531 918.40625 L 516.89062 924.79297 C 516.89062 924.79297 519.31971 928.09007 521.125 928.27148 C 522.93029 928.45267 525.90234 925.73828 525.90234 925.73828 L 547.53125 926.69531 C 547.53125 926.69531 549.70216 931.12195 551.70508 931.54492 C 553.70725 931.97129 555.09081 928.73815 557.0293 929.03711 C 572.07401 931.3732 576.56924 937.03281 582.65039 957.60156 C 587.77505 974.93535 595.22123 992.9761 628.75781 1000.5176 C 648.78447 1005.021 775.66385 1000.6487 849.12305 998.74219 C 849.12305 998.74219 858.5188 1005.9328 870.60547 1002.9863 C 910.19976 993.33421 919.78542 952.33706 923.33398 921.09961 C 926.88262 889.86212 910.49308 842.14037 892.4043 835.26367 C 874.31552 828.38693 867.54688 834.25781 867.54688 834.25781 C 794.38713 828.15886 695.31802 794.91067 642.43555 796.74805 C 623.72658 797.39809 605.92942 809.14688 595.65625 826.28125 C 588.66186 837.94703 583.48245 859.20701 563.14258 859.07812 C 560.89588 859.11237 559.32296 855.73577 557.25 855.80078 C 555.17708 855.86568 552.45117 858.87891 552.45117 858.87891 L 531.66797 857.41211 C 531.66797 857.41211 529.50203 853.62212 527.45508 853.38477 C 525.40816 853.14741 521.82422 856.70312 521.82422 856.70312 L 449.90234 850.62305 C 449.90234 850.62305 447.13702 845.72836 444.7168 844.78711 C 442.29665 843.84582 436.68945 846.35352 436.68945 846.35352 L 415.74219 842.4082 C 415.74219 842.4082 407.89779 846.84558 405.02539 873.69922 C 358.98121 845.1153 229.07948 771.28872 265.40039 726.04102 C 306.49077 674.8517 472.92361 721.17976 650.12695 656.71875 C 726.82706 628.35646 797.61671 580.25753 845.84766 519.08398 A 66.376657 87.827348 48.964508 0 0 927.6875 519.24805 A 66.376657 87.827348 48.964508 0 0 980.98047 413.88477 A 66.376657 87.827348 48.964508 0 0 907.37109 380.61328 C 911.18565 353.15829 910.56576 324.56748 904.71094 295.1582 C 874.19541 141.87518 734.80037 48.0882 582.23438 78.189453 C 572.33148 80.143182 562.48437 82.604632 552.73047 85.566406 C 533.35813 91.448951 516.25153 99.658419 501.06836 109.80859 A 66.428573 82.142858 16.845913 0 0 458.80469 58.953125 A 66.428573 82.142858 16.845913 0 0 443.15234 56.630859 z M 598.64062 188.20703 C 604.22194 188.22929 609.06312 189.70004 612.92773 192.57031 C 630.98057 205.9773 623.87627 246.11384 597.05859 282.2168 C 570.24164 318.31869 533.86885 336.71569 515.81836 323.30664 C 497.76711 309.89888 504.87302 269.76201 531.68945 233.66016 C 549.9558 209.06922 573.57677 191.68513 592.82031 188.66992 L 592.82227 188.66992 C 594.83831 188.35408 596.78019 188.19961 598.64062 188.20703 z M 778.42969 278.44141 C 784.01155 278.46343 788.85382 279.93226 792.71875 282.80273 C 810.7689 296.21155 803.66213 336.34605 776.8457 372.44727 C 750.02943 408.54893 713.65672 426.94663 695.60547 413.53906 C 677.55528 400.13024 684.66205 359.99578 711.47852 323.89453 C 729.74482 299.3036 753.36587 281.91757 772.60938 278.90234 C 774.62562 278.58637 776.56907 278.43406 778.42969 278.44141 z M 582.87695 399.91016 C 586.53338 399.95128 589.93604 400.53593 593.03711 401.66406 C 620.67041 411.71655 618.60959 461.69743 588.43555 513.29883 C 558.26146 564.90004 511.39926 598.58305 483.76562 588.53125 C 456.13229 578.47876 458.1931 528.49788 488.36719 476.89648 C 510.90103 438.36065 543.79364 408.38759 571.19336 401.41992 C 575.31072 400.37297 579.22053 399.86903 582.87695 399.91016 z M 643.83594 816.76172 C 685.1496 816.94824 851.34766 854.11133 851.34766 854.11133 C 851.34766 854.11133 688.31573 835.12065 650.18555 833.82812 C 635.17621 833.31932 591.27148 868.21875 591.27148 868.21875 C 591.27148 868.21875 622.20895 822.68111 636.20117 817.55664 C 637.73138 816.99622 640.33478 816.74591 643.83594 816.76172 z "
 | 
			
		||||
       transform="scale(0.26458333)" />
 | 
			
		||||
    <path
 | 
			
		||||
       id="path10-8"
 | 
			
		||||
       style="fill-opacity:1;stroke-width:3.64724414;fill:#ffffff;stroke-miterlimit:4;stroke-dasharray:none;stroke:#ffffff;stroke-opacity:1;opacity:0.80057803"
 | 
			
		||||
       d="M 512 0 A 511.99997 511.99997 0 0 0 0 512 A 511.99997 511.99997 0 0 0 512 1024 A 511.99997 511.99997 0 0 0 659.25 1002.3672 C 706.36552 1003.0651 793.17503 1000.1943 849.12305 998.74219 C 849.12305 998.74219 858.5188 1005.9328 870.60547 1002.9863 C 910.19976 993.33421 919.78542 952.33706 923.33398 921.09961 C 926.20746 895.80534 916.007 859.7095 902.41797 843.23633 A 511.99997 511.99997 0 0 0 1024 512 A 511.99997 511.99997 0 0 0 512 0 z "
 | 
			
		||||
       transform="scale(0.26458333)" />
 | 
			
		||||
    <rect
 | 
			
		||||
       style="fill:#000000;fill-opacity:1;stroke:#ffffff;stroke-width:0.33699;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
 | 
			
		||||
       id="rect942-1"
 | 
			
		||||
       width="76.028526"
 | 
			
		||||
       height="73.388649"
 | 
			
		||||
       x="-21.278112"
 | 
			
		||||
       y="109.32571"
 | 
			
		||||
       ry="3.5350549"
 | 
			
		||||
       transform="rotate(-30.00892)" />
 | 
			
		||||
    <rect
 | 
			
		||||
       style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.391977;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
 | 
			
		||||
       id="rect944-7"
 | 
			
		||||
       width="69.4505"
 | 
			
		||||
       height="56.151112"
 | 
			
		||||
       x="-17.909185"
 | 
			
		||||
       y="113.14103"
 | 
			
		||||
       ry="0"
 | 
			
		||||
       transform="rotate(-30.00892)" />
 | 
			
		||||
    <path
 | 
			
		||||
       id="path10-3-94"
 | 
			
		||||
       style="fill:#1976d2;fill-opacity:1;stroke-width:0.0683297"
 | 
			
		||||
       d="m 68.884108,90.871044 a 34.92124,34.92124 0 0 0 -11.74769,43.865396 l 2.70637,4.68588 a 34.92124,34.92124 0 0 0 15.52651,12.5468 L 123.2496,124.31547 a 34.92124,34.92124 0 0 0 -2.38462,-18.10096 l -4.46922,-7.73814 A 34.92124,34.92124 0 0 0 73.568128,88.16575 Z" />
 | 
			
		||||
    <path
 | 
			
		||||
       id="path897-6-8"
 | 
			
		||||
       style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#1976d2;stroke-width:0.165241;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
 | 
			
		||||
       d="m 69.039278,95.120659 a 5.6025989,4.5307973 76.836993 0 0 -2.13225,6.090461 5.6025989,4.5307973 76.836993 0 0 5.68756,4.42371 5.6025989,4.5307973 76.836993 0 0 0.43811,-0.13196 c 0.74268,6.24695 3.78537,13.00002 5.51895,19.04423 3.38604,12.82723 -8.78931,14.73905 -4.53067,19.66107 1.76551,2.04052 6.4553,2.39549 11.0381,2.16453 l 3.43497,-1.98389 c -3.77377,-0.36303 -7.4885,-1.26121 -7.11831,-3.66758 0.68073,-4.42505 12.09089,-7.36618 20.358052,-17.21816 3.5626,-4.29154 6.10303,-9.54716 6.86491,-14.80546 a 4.5272563,5.9903123 18.955588 0 0 4.83918,-2.78197 4.5272563,5.9903123 18.955588 0 0 -0.44664,-8.041018 4.5272563,5.9903123 18.955588 0 0 -5.48235,0.545791 c -0.71126,-1.751685 -1.72325,-3.419125 -3.07226,-4.956384 -7.031112,-8.012324 -18.463402,-8.796579 -26.447502,-1.814405 -0.51824,0.453207 -1.01578,0.934617 -1.49084,1.442271 -0.94352,1.008269 -1.67389,2.076631 -2.2244,3.194051 a 5.6025989,4.5307973 76.836993 0 0 -4.23087,-1.562013 5.6025989,4.5307973 76.836993 0 0 -1.00374,0.396734 z m 13.67184,2.467287 c 0.33015,-0.189526 0.66651,-0.267379 0.99269,-0.229688 1.52358,0.176032 2.47307,2.788932 2.12069,5.836062 -0.35237,3.04705 -1.87308,5.37436 -3.3966,5.19813 -1.52351,-0.17613 -2.47289,-2.78913 -2.12054,-5.83615 0.24002,-2.07551 1.04204,-3.90793 2.07575,-4.742444 l 1.7e-4,-9.5e-5 c 0.10831,-0.08739 0.21769,-0.162799 0.32783,-0.225833 z m 13.69685,-0.803574 c 0.33018,-0.189545 0.6664,-0.267533 0.9926,-0.229843 1.52349,0.176235 2.4729,2.789172 2.12054,5.836151 -0.35234,3.04702 -1.87298,5.37441 -3.39651,5.1983 -1.52348,-0.17624 -2.4729,-2.78917 -2.12054,-5.83617 0.24,-2.075497 1.04211,-3.908161 2.07582,-4.742688 0.10834,-0.0874 0.21795,-0.162716 0.32809,-0.22575 z m -7.40627,13.845038 c 0.21745,-0.12213 0.43816,-0.20399 0.65981,-0.24312 1.97501,-0.34891 3.55829,2.67343 3.53636,6.75042 -0.0219,4.077 -1.64072,7.66488 -3.61571,8.01383 -1.975,0.34891 -3.55819,-2.67326 -3.53627,-6.75027 0.0164,-3.04468 0.93655,-5.93703 2.31716,-7.28321 0.20748,-0.20228 0.42129,-0.36535 0.63865,-0.48765 z m 17.352832,21.22847 c -0.10315,0.0588 -0.20272,0.11824 -0.29832,0.17807 -1.05105,0.65671 -1.69275,1.90208 -1.75,3.22056 l 1.74663,-1.00878 c 0.10074,-0.33823 0.21509,-0.61452 0.34506,-0.77008 0.0713,-0.0853 0.2166,-0.18885 0.42393,-0.30733 0.72661,-0.41504 2.22115,-1.01463 3.95458,-1.65068 l 5.84666,-3.37678 c -3.78613,1.29335 -7.9478,2.39117 -10.26846,3.71516 z" />
 | 
			
		||||
    <rect
 | 
			
		||||
       style="opacity:1;fill:#000000;fill-opacity:1;stroke:#ffffff;stroke-width:0.33699;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
 | 
			
		||||
       id="rect942"
 | 
			
		||||
       width="76.028526"
 | 
			
		||||
       height="73.388649"
 | 
			
		||||
       x="97.497429"
 | 
			
		||||
       y="66.694847"
 | 
			
		||||
       ry="3.5350549" />
 | 
			
		||||
    <rect
 | 
			
		||||
       style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.391977;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
 | 
			
		||||
       id="rect944"
 | 
			
		||||
       width="69.4505"
 | 
			
		||||
       height="56.151112"
 | 
			
		||||
       x="100.86639"
 | 
			
		||||
       y="70.51017"
 | 
			
		||||
       ry="0" />
 | 
			
		||||
    <path
 | 
			
		||||
       id="path10-3"
 | 
			
		||||
       style="fill:#1976d2;fill-opacity:1;stroke-width:0.0683297"
 | 
			
		||||
       d="M 132.97782,70.510038 A 34.92124,34.92124 0 0 0 100.8663,102.61974 v 5.41128 a 34.92124,34.92124 0 0 0 7.17007,18.63021 h 55.29238 a 34.92124,34.92124 0 0 0 6.98797,-16.86711 v -8.93604 A 34.92124,34.92124 0 0 0 138.38694,70.510038 Z" />
 | 
			
		||||
    <path
 | 
			
		||||
       id="path897-6"
 | 
			
		||||
       style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#1976d2;stroke-width:0.165241;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
 | 
			
		||||
       d="m 130.9868,74.267588 a 4.5307973,5.6025989 16.845913 0 0 -4.89247,4.20761 4.5307973,5.6025989 16.845913 0 0 2.71268,6.675244 4.5307973,5.6025989 16.845913 0 0 0.44538,0.10485 c -2.4812,5.78097 -3.22383,13.15053 -4.74557,19.251518 -3.4832,12.80118 -14.98258,8.3674 -13.7565,14.75951 0.5083,2.64997 4.39189,5.30288 8.47586,7.39491 h 3.96671 c -3.08632,-2.20176 -5.85386,-4.8374 -4.32979,-6.73605 2.80259,-3.4914 14.15415,-0.33165 26.2404,-4.72825 5.23137,-1.93447 10.05977,-5.215 13.34938,-9.38737 a 4.5272563,5.9903123 48.964508 0 0 5.58183,0.0112 4.5272563,5.9903123 48.964508 0 0 3.63483,-7.186478 4.5272563,5.9903123 48.964508 0 0 -5.0204,-2.26929 c 0.26017,-1.87259 0.21778,-3.82264 -0.18155,-5.82851 -2.08133,-10.454754 -11.58886,-16.851564 -21.9947,-14.798494 -0.67543,0.13326 -1.34705,0.3013 -2.01232,0.50331 -1.32131,0.40122 -2.4881,0.96108 -3.52367,1.65338 a 4.5307973,5.6025989 16.845913 0 0 -2.8825,-3.46863 4.5307973,5.6025989 16.845913 0 0 -1.0676,-0.15845 z m 10.60512,8.974304 c 0.38068,10e-4 0.71089,0.10181 0.97449,0.29758 1.2313,0.91443 0.74671,3.65194 -1.08241,6.11436 -1.82906,2.46235 -4.30989,3.71712 -5.54104,2.80255 -1.23119,-0.91448 -0.74644,-3.65202 1.08259,-6.11436 1.24587,-1.67724 2.85684,-2.8629 4.16936,-3.06855 h 1.8e-4 c 0.1375,-0.0215 0.26994,-0.0321 0.39683,-0.0316 z m 12.26265,6.15442 c 0.38072,0.001 0.71088,0.10162 0.97449,0.2974 1.23112,0.91456 0.74644,3.65206 -1.08258,6.11436 -1.82902,2.46234 -4.30984,3.71721 -5.54104,2.80274 -1.23112,-0.91456 -0.74645,-3.65206 1.08258,-6.11437 1.24586,-1.67724 2.85702,-2.86307 4.16954,-3.06873 0.13752,-0.0215 0.27011,-0.0319 0.39701,-0.0314 z m -13.33783,8.28494 c 0.24939,0.003 0.48145,0.0425 0.69297,0.11947 1.88474,0.68563 1.74421,4.094668 -0.31382,7.614168 -2.05805,3.51949 -5.25426,5.8168 -7.13902,5.13121 -1.88474,-0.68563 -1.74422,-4.09448 0.31382,-7.61399 1.53693,-2.62835 3.78032,-4.672758 5.64914,-5.147988 0.28082,-0.0714 0.54752,-0.10567 0.79691,-0.10287 z m 4.40955,27.061498 c -0.11872,-7e-4 -0.23468,0.001 -0.34739,0.005 -1.2386,0.043 -2.41713,0.80049 -3.12612,1.9136 h 2.01701 c 0.2564,-0.24251 0.4936,-0.42457 0.68395,-0.49428 0.10436,-0.0382 0.28201,-0.0552 0.52081,-0.0541 0.83678,0.004 2.43085,0.23225 4.25002,0.54842 h 6.75175 c -3.92545,-0.7736 -8.07829,-1.90434 -10.75003,-1.91848 z" />
 | 
			
		||||
    <rect
 | 
			
		||||
       style="fill:#000000;fill-opacity:1;stroke:#ffffff;stroke-width:0.33699;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
 | 
			
		||||
       id="rect942-6"
 | 
			
		||||
       width="76.028526"
 | 
			
		||||
       height="73.388649"
 | 
			
		||||
       x="183.4511"
 | 
			
		||||
       y="-21.159952"
 | 
			
		||||
       ry="3.5350549"
 | 
			
		||||
       transform="rotate(27.418518)" />
 | 
			
		||||
    <rect
 | 
			
		||||
       style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.391977;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
 | 
			
		||||
       id="rect944-6"
 | 
			
		||||
       width="69.4505"
 | 
			
		||||
       height="56.151112"
 | 
			
		||||
       x="186.82002"
 | 
			
		||||
       y="-17.344629"
 | 
			
		||||
       ry="0"
 | 
			
		||||
       transform="rotate(27.418518)" />
 | 
			
		||||
    <path
 | 
			
		||||
       id="path10-3-9"
 | 
			
		||||
       style="fill:#1976d2;fill-opacity:1;stroke-width:0.0683297"
 | 
			
		||||
       d="m 202.32517,85.418659 a 34.92124,34.92124 0 0 0 -43.2904,13.715795 l -2.49182,4.803416 a 34.92124,34.92124 0 0 0 -2.21435,19.83912 l 49.0812,25.46141 a 34.92124,34.92124 0 0 0 13.97007,-11.7545 l 4.11493,-7.93223 A 34.92124,34.92124 0 0 0 207.12667,87.90949 Z" />
 | 
			
		||||
    <path
 | 
			
		||||
       id="path897-6-3"
 | 
			
		||||
       style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#1976d2;stroke-width:0.165241;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
 | 
			
		||||
       d="m 198.82751,87.837273 a 4.5307973,5.6025989 44.264431 0 0 -6.28043,1.482039 4.5307973,5.6025989 44.264431 0 0 -0.6659,7.174546 4.5307973,5.6025989 44.264431 0 0 0.34706,0.298162 c -4.86454,3.98902 -8.91733,10.18876 -13.07755,14.90366 -8.9867,9.75921 -17.15262,0.52818 -19.00775,6.76684 -0.76908,2.58635 1.45663,6.72959 4.11849,10.46723 l 3.52111,1.82662 c -1.72575,-3.37564 -2.96872,-6.98962 -0.74155,-7.97318 4.09551,-1.80864 12.71689,6.22341 25.47003,7.88625 5.5345,0.69181 11.33116,0.003 16.17256,-2.18564 a 4.5272563,5.9903123 76.383026 0 0 4.94964,2.5803 4.5272563,5.9903123 76.383026 0 0 6.5358,-4.70541 4.5272563,5.9903123 76.383026 0 0 -3.41147,-4.3262 c 1.09325,-1.54243 1.95359,-3.29295 2.5228,-5.25738 2.96674,-10.23876 -2.52713,-20.295083 -12.70946,-23.264393 -0.66092,-0.192737 -1.33447,-0.352844 -2.01803,-0.479873 -1.35764,-0.252295 -2.65117,-0.292618 -3.88921,-0.154954 a 4.5307973,5.6025989 44.264431 0 0 -0.96143,-4.406339 4.5307973,5.6025989 44.264431 0 0 -0.87472,-0.632269 z m 5.28126,12.849707 c 0.33746,0.17619 0.58416,0.41773 0.72799,0.71289 0.67191,1.37871 -1.01884,3.58556 -3.7764,4.92908 -2.75748,1.34349 -5.53743,1.31492 -6.20913,-0.0638 -0.67178,-1.3787 1.01911,-3.58551 3.77656,-4.929 1.87826,-0.91512 3.85425,-1.22576 5.11402,-0.80391 l 1.7e-4,8e-5 c 0.13196,0.0442 0.25439,0.0958 0.3668,0.15469 z m 8.05112,11.10986 c 0.33749,0.17621 0.58422,0.41755 0.72807,0.71273 0.67168,1.37874 -1.01913,3.58554 -3.77655,4.929 -2.75744,1.3435 -5.53743,1.31502 -6.20922,-0.0637 -0.67169,-1.37874 1.01912,-3.58554 3.77655,-4.92901 1.87826,-0.91512 3.8545,-1.22583 5.11428,-0.80399 0.13197,0.0442 0.25445,0.0961 0.36687,0.15495 z m -15.65465,1.21237 c 0.21999,0.1175 0.4078,0.25943 0.56011,0.42515 1.3573,1.47651 -0.33727,4.43789 -3.7848,6.61434 -3.44753,2.17643 -7.34258,2.74386 -8.69992,1.26738 -1.3573,-1.47651 0.33717,-4.43772 3.78471,-6.61418 2.57461,-1.62536 5.50741,-2.40706 7.38513,-1.96834 0.28216,0.0659 0.53468,0.15833 0.75477,0.27565 z m -8.54725,26.05213 c -0.10506,-0.0553 -0.20878,-0.10718 -0.31067,-0.15553 -1.11927,-0.53219 -2.51422,-0.40249 -3.65614,0.2591 l 1.79043,0.92881 c 0.33927,-0.0972 0.63366,-0.14958 0.83473,-0.12381 0.11023,0.0142 0.27575,0.0809 0.48722,0.19181 0.74094,0.38887 2.05083,1.32553 3.52006,2.44389 l 5.9933,3.10909 c -3.12826,-2.49432 -6.2939,-5.41036 -8.65901,-6.65322 z" />
 | 
			
		||||
    <text
 | 
			
		||||
       xml:space="preserve"
 | 
			
		||||
       id="text1098"
 | 
			
		||||
       style="font-style:normal;font-weight:normal;font-size:22.57779999999999987px;line-height:1.35;font-family:sans-serif;white-space:pre;shape-inside:url(#rect1100);fill:#000000;fill-opacity:1;stroke:none;"
 | 
			
		||||
       x="52.690414"
 | 
			
		||||
       y="0"
 | 
			
		||||
       transform="translate(380.03788,147.12437)"><tspan
 | 
			
		||||
         x="-284.65002"
 | 
			
		||||
         y="47.162986"><tspan
 | 
			
		||||
           style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:condensed;font-size:22.5778px;font-family:'Helvetica Neue';-inkscape-font-specification:'Helvetica Neue Bold Condensed';text-align:center;text-anchor:middle">Kein Bild </tspan></tspan><tspan
 | 
			
		||||
         x="-292.36704"
 | 
			
		||||
         y="78.223231"><tspan
 | 
			
		||||
           style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:condensed;font-size:22.5778px;font-family:'Helvetica Neue';-inkscape-font-specification:'Helvetica Neue Bold Condensed';text-align:center;text-anchor:middle">vorhanden</tspan></tspan></text>
 | 
			
		||||
  </g>
 | 
			
		||||
</svg>
 | 
			
		||||
| 
		 After Width: | Height: | Size: 18 KiB  | 
							
								
								
									
										105
									
								
								quasar.conf.js
								
								
								
								
							
							
						
						| 
						 | 
				
			
			@ -8,12 +8,12 @@
 | 
			
		|||
 | 
			
		||||
/* eslint-env node */
 | 
			
		||||
/* eslint-disable @typescript-eslint/no-var-requires */
 | 
			
		||||
const ESLintPlugin = require('eslint-webpack-plugin')
 | 
			
		||||
const ESLintPlugin = require('eslint-webpack-plugin');
 | 
			
		||||
const { ModifySourcePlugin } = require('modify-source-webpack-plugin');
 | 
			
		||||
const { configure } = require('quasar/wrappers');
 | 
			
		||||
 
 | 
			
		||||
 | 
			
		||||
module.exports = configure(function (/* ctx */) {
 | 
			
		||||
  return {
 | 
			
		||||
    // https://quasar.dev/quasar-cli/supporting-ts
 | 
			
		||||
    // https://quasar.dev/quasar-cli/supporting-ts
 | 
			
		||||
    supportTS: {
 | 
			
		||||
      tsCheckerConfig: {
 | 
			
		||||
| 
						 | 
				
			
			@ -21,7 +21,7 @@ module.exports = configure(function (/* ctx */) {
 | 
			
		|||
          enabled: true,
 | 
			
		||||
          files: './src/**/*.{ts,tsx,js,jsx,vue}',
 | 
			
		||||
        },
 | 
			
		||||
      }
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // https://quasar.dev/quasar-cli/prefetch-feature
 | 
			
		||||
| 
						 | 
				
			
			@ -30,7 +30,7 @@ module.exports = configure(function (/* ctx */) {
 | 
			
		|||
    // app boot file (/src/boot)
 | 
			
		||||
    // --> boot files are part of "main.js"
 | 
			
		||||
    // https://quasar.dev/quasar-cli/boot-files
 | 
			
		||||
    boot: ['axios', 'store', 'plugins', 'loading', 'login'],
 | 
			
		||||
    boot: ['axios', 'store', 'plugins', 'login', 'init'],
 | 
			
		||||
 | 
			
		||||
    // https://quasar.dev/quasar-cli/quasar-conf-js#Property%3A-css
 | 
			
		||||
    css: ['app.scss'],
 | 
			
		||||
| 
						 | 
				
			
			@ -39,12 +39,12 @@ module.exports = configure(function (/* ctx */) {
 | 
			
		|||
    extras: [
 | 
			
		||||
      // 'eva-icons',
 | 
			
		||||
      // 'fontawesome-v5',
 | 
			
		||||
      // 'ionicons-v4',
 | 
			
		||||
      // 'ionicons-v5',
 | 
			
		||||
      // 'line-awesome',
 | 
			
		||||
      // 'material-icons',
 | 
			
		||||
      'mdi-v5',
 | 
			
		||||
      'mdi-v6',
 | 
			
		||||
      // 'themify',
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
      // 'roboto-font-latin-ext', // this or either 'roboto-font', NEVER both!
 | 
			
		||||
      'roboto-font', // optional, you are not bound to it
 | 
			
		||||
    ],
 | 
			
		||||
| 
						 | 
				
			
			@ -60,10 +60,8 @@ module.exports = configure(function (/* ctx */) {
 | 
			
		|||
      // Applies only if "transpile" is set to true.
 | 
			
		||||
      // transpileDependencies: [],
 | 
			
		||||
 | 
			
		||||
      // rtl: false, // https://quasar.dev/options/rtl-support
 | 
			
		||||
      // preloadChunks: true,
 | 
			
		||||
      // showProgress: false,
 | 
			
		||||
      // gzip: true,
 | 
			
		||||
      // rtl: false,
 | 
			
		||||
 | 
			
		||||
      // analyze: true,
 | 
			
		||||
 | 
			
		||||
      // Options below are automatically set depending on the env, set them if you want to override
 | 
			
		||||
| 
						 | 
				
			
			@ -71,34 +69,59 @@ module.exports = configure(function (/* ctx */) {
 | 
			
		|||
 | 
			
		||||
      // https://quasar.dev/quasar-cli/handling-webpack
 | 
			
		||||
      // "chain" is a webpack-chain object https://github.com/neutrinojs/webpack-chain
 | 
			
		||||
      chainWebpack (chain) {
 | 
			
		||||
        chain.plugin('eslint-webpack-plugin')
 | 
			
		||||
          .use(ESLintPlugin, [{
 | 
			
		||||
            extensions: [ 'ts', 'js', 'vue' ],
 | 
			
		||||
            exclude: 'node_modules'
 | 
			
		||||
          }])
 | 
			
		||||
        },
 | 
			
		||||
      
 | 
			
		||||
      chainWebpack(chain) {
 | 
			
		||||
        chain.plugin('eslint-webpack-plugin').use(ESLintPlugin, [
 | 
			
		||||
          {
 | 
			
		||||
            extensions: ['ts', 'js', 'vue'],
 | 
			
		||||
            exclude: ['node_modules', 'src-capacitor'],
 | 
			
		||||
          },
 | 
			
		||||
        ]);
 | 
			
		||||
        chain.plugin('modify-source-webpack-plugin').use(ModifySourcePlugin, [
 | 
			
		||||
          {
 | 
			
		||||
            rules: [
 | 
			
		||||
              {
 | 
			
		||||
                test: /plugins\.ts$/,
 | 
			
		||||
                modify: (src, filename) => {
 | 
			
		||||
                  const custom_plgns = require('./plugin.config.js');
 | 
			
		||||
                  const required_plgns = require('./src/vendor-plugin.config.js');
 | 
			
		||||
                  return src.replace(
 | 
			
		||||
                    /\/\* *INSERT_PLUGIN_LIST *\*\//,
 | 
			
		||||
                    [...custom_plgns, ...required_plgns]
 | 
			
		||||
                      .map((v) => `import("${v}").catch(() => "${v}")`)
 | 
			
		||||
                      .join(',')
 | 
			
		||||
                  );
 | 
			
		||||
                },
 | 
			
		||||
              },
 | 
			
		||||
            ],
 | 
			
		||||
          },
 | 
			
		||||
        ]);
 | 
			
		||||
        chain.merge({
 | 
			
		||||
          snapshot: {
 | 
			
		||||
            managedPaths: [],
 | 
			
		||||
          },
 | 
			
		||||
        });
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // Full list of options: https://quasar.dev/quasar-cli/quasar-conf-js#Property%3A-devServer
 | 
			
		||||
    devServer: {
 | 
			
		||||
      https: false,
 | 
			
		||||
      port: 8080,
 | 
			
		||||
      open: false // opens browser window automatically
 | 
			
		||||
      open: false, // opens browser window automatically
 | 
			
		||||
      watchFiles: { paths: ['/node_modules/@flaschengeist/**/*'] },
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // https://quasar.dev/quasar-cli/quasar-conf-js#Property%3A-framework
 | 
			
		||||
    framework: {
 | 
			
		||||
      iconSet: 'mdi-v5', // Quasar icon set
 | 
			
		||||
      iconSet: 'mdi-v6', // Quasar icon set
 | 
			
		||||
      lang: 'de', // Quasar language pack
 | 
			
		||||
      config: {
 | 
			
		||||
        dark: 'auto',
 | 
			
		||||
        loadingBar: {
 | 
			
		||||
          position: 'top',
 | 
			
		||||
          color: 'warning',
 | 
			
		||||
          size: '5px'
 | 
			
		||||
        }
 | 
			
		||||
          size: '5px',
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
 | 
			
		||||
      // For special cases outside of where the auto-import stategy can have an impact
 | 
			
		||||
| 
						 | 
				
			
			@ -109,13 +132,7 @@ module.exports = configure(function (/* ctx */) {
 | 
			
		|||
      // directives: [],
 | 
			
		||||
 | 
			
		||||
      // Quasar plugins
 | 
			
		||||
      plugins: [
 | 
			
		||||
        'LocalStorage',
 | 
			
		||||
        'SessionStorage',
 | 
			
		||||
        'Loading',
 | 
			
		||||
        'Notify',
 | 
			
		||||
        'LoadingBar'
 | 
			
		||||
      ]
 | 
			
		||||
      plugins: ['LocalStorage', 'SessionStorage', 'Dialog', 'Loading', 'Notify', 'LoadingBar'],
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // animations: 'all', // --- includes all animations
 | 
			
		||||
| 
						 | 
				
			
			@ -124,7 +141,7 @@ module.exports = configure(function (/* ctx */) {
 | 
			
		|||
 | 
			
		||||
    // https://quasar.dev/quasar-cli/developing-ssr/configuring-ssr
 | 
			
		||||
    ssr: {
 | 
			
		||||
      pwa: false
 | 
			
		||||
      pwa: false,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // https://quasar.dev/quasar-cli/developing-pwa/configuring-pwa
 | 
			
		||||
| 
						 | 
				
			
			@ -143,20 +160,20 @@ module.exports = configure(function (/* ctx */) {
 | 
			
		|||
          {
 | 
			
		||||
            src: 'flaschengeist-logo.svg',
 | 
			
		||||
            sizes: 'any',
 | 
			
		||||
            type: 'image/svg+xml'
 | 
			
		||||
            type: 'image/svg+xml',
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            src: 'favicon-128x128.png',
 | 
			
		||||
            sizes: '128x128',
 | 
			
		||||
            type: 'image/png'
 | 
			
		||||
            type: 'image/png',
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            src: 'favicon-256x256.png',
 | 
			
		||||
            sizes: '256x256',
 | 
			
		||||
            type: 'image/png'
 | 
			
		||||
            type: 'image/png',
 | 
			
		||||
          },
 | 
			
		||||
        ]
 | 
			
		||||
      }
 | 
			
		||||
        ],
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // Full list of options: https://quasar.dev/quasar-cli/developing-cordova-apps/configuring-cordova
 | 
			
		||||
| 
						 | 
				
			
			@ -166,7 +183,7 @@ module.exports = configure(function (/* ctx */) {
 | 
			
		|||
 | 
			
		||||
    // Full list of options: https://quasar.dev/quasar-cli/developing-capacitor-apps/configuring-capacitor
 | 
			
		||||
    capacitor: {
 | 
			
		||||
      hideSplashscreen: true
 | 
			
		||||
      hideSplashscreen: true,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // Full list of options: https://quasar.dev/quasar-cli/developing-electron-apps/configuring-electron
 | 
			
		||||
| 
						 | 
				
			
			@ -175,13 +192,11 @@ module.exports = configure(function (/* ctx */) {
 | 
			
		|||
 | 
			
		||||
      packager: {
 | 
			
		||||
        // https://github.com/electron-userland/electron-packager/blob/master/docs/api.md#options
 | 
			
		||||
 | 
			
		||||
        // OS X / Mac App Store
 | 
			
		||||
        // appBundleId: '',
 | 
			
		||||
        // appCategoryType: '',
 | 
			
		||||
        // osxSign: '',
 | 
			
		||||
        // protocol: 'myapp://path',
 | 
			
		||||
 | 
			
		||||
        // Windows only
 | 
			
		||||
        // win32metadata: { ... }
 | 
			
		||||
      },
 | 
			
		||||
| 
						 | 
				
			
			@ -189,16 +204,16 @@ module.exports = configure(function (/* ctx */) {
 | 
			
		|||
      builder: {
 | 
			
		||||
        // https://www.electron.build/configuration/configuration
 | 
			
		||||
 | 
			
		||||
        appId: 'flaschengeist-frontend'
 | 
			
		||||
        appId: 'flaschengeist-frontend',
 | 
			
		||||
      },
 | 
			
		||||
 | 
			
		||||
      // More info: https://quasar.dev/quasar-cli/developing-electron-apps/node-integration
 | 
			
		||||
      nodeIntegration: true,
 | 
			
		||||
 | 
			
		||||
      extendWebpack (/* cfg */) {
 | 
			
		||||
      extendWebpack(/* cfg */) {
 | 
			
		||||
        // do something with Electron main process Webpack cfg
 | 
			
		||||
        // chainWebpack also available besides this extendWebpack
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
  };
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,3 +0,0 @@
 | 
			
		|||
{
 | 
			
		||||
  "@quasar/qcalendar": {}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,9 +1,10 @@
 | 
			
		|||
/* eslint-disable */
 | 
			
		||||
// THIS FEATURE-FLAG FILE IS AUTOGENERATED,
 | 
			
		||||
//  REMOVAL OR CHANGES WILL CAUSE RELATED TYPES TO STOP WORKING
 | 
			
		||||
import 'quasar/dist/types/feature-flag';
 | 
			
		||||
 | 
			
		||||
declare module 'quasar/dist/types/feature-flag' {
 | 
			
		||||
  interface QuasarFeatureFlags {
 | 
			
		||||
    store: true;
 | 
			
		||||
    capacitor: true;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,10 @@
 | 
			
		|||
{
 | 
			
		||||
  "appId": "dev.flaschengeist",
 | 
			
		||||
  "appName": "flaschengeist-frontend",
 | 
			
		||||
  "bundledWebRuntime": false,
 | 
			
		||||
  "npmClient": "yarn",
 | 
			
		||||
  "webDir": "www",
 | 
			
		||||
  "ios": {
 | 
			
		||||
    "allowsLinkPreview": false
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,16 @@
 | 
			
		|||
{
 | 
			
		||||
  "name": "flaschengeist",
 | 
			
		||||
  "version": "2.0.0-alpha.1",
 | 
			
		||||
  "description": "Modular student club administration system",
 | 
			
		||||
  "author": "Tim Gröger <flaschengeist@wu5.de>",
 | 
			
		||||
  "private": true,
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
    "@capacitor/android": "^3.3.2",
 | 
			
		||||
    "@capacitor/app": "^1.0.0",
 | 
			
		||||
    "@capacitor/cli": "^3.0.0",
 | 
			
		||||
    "@capacitor/core": "^3.0.0",
 | 
			
		||||
    "@capacitor/ios": "^3.0.0-beta.0",
 | 
			
		||||
    "@capacitor/splash-screen": "^1.0.0",
 | 
			
		||||
    "@capacitor/storage": "^1.2.3"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,8 +0,0 @@
 | 
			
		|||
.DS_Store
 | 
			
		||||
 | 
			
		||||
# Generated by package manager
 | 
			
		||||
node_modules/
 | 
			
		||||
 | 
			
		||||
# Generated by Cordova
 | 
			
		||||
/plugins/
 | 
			
		||||
/platforms/
 | 
			
		||||
| 
						 | 
				
			
			@ -1,76 +0,0 @@
 | 
			
		|||
<?xml version='1.0' encoding='utf-8'?>
 | 
			
		||||
<widget id="de.wu5.flaschengeist" version="0.0.1" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
 | 
			
		||||
    <name>Flaschengeist</name>
 | 
			
		||||
    <description>Dynamischen Managementsystem für Studentenclubs</description>
 | 
			
		||||
    <author email="dev@cordova.apache.org" href="http://cordova.io">
 | 
			
		||||
        Apache Cordova Team
 | 
			
		||||
    </author>
 | 
			
		||||
    <content src="index.html" />
 | 
			
		||||
    <access origin="*" />
 | 
			
		||||
    <allow-intent href="http://*/*" />
 | 
			
		||||
    <allow-intent href="https://*/*" />
 | 
			
		||||
    <allow-intent href="tel:*" />
 | 
			
		||||
    <allow-intent href="sms:*" />
 | 
			
		||||
    <allow-intent href="mailto:*" />
 | 
			
		||||
    <allow-intent href="geo:*" />
 | 
			
		||||
    <platform name="android">
 | 
			
		||||
        <allow-intent href="market:*" />
 | 
			
		||||
        <icon density="ldpi" src="res/android/ldpi.png" />
 | 
			
		||||
        <icon density="mdpi" src="res/android/mdpi.png" />
 | 
			
		||||
        <icon density="hdpi" src="res/android/hdpi.png" />
 | 
			
		||||
        <icon density="xhdpi" src="res/android/xhdpi.png" />
 | 
			
		||||
        <icon density="xxhdpi" src="res/android/xxhdpi.png" />
 | 
			
		||||
        <icon density="xxxhdpi" src="res/android/xxxhdpi.png" />
 | 
			
		||||
        <splash density="land-ldpi" src="res/screen/android/splash-land-ldpi.png" />
 | 
			
		||||
        <splash density="port-ldpi" src="res/screen/android/splash-port-ldpi.png" />
 | 
			
		||||
        <splash density="land-mdpi" src="res/screen/android/splash-land-mdpi.png" />
 | 
			
		||||
        <splash density="port-mdpi" src="res/screen/android/splash-port-mdpi.png" />
 | 
			
		||||
        <splash density="land-hdpi" src="res/screen/android/splash-land-hdpi.png" />
 | 
			
		||||
        <splash density="port-hdpi" src="res/screen/android/splash-port-hdpi.png" />
 | 
			
		||||
        <splash density="land-xhdpi" src="res/screen/android/splash-land-xhdpi.png" />
 | 
			
		||||
        <splash density="port-xhdpi" src="res/screen/android/splash-port-xhdpi.png" />
 | 
			
		||||
        <splash density="land-xxhdpi" src="res/screen/android/splash-land-xxhdpi.png" />
 | 
			
		||||
        <splash density="port-xxhdpi" src="res/screen/android/splash-port-xxhdpi.png" />
 | 
			
		||||
        <splash density="land-xxxhdpi" src="res/screen/android/splash-land-xxxhdpi.png" />
 | 
			
		||||
        <splash density="port-xxxhdpi" src="res/screen/android/splash-port-xxxhdpi.png" />
 | 
			
		||||
    </platform>
 | 
			
		||||
    <platform name="ios">
 | 
			
		||||
        <allow-intent href="itms:*" />
 | 
			
		||||
        <allow-intent href="itms-apps:*" />
 | 
			
		||||
        <icon height="57" src="res/ios/icon.png" width="57" />
 | 
			
		||||
        <icon height="114" src="res/ios/icon@2x.png" width="114" />
 | 
			
		||||
        <icon height="40" src="res/ios/icon-20@2x.png" width="40" />
 | 
			
		||||
        <icon height="60" src="res/ios/icon-20@3x.png" width="60" />
 | 
			
		||||
        <icon height="29" src="res/ios/icon-29.png" width="29" />
 | 
			
		||||
        <icon height="58" src="res/ios/icon-29@2x.png" width="58" />
 | 
			
		||||
        <icon height="87" src="res/ios/icon-29@3x.png" width="87" />
 | 
			
		||||
        <icon height="80" src="res/ios/icon-40@2x.png" width="80" />
 | 
			
		||||
        <icon height="120" src="res/ios/icon-60@2x.png" width="120" />
 | 
			
		||||
        <icon height="180" src="res/ios/icon-60@3x.png" width="180" />
 | 
			
		||||
        <icon height="20" src="res/ios/icon-20.png" width="20" />
 | 
			
		||||
        <icon height="40" src="res/ios/icon-40.png" width="40" />
 | 
			
		||||
        <icon height="50" src="res/ios/icon-50.png" width="50" />
 | 
			
		||||
        <icon height="100" src="res/ios/icon-50@2x.png" width="100" />
 | 
			
		||||
        <icon height="72" src="res/ios/icon-72.png" width="72" />
 | 
			
		||||
        <icon height="144" src="res/ios/icon-72@2x.png" width="144" />
 | 
			
		||||
        <icon height="76" src="res/ios/icon-76.png" width="76" />
 | 
			
		||||
        <icon height="152" src="res/ios/icon-76@2x.png" width="152" />
 | 
			
		||||
        <icon height="167" src="res/ios/icon-83.5@2x.png" width="167" />
 | 
			
		||||
        <icon height="1024" src="res/ios/icon-1024.png" width="1024" />
 | 
			
		||||
        <icon height="48" src="res/ios/icon-24@2x.png" width="48" />
 | 
			
		||||
        <icon height="55" src="res/ios/icon-27.5@2x.png" width="55" />
 | 
			
		||||
        <icon height="88" src="res/ios/icon-44@2x.png" width="88" />
 | 
			
		||||
        <icon height="172" src="res/ios/icon-86@2x.png" width="172" />
 | 
			
		||||
        <icon height="196" src="res/ios/icon-98@2x.png" width="196" />
 | 
			
		||||
        <splash src="res/screen/ios/Default@2x~iphone~anyany.png" />
 | 
			
		||||
        <splash src="res/screen/ios/Default@2x~iphone~comany.png" />
 | 
			
		||||
        <splash src="res/screen/ios/Default@2x~iphone~comcom.png" />
 | 
			
		||||
        <splash src="res/screen/ios/Default@3x~iphone~anyany.png" />
 | 
			
		||||
        <splash src="res/screen/ios/Default@3x~iphone~anycom.png" />
 | 
			
		||||
        <splash src="res/screen/ios/Default@3x~iphone~comany.png" />
 | 
			
		||||
        <splash src="res/screen/ios/Default@2x~ipad~anyany.png" />
 | 
			
		||||
        <splash src="res/screen/ios/Default@2x~ipad~comany.png" />
 | 
			
		||||
    </platform>
 | 
			
		||||
    <allow-navigation href="about:*" />
 | 
			
		||||
    <preference name="SplashMaintainAspectRatio" value="true" />
 | 
			
		||||
</widget>
 | 
			
		||||
| 
						 | 
				
			
			@ -1,858 +0,0 @@
 | 
			
		|||
{
 | 
			
		||||
  "name": "de.wu5.flaschengeist",
 | 
			
		||||
  "version": "1.0.0",
 | 
			
		||||
  "lockfileVersion": 1,
 | 
			
		||||
  "requires": true,
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
    "@netflix/nerror": {
 | 
			
		||||
      "version": "1.1.3",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/@netflix/nerror/-/nerror-1.1.3.tgz",
 | 
			
		||||
      "integrity": "sha512-b+MGNyP9/LXkapreJzNUzcvuzZslj/RGgdVVJ16P2wSlYatfLycPObImqVJSmNAdyeShvNeM/pl3sVZsObFueg==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "assert-plus": "^1.0.0",
 | 
			
		||||
        "extsprintf": "^1.4.0",
 | 
			
		||||
        "lodash": "^4.17.15"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "@nodelib/fs.scandir": {
 | 
			
		||||
      "version": "2.1.3",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz",
 | 
			
		||||
      "integrity": "sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "@nodelib/fs.stat": "2.0.3",
 | 
			
		||||
        "run-parallel": "^1.1.9"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "@nodelib/fs.stat": {
 | 
			
		||||
      "version": "2.0.3",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz",
 | 
			
		||||
      "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "@nodelib/fs.walk": {
 | 
			
		||||
      "version": "1.2.4",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz",
 | 
			
		||||
      "integrity": "sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "@nodelib/fs.scandir": "2.1.3",
 | 
			
		||||
        "fastq": "^1.6.0"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "abbrev": {
 | 
			
		||||
      "version": "1.1.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
 | 
			
		||||
      "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "android-versions": {
 | 
			
		||||
      "version": "1.6.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/android-versions/-/android-versions-1.6.0.tgz",
 | 
			
		||||
      "integrity": "sha512-ojC2Ig7b/KJ6iNtR8e4bacmOsJyEkoERk3CKMIsnH7kJz5z6551NMbrVaRb7KXYavu1d74Uhml/bfcmqT3nAcg==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "semver": "^5.7.1"
 | 
			
		||||
      },
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "semver": {
 | 
			
		||||
          "version": "5.7.1",
 | 
			
		||||
          "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
 | 
			
		||||
          "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
 | 
			
		||||
          "dev": true
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "ansi": {
 | 
			
		||||
      "version": "0.3.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/ansi/-/ansi-0.3.1.tgz",
 | 
			
		||||
      "integrity": "sha1-DELU+xcWDVqa8eSEus4cZpIsGyE=",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "assert-plus": {
 | 
			
		||||
      "version": "1.0.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
 | 
			
		||||
      "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "at-least-node": {
 | 
			
		||||
      "version": "1.0.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz",
 | 
			
		||||
      "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "balanced-match": {
 | 
			
		||||
      "version": "1.0.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
 | 
			
		||||
      "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "base64-js": {
 | 
			
		||||
      "version": "1.5.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
 | 
			
		||||
      "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "big-integer": {
 | 
			
		||||
      "version": "1.6.48",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.48.tgz",
 | 
			
		||||
      "integrity": "sha512-j51egjPa7/i+RdiRuJbPdJ2FIUYYPhvYLjzoYbcMMm62ooO6F94fETG4MTs46zPAF9Brs04OajboA/qTGuz78w==",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "bplist-creator": {
 | 
			
		||||
      "version": "0.0.8",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/bplist-creator/-/bplist-creator-0.0.8.tgz",
 | 
			
		||||
      "integrity": "sha512-Za9JKzD6fjLC16oX2wsXfc+qBEhJBJB1YPInoAQpMLhDuj5aVOv1baGeIQSq1Fr3OCqzvsoQcSBSwGId/Ja2PA==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "stream-buffers": "~2.2.0"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "bplist-parser": {
 | 
			
		||||
      "version": "0.2.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.2.0.tgz",
 | 
			
		||||
      "integrity": "sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "big-integer": "^1.6.44"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "brace-expansion": {
 | 
			
		||||
      "version": "1.1.11",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
 | 
			
		||||
      "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "balanced-match": "^1.0.0",
 | 
			
		||||
        "concat-map": "0.0.1"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "braces": {
 | 
			
		||||
      "version": "3.0.2",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
 | 
			
		||||
      "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "fill-range": "^7.0.1"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "concat-map": {
 | 
			
		||||
      "version": "0.0.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
 | 
			
		||||
      "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "cordova-android": {
 | 
			
		||||
      "version": "9.0.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/cordova-android/-/cordova-android-9.0.0.tgz",
 | 
			
		||||
      "integrity": "sha512-2ZEgApK4LPMYW0zh/mLAH3CabzCaKE0yxQTzA2wTf0Eo2HHTJnRtDCf9spGf3nPOkubyXS6+pvzz5QzNHpVTqQ==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "android-versions": "^1.5.0",
 | 
			
		||||
        "cordova-common": "^4.0.1",
 | 
			
		||||
        "execa": "^4.0.2",
 | 
			
		||||
        "fs-extra": "^9.0.1",
 | 
			
		||||
        "nopt": "^4.0.3",
 | 
			
		||||
        "properties-parser": "^0.3.1",
 | 
			
		||||
        "which": "^2.0.2"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "cordova-common": {
 | 
			
		||||
      "version": "4.0.2",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/cordova-common/-/cordova-common-4.0.2.tgz",
 | 
			
		||||
      "integrity": "sha512-od7aNShyuBajzPY83mUEO8tERwwWdFklXETHiXP5Ft87CWeo/tSuwNPFztyTy8XYc74yXdogXKPTJeUHuVzB8Q==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "@netflix/nerror": "^1.1.3",
 | 
			
		||||
        "ansi": "^0.3.1",
 | 
			
		||||
        "bplist-parser": "^0.2.0",
 | 
			
		||||
        "cross-spawn": "^7.0.1",
 | 
			
		||||
        "elementtree": "^0.1.7",
 | 
			
		||||
        "endent": "^1.4.1",
 | 
			
		||||
        "fast-glob": "^3.2.2",
 | 
			
		||||
        "fs-extra": "^9.0.0",
 | 
			
		||||
        "glob": "^7.1.6",
 | 
			
		||||
        "plist": "^3.0.1",
 | 
			
		||||
        "q": "^1.5.1",
 | 
			
		||||
        "read-chunk": "^3.2.0",
 | 
			
		||||
        "strip-bom": "^4.0.0",
 | 
			
		||||
        "underscore": "^1.9.2"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "cordova-ios": {
 | 
			
		||||
      "version": "6.1.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/cordova-ios/-/cordova-ios-6.1.1.tgz",
 | 
			
		||||
      "integrity": "sha512-WHNvjVhkuwRpq95rISVXtcRyd6UGZapbmU+hO/CAn1c0AIT5WnO8mg2mOjv0WDNa0mt/V5P+N2Vig1UWwfxa5Q==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "cordova-common": "^4.0.2",
 | 
			
		||||
        "fs-extra": "^9.0.0",
 | 
			
		||||
        "ios-sim": "^8.0.2",
 | 
			
		||||
        "nopt": "^4.0.3",
 | 
			
		||||
        "plist": "^3.0.1",
 | 
			
		||||
        "semver": "^7.3.2",
 | 
			
		||||
        "unorm": "^1.6.0",
 | 
			
		||||
        "which": "^2.0.2",
 | 
			
		||||
        "xcode": "^3.0.1",
 | 
			
		||||
        "xml-escape": "^1.1.0"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "cordova-plugin-splashscreen": {
 | 
			
		||||
      "version": "6.0.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/cordova-plugin-splashscreen/-/cordova-plugin-splashscreen-6.0.0.tgz",
 | 
			
		||||
      "integrity": "sha512-pm4ZtJKQY4bCGXVeIInbGrXilryTevYSKgfvoQJpW9UClOWKAxSsYf2/4G2u1vcn492svOSL42OSa2MhujBWEQ==",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "cordova-plugin-whitelist": {
 | 
			
		||||
      "version": "1.3.4",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/cordova-plugin-whitelist/-/cordova-plugin-whitelist-1.3.4.tgz",
 | 
			
		||||
      "integrity": "sha512-EYC5eQFVkoYXq39l7tYKE6lEjHJ04mvTmKXxGL7quHLdFPfJMNzru/UYpn92AOfpl3PQaZmou78C7EgmFOwFQQ==",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "cross-spawn": {
 | 
			
		||||
      "version": "7.0.3",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
 | 
			
		||||
      "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "path-key": "^3.1.0",
 | 
			
		||||
        "shebang-command": "^2.0.0",
 | 
			
		||||
        "which": "^2.0.1"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "dedent": {
 | 
			
		||||
      "version": "0.7.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz",
 | 
			
		||||
      "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "elementtree": {
 | 
			
		||||
      "version": "0.1.7",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/elementtree/-/elementtree-0.1.7.tgz",
 | 
			
		||||
      "integrity": "sha1-mskb5uUvtuYkTE5UpKw+2K6OKcA=",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "sax": "1.1.4"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "end-of-stream": {
 | 
			
		||||
      "version": "1.4.4",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
 | 
			
		||||
      "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "once": "^1.4.0"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "endent": {
 | 
			
		||||
      "version": "1.4.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/endent/-/endent-1.4.1.tgz",
 | 
			
		||||
      "integrity": "sha512-buHTb5c8AC9NshtP6dgmNLYkiT+olskbq1z6cEGvfGCF3Qphbu/1zz5Xu+yjTDln8RbxNhPoUyJ5H8MSrp1olQ==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "dedent": "^0.7.0",
 | 
			
		||||
        "fast-json-parse": "^1.0.3",
 | 
			
		||||
        "objectorarray": "^1.0.4"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "execa": {
 | 
			
		||||
      "version": "4.1.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz",
 | 
			
		||||
      "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "cross-spawn": "^7.0.0",
 | 
			
		||||
        "get-stream": "^5.0.0",
 | 
			
		||||
        "human-signals": "^1.1.1",
 | 
			
		||||
        "is-stream": "^2.0.0",
 | 
			
		||||
        "merge-stream": "^2.0.0",
 | 
			
		||||
        "npm-run-path": "^4.0.0",
 | 
			
		||||
        "onetime": "^5.1.0",
 | 
			
		||||
        "signal-exit": "^3.0.2",
 | 
			
		||||
        "strip-final-newline": "^2.0.0"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "extsprintf": {
 | 
			
		||||
      "version": "1.4.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.4.0.tgz",
 | 
			
		||||
      "integrity": "sha1-4mifjzVvrWLMplo6kcXfX5VRaS8=",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "fast-glob": {
 | 
			
		||||
      "version": "3.2.4",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.4.tgz",
 | 
			
		||||
      "integrity": "sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "@nodelib/fs.stat": "^2.0.2",
 | 
			
		||||
        "@nodelib/fs.walk": "^1.2.3",
 | 
			
		||||
        "glob-parent": "^5.1.0",
 | 
			
		||||
        "merge2": "^1.3.0",
 | 
			
		||||
        "micromatch": "^4.0.2",
 | 
			
		||||
        "picomatch": "^2.2.1"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "fast-json-parse": {
 | 
			
		||||
      "version": "1.0.3",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/fast-json-parse/-/fast-json-parse-1.0.3.tgz",
 | 
			
		||||
      "integrity": "sha512-FRWsaZRWEJ1ESVNbDWmsAlqDk96gPQezzLghafp5J4GUKjbCz3OkAHuZs5TuPEtkbVQERysLp9xv6c24fBm8Aw==",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "fastq": {
 | 
			
		||||
      "version": "1.9.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.9.0.tgz",
 | 
			
		||||
      "integrity": "sha512-i7FVWL8HhVY+CTkwFxkN2mk3h+787ixS5S63eb78diVRc1MCssarHq3W5cj0av7YDSwmaV928RNag+U1etRQ7w==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "reusify": "^1.0.4"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "fill-range": {
 | 
			
		||||
      "version": "7.0.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
 | 
			
		||||
      "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "to-regex-range": "^5.0.1"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "fs-extra": {
 | 
			
		||||
      "version": "9.0.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.1.tgz",
 | 
			
		||||
      "integrity": "sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "at-least-node": "^1.0.0",
 | 
			
		||||
        "graceful-fs": "^4.2.0",
 | 
			
		||||
        "jsonfile": "^6.0.1",
 | 
			
		||||
        "universalify": "^1.0.0"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "fs.realpath": {
 | 
			
		||||
      "version": "1.0.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
 | 
			
		||||
      "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "get-stream": {
 | 
			
		||||
      "version": "5.2.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
 | 
			
		||||
      "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "pump": "^3.0.0"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "glob": {
 | 
			
		||||
      "version": "7.1.6",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
 | 
			
		||||
      "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "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"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "glob-parent": {
 | 
			
		||||
      "version": "5.1.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz",
 | 
			
		||||
      "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "is-glob": "^4.0.1"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "graceful-fs": {
 | 
			
		||||
      "version": "4.2.4",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz",
 | 
			
		||||
      "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "human-signals": {
 | 
			
		||||
      "version": "1.1.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz",
 | 
			
		||||
      "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "inflight": {
 | 
			
		||||
      "version": "1.0.6",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
 | 
			
		||||
      "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "once": "^1.3.0",
 | 
			
		||||
        "wrappy": "1"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "inherits": {
 | 
			
		||||
      "version": "2.0.4",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
 | 
			
		||||
      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "ios-sim": {
 | 
			
		||||
      "version": "8.0.2",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/ios-sim/-/ios-sim-8.0.2.tgz",
 | 
			
		||||
      "integrity": "sha512-P7nEG771bfd+JoMRjnis1gpZOkjTUUxu+4Ek1Z+eoaEEoT9byllU9pxfQ8Df7hL3gSkIQxNwTSLhos2I8tWUQA==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "bplist-parser": "^0.0.6",
 | 
			
		||||
        "nopt": "1.0.9",
 | 
			
		||||
        "plist": "^3.0.1",
 | 
			
		||||
        "simctl": "^2"
 | 
			
		||||
      },
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "bplist-parser": {
 | 
			
		||||
          "version": "0.0.6",
 | 
			
		||||
          "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.0.6.tgz",
 | 
			
		||||
          "integrity": "sha1-ONo0cYF9+dRKs4kuJ3B7u9daEbk=",
 | 
			
		||||
          "dev": true
 | 
			
		||||
        },
 | 
			
		||||
        "nopt": {
 | 
			
		||||
          "version": "1.0.9",
 | 
			
		||||
          "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.9.tgz",
 | 
			
		||||
          "integrity": "sha1-O8DXy6e/sNWmdtvtfA6+SKT9RU4=",
 | 
			
		||||
          "dev": true,
 | 
			
		||||
          "requires": {
 | 
			
		||||
            "abbrev": "1"
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "is-extglob": {
 | 
			
		||||
      "version": "2.1.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
 | 
			
		||||
      "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "is-glob": {
 | 
			
		||||
      "version": "4.0.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
 | 
			
		||||
      "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "is-extglob": "^2.1.1"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "is-number": {
 | 
			
		||||
      "version": "7.0.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
 | 
			
		||||
      "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "is-stream": {
 | 
			
		||||
      "version": "2.0.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz",
 | 
			
		||||
      "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "isexe": {
 | 
			
		||||
      "version": "2.0.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
 | 
			
		||||
      "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "jsonfile": {
 | 
			
		||||
      "version": "6.1.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
 | 
			
		||||
      "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "graceful-fs": "^4.1.6",
 | 
			
		||||
        "universalify": "^2.0.0"
 | 
			
		||||
      },
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "universalify": {
 | 
			
		||||
          "version": "2.0.0",
 | 
			
		||||
          "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
 | 
			
		||||
          "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==",
 | 
			
		||||
          "dev": true
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "lodash": {
 | 
			
		||||
      "version": "4.17.20",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
 | 
			
		||||
      "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "merge-stream": {
 | 
			
		||||
      "version": "2.0.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
 | 
			
		||||
      "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "merge2": {
 | 
			
		||||
      "version": "1.4.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
 | 
			
		||||
      "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "micromatch": {
 | 
			
		||||
      "version": "4.0.2",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz",
 | 
			
		||||
      "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "braces": "^3.0.1",
 | 
			
		||||
        "picomatch": "^2.0.5"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "mimic-fn": {
 | 
			
		||||
      "version": "2.1.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
 | 
			
		||||
      "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "minimatch": {
 | 
			
		||||
      "version": "3.0.4",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
 | 
			
		||||
      "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "brace-expansion": "^1.1.7"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "nopt": {
 | 
			
		||||
      "version": "4.0.3",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz",
 | 
			
		||||
      "integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "abbrev": "1",
 | 
			
		||||
        "osenv": "^0.1.4"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "npm-run-path": {
 | 
			
		||||
      "version": "4.0.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
 | 
			
		||||
      "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "path-key": "^3.0.0"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "objectorarray": {
 | 
			
		||||
      "version": "1.0.4",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/objectorarray/-/objectorarray-1.0.4.tgz",
 | 
			
		||||
      "integrity": "sha512-91k8bjcldstRz1bG6zJo8lWD7c6QXcB4nTDUqiEvIL1xAsLoZlOOZZG+nd6YPz+V7zY1580J4Xxh1vZtyv4i/w==",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "once": {
 | 
			
		||||
      "version": "1.4.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
 | 
			
		||||
      "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "wrappy": "1"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "onetime": {
 | 
			
		||||
      "version": "5.1.2",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
 | 
			
		||||
      "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "mimic-fn": "^2.1.0"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "os-homedir": {
 | 
			
		||||
      "version": "1.0.2",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
 | 
			
		||||
      "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "os-tmpdir": {
 | 
			
		||||
      "version": "1.0.2",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
 | 
			
		||||
      "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "osenv": {
 | 
			
		||||
      "version": "0.1.5",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz",
 | 
			
		||||
      "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "os-homedir": "^1.0.0",
 | 
			
		||||
        "os-tmpdir": "^1.0.0"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "p-finally": {
 | 
			
		||||
      "version": "1.0.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
 | 
			
		||||
      "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "p-try": {
 | 
			
		||||
      "version": "2.2.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
 | 
			
		||||
      "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "path-is-absolute": {
 | 
			
		||||
      "version": "1.0.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
 | 
			
		||||
      "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "path-key": {
 | 
			
		||||
      "version": "3.1.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
 | 
			
		||||
      "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "picomatch": {
 | 
			
		||||
      "version": "2.2.2",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz",
 | 
			
		||||
      "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "pify": {
 | 
			
		||||
      "version": "4.0.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
 | 
			
		||||
      "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "plist": {
 | 
			
		||||
      "version": "3.0.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/plist/-/plist-3.0.1.tgz",
 | 
			
		||||
      "integrity": "sha512-GpgvHHocGRyQm74b6FWEZZVRroHKE1I0/BTjAmySaohK+cUn+hZpbqXkc3KWgW3gQYkqcQej35FohcT0FRlkRQ==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "base64-js": "^1.2.3",
 | 
			
		||||
        "xmlbuilder": "^9.0.7",
 | 
			
		||||
        "xmldom": "0.1.x"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "properties-parser": {
 | 
			
		||||
      "version": "0.3.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/properties-parser/-/properties-parser-0.3.1.tgz",
 | 
			
		||||
      "integrity": "sha1-ExbpU5/7/ZOEXjabIRAiq9R4dxo=",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "string.prototype.codepointat": "^0.2.0"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "pump": {
 | 
			
		||||
      "version": "3.0.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
 | 
			
		||||
      "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "end-of-stream": "^1.1.0",
 | 
			
		||||
        "once": "^1.3.1"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "q": {
 | 
			
		||||
      "version": "1.5.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz",
 | 
			
		||||
      "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "read-chunk": {
 | 
			
		||||
      "version": "3.2.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/read-chunk/-/read-chunk-3.2.0.tgz",
 | 
			
		||||
      "integrity": "sha512-CEjy9LCzhmD7nUpJ1oVOE6s/hBkejlcJEgLQHVnQznOSilOPb+kpKktlLfFDK3/WP43+F80xkUTM2VOkYoSYvQ==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "pify": "^4.0.1",
 | 
			
		||||
        "with-open-file": "^0.1.6"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "reusify": {
 | 
			
		||||
      "version": "1.0.4",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
 | 
			
		||||
      "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "run-parallel": {
 | 
			
		||||
      "version": "1.1.10",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.10.tgz",
 | 
			
		||||
      "integrity": "sha512-zb/1OuZ6flOlH6tQyMPUrE3x3Ulxjlo9WIVXR4yVYi4H9UXQaeIsPbLn2R3O3vQCnDKkAl2qHiuocKKX4Tz/Sw==",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "sax": {
 | 
			
		||||
      "version": "1.1.4",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/sax/-/sax-1.1.4.tgz",
 | 
			
		||||
      "integrity": "sha1-dLbTPJrh4AFRDxeakRaFiPGu2qk=",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "semver": {
 | 
			
		||||
      "version": "7.3.2",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz",
 | 
			
		||||
      "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "shebang-command": {
 | 
			
		||||
      "version": "2.0.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
 | 
			
		||||
      "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "shebang-regex": "^3.0.0"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "shebang-regex": {
 | 
			
		||||
      "version": "3.0.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
 | 
			
		||||
      "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "shelljs": {
 | 
			
		||||
      "version": "0.2.6",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.2.6.tgz",
 | 
			
		||||
      "integrity": "sha1-kEktcv/MgVmXa6umL7D2iE8MM3g=",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "signal-exit": {
 | 
			
		||||
      "version": "3.0.3",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz",
 | 
			
		||||
      "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "simctl": {
 | 
			
		||||
      "version": "2.0.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/simctl/-/simctl-2.0.0.tgz",
 | 
			
		||||
      "integrity": "sha512-5rB7rN4N3b0z0nFdy9eczVssXqrv2aAgdVRksPVqVoiDtvXmfzNvebp3EMdId2sAUzXIflarQlx4P0hjVQEzKQ==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "shelljs": "^0.2.6",
 | 
			
		||||
        "tail": "^0.4.0"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "simple-plist": {
 | 
			
		||||
      "version": "1.1.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/simple-plist/-/simple-plist-1.1.1.tgz",
 | 
			
		||||
      "integrity": "sha512-pKMCVKvZbZTsqYR6RKgLfBHkh2cV89GXcA/0CVPje3sOiNOnXA8+rp/ciAMZ7JRaUdLzlEM6JFfUn+fS6Nt3hg==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "bplist-creator": "0.0.8",
 | 
			
		||||
        "bplist-parser": "0.2.0",
 | 
			
		||||
        "plist": "^3.0.1"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "stream-buffers": {
 | 
			
		||||
      "version": "2.2.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/stream-buffers/-/stream-buffers-2.2.0.tgz",
 | 
			
		||||
      "integrity": "sha1-kdX1Ew0c75bc+n9yaUUYh0HQnuQ=",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "string.prototype.codepointat": {
 | 
			
		||||
      "version": "0.2.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/string.prototype.codepointat/-/string.prototype.codepointat-0.2.1.tgz",
 | 
			
		||||
      "integrity": "sha512-2cBVCj6I4IOvEnjgO/hWqXjqBGsY+zwPmHl12Srk9IXSZ56Jwwmy+66XO5Iut/oQVR7t5ihYdLB0GMa4alEUcg==",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "strip-bom": {
 | 
			
		||||
      "version": "4.0.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz",
 | 
			
		||||
      "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "strip-final-newline": {
 | 
			
		||||
      "version": "2.0.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz",
 | 
			
		||||
      "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "tail": {
 | 
			
		||||
      "version": "0.4.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/tail/-/tail-0.4.0.tgz",
 | 
			
		||||
      "integrity": "sha1-0p3nJ1DMmdseBTr/E8NZ7PtxMAI=",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "to-regex-range": {
 | 
			
		||||
      "version": "5.0.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
 | 
			
		||||
      "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "is-number": "^7.0.0"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "underscore": {
 | 
			
		||||
      "version": "1.11.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.11.0.tgz",
 | 
			
		||||
      "integrity": "sha512-xY96SsN3NA461qIRKZ/+qox37YXPtSBswMGfiNptr+wrt6ds4HaMw23TP612fEyGekRE6LNRiLYr/aqbHXNedw==",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "universalify": {
 | 
			
		||||
      "version": "1.0.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz",
 | 
			
		||||
      "integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "unorm": {
 | 
			
		||||
      "version": "1.6.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/unorm/-/unorm-1.6.0.tgz",
 | 
			
		||||
      "integrity": "sha512-b2/KCUlYZUeA7JFUuRJZPUtr4gZvBh7tavtv4fvk4+KV9pfGiR6CQAQAWl49ZpR3ts2dk4FYkP7EIgDJoiOLDA==",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "uuid": {
 | 
			
		||||
      "version": "7.0.3",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/uuid/-/uuid-7.0.3.tgz",
 | 
			
		||||
      "integrity": "sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "which": {
 | 
			
		||||
      "version": "2.0.2",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
 | 
			
		||||
      "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "isexe": "^2.0.0"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "with-open-file": {
 | 
			
		||||
      "version": "0.1.7",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/with-open-file/-/with-open-file-0.1.7.tgz",
 | 
			
		||||
      "integrity": "sha512-ecJS2/oHtESJ1t3ZfMI3B7KIDKyfN0O16miWxdn30zdh66Yd3LsRFebXZXq6GU4xfxLf6nVxp9kIqElb5fqczA==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "p-finally": "^1.0.0",
 | 
			
		||||
        "p-try": "^2.1.0",
 | 
			
		||||
        "pify": "^4.0.1"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "wrappy": {
 | 
			
		||||
      "version": "1.0.2",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
 | 
			
		||||
      "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "xcode": {
 | 
			
		||||
      "version": "3.0.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/xcode/-/xcode-3.0.1.tgz",
 | 
			
		||||
      "integrity": "sha512-kCz5k7J7XbJtjABOvkc5lJmkiDh8VhjVCGNiqdKCscmVpdVUpEAyXv1xmCLkQJ5dsHqx3IPO4XW+NTDhU/fatA==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "simple-plist": "^1.1.0",
 | 
			
		||||
        "uuid": "^7.0.3"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "xml-escape": {
 | 
			
		||||
      "version": "1.1.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/xml-escape/-/xml-escape-1.1.0.tgz",
 | 
			
		||||
      "integrity": "sha1-OQTBQ/qOs6ADDsZG0pAqLxtwbEQ=",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "xmlbuilder": {
 | 
			
		||||
      "version": "9.0.7",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz",
 | 
			
		||||
      "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "xmldom": {
 | 
			
		||||
      "version": "0.1.31",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.1.31.tgz",
 | 
			
		||||
      "integrity": "sha512-yS2uJflVQs6n+CyjHoaBmVSqIDevTAWrzMmjG1Gc7h1qQ7uVozNhEPJAwZXWyGQ/Gafo3fCwrcaokezLPupVyQ==",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,31 +0,0 @@
 | 
			
		|||
{
 | 
			
		||||
  "name": "de.wu5.flaschengeist",
 | 
			
		||||
  "displayName": "Flaschengeist",
 | 
			
		||||
  "version": "1.0.0",
 | 
			
		||||
  "description": "A sample Apache Cordova application that responds to the deviceready event.",
 | 
			
		||||
  "main": "index.js",
 | 
			
		||||
  "scripts": {
 | 
			
		||||
    "test": "echo \"Error: no test specified\" && exit 1"
 | 
			
		||||
  },
 | 
			
		||||
  "keywords": [
 | 
			
		||||
    "ecosystem:cordova"
 | 
			
		||||
  ],
 | 
			
		||||
  "author": "Apache Cordova Team",
 | 
			
		||||
  "license": "Apache-2.0",
 | 
			
		||||
  "devDependencies": {
 | 
			
		||||
    "cordova-android": "^9.0.0",
 | 
			
		||||
    "cordova-ios": "^6.1.1",
 | 
			
		||||
    "cordova-plugin-splashscreen": "^6.0.0",
 | 
			
		||||
    "cordova-plugin-whitelist": "^1.3.4"
 | 
			
		||||
  },
 | 
			
		||||
  "cordova": {
 | 
			
		||||
    "plugins": {
 | 
			
		||||
      "cordova-plugin-whitelist": {},
 | 
			
		||||
      "cordova-plugin-splashscreen": {}
 | 
			
		||||
    },
 | 
			
		||||
    "platforms": [
 | 
			
		||||
      "ios",
 | 
			
		||||
      "android"
 | 
			
		||||
    ]
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 2.1 KiB  | 
| 
		 Before Width: | Height: | Size: 913 B  | 
| 
		 Before Width: | Height: | Size: 1.4 KiB  | 
| 
		 Before Width: | Height: | Size: 2.9 KiB  | 
| 
		 Before Width: | Height: | Size: 4.3 KiB  | 
| 
		 Before Width: | Height: | Size: 5.4 KiB  | 
| 
		 Before Width: | Height: | Size: 15 KiB  | 
| 
		 Before Width: | Height: | Size: 370 B  | 
| 
		 Before Width: | Height: | Size: 702 B  | 
| 
		 Before Width: | Height: | Size: 1022 B  | 
| 
		 Before Width: | Height: | Size: 801 B  | 
| 
		 Before Width: | Height: | Size: 969 B  | 
| 
		 Before Width: | Height: | Size: 529 B  | 
| 
		 Before Width: | Height: | Size: 1015 B  | 
| 
		 Before Width: | Height: | Size: 1.5 KiB  | 
| 
		 Before Width: | Height: | Size: 702 B  | 
| 
		 Before Width: | Height: | Size: 1.3 KiB  | 
| 
		 Before Width: | Height: | Size: 1.6 KiB  | 
| 
		 Before Width: | Height: | Size: 885 B  | 
| 
		 Before Width: | Height: | Size: 1.6 KiB  | 
| 
		 Before Width: | Height: | Size: 1.9 KiB  | 
| 
		 Before Width: | Height: | Size: 2.7 KiB  | 
| 
		 Before Width: | Height: | Size: 1.1 KiB  | 
| 
		 Before Width: | Height: | Size: 2.1 KiB  | 
| 
		 Before Width: | Height: | Size: 1.3 KiB  | 
| 
		 Before Width: | Height: | Size: 2.4 KiB  | 
| 
		 Before Width: | Height: | Size: 2.6 KiB  | 
| 
		 Before Width: | Height: | Size: 3.5 KiB  | 
| 
		 Before Width: | Height: | Size: 3.2 KiB  | 
| 
		 Before Width: | Height: | Size: 996 B  | 
| 
		 Before Width: | Height: | Size: 1.9 KiB  | 
| 
		 Before Width: | Height: | Size: 5.3 KiB  | 
| 
		 Before Width: | Height: | Size: 4.1 KiB  | 
| 
		 Before Width: | Height: | Size: 5.6 KiB  | 
| 
		 Before Width: | Height: | Size: 5.9 KiB  | 
| 
		 Before Width: | Height: | Size: 6.5 KiB  | 
| 
		 Before Width: | Height: | Size: 10 KiB  | 
| 
		 Before Width: | Height: | Size: 6.0 KiB  | 
| 
		 Before Width: | Height: | Size: 4.2 KiB  | 
| 
		 Before Width: | Height: | Size: 4.0 KiB  | 
| 
		 Before Width: | Height: | Size: 5.1 KiB  | 
| 
		 Before Width: | Height: | Size: 6.1 KiB  | 
| 
		 Before Width: | Height: | Size: 10 KiB  | 
| 
		 Before Width: | Height: | Size: 16 KiB  | 
| 
		 Before Width: | Height: | Size: 9.9 KiB  | 
| 
		 Before Width: | Height: | Size: 9.3 KiB  | 
| 
		 Before Width: | Height: | Size: 5.4 KiB  | 
| 
		 Before Width: | Height: | Size: 12 KiB  | 
| 
		 Before Width: | Height: | Size: 16 KiB  | 
| 
		 Before Width: | Height: | Size: 9.7 KiB  | 
| 
		 Before Width: | Height: | Size: 8.5 KiB  | 
| 
						 | 
				
			
			@ -1,9 +1,10 @@
 | 
			
		|||
/* eslint-disable */
 | 
			
		||||
// THIS FEATURE-FLAG FILE IS AUTOGENERATED,
 | 
			
		||||
//  REMOVAL OR CHANGES WILL CAUSE RELATED TYPES TO STOP WORKING
 | 
			
		||||
import 'quasar/dist/types/feature-flag';
 | 
			
		||||
 | 
			
		||||
declare module 'quasar/dist/types/feature-flag' {
 | 
			
		||||
  interface QuasarFeatureFlags {
 | 
			
		||||
    cordova: true;
 | 
			
		||||
    electron: true;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,56 @@
 | 
			
		|||
import { app, BrowserWindow, nativeTheme } from 'electron'
 | 
			
		||||
import path from 'path'
 | 
			
		||||
 | 
			
		||||
try {
 | 
			
		||||
  if (process.platform === 'win32' && nativeTheme.shouldUseDarkColors === true) {
 | 
			
		||||
    require('fs').unlinkSync(require('path').join(app.getPath('userData'), 'DevTools Extensions'))
 | 
			
		||||
  }
 | 
			
		||||
} catch (_) { }
 | 
			
		||||
 | 
			
		||||
let mainWindow
 | 
			
		||||
 | 
			
		||||
function createWindow () {
 | 
			
		||||
  /**
 | 
			
		||||
   * Initial window options
 | 
			
		||||
   */
 | 
			
		||||
  mainWindow = new BrowserWindow({
 | 
			
		||||
    width: 1000,
 | 
			
		||||
    height: 600,
 | 
			
		||||
    useContentSize: true,
 | 
			
		||||
    webPreferences: {
 | 
			
		||||
      contextIsolation: true,
 | 
			
		||||
      // More info: /quasar-cli/developing-electron-apps/electron-preload-script
 | 
			
		||||
      preload: path.resolve(__dirname, process.env.QUASAR_ELECTRON_PRELOAD)
 | 
			
		||||
    }
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  mainWindow.loadURL(process.env.APP_URL)
 | 
			
		||||
 | 
			
		||||
  if (process.env.DEBUGGING) {
 | 
			
		||||
    // if on DEV or Production with debug enabled
 | 
			
		||||
    mainWindow.webContents.openDevTools()
 | 
			
		||||
  } else {
 | 
			
		||||
    // we're on production; no access to devtools pls
 | 
			
		||||
    mainWindow.webContents.on('devtools-opened', () => {
 | 
			
		||||
      mainWindow.webContents.closeDevTools()
 | 
			
		||||
    })
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  mainWindow.on('closed', () => {
 | 
			
		||||
    mainWindow = null
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
app.on('ready', createWindow)
 | 
			
		||||
 | 
			
		||||
app.on('window-all-closed', () => {
 | 
			
		||||
  if (process.platform !== 'darwin') {
 | 
			
		||||
    app.quit()
 | 
			
		||||
  }
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
app.on('activate', () => {
 | 
			
		||||
  if (mainWindow === null) {
 | 
			
		||||
    createWindow()
 | 
			
		||||
  }
 | 
			
		||||
})
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,17 @@
 | 
			
		|||
/**
 | 
			
		||||
 * This file is used specifically for security reasons.
 | 
			
		||||
 * Here you can access Nodejs stuff and inject functionality into
 | 
			
		||||
 * the renderer thread (accessible there through the "window" object)
 | 
			
		||||
 *
 | 
			
		||||
 * WARNING!
 | 
			
		||||
 * If you import anything from node_modules, then make sure that the package is specified
 | 
			
		||||
 * in package.json > dependencies and NOT in devDependencies
 | 
			
		||||
 *
 | 
			
		||||
 * Example (injects window.myAPI.doAThing() into renderer thread):
 | 
			
		||||
 *
 | 
			
		||||
 *   const { contextBridge } = require('electron')
 | 
			
		||||
 *
 | 
			
		||||
 *   contextBridge.exposeInMainWorld('myAPI', {
 | 
			
		||||
 *     doAThing: () => {}
 | 
			
		||||
 *   })
 | 
			
		||||
 */
 | 
			
		||||
| 
		 After Width: | Height: | Size: 19 KiB  | 
| 
		 After Width: | Height: | Size: 8.7 KiB  | 
| 
						 | 
				
			
			@ -1,28 +1,77 @@
 | 
			
		|||
import config from 'src/config';
 | 
			
		||||
/**
 | 
			
		||||
 * This boot file registers interceptors for axios
 | 
			
		||||
 */
 | 
			
		||||
import { useMainStore, api } from '@flaschengeist/api';
 | 
			
		||||
import { AxiosError } from 'axios';
 | 
			
		||||
import { boot } from 'quasar/wrappers';
 | 
			
		||||
import { LocalStorage, Notify } from 'quasar';
 | 
			
		||||
import axios, { AxiosError } from 'axios';
 | 
			
		||||
import { useMainStore } from 'src/stores';
 | 
			
		||||
import config from 'src/config';
 | 
			
		||||
import { clone } from '@flaschengeist/api';
 | 
			
		||||
 | 
			
		||||
const api = axios.create();
 | 
			
		||||
/**
 | 
			
		||||
 * Minify data sent to backend server
 | 
			
		||||
 *
 | 
			
		||||
 * Drop unneeded entities which can be identified by ID.
 | 
			
		||||
 *
 | 
			
		||||
 * @param obj Object to minify
 | 
			
		||||
 * @param cloned If this entity is already cloned (JSON En+Decoded)
 | 
			
		||||
 * @returns Minified object (some types are converted, like a Date object is now a ISO string)
 | 
			
		||||
 */
 | 
			
		||||
function minify(entity: unknown, cloned = false) {
 | 
			
		||||
  if (!cloned) entity = clone(entity);
 | 
			
		||||
 | 
			
		||||
  if (typeof entity === 'object') {
 | 
			
		||||
    const obj = entity as { [index: string]: unknown };
 | 
			
		||||
 | 
			
		||||
    for (const prop in obj) {
 | 
			
		||||
      if (obj.hasOwnProperty(prop) && !!obj[prop]) {
 | 
			
		||||
        if (Array.isArray(obj[prop])) {
 | 
			
		||||
          // eslint-disable-next-line @typescript-eslint/no-unsafe-return
 | 
			
		||||
          obj[prop] = (<Array<unknown>>obj[prop]).map((v) => minify(v, true));
 | 
			
		||||
        } else if (
 | 
			
		||||
          typeof obj[prop] === 'object' &&
 | 
			
		||||
          Object.keys(<object>obj[prop]).includes('id') &&
 | 
			
		||||
          typeof (<{ id: unknown }>obj[prop])['id'] === 'number' &&
 | 
			
		||||
          !isNaN((<{ id: number }>obj[prop])['id'])
 | 
			
		||||
        ) {
 | 
			
		||||
          obj[prop] = (<{ id: unknown }>obj[prop])['id'];
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return obj;
 | 
			
		||||
  }
 | 
			
		||||
  return entity;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default boot(({ router }) => {
 | 
			
		||||
  api.defaults.baseURL = LocalStorage.getItem<string>('baseURL') || config.baseURL;
 | 
			
		||||
  // Persisted value is read in plugins.ts boot file!
 | 
			
		||||
  if (api.defaults.baseURL === undefined) api.defaults.baseURL = config.baseURL;
 | 
			
		||||
 | 
			
		||||
  /***
 | 
			
		||||
   * Intercept requests and insert Token if available
 | 
			
		||||
   * Intercept requests
 | 
			
		||||
   *   - insert Token if available
 | 
			
		||||
   *   - minify JSON requests
 | 
			
		||||
   */
 | 
			
		||||
  api.interceptors.request.use((config) => {
 | 
			
		||||
    const store = useMainStore();
 | 
			
		||||
    if (store.session?.token) {
 | 
			
		||||
      config.headers = { Authorization: 'Bearer ' + store.session.token };
 | 
			
		||||
      config.headers = Object.assign(config.headers || {}, {
 | 
			
		||||
        Authorization: `Bearer ${store.session.token}`,
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
    // Minify JSON requests
 | 
			
		||||
    if (
 | 
			
		||||
      !!config.data &&
 | 
			
		||||
      (config.headers === undefined ||
 | 
			
		||||
        config.headers['Content-Type'] === undefined ||
 | 
			
		||||
        config.headers['Content-Type'] === 'application/json')
 | 
			
		||||
    )
 | 
			
		||||
      config.data = minify(config.data);
 | 
			
		||||
    return config;
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  /***
 | 
			
		||||
   * Intercept responses
 | 
			
		||||
   *   - filter 401 --> logout
 | 
			
		||||
   *   - filter 401 --> handleLoggedOut
 | 
			
		||||
   *   - filter timeout or 502-504 --> backendOffline
 | 
			
		||||
   */
 | 
			
		||||
  api.interceptors.response.use(
 | 
			
		||||
| 
						 | 
				
			
			@ -45,12 +94,11 @@ export default boot(({ router }) => {
 | 
			
		|||
            query: { redirect: next },
 | 
			
		||||
          });
 | 
			
		||||
        } else if (e.response && e.response.status == 401) {
 | 
			
		||||
          void store.logout();
 | 
			
		||||
          if (current.name !== 'login') {
 | 
			
		||||
          store.handleLoggedOut();
 | 
			
		||||
          if (current.name != 'login') {
 | 
			
		||||
            await router.push({
 | 
			
		||||
              name: 'login',
 | 
			
		||||
              params: { logout: 'logout' },
 | 
			
		||||
              query: { redirect: current.path },
 | 
			
		||||
              query: { redirect: current.fullPath },
 | 
			
		||||
            });
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -59,19 +107,3 @@ export default boot(({ router }) => {
 | 
			
		|||
    }
 | 
			
		||||
  );
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
export { api };
 | 
			
		||||
 | 
			
		||||
export const setBaseURL = (url: string) => {
 | 
			
		||||
  LocalStorage.set('baseURL', url);
 | 
			
		||||
  api.defaults.baseURL = url;
 | 
			
		||||
  Notify.create({
 | 
			
		||||
    message: 'Serveraddresse gespeichert',
 | 
			
		||||
    position: 'bottom',
 | 
			
		||||
    caption: `${url}`,
 | 
			
		||||
    color: 'positive',
 | 
			
		||||
  });
 | 
			
		||||
  setTimeout(() => {
 | 
			
		||||
    window.location.reload();
 | 
			
		||||
  }, 5000);
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,87 @@
 | 
			
		|||
/**
 | 
			
		||||
 * This boot file initalizes the store from persistent storage and load all plugins
 | 
			
		||||
 */
 | 
			
		||||
import {
 | 
			
		||||
  PersistentStorage,
 | 
			
		||||
  api,
 | 
			
		||||
  isAxiosError,
 | 
			
		||||
  saveSession,
 | 
			
		||||
  useMainStore,
 | 
			
		||||
} from '@flaschengeist/api';
 | 
			
		||||
import { Notify, Platform } from 'quasar';
 | 
			
		||||
import { loadPlugins } from './plugins';
 | 
			
		||||
import { boot } from 'quasar/wrappers';
 | 
			
		||||
import routes from 'src/router/routes';
 | 
			
		||||
 | 
			
		||||
async function loadBaseUrl() {
 | 
			
		||||
  try {
 | 
			
		||||
    const url = await PersistentStorage.get<string>('baseURL');
 | 
			
		||||
    if (url !== null) api.defaults.baseURL = url;
 | 
			
		||||
  } catch (e) {
 | 
			
		||||
    console.warn('Could not load BaseURL', e);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class BackendError extends Error {}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Loading backend information
 | 
			
		||||
 * @returns Backend object or null
 | 
			
		||||
 */
 | 
			
		||||
async function getBackend() {
 | 
			
		||||
  const { data } = await api.get<FG.Backend>('/');
 | 
			
		||||
  if (!data || typeof data !== 'object' || !('plugins' in data))
 | 
			
		||||
    throw new BackendError('Invalid backend response received');
 | 
			
		||||
  return data;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Boot file for loading baseURL + Session from PersistentStorage + loading and initializing all plugins
 | 
			
		||||
 */
 | 
			
		||||
export default boot(async ({ app, router }) => {
 | 
			
		||||
  const store = useMainStore();
 | 
			
		||||
 | 
			
		||||
  // FIRST(!) get the base URL
 | 
			
		||||
  await loadBaseUrl();
 | 
			
		||||
 | 
			
		||||
  // Init the store, load current session and user, if available
 | 
			
		||||
  try {
 | 
			
		||||
    await store.init();
 | 
			
		||||
  } finally {
 | 
			
		||||
    // Any changes on the session is written back to the persistent store
 | 
			
		||||
    store.$subscribe((mutation, state) => {
 | 
			
		||||
      saveSession(state.session);
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Load all plugins
 | 
			
		||||
  try {
 | 
			
		||||
    // Fetch backend data
 | 
			
		||||
    const backend = await getBackend();
 | 
			
		||||
    // Load enabled plugins
 | 
			
		||||
    const flaschengeist = await loadPlugins(backend, routes);
 | 
			
		||||
    // Add loaded routes to router
 | 
			
		||||
    flaschengeist.routes.forEach((route) => router.addRoute(route));
 | 
			
		||||
    // save plugins in VM-variable
 | 
			
		||||
    app.provide('flaschengeist', flaschengeist);
 | 
			
		||||
  } catch (error) {
 | 
			
		||||
    // Handle errors from loading the backend information
 | 
			
		||||
    if (error instanceof BackendError || isAxiosError(error)) {
 | 
			
		||||
      router.isReady().finally(() => {
 | 
			
		||||
        if (Platform.is.capacitor) void router.push({ name: 'setup_backend' });
 | 
			
		||||
        else void router.push({ name: 'offline', params: { refresh: 1 } });
 | 
			
		||||
      });
 | 
			
		||||
    } else if (typeof error === 'string') {
 | 
			
		||||
      // Handle plugin not found errors
 | 
			
		||||
      void router.push({ name: 'error' });
 | 
			
		||||
      Notify.create({
 | 
			
		||||
        type: 'negative',
 | 
			
		||||
        message: `Fehler beim Laden: Bitte wende dich an den Admin (${error})!`,
 | 
			
		||||
        timeout: 10000,
 | 
			
		||||
        progress: true,
 | 
			
		||||
      });
 | 
			
		||||
    } else {
 | 
			
		||||
      console.error('Unknown error in init.ts:', error);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			@ -1,14 +0,0 @@
 | 
			
		|||
import { boot } from 'quasar/wrappers';
 | 
			
		||||
import { Loading } from 'quasar';
 | 
			
		||||
//import DarkCircularProgress from 'components/loading/DarkCircularProgress.vue';
 | 
			
		||||
 | 
			
		||||
// "async" is optional;
 | 
			
		||||
// more info on params: https://quasar.dev/quasar-cli/cli-documentation/boot-files#Anatomy-of-a-boot-file
 | 
			
		||||
export default boot(() => {
 | 
			
		||||
  Loading.setDefaults({
 | 
			
		||||
    // eslint-disable-next-line @typescript-eslint/ban-ts-comment
 | 
			
		||||
    // @ts-ignore
 | 
			
		||||
    // spinner: DarkCircularProgress,
 | 
			
		||||
    // TODO : Das funktioniert wohl erstmal nicht mehr... gibt ne exception
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||