scorm-again
Version:
A modern SCORM JavaScript run-time library for SCORM 1.2 and SCORM 2004
1 lines • 68.1 kB
JavaScript
const e=e=>{if(!e||0>=e)return"00:00:00";const t=Math.floor(e/3600),s=new Date(1e3*e),i=s.getUTCMinutes(),n=s.getSeconds(),o=e%1;let a="";return r(o)>0&&(a=r(o)>2?o.toFixed(2):o+"",a="."+a.split(".")[1]),(t+":"+i+":"+n).replace(/\b\d\b/g,"0$&")+a},t=o((e,t)=>{if("number"!=typeof e&&"boolean"!=typeof e||(e+=""),"string"==typeof t&&(t=RegExp(t)),!e)return 0;if(!e.match(t))return/^\d+(?:\.\d+)?$/.test(e)?+e:0;const s=e.split(":");return 3600*+s[0]+60*+s[1]+ +s[2]},(e,t)=>`${"string"==typeof e?e:(e??"")+""}:${"string"==typeof t?t:t?.toString()??""}`),s=o((e,t)=>{if("string"==typeof t&&(t=RegExp(t)),!e||!e?.match?.(t))return 0;const[,s,i,r,n,o,a,c]=RegExp(t).exec?.(e)??[];let result=0;return result+=+c||0,result+=60*+a||0,result+=3600*+o||0,result+=86400*+n||0,result+=604800*+r||0,result+=2592e3*+i||0,result+=31536e3*+s||0,result},(e,t)=>`${e??""}:${"string"==typeof t?t:t?.toString()??""}`);function i(e){const result={};return function e(t,s){if(Object(t)!==t)result[s]=t;else if(Array.isArray(t))t.forEach((t,i)=>{e(t,`${s}[${i}]`)}),0===t.length&&(result[s]=[]);else{const i=Object.keys(t).filter(e=>({}.hasOwnProperty.call(t,e))),r=0===i.length;i.forEach(i=>{e(t[i],s?`${s}.${i}`:i)}),r&&s&&(result[s]={})}}(e,""),result}function r(e){if(Math.floor(e)===e||0>(e+"")?.indexOf?.("."))return 0;const t=(""+e).split(".")?.[1];return t?.length??0}function n(e,t){return"string"==typeof e&&RegExp(t).test(e)}function o(e,t){const s=new Map;return(...i)=>{const r=t?t(...i):JSON.stringify(i);return s.has(r)?s.get(r):(()=>{const result=e(...i);return s.set(r,result),result})()}}class a{jsonString=!1;_cmi_element;_initialized=!1;constructor(e){this._cmi_element=e}get initialized(){return this._initialized}initialize(){this._initialized=!0}}class c extends a{_start_time;get start_time(){return this._start_time}setStartTime(){if(void 0!==this._start_time)throw Error("Start time has already been set.");this._start_time=(new Date).getTime()}}class l extends Error{constructor(e,t){super(`${e} : ${""+t}`),this._errorCode=t,Object.setPrototypeOf(this,l.prototype)}_errorCode;get errorCode(){return this._errorCode}}class h extends l{constructor(e,t,s,i){super(e,t),this.message=`${e} : ${s}`,this._errorMessage=s,i&&(this._detailedMessage=i),Object.setPrototypeOf(this,h.prototype)}_errorMessage;_detailedMessage="";get errorMessage(){return this._errorMessage}get detailedMessage(){return this._detailedMessage}}const d="true",_="false",u="raw,min,max",m="id,score,status",g={0:{basicMessage:"No Error",detailMessage:"No error occurred, the previous API call was successful."},101:{basicMessage:"General Exception",detailMessage:"No specific error code exists to describe the error."},201:{basicMessage:"Invalid argument error",detailMessage:"Indicates that an argument represents an invalid data model element or is otherwise incorrect."},202:{basicMessage:"Element cannot have children",detailMessage:'Indicates that LMSGetValue was called with a data model element name that ends in "_children" for a data model element that does not support the "_children" suffix.'},203:{basicMessage:"Element not an array - cannot have count",detailMessage:'Indicates that LMSGetValue was called with a data model element name that ends in "_count" for a data model element that does not support the "_count" suffix.'},301:{basicMessage:"Not initialized",detailMessage:"Indicates that an API call was made before the call to lmsInitialize."},401:{basicMessage:"Not implemented error",detailMessage:"The data model element indicated in a call to LMSGetValue or LMSSetValue is valid, but was not implemented by this LMS. SCORM 1.2 defines a set of data model elements as being optional for an LMS to implement."},402:{basicMessage:"Invalid set value, element is a keyword",detailMessage:'Indicates that LMSSetValue was called on a data model element that represents a keyword (elements that end in "_children" and "_count").'},403:{basicMessage:"Element is read only",detailMessage:"LMSSetValue was called with a data model element that can only be read."},404:{basicMessage:"Element is write only",detailMessage:"LMSGetValue was called on a data model element that can only be written to."},405:{basicMessage:"Incorrect Data Type",detailMessage:"LMSSetValue was called with a value that is not consistent with the data format of the supplied data model element."},407:{basicMessage:"Element Value Out Of Range",detailMessage:"The numeric value supplied to a LMSSetValue call is outside of the numeric range allowed for the supplied data model element."},408:{basicMessage:"Data Model Dependency Not Established",detailMessage:"Some data model elements cannot be set until another data model element was set. This error condition indicates that the prerequisite element was not set before the dependent element."}},E=g;class f extends h{constructor(e,t){!{}.hasOwnProperty.call(E,t+"")?super(e,101,E[101]?.basicMessage,E[101]?.detailMessage):super(e,t,E[t+""]?.basicMessage||"Unknown error",E[t+""]?.detailMessage),Object.setPrototypeOf(this,f.prototype)}}const p={GENERAL:101,INITIALIZATION_FAILED:101,INITIALIZED:101,TERMINATED:101,TERMINATION_FAILURE:101,TERMINATION_BEFORE_INIT:101,MULTIPLE_TERMINATION:101,RETRIEVE_BEFORE_INIT:101,RETRIEVE_AFTER_TERM:101,STORE_BEFORE_INIT:101,STORE_AFTER_TERM:101,COMMIT_BEFORE_INIT:101,COMMIT_AFTER_TERM:101,ARGUMENT_ERROR:101,CHILDREN_ERROR:101,COUNT_ERROR:101,GENERAL_GET_FAILURE:101,GENERAL_SET_FAILURE:101,GENERAL_COMMIT_FAILURE:101,UNDEFINED_DATA_MODEL:101,UNIMPLEMENTED_ELEMENT:101,VALUE_NOT_INITIALIZED:101,INVALID_SET_VALUE:101,READ_ONLY_ELEMENT:101,WRITE_ONLY_ELEMENT:101,TYPE_MISMATCH:101,VALUE_OUT_OF_RANGE:101,DEPENDENCY_NOT_ESTABLISHED:101,RETRIEVE_BEFORE_INIT:301,STORE_BEFORE_INIT:301,COMMIT_BEFORE_INIT:301,ARGUMENT_ERROR:201,CHILDREN_ERROR:202,COUNT_ERROR:203,UNDEFINED_DATA_MODEL:401,UNIMPLEMENTED_ELEMENT:401,VALUE_NOT_INITIALIZED:301,INVALID_SET_VALUE:402,READ_ONLY_ELEMENT:403,WRITE_ONLY_ELEMENT:404,TYPE_MISMATCH:405,VALUE_OUT_OF_RANGE:407,DEPENDENCY_NOT_ESTABLISHED:408};class S extends a{_errorCode;_errorClass;__children;childArray;constructor(e){super(e.CMIElement),this.__children=e.children,this._errorCode=e.errorCode??p.GENERAL,this._errorClass=e.errorClass||l,this.childArray=[]}reset(e=!1){if(this._initialized=!1,e)this.childArray=[];else for(let e=0;this.childArray.length>e;e++)this.childArray[e]?.reset()}get _children(){return this.__children}set _children(_children){throw new this._errorClass(this._cmi_element+"._children",this._errorCode)}get _count(){return this.childArray.length}set _count(_count){throw new this._errorClass(this._cmi_element+"._count",this._errorCode)}toJSON(){this.jsonString=!0;const result={};for(let e=0;this.childArray.length>e;e++)result[e+""]=this.childArray[e];return this.jsonString=!1,result}}const O={_:0,DEBUG:1,INFO:2,WARN:3,ERROR:4,NONE:5},C={autocommit:!1,autocommitSeconds:10,throttleCommits:!1,useAsynchronousCommits:!1,sendFullCommit:!0,lmsCommitUrl:!1,dataCommitFormat:"json",commitRequestDataType:"application/json;charset=UTF-8",autoProgress:!1,logLevel:O.ERROR,selfReportSessionTime:!1,alwaysSendTotalTime:!1,renderCommonCommitFields:!1,autoCompleteLessonStatus:!1,strict_errors:!0,xhrHeaders:{},xhrWithCredentials:!1,fetchMode:"cors",asyncModeBeaconBehavior:"never",responseHandler:async function(e){if(void 0!==e){let t=null;try{if("function"==typeof e.json)t=await e.json();else if("function"==typeof e.text){const s=await e.text();s&&(t=JSON.parse(s))}}catch(e){}return null!==t&&{}.hasOwnProperty.call(t,"result")?{result:t.result,errorCode:"number"==typeof t.errorCode?t.errorCode:!0===t.result||t.result===d?0:101}:200===e.status?{result:d,errorCode:0}:{result:_,errorCode:101}}return{result:_,errorCode:101}},xhrResponseHandler:function(e){if(void 0!==e){let t=null;if(200>e.status||e.status>299)return{result:_,errorCode:101};try{t=JSON.parse(e.responseText)}catch(e){}return null!==t&&{}.hasOwnProperty.call(t,"result")?{result:t.result,errorCode:"number"==typeof t.errorCode?t.errorCode:!0===t.result||t.result===d?0:101}:{result:d,errorCode:0}}return{result:_,errorCode:101}},requestHandler:function(e){return e},onLogMessage:R,mastery_override:!1,score_overrides_status:!1,completion_status_on_failed:"completed",scoItemIds:[],scoItemIdValidator:!1,globalObjectiveIds:[],enableOfflineSupport:!1,courseId:"",syncOnInitialize:!0,syncOnTerminate:!0,maxSyncAttempts:5,scoId:"",autoPopulateCommitMetadata:!1,httpService:null,globalStudentPreferences:!1};function R(e,t){switch(e){case"4":case 4:case"ERROR":case O.ERROR:console.error(t);break;case"3":case 3:case"WARN":case O.WARN:console.warn(t);break;case"2":case 2:case"INFO":case O.INFO:console.info(t);break;case"1":case 1:case"DEBUG":case O.DEBUG:console.debug?console.debug(t):console.log(t)}}const L="^[\\s\\S]{0,255}$",y="^([0-9]+):([0-9]{2}):([0-9]{2})(\\.\\d{1,2})?$",I="^-?([0-9]+)$",M="^-?([0-9]{0,10})(\\.[0-9]*)?$",v="^[\\u0021-\\u007E\\s]{0,255}$",N="^.*$",w="^(passed|completed|failed|incomplete|browsed|not attempted)$",T="0#100",A="^P(?:([.,\\d]+)Y)?(?:([.,\\d]+)M)?(?:([.,\\d]+)W)?(?:([.,\\d]+)D)?(?:T?(?:([.,\\d]+)H)?(?:([.,\\d]+)M)?(?:(\\d+(?:\\.\\d{1,2})?)S)?)?$";class b{_API;_cancelled=!1;_timeout;_callback;constructor(e,t,s){this._API=e,this._timeout=setTimeout(this.wrapper.bind(this),t),this._callback=s}cancel(){this._cancelled=!0,this._timeout&&clearTimeout(this._timeout)}wrapper(){this._cancelled||this._API.isInitialized()&&(async()=>{await this._API.commit(this._callback)})()}}class x{settings;error_codes;constructor(e,t){this.settings=e,this.error_codes=t}processHttpRequest(e,t,s=!1,i,r){return this._performAsyncRequest(e,t,s,i,r),{result:d,errorCode:0}}async _performAsyncRequest(e,t,s,i,r){try{const i=this.settings.requestHandler(t);let n;n=s&&"never"!==this.settings.asyncModeBeaconBehavior?await this.performBeacon(e,i):await this.performFetch(e,i);const result=await this.transformResponse(n,r);this._isSuccessResponse(n,result)?r("CommitSuccess"):r("CommitError",void 0,result.errorCode)}catch(e){i("processHttpRequest","Async request failed: "+(e instanceof Error?e.message:e+""),O.ERROR),r("CommitError")}}_prepareRequestBody(e){return{body:e instanceof Array?e.join("&"):JSON.stringify(e),contentType:e instanceof Array?"application/x-www-form-urlencoded":this.settings.commitRequestDataType}}async performFetch(e,t){if("always"===this.settings.asyncModeBeaconBehavior)return this.performBeacon(e,t);const{body:s,contentType:i}=this._prepareRequestBody(t),r={method:"POST",mode:this.settings.fetchMode,body:s,headers:{...this.settings.xhrHeaders,"Content-Type":i},keepalive:!0};return this.settings.xhrWithCredentials&&(r.credentials="include"),fetch(e,r)}async performBeacon(e,t){const{body:s,contentType:i}=this._prepareRequestBody(t),r=navigator.sendBeacon(e,new Blob([s],{type:i}));return Promise.resolve({status:r?200:0,ok:r,json:async()=>({result:r?"true":"false",errorCode:r?0:this.error_codes.GENERAL_COMMIT_FAILURE||391}),text:async()=>JSON.stringify({result:r?"true":"false",errorCode:r?0:this.error_codes.GENERAL_COMMIT_FAILURE||391})})}async transformResponse(e,t){let result;try{result="function"==typeof this.settings.responseHandler?await this.settings.responseHandler(e):await e.json()}catch(t){const s=await e.text().catch(()=>"Unable to read response text");return{result:_,errorCode:this.error_codes.GENERAL_COMMIT_FAILURE||391,errorMessage:"Failed to parse LMS response: "+(t instanceof Error?t.message:t+""),errorDetails:JSON.stringify({status:e.status,statusText:e.statusText,url:e.url,responseText:s.substring(0,500),parseError:t instanceof Error?t.message:t+""})}}return Object.hasOwnProperty.call(result,"errorCode")||(result.errorCode=this._isSuccessResponse(e,result)?0:this.error_codes.GENERAL_COMMIT_FAILURE||391),this._isSuccessResponse(e,result)||(result.errorDetails={status:e.status,statusText:e.statusText,url:e.url,...result.errorDetails}),result}_isSuccessResponse(e,result){const t=result.result;return!(200>e.status||e.status>299||!0!==t&&"true"!==t&&t!==d)}updateSettings(e){this.settings=e}}const D="{target=";function F(e,t){const s=e[t];return void 0===s?(void 0!==console&&console.warn&&console.warn("CMIValueAccessService: Unknown error code key: "+t),e.GENERAL??0):s}class j{context;constructor(e){this.context=e}getUndefinedDataModelErrorCode(e){return F(this.context.errorCodes,e?"UNDEFINED_DATA_MODEL":"GENERAL")}setCMIValue(e,t,s,i){if(!s||""===s)return t&&this.context.throwSCORMError(s,F(this.context.errorCodes,"GENERAL_SET_FAILURE"),"The data model element was not specified"),_;this.context.setLastErrorCode("0");const r=s.split(".");let n=this.context.getDataModel(),o=_,a=!1;const c=`The data model element passed to ${e} (${s}) is not a valid SCORM data model element.`,l=this.getUndefinedDataModelErrorCode(t);for(let e=0;r.length>e;e++){if(e===r.length-1){o=this.setFinalAttribute(n,r[e],i,s,t,l,c);break}{const o=this.traverseToNextLevel(n,r,e,i,s,t,a,l,c);if(o.error)break;n=o.refObject,e=o.idx,a=o.foundFirstIndex}}return o===_&&this.context.apiLog(e,`There was an error setting the value for: ${s}, value of: ${i}`,O.WARN),o}getCMIValue(e,t,s){if(!s||""===s)return t&&this.context.throwSCORMError(s,F(this.context.errorCodes,"GENERAL_GET_FAILURE"),"The data model element was not specified"),"";if(t&&s.endsWith("._version")&&"cmi._version"!==s)return this.context.throwSCORMError(s,F(this.context.errorCodes,"GENERAL_GET_FAILURE"),"The _version keyword was used incorrectly"),"";const i=s.split(".");let r=this.context.getDataModel(),n=null;const o=`The data model element passed to ${e} (${s}) has not been initialized.`,a=`The data model element passed to ${e} (${s}) is not a valid SCORM data model element.`,c=this.getUndefinedDataModelErrorCode(t);for(let e=0;i.length>e;e++){n=i[e];const l=this.validateGetAttribute(r,n,s,t,c,a,e===i.length-1);if(void 0!==l.returnValue)return l.returnValue;if(l.error)return"";if(null==n){this.context.throwSCORMError(s,c,a);break}if(r=r[n],void 0===r){this.context.throwSCORMError(s,c,a);break}if(r instanceof S){const t=this.handleGetArrayAccess(r,i,e,s,o);if(t.error)return"";r=t.refObject,e=t.idx}}return null==r?(t||("_children"===n?this.context.throwSCORMError(s,F(this.context.errorCodes,"CHILDREN_ERROR"),void 0):"_count"===n&&this.context.throwSCORMError(s,F(this.context.errorCodes,"COUNT_ERROR"),void 0)),""):r}setFinalAttribute(e,t,s,i,r,o,a){return r&&t?.startsWith(D)?this.context.isInitialized()?(this.context.throwSCORMError(i,F(this.context.errorCodes,"READ_ONLY_ELEMENT")),_):d:void 0!==t&&this.context.checkObjectHasProperty(e,t)?n(i,"\\.correct_responses\\.\\d+$")&&this.context.isInitialized()&&"pattern"!==t&&(this.context.validateCorrectResponse(i,s),"0"!==this.context.getLastErrorCode())?(this.context.throwSCORMError(i,F(this.context.errorCodes,"TYPE_MISMATCH")),_):r&&"0"!==this.context.getLastErrorCode()?_:void 0===t||"__proto__"===t||"constructor"===t?(this.context.throwSCORMError(i,o,a),_):r&&"id"===t&&this.context.isInitialized()&&this.context.checkForDuplicateId(i,s)?(this.context.throwSCORMError(i,F(this.context.errorCodes,"GENERAL_SET_FAILURE")),_):(e[t]=s,d):(this.context.throwSCORMError(i,o,a),_)}traverseToNextLevel(e,t,s,i,r,n,o,a,c){const l=t[s];if(void 0===l||!this.context.checkObjectHasProperty(e,l))return this.context.throwSCORMError(r,a,c),{refObject:e,idx:s,foundFirstIndex:o,error:!0};if(!(e=e[l]))return this.context.throwSCORMError(r,a,c),{refObject:e,idx:s,foundFirstIndex:o,error:!0};if(e instanceof S){const l=this.handleSetArrayAccess(e,t,s,i,r,n,o,a,c);return l.error?{refObject:e,idx:s,foundFirstIndex:o,error:!0}:l}return{refObject:e,idx:s,foundFirstIndex:o,error:!1}}handleSetArrayAccess(e,t,s,i,r,n,o,a,c){const l=parseInt(t[s+1]||"0",10);if(!isNaN(l)){const t=e.childArray[l];if(t)return{refObject:t,idx:s+1,foundFirstIndex:!0,error:!1};{if(l>e.childArray.length){const t=n?F(this.context.errorCodes,"GENERAL_SET_FAILURE"):F(this.context.errorCodes,"INVALID_SET_VALUE")||F(this.context.errorCodes,"GENERAL_SET_FAILURE");return this.context.throwSCORMError(r,t,`Cannot set array element at index ${l}. Array indices must be sequential. Current array length is ${e.childArray.length}, expected index ${e.childArray.length}.`),{refObject:e,idx:s,foundFirstIndex:o,error:!0}}const t=this.context.getChildElement(r,i,o);return t?(e.initialized&&t.initialize(),e.childArray[l]=t,{refObject:t,idx:s+1,foundFirstIndex:!0,error:!1}):("0"===this.context.getLastErrorCode()&&this.context.throwSCORMError(r,a,c),{refObject:e,idx:s,foundFirstIndex:o,error:!0})}}return{refObject:e,idx:s,foundFirstIndex:o,error:!1}}validateGetAttribute(e,t,s,i,r,n,o){if(i){const i=t+"";if(i.startsWith(D)&&"function"==typeof e._isTargetValid){const t=i.substring(8,i.length-1);return{error:!1,returnValue:e._isTargetValid(t)}}if(void 0===t||!this.context.checkObjectHasProperty(e,t))return"_children"===t?(this.context.throwSCORMError(s,F(this.context.errorCodes,"GENERAL_GET_FAILURE"),"The data model element does not have children"),{error:!0}):"_count"===t?(this.context.throwSCORMError(s,F(this.context.errorCodes,"GENERAL_GET_FAILURE"),"The data model element is not a collection and therefore does not have a count"),{error:!0}):(this.context.throwSCORMError(s,r,n),{error:!0})}else if(o&&(void 0===t||!this.context.checkObjectHasProperty(e,t)))return"_children"===t?this.context.throwSCORMError(s,F(this.context.errorCodes,"CHILDREN_ERROR")):"_count"===t?this.context.throwSCORMError(s,F(this.context.errorCodes,"COUNT_ERROR")):this.context.throwSCORMError(s,r,n),{error:!0};return{error:!1}}handleGetArrayAccess(e,t,s,i,r){const n=parseInt(t[s+1]||"",10);if(!isNaN(n)){const t=e.childArray[n];return t?{refObject:t,idx:s+1,error:!1}:(this.context.throwSCORMError(i,F(this.context.errorCodes,"VALUE_NOT_INITIALIZED"),r),{refObject:e,idx:s,error:!0})}return{refObject:e,idx:s,error:!1}}}class V{static _instance;_logLevel=O.ERROR;_logHandler;constructor(){this._logHandler=R}static getInstance(){return V._instance||(V._instance=new V),V._instance}setLogLevel(e){this._logLevel=e}getLogLevel(){return this._logLevel}setLogHandler(e){this._logHandler=e}log(e,t){this.shouldLog(e)&&this._logHandler(e,t)}error(e){this.log(O.ERROR,e)}warn(e){this.log(O.WARN,e)}info(e){this.log(O.INFO,e)}debug(e){this.log(O.DEBUG,e)}shouldLog(e){return this.getNumericLevel(e)>=this.getNumericLevel(this._logLevel)}getNumericLevel(e){if(void 0===e)return O.NONE;if("number"==typeof e)return e;switch("string"==typeof e?e.toUpperCase():e){case"1":case"DEBUG":return O.DEBUG;case"2":case"INFO":return O.INFO;case"3":case"WARN":return O.WARN;case"4":case"ERROR":default:return O.ERROR;case"5":case"NONE":return O.NONE}}}function U(){return V.getInstance()}class G{_lastErrorCode="0";_lastDiagnostic="";_errorCodes;_apiLog;_getLmsErrorMessageDetails;_loggingService;constructor(e,t,s,i){this._errorCodes=e,this._apiLog=t,this._getLmsErrorMessageDetails=s,this._loggingService=i||U()}get lastErrorCode(){return this._lastErrorCode}set lastErrorCode(e){this._lastErrorCode=e}get lastDiagnostic(){return this._lastDiagnostic}throwSCORMError(e,t,s){this._lastDiagnostic=s||"",s||(s=this._getLmsErrorMessageDetails(t,!0));const i=`SCORM Error ${t}: ${s}${e?` [Element: ${e}]`:""}`;this._apiLog("throwSCORMError",t+": "+s,O.ERROR,e),this._loggingService.error(i),this._lastErrorCode=t+""}clearSCORMError(e){void 0!==e&&e!==_&&(this._lastErrorCode="0")}handleValueAccessException(e,t,s){if(t instanceof h){const i=t;this._lastErrorCode=i.errorCode+"",this._lastDiagnostic="",this._loggingService.warn(`Validation Error ${i.errorCode}: ${i.message} [Element: ${e}]`),s=_}else if(t instanceof Error){const i=t.constructor.name;this._loggingService.error(`${i}: ${t.message} [Element: ${e}]\n${t.stack||""}`),this.throwSCORMError(e,this._errorCodes.GENERAL,`${i}: ${t.message}`),s=_}else{this._loggingService.error(`Unknown error occurred while accessing [Element: ${e}]`);try{const e=JSON.stringify(t);this._loggingService.error("Error details: "+e)}catch(e){this._loggingService.error("Could not stringify error object for details")}this.throwSCORMError(e,this._errorCodes.GENERAL,"Unknown error"),s=_}return s}get errorCodes(){return this._errorCodes}}class ${listenerMap=new Map;listenerCount=0;apiLog;constructor(e){this.apiLog=e}parseListenerName(e){if(!e)return null;const t=e.split("."),s=t[0];let i=null;return t.length>1&&(i=e.replace(s+".","")),{functionName:s??e,CMIElement:i}}on(e,t){if(!t)return;const s=e.split(" ");for(const e of s){const s=this.parseListenerName(e);if(!s)continue;const{functionName:i,CMIElement:r}=s,n=this.listenerMap.get(i)??[];n.push({functionName:i,CMIElement:r,callback:t}),this.listenerMap.set(i,n),this.listenerCount++,this.apiLog("on","Added event listener: "+this.listenerCount,O.INFO,i)}}off(e,t){if(!t)return;const s=e.split(" ");for(const e of s){const s=this.parseListenerName(e);if(!s)continue;const{functionName:i,CMIElement:r}=s,n=this.listenerMap.get(i);if(!n)continue;const o=n.findIndex(e=>e.CMIElement===r&&e.callback===t);-1!==o&&(n.splice(o,1),this.listenerCount--,0===n.length&&this.listenerMap.delete(i),this.apiLog("off","Removed event listener: "+this.listenerCount,O.INFO,i))}}clear(e){const t=e.split(" ");for(const e of t){const t=this.parseListenerName(e);if(!t)continue;const{functionName:s,CMIElement:i}=t;if(this.listenerMap.has(s)){const e=this.listenerMap.get(s),t=null===i?[]:e.filter(e=>e.CMIElement!==i);this.listenerCount-=e.length-t.length,0===t.length?this.listenerMap.delete(s):this.listenerMap.set(s,t)}}}processListeners(e,t,s){this.apiLog(e,s,O.INFO,t);const i=this.listenerMap.get(e);if(i)for(const r of i){const i=!!r.CMIElement;let n=!1;if(t&&r.CMIElement)if(r.CMIElement.endsWith("*")){const e=r.CMIElement.slice(0,-1);n=t.startsWith(e)}else n=r.CMIElement===t;i&&!n||(this.apiLog("processListeners","Processing listener: "+r.functionName,O.DEBUG,t),e.startsWith("Sequence")||"CommitError"===e?r.callback(s):"CommitSuccess"===e?r.callback():r.callback(t,s))}}reset(){this.listenerMap.clear(),this.listenerCount=0}}class P{constructor(e,t,s){this.apiLog=s,this.settings=e,this.error_codes=t,this.boundOnlineStatusChangeHandler=this.handleOnlineStatusChange.bind(this),this.boundCustomNetworkStatusHandler=this.handleCustomNetworkStatus.bind(this),window.addEventListener("online",this.boundOnlineStatusChangeHandler),window.addEventListener("offline",this.boundOnlineStatusChangeHandler),window.addEventListener("scorm-again:network-status",this.boundCustomNetworkStatusHandler)}apiLog;settings;error_codes;storeName="scorm_again_offline_data";syncQueue="scorm_again_sync_queue";isOnline=navigator.onLine;syncInProgress=!1;boundOnlineStatusChangeHandler;boundCustomNetworkStatusHandler;handleOnlineStatusChange(){const e=this.isOnline;this.isOnline=navigator.onLine,!e&&this.isOnline?(this.apiLog("OfflineStorageService","Device is back online, attempting to sync...",O.INFO),this.syncOfflineData().then(e=>{e?this.apiLog("OfflineStorageService","Sync completed successfully",O.INFO):this.apiLog("OfflineStorageService","Sync failed",O.ERROR)},e=>{this.apiLog("OfflineStorageService","Error during sync: "+e,O.ERROR)})):e&&!this.isOnline&&this.apiLog("OfflineStorageService","Device is offline, data will be stored locally",O.INFO)}handleCustomNetworkStatus(e){if(!(e instanceof CustomEvent))return void this.apiLog("OfflineStorageService","Invalid network status event received",O.WARN);const{online:t}=e.detail;if("boolean"!=typeof t)return void this.apiLog("OfflineStorageService","Invalid online status value in custom event",O.WARN);const s=this.isOnline;this.isOnline=t,this.apiLog("OfflineStorageService","Network status updated via custom event: "+(t?"online":"offline"),O.INFO),!s&&this.isOnline?(this.apiLog("OfflineStorageService","Device is back online, attempting to sync...",O.INFO),this.syncOfflineData().then(e=>{e?this.apiLog("OfflineStorageService","Sync completed successfully",O.INFO):this.apiLog("OfflineStorageService","Sync failed",O.ERROR)},e=>{this.apiLog("OfflineStorageService","Error during sync: "+e,O.ERROR)})):s&&!this.isOnline&&this.apiLog("OfflineStorageService","Device is offline, data will be stored locally",O.INFO)}storeOffline(e,t){try{const s={id:`${e}_${Date.now()}_${Math.random().toString(36).substring(2,9)}`,courseId:e,timestamp:Date.now(),data:t,syncAttempts:0},i=this.getFromStorage(this.syncQueue)||[];return i.push(s),this.saveToStorage(this.syncQueue,i),this.saveToStorage(`${this.storeName}_${e}`,t),this.apiLog("OfflineStorageService","Stored data offline for course "+e,O.INFO),{result:d,errorCode:0}}catch(t){const s=(t instanceof Error?t.message:t+"").includes("storage quota");return this.apiLog("OfflineStorageService",s?"storage quota exceeded - cannot store offline data for course "+e:"Error storing offline data: "+t,O.ERROR),{result:_,errorCode:this.error_codes.GENERAL??0}}}async getOfflineData(e){try{return this.getFromStorage(`${this.storeName}_${e}`)||null}catch(e){return this.apiLog("OfflineStorageService","Error retrieving offline data: "+e,O.ERROR),null}}async syncOfflineData(){if(this.syncInProgress||!this.isOnline)return!1;this.syncInProgress=!0;try{const e=this.getFromStorage(this.syncQueue)||[];if(0===e.length)return this.syncInProgress=!1,!0;this.apiLog("OfflineStorageService",`Found ${e.length} items to sync`,O.INFO);const t=[];for(const s of e){const e=this.settings.maxSyncAttempts??5;if(e>s.syncAttempts)try{const e=await this.sendDataToLMS(s.data);!0===e.result||e.result===d?this.apiLog("OfflineStorageService","Successfully synced item "+s.id,O.INFO):(s.syncAttempts++,t.push(s),this.apiLog("OfflineStorageService",`Failed to sync item ${s.id}, attempt #${s.syncAttempts}`,O.WARN))}catch(e){s.syncAttempts++,t.push(s),this.apiLog("OfflineStorageService",`Error syncing item ${s.id}: ${e}`,O.ERROR)}else this.apiLog("OfflineStorageService",`Removing abandoned item ${s.id} after ${e} failed sync attempts`,O.WARN)}return this.saveToStorage(this.syncQueue,t),this.apiLog("OfflineStorageService",`Sync completed. ${e.length-t.length} items synced, ${t.length} items remaining`,O.INFO),this.syncInProgress=!1,!0}catch(e){return this.apiLog("OfflineStorageService","Error during sync process: "+e,O.ERROR),this.syncInProgress=!1,!1}}async sendDataToLMS(e){if(!this.settings.lmsCommitUrl)return{result:_,errorCode:this.error_codes.GENERAL||101};try{const t=this.settings.requestHandler(e),s={method:"POST",mode:this.settings.fetchMode,body:JSON.stringify(t),headers:{...this.settings.xhrHeaders,"Content-Type":this.settings.commitRequestDataType}};this.settings.xhrWithCredentials&&(s.credentials="include");const i=await fetch(this.settings.lmsCommitUrl,s),result="function"==typeof this.settings.responseHandler?await this.settings.responseHandler(i):await i.json();return 200>i.status||i.status>299||!0!==result.result&&result.result!==d?(Object.hasOwnProperty.call(result,"errorCode")||(result.errorCode=this.error_codes.GENERAL),result):(Object.hasOwnProperty.call(result,"errorCode")||(result.errorCode=0),result)}catch(e){return this.apiLog("OfflineStorageService","Error sending data to LMS: "+e,O.ERROR),{result:_,errorCode:this.error_codes.GENERAL||101}}}isDeviceOnline(){return this.isOnline}getFromStorage(e){const t=localStorage.getItem(e);if(t)try{return JSON.parse(t)}catch(e){return null}return null}saveToStorage(e,t){try{localStorage.setItem(e,JSON.stringify(t))}catch(e){if(e instanceof DOMException&&"QuotaExceededError"===e.name)throw Error("storage quota exceeded - localStorage is full",{cause:e});throw e}}async hasPendingOfflineData(e){return(this.getFromStorage(this.syncQueue)||[]).some(t=>t.courseId===e)}updateSettings(e){this.settings=e}destroy(){window.removeEventListener("online",this.boundOnlineStatusChangeHandler),window.removeEventListener("offline",this.boundOnlineStatusChangeHandler),window.removeEventListener("scorm-again:network-status",this.boundCustomNetworkStatusHandler)}}const z=o((e,t,s,i,r,n)=>{if("string"!=typeof t)return!1;const o=RegExp(s),a=t.match(o);if(n&&""===t)return!0;if(!a||""===a[0])throw new r(e,i);return!0},(e,t,s,i,r,n)=>`${e}:${"string"==typeof t?t:`[${typeof t}]`}:${s}:${i}:${n||!1}`),H=o((e,t,s,i,r)=>{const n=s.split("#");if(isNaN(t=+t))throw new r(e,i);const o=n[0],a=n[1],c=void 0!==a&&""!==a&&"*"!==a;if(void 0!==o&&""!==o&&+o>t)throw new r(e,i);if(c&&t>+a)throw new r(e,i);return!0},(e,t,s,i,r)=>`${e}:${t}:${s}:${i}`);class k{loadFromFlattenedJSON(e,t="",s,i,r){if(!i())return void console.error("loadFromFlattenedJSON can only be called before the call to lmsInitialize.");const n=/^(cmi\.interactions\.)(\d+)\.(.*)$/,o=/^(cmi\.objectives\.)(\d+)\.(.*)$/,interactions=[],objectives=[],a=[];for(const t in e)if({}.hasOwnProperty.call(e,t)){const s=t.match(n);if(s){interactions.push({key:t,value:e[t],index:+s[2],field:s[3]||""});continue}const i=t.match(o);if(i){objectives.push({key:t,value:e[t],index:+i[2],field:i[3]||""});continue}a.push({key:t,value:e[t]})}interactions.sort((e,t)=>e.index!==t.index?e.index-t.index:"id"===e.field?-1:"id"===t.field?1:"type"===e.field?-1:"type"===t.field?1:e.field.localeCompare(t.field)),objectives.sort((e,t)=>e.index!==t.index?e.index-t.index:"id"===e.field?-1:"id"===t.field?1:e.field.localeCompare(t.field)),a.sort((e,t)=>e.key.localeCompare(t.key));const c=e=>{e.forEach(e=>{const n={};n[e.key]=e.value,this.loadFromJSON(function(e){if(Object(e)!==e||Array.isArray(e))return e;const result={},pattern=/\.?([^.[\]]+)|\[(\d+)]/g;return Object.keys(e).filter(t=>({}.hasOwnProperty.call(e,t))).forEach(t=>{let s=result,i="";const r=RegExp(pattern);Array.from({length:t.match(RegExp(pattern,"g"))?.length??0},()=>r.exec(t)).forEach(e=>{e&&(s=s[i]??(s[i]=e[2]?[]:{}),i=e[2]||e[1]||"")}),s[i]=e[t]}),result[""]??result}(n),t,s,i,r)})};c(interactions),c(objectives),c(a)}loadFromJSON(e,t="",s,i,r){if(i()){t=void 0!==t?t:"cmi",r(e);for(const n in e)if({}.hasOwnProperty.call(e,n)&&e[n]){const o=(t?t+".":"")+n,a=e[n];if(a.constructor===Array){for(let e=0;a.length>e;e++)if(a[e]){const t=a[e],n=`${o}.${e}`;t.constructor===Object?this.loadFromJSON(t,n,s,i,r):s(n,t)}}else a.constructor===Object?this.loadFromJSON(a,o,s,i,r):s(o,a)}}else console.error("loadFromJSON can only be called before the call to lmsInitialize.")}renderCMIToJSONString(cmi,e){return e?JSON.stringify({cmi:cmi}):JSON.stringify({cmi:cmi},(e,t)=>void 0===t?null:t,2)}renderCMIToJSONObject(cmi,e){return JSON.parse(this.renderCMIToJSONString(cmi,e))}getCommitObject(e,t,s,i,r,n){const o=t||e,a=s?i(e,o):r(e,o);return[O.DEBUG,"1",1,"DEBUG"].includes(n)&&(console.debug("Commit (terminated: "+(e?"yes":"no")+"): "),console.debug(a)),a}}class B{settings;error_codes;constructor(e,t){this.settings=e,this.error_codes=t}processHttpRequest(e,t,s=!1,i,r){return s?this._handleImmediateRequest(e,t):this._performSyncXHR(e,t)}_handleImmediateRequest(e,t){const s=this.settings.requestHandler(t)??t,{body:i}=this._prepareRequestBody(s),r=navigator.sendBeacon(e,new Blob([i],{type:"text/plain;charset=UTF-8"}));return{result:r?"true":"false",errorCode:r?0:this.error_codes.GENERAL_COMMIT_FAILURE||391}}_performSyncXHR(e,t){const s=this.settings.requestHandler(t)??t,{body:i,contentType:r}=this._prepareRequestBody(s),n=new XMLHttpRequest;n.open("POST",e,!1),n.setRequestHeader("Content-Type",r),Object.entries(this.settings.xhrHeaders).forEach(([e,t])=>{n.setRequestHeader(e,t+"")}),this.settings.xhrWithCredentials&&(n.withCredentials=!0);try{return n.send(i),this.settings.xhrResponseHandler(n)}catch(e){return{result:_,errorCode:this.error_codes.GENERAL_COMMIT_FAILURE||391,errorMessage:e instanceof Error?e.message:e+""}}}_prepareRequestBody(e){return{body:e instanceof Array?e.join("&"):JSON.stringify(e),contentType:e instanceof Array?"application/x-www-form-urlencoded":this.settings.commitRequestDataType}}updateSettings(e){this.settings=e}}function J(e,t,s,i){return z(e,t,s,p.TYPE_MISMATCH,f,i)}function q(e,t,s,i){if(""===t)throw new f(e,p.VALUE_OUT_OF_RANGE);return H(e,t,s,p.VALUE_OUT_OF_RANGE,f)}const W=new class{validateScore(e,t,s,i,r,n,o){return z(e,t,s,r,o)&&(!i||H(e,t,i,n,o))}validateScorm12Audio(e,t){return J(e,t,I)&&q(e,t,"-1#100")}validateScorm12Language(e,t){return J(e,t,L)}validateScorm12Speed(e,t){return J(e,t,I)&&q(e,t,"-100#100")}validateScorm12Text(e,t){return J(e,t,I)&&q(e,t,"-1#1")}validateReadOnly(e,t){if(t)throw new f(e,p.READ_ONLY_ELEMENT)}};class Y{_timeout;_error_codes;_settings=C;_httpService;_eventService;_serializationService;_errorHandlingService;_loggingService;_offlineStorageService;_cmiValueAccessService;_courseId="";constructor(e,t,s,i,r,n,o,a,c){if(new.target===Y)throw new TypeError("Cannot construct BaseAPI instances directly");this.currentState=0,this._error_codes=e,t&&(this.settings={...C,...t}),void 0!==t?.asyncCommit&&void 0===t.useAsynchronousCommits&&void 0===t.throttleCommits&&(console.warn("DEPRECATED: 'asyncCommit' setting is deprecated and will be removed in a future version. Use 'useAsynchronousCommits: true' and 'throttleCommits: true' instead."),t.asyncCommit&&(this.settings.useAsynchronousCommits=!0,this.settings.throttleCommits=!0)),!this.settings.useAsynchronousCommits&&this.settings.throttleCommits&&(console.warn("throttleCommits cannot be used with synchronous commits. Setting throttleCommits to false."),this.settings.throttleCommits=!1),this._loggingService=a||U(),this._loggingService.setLogLevel(this.settings.logLevel),this._loggingService.setLogHandler(this.settings.onLogMessage?this.settings.onLogMessage:R),s?this._httpService=s:this.settings.httpService?this._httpService=this.settings.httpService:this.settings.useAsynchronousCommits?(console.warn("WARNING: useAsynchronousCommits=true is not SCORM compliant. Commit failures will not be reported to the SCO, which may cause data loss. This setting should only be used for specific legacy compatibility cases."),this._httpService=new x(this.settings,this._error_codes)):this._httpService=new B(this.settings,this._error_codes),this._eventService=i||new $((e,t,s,i)=>this.apiLog(e,t,s,i)),this._serializationService=r||new k,this._errorHandlingService=o||new G(this._error_codes,(e,t,s,i)=>this.apiLog(e,t,s||O.ERROR,i),(e,t)=>this.getLmsErrorMessageDetails(e,t),void 0),this.settings.enableOfflineSupport&&(this._offlineStorageService=c||new P(this.settings,this._error_codes,(e,t,s,i)=>this.apiLog(e,t,s,i)),this.settings.courseId&&(this._courseId=this.settings.courseId),this.settings.syncOnTerminate&&this._eventService.on("BeforeTerminate",()=>{this._offlineStorageService?.isDeviceOnline()&&this._courseId&&this._offlineStorageService.hasPendingOfflineData(this._courseId).then(e=>{if(e)return this.apiLog("BeforeTerminate","Syncing pending offline data before termination",O.INFO),this._offlineStorageService?.syncOfflineData()}).then(e=>{e?this.processListeners("OfflineDataSynced"):!1===e&&this.processListeners("OfflineDataSyncFailed")}).catch(e=>{this.apiLog("BeforeTerminate","Error syncing offline data: "+e,O.ERROR),this.processListeners("OfflineDataSyncFailed")})}),this._offlineStorageService&&this._courseId&&this._offlineStorageService.getOfflineData(this._courseId).then(e=>{e&&(this.apiLog("constructor","Found offline data to restore",O.INFO),this.loadFromJSON(e.runtimeData))}).catch(e=>{this.apiLog("constructor","Error retrieving offline data: "+e,O.ERROR)})),this._cmiValueAccessService=new j({errorCodes:this._error_codes,getLastErrorCode:()=>this.lastErrorCode,setLastErrorCode:e=>{this.lastErrorCode=e},throwSCORMError:(e,t,s)=>this.throwSCORMError(e,t,s),isInitialized:()=>this.isInitialized(),validateCorrectResponse:(e,t)=>this.validateCorrectResponse(e,t),checkForDuplicateId:(e,t)=>this._checkForDuplicateId(e,t),getChildElement:(e,t,s)=>this.getChildElement(e,t,s),apiLog:(e,t,s)=>this.apiLog(e,t,s),checkObjectHasProperty:(e,t)=>this._checkObjectHasProperty(e,t),getDataModel:()=>this})}startingData;currentState;get lastErrorCode(){return this._errorHandlingService?.lastErrorCode??"0"}set lastErrorCode(e){this._errorHandlingService&&(this._errorHandlingService.lastErrorCode=e)}get eventService(){return this._eventService}get loggingService(){return this._loggingService}commonReset(e){this.apiLog("reset","Called",O.INFO),this.settings={...this.settings,...e},this.clearScheduledCommit(),this.currentState=0,this.lastErrorCode="0",this._eventService.reset(),this.startingData={},this._offlineStorageService&&(this._offlineStorageService.updateSettings(this.settings),e?.courseId&&(this._courseId=e.courseId))}initialize(e,t,s){let i=_;return this.isInitialized()?this.throwSCORMError("api",this._error_codes.INITIALIZED,t):this.isTerminated()?this.throwSCORMError("api",this._error_codes.TERMINATED,s):(this.settings.selfReportSessionTime&&this.cmi.setStartTime(),this.currentState=1,this.lastErrorCode="0",i=d,this.processListeners(e),this.settings.enableOfflineSupport&&this._offlineStorageService&&this._courseId&&this.settings.syncOnInitialize&&this._offlineStorageService.isDeviceOnline()&&this._offlineStorageService.hasPendingOfflineData(this._courseId).then(t=>{t&&(this.apiLog(e,"Syncing pending offline data on initialization",O.INFO),this._offlineStorageService?.syncOfflineData().then(t=>{t&&(this.apiLog(e,"Successfully synced offline data",O.INFO),this.processListeners("OfflineDataSynced"))}))})),this.apiLog(e,"returned: "+i,O.INFO),this.clearSCORMError(i),i}apiLog(e,t,s,i){t=function(e,t,s){let i=e?(e+"").padEnd(20)+": ":"";return s&&(i+=s,i=i.padEnd(70)),i+=t??"",i}(e,t,i),this._loggingService.log(s,t)}get settings(){return this._settings}set settings(e){const t=this._settings;this._settings={...this._settings,...e},this._httpService?.updateSettings(this._settings),void 0!==e.logLevel&&e.logLevel!==t.logLevel&&this._loggingService?.setLogLevel(e.logLevel),void 0!==e.onLogMessage&&e.onLogMessage!==t.onLogMessage&&this._loggingService?.setLogHandler(e.onLogMessage)}terminate(e,t){let s=d,i=!1;if(this.isNotInitialized()){const e=this._error_codes.TERMINATION_BEFORE_INIT??0;this.throwSCORMError("api",e),112===e&&(s=_)}else if(t&&this.isTerminated()){const e=this._error_codes.MULTIPLE_TERMINATION??0;this.throwSCORMError("api",e),113===e&&(s=_)}else{i=!0,this.processListeners("BeforeTerminate");const result=this.storeData(!0);if((result.errorCode??0)>0)result.errorMessage&&this.apiLog("terminate","Terminate failed with error: "+result.errorMessage,O.ERROR),result.errorDetails&&this.apiLog("terminate","Error details: "+JSON.stringify(result.errorDetails),O.DEBUG),this.throwSCORMError("api",result.errorCode??0),s=_;else{this.currentState=2,t&&(this.lastErrorCode="0");const e=result?.result??d;s="boolean"==typeof e?e+"":e}this.processListeners(e)}return this.apiLog(e,"returned: "+s,O.INFO),i&&this.clearSCORMError(s),s}getValue(e,t,s){let i="";if(this.checkState(t,this._error_codes.RETRIEVE_BEFORE_INIT??0,this._error_codes.RETRIEVE_AFTER_TERM??0)){try{i=this.getCMIValue(s)}catch(e){i=this.handleValueAccessException(s,e,i)}this.processListeners(e,s)}return this.apiLog(e,": returned: "+i,O.INFO,s),void 0===i?"":("0"===this.lastErrorCode&&this.clearSCORMError(i),i)}setValue(e,t,s,i,r){void 0!==r&&(r+="");let n=_;if(this.checkState(s,this._error_codes.STORE_BEFORE_INIT??0,this._error_codes.STORE_AFTER_TERM??0)){try{n=this.setCMIValue(i,r)}catch(e){n=this.handleValueAccessException(i,e,n)}this.processListeners(e,i,r)}return void 0===n&&(n=_),this.lastErrorCode+""=="0"&&this.settings.autocommit&&this.scheduleCommit(1e3*this.settings.autocommitSeconds,t),this.apiLog(e,": "+r+": result: "+n,O.INFO,i),"0"===this.lastErrorCode&&this.clearSCORMError(n),n}commit(e,t=!1){this.clearScheduledCommit();let s=d;if(this.isNotInitialized()){const e=this._error_codes.COMMIT_BEFORE_INIT??0;this.throwSCORMError("api",e),142===e&&(s=_)}else if(t&&this.isTerminated()){const e=this._error_codes.COMMIT_AFTER_TERM??0;this.throwSCORMError("api",e),143===e&&(s=_)}else{const result=this.storeData(!1),i=result.errorCode??0;i>0&&(result.errorMessage&&this.apiLog("commit","Commit failed with error: "+result.errorMessage,O.ERROR),result.errorDetails&&this.apiLog("commit","Error details: "+JSON.stringify(result.errorDetails),O.DEBUG),this.throwSCORMError("api",i));const r=result?.result??_;s="boolean"==typeof r?r+"":r,this.apiLog(e," Result: "+s,O.DEBUG,"HttpRequest"),t&&0===i&&(this.lastErrorCode="0"),this.processListeners(e),this.settings.enableOfflineSupport&&this._offlineStorageService&&this._offlineStorageService.isDeviceOnline()&&this._courseId&&this._offlineStorageService.hasPendingOfflineData(this._courseId).then(t=>{t&&(this.apiLog(e,"Syncing pending offline data",O.INFO),this._offlineStorageService?.syncOfflineData().then(t=>{t?(this.apiLog(e,"Successfully synced offline data",O.INFO),this.processListeners("OfflineDataSynced")):this.apiLog(e,"Failed to sync some offline data",O.WARN)}))})}return this.apiLog(e,"returned: "+s,O.INFO),this.isNotInitialized()||t&&this.isTerminated()||this.clearSCORMError(s),s}getLastError(e){const t=this.lastErrorCode+"";return this.processListeners(e),this.apiLog(e,"returned: "+t,O.INFO),t}getErrorString(e,t){let s="";return null!==t&&""!==t&&(s=this.getLmsErrorMessageDetails(t),this.processListeners(e)),s.length>255&&(s=s.substring(0,255)),this.apiLog(e,"returned: "+s,O.INFO),s}getDiagnostic(e,t){let s="";const i=""===t?this.lastErrorCode+"":t;if(null!==i&&""!==i){const t=this._errorHandlingService.lastDiagnostic;s=t&&i+""==this.lastErrorCode+""?t:this.getLmsErrorMessageDetails(i,!0),this.processListeners(e)}return s.length>255&&(s=s.substring(0,255)),this.apiLog(e,"returned: "+s,O.INFO),s}checkState(e,t,s){return this.isNotInitialized()?(this.throwSCORMError("api",t),!1):!e||!this.isTerminated()||(this.throwSCORMError("api",s),!1)}_checkForDuplicateId(e,t){const s=(e,t)=>{if(e&&"object"==typeof e&&t in e){const s=e[t];return s instanceof S?s:void 0}},i=(e,t,s)=>{for(let i=0;e.childArray.length>i;i++)if(i!==t){const t=e.childArray[i];if(t&&"object"==typeof t&&"id"in t&&t.id===s)return!0}return!1},r=e.match(/^cmi\.objectives\.(\d+)\.id$/);if(r&&r[1]){const e=parseInt(r[1],10),objectives=s(this.cmi,"objectives");return!!objectives&&i(objectives,e,t)}const n=e.match(/^cmi\.interactions\.(\d+)\.id$/);if(n&&n[1]){const e=parseInt(n[1],10),interactions=s(this.cmi,"interactions");return!!interactions&&i(interactions,e,t)}const o=e.match(/^cmi\.interactions\.(\d+)\.objectives\.(\d+)\.id$/);if(o&&o[1]&&o[2]){const e=parseInt(o[1],10),r=parseInt(o[2],10),interactions=s(this.cmi,"interactions");if(interactions){const n=interactions.childArray[e];if(n){const objectives=s(n,"objectives");if(objectives)return i(objectives,r,t)}}return!1}return!1}getLmsErrorMessageDetails(e,t=!1){throw Error("The getLmsErrorMessageDetails method has not been implemented")}getCMIValue(e){throw Error("The getCMIValue method has not been implemented")}setCMIValue(e,t){throw Error("The setCMIValue method has not been implemented")}_commonSetCMIValue(e,t,s,i){return this._cmiValueAccessService.setCMIValue(e,t,s,i)}_commonGetCMIValue(e,t,s){return this._cmiValueAccessService.getCMIValue(e,t,s)}isInitialized(){return 1===this.currentState}isNotInitialized(){return 0===this.currentState}isTerminated(){return 2===this.currentState}on(e,t){this._eventService.on(e,t)}off(e,t){this._eventService.off(e,t)}clear(e){this._eventService.clear(e)}processListeners(e,t,s){this._eventService.processListeners(e,t,s)}throwSCORMError(e,t,s){this._errorHandlingService.throwSCORMError(e,t??0,s)}clearSCORMError(e){this._errorHandlingService.clearSCORMError(e)}loadFromFlattenedJSON(e,t){t||(t=""),this._serializationService.loadFromFlattenedJSON(e,t,(e,t)=>this.setCMIValue(e,t),()=>this.isNotInitialized(),e=>{this.startingData=e})}getFlattenedCMI(){return i(this.renderCMIToJSONObject())}loadFromJSON(e,t=""){t&&""!==t||Object.hasOwnProperty.call(e,"cmi")||Object.hasOwnProperty.call(e,"adl")||(t="cmi"),this._serializationService.loadFromJSON(e,t,(e,t)=>this.setCMIValue(e,t),()=>this.isNotInitialized(),e=>{this.startingData=e})}renderCMIToJSONString(){return this._serializationService.renderCMIToJSONString(this.cmi,this.settings.sendFullCommit)}renderCMIToJSONObject(){return this._serializationService.renderCMIToJSONObject(this.cmi,this.settings.sendFullCommit)}processHttpRequest(e,t,s=!1){return this.settings.enableOfflineSupport&&this._offlineStorageService&&!this._offlineStorageService.isDeviceOnline()&&this._courseId?(this.apiLog("processHttpRequest","Device is offline, storing data locally",O.INFO),t&&"object"==typeof t&&"cmi"in t?this._offlineStorageService.storeOffline(this._courseId,t):(this.apiLog("processHttpRequest","Invalid commit data format for offline storage",O.ERROR),{result:_,errorCode:this._error_codes.GENERAL??101})):this._httpService.processHttpRequest(e,t,s,(e,t,s,i)=>this.apiLog(e,t,s,i),(e,t,s)=>this.processListeners(e,t,s))}scheduleCommit(e,t){this._timeout||(this._timeout=new b(this,e,t),this.apiLog("scheduleCommit","scheduled",O.DEBUG,""))}clearScheduledCommit(){this._timeout&&(this._timeout.cancel(),this._timeout=void 0,this.apiLog("clearScheduledCommit","cleared",O.DEBUG,""))}_checkObjectHasProperty(e,t){return null!=e&&"object"==typeof e&&(Object.hasOwnProperty.call(e,t)||null!=Object.getOwnPropertyDescriptor(Object.getPrototypeOf(e),t)||t in e)}handleValueAccessException(e,t,s){return t instanceof h?(this.lastErrorCode=t.errorCode+"",""!==s&&(s=_),this.throwSCORMError(e,t.errorCode,t.errorMessage)):this.throwSCORMError(e,this._error_codes.GENERAL,t instanceof Error&&t.message?t.message:"Unknown error"),s}getCommitObject(e){return this._serializationService.getCommitObject(e,this.settings.alwaysSendTotalTime,this.settings.renderCommonCommitFields,(e,t)=>this.renderCommitObject(e,t),(e,t)=>this.renderCommitCMI(e,t),this.settings.logLevel)}}class Q extends a{__children;__score_range;__invalid_error_code;__invalid_type_code;__invalid_range_code;__decimal_regex;__error_class;_raw="";_min="";_max;constructor(e){super(e.CMIElement),this.__children=e.score_children||u,this.__score_range=!!e.score_range&&T,this._max=e.max||""===e.max?e.max:"100",this.__invalid_error_code=e.invalidErrorCode||p.INVALID_SET_VALUE,this.__invalid_type_code=e.invalidTypeCode||p.TYPE_MISMATCH,this.__invalid_range_code=e.invalidRangeCode||p.VALUE_OUT_OF_RANGE,this.__decimal_regex=e.decimalRegex||M,this.__error_class=e.errorClass}reset(){this._initialized=!1,this._raw="",this._min=""}get _children(){return this.__children}set _children(_children){throw new this.__error_class(this._cmi_element+"._children",this.__invalid_error_code)}get raw(){return this._raw}set raw(e){W.validateScore(this._cmi_element+".raw",e,this.__decimal_regex,this.__score_range,this.__invalid_type_code,this.__invalid_range_code,this.__error_class)&&(this._raw=e)}get min(){return this._min}set min(e){W.validateScore(this._cmi_element+".min",e,this.__decimal_regex,this.__score_range,this.__invalid_type_code,this.__invalid_range_code,this.__error_class)&&(this._min=e)}get max(){return this._max}set max(e){W.validateScore(this._cmi_element+".max",e,this.__decimal_regex,this.__score_range,this.__invalid_type_code,this.__invalid_range_code,this.__error_class)&&(this._max=e)}getScoreObject(){const e={};return Number.isNaN(Number.parseFloat(this.raw))||(e.raw=Number.parseFloat(this.raw)),Number.isNaN(Number.parseFloat(this.min))||(e.min=Number.parseFloat(this.min)),Number.isNaN(Number.parseFloat(this.max))||(e.max=Number.parseFloat(this.max)),e}toJSON(){this.jsonString=!0;const result={raw:this.raw,min:this.min,max:this.max};return this.jsonString=!1,result}}class Z extends a{constructor(){super("cmi.core"),this.score=new Q({CMIElement:"cmi.core.score",score_children:u,score_range:T,invalidErrorCode:p.INVALID_SET_VALUE,invalidTypeCode:p.TYPE_MISMATCH,invalidRangeCode:p.VALUE_OUT_OF_RANGE,errorClass:f})}score;initialize(){super.initialize(),this.score?.initialize()}__children="student_id,student_name,lesson_location,credit,lesson_status,entry,score,total_time,lesson_mode,exit,session_time";_student_id="";_student_name="";_lesson_location="";_credit="";_lesson_status="not attempted";_entry="";_total_time="";_lesson_mode="normal";_exit="";_session_time="00:00:00";_suspend_data="";reset(){this._initialized=!1,this._exit="",this._entry="",this._session_time="00:00:00",this.score?.reset()}get _children(){return this.__children}set _children(_children){throw new f(this._cmi_element+"._children",p.INVALID_SET_VALUE)}get student_id(){return this._student_id}set student_id(student_id){if(this.initialized)throw new f(this._cmi_element+".student_id",p.READ_ONLY_ELEMENT);this._student_id=student_id}get student_name(){return this._student_name}set student_name(student_name){if(this.initialized)throw new f(this._cmi_element+".student_name",p.READ_ONLY_ELEMENT);this._student_name=student_name}get lesson_location(){return this._lesson_location}set lesson_location(lesson_location){J(this._cmi_element+".lesson_location",lesson_location,L,!0)&&(this._lesson_location=lesson_location)}get credit(){return this._credit}set credit(credit){if(this.initialized)throw new f(this._cmi_element+".credit",p.READ_ONLY_ELEMENT);J(this._cmi_element+".credit",credit,"^(credit|no-credit)$",!0)&&(this._credit=credit)}get lesson_status(){return this._lesson_status}set lesson_status(lesson_status){this.initialized?J(this._cmi_element+".lesson_status",lesson_status,"^(passed|completed|failed|incomplete|browsed)$")&&(this._lesson_status=lesson_status):J(this._cmi_element+".lesson_status",lesson_status,w)&&(this._lesson_status=lesson_status)}get entry(){return this._entry}set entry(entry){if(this.initialized)throw new f(this._cmi_element+".entry",p.READ_ONLY_ELEMENT);J(this._cmi_element+".entry",entry,"^(ab-initio|resume|)$",!0)&&(this._entry=entry)}get total_time(){return this._total_time}set total_time(total_time){if(this.initialized)throw new f(this._cmi_element+".total_time",p.READ_ONLY_ELEMENT);if(J(this._cmi_element+".total_time",total_time,y,!0))if(total_time){const s=t(total_time,y);this._total_time=e(s)}else