diff --git a/demo/assets/check-in-place-select.metadata.json b/demo/assets/check-in-place-select.metadata.json new file mode 100644 index 0000000000000000000000000000000000000000..9edd3ffbf4bb8b6dee638fd492b4c8ef1f1f0c25 --- /dev/null +++ b/demo/assets/check-in-place-select.metadata.json @@ -0,0 +1,17 @@ +{ + "element": "dbp-check-in-place-select-demo-activity", + "module_src": "dbp-check-in-place-select-demo-activity.js", + "routing_name": "check-in-place-select", + "name": { + "de": "Ortauswahl", + "en": "Check-in place select" + }, + "short_name": { + "de": "Ortauswahl", + "en": "Check-in place select" + }, + "description": { + "de": "Ort Web Component", + "en": "Check-in place select web component" + } +} diff --git a/demo/assets/dbp-toolkit-demo.topic.metadata.json.ejs b/demo/assets/dbp-toolkit-demo.topic.metadata.json.ejs index 861d6a692f5758a94840d6c1f9837ac87956dac4..9ce40533449ca6f0c93fa68815d258561f92759d 100644 --- a/demo/assets/dbp-toolkit-demo.topic.metadata.json.ejs +++ b/demo/assets/dbp-toolkit-demo.topic.metadata.json.ejs @@ -20,7 +20,7 @@ {"path": "notification.metadata.json"}, {"path": "data-table-view.metadata.json"}, {"path": "language-select.metadata.json"}, - {"path": "location-select.metadata.json"}, + {"path": "check-in-place-select.metadata.json"}, {"path": "matomo.metadata.json"}, {"path": "person-profile.metadata.json"}, {"path": "file-handling.metadata.json"} diff --git a/demo/assets/location-select.metadata.json b/demo/assets/location-select.metadata.json deleted file mode 100644 index 1127c911d465f92067ead032c1a4a02f616a2894..0000000000000000000000000000000000000000 --- a/demo/assets/location-select.metadata.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "element": "dbp-location-select-demo-activity", - "module_src": "dbp-location-select-demo-activity.js", - "routing_name": "location-select", - "name": { - "de": "Ortauswahl", - "en": "Location select" - }, - "short_name": { - "de": "Ortauswahl", - "en": "Location select" - }, - "description": { - "de": "Ort Web Component", - "en": "location select web component" - } -} diff --git a/packages/location-select/.gitignore b/packages/check-in-place-select/.gitignore similarity index 100% rename from packages/location-select/.gitignore rename to packages/check-in-place-select/.gitignore diff --git a/packages/location-select/LICENSE b/packages/check-in-place-select/LICENSE similarity index 100% rename from packages/location-select/LICENSE rename to packages/check-in-place-select/LICENSE diff --git a/packages/check-in-place-select/README.md b/packages/check-in-place-select/README.md new file mode 100644 index 0000000000000000000000000000000000000000..8f921c5abe47dc016d0deefdda18bd9e4769103f --- /dev/null +++ b/packages/check-in-place-select/README.md @@ -0,0 +1,49 @@ +# Check-in place select web component + +[GitLab Repository](https://gitlab.tugraz.at/dbp/web-components/toolkit) + +## Usage + +```html +<dbp-check-in-place-select></dbp-check-in-place-select> +``` + +## Attributes + +- `lang` (optional, default: `de`): set to `de` or `en` for German or English + - example `<dbp-check-in-place-select lang="de"></dbp-check-in-place-select>` +- `entry-point-url` (optional, default is the TU Graz entry point url): entry point url to access the api + - example `<dbp-check-in-place-select entry-point-url="http://127.0.0.1:8000"></dbp-check-in-place-select>` +- `value` (optional): api path of place to preload the selector with + - example `<dbp-check-in-place-select value="Besprechungsraum"></dbp-check-in-place-select>` + - the `value` will also be set automatically when a place is chosen in the selector +- `data-object` (read-only): when a place is selected the place object will be set as json string + - example `<dbp-check-in-place-select data-object="{"@id":"id", "@type":"http://schema.org/Place", "identifier":"id", "name":"Besprechungsraum", "maximumPhysicalAttendeeCapacity":"50"}"></dbp-check-in-place-select>` +- `show-capacity` (optional): also shows the capacity of the places + - example `<dbp-check-in-place-select show-capacity></dbp-check-in-place-select>` +- `show-reload-button` (optional): if set a reload button will be viewed next to the select box + - the button triggers a `change` event on the web component + - the button is disabled if no place is selected + - example `<dbp-check-in-place-select show-reload-button></dbp-check-in-place-select>` +- `reload-button-title` (optional): sets a title text on the reload button + - example `<dbp-check-in-place-select show-reload-button reload-button-text="Reload result list"></dbp-check-in-place-select>` + +## Local development + +```bash +# get the source +git clone git@gitlab.tugraz.at:dbp/web-components/toolkit.git +cd toolkit/packages/check-in-place-select +git submodule update --init + +# install dependencies (make sure you have npm version 4+ installed, so symlinks to the git submodules are created automatically) +yarn install + +# constantly build dist/bundle.js and run a local web-server on port 8002 +yarn run watch-local + +# run tests +yarn test +``` + +Jump to <http://localhost:8002> and you should get a Single Sign On login page. diff --git a/packages/check-in-place-select/assets/index.html b/packages/check-in-place-select/assets/index.html new file mode 100644 index 0000000000000000000000000000000000000000..4926af42b043a6ed1e5784981b9282b48cb2511a --- /dev/null +++ b/packages/check-in-place-select/assets/index.html @@ -0,0 +1,12 @@ +<!doctype html> +<html> +<head> + <meta charset="UTF-8"> + <script type="module" src="dbp-check-in-place-select-demo.js"></script> +</head> + +<body> + +<dbp-check-in-place-select-demo lang="de"></dbp-check-in-place-select-demo> +</body> +</html> diff --git a/packages/location-select/i18next-scanner.config.js b/packages/check-in-place-select/i18next-scanner.config.js similarity index 100% rename from packages/location-select/i18next-scanner.config.js rename to packages/check-in-place-select/i18next-scanner.config.js diff --git a/packages/location-select/karma.conf.js b/packages/check-in-place-select/karma.conf.js similarity index 100% rename from packages/location-select/karma.conf.js rename to packages/check-in-place-select/karma.conf.js diff --git a/packages/location-select/package.json b/packages/check-in-place-select/package.json similarity index 97% rename from packages/location-select/package.json rename to packages/check-in-place-select/package.json index 8dccd2fc40befa396b862340e0a4cc5cd751d462..ab6f3e30e3e76a5ab33a56ce31e7beae7b0a028f 100644 --- a/packages/location-select/package.json +++ b/packages/check-in-place-select/package.json @@ -1,5 +1,5 @@ { - "name": "dbp-location-select", + "name": "dbp-check-in-place-select", "version": "1.0.0", "main": "src/index.js", "license": "LGPL-2.1-or-later", diff --git a/packages/location-select/rollup.config.js b/packages/check-in-place-select/rollup.config.js similarity index 93% rename from packages/location-select/rollup.config.js rename to packages/check-in-place-select/rollup.config.js index fb85e4312b6c48c2c18d8434bef6f07244f72cec..0ea288b1a98e5332a1ca65624c556b20192a20d1 100644 --- a/packages/location-select/rollup.config.js +++ b/packages/check-in-place-select/rollup.config.js @@ -15,7 +15,7 @@ console.log("build: " + build); export default (async () => { return { - input: (build != 'test') ? ['src/dbp-location-select.js', 'src/dbp-location-select-demo.js'] : glob.sync('test/**/*.js'), + input: (build != 'test') ? ['src/dbp-check-in-place-select.js', 'src/dbp-check-in-place-select-demo.js'] : glob.sync('test/**/*.js'), output: { dir: 'dist', entryFileNames: '[name].js', diff --git a/packages/location-select/src/location-select.js b/packages/check-in-place-select/src/check-in-place-select.js similarity index 93% rename from packages/location-select/src/location-select.js rename to packages/check-in-place-select/src/check-in-place-select.js index 44b49571e2bd577f75e7845140aac4f96592a19b..b403a6ec3c738ed38fa4bfd94e60c9a8b38dc1d4 100644 --- a/packages/location-select/src/location-select.js +++ b/packages/check-in-place-select/src/check-in-place-select.js @@ -14,7 +14,7 @@ import select2CSSPath from 'select2/dist/css/select2.min.css'; import * as errorUtils from "dbp-common/error"; -const locationContext = { +const checkInPlaceContext = { "@id": "@id", "name": "http://schema.org/name", "maximumPhysicalAttendeeCapacity": "http://schema.org/maximumPhysicalAttendeeCapacity" @@ -22,7 +22,7 @@ const locationContext = { select2(window, $); -export class LocationSelect extends ScopedElementsMixin(LitElement) { +export class CheckInPlaceSelect extends ScopedElementsMixin(LitElement) { constructor() { super(); @@ -32,7 +32,7 @@ export class LocationSelect extends ScopedElementsMixin(LitElement) { this.$select = null; this.active = false; // For some reason using the same ID on the whole page twice breaks select2 (regardless if they are in different custom elements) - this.selectId = 'location-select-' + commonUtils.makeId(24); + this.selectId = 'check-in-place-select-' + commonUtils.makeId(24); this.value = ''; this.object = null; this.ignoreValueUpdate = false; @@ -125,7 +125,7 @@ export class LocationSelect extends ScopedElementsMixin(LitElement) { return false; } - // find the correct api url for a location + // find the correct api url for a checkInPlace const apiUrl = this.jsonld.getApiUrlForIdentifier("http://schema.org/Place"); // const apiUrl = this.jsonld.getApiUrlForEntityName("CheckInPlace"); @@ -144,8 +144,8 @@ export class LocationSelect extends ScopedElementsMixin(LitElement) { width: '100%', language: this.lang === "de" ? select2LangDe() : select2LangEn(), minimumInputLength: 2, - placeholder: i18n.t('location-select.placeholder'), - dropdownParent: this.$('#location-select-dropdown'), + placeholder: i18n.t('check-in-place-select.placeholder'), + dropdownParent: this.$('#check-in-place-select-dropdown'), ajax: { delay: 500, url: apiUrl, @@ -161,7 +161,7 @@ export class LocationSelect extends ScopedElementsMixin(LitElement) { }, processResults: function (data) { that.lastResult = data; - let transformed = that.jsonld.transformMembers(data, locationContext); + let transformed = that.jsonld.transformMembers(data, checkInPlaceContext); const results = []; transformed.forEach((place) => { results.push({id: place["@id"], maximumPhysicalAttendeeCapacity: place["maximumPhysicalAttendeeCapacity"], text: that.generateOptionText(place)}); @@ -228,7 +228,7 @@ export class LocationSelect extends ScopedElementsMixin(LitElement) { }) .then((place) => { that.object = place; - const transformed = that.jsonld.compactMember(that.jsonld.expandMember(place), locationContext); + const transformed = that.jsonld.compactMember(that.jsonld.expandMember(place), checkInPlaceContext); const identifier = transformed["@id"]; const maxCapacity = transformed["maximumPhysicalAttendeeCapacity"]; const room = place.identifier; @@ -259,7 +259,7 @@ export class LocationSelect extends ScopedElementsMixin(LitElement) { generateOptionText(place) { let text = place["name"]; - // add maximum capacity to location if present + // add maximum capacity to checkInPlace if present if (this.showCapacity && (place["maximumPhysicalAttendeeCapacity"] !== undefined) && (place["maximumPhysicalAttendeeCapacity"] !== null)) { let capacity = place["maximumPhysicalAttendeeCapacity"]; text += ` (${capacity})`; @@ -366,7 +366,7 @@ export class LocationSelect extends ScopedElementsMixin(LitElement) { <div class="field has-addons"> <div class="select2-control control"> <!-- https://select2.org--> - <select id="${this.selectId}" name="location" class="select" ?disabled=${!this.active}>${!this.active ? html`<option value="" disabled selected>${ i18n.t('location-select.login-required')}</option>` : ''}</select> + <select id="${this.selectId}" name="check-in-place" class="select" ?disabled=${!this.active}>${!this.active ? html`<option value="" disabled selected>${ i18n.t('check-in-place-select.login-required')}</option>` : ''}</select> </div> <a class="control button" id="reload-button" @@ -377,7 +377,7 @@ export class LocationSelect extends ScopedElementsMixin(LitElement) { <dbp-icon name="reload"></dbp-icon> </a> </div> - <div id="location-select-dropdown"></div> + <div id="check-in-place-select-dropdown"></div> </div> `; } diff --git a/packages/location-select/src/dbp-location-select-demo.js b/packages/check-in-place-select/src/dbp-check-in-place-select-demo.js similarity index 72% rename from packages/location-select/src/dbp-location-select-demo.js rename to packages/check-in-place-select/src/dbp-check-in-place-select-demo.js index 87da57ef68d0c5c0000f990c4fca5aa824146a13..e4912f49f1cd1331fefe24d931d09264bcb9f321 100644 --- a/packages/location-select/src/dbp-location-select-demo.js +++ b/packages/check-in-place-select/src/dbp-check-in-place-select-demo.js @@ -1,12 +1,12 @@ import {i18n} from './i18n.js'; import {css, html, LitElement} from 'lit-element'; import {ScopedElementsMixin} from '@open-wc/scoped-elements'; -import {LocationSelect} from './location-select.js'; +import {CheckInPlaceSelect} from './check-in-place-select.js'; import {AuthKeycloak, LoginButton} from 'dbp-auth'; import * as commonUtils from 'dbp-common/utils'; import * as commonStyles from 'dbp-common/styles'; -class LocationSelectDemo extends ScopedElementsMixin(LitElement) { +class CheckInPlaceSelectDemo extends ScopedElementsMixin(LitElement) { constructor() { super(); this.lang = 'de'; @@ -17,7 +17,7 @@ class LocationSelectDemo extends ScopedElementsMixin(LitElement) { return { 'dbp-auth-keycloak': AuthKeycloak, 'dbp-login-button': LoginButton, - 'dbp-location-select': LocationSelect, + 'dbp-check-in-place-select': CheckInPlaceSelect, }; } @@ -61,21 +61,21 @@ class LocationSelectDemo extends ScopedElementsMixin(LitElement) { return html` <section class="section"> <div class="container"> - <h1 class="title">Location-Select-Demo</h1> + <h1 class="title">Check-In-Place-Select-Demo</h1> </div> ${this.getAuthComponentHtml()} <div class="container"> <form> <div class="field"> - <label class="label">Location 1</label> + <label class="label">Check-In-Place 1</label> <div class="control"> - <dbp-location-select lang="${this.lang}" entry-point-url="${commonUtils.getAPiUrl()}"></dbp-location-select> + <dbp-check-in-place-select lang="${this.lang}" entry-point-url="${commonUtils.getAPiUrl()}"></dbp-check-in-place-select> </div> </div> <div class="field"> - <label class="label">Location 2</label> + <label class="label">Check-In-Place 2</label> <div class="control"> - <dbp-location-select lang="${this.lang}" entry-point-url="${commonUtils.getAPiUrl()}" show-reload-button reload-button-title="Click me"></dbp-location-select> + <dbp-check-in-place-select lang="${this.lang}" entry-point-url="${commonUtils.getAPiUrl()}" show-reload-button reload-button-title="Click me"></dbp-check-in-place-select> </div> </div> </form> @@ -85,4 +85,4 @@ class LocationSelectDemo extends ScopedElementsMixin(LitElement) { } } -commonUtils.defineCustomElement('dbp-location-select-demo', LocationSelectDemo); +commonUtils.defineCustomElement('dbp-check-in-place-select-demo', CheckInPlaceSelectDemo); diff --git a/packages/check-in-place-select/src/dbp-check-in-place-select.js b/packages/check-in-place-select/src/dbp-check-in-place-select.js new file mode 100644 index 0000000000000000000000000000000000000000..11523e1b8f0816e60ca5fc0beacd58d083d1e0f9 --- /dev/null +++ b/packages/check-in-place-select/src/dbp-check-in-place-select.js @@ -0,0 +1,4 @@ +import * as commonUtils from 'dbp-common/utils'; +import {CheckInPlaceSelect} from './check-in-place-select.js'; + +commonUtils.defineCustomElement('dbp-check-in-place-select', CheckInPlaceSelect); diff --git a/packages/check-in-place-select/src/demo.js b/packages/check-in-place-select/src/demo.js new file mode 100644 index 0000000000000000000000000000000000000000..cfe637db0b68140e67f306ceebe3ae4cf1ad071e --- /dev/null +++ b/packages/check-in-place-select/src/demo.js @@ -0,0 +1 @@ +import './dbp-check-in-place-select-demo.js'; diff --git a/packages/location-select/src/i18n.js b/packages/check-in-place-select/src/i18n.js similarity index 100% rename from packages/location-select/src/i18n.js rename to packages/check-in-place-select/src/i18n.js diff --git a/packages/location-select/src/i18n/de/select2.js b/packages/check-in-place-select/src/i18n/de/select2.js similarity index 100% rename from packages/location-select/src/i18n/de/select2.js rename to packages/check-in-place-select/src/i18n/de/select2.js diff --git a/packages/location-select/src/i18n/de/translation.json b/packages/check-in-place-select/src/i18n/de/translation.json similarity index 84% rename from packages/location-select/src/i18n/de/translation.json rename to packages/check-in-place-select/src/i18n/de/translation.json index eae30547657aaf92157c0f284c13c192a9e08d95..66cf68dc1d0904797a99c85a1387e5793abb92e1 100644 --- a/packages/location-select/src/i18n/de/translation.json +++ b/packages/check-in-place-select/src/i18n/de/translation.json @@ -1,5 +1,5 @@ { - "location-select": { + "check-in-place-select": { "placeholder": "Bitte wählen Sie einen Ort aus", "error-summary": "Ein Fehler ist aufgetreten", "login-required": "Anmeldung erforderlich" diff --git a/packages/location-select/src/i18n/en/select2.js b/packages/check-in-place-select/src/i18n/en/select2.js similarity index 100% rename from packages/location-select/src/i18n/en/select2.js rename to packages/check-in-place-select/src/i18n/en/select2.js diff --git a/packages/location-select/src/i18n/en/translation.json b/packages/check-in-place-select/src/i18n/en/translation.json similarity index 82% rename from packages/location-select/src/i18n/en/translation.json rename to packages/check-in-place-select/src/i18n/en/translation.json index c1f2d7b6ae95f4cfd1bfa6a8a5c9235b833c6a66..1cbc14f66656221ce47672ed463f546eb479d164 100644 --- a/packages/location-select/src/i18n/en/translation.json +++ b/packages/check-in-place-select/src/i18n/en/translation.json @@ -1,5 +1,5 @@ { - "location-select": { + "check-in-place-select": { "placeholder": "Please select a location", "error-summary": "An error occurred", "login-required": "Login required" diff --git a/packages/check-in-place-select/src/index.js b/packages/check-in-place-select/src/index.js new file mode 100644 index 0000000000000000000000000000000000000000..0bbe1832a2891a709d78f0b8d421834606f6f0b4 --- /dev/null +++ b/packages/check-in-place-select/src/index.js @@ -0,0 +1,3 @@ +import {CheckInPlaceSelect} from './check-in-place-select.js'; + +export {CheckInPlaceSelect}; \ No newline at end of file diff --git a/packages/location-select/src/utils.js b/packages/check-in-place-select/src/utils.js similarity index 100% rename from packages/location-select/src/utils.js rename to packages/check-in-place-select/src/utils.js diff --git a/packages/location-select/test/unit.js b/packages/check-in-place-select/test/unit.js similarity index 64% rename from packages/location-select/test/unit.js rename to packages/check-in-place-select/test/unit.js index 139e1c05f05960710f163d03d0de1caedc63cfe9..d5498cebd707c198d3ba744bf54aa29d6e67b8da 100644 --- a/packages/location-select/test/unit.js +++ b/packages/check-in-place-select/test/unit.js @@ -1,11 +1,11 @@ -import '../src/dbp-location-select.js'; +import '../src/dbp-check-in-place-select.js'; import '../src/demo.js'; -describe('dbp-location-select basics', () => { +describe('dbp-check-in-place-select basics', () => { let node; beforeEach(async () => { - node = document.createElement('dbp-location-select'); + node = document.createElement('dbp-check-in-place-select'); document.body.appendChild(node); await node.updateComplete; }); @@ -19,11 +19,11 @@ describe('dbp-location-select basics', () => { }); }); -describe('dbp-location-select-demo basics', () => { +describe('dbp-check-in-place-select-demo basics', () => { let node; beforeEach(async () => { - node = document.createElement('dbp-location-select-demo'); + node = document.createElement('dbp-check-in-place-select-demo'); document.body.appendChild(node); await node.updateComplete; }); diff --git a/packages/location-select/README.md b/packages/location-select/README.md deleted file mode 100644 index 30711d20b7242dfdbee17f2fcd40c3b78bc65de0..0000000000000000000000000000000000000000 --- a/packages/location-select/README.md +++ /dev/null @@ -1,49 +0,0 @@ -# Location Select Web Component - -[GitLab Repository](https://gitlab.tugraz.at/dbp/web-components/toolkit) - -## Usage - -```html -<dbp-location-select></dbp-location-select> -``` - -## Attributes - -- `lang` (optional, default: `de`): set to `de` or `en` for German or English - - example `<dbp-location-select lang="de"></dbp-location-select>` -- `entry-point-url` (optional, default is the TU Graz entry point url): entry point url to access the api - - example `<dbp-location-select entry-point-url="http://127.0.0.1:8000"></dbp-location-select>` -- `value` (optional): api path of location to preload the selector with - - example `<dbp-location-select value="Besprechungsraum"></dbp-location-select>` - - the `value` will also be set automatically when a location is chosen in the selector -- `data-object` (read-only): when a location is selected the location object will be set as json string - - example `<dbp-location-select data-object="{"@id":"id", "@type":"http://schema.org/Place", "identifier":"id", "name":"Besprechungsraum", "maximumPhysicalAttendeeCapacity":"50"}"></dbp-location-select>` -- `show-capacity` (optional): also shows the capacity of the locations - - example `<dbp-location-select show-capacity></dbp-location-select>` -- `show-reload-button` (optional): if set a reload button will be viewed next to the select box - - the button triggers a `change` event on the web component - - the button is disabled if no location is selected - - example `<dbp-location-select show-reload-button></dbp-location-select>` -- `reload-button-title` (optional): sets a title text on the reload button - - example `<dbp-location-select show-reload-button reload-button-text="Reload result list"></dbp-location-select>` - -## Local development - -```bash -# get the source -git clone git@gitlab.tugraz.at:dbp/web-components/toolkit.git -cd toolkit/packages/location-select -git submodule update --init - -# install dependencies (make sure you have npm version 4+ installed, so symlinks to the git submodules are created automatically) -yarn install - -# constantly build dist/bundle.js and run a local web-server on port 8002 -yarn run watch-local - -# run tests -yarn test -``` - -Jump to <http://localhost:8002> and you should get a Single Sign On login page. diff --git a/packages/location-select/assets/index.html b/packages/location-select/assets/index.html deleted file mode 100644 index 437004d2cdf00bcf76e08dd9636737cc9a594ecc..0000000000000000000000000000000000000000 --- a/packages/location-select/assets/index.html +++ /dev/null @@ -1,12 +0,0 @@ -<!doctype html> -<html> -<head> - <meta charset="UTF-8"> - <script type="module" src="dbp-location-select-demo.js"></script> -</head> - -<body> - -<dbp-location-select-demo lang="de"></dbp-location-select-demo> -</body> -</html> diff --git a/packages/location-select/src/dbp-location-select.js b/packages/location-select/src/dbp-location-select.js deleted file mode 100644 index 44f98c1e0e1b9658c8ffe0f99e9be865330dc16a..0000000000000000000000000000000000000000 --- a/packages/location-select/src/dbp-location-select.js +++ /dev/null @@ -1,4 +0,0 @@ -import * as commonUtils from 'dbp-common/utils'; -import {LocationSelect} from './location-select.js'; - -commonUtils.defineCustomElement('dbp-location-select', LocationSelect); diff --git a/packages/location-select/src/demo.js b/packages/location-select/src/demo.js deleted file mode 100644 index a6661deb4507beade4dc71a0d6eaf9e5ece40c2b..0000000000000000000000000000000000000000 --- a/packages/location-select/src/demo.js +++ /dev/null @@ -1 +0,0 @@ -import './dbp-location-select-demo.js'; diff --git a/packages/location-select/src/index.js b/packages/location-select/src/index.js deleted file mode 100644 index 93b98e9f6d8dc6bff7879fe6b336020d617af8ba..0000000000000000000000000000000000000000 --- a/packages/location-select/src/index.js +++ /dev/null @@ -1,3 +0,0 @@ -import {LocationSelect} from './location-select.js'; - -export {LocationSelect}; \ No newline at end of file