UNPKG

territorium-proctoring

Version:

Componente de prueba

779 lines (681 loc) 27.7 kB
import { defineComponent, pushScopeId, popScopeId, resolveComponent, openBlock, createBlock, createVNode, toDisplayString, withScopeId } from 'vue'; // import '@tensorflow/tfjs-backend-webgl'; // import * as cocoSsd from '@tensorflow-models/coco-ssd'; // import * as faceapi from '@vladmandic/face-api'; // import axios from "axios"; // import TerritoriumDeviceManager from 'territorium-device-manager'; // import * as azblob from "./azure-storage-blob.min"; // import { v4 as uuidv4 } from 'uuid'; // import { setIntervalAsync } from 'set-interval-async/dynamic'; // import { clearIntervalAsync } from 'set-interval-async'; // window.navigator.onLine var script = /*#__PURE__*/defineComponent({ name: 'TerritoriumProctoring', // vue component name components: { TerritoriumDeviceManager }, props: { idUniversidad: { type: [Number, String], default: "1483" }, idExamen: { type: [Number, String], default: '6078814' }, idEstudiante: { type: [Number, String], default: '1414446' }, urlConfig: { type: [Number, String], default: "http://localhost:8081/getconfig" }, authorization: { type: [String], default: "62b3500e1fed8933d18a154bc0df26584fc744fb3e71e32fed52b208aa07dfd6c3158990624de11faa4be9a7d6e35c730f39de2074891a98cd60ad97e70926f8" }, urlPerfil: { type: [Number, String], default: "https://proctoring-files.azureedge.net/files/proctoringFiles/1483/2021-03-30/FaceId/1050159/6tLwXWjEFpY51617121804TuoL21228600.jpg" } }, data() { return { modelPromise: null, allowsLocalSupervision: false, uriPerfil: null, uriCaptura: null, feedback: "", diagnosticos: [], capturas: [], objetosSospechoso: ['backpack', 'handbag', 'tv', 'laptop', 'cell phone', 'book'], analisysType: ["objetos", "reconocido", "acompanado", "detectado"], maxDescriptorDistance: 0.6, faceMatcher: null, blobServiceClient: null, containerClient: null, containerName: "container-proctoring-test", // blobSasUrl: "https://proctoringfiles-microsoftrouting.blob.core.windows.net/?sv=2020-02-10&ss=bfqt&srt=sco&sp=rwdlacupx&se=2025-12-31T12:45:48Z&st=2021-05-13T03:45:48Z&spr=https,http&sig=lFCX5yJiGfrkhk2BbqEUJTvJkE3dUQefRERzjh8zgcg%3D", // urlApi: "http://localhost:8081", urlToken: "http://localhost:8081/gentoken", urlProcessDiagnosticos: "http://localhost:8081/territoriumService", urlSaveDiagnosticos: "http://localhost:8081/storeevidences", urlSaveAudio: "http://localhost:8081/storeaudio", urlSaveVideo: "http://localhost:8081/storevideo", sasString: "se=2025-12-31&sp=rwdlac&sv=2018-03-28&ss=b&srt=sco&sig=yygWiToa3acI3mRmryM6t1wi%2Bgh1%2B7c4mme/Z8UOEik%3D", containerURL: null, accountName: "proctoringfiles", // limitSendDiagnostic: 3, token: "", config: {}, idCoreProctoring: null, timeInterval: 1000, timeElapsed: 0, capturarFoto: 0, capturarVideo: 0, capturarAudio: 0, uriAudio: null, uriVideo: null, blobVideo: null }; }, watch: { allowsLocalSupervision: 'configProctoring', diagnosticos: 'processDiagnosticos', capturas: 'processCapturas', uriAudio: 'processBlobAudio', // uriVideo: 'processVideo', blobVideo: 'processBlobVideo' }, methods: { processAudio() { if (this.allowsLocalSupervision) ; else { alert("No se permite supervision local"); } }, async processVideo() { // console.log("processVideo()"); if (this.allowsLocalSupervision) { // console.log("uriVideo", this.uriVideo); this.$refs.video.src = this.uriVideo; await this.uploadFiles(this.uriVideo); // console.log("processVideo", url); } else { alert("No se permite supervision local"); } }, async processBlobVideo() { let url = ""; // console.log("processBlob()"); // if (this.allowsLocalSupervision) { // console.log("blobVideo", this.blobVideo); if (!(this.blobVideo === undefined || this.blobVideo == null || this.blobVideo.size <= 0)) { url = await this.uploadBlobVideo(this.blobVideo); await this.saveVideo(url); } // console.log("processBlob", url); // } else { // alert("No se permite supervision local"); // } }, async uploadBlobAudio(dataBlob, name = "") { let url = ""; try { if (name == "") { name = uuidv4(); name = `${name}.webm`; } this.reportStatus("Uploading files..."); // const blockBlobClient = this.containerClient.getBlockBlobClient(name); // let data = await blockBlobClient.uploadBrowserData(dataBlob); // let url = data._response.request.url; const blockBlobURL = azblob.BlockBlobURL.fromContainerURL(this.containerURL, name); url = await azblob.uploadBrowserDataToBlockBlob(azblob.Aborter.none, dataBlob, blockBlobURL); return url._response.request.url; } catch (error) { this.reportStatus(error.message); return null; } }, async processBlobAudio() { // console.log("processBlobAudio()"); let url = ""; // if (this.allowsLocalSupervision) { // console.log("blobAudio", this.uriAudio); if (!(this.uriAudio === undefined || this.uriAudio == null || this.uriAudio.size <= 0)) { url = await this.uploadBlobAudio(this.uriAudio); await this.saveAudio(url); } // console.log("processAudio", url); // } else { // alert("No se permite supervision local"); // } }, configProctoring() { if (this.allowsLocalSupervision) ; }, async verifyLocalAnalysis() { const modeloCoco = await this.modelPromise; let urlsPhotosToVerify = ["https://i.ibb.co/3N0ZRH1/CA1.jpg", "https://i.ibb.co/C7hXLHt/CA2.jpg", "https://i.ibb.co/tX5kjpL/CA3.jpg", "https://i.ibb.co/yW2r9D4/CA4.jpg", "https://i.ibb.co/VB67VPX/CA5.jpg", "https://i.ibb.co/dLzKt0N/CA6.jpg", "https://i.ibb.co/p0LwmBT/CA7.jpg", "https://i.ibb.co/FwSscRy/CA8.jpg", "https://i.ibb.co/wWyMj2n/CA9.jpg", "https://i.ibb.co/fSjNfwT/CA11.jpg", "https://i.ibb.co/QmWb2gC/CA10.jpg"], urlReferencePhoto = "https://i.ibb.co/fv2Nkyx/chris-Evans-Profile.jpg", // urlReferencePhoto = "https://proctoring-files.azureedge.net/files/proctoringFiles/1483/2021-03-30/FaceId/1050159/6tLwXWjEFpY51617121804TuoL21228600.jpg", defaultFaceMatcher = ["true", "false", "true", "true", "true", "true", "true", "true", "true", "true", "true"], defaultObjects = ["person", "person", "person", "person", "person", "person", "person", "person", "person", "person", "person"], resultsFaceMatcher = [], resultsObjects = [], testCorrect = 0; // image to compare let referencePhoto = await faceapi.fetchImage(urlReferencePhoto); // console.log("referencePhoto", referencePhoto); const referenceFaceAnalysis = await faceapi.detectSingleFace(referencePhoto).withFaceLandmarks().withFaceDescriptor(); const referenceFaceDescriptor = [referenceFaceAnalysis.descriptor]; const referenceFacialFeatures = new faceapi.LabeledFaceDescriptors("true", referenceFaceDescriptor); const maxDescriptorDistance = 0.6; const faceMatcher = new faceapi.FaceMatcher(referenceFacialFeatures, maxDescriptorDistance); for (let index = 0; index < urlsPhotosToVerify.length; index++) { const urlPhotosToVerify = urlsPhotosToVerify[index]; const photosToVerify = await faceapi.fetchImage(urlPhotosToVerify); // console.log("photosToVerify", photosToVerify); const photosToVerifyAnalysis = await faceapi.detectAllFaces(photosToVerify, new faceapi.TinyFaceDetectorOptions()).withFaceLandmarks().withFaceDescriptors(); const photosToVerifyDescriptor = photosToVerifyAnalysis[0].descriptor; const resultFaceMatcher = faceMatcher.findBestMatch(photosToVerifyDescriptor); if (resultFaceMatcher.label == "unknown") { resultsFaceMatcher.push("false"); } else { resultsFaceMatcher.push(resultFaceMatcher.label); } // Deteccion de Objetos let predictions = await modeloCoco.detect(photosToVerify); if (predictions[0]) { resultsObjects.push(predictions[0].class); } if (defaultFaceMatcher[index] == resultsFaceMatcher[index] && defaultObjects[index] == resultsObjects[index]) { testCorrect += 1; } } this.allowsLocalSupervision = testCorrect == 11 ? true : false; }, async verifyFace(imgComparacion) { let url = await this.uploadFiles(this.uriCaptura); let diagnostico = { idUniversidad: this.idUniversidad, idExamen: this.idExamen, IdEstudiante: this.idEstudiante, fotoPerfil: this.urlPerfil, objetos: [], diagnosticos: [], objetosSospechoso: [], marcaTiempoCaptura: "", marcaTiempoGuardado: "", guardado: false, reconocido: false, detectadosAnalisis: 0, detectadosCoco: 0, url: url }; const modeloCoco = await this.modelPromise; let photosToVerify = await faceapi.fetchImage(imgComparacion); const photosToVerifyAnalysis = await faceapi.detectAllFaces(photosToVerify).withFaceLandmarks().withFaceDescriptors(); await faceapi.detectAllFaces(photosToVerify, new faceapi.TinyFaceDetectorOptions()).withFaceLandmarks().withFaceDescriptors(); // console.log("photosToVerifyAnalysis", photosToVerifyAnalysis); // console.log("photosToVerifyAnalysisTiny", photosToVerifyAnalysisTiny); if (photosToVerifyAnalysis.length > 0) { diagnostico.detectadosAnalisis = photosToVerifyAnalysis.length; const bestMatch = photosToVerifyAnalysis.map(fd => this.faceMatcher.findBestMatch(fd.descriptor)); // console.log("bestMatch", bestMatch) for (let index = 0; index < bestMatch.length; index++) { if (bestMatch[index]._label == "true") { diagnostico.reconocido = true; } } } let predictions = await modeloCoco.detect(photosToVerify); let deteccion = { id: 0, name: "" }; diagnostico.objetos = predictions.map(object => object.class); diagnostico.objetosSospechoso = diagnostico.objetos.filter(item => this.objetosSospechoso.includes(item)); diagnostico.detectadosCoco = diagnostico.objetos.filter(item => item == "person").length; if (diagnostico.reconocido) { deteccion = { id: 6, name: "Reconocido" }; diagnostico.diagnosticos = [...diagnostico.diagnosticos, deteccion]; } if (diagnostico.objetosSospechoso.length > 0) { deteccion = { id: 1, name: "Deteccion de objeto sospechoso" }; diagnostico.diagnosticos = [...diagnostico.diagnosticos, deteccion]; } if (diagnostico.detectadosAnalisis == 0 && diagnostico.detectadosCoco == 0) { deteccion = { id: 16, name: "No Detectado" }; diagnostico.diagnosticos = [...diagnostico.diagnosticos, deteccion]; } else if (diagnostico.detectadosAnalisis > 1 || diagnostico.detectadosCoco > 1) { deteccion = { id: 21, name: "Acompañado" }; diagnostico.diagnosticos = [...diagnostico.diagnosticos, deteccion]; } else if (diagnostico.reconocido == false && (diagnostico.detectadosAnalisis > 0 || diagnostico.detectadosCoco > 0)) { deteccion = { id: 11, name: "No Reconocido" }; diagnostico.diagnosticos = [...diagnostico.diagnosticos, deteccion]; } this.diagnosticos = [...this.diagnosticos, diagnostico]; this.feedback = deteccion.name; // console.log("diagnosticos", this.diagnosticos); // 1 Deteccion de objeto sospechoso // 6 Reconocido // 11 No Reconocido // 16 No Detectado // 21 Acompañado // 26 Sin Web Cam // 31 Grabacion de Audio // 36 Componente Eliminado // 41 Error en Captura // 46 Guardar Calificacion // 51 Login Face Id // 56 Sin Face Id // 61 Sin Audio // 66 Ausencia // 71 Distraccion // 76 Photo Upload // 81 Sin Foto // 86 Acompa&ntilde;ado // 91 Analisis de Audio // 96 Video // 101 Screen Recording }, // INSERT INTO auditoria_examenes (id_examen, idpersona, ip_acceso, timestamp_registro, request, request_url, fecha_registro, meta_datos, status) VALUES(1, 1128281476, '169.254.129.3', '2021-03-05 22:42:00.0', '[]', 'https://devopslabsterritorium-2.azurewebsites.net/', '2021-03-05', '{"file_url": "https://proctoring-files.azureedge.net/files/proctoringFiles/1507/2021-03-05/5998545/1433686/Video/4ljCFrT9bB1i1614984120ia6q67903000.webm", "timestamp": "2021-03-05 22:42:00", "session_hash": "f80ede8dff1cd91445d3a1af525d97f8621e8052", "es_incidencia": false, "tipo_incidencia": "Video", "timestamp_session": 1614984105865}', NULL); blobToDataURL(blob) { return new Promise((resolve, reject) => { let reader = new FileReader(); reader.readAsDataURL(blob); reader.onload = () => { resolve(reader.result); }; reader.onerror = reject; }); }, getFoto() { let thas = this; return new Promise((resolve, reject) => { let uriCaptura = thas.$refs.devices.photo(); const captura = new Image(); captura.src = uriCaptura; captura.onload = () => { resolve(captura.src); }; captura.onerror = reject; }); }, getVideo() { this.$refs.devices.video(); }, getAudio() { this.$refs.devices.audio(); }, async procesarPerfil() { if (this.allowsLocalSupervision) { const response = await axios.get(this.urlPerfil, { method: 'GET', responseType: 'blob' // important }); const blob = new Blob([response.data], { type: 'image/jpeg' }); this.uriPerfil = await this.blobToDataURL(blob); let perfil = this.$refs.perfil; perfil.src = this.uriPerfil; const referencePhoto = await faceapi.fetchImage(this.urlPerfil); const referenceFaceAnalysis = await faceapi.detectSingleFace(referencePhoto).withFaceLandmarks().withFaceDescriptor(); const referenceFaceDescriptor = [referenceFaceAnalysis.descriptor]; const referenceFacialFeatures = new faceapi.LabeledFaceDescriptors("true", referenceFaceDescriptor); const maxDescriptorDistance = 0.6; this.faceMatcher = new faceapi.FaceMatcher(referenceFacialFeatures, maxDescriptorDistance); } }, async getDataVerify() { if (this.allowsLocalSupervision) { this.uriCaptura = await this.getFoto(); // let captura = this.$refs.captura; // captura.src = this.uriCaptura; await this.verifyFace(this.uriCaptura); } }, async start() { await this.getDataVerify(); }, reportStatus(message) {// console.log(`${message}`); }, async createContainer() { try { this.reportStatus(`Creating container "${this.containerName}"...`); await this.containerClient.create(); this.reportStatus(`Done.`); } catch (error) { this.reportStatus(error.message); } }, dataURItoBlob(dataURI) { var byteString = atob(dataURI.split(',')[1]); var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]; var ab = new ArrayBuffer(byteString.length); var ia = new Uint8Array(ab); for (var i = 0; i < byteString.length; i++) { ia[i] = byteString.charCodeAt(i); } return new Blob([ab], { type: mimeString }); }, async uploadFiles(dataURL, name = "") { let url = ""; let blob = this.dataURItoBlob(dataURL); try { if (name == "") { name = uuidv4(); name = `${name}.jpg`; } this.reportStatus("Uploading files..."); // const blockBlobClient = this.containerClient.getBlockBlobClient(name); // let data = await blockBlobClient.uploadBrowserData(blob); // let url = data._response.request.url; const blockBlobURL = azblob.BlockBlobURL.fromContainerURL(this.containerURL, name); url = await azblob.uploadBrowserDataToBlockBlob(azblob.Aborter.none, blob, blockBlobURL); return url._response.request.url; } catch (error) { this.reportStatus(error.message); return null; } }, async uploadBlobVideo(dataBlob, name = "") { let url = ""; try { if (name == "") { name = uuidv4(); name = `${name}.webm`; } this.reportStatus("Uploading files..."); // const blockBlobClient = this.containerClient.getBlockBlobClient(name); // // let blob = this.dataURItoBlob(dataURL); // // let data = await blockBlobClient.uploadBrowserData(dataURL); // let data = await blockBlobClient.uploadBrowserData(dataBlob); const blockBlobURL = azblob.BlockBlobURL.fromContainerURL(this.containerURL, name); url = await azblob.uploadBrowserDataToBlockBlob(azblob.Aborter.none, dataBlob, blockBlobURL); return url._response.request.url; } catch (error) { this.reportStatus(error.message); return null; } }, async obtenerToken() { try { let data = JSON.stringify({ "data": { "idtest": this.idExamen, "iduser": this.idEstudiante, "institution": this.idUniversidad } }); var config = { method: 'post', url: this.urlToken, headers: { 'Authorization': `Bearer ${this.authorization}`, 'Content-Type': 'application/json' }, data: data }; const response = await axios(config); this.token = response.data; } catch (error) {// console.log(error); } }, async configDiagnosticos() { try { let data = {}; data = JSON.stringify(data); var config = { method: 'get', url: this.urlConfig, headers: { 'Authorization': `Bearer ${this.token}`, 'Content-Type': 'application/json' }, data: data }; const configDiagnostico = await axios(config); this.config = configDiagnostico.data; this.capturarFoto = this.config.startPhotos; this.capturarVideo = this.config.startVideo; this.capturarAudio = this.config.startAudio; } catch (error) {// console.log(error); } }, async processDiagnosticos() { if (this.diagnosticos.length >= this.config.acumularPhotos) { try { let data = { data: this.diagnosticos }; data = JSON.stringify(data); var config = { method: 'post', url: this.urlSaveDiagnosticos, headers: { 'Authorization': `Bearer ${this.token}`, 'Content-Type': 'application/json' }, data: data }; const response = await axios(config); this.diagnosticos = []; // console.log (response.data); } catch (error) {// console.log(error); } } }, async processCapturas() { if (this.capturas.length >= this.config.acumularPhotos) { try { let capturas = [...this.capturas]; this.capturas = []; let data = { data: capturas, objects: this.objetosSospechoso, analisysType: this.analisysType, compareFace: this.urlPerfil }; data = JSON.stringify(data); var config = { method: 'post', url: this.urlProcessDiagnosticos, headers: { 'Authorization': `Bearer ${this.token}`, 'Content-Type': 'application/json' }, data: data }; const response = await axios(config); // console.log (response.data); } catch (error) {// console.log(error); } } }, async saveVideo(url) { try { let data = { data: { url } }; data = JSON.stringify(data); var config = { method: 'post', url: this.urlSaveVideo, headers: { 'Authorization': `Bearer ${this.token}`, 'Content-Type': 'application/json' }, data: data }; const response = await axios(config); // console.log ("saveVideo", response.data); } catch (error) {// console.log(error); } }, async saveAudio(url) { try { let data = { data: { url } }; data = JSON.stringify(data); var config = { method: 'post', url: this.urlSaveAudio, headers: { 'Authorization': `Bearer ${this.token}`, 'Content-Type': 'application/json' }, data: data }; const response = await axios(config); // console.log ("saveAudio", response.data); } catch (error) {// console.log(error); } }, async coreProctoring() { if (this.timeElapsed >= this.capturarVideo) { this.capturarVideo = this.capturarVideo + this.config.intervalVideo; this.getVideo(); console.log("this.capturarVideo", this.capturarVideo); } if (this.timeElapsed >= this.capturarAudio) { this.capturarAudio = this.capturarAudio + this.config.intervalAudio; this.getAudio(); console.log("this.capturarAudio", this.capturarAudio); } if (this.timeElapsed >= this.capturarFoto) { this.capturarFoto = this.capturarFoto + this.config.intervalPhotos; if (this.allowsLocalSupervision) { await this.getDataVerify(); await this.processDiagnosticos(); } else { let uriCaptura = await this.getFoto(); let url = await this.uploadFiles(uriCaptura); this.capturas = [...this.capturas, url]; // console.log(this.capturas); } console.log("this.capturarFoto", this.capturarFoto); } this.timeElapsed = this.timeElapsed + this.timeInterval; console.log("this.timeElapsed", this.timeElapsed); }, async startProctoring() { console.log(this.config); try { if (this.config.active) { this.idCoreProctoring = setIntervalAsync(this.coreProctoring, this.timeInterval); } } catch (error) { console.log(error); } }, // ---------------------------------------------------------------------------------- async createContainer2() { try { console.log(`Creating container "${this.containerName}"...`); await this.containerURL.create(azblob.Aborter.none); console.log(`Done.`); } catch (error) { console.log(error.body.message); } } }, async mounted() { this.allowsLocalSupervision = false; await this.obtenerToken(); await this.configDiagnosticos(); // this.uriCaptura = this.$refs.devices.photo(); // this.modelPromise = cocoSsd.load(); // const modelPath = 'https://cdn.jsdelivr.net/npm/@vladmandic/face-api@1.2.3/model/'; // await faceapi.nets.tinyFaceDetector.loadFromUri(modelPath); // await faceapi.nets.faceLandmark68Net.loadFromUri(modelPath); // await faceapi.nets.faceRecognitionNet.loadFromUri(modelPath); // await faceapi.nets.ssdMobilenetv1.loadFromUri(modelPath); // await this.verifyLocalAnalysis(); // // -------------------------------------------------------------- // await this.procesarPerfil(); // // ---------------------------------------------------------------------- // AZURE // console.log("this.config.blobSasUrl", this.config.blobSasUrl); // this.blobServiceClient = new BlobServiceClient(this.config.blobSasUrl); // this.containerClient = this.blobServiceClient.getContainerClient(this.containerName); // Crear contenedor // this.createContainer(); // await this.startProctoring(); // ---------------------------------------------------------------------------------- console.log("inicio"); this.containerURL = new azblob.ContainerURL(`https://${this.accountName}.blob.core.windows.net/${this.containerName}?${this.sasString}`, azblob.StorageURL.newPipeline(new azblob.AnonymousCredential())); await this.createContainer2(); await this.startProctoring(); console.log("fin"); }, async beforeUnmount() { await clearIntervalAsync(this.idCoreProctoring); } }); const _withId = /*#__PURE__*/withScopeId("data-v-e6fc70d8"); pushScopeId("data-v-e6fc70d8"); const _hoisted_1 = { class: "territorium-proctoring" }; const _hoisted_2 = { ref: "perfil", src: "" }; const _hoisted_3 = { ref: "captura", src: "" }; popScopeId(); const render = /*#__PURE__*/_withId((_ctx, _cache, $props, $setup, $data, $options) => { const _component_territorium_device_manager = resolveComponent("territorium-device-manager"); return openBlock(), createBlock("div", _hoisted_1, [createVNode(_component_territorium_device_manager, { ref: "devices", onSendAudio: _cache[1] || (_cache[1] = $event => _ctx.uriAudio = $event), onSendBlob: _cache[2] || (_cache[2] = $event => _ctx.blobVideo = $event) }, null, 512), createVNode("label", null, toDisplayString(_ctx.feedback), 1), createVNode("img", _hoisted_2, null, 512), createVNode("img", _hoisted_3, null, 512)]); }); function styleInject(css, ref) { if ( ref === void 0 ) ref = {}; var insertAt = ref.insertAt; if (!css || typeof document === 'undefined') { return; } var head = document.head || document.getElementsByTagName('head')[0]; var style = document.createElement('style'); style.type = 'text/css'; if (insertAt === 'top') { if (head.firstChild) { head.insertBefore(style, head.firstChild); } else { head.appendChild(style); } } else { head.appendChild(style); } if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } } var css_248z = "\n.territorium-proctoring[data-v-e6fc70d8] {\n display: flex;\n flex-direction: column;\n justify-content: center;\n align-items: center;\n background-color: darkgrey;\n width: 100%;\n height: 100%;\n}\n"; styleInject(css_248z); script.render = render; script.__scopeId = "data-v-e6fc70d8"; // Import vue component // IIFE injects install function into component, allowing component // to be registered via Vue.use() as well as Vue.component(), var entry_esm = /*#__PURE__*/(() => { // Get component instance const installable = script; // Attach install function executed by Vue.use() installable.install = app => { app.component('TerritoriumProctoring', installable); }; return installable; })(); // It's possible to expose named exports when writing components that can // also be used as directives, etc. - eg. import { RollupDemoDirective } from 'rollup-demo'; // export const RollupDemoDirective = directive; export default entry_esm;