/*
    Copyright 2021 Rustici Software

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

        http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
*/
/*
 https://www.npmjs.com/package/@rusticisoftware/cmi5
 3.1.0
 */
!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.Cmi5=e():t.Cmi5=e()}(self,(function(){return(()=>{"use strict";var t={d:(e,n)=>{for(var r in n)t.o(n,r)&&!t.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:n[r]})},o:(t,e)=>Object.prototype.hasOwnProperty.call(t,e)},e={};t.d(e,{default:()=>v});const n="3.1.0",r="@rusticisoftware/cmi5",i="1.0.3",o="cmi5LearnerPreferences",a="Normal",s={id:"https://w3id.org/xapi/cmi5/context/categories/cmi5"},c={id:"https://w3id.org/xapi/cmi5/context/categories/moveon"},l={id:`http://id.tincanapi.com/activity/software/${r}/3.1.0`,definition:{name:{und:`${r} (3.1.0)`},description:{en:"A JavaScript library implementing the cmi5 specification for AUs during runtime."},type:"http://id.tincanapi.com/activitytype/source"}},h="https://w3id.org/xapi/cmi5/context/extensions/masteryscore",u="http://adlnet.gov/expapi/verbs/initialized",d="http://adlnet.gov/expapi/verbs/terminated",f="http://adlnet.gov/expapi/verbs/completed",m="http://adlnet.gov/expapi/verbs/passed",p="http://adlnet.gov/expapi/verbs/failed",w={[u]:{en:"initialized"},[d]:{en:"terminated"},[f]:{en:"completed"},[m]:{en:"passed"},[p]:{en:"failed"}},g=["endpoint","fetch","actor","activityId","registration"];function v(t){if(this.log("constructor",t),void 0!==t){const e=new URL(t).searchParams;this.log("params");for(let t=0;t<g.length;t+=1)if(!e.has(g[t]))throw new Error(`Invalid launch string missing or empty parameter: ${g[t]}`);this.setFetch(e.get("fetch")),this.setEndpoint(e.get("endpoint")),this.setActor(e.get("actor")),this.setActivityId(e.get("activityId")),this.setRegistration(e.get("registration"))}}return v.VERSION=n,v.DEBUG=!1,v.enableDebug=()=>{v.DEBUG=!0},v.disableDebug=()=>{v.DEBUG=!1},v.uuidv4=()=>([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g,(t=>(t^crypto.getRandomValues(new Uint8Array(1))[0]&15>>t/4).toString(16))),v.convertISO8601DurationToMilliseconds=t=>{const e=t.indexOf("-")>=0,n=t.indexOf("T"),r=t.indexOf("S");let i,o,a=t.indexOf("H"),s=t.indexOf("M");if(-1===n||-1!==s&&s<n||-1!==t.indexOf("D")||-1!==t.indexOf("Y"))throw new Error("ISO 8601 durations including years, months and/or days are not currently supported");-1===a?(a=n,i=0):i=parseInt(t.slice(n+1,a),10),-1===s?(s=n,o=0):o=parseInt(t.slice(a+1,s),10);const c=parseFloat(t.slice(s+1,r));let l=parseInt(1e3*(60*(60*i+o)+c),10);return isNaN(l)&&(l=0),e&&(l*=-1),l},v.convertMillisecondsToISO8601Duration=t=>{const e=parseInt(t,10);let n="PT",r=Math.round(e/10);r<0&&(n="-"+n,r*=-1);const i=parseInt(r/36e4,10),o=parseInt(r%36e4/6e3,10);return i>0&&(n+=i+"H"),o>0&&(n+=o+"M"),n+=r%36e4%6e3/100+"S",n},v.prototype={_fetch:null,_endpoint:null,_actor:null,_registration:null,_activityId:null,_auth:null,_fetchContent:null,_lmsLaunchData:null,_contextTemplate:null,_learnerPrefs:null,_isActive:!1,_initialized:null,_passed:null,_failed:null,_completed:null,_terminated:null,_durationStart:null,_progress:null,_includeSourceActivity:!0,start:async function(t={},e){this.log("start");try{await this.postFetch(),void 0!==t.postFetch&&await t.postFetch.apply(this),await this.loadLMSLaunchData(),void 0!==t.launchData&&await t.launchData.apply(this),await this.loadLearnerPrefs(),void 0!==t.learnerPrefs&&await t.learnerPrefs.apply(this),await this.initialize(e),void 0!==t.initializeStatement&&await t.initializeStatement.apply(this)}catch(t){throw new Error(`Failed to start AU: ${t}`)}},postFetch:async function(){if(this.log("postFetch"),null===this._fetch)throw new Error("Can't POST to fetch URL without setFetch");let t;try{t=await fetch(this._fetch,{mode:"cors",method:"POST"})}catch(t){throw new Error(`Failed to make fetch request: ${t}`)}if(!t.ok)throw new Error(`Post fetch response returned error: ${t.status}`);if(200===t.status){const e=await t.json();if(void 0!==e["auth-token"])return this._fetchContent=e,void this.setAuth(`Basic ${e["auth-token"]}`);throw new Error(`Post fetch response indicated LMS error: ${e["error-code"]}`)}throw new Error(`Post fetch response status code unexpected: ${t.status}`)},loadLMSLaunchData:async function(){if(this.log("loadLMSLaunchData"),null===this._fetchContent)throw new Error("Can't retrieve LMS Launch Data without successful postFetch");let t;try{t=await fetch(`${this._endpoint}/activities/state?`+new URLSearchParams({stateId:"LMS.LaunchData",activityId:this._activityId,agent:JSON.stringify(this._actor),registration:this._registration}),{mode:"cors",method:"get",headers:{"X-Experience-API-Version":i,Authorization:this._auth}})}catch(t){throw new Error(`Failed to GET LMS launch data: ${t}`)}this._lmsLaunchData=await t.json(),this._contextTemplate=JSON.stringify(this._lmsLaunchData.contextTemplate)},loadLearnerPrefs:async function(){if(this.log("loadLearnerPrefs"),null===this._lmsLaunchData)throw new Error("Can't retrieve Learner Preferences without successful loadLMSLaunchData");let t;try{t=await fetch(`${this._endpoint}/agents/profile?`+new URLSearchParams({profileId:o,agent:JSON.stringify(this._actor)}),{mode:"cors",method:"get",headers:{"X-Experience-API-Version":i,Authorization:this._auth}})}catch(t){throw new Error(`Failed request to retrieve learner preferences: ${t}`)}if(200!==t.status){if(404===t.status)return this.log("Learner Preferences request returned not found (expected)"),void(this._learnerPrefs={contents:{}});throw new Error("Failed to get learner preferences: unrecognized response status")}this._learnerPrefs={contents:await t.json(),etag:t.headers.ETag}},saveLearnerPrefs:async function(){if(this.log("saveLearnerPrefs"),null===this._learnerPrefs)throw new Error("Can't save Learner Preferences without first loading them");let t;try{t=await fetch(`${this._endpoint}/agents/profile?`+new URLSearchParams({profileId:o,agent:JSON.stringify(this._actor)}),{mode:"cors",method:"put",headers:{"X-Experience-API-Version":i,Authorization:this._auth,"Content-Type":"application/json",...this._learnerPrefs.etag?{"If-Match":this._learnerPrefs.etag}:{"If-None-Match":"*"}},body:JSON.stringify(this._learnerPrefs.contents)})}catch(t){throw new Error(`Failed request to save learner preferences: ${t}`)}if(403===t.status)return this.log("Save of learner preferences denied by LMS"),void(this._learnerPrefs.saveDisallowed=!0);if(204!==t.status)throw new Error(`Failed to save learner preferences: ${t.status}`);this._learnerPrefs.etag=t.headers.ETag},initialize:async function(t={}){if(this.log("initialize"),null===this._lmsLaunchData)throw new Error("Failed to initialize: can't send initialized statement without successful loadLMSLaunchData");if(null===this._learnerPrefs)throw new Error("Failed to initialize: can't send initialized statement without successful loadLearnerPrefs");if(this._initialized)throw new Error("Failed to initialize: AU already initialized");const e=this.initializedStatement();this._appendProvidedProperties(e,t);try{await this.sendStatement(e)}catch(t){throw new Error(`Failed to initialize: exception sending initialized statement (${t})`)}this._initialized=!0,this._isActive=!0,this._durationStart=(new Date).getTime()},terminate:async function(t={}){if(this.log("terminate"),!this._initialized)throw new Error("AU not initialized");if(this._terminated)throw new Error("AU already terminated");const e=this.terminatedStatement();this._appendProvidedProperties(e,t);try{await this.sendStatement(e)}catch(t){throw new Error(`Failed to terminate: exception sending terminated statement (${t})`)}this._terminated=!0,this._isActive=!1},completed:async function(t={}){if(this.log("completed"),!this.isActive())throw new Error("AU not active");if(this.getLaunchMode()!==a)throw new Error("AU not in Normal launch mode");if(this._completed)throw new Error("AU already completed");const e=this.completedStatement();this._appendProvidedProperties(e,t);try{await this.sendStatement(e)}catch(t){throw new Error(`Failed to send completed statement: ${t}`)}this.setProgress(null),this._completed=!0},passed:async function(t){if(this.log("passed"),!this.isActive())throw new Error("AU not active");if(this.getLaunchMode()!==a)throw new Error("AU not in Normal launch mode");if(null!==this._passed)throw new Error("AU already passed");let e;try{e=this.passedStatement(t)}catch(t){throw new Error(`Failed to create passed statement: ${t}`)}try{await this.sendStatement(e)}catch(t){throw new Error(`Failed to send passed statement: ${t}`)}this._passed=!0},failed:async function(t){if(this.log("failed"),!this.isActive())throw new Error("AU not active");if(this.getLaunchMode()!==a)throw new Error("AU not in Normal launch mode");if(null!==this._failed||null!==this._passed)throw new Error("AU already passed/failed");let e;try{e=this.failedStatement(t)}catch(t){throw new Error(`Failed to create failed statement: ${t}`)}try{await this.sendStatement(e)}catch(t){throw new Error(`Failed to send failed statement: ${t}`)}this._failed=!0},isActive:function(){return this.log("isActive"),this._isActive},log:function(){v.DEBUG&&"undefined"!=typeof console&&console.log&&(arguments[0]="cmi5.js:"+arguments[0],console.log.apply(console,arguments))},includeSourceActivity:function(t){this._includeSourceActivity=!!t},getLaunchMode:function(){if(this.log("getLaunchMode"),null===this._lmsLaunchData)throw new Error("Can't determine launchMode until LMS LaunchData has been loaded");return this._lmsLaunchData.launchMode},getLaunchParameters:function(){if(this.log("getLaunchParameters"),null===this._lmsLaunchData)throw new Error("Can't determine LaunchParameters until LMS LaunchData has been loaded");let t=null;return void 0!==this._lmsLaunchData.launchParameters&&(t=this._lmsLaunchData.launchParameters),t},getSessionId:function(){if(this.log("getSessionId"),null===this._lmsLaunchData)throw new Error("Can't determine session id until LMS LaunchData has been loaded");return this._lmsLaunchData.contextTemplate.extensions["https://w3id.org/xapi/cmi5/context/extensions/sessionid"]},getMoveOn:function(){if(this.log("getMoveOn"),null===this._lmsLaunchData)throw new Error("Can't determine moveOn until LMS LaunchData has been loaded");return this._lmsLaunchData.moveOn},getMasteryScore:function(){if(this.log("getMasteryScore"),null===this._lmsLaunchData)throw new Error("Can't determine masteryScore until LMS LaunchData has been loaded");let t=null;return void 0!==this._lmsLaunchData.masteryScore&&(t=this._lmsLaunchData.masteryScore),t},getReturnURL:function(){if(this.log("getReturnURL"),null===this._lmsLaunchData)throw new Error("Can't determine returnURL until LMS LaunchData has been loaded");let t=null;return void 0!==this._lmsLaunchData.returnURL&&(t=this._lmsLaunchData.returnURL),t},getEntitlementKey:function(){if(this.log("getEntitlementKey"),null===this._lmsLaunchData)throw new Error("Can't determine entitlementKey until LMS LaunchData has been loaded");let t=null;return void 0!==this._lmsLaunchData.entitlementKey&&(void 0!==this._lmsLaunchData.entitlementKey.alternate?t=this._lmsLaunchData.entitlementKey.alternate:void 0!==this._lmsLaunchData.entitlementKey.courseStructure&&(t=this._lmsLaunchData.entitlementKey.courseStructure)),t},getLanguagePreference:function(){if(this.log("getLanguagePreference"),null===this._learnerPrefs)throw new Error("Can't determine language preference until learner preferences have been loaded");let t=null;return void 0!==this._learnerPrefs.contents.languagePreference&&(t=this._learnerPrefs.contents.languagePreference),t},setLanguagePreference:function(t){if(this.log("setLanguagePreference"),null===this._learnerPrefs)throw new Error("Can't set language preference until learner preferences have been loaded");""===t&&(t=null),this._learnerPrefs.contents.languagePreference=t},getAudioPreference:function(){if(this.log("getAudioPreference"),null===this._learnerPrefs)throw new Error("Can't determine audio preference until learner preferences have been loaded");let t=null;return void 0!==this._learnerPrefs.contents.audioPreference&&(t=this._learnerPrefs.contents.audioPreference),t},setAudioPreference:function(t){if(this.log("setAudioPreference"),null===this._learnerPrefs)throw new Error("Can't set audio preference until learner preferences have been loaded");if("on"!==t&&"off"!==t&&null!==t)throw new Error(`Unrecognized value for audio preference: ${t}`);this._learnerPrefs.contents.audioPreference=t},getDuration:function(){return this.log("getDuration"),(new Date).getTime()-this._durationStart},setProgress:function(t){if(this.log("setProgress: ",t),null!==t){if(!Number.isInteger(t))throw new Error(`Invalid progress measure (not an integer): ${t}`);if(t<0||t>100)throw new Error(`Invalid progress measure must be greater than or equal to 0 and less than or equal to 100: ${t}`)}this._progress=t},getProgress:function(){return this.log("getProgress"),this._progress},setEndpoint:function(t){this.log("setEndpoint: ",t),this._endpoint=t},getEndpoint:function(){return this._endpoint},setAuth:function(t){this.log("setAuth: ",t),this._auth=t},getAuth:function(){return this._auth},setFetch:function(t){this.log("setFetch: ",t),this._fetch=t},getFetch:function(){return this._fetch},setActor:function(t){if(this.log("setActor",t),"string"==typeof t)try{t=JSON.parse(t)}catch(t){throw new Error(`Invalid actor: failed to parse string as JSON (${t})`)}if(void 0===t.account)throw new Error("Invalid actor: account is missing");if(void 0===t.account.name)throw new Error("Invalid actor: account name is missing");if(""===t.account.name)throw new Error("Invalid actor: account name is empty");if(void 0===t.account.homePage)throw new Error("Invalid actor: account homePage is missing");if(""===t.account.homePage)throw new Error("Invalid actor: account homePage is empty");this._actor=t},getActor:function(){return this._actor},setActivityId:function(t){if(this.log("setActivityId",t),void 0===t)throw new Error("Invalid activityId: argument missing");if(""===t)throw new Error("Invalid activityId: empty string");this._activityId=t},getActivityId:function(){return this._activityId},setRegistration:function(t){if(this.log("setRegistration",t),null===t)throw new Error("Invalid registration: null");if(""===t)throw new Error("Invalid registration: empty");this._registration=t},getRegistration:function(){return this._registration},validateScore:function(t){if(null==t)throw new Error(`cannot validate score (score not provided): ${t}`);if(void 0!==t.min&&!Number.isInteger(t.min))throw new Error("score.min is not an integer");if(void 0!==t.max&&!Number.isInteger(t.max))throw new Error("score.max is not an integer");if(void 0!==t.scaled){if(!/^(-|\+)?[01]+(\.[0-9]+)?$/.test(t.scaled))throw new Error(`scaled score not a recognized number: ${t.scaled}`);if(t.scaled<0)throw new Error("scaled score must be greater than or equal to 0");if(t.scaled>1)throw new Error("scaled score must be less than or equal to 1")}if(void 0!==t.raw){if(!Number.isInteger(t.raw))throw new Error("score.raw is not an integer");if(void 0===t.min)throw new Error("minimum score must be provided when including a raw score");if(void 0===t.max)throw new Error("maximum score must be provided when including a raw score");if(t.raw<t.min)throw new Error("raw score must be greater than or equal to minimum score");if(t.raw>t.max)throw new Error("raw score must be less than or equal to maximum score")}return!0},prepareStatement:function(t){const e={id:v.uuidv4(),timestamp:(new Date).toISOString(),actor:this._actor,verb:{id:t},object:{id:this._activityId},context:this._prepareContext()},n=this.getProgress();return void 0!==w[t]&&(e.verb.display=w[t]),t!==f&&null!==n&&(e.result={extensions:{"https://w3id.org/xapi/cmi5/result/extensions/progress":n}}),e},sendStatement:async function(t){let e;this.log("sendStatement",t),void 0===t.id&&(t.id=v.uuidv4());try{e=await fetch(`${this._endpoint}/statements?`+new URLSearchParams({statementId:t.id}),{mode:"cors",method:"put",headers:{"X-Experience-API-Version":i,Authorization:this._auth,"Content-Type":"application/json"},body:JSON.stringify(t)})}catch(t){throw new Error(`Failed request to send statement: ${t}`)}if(204!==e.status)throw new Error(`Failed to send statement: status code ${e.status}`)},sendStatements:async function(t){let e;this.log("sendStatements",t),t.forEach((t=>{void 0===t.id&&(t.id=v.uuidv4())}));try{e=await fetch(`${this._endpoint}/statements`,{mode:"cors",method:"post",headers:{"X-Experience-API-Version":i,Authorization:this._auth,"Content-Type":"application/json"},body:JSON.stringify(t)})}catch(t){throw new Error(`Failed request to send statements: ${t}`)}if(204!==e.status)throw new Error(`Failed to send statements: status code ${e.status}`)},initializedStatement:function(){return this.log("initializedStatement"),this._prepareStatement(u)},terminatedStatement:function(){this.log("terminatedStatement");const t=this._prepareStatement(d);return t.result=t.result||{},t.result.duration=v.convertMillisecondsToISO8601Duration(this.getDuration()),t},passedStatement:function(t){this.log("passedStatement");const e=this._prepareStatement(m);if(e.result=e.result||{},e.result.success=!0,e.result.duration=v.convertMillisecondsToISO8601Duration(this.getDuration()),t){try{this.validateScore(t)}catch(t){throw new Error(`Invalid score: ${t}`)}const n=this.getMasteryScore();if(null!==n&&void 0!==t.scaled){if(t.scaled<n)throw new Error(`Invalid score: scaled score does not meet or exceed mastery score (${t.scaled} < ${n})`);e.context.extensions=e.context.extensions||{},e.context.extensions[h]=n}e.result.score=t}return e.context.contextActivities.category.push(c),e},failedStatement:function(t){this.log("failedStatement");const e=this._prepareStatement(p);if(e.result=e.result||{},e.result.success=!1,e.result.duration=v.convertMillisecondsToISO8601Duration(this.getDuration()),t){try{this.validateScore(t)}catch(t){throw new Error(`Invalid score: ${t}`)}const n=this.getMasteryScore();if(null!==n&&void 0!==t.scaled){if(t.scaled>=n)throw new Error(`Invalid score: scaled score exceeds mastery score (${t.scaled} >= ${n})`);e.context.extensions=e.context.extensions||{},e.context.extensions[h]=n}e.result.score=t}return e.context.contextActivities.category.push(c),e},completedStatement:function(){this.log("completedStatement");const t=this._prepareStatement(f);return t.result=t.result||{},t.result.completion=!0,t.result.duration=v.convertMillisecondsToISO8601Duration(this.getDuration()),t.context.contextActivities.category.push(c),t},_prepareContext:function(){const t=JSON.parse(this._contextTemplate);return t.registration=this._registration,this._includeSourceActivity&&(t.contextActivities=t.contextActivities||{},t.contextActivities.other=t.contextActivities.other||[],t.contextActivities.other.push(l)),t},_prepareStatement:function(t){const e=this.prepareStatement(t);return e.context.contextActivities=e.context.contextActivities||{},e.context.contextActivities.category=e.context.contextActivities.category||[],e.context.contextActivities.category.push(s),e},_appendProvidedProperties:function(t,e){if(void 0!==e.context&&void 0!==e.context.extensions)for(const n in e.context.extensions)e.context.extensions.hasOwnProperty(n)&&(t.context.extensions[n]=e.context.extensions[n]);if(void 0!==e.result&&(t.result=t.result||{},t.result.extensions=t.result.extensions||{},void 0!==e.result.extensions))for(const n in e.result.extensions)e.result.extensions.hasOwnProperty(n)&&(t.result.extensions[n]=e.result.extensions[n]);void 0!==e.object&&void 0!==e.object.definition&&(t.object.definition=t.object.definition||{},void 0!==e.object.definition.type&&(t.object.definition.type=e.object.definition.type))}},e.default})()}));
//# sourceMappingURL=cmi5.min.js.map
