jclic 2.2.1 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -7
- package/dist-node/jclic-node.js +14157 -0
- package/dist-node/jclic-node.umd.cjs +530 -0
- package/package.json +38 -26
- package/.vscode/launch.json +0 -33
- package/.vscode/settings.json +0 -13
- package/CHANGELOG.md +0 -672
- package/TRANSLATIONS.md +0 -11
- package/build-locales.mjs +0 -82
- package/dist/jclic-node.js +0 -31680
- package/dist/jclic-node.js.map +0 -1
- package/dist/jclic.components.LICENSE +0 -2254
- package/dist/jclic.min.js +0 -27
- package/dist/jclic.min.js.map +0 -1
- package/eslint.config.mjs +0 -31
- package/jsdoc.config.js +0 -71
- package/locales/ar.po +0 -244
- package/locales/ast.po +0 -246
- package/locales/bs.po +0 -247
- package/locales/ca.po +0 -248
- package/locales/ca_ES@valencia.po +0 -248
- package/locales/cs.po +0 -244
- package/locales/da.po +0 -244
- package/locales/de.po +0 -246
- package/locales/el.po +0 -244
- package/locales/es.po +0 -248
- package/locales/eu.po +0 -244
- package/locales/fr.po +0 -244
- package/locales/gl.po +0 -244
- package/locales/he.po +0 -244
- package/locales/hr.po +0 -245
- package/locales/it.po +0 -246
- package/locales/ja.po +0 -242
- package/locales/jclic.js.pot +0 -241
- package/locales/nb_NO.po +0 -244
- package/locales/nl.po +0 -244
- package/locales/pl.po +0 -244
- package/locales/pt.po +0 -244
- package/locales/pt_BR.po +0 -248
- package/locales/ro.po +0 -248
- package/locales/ru.po +0 -245
- package/locales/ta.po +0 -244
- package/locales/tr.po +0 -246
- package/locales/uk.po +0 -247
- package/locales/vec.po +0 -244
- package/locales/zh_TW.po +0 -246
- package/patches/po2json+1.0.0-beta-3.patch +0 -12
- package/src/AWT.js +0 -2067
- package/src/Activity.js +0 -1311
- package/src/Deps.js +0 -232
- package/src/GlobalData.js +0 -5
- package/src/JClic.js +0 -196
- package/src/JClicPlayer.js +0 -1308
- package/src/PlayerHistory.js +0 -305
- package/src/Utils.js +0 -1355
- package/src/activities/associations/ComplexAssociation.js +0 -321
- package/src/activities/associations/SimpleAssociation.js +0 -519
- package/src/activities/memory/MemoryGame.js +0 -423
- package/src/activities/panels/Explore.js +0 -349
- package/src/activities/panels/Identify.js +0 -356
- package/src/activities/panels/InformationScreen.js +0 -262
- package/src/activities/panels/Menu.js +0 -209
- package/src/activities/panels/icons/ico00.png +0 -0
- package/src/activities/panels/icons/ico01.png +0 -0
- package/src/activities/panels/icons/ico02.png +0 -0
- package/src/activities/panels/icons/ico03.png +0 -0
- package/src/activities/panels/icons/icofolder.png +0 -0
- package/src/activities/puzzles/DoublePuzzle.js +0 -424
- package/src/activities/puzzles/ExchangePuzzle.js +0 -374
- package/src/activities/puzzles/HolePuzzle.js +0 -360
- package/src/activities/text/Complete.js +0 -127
- package/src/activities/text/Evaluator.js +0 -534
- package/src/activities/text/FillInBlanks.js +0 -426
- package/src/activities/text/IdentifyText.js +0 -253
- package/src/activities/text/OrderText.js +0 -421
- package/src/activities/text/TextActivityBase.js +0 -557
- package/src/activities/text/TextActivityDocument.js +0 -660
- package/src/activities/text/WrittenAnswer.js +0 -557
- package/src/activities/textGrid/CrossWord.js +0 -565
- package/src/activities/textGrid/WordSearch.js +0 -458
- package/src/activities/textGrid/icons/hIcon.svg +0 -3
- package/src/activities/textGrid/icons/vIcon.svg +0 -3
- package/src/automation/AutoContentProvider.js +0 -182
- package/src/automation/arith/Arith.js +0 -864
- package/src/bags/ActivitySequence.js +0 -318
- package/src/bags/ActivitySequenceElement.js +0 -161
- package/src/bags/ActivitySequenceJump.js +0 -140
- package/src/bags/ConditionalJumpInfo.js +0 -113
- package/src/bags/JumpInfo.js +0 -136
- package/src/bags/MediaBag.js +0 -215
- package/src/bags/MediaBagElement.js +0 -516
- package/src/boxes/AbstractBox.js +0 -699
- package/src/boxes/ActiveBagContent.js +0 -494
- package/src/boxes/ActiveBox.js +0 -810
- package/src/boxes/ActiveBoxBag.js +0 -357
- package/src/boxes/ActiveBoxContent.js +0 -484
- package/src/boxes/ActiveBoxGrid.js +0 -179
- package/src/boxes/BoxBag.js +0 -500
- package/src/boxes/BoxBase.js +0 -398
- package/src/boxes/BoxConnector.js +0 -325
- package/src/boxes/TextGrid.js +0 -887
- package/src/boxes/TextGridContent.js +0 -215
- package/src/init-jsdom.js +0 -65
- package/src/jclic-node.js +0 -219
- package/src/media/ActiveMediaBag.js +0 -145
- package/src/media/ActiveMediaPlayer.js +0 -297
- package/src/media/AudioBuffer.js +0 -219
- package/src/media/EventSounds.js +0 -169
- package/src/media/EventSoundsElement.js +0 -155
- package/src/media/MediaContent.js +0 -328
- package/src/media/MidiAudioPlayer.js +0 -254
- package/src/media/icons/audio.svg +0 -3
- package/src/media/icons/generic.svg +0 -3
- package/src/media/icons/mic.svg +0 -3
- package/src/media/icons/movie.svg +0 -3
- package/src/media/icons/music.svg +0 -3
- package/src/media/icons/url.svg +0 -3
- package/src/media/sounds/actionError.mp3 +0 -0
- package/src/media/sounds/actionOk.mp3 +0 -0
- package/src/media/sounds/click.mp3 +0 -0
- package/src/media/sounds/finishedError.mp3 +0 -0
- package/src/media/sounds/finishedOk.mp3 +0 -0
- package/src/media/sounds/start.mp3 +0 -0
- package/src/project/JClicProject.js +0 -282
- package/src/project/ProjectSettings.js +0 -273
- package/src/report/ActionReg.js +0 -123
- package/src/report/ActivityReg.js +0 -271
- package/src/report/EncryptMin.js +0 -210
- package/src/report/Reporter.js +0 -727
- package/src/report/SCORM.js +0 -272
- package/src/report/SequenceReg.js +0 -275
- package/src/report/SessionReg.js +0 -340
- package/src/report/SessionStorageReporter.js +0 -131
- package/src/report/TCPReporter.js +0 -628
- package/src/shapers/ClassicJigSaw.js +0 -138
- package/src/shapers/Holes.js +0 -77
- package/src/shapers/JigSaw.js +0 -161
- package/src/shapers/Rectangular.js +0 -78
- package/src/shapers/Shaper.js +0 -386
- package/src/shapers/TriangularJigSaw.js +0 -121
- package/src/skins/BlueSkin.js +0 -80
- package/src/skins/Counter.js +0 -152
- package/src/skins/CustomSkin.js +0 -412
- package/src/skins/DefaultSkin.js +0 -376
- package/src/skins/EmptySkin.js +0 -82
- package/src/skins/GreenSkin.js +0 -94
- package/src/skins/MiniSkin.js +0 -130
- package/src/skins/OrangeSkin.js +0 -78
- package/src/skins/SimpleSkin.js +0 -92
- package/src/skins/Skin.js +0 -1021
- package/src/skins/assets/actionsIcon.svg +0 -3
- package/src/skins/assets/appLogo.svg +0 -8
- package/src/skins/assets/basic.css +0 -41
- package/src/skins/assets/closeDialogIcon.svg +0 -3
- package/src/skins/assets/closeIcon.svg +0 -3
- package/src/skins/assets/copyIcon.svg +0 -3
- package/src/skins/assets/fullScreenExitIcon.svg +0 -3
- package/src/skins/assets/fullScreenIcon.svg +0 -3
- package/src/skins/assets/infoIcon.svg +0 -3
- package/src/skins/assets/main.css +0 -43
- package/src/skins/assets/mainHalf.css +0 -23
- package/src/skins/assets/mainTwoThirds.css +0 -23
- package/src/skins/assets/mini.css +0 -15
- package/src/skins/assets/nextIcon.svg +0 -3
- package/src/skins/assets/okDialogIcon.svg +0 -3
- package/src/skins/assets/prevIcon.svg +0 -3
- package/src/skins/assets/reports.css +0 -156
- package/src/skins/assets/reportsIcon.svg +0 -3
- package/src/skins/assets/scoreIcon.svg +0 -3
- package/src/skins/assets/simple.css +0 -16
- package/src/skins/assets/simpleHalf.css +0 -11
- package/src/skins/assets/simpleTwoThirds.css +0 -11
- package/src/skins/assets/timeIcon.svg +0 -4
- package/src/skins/assets/waitAnim.css +0 -54
- package/src/skins/assets/waitImgBig.svg +0 -3
- package/src/skins/assets/waitImgSmall.svg +0 -3
- package/webpack.config.mjs +0 -169
package/dist/jclic-node.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"jclic-node.js","mappings":";;UAAA;UACA;;;;;WCDA;WACA;WACA;WACA;WACA;WACA,iCAAiC,WAAW;WAC5C;WACA,E;;;;;WCPA;WACA;WACA;WACA;WACA,yCAAyC,wCAAwC;WACjF;WACA;WACA,E;;;;;WCPA,wF;;;;;;;;;;;;ACAA,MAAM,8BAA4B,oB;;;ACAlC,MAAM,sBAA4B,6B;;ACAlC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAE0B;AACiB;;AAE3C;AACA,gBAAgB,gCAAW,gDAAgD,4BAA4B;;AAEvG;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,2BAA2B,gCAAS;;AAEpC;AACA,iDAAe,EAAE,EAAC;;;AChElB,MAAM,+BAA4B,qB;;;ACAlC,MAAM,8BAA4B,oB;;;ACAlC,MAAM,oCAA4B,0B;;;;ACClC;AACA;;AAEA,iDAAe,CAAC,sOAAsO,MAAM,y9DAAy9D,QAAQ,k/DAAk/D,OAAO,qgEAAqgE,OAAO,ynEAAynE,mBAAmB,0mEAA0mE,OAAO,y+DAAy+D,OAAO,o/DAAo/D,OAAO,q/DAAq/D,OAAO,+oEAA+oE,OAAO,qrEAAqrE,OAAO,+jEAA+jE,OAAO,2pEAA2pE,OAAO,6lEAA6lE,OAAO,y6DAAy6D,OAAO,ojEAAojE,OAAO,8hEAA8hE,OAAO,wpDAAwpD,UAAU,gjEAAgjE,OAAO,2gEAA2gE,OAAO,6jEAA6jE,OAAO,8lEAA8lE,UAAU,4nEAA4nE,OAAO,kmEAAkmE,OAAO,2gEAA2gE,OAAO,+pEAA+pE,OAAO,0gEAA0gE,OAAO,imEAAimE,QAAQ,o+DAAo+D,UAAU,msDAAmsD,E;;ACJ1t2D;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEuB;AACG;AACW;AACI;;AAEzC;AACA;AACA,kDAAkD,yBAAyB;AAC3E,WAAW;AACX;AACO;AACP,GAAG;AACH,OAAO;AACP,YAAY;AACZ;;AAEA;AACA;AACA,WAAW;AACX;AACO;;AAEP;AACA;AACA,WAAW;AACX;AACO;;AAEP;AACA;AACA,UAAU,QAAQ;AACX;AACP;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA,WAAW,QAAQ;AACnB,WAAW,SAAS;AACpB,WAAW,SAAS;AACpB,aAAa,QAAQ;AACrB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,uCAAuC,UAAU;AACjD,6BAA6B,8BAA8B,aAAa,UAAU,SAAS,IAAI;AAC/F,kCAAkC,EAAE,UAAU;AAC9C;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,QAAQ;AACnB,aAAa,QAAQ;AACrB;AACO;AACP;AACA;;AAEA;AACA;AACA;AACA;AACA,WAAW,QAAQ;AACnB;AACA;AACO;AACP,0EAA0E,IAAI,gBAAgB,EAAE;AAChG;AACA,SAAS,uBAAuB,EAAE,cAAc,sBAAsB,OAAO,EAAE,cAAc,sBAAsB,OAAO;AAC1H;AACA;;AAEA;AACA;AACA;AACA,WAAW,UAAU;AACrB,WAAW,QAAQ;AACnB,WAAW,QAAQ;AACnB,aAAa,QAAQ;AACrB;AACO;AACP;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA,kBAAkB,kBAAkB;AACpC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,WAAW,QAAQ,qCAAqC;AACxD;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA,WAAW,QAAQ;AACnB,WAAW,QAAQ;AACnB,2BAA2B,mEAAmE;AAC9F;AACO;AACP;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,yBAAyB,0BAA0B,EAAE,yBAAyB,EAAE,4CAA4C,EAAE,IAAI;AAClI;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,WAAW,QAAQ;AACnB,WAAW,SAAS;AACpB,aAAa;AACb;AACO;AACP;AACA;;AAEA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa;AACb;AACO;AACP;AACA;;AAEA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,QAAQ;AACnB,aAAa;AACb;AACO;AACP;AACA;;AAEA;AACA;AACA,WAAW,QAAQ;AACnB,aAAa;AACb;AACO;AACP,YAAY,sBAAsB;AAClC;;AAEA;AACA;AACA;AACA,WAAW,QAAQ;AACnB,aAAa;AACb;AACO;AACP,aAAa,IAAI;AACjB;;AAEA;AACA;AACA,WAAW,QAAQ;AACnB,aAAa;AACb;AACO;AACP;AACA;AACA,YAAY,kBAAkB,EAAE,2BAA2B,EAAE,MAAM;AACnE;;AAEA;AACA;AACA,WAAW,eAAe;AAC1B,aAAa;AACb;AACO;AACP,YAAY,mBAAmB,GAAG,wBAAwB,GAAG,oBAAoB,EAAE,oBAAoB,GAAG,sBAAsB,GAAG,sBAAsB;AACzJ;;AAEA;AACA;AACA;AACA,WAAW,QAAQ;AACnB,aAAa,eAAe;AAC5B;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wCAAwC,EAAE,GAAG,EAAE,GAAG,EAAE;AACpD;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,QAAQ;AACnB,aAAa,QAAQ;AACrB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,YAAY,QAAQ;AACb;;AAEP,YAAY,QAAQ;AACb;;AAEP,YAAY,QAAQ;AACb;;AAEP;AACA;AACA,WAAW,QAAQ;AACnB,WAAW,KAAK;AAChB,aAAa;AACb;AACO;AACP;AACA;;AAEA;AACA;AACA,WAAW,QAAQ;AACnB,WAAW,QAAQ;AACnB,aAAa;AACb;AACO;AACP;AACA;;AAEA;AACA;AACA,WAAW,KAAK;AAChB,aAAa;AACb;AACO;AACP;AACA;;AAEA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,KAAK;AAChB,aAAa;AACb;AACO;AACP;AACA;;AAEA;AACA;AACA,WAAW,QAAQ;AACnB,aAAa;AACb;AACO;AACP;AACA,EAAE,yBAAC,0CAA0C,cAAc,kBAAkB,QAAQ;AACrF;AACA;;AAEA;AACA;AACA,WAAW,QAAQ;AACnB,WAAW,SAAS;AACpB,aAAa;AACb;AACO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,QAAQ;AACnB,aAAa;AACb;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,IAAI,QAAQ,aAAa,KAAK,oBAAoB,IAAI,mBAAmB;AACzE,WAAW,QAAQ;AACnB,aAAa,QAAQ;AACrB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,QAAQ;AACnB,aAAa;AACb;AACO;AACP,mDAAmD,EAAE,EAAE,IAAI,GAAG,aAAa;AAC3E;;AAEA;AACA;AACA,WAAW,QAAQ;AACnB,WAAW,QAAQ;AACnB,aAAa;AACb;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA,oBAAoB,oCAAoC,GAAG,oCAAoC,GAAG,oCAAoC,GAAG,MAAM;AAC/I;AACA;AACA;;AAEA;AACA;AACA,WAAW,QAAQ;AACnB,aAAa;AACb;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,QAAQ;AACnB,aAAa;AACb;AACA;AACO;AACP,SAAS,gCAAQ;AACjB;;AAEA;AACA;AACA,WAAW,QAAQ;AACnB,aAAa,QAAQ;AACrB;AACO;AACP;AACA;AACA,IAAI,8BAAM;AACV;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;;AAEA;AACA;AACA;AACA;AACA,WAAW,QAAQ;AACnB,WAAW,UAAU;AACrB;AACA;AACA,aAAa;AACb;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,WAAW,KAAK;AAChB,aAAa;AACb;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,WAAW,KAAK;AAChB,aAAa,SAAS,sBAAsB;AAC5C;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,WAAW,QAAQ;AACnB,WAAW,QAAQ;AACnB,WAAW,UAAU;AACrB;AACA;AACA;AACA,oCAAoC,QAAQ;AAC5C,oCAAoC,UAAU;AAC9C,wCAAwC,UAAU;AAClD,uCAAuC,QAAQ;AAC/C;AACA,sCAAsC,QAAQ;AAC9C;AACA;AACA,aAAa,QAAQ;AACrB;AACO;AACP;AACA;AACA,cAAc,+BAA+B;AAC7C;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,IAAI;AACf;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA,GAAG;AACH;AACA;;AAEA;AACA;AACA;AACA,WAAW,UAAU;AACrB,WAAW,QAAQ;AACnB,WAAW,KAAK;AAChB,WAAW,UAAU;AACrB,aAAa,QAAQ;AACrB;AACO;AACP;AACA;;AAEA;AACA;AACA,WAAW,QAAQ;AACnB,aAAa;AACb;AACO;AACP;AACA;;AAEA;AACA;AACA,WAAW,QAAQ;AACnB,aAAa;AACb;AACO;AACP;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM,yBAAyB;AAC/B,MAAM,yBAAyB;AAC/B,MAAM,uBAAuB;AAC7B,MAAM,oBAAoB;AAC1B,MAAM,qBAAqB;AAC3B;AACA,WAAW,GAAG;AACd,aAAa;AACb;AACO;AACP;AACA,gBAAgB;AAChB;AACA,kBAAkB,gBAAgB;AAClC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;AACA,kBAAkB;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,WAAW,QAAQ;AACnB,WAAW,QAAQ;AACnB,aAAa;AACb;AACO;AACP;AACA;;AAEA;AACA;AACA,WAAW,KAAK;AAChB,WAAW,QAAQ;AACnB,aAAa,KAAK;AAClB;AACO;AACP;AACA;;AAEA;AACA;AACA;AACA,WAAW,QAAQ;AACnB,WAAW,QAAQ;AACnB,WAAW,SAAS;AACpB,WAAW,SAAS;AACpB,aAAa;AACb;AACO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,WAAW,QAAQ;AACnB,WAAW,QAAQ;AACnB,WAAW,SAAS;AACpB,aAAa;AACb;AACO;AACP;AACA;;AAEA;AACA;AACA,WAAW,QAAQ;AACnB,WAAW,QAAQ;AACnB,WAAW,SAAS;AACpB,aAAa;AACb;AACO;AACP;AACA;;AAEA;AACA;AACA;AACA,WAAW,QAAQ;AACnB,aAAa;AACb;AACO;AACP;AACA;;AAEA;AACA;AACA,WAAW,QAAQ;AACnB,aAAa;AACb;AACO;AACP;AACA;;AAEA;AACA;AACA;AACA,WAAW,QAAQ;AACnB,aAAa;AACb;AACO;AACP;AACA;AACA;;AAEA;AACA;AACA,WAAW,QAAQ;AACnB,WAAW,QAAQ;AACnB,aAAa;AACb;AACO;AACP;AACA;;AAEA;AACA;AACA,WAAW,QAAQ;AACnB,WAAW,QAAQ;AACnB,aAAa;AACb;AACO;AACP;AACA;;AAEA;AACA;AACA,WAAW,QAAQ;AACnB,WAAW,QAAQ;AACnB,WAAW,gBAAgB,qBAAqB,sBAAsB;AACtE;AACA,aAAa;AACb;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA,0BAA0B,MAAM,SAAS,KAAK;AAC9C,SAAS;AACT,OAAO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA,UAAU;AACV;AACO;AACP,wBAAwB,yBAAC,iBAAiB,yBAAC,0BAA0B,yBAAC;AACtE,YAAY,yBAAC;AACb,0BAA0B,yBAAC,wBAAwB,mBAAmB;AACtE,0BAA0B,yBAAC,wBAAwB,mBAAmB;AACtE;;AAEA;AACA;AACA;AACA,WAAW,QAAQ;AACnB,WAAW,QAAQ;AACnB,WAAW,QAAQ;AACnB,WAAW,QAAQ;AACnB,aAAa,QAAQ;AACrB;AACO;AACP;AACA,iDAAiD,MAAM;AACvD;AACA,mDAAmD,OAAO;AAC1D;AACA,yDAAyD,KAAK;AAC9D;AACA;;AAEA;AACA,oCAAoC;AACpC;AACA,WAAW,QAAQ;AACnB,WAAW,QAAQ;AACnB,WAAW,QAAQ;AACnB,WAAW,QAAQ;AACnB,aAAa,QAAQ;AACrB;AACO;AACP,6BAA6B;AAC7B;;AAEA;AACA;AACA,WAAW,eAAe;AAC1B;AACA,WAAW,QAAQ;AACnB,WAAW,QAAQ;AACnB,WAAW,QAAQ;AACnB,aAAa,QAAQ;AACrB;AACO;AACP,qGAAqG,cAAc,QAAQ,IAAI;AAC/H;AACA;AACA;AACA;;AAEA;AACA;AACA,WAAW,QAAQ,sEAAsE;AACzF,WAAW,sBAAsB;AACjC,aAAa,QAAQ;AACrB;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI;AACJ;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,WAAW,sBAAsB;AACjC,aAAa;AACb;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,WAAW,QAAQ;AACnB,WAAW,gCAAgC,+CAA+C,iDAAiD;AAC3I,aAAa,2BAA2B;AACxC;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,WAAW,uBAAuB;AAClC;AACA,WAAW,UAAU;AACrB;AACA;AACO;AACP,kBAAkB,uBAAuB;AACzC;AACA;;AAEA;AACA;AACA;AACA,WAAW,QAAQ;AACnB,WAAW,QAAQ;AACnB,aAAa,gBAAgB;AAC7B;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,IAAI,8DAA8D;AAClE,IAAI;AACJ,QAAQ;AACR,WAAW,QAAQ;AACnB,aAAa;AACb;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,+BAA+B;AAC/B,WAAW,QAAQ;AACnB,aAAa;AACb;AACO;AACP;AACA;AACA;AACA,IAAI;AACJ;AACA,2CAA2C,SAAS;AACpD;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,QAAQ;AACnB,WAAW,QAAQ;AACnB,WAAW,QAAQ;AACnB;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,oBAAoB,sBAAsB;AAC1C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,UAAU;AACrB,WAAW,QAAQ;AACnB,aAAa,QAAQ;AACrB;AACO;AACP;AACA;;AAEA;AACA;AACA;AACA;AACO;AACP;AACA,WAAW,UAAU;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,yBAAyB,qBAAqB,GAAG;AACjD,8BAA8B,oBAAoB,wEAAwE;;AAE1H;AACA;AACA;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,gDAAe,KAAK,EAAC;;;AC10CrB,MAAM,sCAA4B,4B;;;ACAlC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEuB;AACyG;AAC5F;;AAEpC;AACA;AACA;AACO;AACP;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,sBAAsB;AACtB;;AAEA;AACA;AACA;AACA,aAAa,iBAAiB;AAC9B,aAAa,QAAQ;AACrB,wCAAwC;AACxC;AACA;AACA;AACA;AACA;AACA;AACA;AACA,2DAA2D,kCAAO,IAAI,uCAAY;AAClF,UAAU,qCAAY,GAAG,UAAU,oBAAoB;AACvD;AACA;AACA;AACA,OAAO;AACP;;AAEA;AACA;AACA,wCAAwC;AACxC,sBAAsB,gCAAQ;;AAE9B;AACA;AACA,uBAAuB,yBAAC;AACxB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA,MAAM,oBAAoB;AAC1B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB;AACA;AACA;AACA,6DAA6D,kCAAO,IAAI,uCAAY;AACpF,MAAM,qCAAY,GAAG,UAAU,oBAAoB;AACnD;AACA;AACA;;AAEA;AACA;AACA,aAAa,UAAU;AACvB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,iBAAiB;AAC9B,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kBAAkB,UAAU;AAC5B;AACA,oBAAoB,UAAU;AAC9B;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,eAAe,QAAQ;AACvB;AACA;AACA,WAAW,OAAO;AAClB;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA,WAAW,OAAO;AAClB;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe,QAAQ;AACvB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe,QAAQ;AACvB;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB;AACA,eAAe,QAAQ;AACvB;AACA;AACA;AACA;AACA;AACA;AACA,0BAA0B,UAAU;AACpC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,eAAe,QAAQ;AACvB;AACA;AACA,cAAc,oCAAoC,EAAE,+CAA+C,EAAE,gCAAgC,EAAE,UAAU,KAAK,YAAY;AAClK;;AAEA;AACA,UAAU,gFAAgF;AAC1F,SAAS;AACT;AACA,WAAW;AACX;AACA;AACA;AACA;AACA,sDAAsD,6CAA6C,IAAI,+CAA+C;AACtJ;AACA,eAAe;AACf;AACA;AACA;AACA,cAAc,yBAAC;AACf,eAAe,yBAAC,iBAAiB,sDAAsD;AACvF,aAAa,yBAAC;;AAEd,IAAI,yBAAC;AACL;AACA,mBAAmB,2BAA2B;AAC9C;AACA,mBAAmB,yBAAyB;AAC5C;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,iBAAiB;AAC9B,eAAe,SAAS;AACxB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AAGA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,iEAAiE,qBAAqB,iBAAiB;AACvG;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA,sDAAsD,yCAAyC;AAC/F;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,OAAO;AACnB;AACA;AACA;AACA;AACA,MAAM,iDAAiD;AACvD;AACA;AACA,aAAa,kDAAkD;AAC/D,cAAc,qCAAqC;AACnD,CAAC;;AAED;AACA;AACA;AACO;AACP;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,iBAAiB;AAC9B,eAAe;AACf;AACA;AACA,cAAc,UAAU;AACxB,cAAc,UAAU;AACxB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,eAAe,QAAQ;AACvB;AACA;AACA,WAAW,OAAO;AAClB;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA,WAAW,OAAO;AAClB;;AAEA;AACA,gBAAgB;AAChB;AACA,aAAa,mCAAmC;AAChD,aAAa,sBAAsB;AACnC,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA,oBAAoB,kBAAkB;AACtC;AACA;AACA;;AAEA;AACA;AACA,eAAe,QAAQ;AACvB;AACA;AACA,oCAAoC,kBAAkB,OAAO,QAAQ,IAAI,QAAQ;AACjF,oBAAoB,iBAAiB;AACrC,kBAAkB,OAAO,IAAI,8BAA8B;AAC3D,cAAc,OAAO;AACrB;;AAEA;AACA;AACA,eAAe,SAAS;AACxB;AACA;AACA,WAAW,oBAAoB,aAAa,oBAAoB;AAChE;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA,CAAC;;AAED;AACA;AACA,SAAS;AACT;AACO;AACP;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB;AACA,aAAa,QAAQ;AACrB;AACA,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,eAAe,QAAQ;AACvB;AACA;AACA,WAAW,OAAO;AAClB;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA,WAAW,OAAO;AAClB;;AAEA;AACA;AACA,aAAa,mCAAmC;AAChD,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA,CAAC;;AAED;AACA;AACA;AACO;AACP;AACA;AACA,aAAa,cAAc;AAC3B,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,iBAAiB;AAC9B,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,eAAe,QAAQ;AACvB;AACA;AACA,WAAW,OAAO;AAClB;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA,WAAW,OAAO;AAClB;;AAEA;AACA;AACA,aAAa,iBAAiB;AAC9B,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,cAAc;AAC3B,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,iBAAiB;AAC9B,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,kBAAkB;AAC/B,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,kBAAkB;AAC/B,eAAe,QAAQ;AACvB;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA,CAAC;;AAED;AACA;AACA;AACO;AACP;AACA;AACA,aAAa,cAAc;AAC3B;AACA,aAAa,cAAc;AAC3B;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,iBAAiB;AAC9B,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,eAAe,QAAQ;AACvB;AACA;AACA,WAAW,OAAO;AAClB;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA,WAAW,OAAO;AAClB;;AAEA;AACA;AACA,aAAa,sBAAsB;AACnC,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,iBAAiB;AAC9B,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,kBAAkB;AAC/B,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe,QAAQ;AACvB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA,CAAC;;AAED;AACA;AACA;AACA;AACO;AACP;AACA;AACA,aAAa,kBAAkB;AAC/B;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,iBAAiB;AAC9B,eAAe;AACf;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,kBAAkB;AAC/B,eAAe;AACf;AACA;AACA;AACA;AACA;;AAEA;AACA,yBAAyB,sCAAsC;AAC/D,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,kBAAkB;AAC/B,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,iBAAiB;AAC9B,eAAe;AACf;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,sBAAsB;AACnC;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA,6BAA6B,wBAAwB;AACrD,aAAa,kBAAkB;AAC/B,eAAe;AACf;AACA;AACA;AACA;AACA;;AAEA;AACA,6BAA6B,sCAAsC;AACnE,aAAa,sBAAsB;AACnC,eAAe;AACf;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,mCAAmC;AAChD,aAAa,sBAAsB;AACnC;AACA,eAAe,mCAAmC;AAClD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,mCAAmC;AAChD,eAAe,mCAAmC;AAClD;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,mCAAmC;AAChD,eAAe,mCAAmC;AAClD;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,mCAAmC;AAChD,aAAa,QAAQ;AACrB,eAAe,mCAAmC;AAClD;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,wDAAwD;AACxD,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA,gCAAgC,6BAA6B;AAC7D;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ,uBAAuB;AAC/B;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,kBAAkB;AAC9B;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA,CAAC;;AAED;AACA,oBAAoB,wBAAwB;AAC5C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA,aAAa,iCAAiC;AAC9C,aAAa,kBAAkB;AAC/B,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA,yBAAyB,sCAAsC;AAC/D,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,sBAAsB;AACnC,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,kBAAkB;AAC/B,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,iBAAiB;AAC9B,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,eAAe,wBAAwB;AACvC,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,kBAAkB,aAAa,wBAAwB;AACpE,eAAe;AACf;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,wBAAwB,iBAAiB;AACzC;;AAEA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA,eAAe,uBAAuB,GAAG,uBAAuB,GAAG,wCAAwC,GAAG,yCAAyC;AACvJ;;AAEA;AACA;AACA;AACA;AACA,eAAe,QAAQ;AACvB;AACA;AACA,WAAW,OAAO;AAClB;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA,WAAW,OAAO;AAClB;AACA,QAAQ,uBAAuB;AAC/B,QAAQ,2BAA2B;AACnC;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA,UAAU,sCAAsC;AAChD;AACA,YAAY,sBAAsB;AAClC;AACA,CAAC;;AAED;AACA,0DAA0D;AAC1D;AACA;AACO;AACP;AACA;AACA,aAAa,iCAAiC;AAC9C,aAAa,kBAAkB;AAC/B,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,6CAA6C;;AAE7C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,kCAAkC,iBAAiB;AACnD;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA,CAAC;;AAED;AACA,kBAAkB,wBAAwB;AAC1C,IAAI,6BAA6B;AACjC;AACA;AACO;AACP;AACA;AACA,aAAa,yBAAyB,wBAAwB,6BAA6B;AAC3F;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA,aAAa,6BAA6B;AAC1C,aAAa,uBAAuB;AACpC;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP,KAAK;;AAEL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,oBAAoB,OAAO;AAC3B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,sBAAsB,QAAQ;AAC9B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,eAAe,QAAQ;AACvB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,yBAAyB;AACrC;AACA;AACA,UAAU,sCAAsC;AAChD;AACA,YAAY,sBAAsB;AAClC;AACA;AACA;AACA;AACA,YAAY,oBAAoB;AAChC;AACA,CAAC;;AAED;AACA,yCAAyC,uBAAuB;AAChE;AACO;AACP;AACA;AACA,aAAa,QAAQ;AACrB;AACA,aAAa,oBAAoB,uBAAuB,wBAAwB;AAChF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAwB,mBAAmB;AAC3C;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW;AACX,WAAW;AACX;AACA,aAAa,kBAAkB;AAC/B,aAAa,kBAAkB;AAC/B,aAAa,kBAAkB;AAC/B,aAAa,QAAQ;AACrB,sCAAsC,0CAA0C;AAChF,eAAe,oBAAoB;AACnC;AACA;AACA;AACA,kBAAkB,QAAQ;AAC1B;AACA;AACA;AACA;AACA,oBAAoB,eAAe;AACnC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,kBAAkB;AAC/B,aAAa,kBAAkB;AAC/B,aAAa,kBAAkB;AAC/B,aAAa,kBAAkB;AAC/B,aAAa,QAAQ;AACrB,sCAAsC,0CAA0C;AAChF,eAAe,oBAAoB;AACnC;AACA;AACA;AACA;AACA,kBAAkB,QAAQ;AAC1B;AACA;AACA,oBAAoB,eAAe;AACnC;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,iBAAiB;AAC9B;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,wBAAwB,IAAI,qCAAqC;AAC9E,aAAa,iBAAiB;AAC9B;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,mCAAmC;AAChD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,kBAAkB;AAC/B,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,eAAe,QAAQ;AACvB;AACA;AACA,cAAc,UAAU,GAAG,sCAAsC,EAAE,MAAM,GAAG,EAAE,MAAM,kBAAkB;AACtG;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,oBAAoB;AAChC;AACA,CAAC;;AAED;AACA;AACA;AACO;AACP;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,UAAU;AACvB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,mBAAmB;AAChC,aAAa,QAAQ;AACrB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,4BAA4B;AAC5B;AACA;AACA,aAAa,QAAQ;AACrB;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,UAAU;AACvB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,UAAU;AACvB;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,SAAS;AACtB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA;AACA,YAAY,YAAY;AACxB;AACA,CAAC;;AAED;AACA;AACA;AACO;AACP;AACA;AACA,aAAa,UAAU;AACvB,aAAa,QAAQ;AACrB,aAAa,SAAS;AACtB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,kBAAkB;AAC/B;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,gBAAgB;AAC7B;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,SAAS;AACtB,aAAa,SAAS;AACtB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,SAAS;AACtB;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,SAAS;AACtB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA,CAAC;;AAED;AACA;AACA;AACA,kDAAkD;AAClD;AACA;AACO;AACP;AACA;AACA,aAAa,iCAAiC;AAC9C,aAAa,kBAAkB;AAC/B,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,sBAAsB;AACnC;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,qBAAqB;AACrB,aAAa,kBAAkB;AAC/B;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY,sBAAsB;AAClC;AACA,CAAC;;AAED;AACA;AACA;AACA;AACA,kCAAkC,2BAA2B,GAAG,mCAAmC,GAAG,+BAA+B;AACrI,IAAI,6BAA6B,GAAG,qCAAqC,GAAG,6BAA6B,GAAG,qCAAqC;AACjJ,IAAI,iCAAiC,GAAG,2BAA2B,GAAG,uCAAuC,GAAG,+BAA+B;AAC/I,IAAI,8BAA8B,KAAK,qCAAqC;AAC5E;AACA,0CAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC,EAAC;;;AClhEF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEkC;;AAElC;AACA;AACA;AACO;AACP;AACA;AACA,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,iBAAiB;AAC9B;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,4CAA4C,2BAA2B;AACvE;;AAEA;;AAEA;;AAEA;AACA,YAAY,GAAG,oCAAoC,IAAI;AACvD;AACA;;AAEA;AACA,YAAY,GAAG;AACf;AACA;;AAEA;AACA,YAAY,GAAG;AACf;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,+CAA+C,GAAG,qCAAqC,GAAG;;AAE1F;;AAEA;;AAEA;AACA;AACA;AACA,WAAW;AACX,SAAS;AACT;AACA,UAAU,GAAG;AACb;AACA,SAAS;AACT;AACA;;AAEA;AACA;AACA;AACA;AACA,aAAa,SAAS;AACtB,aAAa,iBAAiB;AAC9B;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY;AACZ;AACA;AACA;AACA;AACA;AACA,YAAY;AACZ;AACA;AACA;AACA,oFAAoF;AACpF;AACA,YAAY;AACZ;AACA;AACA;AACA;AACA;AACA,YAAY;AACZ;AACA;AACA;AACA;AACA;AACA,YAAY;AACZ;AACA;AACA;AACA;AACA;AACA;AACA,YAAY;AACZ;AACA;AACA;AACA;AACA;AACA;AACA,YAAY;AACZ;AACA;AACA,CAAC;;AAED;AACA;AACA,UAAU;AACV;AACA;;AAEA,wDAAe,WAAW,EAAC;;;AC1N3B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEuB;AACoB;;AAE3C;AACA,gDAAgD,8CAA8C;AAC9F;AACA;AACO;AACP;AACA;AACA,aAAa,wCAAwC;AACrD,aAAa,+BAA+B;AAC5C,aAAa,gCAAgC;AAC7C,MAAM,8FAA8F;AACpG,gBAAgB,iDAAiD;AACjE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,8DAA8D,iBAAW;AACzE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kCAAkC,yBAAC;AACnC;AACA;AACA,OAAO;AACP;AACA;;AAEA;AACA;AACA,aAAa,kCAAkC;AAC/C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY;AACZ;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;AACA,YAAY;AACZ;AACA,4BAA4B,yBAAC;AAC7B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;;AAEA;AACA;AACA,aAAa,kCAAkC;AAC/C;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ,iCAAiC;AACtD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ,iCAAiC;AACtD;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,kCAAkC;AAC/C;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,SAAS;AACtB;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,kCAAkC;AAC/C;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY,wCAAwC;AACpD;AACA;AACA;AACA;AACA,YAAY,gCAAgC;AAC5C;AACA;AACA,uCAAuC,kDAAkD;AACzF;AACA,YAAY,kCAAkC;AAC9C;AACA;AACA;AACA;AACA,YAAY,iBAAiB;AAC7B;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA,UAAU,mDAAmD;AAC7D;AACA,YAAY,6CAA6C;AACzD;AACA,CAAC;;AAED;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,wCAAwC;AACxC,0BAA0B,gFAAgF;AAC1G,UAAU,wBAAwB;AAClC;;AAEA,8DAAe,iBAAiB,EAAC;;;;;;;;;;;;;;;ACxSjC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEuB;AACW;AACwD;;AAEhD;AACJ;AACJ;AACI;AACA;AACJ;;AAElC;AACA;AACA;AACA,qBAAqB,kDAAkD;AACvE;AACO;AACP;AACA;AACA,aAAa,QAAQ;AACrB;AACA;AACA,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,iBAAiB;AAC9B;AACA;AACA,IAAI,WAAW;AACf;AACA;AACA;AACA;AACA;AACA,sBAAsB,MAAM;AAC5B;AACA;AACA,+BAA+B,MAAM;AACrC;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,mCAAmC,KAAK;AACxC;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,uBAAuB,UAAU;AACjC;AACA;AACA,KAAK;AACL;AACA;;AAEA;AACA;AACA;AACA;AACA,eAAe,QAAQ;AACvB;AACA;AACA,WAAW,OAAO;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA,WAAW,OAAO;AAClB;AACA,QAAQ,wBAAwB,KAAK,EAAE;AACvC;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,wCAAwC;AACrD,eAAe,SAAS;AACxB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA,oBAAoB,UAAU;AAC9B;AACA,kBAAkB,QAAQ,EAAE,UAAU,EAAE,0BAA0B,UAAU,OAAO,EAAE,sBAAsB,QAAQ,OAAO;AAC1H;AACA,kBAAkB,QAAQ,EAAE,mBAAmB;AAC/C;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA,cAAc,UAAU,EAAE,gBAAgB,UAAU,OAAO;AAC3D;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,kBAAkB;AAC9B;AACA;AACA,WAAW,0DAA0D;AACrE;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA,kFAAkF;AAClF;AACA;AACA,YAAY,SAAS;AACrB;AACA,CAAC;;AAED;AACA;AACA,UAAU,QAAQ;AAClB;AACA,SAAS;AACT,OAAO;AACP,OAAO;AACP,KAAK;AACL,OAAO;AACP,KAAK;AACL;;AAEA;AACA,uBAAuB,iCAAiC;AACxD;AACA,UAAU,QAAQ;AAClB;;AAEA;AACA,8BAAM;AACN;AACA,YAAY,QAAQ;AACpB;AACA,CAAC;;AAED,yDAAe,YAAY,EAAC;;;ACvU5B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEiF;AAC1B;AACV;;AAE7C;AACA;AACA;AACA,6CAA6C;AAC7C;AACO;AACP;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA,UAAU,UAAU;AACpB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,iBAAiB;AAC9B;AACA;AACA;AACA,mBAAmB,WAAW;AAC9B;AACA;;AAEA;AACA;AACA;AACA;AACA,eAAe,QAAQ;AACvB;AACA;AACA,WAAW,OAAO;AAClB,iBAAiB,OAAO,CAAC;AACzB;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA,WAAW,OAAO;AAClB;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,gCAAgC;AAC7C,aAAa,+BAA+B;AAC5C;AACA;AACA;AACA,wBAAwB,uBAAiB,KAAK,kBAAY;AAC1D;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ;AACR;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB,WAAW,OAAO;AAClB;AACA;AACA;AACA,YAAY,kDAAkD;AAC9D;AACA;AACA;AACA;AACA,YAAY,2BAA2B;AACvC;AACA,CAAC;;AAED,+DAAe,kBAAkB,EAAC;;;;;;;;;;;;;;;AC1JlC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEuB;AACkC;AACY;;AAErE;AACuC;AACA;AACM;AACM;AACF;AACM;;AAEvD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,yCAAyC,0DAA0D;AACnG;AACO;AACP;AACA;AACA,aAAa,sCAAsC;AACnD;AACA;AACA;AACA;AACA,sCAAsC;AACtC;AACA;AACA;;AAEA;AACA;AACA,aAAa,iBAAiB;AAC9B;AACA;AACA,mBAAmB,WAAW;AAC9B;AACA;AACA,8BAA8B,wBAAkB;AAChD,sCAAsC,yBAAC;AACvC,KAAK;AACL;AACA;;AAEA;AACA;AACA;AACA;AACA,eAAe,QAAQ;AACvB;AACA;AACA,WAAW,OAAO;AAClB,iBAAiB,OAAO,CAAC;AACzB;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA,WAAW,OAAO;AAClB;AACA,QAAQ,qBAAqB,wBAAkB,mBAAmB;AAClE;AACA;;AAEA;AACA;AACA,aAAa,gCAAgC;AAC7C,aAAa,+BAA+B;AAC5C;AACA;AACA,mBAAmB,mBAAmB;AACtC,IAAI,8BAAM;AACV;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,UAAU,QAAQ;AAClB;AACA,OAAO;AACP,OAAO;AACP,UAAU;AACV,aAAa;AACb,YAAY;AACZ,eAAe;AACf;;AAEA;AACA;AACA,oBAAoB,0DAA0D;AAC9E;AACA,YAAY,QAAQ;AACpB;AACA,eAAe,wBAAkB;AACjC,eAAe,wBAAkB;AACjC,kBAAkB,wBAAkB;AACpC,qBAAqB,wBAAkB;AACvC,oBAAoB,wBAAkB;AACtC,uBAAuB,wBAAkB;AACzC,GAAG;AACH;AACA;AACA;AACA,YAAY,QAAQ;AACpB,WAAW,OAAO;AAClB;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA,CAAC;;AAED,wDAAe,WAAW,EAAC;;;ACxK3B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEuB;AACiG;AAC1D;;AAE9D,sBAAsB,QAAQ;;AAE9B;AACA,sEAAsE,wDAAwD;AAC9H;AACA;AACA;AACA,yBAAyB,wDAAwD;AACjF,yBAAyB,wCAAwC;AACjE;AACA;AACA;AACO;AACP;AACA;AACA,aAAa,8BAA8B;AAC3C;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,iBAAiB;AAC9B;AACA;AACA;AACA;AACA,IAAI,WAAW;AACf;AACA;AACA;AACA,uBAAuB,UAAU;AACjC;AACA;AACA;AACA;AACA;AACA,kCAAkC,MAAM;AACxC;AACA;AACA,kCAAkC,MAAM;AACxC;AACA;AACA,KAAK;AACL;AACA;AACA;AACA,oBAAoB,yBAAC;AACrB;AACA;AACA,2BAA2B,IAAI;AAC/B;;AAEA;AACA,gCAAgC,QAAQ;AACxC;;AAEA;AACA,2BAA2B,UAAU;AACrC,2BAA2B,UAAU;AACrC,6BAA6B,UAAU;AACvC,+BAA+B,UAAU;AACzC,kCAAkC,UAAU;AAC5C,6BAA6B,UAAU;AACvC;AACA;AACA,KAAK;AACL;AACA;;AAEA;AACA;AACA;AACA;AACA,eAAe,QAAQ;AACvB;AACA;AACA,WAAW,OAAO;AAClB;AACA;AACA;AACA;AACA,mBAAmB,4BAA4B;AAC/C,mBAAmB,4BAA4B;AAC/C,qBAAqB,8BAA8B;AACnD,uBAAuB,gCAAgC;AACvD,0BAA0B,mCAAmC;AAC7D,qBAAqB,8BAA8B;AACnD;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA,WAAW,OAAO;AAClB;AACA,QAAQ,yBAAyB,MAAM,EAAE;AACzC,QAAQ,yBAAyB,MAAM,EAAE;AACzC,QAAQ,iBAAiB,IAAI,EAAE;AAC/B,QAAQ,uBAAuB,QAAQ,EAAE;AACzC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,eAAe,KAAK;AACpB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,QAAQ;AACrB,eAAe,KAAK;AACpB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,yBAAyB,WAAW;AACpC;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,SAAS;AACtB,aAAa,SAAS;AACtB,aAAa,SAAS;AACtB,eAAe;AACf;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA,8BAA8B,MAAM,KAAK,MAAM,SAAS,MAAM;AAC9D;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,aAAa,mCAAmC;AAChD,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,eAAe,UAAU;AACzB,oFAAoF;AACpF;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,oBAAoB,kBAAkB;AACtC;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAwB,iBAAiB;AACzC;AACA,cAAc,WAAW;AACzB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,kBAAkB,SAAS;AAC3B,OAAO;;AAEP;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY,8BAA8B;AAC1C;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,iBAAiB;AAC7B,YAAY,IAAI;AAChB;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,qBAAqB;AACjC;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,mBAAmB;AAC/B,oBAAoB,MAAM;AAC1B;AACA;AACA;AACA,YAAY,mBAAmB;AAC/B,oBAAoB,MAAM;AAC1B,CAAC;;AAED;;AAEA,oDAAe,OAAO,EAAC;;;AC7YvB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEuB;AACe;AAC8D;AACjE;AACiB;;AAEpD;AACA;AACA;AACO;AACP;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,eAAe,QAAQ;AACvB;AACA;AACA,WAAW,OAAO;AAClB;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA,WAAW,OAAO;AAClB;AACA;;AAEA;AACA;AACA;AACA,CAAC;;AAED;AACA,0DAA0D,kDAAkD;AAC5G;AACA;AACA,yBAAyB,4CAA4C;AACrE;AACO;AACP;AACA;AACA,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,iBAAiB;AAC9B,aAAa,+BAA+B;AAC5C;AACA;AACA;AACA;AACA,IAAI,WAAW;AACf;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,iCAAiC,SAAS;AAC1C;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,uBAAuB,UAAU;AACjC;;AAEA;AACA,uBAAuB,MAAM;AAC7B;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA,oBAAoB,yBAAC;AACrB;AACA;AACA,2BAA2B,aAAO;AAClC;AACA;AACA,kCAAkC,kBAAY;AAC9C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA,eAAe,QAAQ;AACvB;AACA;AACA,WAAW,OAAO;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,eAAe;AAC5B,aAAa,+BAA+B;AAC5C,eAAe;AACf;AACA;;AAEA;AACA;AACA;AACA,MAAM,OAAO;AACb;AACA;AACA,UAAU,sBAAsB,SAAS,EAAE;AAC3C,UAAU,gCAAgC;AAC1C,UAAU,gCAAgC;AAC1C,UAAU,kBAAkB,aAAO,EAAE;AACrC,UAAU,yBAAyB,kBAAY,EAAE;AACjD;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,gDAAgD;AAC7D,aAAa,SAAS;AACtB,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,QAAQ,UAAU;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,aAAa,2BAA2B;AACxC,aAAa,kBAAkB;AAC/B,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,gCAAgC,yBAAyB;AACtE;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,+BAA+B;AAC5C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB,MAAM,WAAW,EAAE,WAAW;AACnD;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB,MAAM,WAAW,EAAE,WAAW;AACnD;AACA,qBAAqB,MAAM,oBAAoB,EAAE,yCAAyC;AAC1F,+BAA+B,MAAM;AACrC;AACA;;AAEA;AACA;AACA,UAAU,4CAA4C,mDAAmD,kDAAkD;AAC3J;AACA;AACA;AACA,YAAY,8BAA8B;AAC1C;AACA;AACA,+BAA+B,kDAAkD;AACjF;AACA,YAAY,sBAAsB;AAClC;AACA;AACA,UAAU,kDAAkD,kDAAkD,2CAA2C;AACzJ;AACA;AACA,YAAY,cAAc;AAC1B;AACA;AACA,iCAAiC,iDAAiD;AAClF;AACA,YAAY,QAAQ;AACpB;AACA;AACA,mDAAmD,iDAAiD;AACpG;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,kBAAkB;AAC9B;AACA;AACA;AACA;AACA,YAAY,wCAAwC;AACpD;AACA;AACA;AACA,YAAY;AACZ,gBAAgB,QAAQ;AACxB,gBAAgB,QAAQ;AACxB;AACA;AACA;AACA,YAAY,yCAAyC;AACrD;AACA;AACA;AACA;AACA;AACA,YAAY,yCAAyC;AACrD;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,2BAA2B;AACvC;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA,UAAU,0EAA0E;AACpF;AACA,YAAY,kDAAkD;AAC9D;AACA;AACA,UAAU,mDAAmD;AAC7D;AACA,YAAY,6CAA6C;AACzD;AACA,CAAC;;AAED;AACA;AACA,UAAU;AACV;AACA;;AAEA,6DAAe,gBAAgB,EAAC;;;ACnehC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEuB;AACsD;AACL;;AAExE;AACA;AACA,UAAU,kDAAkD;AAC5D;AACA;AACO;AACP;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,UAAU;AACvB,eAAe,8BAA8B;AAC7C;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA;AACA;AACA,MAAM,GAAG,6BAA6B,UAAU;AAChD;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oBAAoB,iBAAiB;AACrC,8BAA8B,KAAK;AACnC;;AAEA;AACA;AACA,aAAa,iBAAiB;AAC9B;AACA;AACA,IAAI,WAAW;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uBAAuB,UAAU;AACjC;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA,MAAM,yBAAC;AACP;AACA;AACA;AACA;AACA,OAAO;AACP,KAAK;;AAEL;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,aAAa,iBAAiB;AAC9B,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA;AACA;AACA,IAAI,8BAAM;AACV;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,uBAAuB,SAAS;AAChC;AACA;AACA,uBAAuB,OAAO;AAC9B;AACA;AACA;AACA,uBAAuB,UAAU;AACjC;AACA;AACA,KAAK;;AAEL,2CAA2C,IAAI;AAC/C;;AAEA;AACA;AACA;AACA;AACA,eAAe,QAAQ;AACvB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA,WAAW,OAAO;AAClB;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA;AACA,IAAI,OAAO;AACX;AACA;AACA;AACA;AACA;AACA,QAAQ,sBAAsB,KAAK,EAAE;AACrC,QAAQ,sBAAsB,KAAK,kBAAkB;AACrD;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,sBAAsB;AACnC,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA,eAAe,SAAS;AACxB;;AAEA;AACA;AACA;AACA,aAAa,sBAAsB;AACnC,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA,2CAA2C,SAAS;AACpD,oBAAoB,iBAAiB;AACrC;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,SAAS,0CAA0C;AACnD;AACA,YAAY,QAAQ;AACpB;AACA;AACA,SAAS,0CAA0C;AACnD;AACA,YAAY,QAAQ;AACpB;AACA;AACA,SAAS,0CAA0C;AACnD;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,SAAS,uCAAuC;AAChD;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA,SAAS,uCAAuC;AAChD;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA,SAAS,uCAAuC;AAChD;AACA,YAAY,kBAAkB;AAC9B;AACA;AACA,SAAS,uCAAuC;AAChD;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA,CAAC;;AAED;AACA;AACA;AACA,UAAU,QAAQ;AAClB;;AAEA,qDAAe,MAAM,EAAC;;;ACjYtB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEuB;AACY;AACkB;AACX;AACJ;AACoD;;AAE1F;AACA,qCAAqC,uEAAuE;AAC5G,sEAAsE,0CAA0C;AAChH,+CAA+C,iDAAiD,WAAW,4CAA4C;AACvJ;AACA;AACO;AACP;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,iBAAiB;AAC9B,aAAa,+BAA+B;AAC5C;AACA;AACA;AACA,IAAI,WAAW;AACf;AACA;AACA;AACA;AACA;AACA,uBAAuB,MAAM;AAC7B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAwB,UAAU;AAClC;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA;AACA;;AAEA;AACA,oBAAoB,yBAAC;AACrB;AACA;AACA,2BAA2B,aAAO;AAClC;AACA;AACA;AACA;AACA;AACA,wBAAwB,cAAM;AAC9B;AACA;AACA;AACA;AACA;AACA,mDAAmD,oBAAoB,sBAAgB,eAAe;AACtG;AACA;AACA,8BAA8B,sBAAgB;AAC9C;AACA;AACA,KAAK;;AAEL;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,sBAAsB,OAAO;AAC7B;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAwB,OAAO;AAC/B;AACA;AACA;;AAEA;AACA;AACA,oCAAoC,+CAA+C;;AAEnF;AACA;;AAEA;AACA;AACA;AACA;AACA,eAAe,QAAQ;AACvB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,+CAA+C;AAC/C,WAAW,OAAO;AAClB;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,+BAA+B;AAC5C,eAAe;AACf;AACA;AACA,IAAI,OAAO;AACX;AACA;AACA;AACA,QAAQ,kBAAkB,aAAO,EAAE;AACnC,QAAQ,mBAAmB,cAAM,EAAE;AACnC;AACA,QAAQ,kBAAkB,sBAAgB,sCAAsC;AAChF;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,iDAAiD,8CAA8C;AAC/F;;AAEA;AACA;AACA;AACA,sBAAsB,OAAO;AAC7B;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAwB,OAAO;AAC/B;AACA;AACA;;AAEA;AACA;AACA,kCAAkC,+CAA+C;;AAEjF;AACA;;AAEA;AACA;;AAEA;AACA;AACA,aAAa,gCAAgC,mBAAmB;AAChE;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA,oBAAoB,2CAA2C;AAC/D,eAAe;AACf;AACA;AACA;AACA,oBAAoB,cAAM;AAC1B;AACA;;AAEA;AACA,oBAAoB,4CAA4C;AAChE,eAAe;AACf;AACA;AACA;AACA,uBAAuB,aAAO;AAC9B;AACA;;AAEA;AACA,iBAAiB,uEAAuE;AACxF,aAAa,gDAAgD;AAC7D;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,mBAAmB,uEAAuE;AAC1F,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA;AACA,sCAAsC,QAAQ;AAC9C,4BAA4B,sBAAgB;AAC5C;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,+BAA+B;AAC5C,aAAa,8BAA8B;AAC3C,aAAa,SAAS;AACtB;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;;AAEA,kBAAkB,SAAS;AAC3B,oBAAoB,wBAAwB;AAC5C;;AAEA;AACA,mCAAmC,sBAAgB;AACnD;AACA;AACA;;AAEA;AACA;AACA,aAAa,UAAU;AACvB,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA;AACA,oBAAoB,OAAO;AAC3B;AACA;;AAEA;AACA,oCAAoC,uEAAuE;AAC3G,aAAa,UAAU;AACvB;AACA;AACA,oBAAoB,yCAAyC;AAC7D;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,KAAK;AAClB;AACA;AACA;AACA;;AAEA;AACA;AACA,sCAAsC,uEAAuE;AAC7G;AACA,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA,uCAAuC,qBAAqB;AAC5D;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,2BAA2B;AACvC;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB,KAAK,QAAQ;AACb;AACA;AACA;AACA,YAAY,QAAQ;AACpB,KAAK,QAAQ;AACb;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,8BAA8B;AAC1C;AACA;AACA;AACA;AACA,YAAY,8BAA8B;AAC1C;AACA;AACA;AACA;AACA,YAAY,gDAAgD;AAC5D;AACA;AACA,wBAAwB,uEAAuE;AAC/F;AACA,YAAY,kDAAkD;AAC9D;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA,CAAC;;AAED,6DAAe,gBAAgB,EAAC;;;AC7ehC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEyC;;AAEzC;AACA;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,oCAAoC;AACpC,aAAa,iBAAiB;AAC9B,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ;AACR,QAAQ,GAAG,gDAAgD,UAAU;AACrE;AACA;AACA;;AAEA;AACA;AACA,aAAa,iBAAiB;AAC9B;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,eAAe,QAAQ;AACvB;AACA;AACA;AACA,WAAW,OAAO;AAClB;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,UAAU;AACvB,eAAe;AACf;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,gBAAgB,qFAAqF;AACrG,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,kDAAkD,gDAAgD;AAC/G;AACA,aAAa,SAAS,yCAAyC,uEAAuE;AACtI,eAAe,SAAS;AACxB;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,2DAA2D;AACxE,eAAe,SAAS;AACxB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,UAAU;AACvB,eAAe,2DAA2D;AAC1E;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA,CAAC;;AAED;AACA;AACA,WAAW,QAAQ;AACnB,WAAW,QAAQ;AACnB,WAAW,kDAAkD,gDAAgD;AAC7G;AACA,WAAW,SAAS,wCAAwC,uEAAuE;AACnI;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,oEAAoE,iDAAiD;AACrH,UAAU,QAAQ;AAClB;AACA;AACA;AACA;;AAEA;AACA;;AAEA,qEAAe,mBAAmB,EAAC;;;ACrLnC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEuB;AAC2D;AAC/C;;AAEnC;AACA,2CAA2C,+CAA+C;AAC1F;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA;AACA;AACA,qBAAqB,aAAO;AAC5B;AACA;;AAEA;AACA;AACA,aAAa,iBAAiB;AAC9B;AACA;AACA;AACA,IAAI,WAAW;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAwB,UAAU;AAClC;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA,uBAAuB,aAAO,iBAAiB,yBAAC;AAChD,KAAK;;AAEL;;AAEA,mCAAmC,cAAc;AACjD;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA,eAAe,QAAQ;AACvB;AACA;AACA,WAAW,OAAO;AAClB;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB,QAAQ,cAAc;AAC3C;AACA;;AAEA;AACA;AACA,aAAa,eAAe;AAC5B,eAAe;AACf;AACA;AACA,WAAW,OAAO;AAClB;AACA;AACA;AACA,QAAQ,kBAAkB,aAAO,EAAE;AACnC;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;AACA,sBAAsB,cAAc;AACpC,wBAAwB,cAAc;AACtC;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA,UAAU,4CAA4C;AACtD;AACA,YAAY,8BAA8B;AAC1C;AACA;AACA;AACA;AACA;AACA,YAAY,UAAU;AACtB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB,eAAe,QAAQ;AACvB,CAAC;;AAED,4DAAe,eAAe,EAAC;;;ACtN/B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEgF;;AAEhF;AACA,mCAAmC,sEAAsE;AACzG,IAAI,0EAA0E;AAC9E;AACA;AACO;AACP;AACA;AACA,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA;AACA,QAAQ;AACR;;AAEA;AACA,0DAA0D,4DAA4D;AACtH;AACA,aAAa,iBAAiB;AAC9B,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ;AACR,QAAQ,GAAG,uCAAuC,UAAU;AAC5D;AACA;AACA;;AAEA;AACA;AACA,aAAa,iBAAiB;AAC9B;AACA;AACA,IAAI,WAAW;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uBAAuB,UAAU;AACjC;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA;AACA;AACA;AACA,aAAa,OAAO;AACpB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,eAAe,QAAQ;AACvB;AACA;AACA,WAAW,OAAO;AAClB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,UAAU;AACvB;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,iBAAiB;AAC9B,eAAe,SAAS;AACxB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,eAAe,SAAS;AACxB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,iBAAiB;AAC9B,eAAe,UAAU;AACzB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,eAAe,UAAU;AACzB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,UAAU;AACvB,eAAe,SAAS;AACxB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,mBAAmB;AAC/B;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA,CAAC;;AAED;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA,aAAa,QAAQ;AACrB;AACA;AACA;AACA;;AAEA;AACA,sBAAsB,mEAAmE;AACzF;AACA,aAAa,UAAU;AACvB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;;AAEA;AACA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,eAAe,SAAS;AACxB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,MAAM,0EAA0E;AAChF;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,eAAe,UAAU;AACzB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,WAAW;AACxB;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA,sCAAsC,gBAAgB;AACtD;AACA;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ;AACR;AACA;AACA;AACA;AACA;AACA,QAAQ;AACR;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA,yFAAyF;AACzF;AACA,YAAY,QAAQ;AACpB,mBAAmB;AACnB,CAAC;;AAED;AACA,+BAA+B,qEAAqE;AACpG;AACA;AACA;AACO;AACP;AACA;AACA,aAAa,QAAQ;AACrB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,MAAM,0EAA0E;AAChF;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,eAAe,UAAU;AACzB;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,oBAAoB,kBAAkB;AACtC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,sBAAsB,kBAAkB;AACxC;AACA;AACA;AACA;AACA;AACA;;AAEA,2BAA2B,iBAAiB;AAC5C;;AAEA;AACA;;AAEA;AACA;AACA,aAAa,UAAU;AACvB,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,UAAU;AACvB;AACA,aAAa,SAAS;AACtB;AACA,eAAe,SAAS;AACxB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA,WAAW,SAAS;AACpB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ;AACR;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAiB,WAAW;AAC5B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAwB,WAAW;AACnC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA,CAAC;;AAED;AACA;AACA;AACA;AACA;;AAEA,qDAAe,SAAS,EAAC;;;ACrhBzB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEuB;AACkG;AAC1D;AACR;;AAEvD;AACA,8DAA8D,oEAAoE;AAClI,IAAI,oEAAoE,GAAG,4DAA4D,KAAK,wDAAwD;AACpM,qEAAqE,oEAAoE;AACzI,gCAAgC,yEAAyE;AACzG;AACO;AACP;AACA;AACA;AACA;AACA;AACA,mBAAmB;AACnB;AACA;;AAEA;AACA;AACA,aAAa,iBAAiB;AAC9B,aAAa,+BAA+B;AAC5C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA,0CAA0C,yBAAC;AAC3C;AACA,wDAAwD,gCAAQ;AAChE,KAAK;;AAEL;AACA;;AAEA,kBAAkB;;AAElB;AACA,MAAM,WAAW;AACjB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;;AAEP;AACA,MAAM,yBAAC;AACP;AACA,uBAAuB,yBAAC;AACxB;;AAEA;AACA,sBAAsB,sBAAgB;AACtC;;AAEA;AACA,oBAAoB,4CAA4C;AAChE;AACA,iBAAiB,uCAAe;AAChC;AACA;AACA;;AAEA;AACA,6EAA6E;AAC7E;AACA;AACA;;AAEA;AACA,YAAY,GAAG,mDAAmD,eAAe;AACjF;AACA;AACA;AACA;AACA;AACA,OAAO;;AAEP;AACA,KAAK;AACL;AACA;;AAEA;AACA;AACA,aAAa,iBAAiB;AAC9B,eAAe;AACf;AACA;AACA;AACA,eAAe;AACf;AACA,IAAI,WAAW;AACf;AACA;AACA,gBAAgB,UAAU;AAC1B;AACA;AACA;AACA;AACA,gBAAgB,UAAU;AAC1B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oCAAoC;AACpC,mBAAmB,gCAAQ,SAAS;AACpC;AACA,qCAAqC;AACrC,oBAAoB,gCAAQ,GAAG;AAC/B;AACA;AACA;AACA,gBAAgB,UAAU;AAC1B;AACA;AACA;AACA;AACA,gBAAgB,UAAU;AAC1B;AACA;AACA;AACA;AACA,uBAAuB,UAAU;AACjC;AACA;AACA;AACA,gCAAgC,IAAI;AACpC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,UAAU,GAAG,qCAAqC,KAAK,OAAO,IAAI;AAClE;AACA;AACA;AACA,KAAK;;AAEL,SAAS,uCAAe;AACxB;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA,eAAe,QAAQ;AACvB;AACA;AACA;AACA,WAAW,OAAO;AAClB;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;;AAEA,IAAI,OAAO;;AAEX;AACA;AACA;AACA;AACA;AACA,wBAAwB,sBAAgB;AACxC;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA,KAAK;AACL;AACA;;AAEA;AACA;AACA,eAAe,QAAQ;AACvB;AACA;AACA,kBAAkB,yBAAC;AACnB;AACA;AACA;AACA,iBAAiB,yBAAC;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA,uBAAuB;AACvB;AACA;AACA;AACA,KAAK;AACL;AACA;;AAEA;AACA;AACA;AACA,aAAa,QAAQ;AACrB,eAAe,QAAQ;AACvB;AACA;AACA,eAAe,gCAAQ,SAAS;AAChC,WAAW,gCAAQ,mDAAmD;AACtE,6BAA6B,8DAA8D;AAC3F;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;;AAEA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA,wBAAwB,kDAAkD;AAC1E;AACA,YAAY,QAAQ;AACpB;AACA;AACA,eAAe,6EAA6E;AAC5F;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA,CAAC;;AAED;AACA;AACA;AACA;AACO;AACP;AACA;AACA,aAAa,kEAAkE;AAC/E,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,iBAAiB;AAC9B,aAAa,+BAA+B;AAC5C;AACA;AACA;AACA;AACA;AACA,oBAAoB,yBAAC;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW;AACX;;AAEA;AACA,yBAAyB,MAAM;AAC/B;AACA,cAAc,QAAQ;AACtB;AACA,6BAA6B,SAAS;AACtC,4BAA4B,SAAS;AACrC,yBAAyB,MAAM;AAC/B;;AAEA;AACA,0BAA0B,MAAM;AAChC,4BAA4B,SAAS;AACrC,8BAA8B,SAAS;AACvC;AACA;AACA,oCAAoC,sBAAgB;AACpD,iDAAiD,kBAAY,iBAAiB,yBAAC;AAC/E,WAAW;AACX;AACA;AACA,sCAAsC,sBAAgB,iBAAiB,yBAAC;AACxE,aAAa;AACb;AACA;;AAEA;AACA,4DAA4D;AAC5D,kDAAkD,yBAAC;AACnD,eAAe,uCAAe;AAC9B;AACA;;AAEA;AACA;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA;AACA;AACA,eAAe,QAAQ;AACvB;AACA;AACA,WAAW,OAAO;AAClB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA,WAAW,OAAO;AAClB;AACA;AACA;AACA,QAAQ,yBAAyB,sBAAgB,sBAAsB;AACvE;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe,QAAQ;AACvB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,UAAU,6FAA6F;AACvG;AACA,YAAY,kEAAkE;AAC9E;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,UAAU;AACtB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA,kBAAkB,uEAAuE;AACzF;AACA,YAAY,gDAAgD;AAC5D;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,iBAAiB;AAC7B;AACA;AACA;AACA;AACA,YAAY,iBAAiB;AAC7B;AACA;AACA;AACA;AACA,YAAY,iBAAiB;AAC7B;AACA;AACA;AACA;AACA,YAAY,iBAAiB;AAC7B;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA,eAAe,4DAA4D;AAC3E;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,+DAA+D;AAC3E;AACA,CAAC;;AAED;;AAEA,gEAAe,oBAAoB,EAAC;;;ACnpBpC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEuB;AACsH;AACjE;AAC3B;AACU;AACA;AAClB;AAC6B;AACb;AACF;AACsB;;AAE7E;AACA;;AAEA;AACA;AACA,IAAI,kDAAkD;AACtD;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA,aAAa,0CAA0C,eAAe,6DAA6D;AACnI;AACA;AACA;AACA,2BAA2B,iBAAW;AACtC;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,UAAU;AACvB,eAAe,0BAA0B;AACzC;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,wBAAwB;AACrC,aAAa,0CAA0C,eAAe,6DAA6D;AACnI,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ;AACR,QAAQ,GAAG,qCAAqC,UAAU;AAC1D;AACA;AACA;;AAEA;AACA;AACA,aAAa,iBAAiB;AAC9B;AACA;;AAEA;AACA,IAAI,WAAW;AACf;AACA;AACA;AACA,gBAAgB,MAAM;AACtB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA,wBAAwB,UAAU;AAClC;;AAEA;AACA;AACA;AACA,uBAAuB,UAAU;AACjC;AACA;AACA,KAAK;;AAEL;AACA;AACA,oBAAoB,yBAAC;AACrB;AACA;AACA;AACA,UAAU,WAAW;AACrB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA,wCAAwC,UAAU;AAClD;AACA;AACA;AACA;AACA;AACA;AACA,6BAA6B,UAAU;AACvC;AACA;AACA,WAAW;;AAEX;AACA;AACA,0BAA0B,yBAAC;AAC3B;AACA;AACA;AACA;;AAEA;AACA,+BAA+B,UAAU;AACzC,oCAAoC,UAAU;AAC9C;AACA;;AAEA;AACA;AACA;AACA,+BAA+B,UAAU,wBAAwB,QAAQ;;AAEzE;AACA,iCAAiC,yBAAC;AAClC;AACA;AACA;AACA,wCAAwC,UAAU;AAClD;AACA;AACA,0CAA0C,UAAU;AACpD,6CAA6C,UAAU;AACvD,2CAA2C,UAAU;AACrD;AACA;AACA,4CAA4C,QAAQ;AACpD;AACA;AACA,iBAAiB;AACjB;;AAEA;AACA;AACA;AACA,uCAAuC,UAAU,wBAAwB,QAAQ;AACjF,qCAAqC,UAAU;AAC/C,8BAA8B,UAAU;AACxC;AACA,iCAAiC,yBAAC;AAClC;AACA;AACA,oDAAoD,QAAQ;AAC5D;AACA;AACA,kDAAkD,KAAK;AACvD;AACA;AACA;AACA,4CAA4C,SAAS;AACrD;AACA;AACA,iBAAiB;AACjB;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW;AACX;;AAEA;AACA;AACA,uCAAuC,yBAAC;AACxC;AACA;AACA,WAAW;AACX;;AAEA;AACA;AACA,qBAAqB,8BAAmB;AACxC;AACA;AACA;;AAEA;AACA;AACA;AACA,8BAA8B,sBAAgB;AAC9C;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,0BAA0B,UAAU;AACpC,0BAA0B,UAAU;AACpC;;AAEA;AACA,UAAU,WAAW;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA,6BAA6B,UAAU;AACvC;AACA,WAAW;AACX;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW;AACX;;AAEA;AACA;AACA;AACA;AACA,yBAAyB,qBAAe;AACxC;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAuC,yBAAC;AACxC;AACA,WAAW;AACX;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,2CAA2C,aAAO,iBAAiB,yBAAC;AACpE;AACA;AACA;AACA;AACA,6CAA6C,kBAAkB;AAC/D;AACA;AACA,WAAW;AACX;;AAEA;AACA,oBAAoB,cAAS;AAC7B;;AAEA;AACA;AACA,8BAA8B,yBAAoB;AAClD;AACA;AACA,KAAK;AACL;AACA;;AAEA;AACA;AACA,aAAa,iBAAiB;AAC9B,eAAe;AACf;AACA;AACA,oBAAoB,sBAAgB;AACpC;AACA;AACA;AACA,QAAQ,aAAa;AACrB,sBAAsB,aAAO;AAC7B;AACA;;AAEA;AACA;AACA;AACA;AACA,eAAe,QAAQ;AACvB;AACA;AACA,WAAW,OAAO;AAClB;AACA;AACA;AACA;AACA,gBAAgB,QAAQ,gBAAgB;AACxC;AACA;AACA;AACA;AACA;AACA,iBAAiB,QAAQ,kBAAkB;AAC3C;AACA,yBAAyB,QAAQ,kBAAkB;AACnD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB;AACA;AACA,IAAI,OAAO;AACX;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ,uBAAuB,QAAQ,EAAE;AACzC,QAAQ,+BAA+B,QAAQ,EAAE;AACjD,QAAQ,6BAA6B,KAAK,EAAE;AAC5C,QAAQ,uBAAuB,SAAS,EAAE;AAC1C,QAAQ,qBAAqB,sBAAgB,oDAAoD;AACjG,QAAQ,gBAAgB,sBAAgB,oDAAoD;AAC5F,QAAQ,gBAAgB,8BAAmB,sBAAsB;AACjE;AACA,QAAQ,gBAAgB,qBAAe,EAAE;AACzC;AACA;AACA,QAAQ,4BAA4B,aAAO,EAAE;AAC7C,QAAQ,eAAe,cAAS,EAAE;AAClC,QAAQ,qBAAqB,yBAAoB,sBAAsB;AACvE;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA,sBAAsB,oFAAoF;AAC1G;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,gCAAgC,UAAU,sCAAsC;AAC7F;AACA;AACA;AACA,IAAI,8BAAM;AACV;AACA,KAAK;AACL,IAAI,8BAAM;AACV;AACA;AACA,KAAK;AACL;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA,eAAe,SAAS;AACxB;;AAEA;AACA;AACA,aAAa,sBAAsB;AACnC;AACA;AACA,0BAA0B,SAAS;AACnC;;AAEA;AACA,iBAAiB,mDAAmD;AACpE;AACA,aAAa,gCAAgC,UAAU,kDAAkD;AACzG,eAAe;AACf;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,UAAU;AACV;AACA;AACA;AACA;;AAEA;AACA;AACA,UAAU,6DAA6D;AACvE;AACA,YAAY,0CAA0C;AACtD;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB,QAAQ,QAAQ;AAChB;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB,UAAU,QAAQ;AAClB;AACA;AACA;AACA,YAAY,QAAQ;AACpB,WAAW,QAAQ;AACnB;AACA;AACA;AACA,YAAY,qBAAqB;AACjC;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,kBAAkB;AAC9B;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA,2CAA2C;AAC3C;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA,sBAAsB,wDAAwD;AAC9E;AACA;AACA,YAAY,sCAAsC;AAClD;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA;AACA,YAAY,OAAO;AACnB;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA;AACA,YAAY,OAAO;AACnB;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,kDAAkD;AAC9D;AACA;AACA;AACA;AACA,YAAY,sBAAsB;AAClC,kBAAkB,SAAS,CAAC,QAAQ,gBAAgB,QAAQ;AAC5D;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB,mBAAmB,QAAQ;AAC3B;AACA;AACA;AACA,YAAY,qBAAqB;AACjC;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,2DAA2D;AACvE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,kDAAkD;AAC9D;AACA;AACA;AACA;AACA,YAAY,8CAA8C;AAC1D;AACA;AACA;AACA;AACA,YAAY,kEAAkE;AAC9E;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB,YAAY,QAAQ;AACpB;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA,yDAAyD;AACzD;AACA,YAAY,UAAU;AACtB;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA,CAAC;;AAED;AACA;AACA;AACA;AACA,cAAc;AACd,YAAY,0FAA0F;AACtG;AACA;AACA;AACO,4BAA4B,SAAS;AAC5C;AACA;AACA,aAAa,0BAA0B,WAAW,yCAAyC;AAC3F,aAAa,gCAAgC;AAC7C,MAAM;AACN;AACA,aAAa,iBAAiB;AAC9B;AACA;AACA;AACA;AACA;AACA;AACA,2BAA2B,SAAS;AACpC,6BAA6B,SAAS;AACtC;AACA;AACA;AACA,kBAAkB,yBAAC,aAAa,sCAAsC,MAAM,oBAAoB;AAChG;AACA;;AAEA;AACA;AACA,aAAa,sBAAsB;AACnC;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,0BAA0B,mCAAmC;AAC7D,aAAa,sBAAsB;AACnC;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,gBAAgB,kDAAkD;AAClE;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,sBAAsB;AACnC,eAAe;AACf;AACA;AACA,eAAe,SAAS;AACxB;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS,QAAQ,iBAAiB,iCAAS;AAC3C;AACA;;AAEA;AACA;AACA,aAAa,iBAAiB;AAC9B,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA,aAAa,QAAQ;AACrB,UAAU,QAAQ;AAClB,YAAY,iCAAS;AACrB;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA,aAAa,gBAAgB;AAC7B,eAAe,SAAS;AACxB,6CAA6C;AAC7C;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,sBAAsB;AACnC,aAAa,sBAAsB;AACnC;AACA;AACA,uBAAuB,KAAK;AAC5B;AACA;AACA;AACA;AACA;AACA;AACA,oCAAoC,SAAS;AAC7C,qCAAqC,QAAQ;AAC7C,qCAAqC,QAAQ;AAC7C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uBAAuB,SAAS;;AAEhC;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,SAAS;AACtB;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,SAAS;AACtB,aAAa,SAAS;AACtB,aAAa,SAAS;AACtB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,0CAA0C;AACvD,aAAa,SAAS;AACtB,aAAa,SAAS;AACtB;AACA;AACA;AACA;AACA;AACA;AACA,0BAA0B,0CAA0C;AACpE;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY,0BAA0B;AACtC;AACA;AACA;AACA;AACA,YAAY,iBAAiB;AAC7B;AACA;AACA;AACA;AACA,YAAY,iBAAiB;AAC7B;AACA;AACA;AACA;AACA;AACA,YAAY;AACZ;AACA;AACA;AACA,2BAA2B;AAC3B;AACA,YAAY,wBAAwB;AACpC;AACA;AACA;AACA;AACA,YAAY,iBAAiB;AAC7B;AACA;AACA;AACA;AACA,YAAY,iBAAiB;AAC7B;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,2BAA2B;AACvC;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,wCAAwC;AACpD;AACA;AACA;AACA,iBAAiB;AACjB;AACA,YAAY,gCAAgC;AAC5C;AACA;AACA;AACA;AACA,YAAY,sBAAsB;AAClC;AACA;AACA;AACA;AACA,YAAY,sBAAsB;AAClC;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,UAAU;AACtB;AACA;AACA;AACA;AACA,CAAC;;AAED;AACA;AACA,UAAU,+BAA+B;AACzC;;AAEA,mDAAe,QAAQ,EAAC;;;AC9xCxB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEuB;AACgD;;AAEvE;AACA;AACA;AACA,sBAAsB,kDAAkD;AACxE;AACO;AACP;AACA;AACA,aAAa,gCAAgC;AAC7C;AACA;AACA;AACA;AACA;AACA;AACA,MAAM,yBAAC;AACP;AACA;AACA;AACA,OAAO;AACP;AACA;;AAEA;AACA;AACA;AACA,aAAa,8BAA8B;AAC3C;AACA;AACA,IAAI,GAAG;AACP;AACA;AACA,MAAM,YAAY;AAClB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,2BAA2B,wEAAwE;AACnG,MAAM;AACN,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA,gCAAgC;AAChC;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,oBAAoB,wEAAwE;AAC5F,mCAAmC,kDAAkD;AACrF;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ,YAAY;AACpB;AACA;AACA;AACA,UAAU,GAAG,sCAAsC,cAAc;AACjE;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,6BAA6B,8CAA8C,qBAAqB,kDAAkD;AAClJ;AACA,aAAa,+BAA+B;AAC5C,aAAa,SAAS;AACtB;AACA,eAAe,SAAS;AACxB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,GAAG;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY;AACZ;AACA,cAAc,GAAG,sCAAsC,eAAe;AACtE,cAAc;AACd;AACA,iCAAiC,OAAO;AACxC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ,gBAAgB,sEAAsE;AAC3G,aAAa,QAAQ;AACrB,iEAAiE,sEAAsE;AACvI;AACA,aAAa,SAAS;AACtB;AACA;AACA;AACA,QAAQ,aAAa,cAAc,aAAa;AAChD;AACA,QAAQ,aAAa;AACrB;AACA;AACA;AACA,WAAW,aAAa;AACxB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,UAAU,kDAAkD;AAC5D;AACA,YAAY,gCAAgC;AAC5C;AACA;AACA;AACA;AACA;AACA,YAAY,qDAAqD;AACjE;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAe,QAAQ;AACvB,eAAe,QAAQ;AACvB,eAAe,QAAQ,+DAA+D;AACtF,eAAe,QAAQ,6CAA6C,4BAA4B;AAChG;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;;AAED,wDAAe,aAAa,EAAC;;;AChT7B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEuD;AAChB;;AAEvC;AACA,+CAA+C,0EAA0E;AACzH,IAAI,6DAA6D,IAAI,wCAAwC;AAC7G;AACO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,oBAAoB,0EAA0E;AAC9F,aAAa,wCAAwC;AACrD,aAAa,+BAA+B;AAC5C,aAAa,gCAAgC;AAC7C;AACA,gBAAgB,iDAAiD;AACjE,eAAe;AACf;AACA;AACA;AACA;AACA;AACA,2CAA2C,QAAQ;AACnD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kBAAkB,uBAAiB;AACnC;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,oCAAoC,0EAA0E;AAC9G;AACA,aAAa,wCAAwC;AACrD,aAAa,+BAA+B;AAC5C,aAAa,gCAAgC;AAC7C,MAAM,8FAA8F;AACpG,gBAAgB,iDAAiD;AACjE,eAAe;AACf;AACA;AACA;AACA;AACA;;AAEA;AACA,2CAA2C,0EAA0E,0BAA0B,6CAA6C;AAC5L,aAAa,wCAAwC;AACrD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,uBAAiB;AACrB;AACA;;AAEA;AACA;AACA,wBAAwB,0EAA0E;AAClG;AACA,YAAY,oDAAoD;AAChE;AACA,CAAC;;AAED,2DAAe,cAAc,EAAC;;;;;;;;;;;;;;;;;;;;;AChJ9B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEuB;AACiI;AAC5F;;AAE5D;AAC0C;AACM;AACF;AACO;AACJ;AACN;AACgB;AACN;AACR;;AAE7C;AACA;AACA;AACA;AACA,wCAAwC,uDAAuD;AAC/F;AACA;AACA;AACO,mBAAmB,SAAS;AACnC;AACA;AACA,aAAa,gCAAgC,qCAAqC,iDAAiD;AACnI;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB;AACA,2CAA2C;;AAE3C;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA,qCAAqC,0BAA0B,kBAAkB,2BAA2B,IAAI,EAAE,WAAW;AAC7H;AACA;AACA,qCAAqC,qBAAqB,kBAAkB,sBAAsB,IAAI,EAAE,MAAM;AAC9G,MAAM,iBAAiB,0BAA0B,YAAY;AAC7D;;AAEA;;AAEA,gBAAgB,yBAAC,aAAa,oBAAoB;AAClD,sBAAsB,yBAAC,aAAa,yBAAyB;;AAE7D;AACA,qBAAqB,yBAAC,kBAAkB,sBAAsB;AAC9D,aAAa,iBAAiB;AAC9B,sBAAsB,yBAAC;AACvB,aAAa,gFAAgF;AAC7F,cAAc,yBAAC,aAAa,oBAAoB,QAAQ,6CAA6C;AACrG,gBAAgB,yBAAC,aAAa,qBAAqB;AACnD,kBAAkB,yBAAC,mBAAmB,yBAAC;AACvC;AACA;;AAEA,mBAAmB,WAAW;AAC9B,oBAAoB,WAAW;AAC/B,mBAAmB,WAAW;;AAE9B;AACA,uBAAuB,yBAAC,aAAa,qBAAqB;AAC1D;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA,KAAK;;AAEL,oBAAoB,yBAAC;AACrB;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA,KAAK;;AAEL,yBAAyB,yBAAC,aAAa,yDAAyD;AAChG,2BAA2B,yBAAC,aAAa,6CAA6C;;AAEtF;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,UAAU,MAAM;AAChB,qBAAqB,yBAAC,aAAa,mBAAmB;AACtD,cAAc,yBAAC,aAAa,qCAAqC;AACjE,gBAAgB,yBAAC,iBAAiB,mBAAmB,QAAQ,6DAA6D;AAC1H;AACA;AACA,YAAY,WAAW;AACvB,YAAY,GAAG;AACf,WAAW;AACX,gBAAgB,yBAAC;AACjB,cAAc,yBAAC,eAAe,yCAAyC;AACvE,gBAAgB,yBAAC,WAAW,0CAA0C;AACtE,gBAAgB,yBAAC;AACjB,gBAAgB,yBAAC,oBAAoB,MAAM,aAAa,EAAE,QAAQ,SAAS;;AAE3E,yBAAyB,yBAAC,aAAa,yCAAyC;;AAEhF,UAAU,MAAM;AAChB,oBAAoB,yBAAC,gBAAgB,+BAA+B;AACpE,cAAc,yBAAC,sBAAsB,+BAA+B;AACpE;AACA;AACA,0CAA0C,MAAM,4GAA4G,SAAS,mBAAmB;AACxL,8DAA8D,kBAAkB;AAChF,SAAS;AACT;AACA;AACA,YAAY,yBAAC,aAAa,qBAAqB;AAC/C,oBAAoB,MAAM;AAC1B;AACA;AACA,qCAAqC,yBAAC,kBAAkB;AACxD;AACA,YAAY,yBAAC,aAAa,qBAAqB;AAC/C,uEAAuE,IAAI;AAC3E;AACA;AACA,qCAAqC,yBAAC,kBAAkB;AACxD,OAAO;;AAEP,UAAU,MAAM;AAChB,wBAAwB,yBAAC,gBAAgB,+BAA+B;AACxE,cAAc,yBAAC,6BAA6B,+BAA+B;AAC3E;;AAEA,UAAU,MAAM;AAChB,qBAAqB,yBAAC,gBAAgB,+BAA+B;AACrE,cAAc,yBAAC,0BAA0B,+BAA+B;AACxE;;AAEA,UAAU,MAAM;AAChB,yBAAyB,yBAAC,gBAAgB,+BAA+B;AACzE,cAAc,yBAAC,6BAA6B,+BAA+B;AAC3E;;AAEA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,UAAU;AACvB,eAAe,wBAAwB;AACvC;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,gCAAgC,+CAA+C,iDAAiD;AAC7I,eAAe,SAAS;AACxB;AACA;AACA;AACA,iBAAiB,WAAW;AAC5B;AACA,4BAA4B,cAAc;;AAE1C;AACA;AACA;AACA;AACA;;AAEA;AACA,MAAM,GAAG,yBAAyB,OAAO,kDAAkD,eAAe;AAC1G;AACA,MAAM;AACN;;AAEA;AACA;;AAEA;AACA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,gCAAgC,iCAAiC,iDAAiD;AAC/H,aAAa,QAAQ;AACrB,eAAe;AACf;AACA,uDAAuD;AACvD;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kCAAkC;AAClC,kCAAkC,6BAA6B;AAC/D;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ,GAAG,gCAAgC,SAAS;AACpD;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA,iBAAiB,kDAAkD;AACnE,aAAa,gCAAgC;AAC7C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,SAAS;AACtB;AACA;AACA;AACA,cAAc;AACd;AACA;;AAEA;AACA;AACA;;AAEA,IAAI,SAAS;AACb,IAAI,SAAS;AACb,IAAI,SAAS;AACb,IAAI,SAAS;AACb,IAAI,SAAS;AACb,IAAI,SAAS;AACb;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,wCAAwC;AACxC;AACA,aAAa,sBAAsB;AACnC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,SAAS;AACtB;AACA;AACA,IAAI,8BAAM;AACV;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA,aAAa,SAAS;AACtB;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT,MAAM;AACN;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA;AACA,6BAA6B,iBAAiB;AAC9C;AACA;AACA;AACA,gDAAgD,oBAAoB;AACpE;AACA;AACA;AACA,MAAM,GAAG,uBAAuB,qBAAqB,GAAG,iBAAiB;AACzE;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,iBAAiB;AAC9B;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,SAAS;AACtB,aAAa,QAAQ;AACrB;AACA;AACA,eAAe,kBAAkB;AACjC;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,+BAA+B,iBAAiB;AAChD;AACA;AACA;AACA;AACA,6BAA6B,oBAAoB;AACjD,KAAK;AACL;;AAEA;AACA;AACA;AACA,aAAa,SAAS;AACtB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,iCAAiC;AAC9C,eAAe,kBAAkB,2BAA2B,qCAAqC;AACjG;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA,aAAa,iCAAiC;AAC9C,eAAe,mBAAmB;AAClC;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,kBAAkB,yBAAC,aAAa,yDAAyD,OAAO,MAAM;;AAEtG,iBAAiB,yBAAC,eAAe,0BAA0B;AAC3D;AACA,QAAQ,KAAK;AACb,UAAU,MAAM;AAChB,aAAa,8BAA8B,EAAE,6BAA6B;AAC1E,QAAQ,KAAK;AACb,UAAU,MAAM;AAChB,aAAa,MAAM,yBAAyB,EAAE,yBAAyB;AACvE;AACA,kBAAkB,KAAK;AACvB,UAAU,MAAM;AAChB;AACA;AACA,kBAAkB,KAAK;AACvB,UAAU,MAAM;AAChB;;AAEA;AACA;AACA,oBAAoB,KAAK;AACzB,YAAY,MAAM;AAClB;AACA;AACA,UAAU,KAAK;AACf,YAAY,MAAM;AAClB;AACA,UAAU,KAAK;AACf,YAAY,MAAM;AAClB;AACA,UAAU,KAAK;AACf,YAAY,MAAM;AAClB,eAAe,kBAAkB,GAAG,mBAAmB,GAAG,UAAU,2BAA2B;AAC/F;AACA,oBAAoB,KAAK;AACzB,YAAY,MAAM;AAClB,eAAe,yBAAyB,GAAG,UAAU,2BAA2B;AAChF;AACA;AACA,cAAc,KAAK;AACnB,gBAAgB,MAAM;AACtB,mBAAmB,UAAU,6BAA6B,EAAE,MAAM,+BAA+B;AACjG,cAAc,KAAK;AACnB,gBAAgB,MAAM;AACtB,mBAAmB,UAAU,4BAA4B,EAAE,MAAM,oCAAoC;AACrG;AACA,YAAY,KAAK;AACjB,cAAc,MAAM;AACpB,cAAc,UAAU;AACxB,YAAY,KAAK;AACjB,cAAc,MAAM;AACpB;AACA;AACA;;AAEA;AACA;AACA,uBAAuB,yBAAC,eAAe,qBAAqB;AAC5D,wBAAwB,yBAAC,8CAA8C,MAAM,aAAa,EAAE,eAAe;AAC3G,sBAAsB,yBAAC,oBAAoB,yBAAC;AAC5C,cAAc,KAAK,IAAI,MAAM;AAC7B,cAAc,KAAK,IAAI,MAAM;AAC7B,cAAc,KAAK,IAAI,MAAM;AAC7B,cAAc,KAAK,IAAI,MAAM;AAC7B,cAAc,KAAK,IAAI,MAAM;AAC7B,cAAc,KAAK,IAAI,MAAM;;AAE7B;AACA,wBAAwB,yBAAC,iBAAiB,yBAAC,YAAY,gCAAgC;AACvF;AACA;AACA,6BAA6B,KAAK;AAClC,0CAA0C,KAAK,IAAI,MAAM,iBAAiB,KAAK,IAAI,MAAM;AACzF,6BAA6B,KAAK;AAClC,6BAA6B,KAAK,IAAI,UAAU;AAChD,6BAA6B,KAAK,IAAI,UAAU;AAChD,kBAAkB;AAClB,6BAA6B,KAAK;AAClC,kCAAkC,OAAO;AACzC,+BAA+B,KAAK;AACpC;AACA;AACA,sBAAsB,yBAAC;AACvB,eAAe;AACf,aAAa;;AAEb,sBAAsB,yBAAC;AACvB,cAAc,KAAK,IAAI,MAAM;AAC7B,cAAc,KAAK,OAAO,WAAW,GAAG,UAAU,uBAAuB;AACzE,cAAc,KAAK,OAAO,WAAW,GAAG,UAAU,uBAAuB;AACzE,cAAc,KAAK;AACnB,cAAc,KAAK,IAAI,UAAU;AACjC,cAAc,KAAK,IAAI,UAAU;;AAEjC;AACA;AACA,SAAS;AACT,QAAQ;AACR,oBAAoB,yBAAC,cAAc,MAAM;AACzC;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,SAAS;AACtB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,kCAAkC,yBAAC,mBAAmB,SAAS,YAAY,UAAU;AACrF,oCAAoC,SAAS;AAC7C;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;;AAEA;AACA;AACA,eAAe,sBAAsB;AACrC;AACA;AACA;AACA,eAAe,SAAS;AACxB;;AAEA;AACA;AACA,MAAM,mEAAmE;AACzE,aAAa,SAAS;AACtB;AACA,eAAe,SAAS;AACxB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ;AACR;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,mBAAmB;AAChC;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,iBAAiB;AAC9B;AACA,aAAa,SAAS;AACtB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,wBAAwB;AACrC,eAAe,SAAS;AACxB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,eAAe,kDAAkD;AACjE,eAAe;AACf;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,UAAU;AACV;AACA;;AAEA;AACA;AACA,UAAU;AACV;AACA;;AAEA;AACA;AACA,UAAU;AACV;AACA;;AAEA;AACA;AACA,UAAU;AACV;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,iBAAiB;AAC7B;AACA;AACA;AACA;AACA,YAAY,iBAAiB;AAC7B;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB,aAAa;AACb;AACA;AACA;AACA,YAAY,iBAAiB;AAC7B;AACA;AACA;AACA;AACA,YAAY,iBAAiB;AAC7B;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,kCAAkC;AAC9C;AACA;AACA;AACA;AACA,YAAY,iBAAiB;AAC7B;AACA;AACA;AACA;AACA,YAAY,iBAAiB;AAC7B;AACA;AACA;AACA;AACA,YAAY,iBAAiB;AAC7B;AACA;AACA;AACA;AACA,YAAY,iBAAiB;AAC7B;AACA;AACA;AACA;AACA,YAAY,iBAAiB;AAC7B;AACA;AACA;AACA;AACA,YAAY,iBAAiB;AAC7B;AACA;AACA;AACA;AACA,YAAY,iBAAiB;AAC7B;AACA;AACA;AACA;AACA,YAAY,iBAAiB;AAC7B;AACA;AACA;AACA;AACA,YAAY,iBAAiB;AAC7B;AACA;AACA;AACA;AACA,YAAY,iBAAiB;AAC7B;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA,iBAAiB,sDAAsD;AACvE;AACA,YAAY,iBAAiB;AAC7B;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,GAAG;AACH;AACA,UAAU,kDAAkD;AAC5D;AACA,YAAY,gCAAgC;AAC5C;AACA;AACA,UAAU;AACV;AACA;AACA,YAAY,gCAAgC;AAC5C;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB,UAAU;AACV;AACA;AACA;AACA,YAAY,QAAQ;AACpB,aAAa;AACb;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB,YAAY;AACZ;AACA;AACA;AACA,YAAY,QAAQ;AACpB,cAAc;AACd;AACA;AACA;AACA,YAAY,QAAQ;AACpB,YAAY;AACZ;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB,iBAAiB;AACjB;AACA;AACA;AACA,YAAY,QAAQ;AACpB,cAAc;AACd;AACA;AACA;AACA,YAAY,QAAQ;AACpB,UAAU;AACV;AACA;AACA;AACA,YAAY,QAAQ;AACpB,SAAS;AACT;AACA;AACA;AACA,YAAY,QAAQ;AACpB,eAAe,yBAAyB;AACxC;AACA;AACA;AACA,YAAY,QAAQ;AACpB,oBAAoB,yBAAyB;AAC7C,CAAC;;AAED,iDAAe,IAAI,EAAC;;;AC5/BpB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEuB;AAC2B;AACyF;;AAE3I;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA,aAAa,0CAA0C;AACvD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,iBAAiB;AAC9B;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,+BAA+B,cAAc;AAC7C;AACA;AACA,UAAU,yBAAC,iEAAiE,YAAY;AACxF;AACA;AACA,4BAA4B,oBAAoB,CAAC,YAAY;AAC7D;AACA;AACA,kCAAkC,oBAAoB,CAAC,YAAY;AACnE;AACA;AACA,2BAA2B,oBAAoB,CAAC,YAAY;AAC5D;AACA,4BAA4B,YAAY;AACxC;AACA;AACA;AACA,8BAA8B,mBAAmB;AACjD;AACA;AACA,iCAAiC,iBAAW;AAC5C,yCAAyC,yBAAC;AAC1C;AACA;AACA,8BAA8B,yBAAC;AAC/B;AACA;AACA,sBAAsB,YAAY;AAClC;AACA;AACA;AACA;AACA;AACA;AACA,yBAAyB,cAAc;AACvC;AACA;AACA;AACA,sBAAsB,cAAc;AACpC;AACA;AACA;AACA;AACA,KAAK;;AAEL;;AAEA;AACA;AACA;AACA,KAAK;;AAEL;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY;AACZ,YAAY,GAAG,+BAA+B,KAAK;AACnD;AACA;AACA,OAAO;AACP;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,eAAe,QAAQ;AACvB;AACA;AACA,WAAW,OAAO;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA,IAAI,OAAO;AACX;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,OAAO;;AAEP;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY,0CAA0C;AACtD;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,UAAU;AACtB;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,UAAU;AACtB;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,UAAU;AACtB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,UAAU;AACtB;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA,MAAM;AACN;AACA,YAAY,UAAU;AACtB;AACA;AACA,mGAAmG;AACnG;AACA,YAAY,QAAQ;AACpB;AACA;AACA,eAAe,wDAAwD;AACvE;AACA,YAAY,sCAAsC;AAClD,mBAAmB,iBAAW;AAC9B,CAAC;;AAED,8DAAe,eAAe,EAAC;;;AChR/B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEuD;;AAEvD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT,SAAS;AACT;AACO;AACP;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,eAAe;AAC5B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,iBAAiB;AAC9B;AACA;AACA;AACA;AACA;AACA,sBAAsB,MAAM;AAC5B;AACA,yBAAyB,MAAM;AAC/B;AACA;;AAEA;AACA;AACA;AACA;AACA,eAAe,QAAQ;AACvB;AACA;AACA,WAAW,OAAO;AAClB;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB;AACA;AACA;AACA,WAAW,OAAO;AAClB;AACA,KAAK;AACL;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA,CAAC;;AAED,oDAAe,QAAQ,EAAC;;;ACvIxB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEqC;AACU;;AAE/C;AACA,yBAAyB,8CAA8C,YAAY,kFAAkF;AACrK;AACA;AACA;AACA,gCAAgC,8CAA8C;AAC9E;AACA;AACA;AACA,IAAI,kFAAkF;AACtF;AACA;AACO,kCAAkC,aAAQ;AACjD;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,eAAe;AAC5B;AACA,aAAa,QAAQ;AACrB;AACA,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,iBAAiB;AAC9B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,eAAe,QAAQ;AACvB;AACA;AACA,gDAAgD,OAAO;AACvD;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA,WAAW,OAAO;AAClB;AACA,KAAK;AACL;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA,CAAC;;AAED,+DAAe,mBAAmB,EAAC;;;AChHnC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEuB;AACc;AACsB;AACrB;;AAEtC;AACA,8BAA8B,6CAA6C,gBAAgB,2FAA2F;AACtL;AACA;AACA;AACA,2DAA2D,+EAA+E;AAC1I;AACA;AACA;AACA;AACO,mCAAmC,aAAQ;AAClD;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,eAAe;AAC5B;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,iBAAiB;AAC9B;AACA;AACA;;AAEA;AACA;AACA,0BAA0B,wBAAmB,iBAAiB,yBAAC;AAC/D;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;;AAEA;AACA;AACA;AACA;AACA,eAAe,QAAQ;AACvB;AACA;AACA,gDAAgD,OAAO;AACvD;;AAEA;AACA;AACA,cAAc,QAAQ;AACtB;AACA;AACA;;AAEA;AACA;AACA,uBAAuB,wBAAmB;AAC1C,KAAK;;AAEL;AACA;;;AAGA;AACA,oBAAoB,8CAA8C;AAClE;AACA,aAAa,QAAQ;AACrB;AACA,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ;AACR;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY,qDAAqD;AACjE;AACA;AACA;AACA;AACA,YAAY,qDAAqD;AACjE;AACA,CAAC;;AAED,gEAAe,oBAAoB,EAAC;;;AC3IpC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEuB;AACsC;AACO;;AAEpE;AACA;AACA,yCAAyC,sEAAsE;AAC/G;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO;AACP;AACA;;AAEA;AACA;AACA,aAAa,iBAAiB;AAC9B;AACA;;AAEA;AACA,IAAI,WAAW;AACf;AACA;AACA,wBAAwB,MAAM;AAC9B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA,sBAAsB,yBAAoB,iBAAiB,yBAAC;AAC5D;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;;AAEA;AACA;AACA;AACA;AACA,eAAe,QAAQ;AACvB;AACA;AACA,WAAW,OAAO;AAClB;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB;AACA;AACA;AACA,WAAW,OAAO;AAClB;AACA,KAAK;;AAEL;AACA;AACA,wBAAwB,yBAAoB;AAC5C;AACA,KAAK;AACL;AACA;AACA;;AAEA;AACA;AACA,wDAAwD,qEAAqE;AAC7H;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA,kBAAkB,yCAAyC;AAC3D;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,uDAAuD;AACnE;AACA;AACA;AACA;AACA,YAAY,uDAAuD;AACnE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA,CAAC;;AAED,mEAAe,uBAAuB,EAAC;;;AChKvC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEuB;AACc;AAC8B;AACN;AACxB;;AAErC;AACA;AACA,IAAI,4DAA4D;AAChE,IAAI,0FAA0F;AAC9F;AACA;AACO;AACP;AACA;AACA,aAAa,0CAA0C;AACvD;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,iBAAiB;AAC9B;AACA;AACA,oEAAoE,4BAAuB,iBAAiB,yBAAC;AAC7G;AACA;;AAEA;AACA;AACA;AACA;AACA,eAAe,QAAQ;AACvB;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB;AACA;AACA,8CAA8C,4BAAuB;AACrE;AACA;;AAEA;AACA;AACA,aAAa,6DAA6D;AAC1E,eAAe,QAAQ;AACvB;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,SAAS;AACtB,eAAe,6DAA6D;AAC5E;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,SAAS;AACtB,eAAe,6DAA6D;AAC5E;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,MAAM;AAClB;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe,6DAA6D;AAC5E;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,SAAS;AACtB;AACA,eAAe,SAAS;AACxB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,SAAS;AACtB;AACA,eAAe,SAAS;AACxB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe,QAAQ,iCAAiC,wFAAwF;AAChJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,SAAS;AACtB;AACA,aAAa,iCAAiC;AAC9C;AACA,eAAe,+BAA+B;AAC9C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB,aAAQ;AAC7B,QAAQ;AACR;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,eAAe,QAAQ;AACvB;AACA;AACA;AACA;AACA,wBAAwB,wBAAwB;AAChD;AACA;AACA;AACA;;AAEA;AACA,qBAAqB,2FAA2F;AAChH;AACA;AACA,aAAa,QAAQ;AACrB,eAAe,6DAA6D;AAC5E;AACA;AACA;AACA;AACA,sBAAsB,6CAA6C;AACnE;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA,sBAAsB,0BAA0B;AAChD;AACA;AACA;AACA;AACA;AACA,gBAAgB,4BAAuB;AACvC;AACA,wBAAwB,yBAAoB;AAC5C,yBAAyB,yBAAoB;AAC7C;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,0BAA0B,2FAA2F;AACrH;AACA,YAAY,+DAA+D;AAC3E;AACA;AACA;AACA;AACA,YAAY,0CAA0C;AACtD;AACA;AACA,qBAAqB,2FAA2F;AAChH;AACA;AACA,YAAY,QAAQ;AACpB;AACA,CAAC;;AAED,4DAAe,gBAAgB,EAAC;;;AC7ThC,MAAM,oCAA4B,6C;;;ACAlC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEwD;AACtB;;AAElC;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA,aAAa,sBAAsB;AACnC,aAAa,QAAQ,WAAW;AAChC;AACA;AACA;AACA;AACA;AACA,gCAAgC;AAChC;AACA;AACA;AACA;AACA;AACA,wBAAwB,uCAAiB;AACzC;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,uBAAuB;AACpC;AACA,uCAAuC;AACvC;AACA;AACA;AACA,MAAM,wCAAoB;AAC1B;AACA;AACA,WAAW,+DAA+D,GAAG,+DAA+D,EAAE,yEAAyE;AACvN;AACA,UAAU,GAAG;AACb;AACA,SAAS;AACT;AACA,UAAU,GAAG,sDAAsD,IAAI;AACvE,SAAS;AACT;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oIAAoI,iDAAiD;AACrL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY,sBAAsB;AAClC;AACA;AACA;AACA;AACA,YAAY,uBAAuB;AACnC;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA;AACA,YAAY,YAAY;AACxB;AACA,CAAC;;AAED;AACA,QAAQ,6BAA6B;AACrC,UAAU;AACV;AACA;;AAEA;AACA;AACA;AACA,UAAU;AACV;AACA;;AAEA;AACA,6CAA6C;AAC7C,UAAU;AACV;AACA;;AAEA;AACA,yDAAyD;AACzD;AACA;AACA,UAAU;AACV;AACA;;AAEA;AACA;AACA;AACA,UAAU;AACV;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,UAAU;AACV;AACA;;AAEA;AACA;AACA;AACA;AACA,UAAU;AACV;AACA;;AAEA,4DAAe,eAAe,EAAC;;;AC7P/B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEuB;AACmC;AAC6D;AACtF;;AAEjC;AACA,+CAA+C,6CAA6C;AAC5F;AACA;AACA;AACA,qCAAqC,6DAA6D;AAClG;AACA;AACO;AACP;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,gBAAgB;AAC7B;AACA;AACA;AACA;AACA;AACA,kBAAkB,MAAM;AACxB,kBAAkB,MAAM;AACxB;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gCAAgC,QAAQ;AACxC;;;AAGA;AACA,8BAA8B,0FAA0F;AACxH;AACA;AACA,YAAY;AACZ;AACA;;AAEA;AACA,sBAAsB;AACtB;AACA,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,8BAA8B,4CAA4C;AAC1E;AACA;AACA,YAAY;AACZ;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,iBAAiB;AAC9B;AACA;AACA,gBAAgB,MAAM;AACtB,gBAAgB,MAAM;AACtB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,eAAe,QAAQ;AACvB;AACA;AACA,WAAW,OAAO;AAClB;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB;AACA;AACA;AACA,WAAW,OAAO;AAClB;AACA,KAAK;;AAEL;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,gBAAgB;AAChB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oDAAoD,uBAAuB;AAC3E;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAc,GAAG,oCAAoC,UAAU;AAC/D;AACA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA;AACA,qBAAqB,QAAQ;AAC7B,UAAU,QAAQ;AAClB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,UAAU;AACvB,aAAa,gCAAgC,kDAAkD,iDAAiD;AAChJ,aAAa,SAAS,yEAAyE,yDAAyD;AACxJ,aAAa,QAAQ;AACrB;AACA;AACA;AACA,QAAQ,QAAQ;AAChB;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kCAAkC,eAAe,cAAc,EAAE,UAAU,SAAS,YAAY,OAAO,IAAI;;AAE3G,cAAc,iBAAiB;AAC/B,8BAA8B,IAAI;AAClC;AACA;;AAEA;AACA;AACA,yDAAyD,2BAA2B,IAAI,YAAY;AACpG;AACA;;AAEA;AACA;AACA,4DAA4D,2BAA2B,IAAI,YAAY;AACvG;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kBAAkB,GAAG,oCAAoC,OAAO,kBAAkB,SAAS;AAC3F;AACA;AACA,kEAAkE,2BAA2B,IAAI,YAAY;AAC7G;AACA;AACA;AACA;AACA;AACA,kBAAkB,GAAG,+CAA+C,MAAM,IAAI,SAAS;AACvF;AACA;AACA;AACA;;AAEA;AACA;AACA,0BAA0B,yBAAC,+EAA+E,SAAS;AACnH;AACA;AACA;;AAEA;AACA,cAAc,6BAAK;AACnB;AACA,8DAA8D,YAAY;AAC1E;AACA,eAAe;AACf,gBAAgB,GAAG,2BAA2B,UAAU,IAAI,IAAI;AAChE;AACA,eAAe;AACf;;AAEA;AACA;AACA;AACA;AACA;AACA,oCAAoC,qBAAe;AACnD;AACA,oBAAoB,GAAG,2BAA2B,UAAU,IAAI,mBAAmB;AACnF;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,cAAc,GAAG,4CAA4C,UAAU;AACvE;AACA;;AAEA;AACA;AACA,SAAS;AACT;AACA;;AAEA;AACA;;AAEA;AACA;AACA,eAAe,SAAS;AACxB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe,SAAS;AACxB;AACA;AACA;AACA;AACA,MAAM,GAAG,mCAAmC,UAAU;AACtD;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA,WAAW,cAAc;AACzB;AACA;AACA,yBAAyB,QAAQ;AACjC;AACA;AACA;AACA,OAAO;AACP;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,gBAAgB;AAC5B;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA;AACA,YAAY,YAAY;AACxB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA;AACA,YAAY;AACZ;AACA;AACA,CAAC;;AAED,2DAAe,eAAe,EAAC;;;ACngB/B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEuB;AAC4B;AACf;AACM;;AAE1C;AACA;AACA,wDAAwD,4DAA4D;AACpH,2CAA2C,mDAAmD;AAC9F;AACO;AACP;AACA;AACA,aAAa,0CAA0C;AACvD;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,iBAAiB;AAC9B;AACA;AACA;AACA,sBAAsB,oBAAe;AACrC,wBAAwB,yBAAC;AACzB;AACA,KAAK;AACL;AACA;;AAEA;AACA;AACA;AACA;AACA,eAAe,QAAQ;AACvB;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA,wBAAwB,oBAAe;AACvC;AACA;AACA,OAAO;AACP;AACA;;AAEA;AACA,cAAc,mDAAmD;AACjE,aAAa,QAAQ;AACrB,aAAa,SAAS;AACtB;AACA,eAAe;AACf;AACA;AACA,WAAW,MAAM;AACjB;AACA;AACA;AACA;AACA;;AAEA;AACA,aAAa,mDAAmD;AAChE,aAAa,QAAQ;AACrB,aAAa,SAAS,+BAA+B,mDAAmD;AACxG;AACA,eAAe;AACf;AACA;AACA;AACA;AACA,aAAa,MAAM;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB,oBAAe;AACpC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA;AACA,IAAI,8BAAM;AACV;AACA;AACA,KAAK;AACL;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,aAAa,QAAQ;AACrB;AACA,aAAa,UAAU;AACvB,aAAa,gCAAgC,+CAA+C,iDAAiD;AAC7I,eAAe,QAAQ;AACvB;AACA;AACA;AACA,IAAI,8BAAM;AACV;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;;AAEA;AACA;AACA,eAAe,QAAQ;AACvB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,IAAI,8BAAM;AACV;AACA,QAAQ,GAAG;AACX;AACA,QAAQ;AACR;AACA,KAAK;AACL;AACA;;AAEA;AACA,cAAc,mCAAmC;AACjD,aAAa,QAAQ;AACrB,aAAa,QAAQ,UAAU,kDAAkD;AACjF,eAAe;AACf;AACA;AACA,WAAW,UAAI;AACf;AACA;;AAEA;AACA;AACA,wBAAwB,mDAAmD;AAC3E;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,0CAA0C;AACtD;AACA,CAAC;;AAED,oDAAe,QAAQ,EAAC;;;ACtNxB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEuB;AAC4B;AACQ;AAChB;AACL;AAC+B;AACpC;;AAEjC;AACA;AACA;AACA;AACA;AACA,OAAO,qEAAqE;AAC5E;AACA,OAAO,qEAAqE;AAC5E,OAAO,6CAA6C;AACpD;AACO;AACP;AACA;AACA;AACA;AACA,wBAAwB,uBAAe;AACvC,gCAAgC,qBAAgB;AAChD;AACA,wBAAwB,aAAQ;AAChC;;AAEA;AACA;AACA,aAAa,iBAAiB;AAC9B,aAAa,QAAQ;AACrB,aAAa,gBAAgB;AAC7B,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAwB,WAAW;AACnC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS,QAAQ;AACjB,MAAM,IAAI;AACV;AACA,mBAAmB,yBAAC;AACpB,uBAAuB,MAAM;AAC7B;AACA;AACA,KAAK;AACL;AACA;;AAEA;AACA;AACA;AACA;AACA,eAAe,QAAQ;AACvB;AACA;AACA;AACA;AACA;AACA;AACA,wCAAwC,YAAQ;AAChD,KAAK;;AAEL,WAAW,OAAO;AAClB;;AAEA;AACA;AACA;AACA,aAAa,QAAQ;AACrB,eAAe,QAAQ;AACvB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,gBAAgB;AAC7B,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAwB,WAAW;AACnC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,IAAI,IAAI;AACR;AACA;AACA;AACA;AACA;;AAEA;AACA,4DAA4D,yCAAyC;AACrG,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA,WAAW,YAAQ,8BAA8B,MAAM;AACvD;;AAEA;AACA;AACA,iBAAiB,kCAAkC,GAAG,wDAAwD,KAAK,8CAA8C;AACjK,aAAa,gCAAgC,iCAAiC,iDAAiD;AAC/H;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,gDAAgD;AAC5D;AACA;AACA;AACA;AACA,YAAY,+CAA+C;AAC3D;AACA;AACA;AACA,kDAAkD,wEAAwE;AAC1H;AACA;AACA,YAAY,mBAAmB;AAC/B;AACA;AACA;AACA;AACA,YAAY;AACZ;AACA;AACA;AACA;AACA;AACA,YAAY,+BAA+B;AAC3C;AACA;AACA;AACA;AACA,YAAY,wBAAwB;AACpC;AACA;AACA;AACA,WAAW;AACX;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,gBAAgB;AAC5B;AACA,CAAC;;AAED,2DAAe,YAAY,EAAC;;;ACzR5B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEuB;AAC+B;;AAEtD;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,OAAO;AACpB,aAAa,OAAO;AACpB,aAAa,SAAS;AACtB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,MAAM,kEAAkE;AACxE,eAAe;AACf;AACA;AACA,mBAAmB;AACnB;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,yBAAC;AACZ;;AAEA;AACA;AACA,aAAa,iBAAiB;AAC9B;AACA;AACA,IAAI,WAAW;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uBAAuB,UAAU;AACjC;AACA;AACA,KAAK;AACL;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA,CAAC;;AAED,uDAAe,SAAS,EAAC;;;AC1HzB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEuB;AAC+B;AACf;;AAEvC;AACA,iFAAiF,wCAAwC;AACzH;AACO;AACP;AACA;AACA,aAAa,0BAA0B,WAAW,yCAAyC;AAC3F;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,MAAM,kEAAkE;AACxE,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,oBAAoB,yBAAC;AACrB;AACA;AACA,KAAK;AACL;AACA;;AAEA;AACA;AACA,eAAe,QAAQ;AACvB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,iBAAiB;AAC9B;AACA;AACA,IAAI,WAAW;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uBAAuB,UAAU;AACjC;AACA;AACA,KAAK;AACL;AACA,yBAAyB,gBAAS;AAClC,2BAA2B,yBAAC;AAC5B;AACA,KAAK;AACL;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,OAAO;AACpB,aAAa,OAAO;AACpB,aAAa,SAAS;AACtB;AACA;AACA;AACA,4BAA4B,gBAAS;AACrC;AACA;AACA;;AAEA;AACA,2BAA2B,mDAAmD;AAC9E,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ;AACR;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,SAAS;AACtB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,qCAAqC;AACjD;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA,WAAW,mDAAmD;AAC9D;AACA,YAAY,mCAAmC;AAC/C;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA,CAAC;;AAED,yDAAe,WAAW,EAAC;;;AC9Q3B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAE2C;;AAE3C;AACA,kEAAkE,0FAA0F;AAC5J,uCAAuC,yDAAyD;AAChG;AACO;AACP;AACA;AACA,aAAa,6DAA6D,WAAW,2FAA2F;AAChL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe,QAAQ;AACvB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,0BAA0B,WAAW,yCAAyC;AAC3F;AACA;AACA;AACA,iCAAiC,kBAAW;AAC5C;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,SAAS;AACtB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,OAAO;AACpB,aAAa,OAAO;AACpB,aAAa,SAAS;AACtB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,yCAAyC;AACzC;AACA,YAAY,QAAQ;AACpB;AACA;AACA,wCAAwC;AACxC;AACA,YAAY,QAAQ;AACpB;AACA;AACA,4BAA4B,yDAAyD;AACrF;AACA,YAAY,yCAAyC;AACrD;AACA;AACA,6BAA6B,yCAAyC;AACtE;AACA,YAAY,uCAAuC;AACnD;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,2CAA2C;AACvD;AACA,CAAC;;AAED;AACA,+CAA+C;AAC/C;AACO;AACP;AACA;AACA,aAAa,uCAAuC,aAAa,yDAAyD;AAC1H;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe,2CAA2C;AAC1D;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,UAAU,yDAAyD;AACnE;AACA,YAAY,uCAAuC;AACnD;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA,CAAC;;AAED;;AAEA,yDAAe,WAAW,EAAC;;;AClR3B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAE2C;;AAE3C;AACA,6FAA6F;AAC7F,oDAAoD,yDAAyD;AAC7G;AACO;AACP;AACA;AACA,aAAa,0CAA0C;AACvD,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,SAAS;AACtB,uDAAuD,yDAAyD;AAChH,aAAa,SAAS;AACtB,eAAe,QAAQ;AACvB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,6DAA6D,WAAW,2FAA2F;AAChL;AACA;AACA;AACA,+BAA+B,kBAAW;AAC1C;AACA;AACA;;AAEA;AACA;AACA,aAAa,0BAA0B,WAAW,yCAAyC;AAC3F;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,SAAS;AACtB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,OAAO;AACpB,aAAa,OAAO;AACpB,aAAa,SAAS;AACtB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,UAAU;AACtB;AACA;AACA;AACA;AACA,YAAY,yCAAyC;AACrD;AACA;AACA;AACA;AACA,YAAY,uCAAuC;AACnD;AACA;AACA;AACA;AACA,YAAY,eAAe;AAC3B;AACA;AACA,kBAAkB,6DAA6D;AAC/E;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,yCAAyC;AACrD;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA,CAAC;;AAED;AACA,+CAA+C;AAC/C;AACO;AACP;AACA;AACA,aAAa,qCAAqC,YAAY,sDAAsD;AACpH;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe,yCAAyC;AACxD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY,qCAAqC;AACjD;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA,CAAC;;AAED;;AAEA,wDAAe,UAAU,EAAC;;;ACnV1B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb,+CAA+C,kDAAkD;AACjG;AACA;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,eAAe,QAAQ;AACvB;AACA;AACA;AACA,oBAAoB,QAAQ;AAC5B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA;AACA,oBAAoB,QAAQ;AAC5B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,gBAAgB,WAAW;AAC3B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4BAA4B,eAAe;AAC3C;;AAEA;AACA;;AAEA;AACA,aAAa,QAAQ;AACrB,eAAe,QAAQ;AACvB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,oBAAoB,2BAA2B;AAC/C;AACA;AACA;AACA;AACA,sBAAsB,gBAAgB;AACtC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA;AACA,oBAAoB,gBAAgB;AACpC;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,aAAa,QAAQ;AACrB,eAAe,QAAQ;AACvB;AACA;AACA;AACA;AACA,oBAAoB,cAAc;AAClC;AACA,oBAAoB,cAAc;AAClC;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA;AACA;AACA,MAAM,cAAc;AACpB;AACA;AACA;AACA;;AAEA;AACA;AACA,SAAS;AACT;AACA;;AAEA,iDAAe,UAAU,EAAC;;;ACjN1B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEuB;AACW;;AAElC;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,iCAAiC,gBAAgB,yCAAyC;AACvG;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,eAAe,QAAQ;AACvB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,iCAAiC,gBAAgB,yCAAyC;AACvG,eAAe,2BAA2B;AAC1C;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA,MAAM,GAAG;AACT;AACA;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ,yBAAC;AACT;AACA;AACA;AACA,SAAS;AACT;AACA,MAAM,GAAG;AACT,MAAM;AACN,MAAM,GAAG,2CAA2C,WAAW;AAC/D;AACA;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;AACA,MAAM;AACN,MAAM,GAAG,0CAA0C,WAAW;AAC9D;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,IAAI,GAAG,qCAAqC,OAAO,GAAG,KAAK;AAC3D;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;AACA,MAAM;AACN,MAAM,GAAG,oDAAoD,WAAW;AACxE;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,eAAe;AAC5B,eAAe;AACf;AACA;AACA;AACA;AACA;AACA,MAAM;AACN,MAAM,GAAG,kCAAkC,MAAM,QAAQ,IAAI,kBAAkB,WAAW;AAC1F;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,eAAe,QAAQ;AACvB;AACA;AACA;AACA;AACA;AACA,MAAM;AACN,MAAM,GAAG,+BAA+B,IAAI,oBAAoB,WAAW;AAC3E;AACA;AACA;;AAEA;AACA;AACA,WAAW;AACX,aAAa,QAAQ;AACrB,eAAe,QAAQ;AACvB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,WAAW,EAAE,GAAG,EAAE,GAAG,EAAE;AACvB,SAAS,uBAAuB,GAAG,qBAAqB,GAAG,qBAAqB;AAChF;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA,oBAAoB,6BAA6B;AACjD;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,iCAAiC;AAC7C;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA,CAAC;;AAED;AACA;AACA,UAAU,QAAQ;AAClB;;AAEA,mDAAe,KAAK,EAAC;;;AC/QrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEuB;AACkB;AACA;AACV;AACmB;;AAElD;AACA;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA,aAAa,gCAAgC,UAAU,kDAAkD;AACzG;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,UAAU;AACvB,eAAe,iCAAiC;AAChD;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,gCAAgC,UAAU,kDAAkD;AACzG,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM,GAAG;;AAET;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,OAAO;AACpB,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,eAAe,kBAAkB;AACjC;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,OAAO;AACpB,eAAe,kBAAkB;AACjC;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,QAAQ;AACrB,eAAe,kBAAkB;AACjC;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,QAAQ;AACrB,eAAe,kBAAkB;AACjC;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe,kBAAkB;AACjC;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe,kBAAkB;AACjC;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAiC,yBAAC,qBAAqB,mDAAmD;AAC1G,uDAAuD,yBAAC,qBAAqB,aAAa;AAC1F,wCAAwC,gCAAgC;AACxE;AACA;AACA,gBAAgB,yBAAC,YAAY,mBAAmB,OAAO,MAAM;AAC7D;AACA;AACA;AACA;AACA,aAAa;AACb;AACA,aAAa;AACb;AACA,SAAS;AACT;AACA,KAAK;AACL;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,0BAA0B,yBAAC,eAAe,0CAA0C;AACpF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oCAAoC,yBAAC,qBAAqB,kDAAkD;AAC5G,yDAAyD,yBAAC,qBAAqB,aAAa;AAC5F,2CAA2C,gCAAgC;AAC3E;AACA;AACA,oBAAoB,yBAAC,YAAY,mBAAmB,OAAO,MAAM;AACjE;AACA,oBAAoB,yBAAC,YAAY,mBAAmB,OAAO,MAAM;AACjE;AACA;AACA;AACA,iBAAiB;AACjB;AACA,6CAA6C,UAAU;AACvD,mCAAmC,MAAM;AACzC;AACA,sBAAsB;AACtB;AACA;AACA;AACA,oBAAoB;AACpB;AACA,iBAAiB;AACjB;AACA,aAAa;AACb,WAAW;AACX,UAAU;AACV,6BAA6B,yBAAC,eAAe,sCAAsC;AACnF;AACA;AACA,cAAc,yBAAC,iBAAiB,uBAAuB;AACvD,wBAAwB,yBAAC,YAAY,mBAAmB,OAAO,MAAM;AACrE;AACA,wBAAwB,yBAAC,YAAY,mBAAmB,OAAO,MAAM;AACrE;AACA;AACA;AACA;AACA,WAAW;AACX;AACA,8BAA8B,UAAU;AACxC,6BAA6B,MAAM;AACnC;AACA,gBAAgB;AAChB;AACA;AACA;AACA,aAAa;AACb,WAAW;AACX;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA,eAAe,QAAQ;AACvB;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,sFAAsF,qBAAqB;;AAE3G;AACA;AACA;AACA,KAAK;;AAEL;AACA;;AAEA;AACA;AACA;AACA,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA;AACA;AACA,kBAAkB,MAAM;AACxB,sBAAsB,MAAM;AAC5B,0BAA0B,MAAM;AAChC,2BAA2B,MAAM;AACjC,0BAA0B,MAAM;AAChC;AACA,mBAAmB,YAAK;AACxB;AACA;AACA;AACA;AACA,IAAI,GAAG;AACP;AACA;;AAEA;AACA;AACA,eAAe,kBAAkB;AACjC;AACA;AACA,IAAI,GAAG;AACP;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,0CAA0C,WAAW,6DAA6D;AAC/H;AACA;AACA;AACA,8BAA8B,iBAAU;AACxC;AACA;AACA;;AAEA;AACA;AACA,aAAa,6DAA6D,WAAW,2FAA2F;AAChL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,0BAA0B,WAAW,yCAAyC;AAC3F;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,SAAS;AACtB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,OAAO;AACpB,aAAa,OAAO;AACpB,aAAa,SAAS;AACtB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,UAAU,wDAAwD;AAClE;AACA,YAAY,qCAAqC;AACjD;AACA;AACA,UAAU,kDAAkD;AAC5D;AACA,YAAY,gCAAgC;AAC5C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,eAAe;AAC3B;AACA;AACA;AACA;AACA,YAAY,uCAAuC;AACnD;AACA;AACA;AACA;AACA,YAAY,qCAAqC;AACjD;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA,CAAC;;AAED;AACA,+CAA+C;AAC/C;AACO;AACP;AACA;AACA,aAAa,iCAAiC,WAAW,yCAAyC;AAClG;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe,qCAAqC;AACpD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY;AACZ;AACA;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA,CAAC;;AAED;;AAEA;AACA;AACA,UAAU;AACV;AACA,qBAAqB;;AAErB,sDAAe,QAAQ,EAAC;;;ACttBxB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEuB;AACG;AACW;AACiG;AAChE;AACvB;AACQ;AACpB;AACc;AACI;AACX;AACiB;AACf;AACY;;AAExD;AACA;AACA,IAAI;AACJ;AACA,0BAA0B,mDAAmD;AAC7E;AACA;AACA;AACA;AACO,0BAA0B,SAAS;;AAE1C;AACA;AACA,aAAa,iBAAiB;AAC9B,aAAa,QAAQ;AACrB;AACA;;AAEA;AACA;AACA;AACA,cAAc,IAAI;AAClB,mBAAmB,gCAAQ;AAC3B;AACA,mBAAmB,uFAAuF;AAC1G;AACA,8BAA8B,yBAAC;AAC/B;AACA,uBAAuB,yBAAyB;;AAEhD;AACA;AACA;AACA;AACA,eAAe,SAAS;AACxB,gBAAgB,SAAS;AACzB,OAAO;AACP;;AAEA;AACA,0BAA0B,yBAAC,aAAa,sCAAsC;AAC9E,aAAa,+BAA+B;AAC5C;;AAEA;AACA;AACA,gBAAgB,yBAAC,aAAa,sBAAsB;AACpD,uBAAuB,oBAAY;AACnC,8BAA8B,oBAAc;AAC5C,wBAAwB;AACxB,6BAA6B,KAAK;AAClC;AACA,uBAAuB,iBAAa;AACpC;AACA;AACA,uBAAuB,UAAI;AAC3B,iBAAiB,UAAI;AACrB;AACA;AACA,IAAI,GAAG;AACP;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,YAAY,oCAAoC;;AAEhD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAc,GAAG;AACjB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gBAAgB,GAAG,+BAA+B,WAAW;AAC7D;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA,cAAc,QAAQ,GAAG,GAAG;AAC5B;;AAEA;AACA,iBAAiB,yBAAyB;AAC1C;AACA;AACA;AACA,kBAAkB,MAAM;AACxB,kBAAkB,MAAM;AACxB,oBAAoB,MAAM;AAC1B,mBAAmB,MAAM,kBAAkB,0EAA0E;AACrH,kBAAkB,MAAM,iBAAiB,8CAA8C;AACvF,kBAAkB,MAAM;AACxB;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP,qBAAqB,MAAM;AAC3B,mBAAmB,MAAM;AACzB;AACA;AACA;AACA,QAAQ,iBAAW;AACnB,OAAO;AACP;;AAEA,IAAI,8BAAM;AACV,0CAA0C,uDAAuD;AACjG,KAAK;AACL;;AAEA;AACA;AACA;AACA;AACA,IAAI,GAAG;AACP;AACA;AACA,8BAA8B,oBAAc;AAC5C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe,kBAAkB;AACjC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,kCAAkC,yCAAyC;AAC3E,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA,oBAAoB,eAAQ;AAC5B;AACA;;AAEA;AACA,8CAA8C;AAC9C;AACA;AACA;AACA;AACA;AACA,qBAAqB,KAAK;AAC1B;AACA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA,4BAA4B,KAAK;AACjC;AACA;AACA,KAAK;AACL;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,wBAAwB;AACrC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,0CAA0C;AACvD;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kCAAkC,oBAAY;AAC9C;AACA;;AAEA;AACA;AACA,aAAa,qBAAqB,yFAAyF,4DAA4D;AACvL;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa,eAAe,mDAAmD;AAC/E,4EAA4E;AAC5E;AACA,aAAa,QAAQ;AACrB;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA,yBAAyB,OAAO;;AAEhC;AACA;AACA,UAAU,GAAG,oCAAoC,SAAS;AAC1D,UAAU,iCAAS,mBAAmB,UAAU;AAChD;AACA,4BAA4B,QAAQ,wBAAwB,QAAQ;AACpE;AACA,wBAAwB,OAAO,CAAC,WAAW;AAC3C,cAAc;AACd,cAAc,GAAG,qDAAqD,UAAU;AAChF;AACA,WAAW;AACX,8BAA8B,YAAY,GAAG,MAAM,kBAAkB,QAAQ;AAC7E,YAAY,GAAG;AACf,oCAAoC,OAAO;AAC3C,WAAW;AACX;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,UAAU,GAAG,8BAA8B,SAAS;;AAEpD;AACA,UAAU,+CAA2B;AACrC;AACA;AACA,cAAc,GAAG,qCAAqC,eAAe;AACrE;AACA;AACA,gBAAgB,0BAAK;AACrB;AACA;AACA,qCAAqC,WAAW;AAChD;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAwB,QAAQ;AAChC;AACA,gCAAgC,OAAO;AACvC,sBAAsB;AACtB,sBAAsB,GAAG,qDAAqD,UAAU;AACxF;AACA,oBAAoB;AACpB,oBAAoB,GAAG,6CAA6C,SAAS,IAAI,uCAAuC;AACxH;AACA,iBAAiB;AACjB,kBAAkB,GAAG,qCAAqC,8CAA8C;AACxG,iBAAiB;AACjB,gBAAgB;AAChB;AACA;AACA;AACA,4BAA4B,OAAO;AACnC;AACA,kBAAkB,GAAG;AACrB;AACA;AACA,aAAa;AACb,cAAc,GAAG,qCAAqC,8CAA8C;AACpG;AACA,aAAa;AACb,WAAW;AACX;AACA,UAAU;AACV;AACA,6BAA6B,SAAS;AACtC;AACA;AACA;AACA;AACA,0DAA0D,QAAQ;AAClE,uBAAuB;AACvB,uBAAuB;AACvB,uBAAuB;AACvB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,kDAAkD;;AAElD,iCAAiC,6BAAK,0BAA0B,iCAAS;;AAEzE;AACA;AACA,cAAc,GAAG,2CAA2C,QAAQ;AACpE;AACA;AACA,4BAA4B,oBAAY;AACxC;AACA,gCAAgC,yBAAC;AACjC;AACA;;AAEA,YAAY,GAAG,4CAA4C,QAAQ;AACnE;AACA,cAAc,GAAG,cAAc,aAAa;AAC5C;AACA,aAAa;AACb,YAAY,GAAG,yCAAyC,SAAS;AACjE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gBAAgB,GAAG;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb,WAAW;AACX,8BAA8B,YAAY,GAAG,YAAY,kBAAkB,QAAQ;AACnF,YAAY,GAAG;AACf,oCAAoC,OAAO;AAC3C,WAAW;AACX;;;AAGA,QAAQ,GAAG,6BAA6B,QAAQ;AAChD;;AAEA;AACA;AACA,wBAAwB,eAAe;AACvC;AACA;AACA,yCAAyC,4DAA4D,gBAAgB,yBAAyB;AAC9I,aAAa;AACb,cAAc,GAAG,gCAAgC,MAAM,8BAA8B,8CAA8C;AACnI;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA,yBAAyB,+DAA+D,gBAAgB,8DAA8D;AACtK,YAAY;AACZ,YAAY,GAAG,6BAA6B,SAAS;AACrD;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA,SAAS,aAAa;AACtB,MAAM,GAAG,8BAA8B,SAAS;AAChD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,QAAQ,GAAG,8BAA8B,SAAS;AAClD;AACA,QAAQ,oBAAe;AACvB;AACA;AACA;AACA;AACA,QAAQ;AACR,QAAQ,GAAG,+BAA+B,SAAS;AACnD;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,0BAA0B,mDAAmD;AAC7E;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM,GAAG,sBAAsB,uBAAuB;AACtD;AACA;AACA;;AAEA;AACA,gBAAgB,2CAA2C,UAAU,mDAAmD;AACxH;AACA;AACA;AACA;AACA;AACA,MAAM,GAAG;AACT;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW;AACX,SAAS;AACT;;AAEA;AACA;AACA;AACA,YAAY,QAAQ;AACpB,2BAA2B,SAAS;;AAEpC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,wCAAwC;AACrD,aAAa,kCAAkC;AAC/C,aAAa,YAAY;AACzB;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,iBAAiB,aAAQ;AACzB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAiB,aAAQ;AACzB;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA,QAAQ,GAAG,iCAAiC,kBAAkB;AAC9D;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,QAAQ;AACrB;AACA;AACA,IAAI,GAAG,mDAAmD,IAAI;AAC9D;;AAEA;AACA,kBAAkB,yCAAyC;AAC3D,aAAa,SAAS;AACtB;AACA;AACA;AACA;AACA,IAAI,GAAG;AACP;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,gDAAgD;AAC7D;AACA;AACA;AACA;AACA;AACA;AACA,gCAAgC,sBAAgB;AAChD;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,SAAS;AACtB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA,gCAAgC,mCAAmC;AACnE;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,SAAS;AACtB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA;;AAEA;AACA,gBAAgB,0EAA0E,mBAAmB;AAC7G,aAAa,wCAAwC;AACrD,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,0BAA0B;AACvC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,0BAA0B;AACvC,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,SAAS;AACtB,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,0BAA0B;AACvC,aAAa,SAAS;AACtB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,iBAAiB;AAC9B,eAAe,SAAS;AACxB;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,SAAS;AACtB;AACA;AACA;AACA;AACA;AACA;AACA,gCAAgC,6BAA6B;AAC7D;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB;AACA;AACA,IAAI,GAAG,oBAAoB,SAAS;AACpC;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,iBAAiB;AAC7B;AACA;AACA;AACA;AACA,YAAY,iBAAiB;AAC7B;AACA;AACA;AACA;AACA,YAAY,iBAAiB;AAC7B;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA,UAAU,6DAA6D;AACvE;AACA,YAAY,0CAA0C;AACtD;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA,QAAQ,sBAAsB;AAC9B;AACA;AACA,4BAA4B,QAAQ;AACpC,4BAA4B,QAAQ;AACpC;AACA,YAAY,gBAAgB;AAC5B;AACA;AACA;AACA;AACA,YAAY;AACZ;AACA;AACA;AACA,UAAU,mDAAmD;AAC7D;AACA,YAAY,gCAAgC;AAC5C;AACA;AACA;AACA;AACA,YAAY,oCAAoC;AAChD;AACA;AACA;AACA;AACA,YAAY,wBAAwB;AACpC;AACA;AACA;AACA;AACA,YAAY,wBAAwB;AACpC;AACA;AACA,4CAA4C;AAC5C;AACA,YAAY,wBAAwB;AACpC;AACA;AACA;AACA;AACA,YAAY,4CAA4C;AACxD;AACA;AACA;AACA;AACA;AACA,YAAY,iCAAiC;AAC7C;AACA;AACA,oBAAoB,yBAAyB;AAC7C;AACA,YAAY,qBAAqB;AACjC,aAAa;AACb;AACA;AACA;AACA,YAAY,kBAAkB;AAC9B;AACA;AACA;AACA;AACA,YAAY,kBAAkB;AAC9B;AACA;AACA;AACA;AACA,YAAY,mBAAmB;AAC/B;AACA;AACA;AACA,YAAY;AACZ,gBAAgB,QAAQ;AACxB,gBAAgB,QAAQ;AACxB,gBAAgB,QAAQ;AACxB;AACA;AACA;AACA,YAAY,+CAA+C;AAC3D,gBAAgB,+BAA+B;AAC/C;AACA;AACA;AACA,YAAY,kBAAkB;AAC9B;AACA;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA,CAAC;;AAED,sDAAe,WAAW,EAAC;;;AC3xC3B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEgE;AAC7B;;AAEnC;AACA;AACA,mBAAmB,2BAA2B;AAC9C;AACA;AACA;AACA;AACA;AACA;AACO,0BAA0B,SAAS;AAC1C;AACA;AACA,aAAa,oBAAoB;AACjC,aAAa,sBAAsB;AACnC,aAAa,gBAAgB;AAC7B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,sCAAsC;AACnD;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,sBAAsB;AACnC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,uEAAuE,2BAA2B;AAClG,aAAa,sBAAsB;AACnC;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,eAAe,4CAA4C;AAC3D,aAAa,8BAA8B;AAC3C;AACA;AACA;AACA;AACA;;AAEA;AACA,oBAAoB,4CAA4C;AAChE,eAAe;AACf;AACA;AACA;AACA;AACA;AACA,yBAAyB,aAAO;AAChC;;AAEA;AACA;AACA,aAAa,kBAAkB;AAC/B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,kBAAkB;AAC/B,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,sBAAsB;AACnC;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA,iBAAiB,SAAS;AAC1B;AACA;AACA;;AAEA;AACA;AACA;AACA,+BAA+B,SAAS;AACxC;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,aAAa,kBAAkB;AAC/B,aAAa,QAAQ;AACrB;AACA;AACA;AACA,mBAAmB,KAAK;AACxB,wBAAwB,SAAS;AACjC;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB;AACA;AACA,wBAAwB,SAAS;AACjC;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB;AACA;AACA,uBAAuB,SAAS,eAAe,SAAS;AACxD;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,SAAS;AACtB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,SAAS;AACtB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,YAAY,6DAA6D;AACzE;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,SAAS;AACtB;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,SAAS;AACtB;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;;AAGA;AACA;AACA,aAAa,SAAS;AACtB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,SAAS;AACtB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,SAAS;AACtB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,SAAS;AACtB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,MAAM,yDAAyD;AAC/D,aAAa,mCAAmC;AAChD;AACA,aAAa,sBAAsB;AACnC;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA,yCAAyC,wDAAwD;AACjG,4DAA4D,kDAAkD;AAC9G,aAAa,mCAAmC;AAChD;AACA,aAAa,sBAAsB;AACnC;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,mCAAmC;AAChD;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA,MAAM,MAAM;AACZ;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA,uBAAuB,SAAS;AAChC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,eAAe,8EAA8E;AAC7F,aAAa,iBAAiB;AAC9B;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,uBAAuB,8EAA8E;AACrG,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA,WAAW,8EAA8E;AACzF,2BAA2B,4CAA4C;AACvE;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qCAAqC,+CAA+C,GAAG,wBAAwB;AAC/G;AACA;AACA;;AAEA;AACA,eAAe,8EAA8E;AAC7F,MAAM,4CAA4C;AAClD;AACA;AACA;AACA;AACA;AACA,2BAA2B,mEAAmE;AAC9F;AACA;AACA,OAAO;AACP;AACA;;AAEA;AACA,yBAAyB,6EAA6E;AACtG;AACA,aAAa,SAAS,iCAAiC,kDAAkD;AACzG;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY,sCAAsC;AAClD;AACA;AACA;AACA;AACA,YAAY,sBAAsB;AAClC;AACA;AACA,UAAU,4CAA4C;AACtD;AACA;AACA,YAAY,8BAA8B;AAC1C;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,kBAAkB;AAC9B;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,iBAAiB;AAC7B;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,iBAAiB;AAC7B;AACA,CAAC;;AAED,wDAAe,WAAW,EAAC;;;AC1rB3B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAE2C;AACa;AACjB;;AAEvC;AACA,mCAAmC,wDAAwD;AAC3F,+BAA+B,uDAAuD;AACtF;AACA;AACA;AACO,qBAAqB,iBAAW;AACvC;AACA;AACA,aAAa,sCAAsC;AACnD,aAAa,sBAAsB;AACnC,aAAa,8BAA8B;AAC3C;AACA;AACA;AACA;AACA,+BAA+B,SAAS;AACxC;AACA;;AAEA;AACA;AACA;AACA,aAAa,sBAAsB;AACnC,aAAa,WAAW;AACxB,MAAM;AACN,sCAAsC,yCAAyC,IAAI,8CAA8C;AACjI,aAAa,QAAQ;AACrB,eAAe,sBAAsB;AACrC;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,aAAa,sBAAsB;AACnC,aAAa,WAAW;AACxB,MAAM;AACN,sCAAsC,yCAAyC,IAAI,8CAA8C;AACjI,aAAa,WAAW;AACxB,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA,aAAa,QAAQ;AACrB,eAAe,sBAAsB;AACrC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA,kBAAkB,SAAS;AAC3B;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,oBAAoB,SAAS;AAC7B;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,kBAAkB,SAAS;AAC3B;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA,eAAe,SAAS;AACxB,eAAe,QAAQ;AACvB,eAAe,QAAQ;AACvB;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA;AACA,eAAe,SAAS;AACxB;;AAEA;AACA,cAAc,wDAAwD;AACtE,aAAa,sCAAsC;AACnD;AACA;AACA;AACA;;AAEA;AACA,MAAM,SAAS;AACf;AACA;;AAEA;AACA;;AAEA;AACA;AACA,aAAa,sCAAsC;AACnD,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,sCAAsC;AACnD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,SAAS;AACb;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,qCAAqC,SAAS;AAC9C;AACA;AACA,gBAAgB,SAAS;AACzB;AACA;AACA,KAAK;AACL;AACA,cAAc,SAAS;AACvB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,KAAK;AAClB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,gBAAgB,sDAAsD;AACtE;AACA,aAAa,SAAS;AACtB;AACA;AACA;AACA;;AAEA;AACA,gBAAgB,uDAAuD;AACvE;AACA,aAAa,SAAS;AACtB;AACA;AACA;AACA;;AAEA;AACA,gBAAgB,2DAA2D;AAC3E;AACA,aAAa,SAAS;AACtB;AACA;AACA;AACA;AACA;;AAEA;AACA,gBAAgB,sDAAsD;AACtE;AACA,aAAa,wBAAwB;AACrC;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA,iBAAiB,SAAS;AAC1B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,sBAAsB,KAAK;AAC3B;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA,kBAAkB,KAAK;AACvB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,gBAAgB;AAChB;AACA,aAAa,mCAAmC;AAChD;AACA,aAAa,sBAAsB;AACnC;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;;AAEA;AACA,8BAA8B,wDAAwD;AACtF,aAAa,kBAAkB;AAC/B,eAAe;AACf;AACA;AACA;AACA,wCAAwC,QAAQ;AAChD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY,wCAAwC;AACpD;AACA;AACA;AACA;AACA,YAAY,sBAAsB;AAClC,uBAAuB,SAAS;AAChC;AACA;AACA;AACA,YAAY,sCAAsC;AAClD;AACA,CAAC;;AAED,mDAAe,MAAM,EAAC;;;ACnftB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEuB;AACU;AACC;;AAElC;AACA,oCAAoC,yCAAyC,iCAAiC,iDAAiD;AAC/J;AACA,IAAI,uEAAuE;AAC3E;AACA;AACA;AACO,2BAA2B,YAAM;AACxC;AACA;AACA,aAAa,sCAAsC;AACnD,aAAa,sBAAsB;AACnC,aAAa,8BAA8B;AAC3C;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,cAAc,kDAAkD;AAChE,aAAa,kCAAkC;AAC/C;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA,6EAA6E;AAC7E;AACA,aAAa,gDAAgD;AAC7D,aAAa,gDAAgD;AAC7D,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,oBAAoB,cAAc;AAClC;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,kBAAkB;AAC/B,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA,gBAAgB,kDAAkD;AAClE,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,kCAAkC;AAC/C,aAAa,SAAS;AACtB,eAAe;AACf;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,SAAS;AACtB,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,SAAS;AACtB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gBAAgB,KAAK;;AAErB,sBAAsB,QAAQ;AAC9B;AACA,qBAAqB,KAAK;AAC1B;AACA;;AAEA,sBAAsB,WAAW;AACjC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,sBAAsB,QAAQ;AAC9B;AACA;AACA;AACA;AACA,sBAAsB,KAAK;AAC3B;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,oCAAoC;AACjD;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,sBAAsB,KAAK;;AAE3B;AACA;AACA;AACA;AACA,sBAAsB,KAAK;AAC3B,KAAK;AACL;;AAEA;AACA;AACA,aAAa,kCAAkC;AAC/C,aAAa,kCAAkC;AAC/C,aAAa,SAAS;AACtB;AACA;AACA;AACA;AACA,iBAAiB,KAAK;AACtB;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,uBAAuB;AAClC;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ;AACR;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa,iBAAiB;AAC9B,aAAa,iBAAiB;AAC9B,aAAa,QAAQ;AACrB,eAAe,iBAAiB;AAChC;AACA;AACA,uDAAuD,yBAAC,aAAa,gDAAgD;AACrH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY,iBAAiB;AAC7B;AACA,CAAC;;AAED,yDAAe,YAAY,EAAC;;;ACpW5B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEuB;AACoB;AACU;AACA;AACG;AACJ;;AAEpD;AACA;AACA;AACA;AACA;AACA,IAAI,uEAAuE;AAC3E;AACA;AACA;AACA;AACA,kBAAkB,uEAAuE;AACzF;AACA;AACO,wBAAwB,iBAAW;AAC1C;AACA;AACA,aAAa,sCAAsC;AACnD,aAAa,sBAAsB;AACnC,aAAa,8BAA8B;AAC3C;AACA,aAAa,QAAQ;AACrB,aAAa,sBAAsB;AACnC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,iBAAiB;AAC9B,aAAa,gDAAgD;AAC7D;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;AACA,kBAAkB,yBAAC;AACnB,mBAAmB,SAAS;AAC5B,0BAA0B,SAAS;AACnC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA,0BAA0B,sBAAgB;AAC1C;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,kCAAkC;AAC/C,aAAa,SAAS;AACtB,eAAe,SAAS;AACxB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,4BAA4B,iEAAiE;AAC7F,aAAa,kCAAkC;AAC/C,aAAa,SAAS;AACtB,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,kCAAkC;AAC/C;AACA;AACA;AACA,eAAe,KAAK;AACpB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,kCAAkC;AAC/C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,kCAAkC;AAC/C;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA;AACA;AACA,yBAAyB,sBAAgB;AACzC;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA,eAAe,uEAAuE;AACtF,aAAa,mCAAmC;AAChD,aAAa,QAAQ,sBAAsB,sEAAsE;AACjH;AACA;AACA;AACA,uBAAuB,sBAAgB;AACvC;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,2BAA2B,oBAAoB;AAC/C,oBAAoB,yBAAC;AACrB;AACA;AACA;AACA,SAAS;AACT;AACA;;AAEA;AACA;AACA;AACA,sCAAsC,mBAAmB,KAAK,mBAAmB;AACjF;AACA;AACA,WAAW;AACX;AACA;AACA;;AAEA;AACA;;AAEA;AACA,gCAAgC,yBAAC;;AAEjC;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;;AAEA;AACA;AACA;AACA;;AAEA;AACA,eAAe,uEAAuE;AACtF;AACA,aAAa,mCAAmC;AAChD,aAAa,QAAQ,sBAAsB,sEAAsE;AACjH;AACA;AACA;AACA,uBAAuB,sBAAgB;AACvC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,gDAAgD;AAC7D;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,WAAW;AACX;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,+BAA+B,8CAA8C;AAC7E;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,mCAAmC;AAChD;AACA,aAAa,sBAAsB;AACnC;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,UAAU;AACV;AACA;AACA;AACA;AACA;AACA,cAAc,QAAQ;AACtB;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY;AACZ;;AAEA;AACA,0BAA0B,SAAS;AACnC;AACA;AACA;AACA,QAAQ;AACR,QAAQ,GAAG,kCAAkC,UAAU,KAAK,WAAW;AACvE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gBAAgB,SAAS;AACzB;AACA,gBAAgB,SAAS;AACzB;AACA,gBAAgB,SAAS;AACzB;AACA,gBAAgB,SAAS;AACzB;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAwB,eAAe;AACvC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA,sBAAsB,kBAAkB;AACxC;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,aAAa,mCAAmC;AAChD;AACA;AACA;AACA,QAAQ,QAAQ;AAChB;AACA;AACA;AACA;;;AAGA;AACA,kDAAkD;AAClD,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA,mCAAmC,MAAM;AACzC;;AAEA;AACA;AACA,aAAa,gCAAgC,iBAAiB;AAC9D,aAAa,YAAY;AACzB;AACA;AACA;AACA;AACA,MAAM,GAAG,sBAAsB,4BAA4B;AAC3D;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,kDAAkD;AAC/D;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,sBAAsB;AACnC;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA,iBAAiB,SAAS;AAC1B;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,yBAAyB,6EAA6E;AACtG;AACA;AACA,aAAa,SAAS,gCAAgC,kDAAkD;AACxG;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAwB,UAAU,KAAK,UAAU;AACjD;AACA;AACA,sCAAsC,2BAA2B,KAAK,2BAA2B;AACjG;AACA,WAAW;AACX,UAAU;AACV;AACA;AACA,wBAAwB,UAAU,KAAK,UAAU;AACjD;AACA;AACA;AACA,WAAW;AACX;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa,iBAAiB;AAC9B,aAAa,iBAAiB;AAC9B,aAAa,iBAAiB;AAC9B,aAAa,QAAQ;AACrB,eAAe,iBAAiB;AAChC;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,gCAAgC,yBAAC;AACjC;AACA,iBAAiB,GAAG;AACpB,OAAO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,UAAU,GAAG,0CAA0C,gBAAgB;AACvE;AACA,qBAAqB,+BAAO;AAC5B;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA,UAAU,QAAQ;AAClB;AACA,UAAU,GAAG,aAAa,SAAS,sBAAsB,gBAAgB;AACzE;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,kBAAkB;AAC9B;AACA;AACA;AACA;AACA,YAAY,gDAAgD;AAC5D;AACA;AACA;AACA;AACA,YAAY,gDAAgD;AAC5D;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,kDAAkD;AAC9D;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA,CAAC;;AAED,sDAAe,SAAS,EAAC;;;;ACxyBzB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAE6C;AACN;AACiB;AACR;;AAEhD;AACA,uBAAuB,2DAA2D;AAClF,IAAI,2CAA2C,uBAAuB,iDAAiD;AACvH;AACA;AACA;AACA;AACO,4BAA4B,kBAAY;AAC/C;AACA;AACA,aAAa,sCAAsC;AACnD,aAAa,sBAAsB;AACnC,aAAa,sBAAsB;AACnC,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,8BAA8B;AAC3C;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA,kBAAkB,SAAS;AAC3B,UAAU,KAAK;AACf,UAAU,SAAS;AACnB;AACA;;AAEA;AACA;AACA,oBAAoB,eAAe;AACnC;AACA;AACA,iBAAiB,eAAS;AAC1B;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,iBAAiB,eAAS;AAC1B;AACA;AACA;AACA;;AAEA;AACA;AACA,MAAM,uEAAuE;AAC7E,aAAa,sCAAsC;AACnD,aAAa,sBAAsB;AACnC,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,gDAAgD;AAC7D,aAAa,8BAA8B;AAC3C,aAAa,8BAA8B;AAC3C;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA,eAAe,SAAS;AACxB,MAAM,QAAQ;AACd,MAAM,QAAQ;AACd;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA,eAAe,SAAS;AACxB,MAAM,OAAO;AACb,MAAM,OAAO;AACb;;AAEA;AACA,sDAAsD,iDAAiD;AACvG;AACA;AACA,aAAa,kCAAkC;AAC/C,eAAe;AACf;AACA;AACA,eAAe,KAAK;AACpB;;AAEA;AACA,kDAAkD,kDAAkD;AACpG;AACA;AACA,aAAa,kCAAkC;AAC/C,aAAa,kCAAkC;AAC/C,eAAe;AACf;AACA;AACA;AACA;AACA;AACA,eAAe,KAAK;AACpB;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA,CAAC;;AAED,0DAAe,aAAa,EAAC;;;AClL7B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEwD;;AAExD;;AAEA;AACA,sDAAsD,kDAAkD;AACxG,IAAI,kDAAkD;AACtD;AACA;AACA;AACA;AACA;AACA;AACA;AACO;AACP;AACA;AACA,aAAa,sBAAsB;AACnC,aAAa,iBAAiB;AAC9B;AACA;AACA;AACA,kDAAkD,0BAA0B;AAC5E,mBAAmB,SAAS;AAC5B,sBAAsB,KAAK;AAC3B,oBAAoB,KAAK;AACzB,2BAA2B,KAAK;AAChC;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB;AACA;AACA,gBAAgB,KAAK;AACrB;;AAEA;AACA;AACA,aAAa,kBAAkB;AAC/B,aAAa,SAAS;AACtB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ;AACR;AACA;;AAEA;;AAEA;AACA;AACA,oBAAoB,KAAK;AACzB,sBAAsB,SAAS,kCAAkC,SAAS;AAC1E;AACA,oBAAoB,KAAK;AACzB,wBAAwB,SAAS,kCAAkC,SAAS;AAC5E;AACA;;AAEA;AACA;AACA,yBAAyB,KAAK;AAC9B;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,kBAAkB;AAC/B,aAAa,kCAAkC;AAC/C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,kBAAkB,KAAK;AACvB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY,2BAA2B;AACvC;AACA;AACA,uBAAuB,mDAAmD;AAC1E;AACA,YAAY,sBAAsB;AAClC;AACA;AACA;AACA;AACA,YAAY,kBAAkB;AAC9B;AACA;AACA;AACA;AACA,YAAY,kBAAkB;AAC9B;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,MAAM;AACN;AACA,YAAY,QAAQ;AACpB;AACA;AACA,kBAAkB;AAClB;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,kBAAkB;AAC9B;AACA;AACA;AACA;AACA,YAAY,kCAAkC;AAC9C;AACA;AACA;AACA;AACA,YAAY,mCAAmC;AAC/C;AACA;AACA;AACA;AACA,YAAY,sBAAsB;AAClC;AACA;AACA;AACA;AACA,YAAY,sBAAsB;AAClC;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA,CAAC;;AAED,yDAAe,YAAY,EAAC;;;ACpU5B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEuB;AACqC;AACH;AACd;AACY;AACP;AACR;;AAExC;AACA,kBAAkB,yCAAyC;AAC3D,IAAI,kDAAkD,oCAAoC,uEAAuE;AACjK;AACA,iFAAiF;AACjF;AACA;AACA;AACA;AACO,gCAAgC,QAAQ;AAC/C;AACA;AACA,aAAa,0CAA0C;AACvD;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA,CAAC;;AAED;AACA,QAAQ,mDAAmD,OAAO,4FAA4F;AAC9J;AACA;AACO,qCAAqC,aAAa;AACzD;AACA;AACA,aAAa,0BAA0B,WAAW,yCAAyC;AAC3F,aAAa,gCAAgC;AAC7C;AACA,aAAa,iBAAiB;AAC9B;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,6BAA6B,yBAAC;AAC9B,uCAAuC,qBAAqB;AAC5D;AACA;AACA;AACA,WAAW;AACX;;AAEA;AACA;AACA;AACA,8BAA8B,yBAAC;AAC/B,uCAAuC,qBAAqB;AAC5D;AACA;AACA;AACA,WAAW;AACX;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA,iBAAiB,mBAAa;AAC9B,iBAAiB,mBAAa;;AAE9B;AACA;AACA;;AAEA;AACA;AACA;;AAEA,gCAAgC,MAAM;AACtC,gCAAgC,MAAM;;AAEtC;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,sCAAsC,mCAAmC;AACzE;AACA,aAAa,sBAAsB;AACnC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,0BAA0B,SAAS;AACnC;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,sBAAsB;AACnC,eAAe;AACf;AACA;AACA;AACA;AACA,MAAM,YAAM;AACZ;;AAEA;AACA;AACA;AACA,aAAa,sBAAsB;AACnC;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,qBAAqB,yBAAC,mBAAmB,eAAe,YAAY,gBAAgB;AACpF;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gCAAgC,iBAAiB,KAAK,kBAAkB;AACxE,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gCAAgC,kBAAkB,KAAK,mBAAmB;AAC1E,SAAS;AACT;AACA;;AAEA;AACA,oBAAoB,kBAAY;;AAEhC;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,gBAAgB;AAC7B,eAAe,SAAS;AACxB,6CAA6C;AAC7C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wDAAwD,KAAK;AAC7D;AACA;AACA;AACA;AACA;AACA,gBAAgB,KAAK;AACrB;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY;AACZ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAc;AACd;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kBAAkB;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,UAAU,2DAA2D;AACrE;AACA,YAAY,wCAAwC;AACpD;AACA;AACA,UAAU,2DAA2D;AACrE;AACA,YAAY,wCAAwC;AACpD;AACA;AACA;AACA;AACA,YAAY,wCAAwC;AACpD;AACA;AACA;AACA;AACA;AACA,YAAY,UAAU;AACtB;AACA,CAAC;;AAED;AACA,qDAAqD;AACrD,UAAU,OAAO;AACjB;;AAEA;AACA,qEAAe,QAAQ,oEAAoE,EAAC;;;ACtgB5F;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AAGyC;AACJ;AAC8C;;AAEnF;AACA,8BAA8B,4FAA4F;AAC1H;AACA;AACA;AACO,iCAAiC,iBAAiB;AACzD;AACA;AACA,aAAa,0CAA0C;AACvD;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,iBAAiB;AAC9B;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA,CAAC;;AAED;AACA,QAAQ,mDAAmD,OAAO,+FAA+F;AACjK;AACA;AACO,sCAAsC,sBAAsB;AACnE;AACA;AACA,aAAa,0BAA0B,WAAW,yCAAyC;AAC3F,aAAa,gCAAgC;AAC7C;AACA,aAAa,iBAAiB;AAC9B;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,gBAAgB;AAC7B,eAAe,SAAS;AACxB,6CAA6C;AAC7C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,wDAAwD,KAAK;AAC7D,QAAQ;AACR;AACA;AACA;AACA;AACA,gBAAgB,KAAK;AACrB;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY;AACZ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAc;AACd;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kBAAkB;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAc;AACd;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY,WAAW;AACvB;AACA,CAAC;;AAED;AACA,qDAAqD;AACrD,UAAU,OAAO;AACjB;;AAEA;AACA,sEAAe,YAAQ,sEAAsE,EAAC;;;AChU9F;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEiC;AACuB;;AAExD;AACA;AACA,yBAAyB,0CAA0C;AACnE;AACA;AACA;AACO,0BAA0B,cAAM;AACvC;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oBAAoB,gBAAgB;AACpC,sBAAsB,gBAAgB;AACtC,iDAAiD,SAAS,KAAK,KAAK,oBAAoB,SAAS;AACjG;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,6BAA6B;AAC7B;AACA;AACA,YAAY,SAAS;AACrB;AACA,CAAC;;AAED;AACA,0DAAe,cAAM,2CAA2C,EAAC;;;AC7EjE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEuB;AACqC;AACH;AACd;AACY;AACP;AACO;;AAEvD;AACA,kBAAkB,yCAAyC,8BAA8B,kDAAkD;AAC3I;AACA;AACA;AACA,wEAAwE,uEAAuE;AAC/I;AACA;AACA;AACA;AACO,yBAAyB,QAAQ;AACxC;AACA;AACA,aAAa,0CAA0C,eAAe,6DAA6D;AACnI;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;;AAEA;AACA,QAAQ,mDAAmD,OAAO,iEAAiE;AACnI;AACA;AACO,8BAA8B,aAAa;AAClD;AACA;AACA,aAAa,0BAA0B,WAAW,yCAAyC;AAC3F,aAAa,gCAAgC;AAC7C;AACA,aAAa,iBAAiB;AAC9B;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA,oBAAoB,mBAAa;AACjC;AACA,wCAAwC,mBAAW;;AAEnD;AACA;AACA;AACA;AACA,sBAAsB,OAAO;AAC7B,wBAAwB,QAAQ;AAChC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,sCAAsC,mCAAmC;AACzE;AACA,aAAa,sBAAsB;AACnC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,0BAA0B,SAAS;AACnC;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,sBAAsB;AACnC,eAAe;AACf;AACA;AACA;AACA;AACA,WAAW,YAAM;AACjB;;AAEA;AACA;AACA;AACA,aAAa,sBAAsB;AACnC;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,qBAAqB,yBAAC,mBAAmB,eAAe,YAAY,gBAAgB;AACpF;AACA;AACA;AACA,OAAO;AACP;;AAEA;AACA,oBAAoB,kBAAY;;AAEhC;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,gBAAgB;AAC7B,eAAe,SAAS;AACxB,6CAA6C;AAC7C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wDAAwD,KAAK;AAC7D;AACA;AACA;AACA;AACA;AACA,gBAAgB,KAAK;AACrB;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY;AACZ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kBAAkB;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gBAAgB;AAChB;AACA;AACA;AACA,cAAc;AACd;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,UAAU,2DAA2D;AACrE;AACA,YAAY,wCAAwC;AACpD;AACA;AACA,UAAU,2DAA2D;AACrE;AACA,YAAY,wCAAwC;AACpD;AACA;AACA;AACA;AACA;AACA,YAAY,UAAU;AACtB;AACA,CAAC;;AAED;AACA,qDAAqD;AACrD,UAAU,OAAO;AACjB;;AAEA;AACA,wDAAe,QAAQ,gDAAgD,EAAC;;;ACtaxE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEuB;AACqC;AACH;AACd;AACK;AACO;;AAEvD;AACA,kBAAkB,yCAAyC,oBAAoB,kDAAkD;AACjI;AACA;AACA;AACA;AACO,sBAAsB,QAAQ;AACrC;AACA;AACA,aAAa,0CAA0C,eAAe,6DAA6D;AACnI;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;;AAEA;AACA,QAAQ,mDAAmD,OAAO,wDAAwD;AAC1H;AACA;AACO,2BAA2B,aAAa;AAC/C;AACA;AACA,aAAa,0BAA0B,WAAW,yCAAyC;AAC3F,aAAa,gCAAgC;AAC7C;AACA,aAAa,iBAAiB;AAC9B;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,6BAA6B,yBAAC;AAC9B,uCAAuC,qBAAqB;AAC5D;AACA;AACA;AACA,WAAW;AACX;;AAEA;AACA;;AAEA;AACA;;AAEA,iBAAiB,mBAAa;AAC9B;AACA,qBAAqB,mBAAa,0EAA0E,mBAAW;;AAEvH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,sCAAsC,mCAAmC;AACzE;AACA,aAAa,sBAAsB;AACnC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,0BAA0B,SAAS;AACnC;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,sBAAsB;AACnC,eAAe;AACf;AACA;AACA;AACA;AACA,MAAM,YAAM;AACZ;;AAEA;AACA;AACA;AACA,aAAa,sBAAsB;AACnC;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,qBAAqB,yBAAC,mBAAmB,eAAe,YAAY,gBAAgB;AACpF;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;AACA;AACA;AACA,oBAAoB,iBAAiB;AACrC,qBAAqB,kBAAkB;AACvC,gCAAgC,iBAAiB,KAAK,kBAAkB;AACxE,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,gBAAgB;AAC7B,eAAe,SAAS;AACxB,6CAA6C;AAC7C;AACA;AACA;AACA,oBAAoB,KAAK;AACzB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,cAAc;AACd;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,UAAU,2DAA2D;AACrE;AACA,YAAY,wCAAwC;AACpD;AACA;AACA,UAAU,2DAA2D;AACrE;AACA;AACA,YAAY,wCAAwC;AACpD;AACA;AACA;AACA;AACA;AACA,YAAY,UAAU;AACtB;AACA,CAAC;;AAED;AACA,qDAAqD;AACrD,UAAU,OAAO;AACjB;;AAEA;AACA,qDAAe,QAAQ,0CAA0C,EAAC;;;AC5VlE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEuB;AACqC;AACH;AACd;AACK;;AAEhD;AACA,4BAA4B,yCAAyC,gBAAgB,kDAAkD;AACvI;AACA;AACA;AACO,uBAAuB,QAAQ;AACtC;AACA;AACA,aAAa,0CAA0C,eAAe,6DAA6D;AACnI;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,kDAAkD,kGAAkG;AACpJ;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA,MAAM,kGAAkG;AACxG;AACA,YAAY,QAAQ;AACpB;AACA,CAAC;;AAED;AACA,QAAQ,mDAAmD,OAAO,2DAA2D;AAC7H;AACA;AACO,4BAA4B,aAAa;AAChD;AACA;AACA,aAAa,0BAA0B,WAAW,yCAAyC;AAC3F,aAAa,gCAAgC;AAC7C;AACA,aAAa,iBAAiB;AAC9B;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,6BAA6B,yBAAC;AAC9B,uCAAuC,oBAAoB;AAC3D;AACA;AACA;AACA,WAAW;AACX;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gBAAgB,mBAAa;AAC7B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,sBAAsB,OAAO;AAC7B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,sCAAsC,mCAAmC;AACzE;AACA,aAAa,sBAAsB;AACnC;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,0BAA0B,SAAS;AACnC;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,sBAAsB;AACnC,eAAe;AACf;AACA;AACA;AACA;AACA,MAAM,YAAM;AACZ;;AAEA;AACA;AACA;AACA,aAAa,sBAAsB;AACnC;AACA;AACA;AACA;;AAEA;AACA;AACA,qBAAqB,yBAAC,mBAAmB,eAAe,YAAY,gBAAgB;AACpF;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;AACA;AACA;AACA,oBAAoB,iBAAiB;AACrC,qBAAqB,kBAAkB;AACvC,gCAAgC,iBAAiB,KAAK,kBAAkB;AACxE,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,gBAAgB;AAC7B,eAAe,SAAS;AACxB,6CAA6C;AAC7C;AACA;AACA;AACA,oBAAoB,KAAK;AACzB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAc;AACd;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,UAAU,2DAA2D;AACrE;AACA,YAAY,wCAAwC;AACpD;AACA;AACA;AACA;AACA;AACA,YAAY,UAAU;AACtB;AACA,CAAC;;AAED;AACA,qDAAqD;AACrD,UAAU,OAAO;AACjB;;AAEA;AACA,sDAAe,QAAQ,4CAA4C,EAAC;;;ACnWpE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEuB;AACqC;AACH;AACd;AACK;;AAEhD;AACA,kBAAkB,yCAAyC,yBAAyB,kDAAkD;AACtI;AACA;AACA;AACA;AACA;AACO,gCAAgC,QAAQ;AAC/C;AACA;AACA,aAAa,0CAA0C,eAAe,6DAA6D;AACnI;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,QAAQ,mDAAmD,OAAO,sFAAsF;AACxJ;AACA;AACO,qCAAqC,aAAa;AACzD;AACA;AACA,aAAa,0BAA0B,WAAW,yCAAyC;AAC3F,aAAa,gCAAgC;AAC7C;AACA,aAAa,iBAAiB;AAC9B;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,6BAA6B,yBAAC;AAC9B,uCAAuC,oBAAoB;AAC3D;AACA;AACA;AACA,WAAW;AACX;;AAEA;AACA;;AAEA,gBAAgB,mBAAa;AAC7B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA,sCAAsC,mCAAmC;AACzE;AACA,aAAa,sBAAsB;AACnC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,0BAA0B,SAAS;AACnC;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,sBAAsB;AACnC,eAAe;AACf;AACA;AACA;AACA;AACA,MAAM,YAAM;AACZ;;AAEA;AACA;AACA;AACA,aAAa,sBAAsB;AACnC;AACA;AACA;AACA;;AAEA;AACA;AACA,qBAAqB,yBAAC;AACtB;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;AACA;AACA;AACA,oBAAoB,iBAAiB;AACrC,qBAAqB,kBAAkB;AACvC,gCAAgC,iBAAiB,KAAK,kBAAkB;AACxE,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,gBAAgB;AAC7B,eAAe,SAAS;AACxB,6CAA6C;AAC7C;AACA;AACA;AACA,oBAAoB,KAAK;AACzB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,UAAU,2DAA2D;AACrE;AACA,YAAY,wCAAwC;AACpD;AACA;AACA;AACA;AACA;AACA,YAAY,UAAU;AACtB;AACA,CAAC;;AAED;AACA,qDAAqD;AACrD,UAAU,OAAO;AACjB;;AAEA;AACA,+DAAe,QAAQ,8DAA8D,EAAC;;;;;;;;;;;;;ACrQtF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEuB;AACqC;AACL;AAClB;;AAErC;AACsC;AACA;AACA;AACA;AACQ;;AAE9C;AACA,kBAAkB,yCAAyC;AAC3D;AACA;AACA;AACO,mBAAmB,QAAQ;AAClC;AACA;AACA,aAAa,0CAA0C,eAAe,6DAA6D;AACnI;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,QAAQ,mDAAmD;AAC3D;AACA;AACO,wBAAwB,aAAa;AAC5C;AACA;AACA,aAAa,0BAA0B,WAAW,yCAAyC;AAC3F,aAAa,gCAAgC;AAC7C;AACA,aAAa,iBAAiB;AAC9B;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oBAAoB,yBAAC;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA,mBAAmB,yBAAC;AACpB;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;;AAEP;AACA;AACA;AACA,eAAe,yBAAC,aAAa,oBAAoB;AACjD;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,kBAAkB,yBAAC;AACnB;AACA;AACA;AACA;AACA,OAAO;;AAEP;AACA;AACA;AACA,uBAAuB,kBAAY;AACnC;AACA;AACA,QAAQ,GAAG,sBAAsB,sBAAsB,EAAE,kBAAkB;AAC3E;AACA;AACA,OAAO;;AAEP;AACA;AACA,KAAK;;AAEL;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,sBAAsB;AACnC,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA,UAAU;AACV;AACA;AACA,gBAAgB,qBAAK;AACrB,gBAAgB,qBAAK;AACrB,gBAAgB,qBAAK;AACrB,gBAAgB,qBAAK;AACrB,oBAAoB,yBAAS;AAC7B;;AAEA;AACA,qDAAqD;AACrD,UAAU,OAAO;AACjB;;AAEA;AACA,kDAAe,QAAQ,oCAAoC,EAAC;;;;;AC9M5D;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEuB;AACqC;AACH;AACd;AACY;AACP;AACR;;AAExC;AACA,6BAA6B,yCAAyC;AACtE,IAAI,uEAAuE;AAC3E;AACA;AACA;AACA;AACA;AACO,2BAA2B,QAAQ;AAC1C;AACA;AACA,aAAa,0CAA0C,eAAe,6DAA6D;AACnI;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;;AAEA;AACA,QAAQ,mDAAmD,OAAO,wEAAwE;AAC1I;AACA;AACO,gCAAgC,aAAa;AACpD;AACA;AACA,aAAa,0BAA0B,WAAW,yCAAyC;AAC3F,aAAa,gCAAgC;AAC7C;AACA;AACA,aAAa,iBAAiB;AAC9B;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA,iBAAiB,mBAAa;AAC9B,iBAAiB,mBAAa;;AAE9B;;AAEA,gCAAgC,MAAM;AACtC,gCAAgC,MAAM;;AAEtC;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,sCAAsC,mCAAmC;AACzE;AACA,aAAa,sBAAsB;AACnC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,0BAA0B,SAAS;AACnC;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,sBAAsB;AACnC,eAAe;AACf;AACA;AACA;AACA;AACA,MAAM,YAAM;AACZ;;AAEA;AACA;AACA;AACA,aAAa,sBAAsB;AACnC;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,qBAAqB,yBAAC,mBAAmB,eAAe,YAAY,gBAAgB;AACpF;AACA;AACA;AACA,OAAO;AACP;;AAEA;AACA,oBAAoB,kBAAY;;AAEhC;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,gBAAgB;AAC7B,eAAe,SAAS;AACxB,6CAA6C;AAC7C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wDAAwD,KAAK;AAC7D;AACA;AACA;AACA;AACA;AACA,gBAAgB,KAAK;AACrB;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY;AACZ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA,yBAAyB,sBAAsB,GAAG,YAAY;AAC9D,2BAA2B,YAAY;AACvC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,UAAU,2DAA2D;AACrE;AACA,YAAY,wCAAwC;AACpD;AACA;AACA,oBAAoB,0DAA0D;AAC9E;AACA,YAAY,wCAAwC;AACpD;AACA;AACA;AACA;AACA,YAAY,wCAAwC;AACpD;AACA;AACA;AACA;AACA;AACA,YAAY,UAAU;AACtB;AACA,CAAC;;AAED;AACA,qDAAqD;AACrD,UAAU,OAAO;AACjB;;AAEA;AACA,2DAAe,QAAQ,qDAAqD,EAAC;;;;ACta7E;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEuB;AACqC;AACH;AACd;AACY;AACP;;AAEhD;AACA,kBAAkB,yCAAyC,oCAAoC,kDAAkD;AACjJ;AACA;AACA;AACA;AACO,6BAA6B,QAAQ;AAC5C;AACA;AACA,aAAa,0CAA0C,eAAe,6DAA6D;AACnI;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;;AAEA;AACA,QAAQ,mDAAmD,0BAA0B,8EAA8E;AACnK;AACA;AACA,kCAAkC,aAAa;AAC/C;AACA;AACA,aAAa,0BAA0B,WAAW,yCAAyC;AAC3F,aAAa,gCAAgC;AAC7C;AACA,aAAa,iBAAiB;AAC9B;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA,gBAAgB,mBAAa;AAC7B;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,sCAAsC,mCAAmC;AACzE;AACA,aAAa,sBAAsB;AACnC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,0BAA0B,SAAS;AACnC;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,sBAAsB;AACnC,eAAe;AACf;AACA;AACA;AACA;AACA,MAAM,YAAM;AACZ;;AAEA;AACA;AACA;AACA,aAAa,sBAAsB;AACnC;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,qBAAqB,yBAAC,mBAAmB,eAAe,YAAY,gBAAgB;AACpF;AACA;AACA;AACA,OAAO;AACP;;AAEA;AACA,oBAAoB,kBAAY;;AAEhC;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,gBAAgB;AAC7B,eAAe,SAAS;AACxB,6CAA6C;AAC7C;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wDAAwD,KAAK;AAC7D;AACA;AACA;AACA;AACA;AACA,gBAAgB,KAAK;AACrB;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY;AACZ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,yBAAyB,sBAAsB,GAAG,YAAY;AAC9D,2BAA2B,UAAU;AACrC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,UAAU,2DAA2D;AACrE;AACA,YAAY,wCAAwC;AACpD;AACA;AACA;AACA;AACA,YAAY,wCAAwC;AACpD;AACA;AACA;AACA;AACA;AACA,YAAY,UAAU;AACtB;AACA,CAAC;;AAED;AACA,qDAAqD;AACrD,UAAU,OAAO;AACjB;;AAEA;AACA,6DAAe,QAAQ,yDAAyD,EAAC;;;ACrXjF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEuB;AACqC;AACH;AACd;AACK;AACO;;AAEvD;AACA,kBAAkB,yCAAyC,oCAAoC,kDAAkD;AACjJ;AACA;AACA;AACA;AACA;AACA;AACA;AACO,yBAAyB,QAAQ;AACxC;AACA;AACA,aAAa,0CAA0C,eAAe,6DAA6D;AACnI;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;;AAEA;AACA,QAAQ,mDAAmD,OAAO,kEAAkE;AACpI;AACA;AACO,8BAA8B,aAAa;AAClD;AACA;AACA,aAAa,0BAA0B,WAAW,yCAAyC;AAC3F,aAAa,gCAAgC;AAC7C;AACA,aAAa,iBAAiB;AAC9B;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA,gBAAgB,mBAAa;AAC7B;AACA;;AAEA;AACA;AACA;AACA,wBAAwB,mBAAa;AACrC,iEAAiE,mBAAW;AAC5E;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,sBAAsB,uBAAuB;AAC7C;AACA;;AAEA;AACA;AACA;AACA;AACA,UAAU;AACV;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,sCAAsC,mCAAmC;AACzE;AACA,aAAa,sBAAsB;AACnC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,0BAA0B,SAAS;AACnC;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,sBAAsB;AACnC,eAAe;AACf;AACA;AACA;AACA;AACA,MAAM,YAAM;AACZ;;AAEA;AACA;AACA;AACA,aAAa,sBAAsB;AACnC;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,qBAAqB,yBAAC,mBAAmB,eAAe,YAAY,gBAAgB;AACpF;AACA;AACA;AACA,OAAO;AACP;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,gBAAgB;AAC7B,eAAe,SAAS;AACxB,6CAA6C;AAC7C;AACA;AACA;AACA,oBAAoB,KAAK;AACzB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,2BAA2B,qBAAqB,GAAG,WAAW;AAC9D,6BAA6B,qBAAqB;AAClD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kBAAkB;AAClB;AACA;AACA;AACA;AACA,cAAc;AACd;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,UAAU,2DAA2D;AACrE;AACA,YAAY,wCAAwC;AACpD;AACA;AACA;AACA;AACA;AACA,YAAY,0CAA0C;AACtD;AACA;AACA;AACA;AACA,YAAY,kCAAkC;AAC9C;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA;AACA,YAAY,UAAU;AACtB;AACA,CAAC;;AAED;AACA,qDAAqD;AACrD,UAAU,OAAO;AACjB;;AAEA;AACA,yDAAe,QAAQ,iDAAiD,EAAC;;;ACvWzE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEuB;AACwB;AACa;AACX;AACJ;;AAE7C;AACA,wCAAwC,2FAA2F;AACnI,oBAAoB,oEAAoE,GAAG,oEAAoE,GAAG,4DAA4D,KAAK,wDAAwD;AAC3R;AACA;AACO,+BAA+B,QAAQ;AAC9C;AACA;AACA,aAAa,0CAA0C;AACvD;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY,4CAA4C;AACxD;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,8BAA8B;AAC1C;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA,CAAC;;AAED;AACA,QAAQ,mDAAmD,iCAAiC,gFAAgF;AAC5K;AACA;AACA;AACO,oCAAoC,aAAa;AACxD;AACA;AACA,aAAa,0BAA0B,WAAW,yCAAyC;AAC3F,aAAa,gCAAgC;AAC7C;AACA,aAAa,iBAAiB;AAC9B;AACA;AACA;AACA;AACA;;AAEA;AACA,sEAAsE,4FAA4F;AAClK,aAAa,iBAAiB;AAC9B,aAAa,kEAAkE;AAC/E;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,qDAAqD,6CAA6C;;AAElG,sBAAsB,yBAAC,iBAAiB,kCAAkC;AAC1E,iBAAiB,yBAAC,aAAa,4BAA4B,QAAQ,cAAc;;AAEjF;AACA;;AAEA;AACA;AACA;AACA;AACA,iBAAiB,yBAAC,eAAe,WAAW;AAC5C;;AAEA;AACA;AACA;AACA;AACA,QAAQ;AACR;;AAEA;AACA;AACA;AACA,iBAAiB,iEAAiE;AAClF;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,+BAA+B,yBAAC;AAChC;AACA,gBAAgB,aAAa;AAC7B,mBAAmB,2BAA2B;AAC9C,iCAAiC,WAAW;AAC5C,iCAAiC;AACjC;AACA,+BAA+B;AAC/B;AACA,+BAA+B;AAC/B;AACA;AACA;AACA;AACA,0BAA0B,yBAAC;AAC3B;AACA;AACA;AACA,kBAAkB;AAClB;AACA,4BAA4B,yBAAC;AAC7B;AACA;AACA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA,aAAa;AACb;;AAEA;AACA;AACA,oBAAoB,yBAAC;AACrB,wBAAwB,eAAS,wBAAwB,sBAAsB;AAC/E,wBAAwB,uDAAuD;AAC/E;AACA;AACA;AACA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;;AAEA;AACA,oBAAoB,yBAAC;AACrB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,uBAAuB,yBAAC,kBAAkB,6DAA6D;AACvG;AACA,+BAA+B,eAAS;AACxC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB;AACA;AACA;AACA,gCAAgC,oCAAoC;AACpE;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kBAAkB;AAClB;AACA,gBAAgB;AAChB;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,oBAAoB;AACpB;AACA;AACA;AACA,iBAAiB;AACjB;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,cAAc;AACd;;AAEA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA,uBAAuB;;AAEvB;AACA;AACA,KAAK;;AAEL;;AAEA;AACA,0BAA0B,yBAAC,gBAAgB,mBAAmB;AAC9D;AACA,eAAe,iCAAiC;AAChD;AACA;AACA;;AAEA;AACA,iDAAiD,wCAAwC;;AAEzF;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,aAAa,wDAAwD;AACrE,aAAa,iBAAiB;AAC9B;AACA,eAAe,iBAAiB;AAChC;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,qBAAqB,gBAAgB;AACrC,aAAa,iBAAiB;AAC9B;AACA,eAAe,iBAAiB;AAChC;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,MAAM;AACN;AACA,uCAAuC,aAAO;AAC9C;AACA,oBAAoB,yBAAC,aAAa,4BAA4B;AAC9D,eAAe,cAAc;AAC7B;AACA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,eAAe,SAAS;AACxB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,SAAS;AACtB;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,gBAAgB;AAC7B,eAAe,SAAS;AACxB,6CAA6C;AAC7C;AACA;AACA;AACA;;AAEA;AACA,aAAa,iBAAiB;AAC9B,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA,+BAA+B,iBAAiB;AAChD;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;;AAEA;AACA,mBAAmB,aAAa;AAChC;;AAEA;AACA;AACA;AACA,uBAAuB,iBAAiB;AACxC;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY,mBAAmB;AAC/B;AACA;AACA;AACA,kCAAkC,qEAAqE;AACvG;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,gBAAgB;AAC5B;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,iBAAiB;AAC7B;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA,6BAA6B,wFAAwF;AACrH;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA,CAAC;;AAED;AACA,qDAAqD;AACrD,UAAU,OAAO;AACjB;;AAEA,4DAAe,gBAAgB,EAAC;;;AC5iBhC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEyC;AACuC;;AAEhF;AACA;AACA;AACA;AACA;AACO,uBAAuB,gBAAgB;AAC9C;AACA;AACA,aAAa,0CAA0C;AACvD;AACA;AACA;AACA;AACA;;AAEA;AACA,QAAQ,2FAA2F,OAAO,yDAAyD;AACnK;AACA;AACO,4BAA4B,qBAAqB;AACxD;AACA;AACA,aAAa,0BAA0B,WAAW,yCAAyC;AAC3F,aAAa,gCAAgC;AAC7C;AACA,aAAa,iBAAiB;AAC9B;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,wDAAwD;AACrE,aAAa,iBAAiB;AAC9B;AACA,eAAe,iBAAiB;AAChC;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,eAAe,SAAS;AACxB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,SAAS;AACtB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,qDAAqD;AACrD,UAAU,OAAO;AACjB;;AAEA;AACA,oDAAe,YAAQ,0CAA0C,EAAC;;;AC9HlE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEyC;AAClB;AACuE;AACd;;AAEhF;AACA;AACA;AACA;AACA;AACA;AACO,2BAA2B,gBAAgB;AAClD;AACA;AACA,aAAa,0CAA0C,eAAe,6DAA6D;AACnI;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA,CAAC;;AAED;AACA,QAAQ,qEAAqE,OAAO,qEAAqE;AACzJ;AACA;AACO,gCAAgC,qBAAqB;AAC5D;AACA;AACA,aAAa,0BAA0B,WAAW,yCAAyC;AAC3F,aAAa,gCAAgC;AAC7C;AACA,aAAa,iBAAiB;AAC9B;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,aAAa,wDAAwD;AACrE,aAAa,iBAAiB;AAC9B;AACA,eAAe,iBAAiB;AAChC;AACA;;AAEA;;AAEA,6BAA6B,MAAM,wBAAwB,YAAY;AACvE;AACA;AACA,cAAc,yBAAC,gBAAgB,4BAA4B;AAC3D;AACA,QAAQ,yBAAC,yBAAyB,qBAAqB;AACvD,mCAAmC,yBAAC,gBAAgB,qBAAqB;AACzE;AACA;AACA;AACA,OAAO;AACP,MAAM;AACN;AACA;AACA;AACA,UAAU,UAAU;;AAEpB;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;;AAEA;AACA;AACA;AACA,eAAe,SAAS;AACxB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;;AAEA;AACA;AACA,aAAa,wDAAwD;AACrE,aAAa,SAAS;AACtB,aAAa,QAAQ;AACrB,eAAe,SAAS;AACxB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,QAAQ,iBAAiB;AACzB,QAAQ;AACR;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,SAAS;AACtB;AACA,aAAa,SAAS;AACtB,eAAe,QAAQ;AACvB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA,aAAa,wDAAwD;AACrE,aAAa,UAAU;AACvB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa,yCAAyC;AACtD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ,yBAAC;AACT;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;;AAEA;AACA,gBAAgB,kDAAkD;AAClE;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,IAAI,yBAAC;AACL;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,SAAS;AACtB;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;;AAEA;AACA;AACA;AACA,aAAa,gBAAgB;AAC7B,eAAe,SAAS;AACxB,6CAA6C;AAC7C;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAc,6BAA6B;AAC3C;AACA;AACA,YAAY,iBAAiB;AAC7B;AACA,YAAY;AACZ;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,sBAAsB,6BAA6B;AACnD,gCAAgC,WAAW;AAC3C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gBAAgB,iBAAiB;AACjC;;AAEA;AACA;AACA,sBAAsB,6BAA6B;AACnD;AACA;AACA;AACA,gBAAgB,iBAAiB;AACjC;AACA,cAAc;AACd;AACA;AACA,cAAc,iBAAiB;AAC/B;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA,CAAC;;AAED;AACA,qDAAqD;AACrD,UAAU,OAAO;AACjB;;AAEA;AACA,wDAAe,YAAQ,kDAAkD,EAAC;;;ACza1E;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEuE;AACjC;AACK;AACQ;;AAEnD;AACA;AACA,UAAU;AACV;AACO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA,UAAU;AACV;AACO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,oCAAoC,wDAAwD;AAC5F;AACA;AACA,cAAc,gEAAgE,KAAK,mEAAmE;AACtJ;AACA;AACO,uBAAuB,iBAAW;AACzC;AACA;AACA,aAAa,sCAAsC;AACnD,aAAa,sBAAsB;AACnC,aAAa,8BAA8B;AAC3C,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,SAAS;AACtB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,+BAA+B,SAAS;AACxC;AACA,2BAA2B,KAAK;AAChC;AACA;AACA;AACA,sBAAsB,KAAK;AAC3B;;AAEA;AACA,gEAAgE;AAChE,aAAa,sCAAsC;AACnD,aAAa,sBAAsB;AACnC,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,8CAA8C;AAC3D,aAAa,SAAS;AACtB,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA;AACA,qBAAqB,iBAAiB;AACtC;AACA;AACA;AACA;AACA,uBAAuB,iBAAiB;AACxC;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,qBAAqB,iBAAiB;AACtC,uBAAuB,iBAAiB;AACxC;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,SAAS;AACtB;AACA,aAAa,SAAS;AACtB;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB,iBAAiB;AACtC,uBAAuB,iBAAiB;AACxC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,SAAS;AACtB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,MAAM,gEAAgE;AACtE;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,eAAe,kBAAkB;AACjC;AACA;AACA;AACA;AACA;AACA;;AAEA,sBAAsB,KAAK;AAC3B;AACA;AACA;;AAEA,qBAAqB,SAAS;AAC9B;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ;AACR;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB,SAAS;AAC9B;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ;AACR;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,SAAS;AACtB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,iBAAiB,wBAAwB;AACzC;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,gBAAgB,wBAAwB;AACxC;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,SAAS,8CAA8C,+DAA+D;AACnI;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,kBAAkB;AAC/B,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA;AACA;AACA,uBAAuB,KAAK;AAC5B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,QAAQ,gCAAgC,2CAA2C;AAChG,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,SAAS;AACtB,eAAe;AACf;AACA;AACA,sBAAsB,KAAK;AAC3B;AACA;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ;AACR;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ;AACR;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,SAAS;AACtB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ;AACR;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,SAAS;AACtB;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA;AACA,qBAAqB,iBAAiB;AACtC,uBAAuB,iBAAiB;AACxC;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,SAAS;AACtB,eAAe;AACf;AACA;AACA;AACA;AACA,uBAAuB,iBAAiB;AACxC,yBAAyB,iBAAiB;AAC1C;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,SAAS;AACtB,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,kBAAkB;AAC/B,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,0CAA0C,KAAK;AAC/C;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAwB,YAAY;AACpC;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,QAAQ,8DAA8D,2CAA2C;AAC9H,aAAa,SAAS;AACtB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAwB,YAAY;AACpC;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,QAAQ,8DAA8D,2CAA2C;AAC9H,aAAa,SAAS;AACtB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ,8DAA8D,2CAA2C;AAC9H,aAAa,SAAS;AACtB;AACA;AACA,qBAAqB,iBAAiB;AACtC,uBAAuB,iBAAiB;AACxC;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,QAAQ,8DAA8D,2CAA2C;AAC9H,eAAe,SAAS;AACxB;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA,eAAe,SAAS;AACxB;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA,eAAe,SAAS;AACxB;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA,eAAe,SAAS;AACxB,MAAM,OAAO;AACb,MAAM,OAAO;AACb;;AAEA;AACA,gBAAgB;AAChB;AACA,aAAa,sBAAsB;AACnC;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,gBAAgB;AAChB;AACA,aAAa,mCAAmC;AAChD;AACA,aAAa,sBAAsB;AACnC;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA,qBAAqB,iBAAiB;AACtC,uBAAuB,iBAAiB;AACxC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,YAAY,MAAM;AAClB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,MAAM;AACN,aAAa,SAAS;AACtB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,YAAY;AACxB;AACA;AACA;AACA;AACA,YAAY,YAAY;AACxB;AACA;AACA;AACA;AACA;AACA,YAAY,YAAY;AACxB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,sBAAsB;AAClC;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB,QAAQ,qBAAe;AACvB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB,eAAe,qBAAe;AAC9B;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,kBAAkB;AAC9B;AACA;AACA,4DAA4D,4CAA4C;AACxG;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,kBAAkB;AAC9B;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA,CAAC;;AAED;AACA;AACA;AACA;AACA,UAAU,QAAQ;AAClB;;AAEA;AACA;AACA;AACA;AACA,UAAU,QAAQ;AAClB;;AAEA,qDAAe,QAAQ,EAAC;;;;;;;ACt3BxB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEuB;AACqC;AACf;AACF;AACI;AACM;AACJ;AACD;AACI;;AAEpD;AACsC;AACA;;AAEtC;AACA,kBAAkB,yCAAyC,SAAS,+CAA+C;AACnH;AACA;AACA;AACA;AACA,iDAAiD,kDAAkD;AACnG,IAAI,8CAA8C;AAClD;AACA;AACA;AACA;AACA;AACA;AACO,wBAAwB,QAAQ;AACvC;AACA;AACA,aAAa,0CAA0C;AACvD;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,iCAAiC,+CAA+C;AAChF;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA,iDAAiD,+CAA+C;AAChG;AACA,YAAY,SAAS;AACrB;AACA,CAAC;;AAED;AACA,QAAQ,mDAAmD,OAAO,gEAAgE;AAClI;AACA;AACO,6BAA6B,aAAa;AACjD;AACA;AACA,aAAa,0BAA0B,WAAW,yCAAyC;AAC3F,aAAa,gCAAgC;AAC7C;AACA,aAAa,iBAAiB;AAC9B;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,gBAAgB,yCAAyC,kDAAkD;AAC3G;AACA,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA;AACA,gBAAgB,YAAM;AACtB,eAAe,iBAAW;;AAE1B;AACA,iBAAiB,yBAAC,gBAAgB,mBAAmB;AACrD;AACA;AACA,iCAAiC,iDAAiD;AAClF;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA,KAAK;;AAEL;AACA;;AAEA,mBAAmB,eAAS,4BAA4B,SAAS;AACjE;AACA;;AAEA,kCAAkC;AAClC;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA,kBAAkB,cAAQ;AAC1B,uBAAuB,YAAM;AAC7B;AACA;AACA;AACA;AACA,wBAAwB,KAAK;AAC7B;AACA,wBAAwB,KAAK;AAC7B;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA,sCAAsC,mCAAmC;AACzE;AACA,aAAa,sBAAsB;AACnC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,0BAA0B,SAAS;AACnC;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,sBAAsB;AACnC,eAAe;AACf;AACA;AACA;AACA;AACA,MAAM,YAAM;AACZ;;AAEA;AACA;AACA;AACA,aAAa,sBAAsB;AACnC;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,qBAAqB,yBAAC,mBAAmB,eAAe,YAAY,gBAAgB;AACpF;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,gBAAgB;AAC7B,eAAe,SAAS;AACxB,6CAA6C;AAC7C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oBAAoB,KAAK;AACzB;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,kBAAkB,QAAQ;AAC1B;AACA;AACA,6CAA6C,+BAA+B;AAC5E;AACA;AACA;AACA,YAAY;AACZ;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,iBAAiB,QAAQ;AACzB;AACA;AACA,iBAAiB,QAAQ;AACzB;AACA;AACA,iBAAiB,QAAQ;AACzB;AACA;AACA,iBAAiB,QAAQ;AACzB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,QAAQ;AACrB;AACA;AACA;AACA,sBAAsB,gBAAgB;AACtC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4DAA4D,OAAO,IAAI,MAAM;AAC7E;AACA;AACA;AACA;AACA;AACA,UAAU;AACV;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,gCAAgC;AAC5C;AACA;AACA;AACA;AACA,YAAY,4BAA4B;AACxC;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,kCAAkC;AAC9C;AACA;AACA;AACA;AACA,YAAY,kCAAkC;AAC9C;AACA;AACA;AACA;AACA,YAAY,kCAAkC;AAC9C;AACA;AACA;AACA;AACA,YAAY,kCAAkC;AAC9C;AACA;AACA;AACA;AACA;AACA,YAAY,UAAU;AACtB;AACA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB,SAAS,QAAQ,CAAC,qBAAK;AACvB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB,SAAS,QAAQ,CAAC,qBAAK;AACvB;AACA;AACA;AACA,YAAY,QAAQ;AACpB,aAAa,cAAc;AAC3B;AACA;AACA;AACA,YAAY,8BAA8B;AAC1C,aAAa,aAAO;AACpB,CAAC;;AAED;AACA,qDAAqD;AACrD,UAAU,OAAO;AACjB;;AAEA;AACA,yDAAe,QAAQ,gDAAgD,EAAC;;;ACpjBxE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEuB;AACqC;AACH;AACd;AACY;AACP;AACD;;AAE/C;AACA,kBAAkB,yCAAyC,SAAS,+CAA+C;AACnH;AACA;AACA;AACA;AACA,+BAA+B,uEAAuE;AACtG;AACA;AACA;AACO,yBAAyB,QAAQ;AACxC;AACA;AACA,aAAa,0CAA0C;AACvD;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY,UAAU;AACtB;AACA;AACA;AACA,uBAAuB,uEAAuE,0BAA0B,0DAA0D;AAClL;AACA;AACA,YAAY,UAAU;AACtB;AACA;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA,CAAC;;AAED;AACA,QAAQ,mDAAmD,OAAO,mEAAmE;AACrI;AACA;AACO,8BAA8B,aAAa;AAClD;AACA;AACA,aAAa,0BAA0B,WAAW,yCAAyC;AAC3F,aAAa,gCAAgC;AAC7C;AACA,aAAa,iBAAiB;AAC9B;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,6BAA6B,yBAAC;AAC9B,uCAAuC,uBAAuB;AAC9D;AACA;AACA;AACA,WAAW;AACX;;AAEA;AACA;AACA;;AAEA;AACA,kBAAkB,cAAQ;AAC1B;AACA,qBAAqB,mBAAa;AAClC;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,qCAAqC,oBAAc;;AAEnD;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,sCAAsC,mCAAmC;AACzE;AACA,aAAa,sBAAsB;AACnC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,0BAA0B,SAAS;AACnC;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,sBAAsB;AACnC,eAAe;AACf;AACA;AACA;AACA;AACA;AACA,aAAa,YAAM;AACnB;AACA,aAAa,YAAM;AACnB;;AAEA;AACA;AACA;AACA,aAAa,sBAAsB;AACnC;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB,yBAAC,mBAAmB,eAAe,YAAY,gBAAgB;AACpF;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;AACA;AACA;AACA,oBAAoB,iBAAiB;AACrC,qBAAqB,kBAAkB;AACvC,gCAAgC,iBAAiB,KAAK,kBAAkB;AACxE,SAAS;AACT;AACA;;AAEA;AACA,oBAAoB,kBAAY;;AAEhC;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,gBAAgB;AAC7B,eAAe,SAAS;AACxB,6CAA6C;AAC7C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wDAAwD,KAAK;AAC7D;AACA;AACA;AACA;AACA;AACA,gBAAgB,KAAK;AACrB;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,YAAY;AACZ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB,2BAA2B;AAChD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,0EAA0E,oBAAc;AACxF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gBAAgB;AAChB;AACA,cAAc;AACd;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,UAAU,+CAA+C;AACzD;AACA,YAAY,gCAAgC;AAC5C;AACA;AACA,kBAAkB,2DAA2D;AAC7E;AACA,YAAY,wCAAwC;AACpD;AACA;AACA;AACA;AACA,YAAY,WAAW;AACvB;AACA;AACA;AACA;AACA,YAAY,wCAAwC;AACpD;AACA;AACA;AACA;AACA;AACA,YAAY,UAAU;AACtB;AACA,CAAC;;AAED;AACA,qDAAqD;AACrD,UAAU,OAAO;AACjB;;AAEA;AACA,0DAAe,QAAQ,kDAAkD,EAAC;;;ACzc1E;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEyC;AACuC;;AAEhF;AACA;AACA;AACA;AACA;AACO,2BAA2B,gBAAgB;AAClD;AACA;AACA,aAAa,0CAA0C;AACvD;AACA;AACA;AACA;AACA;;AAEA;AACA,QAAQ,2FAA2F,OAAO,qEAAqE;AAC/K;AACA;AACA,gCAAgC,qBAAqB;AACrD;AACA;AACA,aAAa,0BAA0B,WAAW,yCAAyC;AAC3F,aAAa,gCAAgC;AAC7C;AACA,aAAa,iBAAiB;AAC9B;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,wDAAwD;AACrE,aAAa,iBAAiB;AAC9B;AACA,eAAe,iBAAiB;AAChC;AACA;AACA;AACA,6BAA6B,MAAM,wBAAwB,YAAY;AACvE;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;;AAEA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA,kCAAkC,cAAc;AAChD;;AAEA;AACA;AACA;AACA,eAAe,SAAS;AACxB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;;;AAGL;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,SAAS;AACtB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,gBAAgB;AAC7B,eAAe,SAAS;AACxB,6CAA6C;AAC7C;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,UAAU;AACV;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY;AACZ;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,KAAK;AACjB;AACA,CAAC;;AAED;AACA,qDAAqD;AACrD,UAAU,OAAO;AACjB;;AAEA;AACA,wDAAe,YAAQ,8CAA8C,EAAC;;;AC5PtE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEuB;AACkB;AACuC;AACzB;AAClB;;AAErC;AACA;AACA;AACA;AACA;AACO,wBAAwB,gBAAgB;AAC/C;AACA;AACA,aAAa,0CAA0C;AACvD;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,wCAAwC;AACpD;AACA,CAAC;;AAED;AACA,QAAQ,2FAA2F,OAAO,4DAA4D;AACtK;AACA;AACO,6BAA6B,qBAAqB;AACzD;AACA;AACA,aAAa,0BAA0B,WAAW,yCAAyC;AAC3F,aAAa,gCAAgC;AAC7C;AACA,aAAa,iBAAiB;AAC9B;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,sBAAsB;AACnC;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,qBAAqB,yBAAC,mBAAmB,eAAe,YAAY,gBAAgB;AACpF;AACA;AACA;AACA;AACA,OAAO;AACP;;AAEA;AACA,oBAAoB,kBAAY;AAChC;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,wDAAwD;AACrE,aAAa,iBAAiB;AAC9B;AACA,eAAe,iBAAiB;AAChC;AACA;AACA;AACA,6BAA6B,MAAM,wBAAwB,YAAY;AACvE;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;;AAEA;AACA;AACA,aAAa,wDAAwD;AACrE,aAAa,wDAAwD;AACrE;AACA;AACA;AACA;AACA;AACA,gBAAgB,yBAAC;AACjB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;;AAEA;AACA;AACA,QAAQ;AACR;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,0DAA0D;AACvE;AACA,2BAA2B,wCAAwC;AACnE,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA;AACA,sBAAsB,WAAW;AACjC;AACA;AACA;AACA;AACA;AACA,UAAU;AACV;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,wDAAwD;AACrE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA,kCAAkC,UAAU;AAC5C;;AAEA;AACA;AACA;AACA,eAAe,SAAS;AACxB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,SAAS;AACtB;AACA;AACA,IAAI,yBAAC;AACL;AACA;;AAEA;AACA;AACA;AACA,aAAa,gBAAgB;AAC7B,eAAe,SAAS;AACxB,6CAA6C;AAC7C;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,wDAAwD,KAAK;AAC7D;AACA;AACA;AACA;AACA;AACA,gBAAgB,KAAK;AACrB;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,cAAc;AACd;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,YAAY,6EAA6E;AACzF;AACA;AACA;AACA;AACA,YAAY,wCAAwC;AACpD;AACA;AACA;AACA;AACA;AACA,YAAY,UAAU;AACtB;AACA,CAAC;;AAED;AACA,qDAAqD;AACrD,UAAU,OAAO;AACjB;;AAEA;AACA,qDAAe,YAAQ,wCAAwC,EAAC;;;ACpahE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEuB;AACqC;AACH;AACd;AACK;AACQ;AACD;;AAEvD;AACA,kBAAkB,yCAAyC,oBAAoB,kDAAkD;AACjI;AACA;AACA,yDAAyD,uEAAuE;AAChI;AACA,aAAa,uEAAuE;AACpF;AACA;AACA;AACO,4BAA4B,QAAQ;AAC3C;AACA;AACA,aAAa,0CAA0C;AACvD;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,iBAAiB;AAC9B;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA,CAAC;;AAED;AACA,QAAQ,mDAAmD,OAAO,wEAAwE;AAC1I;AACA;AACO,iCAAiC,aAAa;AACrD;AACA;AACA,aAAa,0BAA0B,WAAW,yCAAyC;AAC3F,aAAa,gCAAgC;AAC7C;AACA,aAAa,iBAAiB;AAC9B;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA,6BAA6B,yBAAC;AAC9B;AACA;AACA;AACA;AACA,WAAW;AACX;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA,iBAAiB,mBAAa;;AAE9B;AACA;AACA;AACA;AACA;AACA,qBAAqB,mBAAa,0EAA0E,mBAAW;AACvH,mBAAmB,yBAAC,cAAc,gCAAgC;AAClE;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;;AAEP,wBAAwB,yBAAC,eAAe,yBAAyB;AACjE;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA;AACA;;AAEA;AACA,sBAAsB,4BAA4B;AAClD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,sCAAsC,mCAAmC;AACzE;AACA,aAAa,sBAAsB;AACnC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,0BAA0B,SAAS;AACnC;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,sBAAsB;AACnC,eAAe;AACf;AACA;AACA;AACA;AACA,MAAM,YAAM;AACZ;;AAEA;AACA;AACA;AACA,aAAa,sBAAsB;AACnC;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,qBAAqB,yBAAC;AACtB;AACA;AACA;AACA,OAAO;;AAEP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA,QAAQ;AACR;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ,oBAAoB,2DAA2D;AACpG,aAAa,YAAY;AACzB;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,sBAAsB;AAClC;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,YAAY;AACZ;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,UAAU;AACV;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA,sBAAsB,4BAA4B;AAClD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,gBAAgB;AAC7B,eAAe,SAAS;AACxB,6CAA6C;AAC7C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAwB,KAAK;AAC7B;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY,iBAAiB;AAC7B;AACA;AACA;AACA;AACA,YAAY,WAAW;AACvB;AACA;AACA,UAAU,2DAA2D;AACrE;AACA,YAAY,wCAAwC;AACpD;AACA;AACA,kBAAkB,2DAA2D;AAC7E;AACA,YAAY,wCAAwC;AACpD;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA;AACA,YAAY,UAAU;AACtB;AACA,CAAC;;AAED;AACA,qDAAqD;AACrD,UAAU,OAAO;AACjB;;AAEA;AACA,yDAAe,QAAQ,oDAAoD,EAAC;;;AC5iB5E;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEuB;AACqC;AAC0B;;AAEtF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,oBAAoB,8BAAmB;AAC9C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa,SAAS;AACtB,qBAAqB,OAAO;AAC5B;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,iBAAiB;AAC9B;AACA;AACA;AACA,oBAAoB,yBAAC;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,yBAAyB,UAAU;AACnC,2BAA2B,UAAU;AACrC,0BAA0B,UAAU;AACpC,yBAAyB,UAAU;AACnC;AACA;AACA,yBAAyB,UAAU;AACnC,yBAAyB,UAAU;AACnC,yBAAyB,UAAU;AACnC,0BAA0B,UAAU;AACpC,0BAA0B,UAAU;AACpC;AACA;AACA;AACA,8BAA8B,SAAS;AACvC;AACA,8BAA8B,SAAS;AACvC,6BAA6B,UAAU;AACvC,8BAA8B,UAAU;AACxC;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;;AAEA;AACA;AACA;AACA;AACA,eAAe,QAAQ;AACvB;AACA;AACA,WAAW,OAAO;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA,WAAW,OAAO;AAClB;AACA,QAAQ,gCAAgC;AACxC,QAAQ,gCAAgC;AACxC;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,kCAAkC,4CAA4C;AAC9E,iCAAiC,sDAAsD;AACvF,aAAa,mCAAmC;AAChD,aAAa,wCAAwC;AACrD,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,eAAe,SAAS;AACxB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ;AACR;AACA;AACA,QAAQ;AACR;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,yBAAyB,uDAAuD;AAChF,aAAa,wCAAwC;AACrD,eAAe,SAAS;AACxB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,oBAAoB,eAAe;AACnC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,sBAAsB,QAAQ;AAC9B;AACA;AACA,iBAAiB,QAAQ;AACzB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,oBAAoB,eAAe;AACnC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,sBAAsB,QAAQ;AAC9B;AACA;AACA,iBAAiB,QAAQ;AACzB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,oBAAoB,eAAe;AACnC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,oBAAoB,eAAe;AACnC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,2DAA2D;AACxE,eAAe,SAAS;AACxB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,gBAAgB,YAAY;AAC5B;AACA,kBAAkB,eAAe;AACjC;AACA;AACA,sBAAsB,OAAO;AAC7B;AACA;AACA;AACA;AACA;AACA,UAAU;AACV;AACA;AACA;AACA;;AAEA;AACA,2BAA2B,OAAO;AAClC,oBAAoB,OAAO;AAC3B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,gBAAgB,YAAY;AAC5B;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA,qBAAqB,GAAG,WAAW,GAAG,MAAM,SAAS,MAAM,GAAG;AAC9D;AACA,qBAAqB,GAAG,MAAM,SAAS,MAAM,GAAG,WAAW,GAAG;;AAE9D;AACA;AACA;AACA,gCAAgC,GAAG,WAAW,GAAG,MAAM,SAAS,YAAY,GAAG,MAAM,SAAS,gBAAgB,GAAG;AACjH;;AAEA;AACA;AACA,gCAAgC,GAAG,gBAAgB,SAAS,MAAM,GAAG,YAAY,SAAS,MAAM,GAAG,WAAW,GAAG;AACjH;;AAEA;AACA;AACA,gCAAgC,GAAG,WAAW,GAAG,WAAW,GAAG,OAAO,GAAG,WAAW,GAAG,WAAW,GAAG;AACrG;;AAEA;AACA;AACA,0CAA0C,GAAG,MAAM,SAAS,MAAM,GAAG,OAAO,GAAG,MAAM,SAAS,MAAM,GAAG;AACvG;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,kBAAkB,YAAY;AAC9B,oBAAoB,OAAO;AAC3B;AACA;AACA;AACA;AACA;AACA;AACA,UAAU;AACV;AACA;;AAEA;AACA,kBAAkB,OAAO;AACzB;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,+BAA+B;AAC/B;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,wCAAwC;AACpD;AACA;AACA;AACA;AACA,YAAY,wCAAwC;AACpD;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA,WAAW;AACX;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,iBAAiB;AAC9B;AACA;AACA;AACA,IAAI,WAAW;AACf;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA,sBAAsB,yBAAC;AACvB;AACA;AACA,yBAAyB,UAAU;AACnC,wBAAwB,UAAU;AAClC,6BAA6B,UAAU;AACvC;AACA;AACA,OAAO;AACP,KAAK;AACL;AACA;;AAEA;AACA;AACA;AACA;AACA,eAAe,QAAQ;AACvB;AACA;AACA,WAAW,OAAO;AAClB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA,WAAW,OAAO;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,UAAU;AACtB;AACA,CAAC;;AAED;AACA;AACA,mBAAmB;AACnB,gBAAgB;AAChB;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,kDAAe,8BAAmB,qCAAqC,EAAC;;;AC/1BxE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEqC;;AAErC;AACA,eAAe,yCAAyC;AACxD,QAAQ,kGAAkG;AAC1G,4FAA4F,kDAAkD,YAAY,iDAAiD;AAC3M,gFAAgF;AAChF,wCAAwC,8EAA8E;AACtH;AACA;AACO,qCAAqC,eAAQ;AACpD;AACA;AACA,aAAa,gCAAgC,UAAU,kDAAkD;AACzG;AACA;AACA;AACA,wBAAwB,2BAA2B,GAAG,gCAAgC;AACtF;;AAEA;AACA;AACA;AACA;AACA,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,eAAQ;AACnB;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,SAAS;AACtB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY,kBAAkB;AAC9B;AACA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA,CAAC;;AAED;AACA,oEAAe,eAAQ,gEAAgE,EAAC;;;AClIxF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEuB;AACc;AACiB;;AAEtD;AACA,yBAAyB,yCAAyC;AAClE,QAAQ,kGAAkG;AAC1G;AACA,gDAAgD,kDAAkD,YAAY,iDAAiD;AAC/J;AACA;AACO,0BAA0B,eAAQ;AACzC;AACA;AACA,aAAa,gCAAgC,UAAU,kDAAkD;AACzG;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,OAAO;AACpB,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,sCAAsC;AACnD;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,sBAAsB,uBAAuB;AAC7C;;AAEA,MAAM,GAAG;;AAET;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA,WAAW;AACX;AACA;AACA;AACA,iDAAiD,iBAAiB,GAAG,YAAY,EAAE,YAAY;AAC/F;AACA,WAAW;AACX,OAAO;AACP;AACA;;AAEA;AACA;AACA;AACA;AACA,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,SAAS,UAAU;AACnB,0BAA0B,cAAc;AACxC;AACA,yBAAyB,eAAe,KAAK,gBAAgB,EAAE,cAAc;;AAE7E;AACA;AACA;AACA;AACA;AACA,UAAU,yBAAC;AACX,2BAA2B,yBAAC;AAC5B;AACA,WAAW;AACX;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,+BAA+B,MAAM;AACrC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW;AACX;AACA,iDAAiD,IAAI;AACrD,WAAW;AACX,SAAS;AACT;AACA;AACA,uDAAuD,iBAAiB,GAAG,YAAY,EAAE,YAAY;AACrG,SAAS;AACT,KAAK;AACL;;AAEA;AACA;AACA;AACA,aAAa,0CAA0C,WAAW,6DAA6D;AAC/H;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,SAAS;AACtB,eAAe,kBAAkB;AACjC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,wCAAwC,yBAAC;AACzC;AACA,eAAe;AACf;AACA;AACA,gEAAgE,iBAAiB,GAAG,YAAY,EAAE,YAAY;AAC9G,eAAe;AACf,WAAW;AACX,UAAU;AACV;AACA,OAAO;AACP;;AAEA;AACA;AACA;AACA,eAAe,kBAAkB;AACjC;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,iBAAiB;AAC9B,eAAe,gBAAgB,OAAO,sBAAsB;AAC5D;AACA,kBAAkB,gEAAgE;AAClF;AACA;AACA;AACA;AACA,MAAM,8BAAM;AACZ;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;;AAEA;AACA;AACA;AACA,eAAe,kBAAkB;AACjC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,yBAAC;AACb,6BAA6B,yBAAC;AAC9B,mCAAmC,kDAAkD;AACrF,aAAa;AACb;AACA,WAAW;AACX;AACA,wDAAwD,iBAAiB,GAAG,YAAY,EAAE,YAAY;AACtG,WAAW;AACX;AACA,KAAK;AACL;;AAEA;AACA;AACA;AACA;AACA,aAAa,OAAO;AACpB,eAAe,kBAAkB;AACjC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,yBAAC;AACb,4BAA4B,yBAAC;AAC7B,6BAA6B;AAC7B;AACA;AACA;AACA,aAAa;AACb;AACA,WAAW;AACX;AACA,uDAAuD,iBAAiB,GAAG,YAAY,EAAE,YAAY;AACrG,WAAW;AACX;AACA,KAAK;AACL;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,eAAe,kBAAkB;AACjC;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA,0BAA0B,yBAAC;AAC3B;AACA,2BAA2B,MAAM;AACjC;AACA,cAAc;AACd,6BAA6B;AAC7B;AACA;AACA;AACA;AACA,WAAW;AACX;AACA,sDAAsD,iBAAiB,GAAG,YAAY,EAAE,YAAY;AACpG,WAAW;AACX;AACA,KAAK;AACL;;AAEA;AACA;AACA;AACA,eAAe,kBAAkB;AACjC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oCAAoC,iBAAiB,GAAG,MAAM,kBAAkB;AAChF;AACA,OAAO;AACP;AACA;AACA;;AAEA;AACA,iBAAiB,uDAAuD;AACxE;AACA,aAAa,SAAS;AACtB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;;AAEA;AACA;AACA;AACA,aAAa,0BAA0B,WAAW,yCAAyC;AAC3F;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,SAAS;AACtB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,UAAU;AACtB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,uCAAuC;AACnD;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA,cAAc,uDAAuD;AACrE;AACA,YAAY,wCAAwC;AACpD;AACA;AACA;AACA;AACA,YAAY,wCAAwC;AACpD;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA,CAAC;;AAED;AACA;AACA;AACA;AACO;AACP;AACA;AACA,gBAAgB,QAAQ;AACxB;AACA;AACA,mBAAmB,gBAAgB;AACnC;AACA;AACA,iBAAiB,yBAAC,mBAAmB,QAAQ;AAC7C;AACA;AACA;;AAEA;AACA;AACA,aAAa,iBAAiB;AAC9B;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,uBAAuB;AACpC;AACA;AACA;AACA,sBAAsB,yBAAC,oBAAoB,0BAA0B;AACrE;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY,iBAAiB;AAC7B;AACA,CAAC;;AAED;;AAEA;AACA,yDAAe,eAAQ,0CAA0C,EAAC;;;ACnnBlE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEiC;AACY;;AAE7C;AACA;AACA,SAAS,2CAA2C;AACpD;AACA;AACO,qBAAqB,cAAM;AAClC;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oBAAoB,iBAAiB;AACrC;AACA;AACA;;AAEA,sBAAsB,kBAAkB;AACxC,wBAAwB,kBAAkB;AAC1C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,oBAAoB,gBAAgB;AACpC,sBAAsB,gBAAgB;AACtC;AACA;AACA,uBAAuB,IAAI,MAAM,UAAU;AAC3C;AACA;AACA;AACA;AACA,yBAAyB,UAAU;AACnC;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,iBAAiB;AAC9B,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,SAAS;AACtB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,uBAAuB,UAAU;AACjC;AACA;AACA;AACA;AACA,uBAAuB,UAAU;AACjC;AACA;AACA,uBAAuB,UAAU;AACjC,uBAAuB,UAAU;AACjC,uBAAuB,UAAU;AACjC;AACA,uBAAuB,UAAU;AACjC;AACA;;AAEA;AACA;AACA;AACA,aAAa,iBAAiB;AAC9B,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,SAAS;AACtB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,uBAAuB,UAAU;AACjC,MAAM;AACN;AACA;AACA;AACA,uBAAuB,UAAU;AACjC;AACA;AACA,uBAAuB,UAAU;AACjC,uBAAuB,UAAU;AACjC,uBAAuB,UAAU;AACjC;AACA,uBAAuB,UAAU;AACjC;AACA;AACA;;AAEA;AACA,qDAAe,cAAM,iCAAiC,EAAC;;;AChKvD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEiC;AACA;AACM;;AAEvC;AACA,wBAAwB,4CAA4C,2CAA2C;AAC/G;AACA;AACA;AACO,4BAA4B,cAAM;AACzC;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB;AACA;AACA;AACA;;AAEA;AACA,gBAAgB;AAChB;AACA,aAAa,iBAAiB;AAC9B,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,SAAS;AACtB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,uBAAuB,UAAU;AACjC;AACA;AACA;AACA;;AAEA;AACA,uBAAuB,UAAU;AACjC;AACA;AACA,uBAAuB,UAAU;AACjC,uBAAuB,UAAU;AACjC,uBAAuB,UAAU;AACjC;AACA,uBAAuB,UAAU;AACjC;AACA;;AAEA;AACA,gBAAgB;AAChB;AACA,aAAa,iBAAiB;AAC9B,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,SAAS;AACtB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,uBAAuB,UAAU;AACjC;AACA;AACA;AACA;;AAEA;AACA,uBAAuB,UAAU;AACjC;AACA;AACA,uBAAuB,UAAU;AACjC,uBAAuB,UAAU;AACjC,uBAAuB,UAAU;AACjC;AACA,uBAAuB,UAAU;AACjC;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA,CAAC;;AAED;AACA,4DAAe,cAAM,+CAA+C,EAAC;;;ACzIrE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEiC;;AAEjC;AACA,SAAS,2CAA2C;AACpD;AACA,kCAAkC,2BAA2B,GAAG,0BAA0B,IAAI,sBAAsB;AACpH;AACA;AACA;AACA;AACA;AACO,oBAAoB,cAAM;AACjC;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,mCAAmC,0CAA0C;AAC7E;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;;AAEA;AACA,oDAAe,cAAM,+BAA+B,EAAC;;;AC5ErD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEiC;AACA;AACM;;AAEvC;AACA,SAAS,2CAA2C;AACpD;AACA;AACA;AACO,+BAA+B,cAAM;AAC5C;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB;AACA;AACA;AACA;;AAEA;AACA,gBAAgB;AAChB;AACA,aAAa,iBAAiB;AAC9B,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,SAAS;AACtB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,uBAAuB,UAAU;AACjC;AACA;AACA;AACA;AACA,uBAAuB,UAAU;AACjC;AACA;AACA,uBAAuB,UAAU;AACjC,uBAAuB,UAAU;AACjC;AACA,uBAAuB,UAAU;AACjC;AACA;;AAEA;AACA,gBAAgB;AAChB;AACA,aAAa,iBAAiB;AAC9B,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB,aAAa,SAAS;AACtB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,uBAAuB,UAAU;AACjC;AACA;AACA;AACA;;AAEA;AACA,uBAAuB,UAAU;AACjC;AACA;AACA,uBAAuB,UAAU;AACjC,uBAAuB,UAAU;AACjC;AACA,uBAAuB,UAAU;AACjC;AACA;AACA;;AAEA;AACA,+DAAe,cAAM,qDAAqD,EAAC;;;ACxH3E;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACO;AACP;AACA;AACA,aAAa,QAAQ;AACrB,aAAa,iBAAiB;AAC9B;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,SAAS;AACtB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY;AACZ;AACA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA;AACA,YAAY;AACZ;AACA;AACA,CAAC;;AAED,oDAAe,OAAO,EAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACvJvB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEuB;AACU;AACJ;AACiB;AACX;AACyB;;AAE5D;AACwC;AACQ;AACU;AACb;AACA;AACY;AACQ;AAClB;AACF;AACM;AACN;AACE;AACI;;AAEnD;AACA,wBAAwB,mCAAmC;AAC3D;AACA;AACO,0BAA0B,UAAI;AACrC;AACA;AACA,aAAa,gCAAgC,mCAAmC,iDAAiD;AACjI;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB;AACA;AACA,2CAA2C;AAC3C;AACA;AACA;;AAEA,IAAI,IAAI;;AAER;AACA,oBAAoB,yBAAC,aAAa,4DAA4D;AAC9F;;AAEA;AACA,UAAU,MAAM;AAChB,wBAAwB,yBAAC,gBAAgB,kDAAkD;AAC3F,cAAc,yBAAC,CAAC,MAAM;AACtB;AACA;AACA;AACA,OAAO;AACP;;AAEA;AACA,sBAAsB,eAAS;AAC/B;AACA,sBAAsB,yBAAC,aAAa,sBAAsB;AAC1D;AACA;AACA;AACA,OAAO;AACP;;AAEA;AACA,UAAU,MAAM;AAChB,wBAAwB,yBAAC,gBAAgB,kDAAkD;AAC3F,cAAc,yBAAC,CAAC,MAAM;AACtB;AACA;AACA;AACA,OAAO;AACP;;AAEA;AACA;AACA;AACA,YAAY,MAAM;AAClB,wBAAwB,yBAAC,gBAAgB,2CAA2C;AACpF;AACA;AACA;AACA,SAAS;AACT,MAAM,8BAAM,CAAC,UAAI;AACjB,cAAc,MAAM;AACpB,kCAAkC,aAAO,OAAO,yBAAC,aAAa,sDAAsD;AACpH;AACA,uCAAuC,QAAQ,2FAA2F;AAC1I;AACA,WAAW;AACX;AACA;AACA,OAAO;AACP;AACA;;AAEA;AACA;AACA,YAAY,MAAM;AAClB,0BAA0B,yBAAC,gBAAgB,kDAAkD;AAC7F,gBAAgB,yBAAC,CAAC,MAAM;AACxB;AACA;AACA;AACA,SAAS;AACT;AACA;;AAEA;AACA;AACA,YAAY,MAAM;AAClB,2BAA2B,yBAAC,gBAAgB,kDAAkD;AAC9F,gBAAgB,yBAAC,CAAC,MAAM;AACxB;AACA;AACA;AACA,SAAS;AACT;AACA;;AAEA;AACA;AACA,YAAY,MAAM;AAClB,gCAAgC,yBAAC,gBAAgB,kDAAkD;AACnG,gBAAgB,yBAAC,aAAa,KAAK,QAAQ,uEAAuE;AAClH;AACA;AACA,SAAS;AACT;AACA;;AAEA;AACA;AACA,YAAY,MAAM;AAClB;AACA,2BAA2B,yBAAC,gBAAgB,kDAAkD;AAC9F,gBAAgB,yBAAC,CAAC,MAAM;AACxB;AACA,UAAU,GAAG;AACb;AACA,SAAS;AACT;AACA;;AAEA;AACA;AACA;AACA;AACA,IAAI,8BAAM;AACV;AACA;AACA,0BAA0B,GAAG;AAC7B;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA;AACA,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA,cAAc,6BAA6B,EAAE,8HAA8H;AAC3K;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,wDAAwD,QAAQ;AAChE;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,SAAS;AACtB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,YAAY;AACZ;AACA;AACA;AACA;AACA;AACA,YAAY,iBAAiB;AAC7B;AACA;AACA,oDAAoD;AACpD;AACA,YAAY,QAAQ;AACpB;AACA;AACA,gBAAgB;AAChB;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB,SAAS;AACT;AACA;AACA;AACA,YAAY,QAAQ;AACpB,aAAa;AACb;AACA;AACA;AACA,YAAY,QAAQ;AACpB,kBAAkB;AAClB;AACA;AACA;AACA,YAAY,UAAU;AACtB;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB,UAAU;AACV;AACA;AACA;AACA,YAAY,QAAQ;AACpB,UAAU;AACV;AACA;AACA;AACA,YAAY,QAAQ;AACpB,gBAAgB;AAChB;AACA;AACA;AACA,YAAY,QAAQ;AACpB,oBAAoB;AACpB;AACA;AACA;AACA,YAAY,QAAQ;AACpB,WAAW;AACX;AACA;AACA;AACA,YAAY,QAAQ;AACpB,UAAU;AACV;AACA;AACA;AACA,YAAY,QAAQ;AACpB,aAAa;AACb;AACA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB,UAAU;AACV;AACA;AACA;AACA,YAAY,QAAQ;AACpB,WAAW;AACX;AACA;AACA;AACA,YAAY,QAAQ;AACpB,aAAa;AACb,CAAC;;AAED;AACA,wDAAe,UAAI,sCAAsC,EAAC;;;ACvX1D;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAE6B;AACc;;;AAG3C;AACA,qCAAqC,mCAAmC;AACxE,oBAAoB,wDAAwD;AAC5E;AACA;AACO,uBAAuB,iBAAW;AACzC;AACA;AACA,aAAa,gCAAgC,mCAAmC,iDAAiD;AACjI;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB;AACA,2CAA2C;AAC3C;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB,iBAAiB,0BAA0B;AAC3C,CAAC;;AAED;AACA,qDAAe,UAAI,gCAAgC,EAAC;;;AC/EpD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEuB;AACM;AACM;AAC6B;AAC1B;AACQ;;AAE9C;AACA,WAAW,mCAAmC;AAC9C;AACA;AACO,yBAAyB,UAAI;;AAEpC;AACA;AACA;AACA,aAAa,gCAAgC,mCAAmC,iDAAiD;AACjI;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA;;AAEA,sBAAsB,yBAAC,aAAa,+BAA+B;AACnE,sBAAsB,yBAAC,aAAa,yBAAyB;AAC7D,oBAAoB,OAAO;AAC3B,6BAA6B,yBAAC,aAAa,6BAA6B,MAAM,GAAG;AACjF;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,oBAAoB,MAAM;AAC1B,2BAA2B,yBAAC,gBAAgB,sCAAsC,GAAG,qFAAqF;AAC1K,gCAAgC,uDAAuD;AACvF;AACA,OAAO;AACP;;AAEA;AACA;AACA,wBAAwB,eAAS;AACjC;AACA,wBAAwB,yBAAC,aAAa,sBAAsB;AAC5D;AACA;AACA;AACA,SAAS;AACT;AACA;;AAEA;AACA;AACA,MAAM,8BAAM,CAAC,UAAI;AACjB;AACA,sBAAsB,MAAM;AAC5B,oCAAoC,aAAO,OAAO,yBAAC,aAAa,8CAA8C,KAAK,kCAAkC;AACrJ;AACA;AACA;AACA,OAAO;AACP;;AAEA;AACA;AACA,gCAAgC,yBAAC,aAAa,gDAAgD;AAC9F;AACA;;AAEA;;AAEA;AACA;AACA;AACA,aAAa,SAAS;AACtB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;;AAEA,4BAA4B;AAC5B;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,+BAA+B,aAAa,sBAAsB,SAAS;AAC3E,+BAA+B,aAAa,sBAAsB,SAAS;AAC3E,+BAA+B,aAAa,sBAAsB,SAAS;AAC3E,+BAA+B,aAAa,sBAAsB,SAAS;AAC3E,+BAA+B,aAAa,sBAAsB,SAAS;AAC3E,+BAA+B,aAAa,sBAAsB,SAAS;AAC3E,+BAA+B,aAAa,sBAAsB,SAAS;AAC3E,+BAA+B,aAAa,sBAAsB,SAAS;;AAE3E;AACA,2BAA2B,YAAY,kBAAkB,oBAAoB,UAAU;AACvF,qBAAqB,kBAAkB,WAAW,YAAY,aAAa,wBAAwB,UAAU,SAAS,UAAU,GAAG,qBAAqB,UAAU,SAAS,UAAU;AACrL,gBAAgB,4BAA4B;AAC5C,sBAAsB,kBAAkB,MAAM,UAAU,GAAG,QAAQ,UAAU,GAAG,SAAS,UAAU,GAAG,OAAO,UAAU;AACvH,iBAAiB,uBAAuB,KAAK;AAC7C,iBAAiB,uBAAuB,KAAK,EAAE;AAC/C,iBAAiB,uBAAuB,KAAK;AAC7C,iBAAiB,uBAAuB,KAAK,EAAE;AAC/C;AACA,iBAAiB,uBAAuB,KAAK,EAAE;AAC/C,iBAAiB,uBAAuB,KAAK;AAC7C,iBAAiB,uBAAuB,KAAK,EAAE;AAC/C,iBAAiB,uBAAuB,KAAK,GAAG;;AAEhD;AACA,qBAAqB,wBAAwB,4BAA4B,SAAS,4BAA4B,GAAG,qBAAqB,4BAA4B,SAAS,4BAA4B;AACvM,sBAAsB,MAAM,4BAA4B,GAAG,QAAQ,4BAA4B,GAAG,SAAS,4BAA4B,GAAG,OAAO,4BAA4B;AAC7K,qBAAqB,uBAAuB;;AAE5C;AACA,qBAAqB,wBAAwB,gCAAgC,SAAS,gCAAgC,GAAG,qBAAqB,gCAAgC,SAAS,gCAAgC;AACvN,sBAAsB,MAAM,gCAAgC,GAAG,QAAQ,gCAAgC,GAAG,SAAS,gCAAgC,GAAG,OAAO,gCAAgC;AAC7L,qBAAqB,yBAAyB;;AAE9C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qCAAqC;AACrC;AACA;AACA;AACA,iCAAiC,EAAE,aAAa,YAAY;AAC5D,qCAAqC,0BAA0B,aAAa,sCAAsC;AAClH,0CAA0C,8BAA8B,aAAa,0CAA0C;AAC/H;AACA,gCAAgC,EAAE,cAAc,YAAY;AAC5D,oCAAoC,0BAA0B,cAAc,sCAAsC;AAClH,yCAAyC,8BAA8B,cAAc,0CAA0C;AAC/H;AACA;AACA,2BAA2B,KAAK,kBAAkB,EAAE,GAAG,GAAG,EAAE,GAAG,GAAG,QAAQ,EAAE,GAAG,SAAS,EAAE,GAAG,iBAAiB,OAAO,aAAa,uBAAuB,GAAG,MAAM,GAAG,eAAe;AACpL,+BAA+B,KAAK,EAAE,OAAO,GAAG,EAAE,OAAO,IAAI;AAC7D,oCAAoC,KAAK,EAAE,YAAY,GAAG,EAAE,YAAY,IAAI;AAC5E;AACA,6BAA6B,GAAG,SAAS,uBAAuB,yBAAyB,MAAM,wBAAwB,eAAe;AACtI;AACA,6BAA6B,GAAG,QAAQ,uBAAuB,uBAAuB,MAAM,sBAAsB,eAAe;AACjI;AACA,6BAA6B,GAAG,WAAW,uBAAuB,2BAA2B,MAAM,0BAA0B,eAAe;AAC5I,OAAO;AACP;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAiB,UAAU;AAC3B;AACA;AACA;AACA;AACA,yBAAyB,wCAAwC;AACjE;;AAEA,iCAAiC,YAAY,UAAU,GAAG,QAAQ,QAAQ;AAC1E;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAiC,EAAE,aAAa,YAAY;AAC5D,qCAAqC,0BAA0B,aAAa,sCAAsC;AAClH,0CAA0C,8BAA8B,aAAa,0CAA0C;AAC/H;AACA;AACA,gCAAgC,EAAE,cAAc,YAAY;AAC5D,oCAAoC,0BAA0B,cAAc,sCAAsC;AAClH,yCAAyC,8BAA8B,cAAc,0CAA0C;AAC/H;AACA,+BAA+B,IAAI,kBAAkB,EAAE,GAAG,GAAG,EAAE,GAAG,GAAG,QAAQ,EAAE,GAAG,SAAS,EAAE,GAAG,cAAc,EAAE,IAAI;AACpH;AACA,+BAA+B,EAAE,SAAS,WAAW,MAAM,IAAI,EAAE,YAAY,UAAU,GAAG,cAAc,aAAa,QAAQ,IAAI,GAAG,SAAS,IAAI,GAAG,cAAc,IAAI,GAAG,kBAAkB,MAAM,OAAO,GAAG,OAAO,OAAO,IAAI;AAC7N;AACA,mCAAmC,IAAI,EAAE,OAAO,GAAG,EAAE,OAAO,IAAI;AAChE,wCAAwC,IAAI,EAAE,YAAY,GAAG,EAAE,YAAY,IAAI;AAC/E,OAAO;AACP;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,+BAA+B,EAAE,aAAa,YAAY;AAC1D,mCAAmC,0BAA0B,aAAa,sCAAsC;AAChH,wCAAwC,8BAA8B,aAAa,0CAA0C;AAC7H;AACA,8BAA8B,EAAE,cAAc,YAAY;AAC1D,kCAAkC,0BAA0B,cAAc,sCAAsC;AAChH,uCAAuC,8BAA8B,cAAc,0CAA0C;AAC7H;AACA;AACA,2CAA2C,kBAAkB,EAAE,GAAG,GAAG,EAAE,GAAG,GAAG,QAAQ,EAAE,GAAG,SAAS,EAAE,GAAG,iBAAiB,OAAO,EAAE,uBAAuB,GAAG,MAAM,GAAG,IAAI;AACzK,+CAA+C,EAAE,OAAO,GAAG,EAAE,OAAO,IAAI;AACxE,oDAAoD,EAAE,YAAY,GAAG,EAAE,YAAY,IAAI;;AAEvF;AACA;AACA;AACA;AACA,mCAAmC,MAAM,sBAAsB,2BAA2B,KAAK,2BAA2B,KAAK,+BAA+B,kBAAkB,qBAAqB,WAAW,UAAU,YAAY;AACtO;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,mCAAmC,OAAO,cAAc,yBAAyB;AACjF,uCAAuC,uBAAuB,cAAc,2CAA2C;AACvH,4CAA4C,2BAA2B,cAAc,+CAA+C;;AAEpI,gCAAgC,kBAAkB,OAAO,KAAK,GAAG,QAAQ,MAAM,GAAG,SAAS,UAAU,GAAG,EAAE,GAAG,IAAI;AACjH,oCAAoC,OAAO,qBAAqB,GAAG,QAAQ,sBAAsB,GAAG,SAAS,0BAA0B,GAAG,EAAE,OAAO,IAAI;AACvJ,yCAAyC,OAAO,yBAAyB,GAAG,QAAQ,0BAA0B,GAAG,SAAS,8BAA8B,GAAG,EAAE,YAAY,IAAI;AAC7K;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,QAAQ;AACrB;AACA,eAAe;AACf;AACA;AACA;AACA;AACA,cAAc,6BAA6B,EAAE,8BAA8B;AAC3E;;AAEA;AACA;AACA;AACA,aAAa,SAAS;AACtB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA,qBAAqB,UAAU;AAC/B,qBAAqB,WAAW;AAChC,mBAAmB,8BAA8B,mBAAmB;AACpE;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA,YAAY,iBAAiB;AAC7B;AACA,CAAC;;AAED;AACA,uDAAe,UAAI,oCAAoC,EAAC;;;AC3ZxD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAE6B;AACiB;;AAE9C;AACA,iBAAiB,mCAAmC;AACpD;AACA;AACO,wBAAwB,UAAI;;AAEnC;AACA;AACA;AACA,aAAa,gCAAgC,mCAAmC,iDAAiD;AACjI;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB;AACA,2CAA2C;AAC3C;AACA;AACA,sBAAsB,eAAS;AAC/B;AACA;AACA;AACA;AACA;AACA,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB,iCAAiC,UAAU;AAC3C,CAAC;;AAED;AACA,sDAAe,UAAI,kCAAkC,EAAC;;;ACjFtD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAE6B;AACc;;AAE3C;AACA,qCAAqC,mCAAmC;AACxE,oBAAoB,wDAAwD;AAC5E;AACA;AACO,wBAAwB,iBAAW;AAC1C;AACA;AACA;AACA,aAAa,gCAAgC,mCAAmC,iDAAiD;AACjI;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB;AACA,2CAA2C;AAC3C;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB,iBAAiB,0BAA0B;AAC3C,CAAC;;AAED;AACA,sDAAe,UAAI,kCAAkC,EAAC;;;;;AC7FtD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAE6B;AACc;;AAE3C;AACwC;;AAExC;AACA,qCAAqC,mCAAmC;AACxE,oBAAoB,wDAAwD;AAC5E;AACA;AACO,uBAAuB,iBAAW;AACzC;AACA;AACA;AACA,aAAa,gCAAgC,mCAAmC,iDAAiD;AACjI;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB;AACA,2CAA2C;AAC3C;AACA,oCAAoC,aAAa,mCAAmC;AACpF;;AAEA;AACA;AACA;AACA,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,YAAY;AACZ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB,SAAS;AACT;AACA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA,CAAC;;AAED;AACA,qDAAe,UAAI,gCAAgC,EAAC;;;ACjIpD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAE6B;AACc;;AAE3C;AACA,qCAAqC,mCAAmC;AACxE,oBAAoB,wDAAwD;AAC5E;AACA;AACO,yBAAyB,iBAAW;AAC3C;AACA;AACA,aAAa,gCAAgC,mCAAmC,iDAAiD;AACjI;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB;AACA,2CAA2C;AAC3C;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB,iBAAiB,0BAA0B;AAC3C,CAAC;;AAED,uDAAe,UAAI,oCAAoC,EAAC;;;;;;;;;AC7ExD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEuB;AACM;AACc;;AAE3C;AAC0C;AACQ;AACU;;AAE5D;AACA,qCAAqC,mCAAmC;AACxE;AACA;AACA;AACO,yBAAyB,iBAAW;AAC3C;AACA;AACA,aAAa,gCAAgC,mCAAmC,iDAAiD;AACjI;AACA,aAAa,QAAQ;AACrB,aAAa,QAAQ;AACrB;AACA,2CAA2C;AAC3C;AACA,oCAAoC,aAAa,mCAAmC;;AAEpF;AACA;AACA;AACA,IAAI,yBAAC,iBAAiB,gBAAgB;AACtC;;AAEA;AACA;AACA;AACA,aAAa,QAAQ;AACrB,eAAe;AACf;AACA;AACA,cAAc,6BAA6B,EAAE,8HAA8H;AAC3K;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB;AACA;AACA;AACA;AACA,YAAY,QAAQ;AACpB,SAAS;AACT,aAAa;AACb,kBAAkB;AAClB,CAAC;;AAED;AACA,uDAAe,UAAI,oCAAoC,EAAC;;;AC3FxD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACyB;;AAEF;AACI;AACU;AACI;AACE;AACZ;AACgB;AACkC;AACF;AACpB;AACN;AACE;AACkB;AAC1B;AACiB;AACI;AACR;AACP;AACE;AACM;AACF;AACE;AACA;AACN;AACc;AACQ;AACd;AACf;AACsB;AACE;AACd;AACQ;AACF;AACtB;AACc;AACd;AACO;AACU;AACR;AACQ;AACN;AACR;AACN;AACE;AACU;AACM;AACd;AACY;AACM;AACZ;AACc;AACd;AACE;AACM;AACJ;AACM;AACb;AACI;AACF;AACJ;AACN;AACY;AACF;AACwB;AACtB;AACK;AAChB;AACE;AACU;AACV;AACoB;AAClB;AACF;AACM;AACE;AACJ;AACA;AACF;AACI;AACA;AACZ;;AAEnC;AACA,iDAAgB;AAChB,GAAG;AACH,KAAK;AACL,UAAU;AACV,YAAY;AACZ,aAAa;AACb,OAAO;AACP,eAAe;AACf,cAAc;AACd;AACA,sBAAsB;AACtB,qBAAqB;AACrB,cAAc;AACd,WAAW;AACX,YAAY;AACZ,qBAAqB;AACrB,QAAQ;AACR,gBAAgB;AAChB,kBAAkB;AAClB,cAAc;AACd,YAAY;AACZ,aAAa;AACb,gBAAgB;AAChB,aAAa;AACb,cAAc;AACd,gBAAgB;AAChB,aAAa;AACb,oBAAoB;AACpB,wBAAwB;AACxB,iBAAiB;AACjB,GAAG;AACH;AACA,SAAS;AACT,uBAAuB;AACvB,GAAG;AACH;AACA,2BAA2B;AAC3B,oBAAoB;AACpB,wBAAwB;AACxB,uBAAuB;AACvB,YAAY;AACZ,mBAAmB;AACnB,YAAY;AACZ,GAAG;AACH;AACA,eAAe;AACf,oBAAoB;AACpB,gBAAgB;AAChB,oBAAoB;AACpB,iBAAiB;AACjB,aAAa;AACb,UAAU;AACV,WAAW;AACX,gBAAgB;AAChB,mBAAmB;AACnB,YAAY;AACZ,GAAG;AACH;AACA,kBAAkB;AAClB,qBAAqB;AACrB,eAAe;AACf,sBAAsB;AACtB,eAAe;AACf,gBAAgB;AAChB,mBAAmB;AACnB,GAAG;AACH;AACA,gBAAgB;AAChB,mBAAmB;AACnB,GAAG;AACH;AACA,aAAa;AACb,eAAe;AACf,cAAc;AACd,YAAY;AACZ,SAAS;AACT,eAAe;AACf,cAAc;AACd,0BAA0B;AAC1B,eAAe;AACf,GAAG;AACH;AACA,iBAAiB;AACjB,SAAS;AACT,UAAU;AACV,eAAe;AACf,UAAU;AACV,oBAAoB;AACpB,GAAG;AACH;AACA,YAAY;AACZ,WAAW;AACX,cAAc;AACd,eAAe;AACf,aAAa;AACb,aAAa;AACb,YAAY;AACZ,cAAc;AACd,cAAc;AACd,QAAQ;AACR,GAAG;AACH,CAAC,EAAE","sources":["webpack://jclic/webpack/bootstrap","webpack://jclic/webpack/runtime/compat get default export","webpack://jclic/webpack/runtime/define property getters","webpack://jclic/webpack/runtime/hasOwnProperty shorthand","webpack://jclic/external commonjs \"jsdom\"","webpack://jclic/external commonjs \"@xmldom/xmldom\"","webpack://jclic/./src/init-jsdom.js","webpack://jclic/external commonjs \"jquery\"","webpack://jclic/external commonjs \"jszip\"","webpack://jclic/external commonjs \"jszip-utils\"","webpack://jclic/./src/GlobalData.js","webpack://jclic/./src/Utils.js","webpack://jclic/external commonjs \"webfontloader\"","webpack://jclic/./src/AWT.js","webpack://jclic/./src/media/AudioBuffer.js","webpack://jclic/./src/media/ActiveMediaPlayer.js","webpack://jclic/./src/media/MediaContent.js","webpack://jclic/./src/media/EventSoundsElement.js","webpack://jclic/./src/media/EventSounds.js","webpack://jclic/./src/boxes/BoxBase.js","webpack://jclic/./src/boxes/ActiveBoxContent.js","webpack://jclic/./src/shapers/Shaper.js","webpack://jclic/./src/boxes/ActiveBagContent.js","webpack://jclic/./src/automation/AutoContentProvider.js","webpack://jclic/./src/boxes/TextGridContent.js","webpack://jclic/./src/activities/text/Evaluator.js","webpack://jclic/./src/activities/text/TextActivityDocument.js","webpack://jclic/./src/Activity.js","webpack://jclic/./src/PlayerHistory.js","webpack://jclic/./src/media/ActiveMediaBag.js","webpack://jclic/./src/skins/Skin.js","webpack://jclic/./src/project/ProjectSettings.js","webpack://jclic/./src/bags/JumpInfo.js","webpack://jclic/./src/bags/ConditionalJumpInfo.js","webpack://jclic/./src/bags/ActivitySequenceJump.js","webpack://jclic/./src/bags/ActivitySequenceElement.js","webpack://jclic/./src/bags/ActivitySequence.js","webpack://jclic/external commonjs \"@francesc/basic-midi-player-js\"","webpack://jclic/./src/media/MidiAudioPlayer.js","webpack://jclic/./src/bags/MediaBagElement.js","webpack://jclic/./src/bags/MediaBag.js","webpack://jclic/./src/project/JClicProject.js","webpack://jclic/./src/report/ActionReg.js","webpack://jclic/./src/report/ActivityReg.js","webpack://jclic/./src/report/SequenceReg.js","webpack://jclic/./src/report/SessionReg.js","webpack://jclic/./src/report/EncryptMin.js","webpack://jclic/./src/report/SCORM.js","webpack://jclic/./src/report/Reporter.js","webpack://jclic/./src/JClicPlayer.js","webpack://jclic/./src/boxes/AbstractBox.js","webpack://jclic/./src/boxes/BoxBag.js","webpack://jclic/./src/boxes/ActiveBoxBag.js","webpack://jclic/./src/boxes/ActiveBox.js","webpack://jclic/./src/boxes/ActiveBoxGrid.js","webpack://jclic/./src/boxes/BoxConnector.js","webpack://jclic/./src/activities/associations/SimpleAssociation.js","webpack://jclic/./src/activities/associations/ComplexAssociation.js","webpack://jclic/./src/shapers/Rectangular.js","webpack://jclic/./src/activities/memory/MemoryGame.js","webpack://jclic/./src/activities/panels/Explore.js","webpack://jclic/./src/activities/panels/Identify.js","webpack://jclic/./src/activities/panels/InformationScreen.js","webpack://jclic/./src/activities/panels/Menu.js","webpack://jclic/./src/activities/puzzles/DoublePuzzle.js","webpack://jclic/./src/activities/puzzles/ExchangePuzzle.js","webpack://jclic/./src/activities/puzzles/HolePuzzle.js","webpack://jclic/./src/activities/text/TextActivityBase.js","webpack://jclic/./src/activities/text/Complete.js","webpack://jclic/./src/activities/text/FillInBlanks.js","webpack://jclic/./src/boxes/TextGrid.js","webpack://jclic/./src/activities/textGrid/CrossWord.js","webpack://jclic/./src/activities/textGrid/WordSearch.js","webpack://jclic/./src/activities/text/IdentifyText.js","webpack://jclic/./src/activities/text/OrderText.js","webpack://jclic/./src/activities/text/WrittenAnswer.js","webpack://jclic/./src/automation/arith/Arith.js","webpack://jclic/./src/report/SessionStorageReporter.js","webpack://jclic/./src/report/TCPReporter.js","webpack://jclic/./src/shapers/JigSaw.js","webpack://jclic/./src/shapers/ClassicJigSaw.js","webpack://jclic/./src/shapers/Holes.js","webpack://jclic/./src/shapers/TriangularJigSaw.js","webpack://jclic/./src/skins/Counter.js","webpack://jclic/./src/skins/DefaultSkin.js","webpack://jclic/./src/skins/BlueSkin.js","webpack://jclic/./src/skins/CustomSkin.js","webpack://jclic/./src/skins/EmptySkin.js","webpack://jclic/./src/skins/GreenSkin.js","webpack://jclic/./src/skins/MiniSkin.js","webpack://jclic/./src/skins/OrangeSkin.js","webpack://jclic/./src/skins/SimpleSkin.js","webpack://jclic/./src/jclic-node.js"],"sourcesContent":["// The require scope\nvar __webpack_require__ = {};\n\n","// getDefaultExport function for compatibility with non-harmony modules\n__webpack_require__.n = (module) => {\n\tvar getter = module && module.__esModule ?\n\t\t() => (module['default']) :\n\t\t() => (module);\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};","// define getter functions for harmony exports\n__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","const __WEBPACK_NAMESPACE_OBJECT__ = require(\"jsdom\");","const __WEBPACK_NAMESPACE_OBJECT__ = require(\"@xmldom/xmldom\");","/*!\n * File : init-jsdom.js\n * Created : 12/11/2024\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2024 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\n/* global global, globalThis */\n\n/**\n * Initializes some global variables needed for JClic in order to be used in nodeJS\n */\n\nimport jsdom from 'jsdom';\nimport { DOMParser } from '@xmldom/xmldom';\n\n// Create a new DOM object\nconst dom = new jsdom.JSDOM('<!DOCTYPE html><head></head><body></body>', { url: 'https://example.com' });\n\n// `global` is a legacy object in NodeJS 22 and will be replaced soon by `globalThis`\n// Also, provide a fallback empty object in case of no `global` object at all (should not occur!)\nconst globalObject = globalThis || global || {};\n\n// Assign global variables, only if not already assigned\nif (!globalObject.window)\n globalObject.window = dom.window;\nif (!globalObject.document)\n globalObject.document = dom.window.document;\nif (!globalObject.navigator)\n globalObject.navigator = dom.window.navigator;\nif (!globalObject.Image)\n globalObject.Image = dom.window.Image;\nif (!globalObject.Audio)\n globalObject.Audio = dom.window.Audio;\nif (!globalObject.XMLHttpRequest)\n globalObject.XMLHttpRequest = dom.window.XMLHttpRequest;\nif (!globalObject.DOMParser)\n globalObject.DOMParser = DOMParser;\n\n// This is just a side-effect module\nexport default {};\n","const __WEBPACK_NAMESPACE_OBJECT__ = require(\"jquery\");","const __WEBPACK_NAMESPACE_OBJECT__ = require(\"jszip\");","const __WEBPACK_NAMESPACE_OBJECT__ = require(\"jszip-utils\");","\n// WARNING: Auto-generated file, based on \"language.po\" files stored in \"/locales\". Do not edit!\n// Launch \"npm run build-locales\" to update this file\n\nexport default {\"version\":\"2.2.1 (2026-02-14)\",\"languages\":[\"en\",\"ar\",\"ast\",\"bs\",\"ca\",\"ca_ES@valencia\",\"cs\",\"da\",\"de\",\"el\",\"es\",\"eu\",\"fr\",\"gl\",\"he\",\"hr\",\"it\",\"ja\",\"nb_NO\",\"nl\",\"pl\",\"pt\",\"pt_BR\",\"ro\",\"ru\",\"ta\",\"tr\",\"uk\",\"vec\",\"zh_TW\"],\"messages\":{\"ar\":{\"Version\":\"الإصدار\",\"time\":\"الوقت\",\"actions\":\"المحاولات\",\"score\":\"النتيجة\",\"Next activity\":\"النشاط التالي\",\"Previous activity\":\"النشاط السابق\",\"Restart activity\":\"استئنف النشاط\",\"Information\":\"المعلومة\",\"Results are not currently being saved\":\"Results are not currently being saved\",\"Current results\":\"تقارير المستخدم\",\"Session started:\":\"Session started:\",\"Reports system:\":\"Reports system:\",\"User:\":\"المستخدم:\",\"Projects:\":\"المشاريع:\",\"Sequences:\":\"التسلسل\",\"Activities done:\":\"Activities done:\",\"Activities solved:\":\"Activities solved:\",\"Global score:\":\"Global score:\",\"(out of all project activities)\":\"(out of all project activities)\",\"Total time in activities:\":\"Total time in activities:\",\"Actions done:\":\"المحاولات\",\"No activities done!\":\"No activities done!\",\"Project\":\"المشروع:\",\"sequence\":\"التسلسل\",\"activity\":\"النشاط\",\"OK\":\"موافق\",\"YES\":\"YES\",\"NO\":\"NO\",\"Total:\":\"المجموع:\",\"Select group:\":\"Select group:\",\"Select user:\":\"Select user:\",\"Cancel\":\"Cancel\",\"Close\":\"Close\",\"Copy data to clipboard\":\"Copy data to clipboard\",\"The data has been copied in HTML format. Please paste them into a spreadsheet or in a rich text editor\":\"The data has been copied in HTML format. Please paste them into a spreadsheet or in a rich text editor\",\"The data has been copied to clipboard\":\"The data has been copied to clipboard\",\"not connected\":\"not connected\",\"Please wait until the results of your activities are sent to the reports system\":\"Please wait until the results of your activities are sent to the reports system\",\"Password:\":\"Password:\",\"Incorrect password\":\"Incorrect password\",\"Invalid user\":\"Invalid user\",\"Partial score:\":\"Partial score:\",\"(out of played activities)\":\"(out of played activities)\",\"Activities played at least once:\":\"Activities played at least once:\",\"Reports\":\"Reports\",\"Toggle full screen\":\"Toggle full screen\",\"JClic logo\":\"JClic logo\",\"message\":\"message\",\"Activity panel\":\"النشاط\",\"cell\":\"cell\",\"image\":\"image\",\"source\":\"source\",\"target\":\"target\",\"image fragment\":\"image fragment\"},\"ast\":{\"Version\":\"Versión\",\"time\":\"tiempu\",\"actions\":\"aiciones\",\"score\":\"puntuación\",\"Next activity\":\"Xera siguiente\",\"Previous activity\":\"Xera previa\",\"Restart activity\":\"Reaniciar xera\",\"Information\":\"Información\",\"Results are not currently being saved\":\"Anguaño los resultaos nun tán guardándose\",\"Current results\":\"Resultaos actuales\",\"Session started:\":\"Entamu de sesión:\",\"Reports system:\":\"Sistema d'informes:\",\"User:\":\"Usuariu:\",\"Projects:\":\"Proyeutos:\",\"Sequences:\":\"Secuencies:\",\"Activities done:\":\"Xeres feches:\",\"Activities solved:\":\"Xeres correutes:\",\"Global score:\":\"Puntuación global:\",\"(out of all project activities)\":\"Tiempu total en xeres:\",\"Total time in activities:\":\"Tiempu total en xeres:\",\"Actions done:\":\"Aiciones feches:\",\"No activities done!\":\"¡Nun se fexo xera dala!\",\"Project\":\"Proyeutu\",\"sequence\":\"Secuencia\",\"activity\":\"xera\",\"OK\":\"Aceutar\",\"YES\":\"SÍ\",\"NO\":\"NON\",\"Total:\":\"Total:\",\"Select group:\":\"Select group:\",\"Select user:\":\"Select user:\",\"Cancel\":\"Cancel\",\"Close\":\"Close\",\"Copy data to clipboard\":\"Copy data to clipboard\",\"The data has been copied in HTML format. Please paste them into a spreadsheet or in a rich text editor\":\"The data has been copied in HTML format. Please paste them into a spreadsheet or in a rich text editor\",\"The data has been copied to clipboard\":\"The data has been copied to clipboard\",\"not connected\":\"not connected\",\"Please wait until the results of your activities are sent to the reports system\":\"Please wait until the results of your activities are sent to the reports system\",\"Password:\":\"Password:\",\"Incorrect password\":\"Incorrect password\",\"Invalid user\":\"Invalid user\",\"Partial score:\":\"Puntuación global:\",\"(out of played activities)\":\"(out of played activities)\",\"Activities played at least once:\":\"Xeres feches:\",\"Reports\":\"Sistema d'informes:\",\"Toggle full screen\":\"Toggle full screen\",\"JClic logo\":\"JClic logo\",\"message\":\"message\",\"Activity panel\":\"Xeres feches:\",\"cell\":\"cell\",\"image\":\"image\",\"source\":\"source\",\"target\":\"target\",\"image fragment\":\"image fragment\"},\"bs\":{\"Version\":\"Verzija\",\"time\":\"vrijeme\",\"actions\":\"pokušaji\",\"score\":\"rezultat\",\"Next activity\":\"Sljedeća aktivnost\",\"Previous activity\":\"Prethodna aktivnost\",\"Restart activity\":\"Ponovno pokreni aktivnost\",\"Information\":\"Informacije\",\"Results are not currently being saved\":\"Results are not currently being saved\",\"Current results\":\"Izvješća korisnika\",\"Session started:\":\"Sesija započeta:\",\"Reports system:\":\"Reports system:\",\"User:\":\"Korisnik:\",\"Projects:\":\"Projekti:\",\"Sequences:\":\"Sekvenca\",\"Activities done:\":\"Urađene aktivnosti:\",\"Activities solved:\":\"Aktivnosti ok:\",\"Global score:\":\"Ukupan rezultat:\",\"(out of all project activities)\":\"Ukupno vrijeme aktivnosti:\",\"Total time in activities:\":\"Ukupno vrijeme aktivnosti:\",\"Actions done:\":\"Urađene aktivnosti:\",\"No activities done!\":\"Urađene aktivnosti:\",\"Project\":\"Projekt:\",\"sequence\":\"Sekvenca\",\"activity\":\"Aktivnost\",\"OK\":\"Uredu\",\"YES\":\"DA\",\"NO\":\"NE\",\"Total:\":\"Ukupno:\",\"Select group:\":\"Select group:\",\"Select user:\":\"Select user:\",\"Cancel\":\"Cancel\",\"Close\":\"Close\",\"Copy data to clipboard\":\"Copy data to clipboard\",\"The data has been copied in HTML format. Please paste them into a spreadsheet or in a rich text editor\":\"The data has been copied in HTML format. Please paste them into a spreadsheet or in a rich text editor\",\"The data has been copied to clipboard\":\"The data has been copied to clipboard\",\"not connected\":\"not connected\",\"Please wait until the results of your activities are sent to the reports system\":\"Please wait until the results of your activities are sent to the reports system\",\"Password:\":\"Password:\",\"Incorrect password\":\"Incorrect password\",\"Invalid user\":\"Invalid user\",\"Partial score:\":\"Ukupan rezultat:\",\"(out of played activities)\":\"(out of played activities)\",\"Activities played at least once:\":\"Urađene aktivnosti:\",\"Reports\":\"Reports\",\"Toggle full screen\":\"Toggle full screen\",\"JClic logo\":\"JClic logo\",\"message\":\"message\",\"Activity panel\":\"Urađene aktivnosti:\",\"cell\":\"cell\",\"image\":\"image\",\"source\":\"source\",\"target\":\"target\",\"image fragment\":\"image fragment\"},\"ca\":{\"Version\":\"Versió\",\"time\":\"temps\",\"actions\":\"accions\",\"score\":\"encerts\",\"Next activity\":\"Activitat següent\",\"Previous activity\":\"Activitat anterior\",\"Restart activity\":\"Reinicia l'activitat\",\"Information\":\"Informació\",\"Results are not currently being saved\":\"Els resultats no s'estan desant\",\"Current results\":\"Resultats actuals\",\"Session started:\":\"Inici de sessió:\",\"Reports system:\":\"Sistema d'informes:\",\"User:\":\"Usuari:\",\"Projects:\":\"Projectes:\",\"Sequences:\":\"Seqüències:\",\"Activities done:\":\"Activitats fetes:\",\"Activities solved:\":\"Activitats resoltes:\",\"Global score:\":\"Puntuació global:\",\"(out of all project activities)\":\"(sobre totes les activitats del projecte)\",\"Total time in activities:\":\"Temps total en les activitats:\",\"Actions done:\":\"Accions fetes:\",\"No activities done!\":\"No heu fet cap activitat!\",\"Project\":\"Projecte\",\"sequence\":\"seqüència\",\"activity\":\"activitat\",\"OK\":\"OK\",\"YES\":\"SÍ\",\"NO\":\"NO\",\"Total:\":\"Totals:\",\"Select group:\":\"Seleccioneu el grup:\",\"Select user:\":\"Seleccioneu l'usuari:\",\"Cancel\":\"Cancel·la\",\"Close\":\"Tanca\",\"Copy data to clipboard\":\"Copia les dades al porta-retalls\",\"The data has been copied in HTML format. Please paste them into a spreadsheet or in a rich text editor\":\"Les dades s'han copiat en format HTML. Enganxeu-les a un full de càlcul o a un editor de text enriquit\",\"The data has been copied to clipboard\":\"Les dades s'han copiat al porta-retalls\",\"not connected\":\"no connectat\",\"Please wait until the results of your activities are sent to the reports system\":\"Si us plau, espereu a que els resultats de les vostres activitats s'enviïn al servidor d'informes\",\"Password:\":\"Contrasenya:\",\"Incorrect password\":\"Contrasenya incorrecta\",\"Invalid user\":\"Usuari/ària incorrecte\",\"Partial score:\":\"Puntuació parcial:\",\"(out of played activities)\":\"(sobre les activitats fetes)\",\"Activities played at least once:\":\"Activitats fetes almenys una vegada:\",\"Reports\":\"Informes\",\"Toggle full screen\":\"Commuta pantalla completa\",\"JClic logo\":\"Logotip del JClic\",\"message\":\"missatge\",\"Activity panel\":\"Tauler d'activitats\",\"cell\":\"cel·la\",\"image\":\"imatge\",\"source\":\"origen\",\"target\":\"destí\",\"image fragment\":\"fragment d'imatge\"},\"ca_ES@valencia\":{\"Version\":\"Versió\",\"time\":\"temps\",\"actions\":\"accions\",\"score\":\"encerts\",\"Next activity\":\"Activitat següent\",\"Previous activity\":\"Activitat anterior\",\"Restart activity\":\"Reinicia l'activitat\",\"Information\":\"Informació\",\"Results are not currently being saved\":\"Els resultats no s'estan alçant\",\"Current results\":\"Resultats actuals\",\"Session started:\":\"Inici de sessió:\",\"Reports system:\":\"Sistema d'informes:\",\"User:\":\"Usuari:\",\"Projects:\":\"Projectes:\",\"Sequences:\":\"Seqüències:\",\"Activities done:\":\"Activitats fetes:\",\"Activities solved:\":\"Activitats resoltes:\",\"Global score:\":\"Puntuació global:\",\"(out of all project activities)\":\"(sobre totes les activitats del projecte)\",\"Total time in activities:\":\"Temps total en les activitats:\",\"Actions done:\":\"Accions fetes:\",\"No activities done!\":\"No heu fet cap activitat!\",\"Project\":\"Projecte\",\"sequence\":\"seqüència\",\"activity\":\"activitat\",\"OK\":\"OK\",\"YES\":\"SÍ\",\"NO\":\"NO\",\"Total:\":\"Totals:\",\"Select group:\":\"Seleccioneu el grup:\",\"Select user:\":\"Seleccioneu l'usuari:\",\"Cancel\":\"Cancel·la\",\"Close\":\"Ix\",\"Copy data to clipboard\":\"Copia les dades al porta-retalls\",\"The data has been copied in HTML format. Please paste them into a spreadsheet or in a rich text editor\":\"Les dades s'han copiat en format HTML. Enganxeu-les a un full de càlcul o a un editor de text enriquit\",\"The data has been copied to clipboard\":\"Les dades s'han copiat al porta-retalls\",\"not connected\":\"no connectat\",\"Please wait until the results of your activities are sent to the reports system\":\"Espereu a que els resultats de les vostres activitats s'enviïn al servidor d'informes\",\"Password:\":\"Contrasenya:\",\"Incorrect password\":\"Contrasenya incorrecta\",\"Invalid user\":\"Usuari/ària incorrecte\",\"Partial score:\":\"Puntuació parcial:\",\"(out of played activities)\":\"(sobre les activitats fetes)\",\"Activities played at least once:\":\"Activitats fetes almenys una vegada:\",\"Reports\":\"Informes\",\"Toggle full screen\":\"Commuta pantalla completa\",\"JClic logo\":\"Logotip del JClic\",\"message\":\"missatge\",\"Activity panel\":\"Tauler d'activitats\",\"cell\":\"cel·la\",\"image\":\"imatge\",\"source\":\"origen\",\"target\":\"destí\",\"image fragment\":\"fragment d'imatge\"},\"cs\":{\"Version\":\"Verze\",\"time\":\"čas\",\"actions\":\"pokusů\",\"score\":\"skóre\",\"Next activity\":\"Další aktivita\",\"Previous activity\":\"Předchozí aktivita\",\"Restart activity\":\"Restartovat aktivitu\",\"Information\":\"Informace\",\"Results are not currently being saved\":\"Zpráva není zaregistrována v žádné DB\",\"Current results\":\"Uživatelská sestava\",\"Session started:\":\"Sezení spuštěno:\",\"Reports system:\":\"Systém zprávy:\",\"User:\":\"Uživatel:\",\"Projects:\":\"Projekty:\",\"Sequences:\":\"Sekvence:\",\"Activities done:\":\"Dokončené aktivity:\",\"Activities solved:\":\"Aktivity ok:\",\"Global score:\":\"Celkové skóre:\",\"(out of all project activities)\":\"Celkový čas aktivit:\",\"Total time in activities:\":\"Celkový čas aktivit:\",\"Actions done:\":\"Provedené akce:\",\"No activities done!\":\"Nebyly nahlášeny žádné aktivity!\",\"Project\":\"Projekt\",\"sequence\":\"Sekvence\",\"activity\":\"Aktivita\",\"OK\":\"Ok\",\"YES\":\"ANO\",\"NO\":\"NE\",\"Total:\":\"Celkem:\",\"Select group:\":\"Select group:\",\"Select user:\":\"Select user:\",\"Cancel\":\"Cancel\",\"Close\":\"Close\",\"Copy data to clipboard\":\"Copy data to clipboard\",\"The data has been copied in HTML format. Please paste them into a spreadsheet or in a rich text editor\":\"The data has been copied in HTML format. Please paste them into a spreadsheet or in a rich text editor\",\"The data has been copied to clipboard\":\"The data has been copied to clipboard\",\"not connected\":\"not connected\",\"Please wait until the results of your activities are sent to the reports system\":\"Please wait until the results of your activities are sent to the reports system\",\"Password:\":\"Password:\",\"Incorrect password\":\"Incorrect password\",\"Invalid user\":\"Invalid user\",\"Partial score:\":\"Celkové skóre:\",\"(out of played activities)\":\"(out of played activities)\",\"Activities played at least once:\":\"Dokončené aktivity:\",\"Reports\":\"Systém zprávy:\",\"Toggle full screen\":\"Toggle full screen\",\"JClic logo\":\"JClic logo\",\"message\":\"message\",\"Activity panel\":\"Dokončené aktivity:\",\"cell\":\"cell\",\"image\":\"image\",\"source\":\"source\",\"target\":\"target\",\"image fragment\":\"image fragment\"},\"da\":{\"Version\":\"Version\",\"time\":\"tid\",\"actions\":\"forsøg\",\"score\":\"score\",\"Next activity\":\"Næste aktivitet\",\"Previous activity\":\"Forrige aktivitet\",\"Restart activity\":\"Genstart aktivitet\",\"Information\":\"Information\",\"Results are not currently being saved\":\"Results are not currently being saved\",\"Current results\":\"Bruger rapport\",\"Session started:\":\"Session started:\",\"Reports system:\":\"Reports system:\",\"User:\":\"Bruger:\",\"Projects:\":\"Projekter:\",\"Sequences:\":\"Sekvenser:\",\"Activities done:\":\"Aktiviteter udført:\",\"Activities solved:\":\"Aktiviteter OK:\",\"Global score:\":\"Global score:\",\"(out of all project activities)\":\"(out of all project activities)\",\"Total time in activities:\":\"Total time in activities:\",\"Actions done:\":\"Aktiviteter udført:\",\"No activities done!\":\"Ingen aktiviteter rapporteret!\",\"Project\":\"Projekt\",\"sequence\":\"Sequence\",\"activity\":\"Aktivitet\",\"OK\":\"Ok\",\"YES\":\"JA\",\"NO\":\"IKKE\",\"Total:\":\"Total:\",\"Select group:\":\"Select group:\",\"Select user:\":\"Select user:\",\"Cancel\":\"Cancel\",\"Close\":\"Close\",\"Copy data to clipboard\":\"Copy data to clipboard\",\"The data has been copied in HTML format. Please paste them into a spreadsheet or in a rich text editor\":\"The data has been copied in HTML format. Please paste them into a spreadsheet or in a rich text editor\",\"The data has been copied to clipboard\":\"The data has been copied to clipboard\",\"not connected\":\"not connected\",\"Please wait until the results of your activities are sent to the reports system\":\"Please wait until the results of your activities are sent to the reports system\",\"Password:\":\"Password:\",\"Incorrect password\":\"Incorrect password\",\"Invalid user\":\"Invalid user\",\"Partial score:\":\"Global score:\",\"(out of played activities)\":\"(out of played activities)\",\"Activities played at least once:\":\"Aktiviteter udført:\",\"Reports\":\"Reports\",\"Toggle full screen\":\"Toggle full screen\",\"JClic logo\":\"JClic logo\",\"message\":\"message\",\"Activity panel\":\"Aktiviteter udført:\",\"cell\":\"cell\",\"image\":\"image\",\"source\":\"source\",\"target\":\"target\",\"image fragment\":\"image fragment\"},\"de\":{\"Version\":\"Version\",\"time\":\"Zeit\",\"actions\":\"Versuche\",\"score\":\"Ergebnis\",\"Next activity\":\"Nächste Übung\",\"Previous activity\":\"Vorherige Übung\",\"Restart activity\":\"Übung neu starten\",\"Information\":\"Informationen\",\"Results are not currently being saved\":\"Bericht in keiner Datenbank eingetragen\",\"Current results\":\"Benutzerberichte\",\"Session started:\":\"Sitzung gestartet:\",\"Reports system:\":\"Report system:\",\"User:\":\"Benutzer:\",\"Projects:\":\"Projekte:\",\"Sequences:\":\"Sequenzen:\",\"Activities done:\":\"Beendete Übungen:\",\"Activities solved:\":\"Korrekte Übungen:\",\"Global score:\":\"Gesamtpunktezahl:\",\"(out of all project activities)\":\"Übungs-Gesamtzeit:\",\"Total time in activities:\":\"Übungs-Gesamtzeit:\",\"Actions done:\":\"Durchgeführte Aktionen:\",\"No activities done!\":\"Keine Übungsberichte vorhanden!\",\"Project\":\"Projekt\",\"sequence\":\"Sequenz\",\"activity\":\"Übung\",\"OK\":\"OK\",\"YES\":\"JA\",\"NO\":\"NEIN\",\"Total:\":\"Gesamt:\",\"Select group:\":\"Select group:\",\"Select user:\":\"Select user:\",\"Cancel\":\"Cancel\",\"Close\":\"Close\",\"Copy data to clipboard\":\"Copy data to clipboard\",\"The data has been copied in HTML format. Please paste them into a spreadsheet or in a rich text editor\":\"The data has been copied in HTML format. Please paste them into a spreadsheet or in a rich text editor\",\"The data has been copied to clipboard\":\"The data has been copied to clipboard\",\"not connected\":\"not connected\",\"Please wait until the results of your activities are sent to the reports system\":\"Please wait until the results of your activities are sent to the reports system\",\"Password:\":\"Password:\",\"Incorrect password\":\"Incorrect password\",\"Invalid user\":\"Invalid user\",\"Partial score:\":\"Gesamtpunktezahl:\",\"(out of played activities)\":\"(out of played activities)\",\"Activities played at least once:\":\"Beendete Übungen:\",\"Reports\":\"Report system:\",\"Toggle full screen\":\"Toggle full screen\",\"JClic logo\":\"JClic logo\",\"message\":\"message\",\"Activity panel\":\"Beendete Übungen:\",\"cell\":\"cell\",\"image\":\"image\",\"source\":\"source\",\"target\":\"target\",\"image fragment\":\"image fragment\"},\"el\":{\"Version\":\"Έκδοση\",\"time\":\"χρόνος\",\"actions\":\"προσπάθειες\",\"score\":\"βαθμολογία\",\"Next activity\":\"Επόμενη δραστηριότητα\",\"Previous activity\":\"Προηγούμενη δραστηριότητα\",\"Restart activity\":\"Επανεκκίνηση δραστηριότητας\",\"Information\":\"Πληροφορίες\",\"Results are not currently being saved\":\"Η αναφορά δεν εγγράφηκε στις βάσεις δεδομένων\",\"Current results\":\"Αναφορές χρήστη\",\"Session started:\":\"Έναρξη συνεδρίας:\",\"Reports system:\":\"Σύστημα αναφορών:\",\"User:\":\"Χρήστης:\",\"Projects:\":\"Έργα:\",\"Sequences:\":\"Αλληλουχίες:\",\"Activities done:\":\"Ολοκληρωμένες δραστηριότητες:\",\"Activities solved:\":\"Δραστηριότητες, εντάξει:\",\"Global score:\":\"Συνολική βαθμολογία:\",\"(out of all project activities)\":\"Συνολικός χρόνος δραστηριοτήτων:\",\"Total time in activities:\":\"Συνολικός χρόνος δραστηριοτήτων:\",\"Actions done:\":\"Οι ενέργειες ολοκληρώθηκαν:\",\"No activities done!\":\"Για καμμία δραστηριότητα δεν έχει υποβληθεί αναφορά!\",\"Project\":\"Έργο\",\"sequence\":\"Αλληλουχία\",\"activity\":\"Δραστηριότητα\",\"OK\":\"Εντάξει\",\"YES\":\"Ναί\",\"NO\":\"όχι\",\"Total:\":\"Σύνολο:\",\"Select group:\":\"Select group:\",\"Select user:\":\"Select user:\",\"Cancel\":\"Cancel\",\"Close\":\"Close\",\"Copy data to clipboard\":\"Copy data to clipboard\",\"The data has been copied in HTML format. Please paste them into a spreadsheet or in a rich text editor\":\"The data has been copied in HTML format. Please paste them into a spreadsheet or in a rich text editor\",\"The data has been copied to clipboard\":\"The data has been copied to clipboard\",\"not connected\":\"not connected\",\"Please wait until the results of your activities are sent to the reports system\":\"Please wait until the results of your activities are sent to the reports system\",\"Password:\":\"Password:\",\"Incorrect password\":\"Incorrect password\",\"Invalid user\":\"Invalid user\",\"Partial score:\":\"Συνολική βαθμολογία:\",\"(out of played activities)\":\"(out of played activities)\",\"Activities played at least once:\":\"Ολοκληρωμένες δραστηριότητες:\",\"Reports\":\"Σύστημα αναφορών:\",\"Toggle full screen\":\"Toggle full screen\",\"JClic logo\":\"JClic logo\",\"message\":\"message\",\"Activity panel\":\"Ολοκληρωμένες δραστηριότητες:\",\"cell\":\"cell\",\"image\":\"image\",\"source\":\"source\",\"target\":\"target\",\"image fragment\":\"image fragment\"},\"es\":{\"Version\":\"Versión\",\"time\":\"tiempo\",\"actions\":\"acciones\",\"score\":\"aciertos\",\"Next activity\":\"Actividad siguiente\",\"Previous activity\":\"Actividad anterior\",\"Restart activity\":\"Reiniciar actividad\",\"Information\":\"Información\",\"Results are not currently being saved\":\"Los resultados no se están guardando\",\"Current results\":\"Resultados actuales\",\"Session started:\":\"Inicio de sesión:\",\"Reports system:\":\"Sistema de informes:\",\"User:\":\"Usuario:\",\"Projects:\":\"Proyectos:\",\"Sequences:\":\"Secuencias:\",\"Activities done:\":\"Actividades realizadas:\",\"Activities solved:\":\"Actividades resueltas:\",\"Global score:\":\"Puntuación global:\",\"(out of all project activities)\":\"(sobre todas las actividades del proyecto)\",\"Total time in activities:\":\"Tiempo total en las actividades:\",\"Actions done:\":\"Acciones realizadas:\",\"No activities done!\":\"¡No se ha realizado ninguna actividad!\",\"Project\":\"Proyecto\",\"sequence\":\"secuencia\",\"activity\":\"actividad\",\"OK\":\"OK\",\"YES\":\"SI\",\"NO\":\"NO\",\"Total:\":\"Totales:\",\"Select group:\":\"Seleccionar grupo:\",\"Select user:\":\"Seleccionar usuario:\",\"Cancel\":\"Cancelar\",\"Close\":\"Cerrar\",\"Copy data to clipboard\":\"Copiar datos al portapapeles\",\"The data has been copied in HTML format. Please paste them into a spreadsheet or in a rich text editor\":\"Los datos se han copiado en formato HTML. Puedes pegarlos en una hoja de cálculo o en un editor de texto enriquecido\",\"The data has been copied to clipboard\":\"Los datos se han copiado al portapapeles\",\"not connected\":\"no conectado\",\"Please wait until the results of your activities are sent to the reports system\":\"Por favor, espera mientras los resultados de las actividades se envian al servidor de informes\",\"Password:\":\"Contraseña:\",\"Incorrect password\":\"Contraseña incorrecta\",\"Invalid user\":\"Usuario incorrecto\",\"Partial score:\":\"Puntuación parcial:\",\"(out of played activities)\":\"(sobre las actividades realizadas)\",\"Activities played at least once:\":\"Actividades realizadas al menos una vez:\",\"Reports\":\"Informes\",\"Toggle full screen\":\"Conmutar pantalla completa\",\"JClic logo\":\"Logotipo de JClic\",\"message\":\"mensaje\",\"Activity panel\":\"Panel de actividad\",\"cell\":\"celda\",\"image\":\"imagen\",\"source\":\"origen\",\"target\":\"destino\",\"image fragment\":\"fragmento de imagen\"},\"eu\":{\"Version\":\"Bertsioa\",\"time\":\"denbora\",\"actions\":\"saiakerak\",\"score\":\"puntuazioa\",\"Next activity\":\"Hurrengo jarduera\",\"Previous activity\":\"Aurreko jarduera\",\"Restart activity\":\"Jarduera berriro hasi\",\"Information\":\"Informazioa\",\"Results are not currently being saved\":\"Txostena ez dago ezein datu-basetan\",\"Current results\":\"Erabiltzailearen txostenak\",\"Session started:\":\"Saio-hasiera:\",\"Reports system:\":\"Txosten-sistema:\",\"User:\":\"Erabiltzailea:\",\"Projects:\":\"Proiektuak:\",\"Sequences:\":\"Sekuentziak:\",\"Activities done:\":\"Burututako ekinzak:\",\"Activities solved:\":\"Jarduera zuzenak:\",\"Global score:\":\"Jarduera zuzenak:\",\"(out of all project activities)\":\"Jardueretan emandako denbora guztira:\",\"Total time in activities:\":\"Jardueretan emandako denbora guztira:\",\"Actions done:\":\"Burututako ekintzak:\",\"No activities done!\":\"Ez da jardueren txostenik!\",\"Project\":\"Proiektua\",\"sequence\":\"Sekuentzia\",\"activity\":\"Jarduera\",\"OK\":\"Ados\",\"YES\":\"BAI\",\"NO\":\"EZ\",\"Total:\":\"Guztira:\",\"Select group:\":\"Select group:\",\"Select user:\":\"Select user:\",\"Cancel\":\"Cancel\",\"Close\":\"Close\",\"Copy data to clipboard\":\"Copy data to clipboard\",\"The data has been copied in HTML format. Please paste them into a spreadsheet or in a rich text editor\":\"The data has been copied in HTML format. Please paste them into a spreadsheet or in a rich text editor\",\"The data has been copied to clipboard\":\"The data has been copied to clipboard\",\"not connected\":\"not connected\",\"Please wait until the results of your activities are sent to the reports system\":\"Please wait until the results of your activities are sent to the reports system\",\"Password:\":\"Password:\",\"Incorrect password\":\"Incorrect password\",\"Invalid user\":\"Invalid user\",\"Partial score:\":\"Jarduera zuzenak:\",\"(out of played activities)\":\"(out of played activities)\",\"Activities played at least once:\":\"Burututako ekinzak:\",\"Reports\":\"Txosten-sistema:\",\"Toggle full screen\":\"Toggle full screen\",\"JClic logo\":\"JClic logo\",\"message\":\"message\",\"Activity panel\":\"Burututako ekinzak:\",\"cell\":\"cell\",\"image\":\"image\",\"source\":\"source\",\"target\":\"target\",\"image fragment\":\"image fragment\"},\"fr\":{\"Version\":\"Version\",\"time\":\"temps\",\"actions\":\"essais\",\"score\":\"résultat\",\"Next activity\":\"Activité suivante\",\"Previous activity\":\"Activité précédente\",\"Restart activity\":\"Recommencer l'activité\",\"Information\":\"Informations\",\"Results are not currently being saved\":\"Le rapport n'est enregistré dans aucune base de données\",\"Current results\":\"Rapports utilisateur\",\"Session started:\":\"Session démarrée :\",\"Reports system:\":\"Système de rapports :\",\"User:\":\"Utilisateur :\",\"Projects:\":\"Projets :\",\"Sequences:\":\"Séquences :\",\"Activities done:\":\"Activités réalisées :\",\"Activities solved:\":\"Activités résolues :\",\"Global score:\":\"Score global :\",\"(out of all project activities)\":\"(sur toutes les activités du projet)\",\"Total time in activities:\":\"Temps total sur les activités :\",\"Actions done:\":\"Actions réalisées :\",\"No activities done!\":\"Aucune activité réalisée !\",\"Project\":\"Projet\",\"sequence\":\"séquence\",\"activity\":\"activité\",\"OK\":\"OK\",\"YES\":\"OUI\",\"NO\":\"NON\",\"Total:\":\"Total :\",\"Select group:\":\"Sélectionner un groupe:\",\"Select user:\":\"Sélectionner l'utilisateur:\",\"Cancel\":\"Annuler\",\"Close\":\"Fermer\",\"Copy data to clipboard\":\"Copier les données dans le presse-papier\",\"The data has been copied in HTML format. Please paste them into a spreadsheet or in a rich text editor\":\"Les données ont été copiées au format HTML. Veuillez les coller dans une feuille de calcul ou dans un éditeur de texte\",\"The data has been copied to clipboard\":\"Les données sont copier dans le presse-papier\",\"not connected\":\"Non connecté \",\"Please wait until the results of your activities are sent to the reports system\":\"Veuillez patienter durant l'envoi de votre activité au rapport système\",\"Password:\":\"Mot de passe: \",\"Incorrect password\":\"Mot de passe incorrect\",\"Invalid user\":\"Utilisateur invalide\",\"Partial score:\":\"Score partiel:\",\"(out of played activities)\":\"(Hors activités jouées)\",\"Activities played at least once:\":\"Les activités joué au moins une fois:\",\"Reports\":\"Rapport\",\"Toggle full screen\":\"Basculer en plein écran\",\"JClic logo\":\"JClic logo\",\"message\":\"message\",\"Activity panel\":\"Groupe d'activités\",\"cell\":\"cellule\",\"image\":\"image\",\"source\":\"source\",\"target\":\"cible\",\"image fragment\":\"fragment d'image\"},\"gl\":{\"Version\":\"Versión\",\"time\":\"tempo\",\"actions\":\"intentos\",\"score\":\"acertos\",\"Next activity\":\"Seguinte actividade\",\"Previous activity\":\"Anterior actividade\",\"Restart activity\":\"Reiniciar a actividade\",\"Information\":\"Información\",\"Results are not currently being saved\":\"O informe non está rexistrado en ningunha base de datos\",\"Current results\":\"Informes de usuario\",\"Session started:\":\"Inicio de sesión:\",\"Reports system:\":\"Sistema de informes:\",\"User:\":\"Usuario:\",\"Projects:\":\"Proxectos:\",\"Sequences:\":\"Secuencias:\",\"Activities done:\":\"Actividades realizadas:\",\"Activities solved:\":\"Actividades correctas:\",\"Global score:\":\"Puntuación global:\",\"(out of all project activities)\":\"Tempo total nas actividades:\",\"Total time in activities:\":\"Tempo total nas actividades:\",\"Actions done:\":\"Accións efectuadas:\",\"No activities done!\":\"Non hai informada ningunha actividade!\",\"Project\":\"Proxecto\",\"sequence\":\"secuencia\",\"activity\":\"actividade\",\"OK\":\"Correcta\",\"YES\":\"SI\",\"NO\":\"NON\",\"Total:\":\"Total:\",\"Select group:\":\"Select group:\",\"Select user:\":\"Select user:\",\"Cancel\":\"Cancel\",\"Close\":\"Close\",\"Copy data to clipboard\":\"Copy data to clipboard\",\"The data has been copied in HTML format. Please paste them into a spreadsheet or in a rich text editor\":\"The data has been copied in HTML format. Please paste them into a spreadsheet or in a rich text editor\",\"The data has been copied to clipboard\":\"The data has been copied to clipboard\",\"not connected\":\"not connected\",\"Please wait until the results of your activities are sent to the reports system\":\"Please wait until the results of your activities are sent to the reports system\",\"Password:\":\"Password:\",\"Incorrect password\":\"Incorrect password\",\"Invalid user\":\"Invalid user\",\"Partial score:\":\"Puntuación global:\",\"(out of played activities)\":\"(out of played activities)\",\"Activities played at least once:\":\"Actividades realizadas:\",\"Reports\":\"Sistema de informes:\",\"Toggle full screen\":\"Toggle full screen\",\"JClic logo\":\"JClic logo\",\"message\":\"message\",\"Activity panel\":\"Actividades realizadas:\",\"cell\":\"cell\",\"image\":\"image\",\"source\":\"source\",\"target\":\"target\",\"image fragment\":\"image fragment\"},\"he\":{\"Version\":\"גירסה\",\"time\":\"זמן\",\"actions\":\"נסיונות\",\"score\":\"ניקוד\",\"Next activity\":\"הפעילות הבאה\",\"Previous activity\":\"הפעילות הקודמת\",\"Restart activity\":\"התחל פעילות מחדש\",\"Information\":\"מידע\",\"Results are not currently being saved\":\"הדיווח אינו רשום במסד נתונים כלשהו\",\"Current results\":\"דוחות משתמש\",\"Session started:\":\"הפעלה החלה:\",\"Reports system:\":\"מערכת דוחות:\",\"User:\":\"משתמש:\",\"Projects:\":\"פרוייקטים:\",\"Sequences:\":\"רצפים:\",\"Activities done:\":\"פעילויות שהושלמו:\",\"Activities solved:\":\"פעילויות מאושרות:\",\"Global score:\":\"ניקוד כללי:\",\"(out of all project activities)\":\"משך הפעילויות המצטבר:\",\"Total time in activities:\":\"משך הפעילויות המצטבר:\",\"Actions done:\":\"פעולות שבוצעו:\",\"No activities done!\":\"לא דווחו פעילויות!\",\"Project\":\"פרוייקט\",\"sequence\":\"רצף\",\"activity\":\"פעילות\",\"OK\":\"אישור\",\"YES\":\"כן\",\"NO\":\"לא\",\"Total:\":\"סך הכל:\",\"Select group:\":\"Select group:\",\"Select user:\":\"Select user:\",\"Cancel\":\"Cancel\",\"Close\":\"Close\",\"Copy data to clipboard\":\"Copy data to clipboard\",\"The data has been copied in HTML format. Please paste them into a spreadsheet or in a rich text editor\":\"The data has been copied in HTML format. Please paste them into a spreadsheet or in a rich text editor\",\"The data has been copied to clipboard\":\"The data has been copied to clipboard\",\"not connected\":\"not connected\",\"Please wait until the results of your activities are sent to the reports system\":\"Please wait until the results of your activities are sent to the reports system\",\"Password:\":\"Password:\",\"Incorrect password\":\"Incorrect password\",\"Invalid user\":\"Invalid user\",\"Partial score:\":\"ניקוד כללי:\",\"(out of played activities)\":\"(out of played activities)\",\"Activities played at least once:\":\"פעילויות שהושלמו:\",\"Reports\":\"מערכת דוחות:\",\"Toggle full screen\":\"Toggle full screen\",\"JClic logo\":\"JClic logo\",\"message\":\"message\",\"Activity panel\":\"פעילויות שהושלמו:\",\"cell\":\"cell\",\"image\":\"image\",\"source\":\"source\",\"target\":\"target\",\"image fragment\":\"image fragment\"},\"hr\":{\"Version\":\"Verzija\",\"time\":\"vrijeme\",\"actions\":\"radnje\",\"score\":\"rezultat\",\"Next activity\":\"Sljedeća aktivnost\",\"Previous activity\":\"Prethodna aktivnost\",\"Restart activity\":\"Ponovo pokreni aktivnost\",\"Information\":\"Informacije\",\"Results are not currently being saved\":\"Rezultati se trenutačno ne spremaju\",\"Current results\":\"Trenutačni rezultati\",\"Session started:\":\"Sesija započeta:\",\"Reports system:\":\"Sustav izvještaja:\",\"User:\":\"Korisnik:\",\"Projects:\":\"Projekti:\",\"Sequences:\":\"Slijedovi:\",\"Activities done:\":\"Obavljene aktivnosti:\",\"Activities solved:\":\"Riješene aktivnosti:\",\"Global score:\":\"Ukupni rezultat:\",\"(out of all project activities)\":\"(od svih projektnih aktivnosti)\",\"Total time in activities:\":\"Ukupno vrijeme u aktivnostima:\",\"Actions done:\":\"Izvršene radnje:\",\"No activities done!\":\"Nema obavljenih aktivnosti!\",\"Project\":\"Projekt\",\"sequence\":\"slijed\",\"activity\":\"aktivnost\",\"OK\":\"U redu\",\"YES\":\"DA\",\"NO\":\"NE\",\"Total:\":\"Ukupno:\",\"Select group:\":\"Odaberi grupu:\",\"Select user:\":\"Odaberi korisnika:\",\"Cancel\":\"Odustani\",\"Close\":\"Zatvori\",\"Copy data to clipboard\":\"Kopiraj podatke u međuspremnik\",\"The data has been copied in HTML format. Please paste them into a spreadsheet or in a rich text editor\":\"Podaci su kopirani u HTML formatu. Umetni ih u proračunsku tablicu ili u uređivač formatiranog teksta\",\"The data has been copied to clipboard\":\"Podaci su kopirani u međuspremnik\",\"not connected\":\"nepovezano\",\"Please wait until the results of your activities are sent to the reports system\":\"Pričekaj da se rezultati tvojih aktivnosti pošalju sustavu izvještaja\",\"Password:\":\"Lozinka:\",\"Incorrect password\":\"Neispravna lozinka\",\"Invalid user\":\"Korisnik ne postoji\",\"Partial score:\":\"Prosjek:\",\"(out of played activities)\":\"(od odigranih aktivnosti)\",\"Activities played at least once:\":\"Barem jednom odigrane aktivnosti:\",\"Reports\":\"Sustav izvještaja:\",\"Toggle full screen\":\"Toggle full screen\",\"JClic logo\":\"JClic logo\",\"message\":\"message\",\"Activity panel\":\"Obavljene aktivnosti:\",\"cell\":\"cell\",\"image\":\"image\",\"source\":\"source\",\"target\":\"target\",\"image fragment\":\"image fragment\"},\"it\":{\"Version\":\"Versione\",\"time\":\"tempo\",\"actions\":\"tentativi\",\"score\":\"punteggio\",\"Next activity\":\"Attività successiva\",\"Previous activity\":\"Attività precedente\",\"Restart activity\":\"Riavvia l'attività\",\"Information\":\"Informazioni\",\"Results are not currently being saved\":\"Rapporto non registrato in alcuna banca dati\",\"Current results\":\"Rapporti utente\",\"Session started:\":\"Sessione avviata:\",\"Reports system:\":\"Sistema dei rapporti:\",\"User:\":\"Utente:\",\"Projects:\":\"Progetti:\",\"Sequences:\":\"Sequenze:\",\"Activities done:\":\"Attività eseguite:\",\"Activities solved:\":\"Attività ok:\",\"Global score:\":\"Punteggio globale:\",\"(out of all project activities)\":\"Tempo totale nelle attività:\",\"Total time in activities:\":\"Tempo totale nelle attività:\",\"Actions done:\":\"Azioni compiute:\",\"No activities done!\":\"Nessuna attività a rapporto!\",\"Project\":\"Progetto\",\"sequence\":\"sequenza\",\"activity\":\"attività\",\"OK\":\"Ok\",\"YES\":\"SÌ\",\"NO\":\"NO\",\"Total:\":\"Totale:\",\"Select group:\":\"Select group:\",\"Select user:\":\"Select user:\",\"Cancel\":\"Cancel\",\"Close\":\"Close\",\"Copy data to clipboard\":\"Copy data to clipboard\",\"The data has been copied in HTML format. Please paste them into a spreadsheet or in a rich text editor\":\"The data has been copied in HTML format. Please paste them into a spreadsheet or in a rich text editor\",\"The data has been copied to clipboard\":\"The data has been copied to clipboard\",\"not connected\":\"not connected\",\"Please wait until the results of your activities are sent to the reports system\":\"Please wait until the results of your activities are sent to the reports system\",\"Password:\":\"Password:\",\"Incorrect password\":\"Incorrect password\",\"Invalid user\":\"Invalid user\",\"Partial score:\":\"Punteggio globale:\",\"(out of played activities)\":\"(out of played activities)\",\"Activities played at least once:\":\"Attività eseguite:\",\"Reports\":\"Sistema dei rapporti:\",\"Toggle full screen\":\"Toggle full screen\",\"JClic logo\":\"JClic logo\",\"message\":\"message\",\"Activity panel\":\"Attività eseguite:\",\"cell\":\"cell\",\"image\":\"image\",\"source\":\"source\",\"target\":\"target\",\"image fragment\":\"image fragment\"},\"ja\":{\"Version\":\"バージョン\",\"time\":\"時間\",\"actions\":\"アクション\",\"score\":\"スコア\",\"Next activity\":\"次のアクティビティ\",\"Previous activity\":\"前のアクティビティ\",\"Restart activity\":\"アクティビティを再起動\",\"Information\":\"情報\",\"Results are not currently being saved\":\"結果は、現在保存されていません\",\"Current results\":\"現在の結果\",\"Session started:\":\"セッションが開始しました:\",\"Reports system:\":\"レポート システム:\",\"User:\":\"ユーザー:\",\"Projects:\":\"プロジェクト:\",\"Sequences:\":\"シーケンス:\",\"Activities done:\":\"完了したアクティビティ:\",\"Activities solved:\":\"解決したアクティビティ:\",\"Global score:\":\"グローバル スコア:\",\"(out of all project activities)\":\"(すべてのプロジェクト アクティビティの結果)\",\"Total time in activities:\":\"アクティビティ時間の合計:\",\"Actions done:\":\"完了したアクション:\",\"No activities done!\":\"アクティビティは行われていません!\",\"Project\":\"プロジェクト\",\"sequence\":\"シーケンス\",\"activity\":\"アクティビティ\",\"OK\":\"OK\",\"YES\":\"はい\",\"NO\":\"いいえ\",\"Total:\":\"合計:\",\"Select group:\":\"グループを選択:\",\"Select user:\":\"ユーザーを選択:\",\"Cancel\":\"キャンセル\",\"Close\":\"閉じる\",\"Copy data to clipboard\":\"データをクリップボードにコピー\",\"The data has been copied in HTML format. Please paste them into a spreadsheet or in a rich text editor\":\"データは HTML 形式でコピーされます。リッチ テキスト エディターやスプレッドシートに貼り付けてください\",\"The data has been copied to clipboard\":\"クリップボードにデータがコピーされました\",\"not connected\":\"接続されていません\",\"Please wait until the results of your activities are sent to the reports system\":\"アクティビティの結果がレポート システムに送信されるまでお待ちください\",\"Password:\":\"パスワード:\",\"Incorrect password\":\"パスワードが正しくありません\",\"Invalid user\":\"無効なユーザー\",\"Partial score:\":\"部分スコア:\",\"(out of played activities)\":\"(プレイしたアクティビティの結果)\",\"Activities played at least once:\":\"少なくとも一度プレイしたアクティビティ:\",\"Reports\":\"レポート\",\"Toggle full screen\":\"全画面の切り替え\",\"JClic logo\":\"JClic ロゴ\",\"message\":\"メッセージ\",\"Activity panel\":\"アクティビティ パネル\",\"cell\":\"セル\",\"image\":\"画像\",\"source\":\"ソース\",\"target\":\"ターゲット\",\"image fragment\":\"画像フラグメント\"},\"nb_NO\":{\"Version\":\"Versjon\",\"time\":\"tid\",\"actions\":\"forsøk\",\"score\":\"poengsum\",\"Next activity\":\"Neste aktivitet\",\"Previous activity\":\"Forrige aktivitet\",\"Restart activity\":\"Start aktivitet på nytt\",\"Information\":\"Informasjon\",\"Results are not currently being saved\":\"Resultater blir foreløpig ikke lagret\",\"Current results\":\"Nåværende resultater\",\"Session started:\":\"Økta startet:\",\"Reports system:\":\"Rapportsystem:\",\"User:\":\"Bruker:\",\"Projects:\":\"Prosjekter:\",\"Sequences:\":\"Sekvenser:\",\"Activities done:\":\"Aktiviteter fullført:\",\"Activities solved:\":\"Løste aktiviteter:\",\"Global score:\":\"Global poengsum:\",\"(out of all project activities)\":\"(av alle prosjektaktiviteter)\",\"Total time in activities:\":\"Tidsforbruk på aktiviteter:\",\"Actions done:\":\"Handlinger gjort:\",\"No activities done!\":\"Ingen aktiviteter unnagjort.\",\"Project\":\"Prosjekt\",\"sequence\":\"sekvens\",\"activity\":\"aktivitet\",\"OK\":\"OK\",\"YES\":\"JA\",\"NO\":\"NEI\",\"Total:\":\"Total:\",\"Select group:\":\"Velg gruppe:\",\"Select user:\":\"Velg bruker:\",\"Cancel\":\"Avbryt\",\"Close\":\"Lukk\",\"Copy data to clipboard\":\"Kopier data til utklippstavle\",\"The data has been copied in HTML format. Please paste them into a spreadsheet or in a rich text editor\":\"Dataen har blitt kopiert i HTML-format. Lim inn i et regneark eller en tekstbehandler med støtte for formatering\",\"The data has been copied to clipboard\":\"Dataen har blitt kopier til utklippstavle\",\"not connected\":\"ikke tilkoblet\",\"Please wait until the results of your activities are sent to the reports system\":\"Vent mens resultatet av dine aktiviteter sendes til rapportsystemet\",\"Password:\":\"Passord:\",\"Incorrect password\":\"Feilaktig passord\",\"Invalid user\":\"Ugyldig bruker\",\"Partial score:\":\"Delvis poengsum:\",\"(out of played activities)\":\"(av utførte aktiviteter)\",\"Activities played at least once:\":\"Aktiviteter som har blitt utført minst én gang:\",\"Reports\":\"Rapportsystem:\",\"Toggle full screen\":\"Toggle full screen\",\"JClic logo\":\"JClic logo\",\"message\":\"message\",\"Activity panel\":\"Aktiviteter fullført:\",\"cell\":\"cell\",\"image\":\"image\",\"source\":\"source\",\"target\":\"target\",\"image fragment\":\"image fragment\"},\"nl\":{\"Version\":\"Versie\",\"time\":\"tijd\",\"actions\":\"pogingen\",\"score\":\"punten\",\"Next activity\":\"Volgende activiteit\",\"Previous activity\":\"Vorige activiteit\",\"Restart activity\":\"Herstart activiteit\",\"Information\":\"Informatie\",\"Results are not currently being saved\":\"Rapport niet geregistreerd in een DB\",\"Current results\":\"Gebruikers rapport\",\"Session started:\":\"Reeks gestart:\",\"Reports system:\":\"Rapporteer systeem:\",\"User:\":\"Gebruiker:\",\"Projects:\":\"Projecten:\",\"Sequences:\":\"Reeksen:\",\"Activities done:\":\"Activiteiten klaar:\",\"Activities solved:\":\"Activiteiten ok:\",\"Global score:\":\"Puntentotaal:\",\"(out of all project activities)\":\"Totale tijd activiteiten:\",\"Total time in activities:\":\"Totale tijd activiteiten:\",\"Actions done:\":\"Einde activiteiten:\",\"No activities done!\":\"Geen activiteiten gerapporteerd!\",\"Project\":\"Project\",\"sequence\":\"Volgorde\",\"activity\":\"Activiteit\",\"OK\":\"Ok\",\"YES\":\"JA\",\"NO\":\"NEE\",\"Total:\":\"Totaal:\",\"Select group:\":\"Select group:\",\"Select user:\":\"Select user:\",\"Cancel\":\"Cancel\",\"Close\":\"Close\",\"Copy data to clipboard\":\"Copy data to clipboard\",\"The data has been copied in HTML format. Please paste them into a spreadsheet or in a rich text editor\":\"The data has been copied in HTML format. Please paste them into a spreadsheet or in a rich text editor\",\"The data has been copied to clipboard\":\"The data has been copied to clipboard\",\"not connected\":\"not connected\",\"Please wait until the results of your activities are sent to the reports system\":\"Please wait until the results of your activities are sent to the reports system\",\"Password:\":\"Password:\",\"Incorrect password\":\"Incorrect password\",\"Invalid user\":\"Invalid user\",\"Partial score:\":\"Puntentotaal:\",\"(out of played activities)\":\"(out of played activities)\",\"Activities played at least once:\":\"Activiteiten klaar:\",\"Reports\":\"Rapporteer systeem:\",\"Toggle full screen\":\"Toggle full screen\",\"JClic logo\":\"JClic logo\",\"message\":\"message\",\"Activity panel\":\"Activiteiten klaar:\",\"cell\":\"cell\",\"image\":\"image\",\"source\":\"source\",\"target\":\"target\",\"image fragment\":\"image fragment\"},\"pl\":{\"Version\":\"Wersja\",\"time\":\"czas\",\"actions\":\"działanie\",\"score\":\"wynik\",\"Next activity\":\"Następna aktywność\",\"Previous activity\":\"Poprzednia aktywność\",\"Restart activity\":\"Zrestartuj aktywność\",\"Information\":\"Informacje\",\"Results are not currently being saved\":\"Wyniki nie są obecnie zapisywane\",\"Current results\":\"Aktualne wyniki\",\"Session started:\":\"Sesja rozpoczęła się:\",\"Reports system:\":\"System raportów:\",\"User:\":\"Użytkownik:\",\"Projects:\":\"Projektowanie:\",\"Sequences:\":\"Sekwencje:\",\"Activities done:\":\"Działania wykonane:\",\"Activities solved:\":\"Działania rozwiązane:\",\"Global score:\":\"Globalny wynik:\",\"(out of all project activities)\":\"(poza wszystkimi działaniami projektu)\",\"Total time in activities:\":\"Całkowity czas aktywności:\",\"Actions done:\":\"Wykonane czynności:\",\"No activities done!\":\"Nie wykonano żadnych czynności!\",\"Project\":\"Projekt\",\"sequence\":\"sekwencja\",\"activity\":\"aktywność\",\"OK\":\"OK\",\"YES\":\"Tak\",\"NO\":\"Nie\",\"Total:\":\"Całkowity:\",\"Select group:\":\"Wybierz grupę:\",\"Select user:\":\"Wybierz użytkownika:\",\"Cancel\":\"Anuluj\",\"Close\":\"Zamknij\",\"Copy data to clipboard\":\"Skopiuj dane do schowka\",\"The data has been copied in HTML format. Please paste them into a spreadsheet or in a rich text editor\":\"Dane zostały skopiowane w formacie HTML. Wklej je do arkusza kalkulacyjnego lub edytora tekstu\",\"The data has been copied to clipboard\":\"Dane zostały skopiowane do schowka\",\"not connected\":\"nie połączony\",\"Please wait until the results of your activities are sent to the reports system\":\"Poczekaj, aż wyniki Twoich działań zostaną przesłane do systemu raportów\",\"Password:\":\"Hasło:\",\"Incorrect password\":\"Niepoprawne hasło\",\"Invalid user\":\"Nieprawidłowy użytkownik\",\"Partial score:\":\"Wynik częściowy:\",\"(out of played activities)\":\"(z granych zajęć)\",\"Activities played at least once:\":\"Działania grane co najmniej raz:\",\"Reports\":\"Raporty\",\"Toggle full screen\":\"Przełącz tryb pełnoekranowy\",\"JClic logo\":\"Logo JClic\",\"message\":\"komunikat\",\"Activity panel\":\"Panel aktywności\",\"cell\":\"komórka\",\"image\":\"obraz\",\"source\":\"źródło\",\"target\":\"miejsce docelowe\",\"image fragment\":\"fragment obrazu\"},\"pt\":{\"Version\":\"Versão\",\"time\":\"tempo\",\"actions\":\"tentativas\",\"score\":\"acertos\",\"Next activity\":\"Actividade seguinte\",\"Previous activity\":\"Actividade anterior\",\"Restart activity\":\"Reiniciar a actividade\",\"Information\":\"Informação\",\"Results are not currently being saved\":\"O relatório não está registado em nenhuma base de dados\",\"Current results\":\"Relatórios do utilizador\",\"Session started:\":\"Início da sessão:\",\"Reports system:\":\"Sistema de relatórios:\",\"User:\":\"Utilizador:\",\"Projects:\":\"Projectos:\",\"Sequences:\":\"Sequências:\",\"Activities done:\":\"Actividades realizadas:\",\"Activities solved:\":\"Actividades correctas:\",\"Global score:\":\"Pontuação global:\",\"(out of all project activities)\":\"Tempo total das actividades:\",\"Total time in activities:\":\"Tempo total das actividades:\",\"Actions done:\":\"Acções efectuadas:\",\"No activities done!\":\"Nenhuma actividade registada!\",\"Project\":\"Projecto\",\"sequence\":\"sequência\",\"activity\":\"Actividade\",\"OK\":\"Correcta\",\"YES\":\"sim\",\"NO\":\"não\",\"Total:\":\"Total:\",\"Select group:\":\"Select group:\",\"Select user:\":\"Select user:\",\"Cancel\":\"Cancel\",\"Close\":\"Close\",\"Copy data to clipboard\":\"Copy data to clipboard\",\"The data has been copied in HTML format. Please paste them into a spreadsheet or in a rich text editor\":\"The data has been copied in HTML format. Please paste them into a spreadsheet or in a rich text editor\",\"The data has been copied to clipboard\":\"The data has been copied to clipboard\",\"not connected\":\"not connected\",\"Please wait until the results of your activities are sent to the reports system\":\"Please wait until the results of your activities are sent to the reports system\",\"Password:\":\"Password:\",\"Incorrect password\":\"Incorrect password\",\"Invalid user\":\"Invalid user\",\"Partial score:\":\"Pontuação global:\",\"(out of played activities)\":\"(out of played activities)\",\"Activities played at least once:\":\"Actividades realizadas:\",\"Reports\":\"Sistema de relatórios:\",\"Toggle full screen\":\"Toggle full screen\",\"JClic logo\":\"JClic logo\",\"message\":\"message\",\"Activity panel\":\"Actividades realizadas:\",\"cell\":\"cell\",\"image\":\"image\",\"source\":\"source\",\"target\":\"target\",\"image fragment\":\"image fragment\"},\"pt_BR\":{\"Version\":\"Versão\",\"time\":\"tempo\",\"actions\":\"tentativas\",\"score\":\"acertos\",\"Next activity\":\"atividade seguinte\",\"Previous activity\":\"atividade anterior\",\"Restart activity\":\"Reiniciar a atividade\",\"Information\":\"Informação\",\"Results are not currently being saved\":\"O relatório não está registrando em nenhuma base de dados\",\"Current results\":\"relatórios de usuário\",\"Session started:\":\"Início da sessão:\",\"Reports system:\":\"Sistema de relatórios:\",\"User:\":\"Usuário:\",\"Projects:\":\"Projetos:\",\"Sequences:\":\"Sequências:\",\"Activities done:\":\"Atividades realizadas:\",\"Activities solved:\":\"Atividades corretas:\",\"Global score:\":\"Pontuação geral:\",\"(out of all project activities)\":\"Tempo total das atividades:\",\"Total time in activities:\":\"Tempo total das atividades:\",\"Actions done:\":\"Ações efetuadas:\",\"No activities done!\":\"Nenhuma atividade registrada!\",\"Project\":\"Projeto\",\"sequence\":\"sequência\",\"activity\":\"atividade\",\"OK\":\"Correta\",\"YES\":\"sim\",\"NO\":\"não\",\"Total:\":\"Total:\",\"Select group:\":\"Selecionar grupo:\",\"Select user:\":\"Selecionar usuário:\",\"Cancel\":\"Cancelar\",\"Close\":\"Fechar\",\"Copy data to clipboard\":\"Copiar dados para o clipboard\",\"The data has been copied in HTML format. Please paste them into a spreadsheet or in a rich text editor\":\"Os dados foram copiados no formato HTML. Favor colá-los em uma planilha ou em um editor de texto com formatação\",\"The data has been copied to clipboard\":\"Os dados foram copiados para o clipboard\",\"not connected\":\"não conectado\",\"Please wait until the results of your activities are sent to the reports system\":\"Favor aguardar até que os resultados das suas atividades sejam enviados ao sistema de relatórios\",\"Password:\":\"Senha:\",\"Incorrect password\":\"Senha errada\",\"Invalid user\":\"Usuário inválido\",\"Partial score:\":\"Pontuação geral:\",\"(out of played activities)\":\"(das atividades realizadas)\",\"Activities played at least once:\":\"Atividades realizadas:\",\"Reports\":\"Sistema de relatórios:\",\"Toggle full screen\":\"Modo tela cheia\",\"JClic logo\":\"logo do JClic\",\"message\":\"mensagem\",\"Activity panel\":\"Atividades realizadas:\",\"cell\":\"célula\",\"image\":\"imagem\",\"source\":\"fonte\",\"target\":\"alvo\",\"image fragment\":\"fragmento de imagem\"},\"ro\":{\"Version\":\"Versiune\",\"time\":\"timp\",\"actions\":\"acțiuni\",\"score\":\"rezultat\",\"Next activity\":\"Activitatea următoare\",\"Previous activity\":\"Activitatea anterioară\",\"Restart activity\":\"Restartează activitatea\",\"Information\":\"Informații\",\"Results are not currently being saved\":\"Rezultatul nu pare a fi salvat\",\"Current results\":\"Rezultatul curent\",\"Session started:\":\"Sesiune pornită la:\",\"Reports system:\":\"Sistem raportare:\",\"User:\":\"Utilizator\",\"Projects:\":\"Proiecte:\",\"Sequences:\":\"Secvențe:\",\"Activities done:\":\"Activități realizate: \",\"Activities solved:\":\"Activități rezolvate: \",\"Global score:\":\"Rezultat global:\",\"(out of all project activities)\":\"(în afara activităților din proiect)\",\"Total time in activities:\":\"Timp total în activitate:\",\"Actions done:\":\"Activități realizate: \",\"No activities done!\":\"Activități nerealizate: \",\"Project\":\"Proiect\",\"sequence\":\"secvență\",\"activity\":\"activitate\",\"OK\":\"OK\",\"YES\":\"DA\",\"NO\":\"NU\",\"Total:\":\"Total:\",\"Select group:\":\"Alege grup:\",\"Select user:\":\"Alege utilizator:\",\"Cancel\":\"Anuleaza\",\"Close\":\"Închide\",\"Copy data to clipboard\":\"Copiază datele in clipboard\",\"The data has been copied in HTML format. Please paste them into a spreadsheet or in a rich text editor\":\"Datele au fost copiate în format HTML. Vă rog lipiți-le într-o foaie de calcul sau într-un editor compatibil rich text\",\"The data has been copied to clipboard\":\"Datele au fost copiate în clipboard\",\"not connected\":\"neconectat\",\"Please wait until the results of your activities are sent to the reports system\":\"Vă rugăm să așteptați până ce rezultatele activităților sunt trimise către sistemul de raportare\",\"Password:\":\"Parolă:\",\"Incorrect password\":\"Parolă incorectă\",\"Invalid user\":\"Utilizator incorect\",\"Partial score:\":\"Rezultat parțial:\",\"(out of played activities)\":\"(în afara activități jucate) \",\"Activities played at least once:\":\"Activități jucate cel puțin o dată: \",\"Reports\":\"Rapoarte\",\"Toggle full screen\":\"Comută în ecran plin\",\"JClic logo\":\"Jclic logo\",\"message\":\"mesaj\",\"Activity panel\":\"Panou activități\",\"cell\":\"celulă\",\"image\":\"imagine\",\"source\":\"sursă\",\"target\":\"țintă\",\"image fragment\":\"fragment de imagine \"},\"ru\":{\"Version\":\"Версия\",\"time\":\"время\",\"actions\":\"попытки\",\"score\":\"счёт\",\"Next activity\":\"Следующее действие\",\"Previous activity\":\"Предыдущее действие\",\"Restart activity\":\"Перезапуск действия\",\"Information\":\"Информация\",\"Results are not currently being saved\":\"Отчёт не зарегистрирован в БД\",\"Current results\":\"Отчёты пользователя\",\"Session started:\":\"Сессия начата:\",\"Reports system:\":\"Система отчётов:\",\"User:\":\"Пользователь:\",\"Projects:\":\"Проекты:\",\"Sequences:\":\"Последовательности:\",\"Activities done:\":\"Совершенные действия:\",\"Activities solved:\":\"Действия в порядке:\",\"Global score:\":\"Общий счёт:\",\"(out of all project activities)\":\"Общее время активности:\",\"Total time in activities:\":\"Общее время активности:\",\"Actions done:\":\"Завершено действий:\",\"No activities done!\":\"Нет сообщенных действий!\",\"Project\":\"Проект\",\"sequence\":\"Последовательность\",\"activity\":\"Активность\",\"OK\":\"ОК\",\"YES\":\"да\",\"NO\":\"нет\",\"Total:\":\"Итого:\",\"Select group:\":\"Select group:\",\"Select user:\":\"Select user:\",\"Cancel\":\"Cancel\",\"Close\":\"Close\",\"Copy data to clipboard\":\"Copy data to clipboard\",\"The data has been copied in HTML format. Please paste them into a spreadsheet or in a rich text editor\":\"The data has been copied in HTML format. Please paste them into a spreadsheet or in a rich text editor\",\"The data has been copied to clipboard\":\"The data has been copied to clipboard\",\"not connected\":\"not connected\",\"Please wait until the results of your activities are sent to the reports system\":\"Please wait until the results of your activities are sent to the reports system\",\"Password:\":\"Password:\",\"Incorrect password\":\"Incorrect password\",\"Invalid user\":\"Invalid user\",\"Partial score:\":\"Общий счёт:\",\"(out of played activities)\":\"(out of played activities)\",\"Activities played at least once:\":\"Совершенные действия:\",\"Reports\":\"Система отчётов:\",\"Toggle full screen\":\"Toggle full screen\",\"JClic logo\":\"JClic logo\",\"message\":\"message\",\"Activity panel\":\"Совершенные действия:\",\"cell\":\"cell\",\"image\":\"image\",\"source\":\"source\",\"target\":\"target\",\"image fragment\":\"image fragment\"},\"ta\":{\"Version\":\"பதிப்பு\",\"time\":\"நேரம்\",\"actions\":\"செயல்கள்\",\"score\":\"கெலிப்பெண்\",\"Next activity\":\"அடுத்த செயல்பாடு\",\"Previous activity\":\"முந்தைய செயல்பாடு\",\"Restart activity\":\"செயல்பாட்டை மறுதொடக்கம் செய்யுங்கள்\",\"Information\":\"தகவல்\",\"Results are not currently being saved\":\"முடிவுகள் தற்போது சேமிக்கப்படவில்லை\",\"Current results\":\"தற்போதைய முடிவுகள்\",\"Session started:\":\"சந்திப்பு தொடங்கியது:\",\"Reports system:\":\"அறிக்கை அமைப்பு:\",\"User:\":\"பயனர்:\",\"Projects:\":\"திட்டங்கள்:\",\"Sequences:\":\"தொடர்கள்:\",\"Activities done:\":\"முடிந்த நடவடிக்கைகள்:\",\"Activities solved:\":\"தீர்க்கப்பட்ட நடவடிக்கைகள்:\",\"Global score:\":\"உலகளாவிய மதிப்பெண்:\",\"(out of all project activities)\":\"(அனைத்து திட்ட நடவடிக்கைகளிலும்)\",\"Total time in activities:\":\"நடவடிக்கைகளில் மொத்த நேரம்:\",\"Actions done:\":\"செய்யப்பட்ட செயல்கள்:\",\"No activities done!\":\"நடவடிக்கைகள் எதுவும் செய்யப்படவில்லை!\",\"Project\":\"திட்டம்\",\"sequence\":\"வரிசை\",\"activity\":\"செய்கைப்பாடு\",\"OK\":\"சரி\",\"YES\":\"ஆம்\",\"NO\":\"இல்லை\",\"Total:\":\"மொத்தம்:\",\"Select group:\":\"குழுவைத் தேர்ந்தெடுக்கவும்:\",\"Select user:\":\"பயனரைத் தேர்ந்தெடுக்கவும்:\",\"Cancel\":\"ரத்துசெய்\",\"Close\":\"மூடு\",\"Copy data to clipboard\":\"இடைநிலைப்பலகைக்கு தரவை நகலெடுக்கவும்\",\"The data has been copied in HTML format. Please paste them into a spreadsheet or in a rich text editor\":\"தரவு உஉகுமொ வடிவத்தில் நகலெடுக்கப்பட்டுள்ளது. தயவுசெய்து அவற்றை ஒரு விரிதாளில் அல்லது பணக்கார உரை திருத்தியில் ஒட்டவும்\",\"The data has been copied to clipboard\":\"தரவு இடைநிலைப்பலகைக்கு நகலெடுக்கப்பட்டுள்ளது\",\"not connected\":\"இணைக்கப்படவில்லை\",\"Please wait until the results of your activities are sent to the reports system\":\"உங்கள் செயல்பாடுகளின் முடிவுகள் அறிக்கைகள் முறைக்கு அனுப்பப்படும் வரை காத்திருங்கள்\",\"Password:\":\"கடவுச்சொல்:\",\"Incorrect password\":\"தவறான கடவுச்சொல்\",\"Invalid user\":\"தவறான பயனர்\",\"Partial score:\":\"பகுதி மதிப்பெண்:\",\"(out of played activities)\":\"(விளையாடிய நடவடிக்கைகளுக்கு வெளியே)\",\"Activities played at least once:\":\"செயல்பாடுகள் ஒரு முறையாவது:\",\"Reports\":\"அறிக்கை அமைப்பு:\",\"Toggle full screen\":\"Toggle full screen\",\"JClic logo\":\"JClic logo\",\"message\":\"message\",\"Activity panel\":\"முடிந்த நடவடிக்கைகள்:\",\"cell\":\"cell\",\"image\":\"image\",\"source\":\"source\",\"target\":\"target\",\"image fragment\":\"image fragment\"},\"tr\":{\"Version\":\"Sürüm\",\"time\":\"zaman\",\"actions\":\"Denemeler\",\"score\":\"sonuç\",\"Next activity\":\"Sonraki etkinlik\",\"Previous activity\":\"Önceki etkinlik\",\"Restart activity\":\"Etkinliği yeniden başlat\",\"Information\":\"Bilgi\",\"Results are not currently being saved\":\"Sonuçlar şu anda kaydedilmiyor\",\"Current results\":\"Geçerli sonuçlar\",\"Session started:\":\"Oturum başlatıldı:\",\"Reports system:\":\"Sistem raporları:\",\"User:\":\"Kullanıcı:\",\"Projects:\":\"Projeler:\",\"Sequences:\":\"Sekanslar:\",\"Activities done:\":\"Tamamlanan etkinlikler:\",\"Activities solved:\":\"Çözülen etkinlikler:\",\"Global score:\":\"Genel puan:\",\"(out of all project activities)\":\"Toplam etkinlik süresi:\",\"Total time in activities:\":\"Toplam etkinlik süresi:\",\"Actions done:\":\"Tamamlanan işlemler:\",\"No activities done!\":\"Tamamlanan etkinlik yok!\",\"Project\":\"Proje\",\"sequence\":\"Etkinlik dizisi\",\"activity\":\"Etkinlik\",\"OK\":\"Tamam\",\"YES\":\"Evet\",\"NO\":\"Hayır\",\"Total:\":\"Toplam:\",\"Select group:\":\"Select group:\",\"Select user:\":\"Select user:\",\"Cancel\":\"Cancel\",\"Close\":\"Close\",\"Copy data to clipboard\":\"Copy data to clipboard\",\"The data has been copied in HTML format. Please paste them into a spreadsheet or in a rich text editor\":\"The data has been copied in HTML format. Please paste them into a spreadsheet or in a rich text editor\",\"The data has been copied to clipboard\":\"The data has been copied to clipboard\",\"not connected\":\"not connected\",\"Please wait until the results of your activities are sent to the reports system\":\"Please wait until the results of your activities are sent to the reports system\",\"Password:\":\"Password:\",\"Incorrect password\":\"Incorrect password\",\"Invalid user\":\"Invalid user\",\"Partial score:\":\"Genel puan:\",\"(out of played activities)\":\"(out of played activities)\",\"Activities played at least once:\":\"Tamamlanan etkinlikler:\",\"Reports\":\"Sistem raporları:\",\"Toggle full screen\":\"Toggle full screen\",\"JClic logo\":\"JClic logo\",\"message\":\"message\",\"Activity panel\":\"Tamamlanan etkinlikler:\",\"cell\":\"cell\",\"image\":\"image\",\"source\":\"source\",\"target\":\"target\",\"image fragment\":\"image fragment\"},\"uk\":{\"Version\":\"Версія\",\"time\":\"Час\",\"actions\":\"спроби\",\"score\":\"оцінка\",\"Next activity\":\"Наступна діяльність\",\"Previous activity\":\"Попередня діяльність\",\"Restart activity\":\"Перезапуск діяльності\",\"Information\":\"Інформація\",\"Results are not currently being saved\":\"Звіт не зареєстровано в БД\",\"Current results\":\"Звіти користувача\",\"Session started:\":\"Сеанс розпочато:\",\"Reports system:\":\"Система звітів:\",\"User:\":\"Користувач:\",\"Projects:\":\"Проєкти:\",\"Sequences:\":\"Послідовності:\",\"Activities done:\":\"Виконані діяльності:\",\"Activities solved:\":\"Вирішені діяльності:\",\"Global score:\":\"Загальна оцінка:\",\"(out of all project activities)\":\"(з усіх діяльностей проєкту)\",\"Total time in activities:\":\"Загальний час діяльності:\",\"Actions done:\":\"Виконані дії:\",\"No activities done!\":\"Жодних діяльностей не виконано!\",\"Project\":\"Проєкт\",\"sequence\":\"послідовність\",\"activity\":\"активність\",\"OK\":\"Гаразд\",\"YES\":\"Так\",\"NO\":\"Ні\",\"Total:\":\"Підсумок:\",\"Select group:\":\"Вибрати групу:\",\"Select user:\":\"Виберіть користувача:\",\"Cancel\":\"Скасувати\",\"Close\":\"Закрити\",\"Copy data to clipboard\":\"Копіювати дані в буфер обміну\",\"The data has been copied in HTML format. Please paste them into a spreadsheet or in a rich text editor\":\"Дані скопійовані у форматі HTML. Будь ласка, вставте їх в електронну таблицю або у текстовий редактор\",\"The data has been copied to clipboard\":\"Дані скопійовано до буферу обміну\",\"not connected\":\"Немає з’єднання\",\"Please wait until the results of your activities are sent to the reports system\":\"Будь ласка, зачекайте, поки результати вашої діяльності будуть надіслані до системи звітів\",\"Password:\":\"Пароль:\",\"Incorrect password\":\"Неправильний пароль\",\"Invalid user\":\"Неприпустимий користувач\",\"Partial score:\":\"Часткова оцінка:\",\"(out of played activities)\":\"(поза відтвореними діяльностями)\",\"Activities played at least once:\":\"Діяльності, які відтворювалися принаймні один раз:\",\"Reports\":\"Система звітів:\",\"Toggle full screen\":\"Toggle full screen\",\"JClic logo\":\"JClic logo\",\"message\":\"message\",\"Activity panel\":\"Виконані діяльності:\",\"cell\":\"cell\",\"image\":\"image\",\"source\":\"source\",\"target\":\"target\",\"image fragment\":\"image fragment\"},\"vec\":{\"Version\":\"Version\",\"time\":\"tenpo\",\"actions\":\"tentadivi\",\"score\":\"pontexio\",\"Next activity\":\"Pròsima atività\",\"Previous activity\":\"Atività presedente\",\"Restart activity\":\"Invìa atività da novo\",\"Information\":\"Informasion\",\"Results are not currently being saved\":\"Report no registrà inte nisun database\",\"Current results\":\"Reports utenti\",\"Session started:\":\"Sesion inviada:\",\"Reports system:\":\"Sistèma de report\",\"User:\":\"Utente:\",\"Projects:\":\"Proxèti:\",\"Sequences:\":\"Secuense:\",\"Activities done:\":\"Atività fate:\",\"Activities solved:\":\"Atività ok:\",\"Global score:\":\"Pontexio global\",\"(out of all project activities)\":\"Tenpo total so ƚe atività\",\"Total time in activities:\":\"Tenpo total so ƚe atività\",\"Actions done:\":\"Asion exeguìe\",\"No activities done!\":\"No xé stà reportà atività!\",\"Project\":\"Proxèto:\",\"sequence\":\"secuensa\",\"activity\":\"Atività\",\"OK\":\"Ok\",\"YES\":\"SI\",\"NO\":\"NO\",\"Total:\":\"Total:\",\"Select group:\":\"Select group:\",\"Select user:\":\"Select user:\",\"Cancel\":\"Cancel\",\"Close\":\"Close\",\"Copy data to clipboard\":\"Copy data to clipboard\",\"The data has been copied in HTML format. Please paste them into a spreadsheet or in a rich text editor\":\"The data has been copied in HTML format. Please paste them into a spreadsheet or in a rich text editor\",\"The data has been copied to clipboard\":\"The data has been copied to clipboard\",\"not connected\":\"not connected\",\"Please wait until the results of your activities are sent to the reports system\":\"Please wait until the results of your activities are sent to the reports system\",\"Password:\":\"Password:\",\"Incorrect password\":\"Incorrect password\",\"Invalid user\":\"Invalid user\",\"Partial score:\":\"Pontexio global\",\"(out of played activities)\":\"(out of played activities)\",\"Activities played at least once:\":\"Atività fate:\",\"Reports\":\"Sistèma de report\",\"Toggle full screen\":\"Toggle full screen\",\"JClic logo\":\"JClic logo\",\"message\":\"message\",\"Activity panel\":\"Atività fate:\",\"cell\":\"cell\",\"image\":\"image\",\"source\":\"source\",\"target\":\"target\",\"image fragment\":\"image fragment\"},\"zh_TW\":{\"Version\":\"版本\",\"time\":\"時間\",\"actions\":\"嘗試次數\",\"score\":\"分數\",\"Next activity\":\"下一個活動\",\"Previous activity\":\"上一個活動\",\"Restart activity\":\"重設活動\",\"Information\":\"相關資訊\",\"Results are not currently being saved\":\"回報在DB中無註冊\",\"Current results\":\"使用者報告\",\"Session started:\":\"工作開始:\",\"Reports system:\":\"報告系統:\",\"User:\":\"使用者:\",\"Projects:\":\"專案:\",\"Sequences:\":\"順序:\",\"Activities done:\":\"活動結束:\",\"Activities solved:\":\"活動完成:\",\"Global score:\":\"總成績:\",\"(out of all project activities)\":\"活動總時間:\",\"Total time in activities:\":\"活動總時間:\",\"Actions done:\":\"活動完成:\",\"No activities done!\":\"沒有活動完成!\",\"Project\":\"專案\",\"sequence\":\"順序\",\"activity\":\"活動\",\"OK\":\"確定\",\"YES\":\"是\",\"NO\":\"否\",\"Total:\":\"總計:\",\"Select group:\":\"Select group:\",\"Select user:\":\"Select user:\",\"Cancel\":\"Cancel\",\"Close\":\"Close\",\"Copy data to clipboard\":\"Copy data to clipboard\",\"The data has been copied in HTML format. Please paste them into a spreadsheet or in a rich text editor\":\"The data has been copied in HTML format. Please paste them into a spreadsheet or in a rich text editor\",\"The data has been copied to clipboard\":\"The data has been copied to clipboard\",\"not connected\":\"not connected\",\"Please wait until the results of your activities are sent to the reports system\":\"Please wait until the results of your activities are sent to the reports system\",\"Password:\":\"Password:\",\"Incorrect password\":\"Incorrect password\",\"Invalid user\":\"Invalid user\",\"Partial score:\":\"總成績:\",\"(out of played activities)\":\"(out of played activities)\",\"Activities played at least once:\":\"活動結束:\",\"Reports\":\"報告系統:\",\"Toggle full screen\":\"Toggle full screen\",\"JClic logo\":\"JClic logo\",\"message\":\"message\",\"Activity panel\":\"活動結束:\",\"cell\":\"cell\",\"image\":\"image\",\"source\":\"source\",\"target\":\"target\",\"image fragment\":\"image fragment\"}}};","/**\n * File : Utils.js\n * Created : 01/04/2015\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\n/* global Promise, window, document, console, HTMLElement */\n\nimport $ from 'jquery';\nimport JSZip from 'jszip';\nimport JSZipUtils from 'jszip-utils';\nimport GlobalData from './GlobalData.js';\n\n/**\n * Exports third-party NPM packages used by JClic, so they become available to other scripts through\n * the global variable `JClicObject` (defined in {@link module:JClic.JClic})\n * @type: {object}\n */\nexport const pkg = {\n $,\n JSZip,\n JSZipUtils,\n};\n\n/**\n * List of valid verbosity levels\n * @const {string[]}\n */\nexport const LOG_LEVELS = ['none', 'error', 'warn', 'info', 'debug', 'trace', 'all'];\n\n/**\n * Labels printed on logs for each message type\n * @const {string[]}\n */\nexport const LOG_PRINT_LABELS = [' ', 'ERROR', 'WARN ', 'INFO ', 'DEBUG', 'TRACE', 'ALL '];\n\n/**\n * Options of the logging system\n * @type {object} */\nexport const LOG_OPTIONS = {\n level: 2, // warn\n prefix: 'JClic',\n timestamp: true,\n popupOnErrors: false,\n chainTo: null,\n pipeTo: null,\n};\n\n/**\n * Current dictionary of string translations\n */\nlet _messages = {};\n\n/**\n * Initializes the global settings\n * @param {object} options - An object with global settings\n * @param {boolean} [setLog=true] - When `true`, the log level will be set\n * @param {boolean} [setLang=true] - When `true`, the current language will be set\n * @returns {object} The normalized `options` object\n */\nexport function init(options, setLog = true, setLang = true) {\n options = normalizeObject(options);\n if (setLog) {\n if (typeof options.logLevel !== 'undefined')\n setLogLevel(options.logLevel);\n if (typeof options.chainLogTo === 'function')\n LOG_OPTIONS.chainTo = options.chainLogTo;\n if (typeof options.pipeLogTo === 'function')\n LOG_OPTIONS.pipeTo = options.pipeLogTo;\n }\n\n if (setLang) {\n const lngRequested = options.lang;\n const lng = checkPreferredLanguage(GlobalData.languages, 'en', lngRequested);\n log('debug', `Language ${lngRequested ? `requested: \"${lngRequested}\" ` : ''} used: \"${lng}\"`);\n _messages = lng === 'en' ? {} : GlobalData.messages[lng];\n }\n\n return options;\n};\n\n/**\n * Function that will return the translation of the provided key\n * into the current language.\n * @param {string} key - ID of the expression to be translated\n * @returns {string} - The translated text\n */\nexport function getMsg(key) {\n return _messages[key] || key;\n}\n\n/**\n * Converts expressions of type 'pt-br', 'FR', 'ca_es@valencia'... to the format expected by the i18n system:\n * lc[_CC][@variant] where 'lc' is a two or three lowercase letter language code, CC is an optional two uppercase\n * letter country code, followed by an optional 'variant' consisting in letters and/or digits.\n * @param {string} locale - The locale expression to be normalized\n * @returns string - The normalized locale\n */\nexport function normalizeLocale(locale = '') {\n const [, language = null, country = null, variant = null] = /^([a-zA-Z]{2,3})[_-]?([a-zA-Z]{2})?@?([a-zA-Z0-9]*)?$/.exec(locale.trim()) || [];\n return language\n ? `${language.toLowerCase()}${country ? `_${country.toUpperCase()}` : ''}${variant ? `@${variant.toLowerCase()}` : ''}`\n : '';\n};\n\n/**\n * Checks if the language preferred by the user (based on browser and/or specific settings)\n * is in a list of available languages.\n * @param {string[]} availableLangs - Array of available languages. It should contain at least one item.\n * @param {string} [defaultLang=en] - Language to be used by default when not found the selected one\n * @param {string} [requestedLang=''] - Request this specific language\n * @returns {string} - The most suitable language for this request\n */\nexport function checkPreferredLanguage(availableLangs, defaultLang = 'en', requestedLang = '') {\n let result = -1;\n\n // Create an array to store possible values\n let tries = [];\n\n // If \"setLang\" is specified, check it\n if (requestedLang) {\n // Normalize requested locale\n const lang = normalizeLocale(requestedLang);\n if (lang)\n tries.push(lang);\n }\n\n // Add user's preferred languages, if any\n if (window.navigator.languages)\n tries = tries.concat(window.navigator.languages);\n\n // Add the navigator main language, if defined\n if (window.navigator.language)\n tries.push(window.navigator.language);\n\n // Add English as final option\n tries.push(defaultLang);\n\n for (let i = 0; i < tries.length; i++) {\n let match = -1;\n for (let n in availableLangs) {\n if (tries[i].indexOf(availableLangs[n]) === 0) {\n match = n;\n if (tries[i] === availableLangs[n]) {\n result = n;\n break;\n }\n }\n }\n if (result >= 0 || (result = match) >= 0)\n break;\n }\n return availableLangs[result >= 0 ? result : 0];\n};\n\n/**\n * Establishes the current verbosity level of the logging system\n * @param {string} level - One of the valid strings in {@link module:Utils.LOG_LEVELS}\n */\nexport function setLogLevel(level) {\n const log = LOG_LEVELS.indexOf(level);\n if (log >= 0)\n LOG_OPTIONS.level = log;\n};\n\n/**\n * Reports a new message to the logging system\n * @param {string} type - The type of message. Mus be `error`, `warn`, `info`, `debug` or `trace`.\n * @param {string} msg - The main message to be logged. Additional parameters can be added, like\n * in `console.log` (see: {@link https://developer.mozilla.org/en-US/docs/Web/API/Console/log})\n */\nexport function log(type, msg) {\n const level = LOG_LEVELS.indexOf(type);\n const args = Array.prototype.slice.call(arguments);\n\n // Check if message should currently be logged\n if (level < 0 || level <= LOG_OPTIONS.level) {\n if (LOG_OPTIONS.pipeTo)\n LOG_OPTIONS.pipeTo.apply(null, args);\n else {\n const mainMsg = `${LOG_OPTIONS.prefix || ''} ${LOG_PRINT_LABELS[level]} ${LOG_OPTIONS.timestamp ? getDateTime() : ''} ${msg}`;\n console[level === 1 ? 'error' : level === 2 ? 'warn' : 'log'].apply(console, [mainMsg].concat(args.slice(2)));\n // Call chained logger, if anny\n if (LOG_OPTIONS.chainTo)\n LOG_OPTIONS.chainTo.apply(null, args);\n }\n }\n};\n\n/**\n * Gets a boolean value from a textual expression\n * @param {string} val - The value to be parsed (`true` for true, null or otherwise for `false`)\n * @param {boolean} [defaultValue=false] - The default value to return when `val` is false\n * @returns {number}\n */\nexport function getBoolean(val, defaultValue = false) {\n return val === 'true' ? true : val === 'false' ? false : defaultValue;\n};\n\n/**\n * Gets a value from an given expression that can be `null`, `undefined` or empty string ('')\n * @param {any} val - The expression to parse\n * @param {any} [defaultValue=null] - The value to return when `val` is `null`, `''` or `undefined`\n * @returns {any}\n */\nexport function getVal(val, defaultValue = null) {\n return (val === '' || val === null || typeof val === 'undefined') ? defaultValue : val;\n};\n\n/**\n * Gets a number from a string or another number\n * @param {any} val - The expression to parse\n * @param {number} [defaultValue=0] - The default value\n * @returns {number}\n */\nexport function getNumber(val, defaultValue) {\n return Number(getVal(val, defaultValue));\n};\n\n/**\n * Gets the plain percent expression (without decimals) of the given value\n * @param {number} val - The value to be expressed as a percentile\n * @returns {string}\n */\nexport function getPercent(val) {\n return `${Math.round(val * 100)}%`;\n}\n\n/**\n * Returns the two-digits text expression representing the given number (lesser than 100) zero-padded at left\n * Useful for representing hours, minutes and seconds\n * @param {number} val - The number to be processed\n * @returns {string}\n */\nexport function zp(val) {\n return `0${val}`.slice(-2);\n};\n\n/**\n * Returns a given time in [00h 00'00\"] format\n * @param {number} millis - Amount of milliseconds to be processed\n * @returns {string}\n */\nexport function getHMStime(millis) {\n const d = new Date(millis);\n const h = d.getUTCHours(), m = d.getUTCMinutes(), s = d.getUTCSeconds();\n return `${h ? h + 'h ' : ''}${h || m ? zp(m) + '\\'' : ''}${zp(s)}\"`;\n};\n\n/**\n * Returns a formatted string with the provided date and time\n * @param {external:Date} date - The date to be formatted. When `null` or `undefined`, the current date will be used.\n * @returns {string}\n */\nexport function getDateTime(date = new Date()) {\n return `${date.getFullYear()}/${zp(date.getMonth() + 1)}/${zp(date.getDate())} ${zp(date.getHours())}:${zp(date.getMinutes())}:${zp(date.getSeconds())}`;\n};\n\n/**\n * Parse 'date' fields generated by \"JClic Author\" in format d/m/y, with\n * variable number of digits.\n * @param {string} text - The old 'date' field\n * @returns {external:Date} - Always return a Date object (now, if text was invalid)\n */\nexport function parseOldDate(text) {\n let result = null;\n if (text) {\n const elements = text.trim().split('/');\n if (elements.length === 3) {\n let m = parseInt(elements[0]) || 0;\n let d = parseInt(elements[1]) || 0;\n let y = parseInt(elements[2]) || 0;\n if (m > 12 && d <= 12) {\n const t = m;\n m = d;\n d = t;\n }\n if (y < 1980)\n y += (y < 90 ? 2000 : 1900);\n if (d && m && y) {\n result = new Date(Date.parse(`${m}/${d}/${y}`));\n }\n }\n }\n return result || new Date();\n};\n\n/**\n * Extracts just the ISO-639 language code from complex\n * expressions like \"English (en)\", buid by JClic Author.\n * @param {string} text - The expression to parse\n * @returns {string} - The ISO-639 language code, or '--' if none found\n */\nexport function cleanOldLanguageTag(text) {\n if (!text)\n text = '--';\n // Allow only ISO-639-1 and ISO-639-2 language codes\n else if (!text.match(/^[a-z][a-z][a-z]?$/)) {\n const matches = text.match(/\\(([a-z][a-z][a-z]?)\\)/);\n if (matches && matches.length === 2)\n text = matches[1];\n else\n text = '--';\n }\n return text;\n};\n\n/** @const {number} */\nexport const FALSE = 0;\n\n/** @const {number} */\nexport const TRUE = 1;\n\n/** @const {number} */\nexport const DEFAULT = 2;\n\n/**\n * Gets a numeric value (0, 1 or 2) from a set of possible values: `false`, `true` and `default`.\n * @param {string} val - The text to be parsed\n * @param {any} def - An optional default value\n * @returns {number}\n */\nexport function getTriState(val, def = DEFAULT) {\n return val === 'true' ? TRUE : val === 'false' ? FALSE : def;\n};\n\n/**\n * Returns a string with the given `tag` repeated n times\n * @param {string} tag - The tag to be repeated\n * @param {number} repeats - The number of times to repeat the tag\n * @returns {string}\n */\nexport function fillString(tag, repeats = 0) {\n return Array(repeats).fill(tag).join('');\n};\n\n/**\n * Checks if the provided value is 'null' or 'undefined'.\n * @param {any} val - The value to be parsed\n * @returns {boolean}\n */\nexport function isNullOrUndef(val) {\n return typeof val === 'undefined' || val === null;\n};\n\n/**\n * Checks if two expressions are equivalent.\n * Returns `true` when both parameters are `null` or `undefined`, and also when both have\n * equivalent values.\n * @param {any} a\n * @param {any} b\n * @returns {boolean}\n */\nexport function isEquivalent(a, b) {\n return (typeof a === 'undefined' || a === null) && (typeof b === 'undefined' || b === null) || a === b;\n};\n\n/**\n * Reads paragraphs, identified by `<p></p>` elements, inside XML data\n * @param {object} xml - The DOM-XML element to be parsed\n * @returns {string}\n */\nexport function getXmlText(xml) {\n let text = '';\n $(xml).children('p').each((_n, child) => { text += `<p>${child.textContent}</p>`; });\n return text;\n};\n\n/**\n * Parse the provided XML element node, returning a complex object\n * @param {object} xml - The root XML element to parse\n * @param {boolean} [withText=false] - When `true`, any text found inside the XML element is also included in the resulting object.\n * @returns {object}\n */\nexport function parseXmlNode(xml, withText = false) {\n // Initialize the resulting object\n const result = {};\n // Direct copy of root element attributes as object properties\n if (xml.attributes)\n attrForEach(xml.attributes, (name, value) => result[name] = /^-?\\d*$/.test(value) ? Number(value) : value);\n\n const keys = [];\n const children = Array.from(xml.children || xml.childNodes || []);\n\n // If all children is of type 'p', just compile it in a single string\n const paragraphs = children.filter(child => child.nodeName === 'p');\n if (paragraphs.length > 0 && paragraphs.length === children.filter(ch => ch.nodeName !== '#text').length) {\n const text = paragraphs.map(ch => ch.textContent).join('\\n');\n if (xml.attributes) {\n result.text = text;\n return result;\n }\n return text;\n }\n\n // Process children elements\n children.forEach(child => {\n // Avoid extra text content collected by [xmldom](https://www.npmjs.com/package/xmldom)\n if (child.nodeName === '#text' && !withText)\n return;\n\n // Recursive processing of children\n const ch = parseXmlNode(child, withText);\n // Store the result into a temporary object named as the child node name,\n if (!result[child.nodeName]) {\n // Create object and save key for later processing\n result[child.nodeName] = {};\n keys.push(child.nodeName);\n }\n // Use 'id' (or an incremental number if 'id' is not set) as a key\n if (ch.id)\n result[child.nodeName][ch.id] = ch;\n else {\n const n = Object.keys(result[child.nodeName]).length;\n result[child.nodeName][n] = ch;\n }\n });\n // Check temporary objects, converting it to an array, a single object or a complex object\n keys.forEach(k => {\n // Retrieve temporary object from `keys`\n const kx = Object.keys(result[k]);\n // If all keys are numbers, convert object into an array (or leave it as a single object)\n if (!kx.find(kk => isNaN(kk))) {\n if (kx.length === 1)\n // Array with a single element. Leave it as a simple object:\n result[k] = result[k][0];\n else {\n // Object with numeric keys. Convert it to array:\n const arr = [];\n kx.forEach(kk => arr.push(result[k][kk]));\n result[k] = arr;\n }\n }\n });\n // Save text content, if any:\n if (children.length === 0 && xml.textContent)\n result.textContent = xml.textContent;\n return result;\n};\n\n/**\n * Parse the given XML node, known as containing only text elements,\n * and return its content as a string (when possible)\n * @param {object} xml - The XML element to parse\n * @returns {string|object}\n */\nexport function getXmlNodeText(node) {\n const result = parseXmlNode(node);\n return typeof result === 'string' ?\n result :\n result.hasOwnProperty('text') ?\n result.text :\n result.hasOwnProperty('textContent') ?\n result.textContent :\n result;\n};\n\n/**\n * Recursively explore the given object, converting to a string\n * all attributes with a single attribute named 'text'.\n * Example:\n * {a:1, b:{text:\"hello\"}, c:{d:2, text:\"world\"}} => {a:1, b:\"hello\", c:{d:2, text:\"world\"}}\n * @param {object} obj - The object to explore\n * @returns {object} - The same object, with text attributes reduced to strings\n */\nexport function reduceTextsToStrings(obj) {\n if (obj) {\n const keys = Object.keys(obj);\n keys.forEach(k => {\n const attr = obj[k];\n if (typeof attr === 'object') {\n const ko = Object.keys(attr);\n if (ko.length === 1 && ko[0] === 'text')\n obj[k] = attr.text;\n else\n obj[k] = reduceTextsToStrings(attr);\n }\n });\n }\n return obj;\n};\n\n/**\n * Creates a string suitable to be used in the 'style' attribute of HTML tags, filled with the\n * CSS attributes contained in the provided object.\n * @param {object} cssObj\n * @returns {string}\n */\nexport function cssToString(cssObj) {\n return Object.keys(cssObj).reduce((s, key) => `${s}${key}:${cssObj[key]};`, '');\n};\n\n/**\n * Converts java-like color codes (like '0xRRGGBB') to valid CSS values like '#RRGGBB' or 'rgba(r,g,b,a)'\n * @param {string} [color] - A color, as codified in Java\n * @param {string} [defaultColor] - The default color to be used\n * @returns {string}\n */\nexport function checkColor(color, defaultColor = settings.BoxBase.BACK_COLOR) {\n if (typeof color === 'undefined' || color === null)\n color = defaultColor;\n color = color.replace('0x', '#');\n // Check for Alpha value\n if (color.charAt(0) === '#' && color.length > 7) {\n const alpha = fx(parseInt(color.substring(1, 3), 16) / 255.0, 2);\n color = `rgba(${parseInt(color.substring(3, 5), 16)},${parseInt(color.substring(5, 7), 16)},${parseInt(color.substring(7, 9), 16)},${alpha})`;\n }\n return color;\n};\n\n/**\n * Checks if the provided color has an alpha value less than 1\n * @param {string} color - The color to be analyzed\n * @returns {boolean}\n */\nexport function colorHasTransparency(color) {\n if (startsWith(color, 'rgba(')) {\n var alpha = parseInt(color.substring(color.lastIndexOf(',')));\n return typeof alpha === 'number' && alpha < 1.0;\n }\n return false;\n};\n\n/**\n * Clones the provided object\n * See: https://stackoverflow.com/questions/41474986/how-to-clone-a-javascript-es6-class-instance\n * @param {object} obj\n * @returns {object}\n */\n//cloneObject: obj => Object.assign(Object.create(Object.getPrototypeOf(obj)), obj),\nexport function cloneObject(obj) {\n return $.extend(true, Object.create(Object.getPrototypeOf(obj)), obj);\n};\n\n/**\n * Converts string values to number or boolean when needed\n * @param {object} obj - The object to be processed\n * @returns {object} - A new object with normalized content\n */\nexport function normalizeObject(obj) {\n const result = {};\n if (obj)\n $.each(obj, (key, value) => {\n let s;\n if (typeof value === 'string' && (s = value.trim().toLowerCase()) !== '')\n value = s === 'true' ? true : s === 'false' ? false : isNaN(s) ? value : Number(s);\n result[key] = value;\n });\n return result;\n};\n\n/**\n * Returns an partial clone of an object, containing only the own attributes specified in an array of possible keys.\n * When the value of an attribute is of type 'Object' and this object has a method named `getAttributes`, the result of calling\n * this method is returned instead of the crude object.\n * @param {object} obj - The object to be processed\n * @param {string[]} [keys] - An optional array of keys to be included in the resulting object.\n * When null or not set, all keys of `obj` are included. Keys can include a default value separed by '|'.\n * Attributes with default value will be excluded from the resulting object.\n * @returns {object}\n */\nexport function getAttr(obj, keys = null) {\n let result = {};\n keys = keys || Object.keys(obj);\n keys.forEach(key => {\n const [k, d] = key.split('|');\n if (obj.hasOwnProperty(k) && typeof obj[k] !== 'undefined' && obj[k] !== null && obj[k].toString() !== d) {\n const v = getValue(obj[k]);\n if (!isEmpty(v))\n result[k] = v;\n }\n });\n\n // Convert to string objects with only a \"text\" attribute\n keys = Object.keys(result);\n if (keys.length === 1 && keys[0] === 'text')\n result = result.text;\n\n return result;\n};\n\n/**\n * Gets the minimal representation of the given value (object, array, string, number...)\n * @param {any} value - The value to be processed\n * @returns {any}\n */\nexport function getValue(value) {\n return value.getAttributes ?\n value.getAttributes() :\n value instanceof Array ?\n value.map(e => getValue(e)) :\n value instanceof Date ?\n value.toISOString() :\n value instanceof Object ?\n getAttr(value) :\n value;\n};\n\n/**\n * Checks if the given value is an empty object, null or a zero-length string\n * @param {any} v - The value to be checked\n * @returns {boolean} - `true` if `v` is `{}`, `null` or `\"\"`\n */\nexport function isEmpty(v) {\n let result = (typeof v === 'undefined' || v === null);\n if (!result) {\n switch (typeof v) {\n case 'object':\n result = Object.keys(v).length === 0;\n break;\n\n case 'string':\n result = v.length === 0;\n break;\n }\n }\n return result;\n};\n\n/**\n * Fills an object with specific attributes from another data object\n * @param {object} obj - The target object\n * @param {object} data - The data object\n * @param {string[]} attr - The list of attributes to be copied from `data` to `obj`\n * Elements of this list can be:\n * a) Just a string. In this case, the native object will be used as a value\n * b) An object with the following members:\n * - `key`{string} - The attribute name\n * - `fn` {function} - The function to be invoked to build the object\n * - `params` {string[]} - Optional params to be passed to the `setAttributes` method of the created object\n * - `group` {string} - Used when `data` is an object or an array (possible values are `object` and `array`), and multiple results\n * should be aggregated in a resulting object or array with the same keys (or ordering) as data.\n * - `init` {string} - Optional parameter indicating if `fn` should be passed with an additional param. This param can be:\n * - `key` - The member's key\n *\n * @returns {object} - Always returns `obj`\n */\nexport function setAttr(obj, data, attr) {\n attr.forEach(a => {\n if (a.key) {\n const { key, fn, group, init, params } = a;\n // A new object should be built\n if (!isEmpty(data[key])) {\n const dataset = data[key];\n if (group === 'object')\n obj[key] = Object.keys(dataset).reduce((o, k) => {\n o[k] = buildObj(fn, dataset[k], init === 'key' ? k : init, params);\n return o;\n }, {});\n else if (group === 'array')\n obj[key] = dataset.map((element, n) => buildObj(fn, element, init === 'key' ? n : init, params));\n else\n obj[key] = buildObj(fn, dataset, init, params);\n }\n } else if (!isEmpty(data[a]))\n obj[a] = data[a];\n });\n return obj;\n};\n\n/**\n * Builds a new object based on the provided constructor, data and initialization value\n * Objects used with this function should implement `setAttributes`, or an static method named `factory`\n * @param {function} objType - A class or function to be invoked to build the object.\n * @param {object} [data] - An optional object filled with the attributes to be assigned to the newly created object.\n * @param {any} [init] - An optional value to be passed to the function when invoked with `new`\n * @param {object[]} [params=[]] - Optional array of params to be passed when calling `setAttributes` on the final object\n * @returns {object} - The resulting object\n */\nexport function buildObj(objType, data, init, params = []) {\n return objType.factory ? objType.factory(data, init, params) : new objType(init).setAttributes(data, ...params);\n};\n\n/**\n * Check if the given char is a separator\n * @param {string} ch - A string with a single character\n * @returns {boolean}\n */\nexport function isSeparator(ch) {\n return settings.SEPARATORS.includes(ch);\n};\n\n/**\n * Check if the given char is a word delimiter\n * @param {string} ch - A string with a single character\n * @returns {boolean}\n */\nexport function isWordDelimiter(ch) {\n return settings.WORD_DELIMITERS.includes(ch);\n}\n\n/**\n * Converts a string in an array of objects with 'text' and 'sep' attributes, where 'text' are single words and 'sep'\n * are the word separators following each word in the sentence.\n * @example\n * stringToWords(\"Hello, World! That's all\") returns:\n * [\n * {text: \"Hello\", sep: \", \"},\n * {text: \"World\", sep: \"! \"},\n * {text: \"That\", sep: \"'\"},\n * {text: \"s\", sep: \" \"},\n * {text: \"all\", sep: \"\"},\n * ]\n * @param {*} str - The text to be tokenized\n * @returns {object[]}\n */\nexport function stringToWords(str) {\n const result = [];\n let token = { text: '', sep: '' };\n let inWord = true;\n for (let i = 0; i < str.length; i++) {\n const ch = str.charAt(i);\n const delim = isWordDelimiter(ch);\n if (inWord) {\n if (!delim)\n token.text += ch;\n else {\n inWord = false;\n token.sep = ch;\n }\n } else {\n if (delim)\n token.sep += ch;\n else {\n result.push(token);\n token = { text: ch, sep: '' };\n inWord = true;\n }\n }\n }\n result.push(token);\n return result;\n}\n\n/**\n * Rounds `v` to the nearest multiple of `n`\n * @param {number} v\n * @param {number} n - Cannot be zero!\n * @returns {number}\n */\nexport function roundTo(v, n) {\n return Math.round(v / n) * n;\n};\n\n/**\n * Set the maximum number of decimals for a number\n * @param {any} v - The value to be converted to a fixed number of decimals. Can be anything.\n * @param {number} n=4 - the maximum number of decimals\n * @returns {any} - When `v` is a number, a number with fixed decimals is returned. Otherwise, returns `v`\n */\nexport function fx(v, n = 4) {\n return v.toFixed ? Number(v.toFixed(n)) : v;\n};\n\n/**\n * Compares the provided answer against multiple valid options. These valid options are\n * concatenated in a string, separated by pipe chars (`|`). The comparing can be case sensitive.\n * @param {string} answer - The text to check against to\n * @param {string} check - String containing one or multiple options, separated by `|`\n * @param {boolean} [checkCase=false] - When true, the comparing will be case-sensitive\n * @param {boolean} [numeric=false] - When true, we are comparing numeric expressions\n * @returns {boolean}\n */\nexport function compareMultipleOptions(answer, check, checkCase = false, numeric = false) {\n if (answer === null || answer.length === 0 || check === null || check.length === 0)\n return false;\n if (!checkCase && !numeric)\n answer = answer.toUpperCase();\n answer = answer.trim();\n\n // Check for numeric digits in answer!\n numeric = numeric && /\\d/.test(answer);\n\n for (let token of check.split('|')) {\n if (numeric) {\n if (Number.parseFloat(answer.replace(/,/, '.')) === Number.parseFloat(token.replace(/,/, '.')))\n return true;\n }\n else if (answer === (checkCase ? token : token.toUpperCase()).trim())\n return true;\n }\n return false;\n};\n\n/**\n * Checks if the given string ends with the specified expression\n * @param {string} text - The string where to find the expression\n * @param {string} expr - The expression to search for.\n * @param {boolean} [trim] - When `true`, the `text` string will be trimmed before check\n * @returns {boolean}\n */\nexport function endsWith(text = '', expr, trim) {\n return typeof text === 'string' && (trim ? text.trim() : text).endsWith(expr);\n};\n\n/**\n * Checks if the given string starts with the specified expression\n * @param {string} text - The string where to find the expression\n * @param {string} expr - The expression to search for.\n * @param {boolean} [trim] - When `true`, the `text` string will be trimmed before check\n * @returns {boolean}\n */\nexport function startsWith(text = '', expr, trim) {\n return typeof text === 'string' && (trim ? text.trim() : text).indexOf(expr) === 0;\n};\n\n/**\n * Replaces all occurrences of the backslash character (`\\`) by a regular slash (`/`)\n * This is useful to normalize bad path names present in some old JClic projects\n * @param {string} str - The string to be normalized\n * @returns {string}\n */\nexport function nSlash(str) {\n return str ? str.replace(/\\\\/g, '/') : str;\n};\n\n/**\n * Checks if the given expression is an absolute URL\n * @param {string} exp - The expression to be checked\n * @returns {boolean}\n */\nexport function isURL(exp) {\n return /^(filesystem:)?(https?|file|data|ftps?):/i.test(exp);\n};\n\n/**\n * Gets the base path of the given file path (absolute or full URL). This base path always ends\n * with `/`, meaning it can be concatenated with relative paths without adding a separator.\n * @param {string} path - The full path to be parsed\n * @returns {string}\n */\nexport function getBasePath(path) {\n const p = path.lastIndexOf('/');\n return p >= 0 ? path.substring(0, p + 1) : '';\n};\n\n/**\n * Gets the full path of `file` relative to `basePath`\n * @param {string} file - The file name\n * @param {string} [path] - The base path\n * @returns {string}\n */\nexport function getRelativePath(file, path) {\n return (!path || path === '' || file.indexOf(path) !== 0) ? file : file.substring(path.length);\n};\n\n/**\n * Gets the complete path of a relative or absolute URL, using the provided `basePath`\n * @param {string} basePath - The base URL\n * @param {string} path - The filename\n * @returns {string}\n */\nexport function getPath(basePath, path) {\n return isURL(path) ? path : basePath + path;\n};\n\n/**\n * Gets a promise with the complete path of a relative or absolute URL, using the provided `basePath`\n * @param {string} basePath - The base URL\n * @param {string} path - The filename\n * @param {external:JSZip} [zip] - An optional {@link external:JSZip} object where to look\n * for the file\n * @returns {external:Promise}\n */\nexport function getPathPromise(basePath, path, zip) {\n if (zip) {\n const fName = getRelativePath(basePath + path, zip.zipBasePath);\n if (zip.files[fName]) {\n return new Promise((resolve, reject) => {\n zip.file(fName).async('base64').then(data => {\n const ext = path.toLowerCase().split('.').pop();\n const mime = settings.MIME_TYPES[ext] || 'application/octet-stream';\n resolve(`data:${mime};base64,${data}`);\n }).catch(reject);\n });\n }\n }\n return Promise.resolve(getPath(basePath, path));\n};\n\n/**\n * Utility object that provides several methods to build simple and complex DOM objects\n * @type {object}\n */\nexport const $HTML = {\n doubleCell: (a, b) => $('<tr/>').append($('<td/>').html(a)).append($('<td/>').html(b)),\n p: txt => $('<p/>').html(txt),\n td: (txt, className) => $('<td/>', className ? { class: className } : null).html(txt),\n th: (txt, className) => $('<th/>', className ? { class: className } : null).html(txt),\n};\n\n/**\n * Replaces `width`, `height` and `fill` attributes of a simple SVG image\n * with the provided values\n * @param {string} svg - The SVG image as XML string\n * @param {string} [width] - Optional setting for \"width\" property\n * @param {string} [height] - Optional setting for \"height\" property\n * @param {string} [fill] - Optional setting for \"fill\" property\n * @returns {string} - The resulting svg code\n */\nexport function getSvg(svg, width, height, fill) {\n if (width)\n svg = svg.replace(/width=\\\"\\d*\\\"/, `width=\"${width}\"`);\n if (height)\n svg = svg.replace(/height=\\\"\\d*\\\"/, `height=\"${height}\"`);\n if (fill)\n svg = svg.replace(/fill=\\\"[#A-Za-z0-9]*\\\"/, `fill=\"${fill}\"`);\n return svg;\n};\n\n/**\n * Encodes a svg expression into a {@link https://developer.mozilla.org/en-US/docs/Web/HTTP/data_URIs|data URI}\n * suitable for the `src` property of `img` elements, optionally changing its original size and fill values.\n * @param {string} svg - The SVG image as XML string\n * @param {string} [width] - Optional setting for \"width\" property\n * @param {string} [height] - Optional setting for \"height\" property\n * @param {string} [fill] - Optional setting for \"fill\" property\n * @returns {string} - The resulting Data URI\n */\nexport function svgToURI(svg, width, height, fill) {\n return 'data:image/svg+xml;base64,' + window.btoa(getSvg(svg, width, height, fill));\n};\n\n/**\n * Converts the given expression into a valid value for CSS size values\n * @param {string|number} exp - The expression to be evaluated. Can be a numeric value, `null` or `undefined`.\n * Positive values are in \"px\" units, negative ones are \"%\"\n * @param {object} css - An optional Object where the resulting expression (if any) will be saved\n * @param {string} key - The key under which the result will be stored in `css`\n * @param {string} def - Default value to be used when `exp` is `null` or `undefined`\n * @returns {string} - A valid CSS value, or `null` if it can't be found. Default units are `px`\n */\nexport function toCssSize(exp, css, key, def) {\n const result = typeof exp === 'undefined' || exp === null ? null : isNaN(exp) ? exp : exp < 0 ? `${Math.abs(exp)}%` : `${exp}px`;\n if (css && key && (result || def))\n css[key] = result !== null ? result : def;\n return result;\n};\n\n/**\n * Gets a clip of the give image data, in a URL base64 encoded format\n * @param {object} img - The binary data of the realized image, usually obtained from a {@link module:bads/MediaBagElement.MediaBagElement}\n * @param {module:AWT.Rectangle} rect - A rectangle containing the requested clip\n * @returns {string} - The URL with the image clip, as a PNG file encoded in base64\n */\nexport function getImgClipUrl(img, rect) {\n const canvas = document.createElement('canvas');\n canvas.width = rect.dim.width;\n canvas.height = rect.dim.height;\n const ctx = canvas.getContext('2d');\n let result = '';\n try {\n ctx.drawImage(img, rect.pos.x, rect.pos.y, rect.dim.width, rect.dim.height, 0, 0, rect.dim.width, rect.dim.height);\n result = canvas.toDataURL();\n } catch (err) {\n // catch 'tainted canvases may not be exported' and other errors\n log('error', err);\n }\n return result;\n};\n\n/**\n * Finds the nearest `head` or root node of a given HTMLElement, useful to place `<style/>` elements when\n * the main component of JClic is behind a shadow-root.\n * This method will be replaced by a call to [Node.getRootNode()](https://developer.mozilla.org/en-US/docs/Web/API/Node/getRootNode)\n * when fully supported by all major browsers.\n * @param {external:HTMLElement} [el] - The element from which to start the search\n * @returns {external:HTMLElement}\n */\nexport function getRootHead(el) {\n if (el) {\n // Skip HTMLElements\n while (el.parentElement)\n el = el.parentElement;\n // Get the parent node of the last HTMLElement\n if (el instanceof HTMLElement)\n el = el.parentNode || el;\n // If the root node has a `head`, take it\n el = el['head'] || el;\n }\n return el || document.head;\n};\n\n/**\n * Appends a stylesheet element to the `head` or root node nearest to the given `HTMLElement`.\n * @param {string} css - The content of the stylesheet\n * @param {module:JClicPlayer.JClicPlayer} [ps] - An optional `PlayStation` (currently a {@link module:JClicPlayer.JClicPlayer JClicPlayer}) used as a base to find the root node\n * @returns {external:HTMLStyleElement} - The appended style element\n */\nexport function appendStyleAtHead(css, ps) {\n const root = getRootHead(ps && ps.$topDiv ? ps.$topDiv[0] : null);\n const style = document.createElement('style');\n style.type = 'text/css';\n style.appendChild(document.createTextNode(css));\n return root.appendChild(style);\n};\n\n/**\n * Traverses all the attributes defined in an Element, calling a function with its name and value as a parameters\n * @param {external:NamedNodeMap} attributes - The [Element.attributes](https://developer.mozilla.org/en-US/docs/Web/API/Element/attributes)\n * object to be traversed\n * @param {function} callback - The function to be called for each [Attr](https://developer.mozilla.org/en-US/docs/Web/API/NamedNodeMap)\n * object. It should take two parametres: `name` and `value`\n */\nexport function attrForEach(attributes, callback) {\n for (let i = 0; i < attributes.length; i++)\n callback(attributes[i].name, attributes[i].value);\n};\n\n/**\n * Recursive traversal of all nodes of the given object looking for children having the `childName` attribute\n * WARNING: Don't call this method on objects with circular dependencies!\n * @param {object} obj - The object to be analized\n * @param {string} childName - Name of the attribute to search for\n * @returns {object[]} - Array of children having the searched attribute\n */\nexport function findParentsWithChild(obj, childName, _result = []) {\n if (obj[childName])\n _result.push(obj);\n else\n Object.values(obj).forEach(val => {\n if (typeof val === 'object')\n findParentsWithChild(val, childName, _result);\n });\n return _result;\n};\n\n//\n// Functions useful to deal with caret position in `contentEditable` DOM elements\n//\n/**\n * Gets the caret position within the given element. Thanks to\n * {@link http://stackoverflow.com/users/96100/tim-down|Tim Down} answers in:\n * {@link http://stackoverflow.com/questions/4811822/get-a-ranges-start-and-end-offsets-relative-to-its-parent-container}\n * and {@link http://stackoverflow.com/questions/6240139/highlight-text-range-using-javascript/6242538}\n * @param {object} element - A DOM element\n * @returns {number}\n */\nexport function getCaretCharacterOffsetWithin(element) {\n let caretOffset = 0;\n const doc = element.ownerDocument || element.document;\n const win = doc.defaultView || doc.parentWindow;\n let sel;\n if (typeof win.getSelection !== \"undefined\") {\n sel = win.getSelection();\n if (sel.rangeCount > 0) {\n const range = win.getSelection().getRangeAt(0);\n const preCaretRange = range.cloneRange();\n preCaretRange.selectNodeContents(element);\n preCaretRange.setEnd(range.endContainer, range.endOffset);\n caretOffset = preCaretRange.toString().length;\n }\n } else if ((sel = doc.selection) && sel.type !== \"Control\") {\n const textRange = sel.createRange();\n const preCaretTextRange = doc.body.createTextRange();\n preCaretTextRange.moveToElementText(element);\n preCaretTextRange.setEndPoint(\"EndToEnd\", textRange);\n caretOffset = preCaretTextRange.text.length;\n }\n return caretOffset;\n};\n\n/**\n * Utility function called by {@link module:Utils.getCaretCharacterOffsetWithin}\n * @param {object} node - A text node\n * @returns {object[]}\n */\nexport function getTextNodesIn(node) {\n const textNodes = [];\n if (node.nodeType === 3) {\n textNodes.push(node);\n } else {\n const children = node.childNodes;\n for (let i = 0, len = children.length; i < len; ++i) {\n textNodes.push.apply(textNodes, getTextNodesIn(children[i]));\n }\n }\n return textNodes;\n};\n\n/**\n * Sets the selection range (or the cursor position, when `start` and `end` are the same) to a\n * specific position inside a DOM element.\n * @param {object} el - The DOM element where to set the cursor\n * @param {number} start - The start position of the selection (or cursor position)\n * @param {number} end - The end position of the selection. When null or identical to `start`,\n * indicates a cursor position.\n */\nexport function setSelectionRange(el, start, end) {\n if (isNullOrUndef(end))\n end = start;\n if (document.createRange && window.getSelection) {\n const range = document.createRange();\n range.selectNodeContents(el);\n const textNodes = getTextNodesIn(el);\n let foundStart = false;\n let charCount = 0, endCharCount, textNode;\n\n for (let i = 0; i < textNodes.length; i++) {\n textNode = textNodes[i];\n endCharCount = charCount + textNode.length;\n if (!foundStart && start >= charCount &&\n (start < endCharCount ||\n start === endCharCount && i + 1 <= textNodes.length)) {\n range.setStart(textNode, start - charCount);\n foundStart = true;\n }\n if (foundStart && end <= endCharCount) {\n range.setEnd(textNode, end - charCount);\n break;\n }\n charCount = endCharCount;\n }\n const sel = window.getSelection();\n sel.removeAllRanges();\n sel.addRange(range);\n } else if (document.selection && document.body.createTextRange) {\n const textRange = document.body.createTextRange();\n textRange.moveToElementText(el);\n textRange.collapse(true);\n textRange.moveEnd('character', end);\n textRange.moveStart('character', start);\n textRange.select();\n }\n};\n\n/**\n * Performs multiple replacements on the provided string\n * See: https://stackoverflow.com/questions/2501435/replacing-multiple-patterns-in-a-block-of-data\n * @param {Object[]} replacements - Array of pairs formed by an \"expression\" (regexp or string) and a \"value\" (string) to replace the fragments found\n * @param {String} str - The string to be checked for replacements\n * @returns {String} - The original string with the fragments found already replaced\n */\nexport function mReplace(replacements, str) {\n return replacements.reduce((result, [exp, replacement]) => result.replace(exp, replacement), str);\n};\n\n/**\n * Global constants\n * @const\n */\nexport const settings = {\n // JClic.js Version\n VERSION: GlobalData.version,\n // Check if we are running on NodeJS with JSDOM\n NODEJS: typeof window === 'undefined' || window?.navigator?.userAgent?.includes('jsdom'),\n // layout constants\n AB: 0, BA: 1, AUB: 2, BUA: 3,\n LAYOUT_NAMES: ['AB', 'BA', 'AUB', 'BUA'],\n DEFAULT_WIDTH: 400,\n DEFAULT_HEIGHT: 300,\n MINIMUM_WIDTH: 40,\n MINIMUM_HEIGHT: 40,\n DEFAULT_NAME: '---',\n DEFAULT_MARGIN: 8,\n DEFAULT_SHUFFLES: 31,\n DEFAULT_GRID_ELEMENT_SIZE: 20,\n MIN_CELL_SIZE: 10,\n //DEFAULT_BG_COLOR: '#D3D3D3', // LightGray\n DEFAULT_BG_COLOR: '#C0C0C0', // LightGray\n ACTIONS: {\n ACTION_MATCH: 'MATCH', ACTION_PLACE: 'PLACE',\n ACTION_WRITE: 'WRITE', ACTION_SELECT: 'SELECT', ACTION_HELP: 'HELP'\n },\n PREVIOUS: 0, MAIN: 1, END: 2, END_ERROR: 3, NUM_MSG: 4,\n MSG_TYPE: ['previous', 'initial', 'final', 'finalError'],\n RANDOM_CHARS: \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\",\n NUM_COUNTERS: 3,\n MAX_RECORD_LENGTH: 180,\n // BoxBase defaults\n BoxBase: {\n REDUCE_FONT_STEP: 1.0,\n MIN_FONT_SIZE: 8,\n STROKE: 1,\n AC_MARGIN: 6,\n //BACK_COLOR: 'lightgray',\n BACK_COLOR: '#C0C0C0',\n TEXT_COLOR: 'black',\n SHADOW_COLOR: 'gray',\n INACTIVE_COLOR: 'gray',\n ALTERNATIVE_COLOR: 'gray',\n BORDER_COLOR: 'black',\n BORDER_STROKE_WIDTH: 0.75,\n MARKER_STROKE_WIDTH: 2.75\n },\n FILE_TYPES: {\n image: 'gif,jpg,png,jpeg,bmp,ico,svg',\n audio: 'wav,mp3,ogg,oga,au,aiff,flac',\n video: 'avi,mov,mpeg,mp4,ogv,m4v,webm',\n font: 'ttf,otf,eot,woff,woff2',\n midi: 'mid,midi',\n anim: 'swf',\n // Used in custom skins\n xml: 'xml'\n },\n MIME_TYPES: {\n xml: 'text/xml',\n gif: 'image/gif',\n jpg: 'image/jpeg',\n jpeg: 'image/jpeg',\n png: 'image/png',\n bmp: 'image/bmp',\n svg: 'image/svg+xml',\n ico: 'image/x-icon',\n wav: 'audio/wav',\n mp3: 'audio/mpeg',\n mp4: 'video/mp4',\n m4v: 'video/mp4',\n ogg: 'audio/ogg',\n oga: 'audio/ogg',\n ogv: 'video/ogg',\n webm: 'video/webm',\n au: 'audio/basic',\n aiff: 'audio/x-aiff',\n flac: 'audio/flac',\n avi: 'video/avi',\n mov: 'video/quicktime',\n mpeg: 'video/mpeg',\n ttf: 'application/font-sfnt',\n otf: 'application/font-sfnt',\n eot: ' application/vnd.ms-fontobject',\n woff: 'application/font-woff',\n woff2: 'application/font-woff2',\n swf: 'application/x-shockwave-flash',\n mid: 'audio/midi',\n midi: 'audio/midi'\n },\n // Global settings susceptible to be modified\n COMPRESS_IMAGES: true,\n // Keyboard key codes\n VK: {\n LEFT: 37,\n UP: 38,\n RIGHT: 39,\n DOWN: 40\n },\n // Flag to indicate that we are running on a touch device\n TOUCH_DEVICE: false,\n // Amount of time (in milliseconds) to wait before a media resource is loaded\n LOAD_TIMEOUT: 10000,\n // Number of points to be calculated as polygon vertexs when simplifying bezier curves\n BEZIER_POINTS: 4,\n // Check if canvas accessibility features are enabled\n // See: http://codepen.io/francesc/pen/amwvRp\n // UPDATED May 2020: Detection removed since Canvas HitRegions have been deprecated\n // See: https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Hit_regions_and_accessibility\n //\n // CANVAS_HITREGIONS: typeof CanvasRenderingContext2D !== 'undefined' && typeof CanvasRenderingContext2D.prototype.addHitRegion === 'function',\n // CANVAS_HITREGIONS_FOCUS: typeof CanvasRenderingContext2D !== 'undefined' && typeof CanvasRenderingContext2D.prototype.drawFocusIfNeeded === 'function',\n //\n CANVAS_DRAW_FOCUS: typeof window !== 'undefined' && typeof window?.CanvasRenderingContext2D?.prototype?.drawFocusIfNeeded === 'function',\n // See: https://emptycharacter.com/\n // See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Character_Classes\n WHITESPACES: ' \\f\\n\\r\\t\\v\\u00a0\\u1680\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200A\\u2028\\u2029\\u202f\\u205f\\u3000\\ufeff',\n};\nsettings.SEPARATORS = `${settings.WHITESPACES}.,;-|`;\nsettings.WORD_DELIMITERS = `${settings.SEPARATORS}…_<>\"“”«»'\\xB4\\x60\\u2018\\u2019\\u2022~+\\u2013\\u2014\\u2015=%¿?¡!:/\\\\()[]{}$£€`;\n\n/**\n * Miscellaneous utility functions and constants\n */\nexport const Utils = {\n pkg,\n settings,\n getMsg,\n LOG_LEVELS,\n LOG_PRINT_LABELS,\n LOG_OPTIONS,\n init,\n setLogLevel,\n log,\n getBoolean,\n getVal,\n getNumber,\n getPercent,\n zp,\n getHMStime,\n getDateTime,\n parseOldDate,\n cleanOldLanguageTag,\n FALSE,\n TRUE,\n DEFAULT,\n getTriState,\n fillString,\n isNullOrUndef,\n isEquivalent,\n getXmlText,\n parseXmlNode,\n getXmlNodeText,\n reduceTextsToStrings,\n cssToString,\n checkColor,\n colorHasTransparency,\n cloneObject,\n normalizeObject,\n getAttr,\n getValue,\n isEmpty,\n setAttr,\n buildObj,\n isSeparator,\n isWordDelimiter,\n stringToWords,\n roundTo,\n fx,\n compareMultipleOptions,\n endsWith,\n startsWith,\n nSlash,\n isURL,\n getBasePath,\n getRelativePath,\n getPath,\n getPathPromise,\n $HTML,\n getSvg,\n svgToURI,\n toCssSize,\n getImgClipUrl,\n getRootHead,\n appendStyleAtHead,\n attrForEach,\n findParentsWithChild,\n getCaretCharacterOffsetWithin,\n getTextNodesIn,\n setSelectionRange\n};\n\nexport default Utils;\n","const __WEBPACK_NAMESPACE_OBJECT__ = require(\"webfontloader\");","/**\n * File : AWT.js\n * Created : 12/04/2015\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\n/* global console, window */\n\nimport $ from 'jquery';\nimport { settings, findParentsWithChild, getBoolean, getAttr, setAttr, checkColor, colorHasTransparency, fx } from './Utils.js';\nimport WebFont from 'webfontloader';\n\n/**\n * Font contains properties and provides methods to manage fonts\n */\nexport class Font {\n /**\n * Font constructor\n * @param {string} [family='Arial']\n * @param {number} [size=17]\n * @param {number} [bold=0]\n * @param {number} [italic=0]\n * @param {string} [variant='']\n */\n constructor(family, size, bold, italic, variant) {\n if (family)\n this.family = family;\n if (typeof size === 'number')\n this.size = size;\n if (bold)\n this.bold = bold;\n if (italic)\n this.italic = italic;\n if (variant)\n this.variant = variant;\n this._metrics = { ascent: -1, descent: -1, height: -1 };\n }\n\n /**\n * Finds the XML elements with typeface specifications, checks its value against the font\n * substitution list, replacing the `family` attribute and loading the alternative font when needed.\n * @param {external:jQuery} $tree - The xml element to be processed\n * @param {object} [options] - Optional param that can contain a `fontSubstitutions` attribute with\n * a substition table to be added to {@link module:AWT.Font.SUBSTITUTIONS SUBSTITUTIONS}\n */\n static checkTree($tree, options) {\n let substitutions = Font.SUBSTITUTIONS;\n // Load own fonts and remove it from the substitution table\n if (options && options.ownFonts) {\n options.ownFonts.forEach(name => {\n // Check WebFont as a workaround to avoid problems with a different version of `webfontloader` in agora.xtec.cat\n if (Font.ALREADY_LOADED_FONTS.indexOf(name) < 0 && WebFont && WebFont.load) {\n WebFont.load({ custom: { families: [name] } });\n Font.ALREADY_LOADED_FONTS.push(name);\n delete substitutions[name.trim().toLowerCase()];\n }\n });\n }\n\n // Add custom font substitutions\n if (options && options.fontSubstitutions)\n //substitutions = Object.assign({}, substitutions, options.fontSubstitutions)\n substitutions = $.extend(Object.create(substitutions), options.fontSubstitutions);\n\n if ($tree.jquery)\n $tree.find('style[family],font[family]').each((_n, style) => {\n const $style = $(style),\n name = $style.attr('family').trim().toLowerCase();\n if (name in substitutions) {\n const newName = substitutions[name];\n if (newName !== '') {\n Font.loadGoogleFont(newName);\n $style.attr('family', newName);\n }\n }\n });\n else {\n findParentsWithChild($tree, 'family').forEach(parent => {\n if (typeof parent.family === 'string') {\n const name = parent.family;\n if (Font.GOOGLEFONTS.includes(name))\n Font.loadGoogleFont(name);\n else {\n const newName = substitutions[name.trim().toLowerCase()];\n if (newName) {\n Font.loadGoogleFont(newName);\n parent.family = newName;\n }\n }\n }\n });\n }\n }\n\n /**\n * Try to load a specific font from [http://www.google.com/fonts]\n * @param {string} name - The font family name\n */\n // Check WebFont as a workaround to avoid problems with a different version of `webfontloader` in agora.xtec.cat\n static loadGoogleFont(name) {\n if (name && !Font.ALREADY_LOADED_FONTS.includes(name) && WebFont && WebFont.load) {\n WebFont.load({ google: { families: [name] } });\n Font.ALREADY_LOADED_FONTS.push(name);\n }\n }\n\n /**\n * Try to load a set of Google fonts\n * @param {string[]} fonts - An array of font names\n */\n static loadGoogleFonts(fonts) {\n if (fonts && fonts.forEach)\n fonts.forEach(name => Font.loadGoogleFont(name));\n }\n\n /**\n * Reads the properties of this Font from an XML element\n * @param {external:jQuery} $xml - The xml element to be parsed\n * @returns {module:AWT.Font}\n */\n setProperties($xml) {\n if ($xml.attr('family'))\n this.family = $xml.attr('family');\n if ($xml.attr('size'))\n this.size = Number($xml.attr('size'));\n if ($xml.attr('bold'))\n this.bold = getBoolean($xml.attr('bold'));\n if ($xml.attr('italic'))\n this.italic = getBoolean($xml.attr('italic'));\n if ($xml.attr('variant'))\n this.variant = $xml.attr('variant');\n return this;\n }\n\n /**\n * Gets a object with the basic attributes needed to rebuild this instance excluding functions,\n * parent references, constants and also attributes retaining the default value.\n * The resulting object is commonly usued to serialize elements in JSON format.\n * @returns {object} - The resulting object, with minimal attrributes\n */\n getAttributes() {\n return getAttr(this, ['family|Arial', 'size|17', 'bold|0', 'italic|0', 'variant']);\n }\n\n /**\n * Reads the properties of this Font from a data object\n * @param {object} data - The data object to be parsed\n * @returns {module:AWT.Font}\n */\n setAttributes(data) {\n return setAttr(this, data, ['family', 'size', 'bold', 'italic', 'variant']);\n }\n\n /**\n * Allows to change the `size` member, recalculating the vertical metrics.\n * @param {number} size - The new size to set\n * @returns {module:AWT.Font}\n */\n setSize(size) {\n const currentSize = this.size;\n this.size = size;\n if (currentSize !== size)\n this._metrics.height = -1;\n return this;\n }\n\n /**\n * Increases or decreases the current font size by the specified amount\n * @param {number} amount - The amount to increase or decrease current size\n * @returns {module:AWT.Font}\n */\n zoom(amount) {\n return this.setSize(this.size + amount);\n }\n\n /**\n * Calculates the font metrics\n * @returns {Object} - The font metrics\n */\n getMetrics() {\n if (this._metrics.height < 0) {\n // Look for an equivalent font already calculated\n const font = Font.ALREADY_CALCULATED_FONTS.find(font => font.equals(this));\n if (font)\n Object.assign(this._metrics, font._metrics);\n\n if (this._metrics.height < 0) {\n this._calcHeight();\n if (this._metrics.height > 0)\n Font.ALREADY_CALCULATED_FONTS.push(this);\n }\n }\n return this._metrics;\n }\n\n /**\n * Calculates the font metrics and returns its height\n * @returns {number} - The font height\n */\n getHeight() {\n return this.getMetrics().height;\n }\n\n /**\n * Translates the Font properties into CSS statements\n * @param {object} css - The object where to add CSS properties. When null or undefined, a new\n * object will be created and returned.\n * @returns {object} - A set of CSS property-values pairs, ready to be used by JQuery\n * [.css(properties)](http://api.jquery.com/css/#css-properties).\n */\n toCss(css) {\n if (!css)\n css = {};\n css['font-family'] = this.family;\n css['font-size'] = `${this.size}px`;\n if (this.hasOwnProperty('bold'))\n css['font-weight'] = this.bold ? 'bold' : 'normal';\n if (this.hasOwnProperty('italic'))\n css['font-style'] = this.italic ? 'italic' : 'normal';\n if (this.hasOwnProperty('variant'))\n css['font-variant'] = this.variant;\n return css;\n }\n\n /**\n * Gets the codification of this font in a single string, suitable to be used in a `font`\n * CSS attribute.\n * @returns {string} - A string with all the CSS font properties concatenated\n */\n cssFont() {\n return `${this.italic ? 'italic ' : 'normal'} ${this.variant === '' ? 'normal' : this.variant} ${this.bold ? 'bold ' : 'normal'} ${this.size}px ${this.family}`;\n }\n\n /**\n * The {@link https://developer.mozilla.org/en-US/docs/Web/API/TextMetrics TextMetrics} object used\n * by {@link https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D CanvasRenderingContext2D}\n * does not provide a `heigth` value for rendered text.\n * This {@link http://stackoverflow.com/questions/1134586/how-can-you-find-the-height-of-text-on-an-html-canvas stackoverflow question}\n * has an excellent response by Daniel Earwicker explaining how to measure the\n * vertical dimension of rendered text using a `span` element.\n * The code has been slighty adapted to deal with Font objects.\n *\n * _Warning_: Do not call this method direcly. Use {@link module:AWT.Font#getHeight getHeight()} or {@link module:AWT.Font#getMetrics getMetrics()} instead\n *\n * @returns {module:AWT.Font}\n */\n _calcHeight() {\n const\n $text = $('<span/>').html('Hg').css(this.toCss()),\n $block = $('<div/>').css({ display: 'inline-block', width: '1px', height: '0px' }),\n $div = $('<div/>').append($text, $block);\n\n $('body').append($div);\n try {\n $block.css({ verticalAlign: 'baseline' });\n this._metrics.ascent = $block.offset().top - $text.offset().top;\n $block.css({ verticalAlign: 'bottom' });\n this._metrics.height = $block.offset().top - $text.offset().top;\n this._metrics.descent = this._metrics.height - this._metrics.ascent;\n } finally {\n $div.remove();\n }\n return this;\n }\n\n /**\n * Checks if two Font objects are equivalent\n * @param {module:AWT.Font} font - The Font object to compare against this one\n * @returns {boolean} - `true` if both objects are equivalent, `false` otherwise\n */\n equals(font) {\n return this.family === font.family &&\n this.size === font.size &&\n this.bold === font.bold &&\n this.italic === font.italic &&\n this.variant === font.variant;\n }\n}\n\n\n/**\n * Array of font objects with already calculated heights */\nFont.ALREADY_CALCULATED_FONTS = [];\n\n/**\n * Array of font names already loaded from Google Fonts, or generic names provided by browsers by default\n * See: https://developer.mozilla.org/en-US/docs/Web/CSS/font-family */\nFont.ALREADY_LOADED_FONTS = ['serif', 'sans-serif', 'monospace', 'cursive', 'fantasy'];\n\n/**\n * Google Fonts equivalent for special fonts used in some JClic projects.\n * More substitutions can be added to the list for specific projects indicating a\n * `fontSubstitutions` object in the `data-options` attribute of the HTML `div` element\n * containing the player.\n * For example:\n * `<div class =\"JClic\" data-project=\"demo.jclic\" data-options='{\"fontSubstitutions\":{\"arial\":\"Arimo\"}}'/>`\n */\nFont.SUBSTITUTIONS = {\n // Lowercase versions of JDK Logical Fonts (see: https://docs.oracle.com/javase/tutorial/2d/text/fonts.html)\n 'dialog': 'sans-serif',\n 'dialoginput': 'sans-serif',\n 'monospaced': 'monospace',\n //'serif': 'serif',\n 'sansserif': 'sans-serif',\n // Other fonts commonly used in JClic activities, mapped to similar Google Fonts\n 'abc': 'Kalam',\n 'a.c.m.e. secret agent': 'Permanent Marker',\n 'comic sans ms': 'Patrick Hand',\n 'impact': 'Oswald',\n 'massallera': 'Vibur',\n 'memima': 'Vibur',\n 'memima_n1': 'Vibur',\n 'memima_n2': 'Vibur',\n 'memimas-regularalternate': 'Vibur',\n 'palmemim': 'Vibur',\n 'zurichcalligraphic': 'Felipa'\n};\n/**\n * Google Fonts currently used in substitutions\n */\nFont.GOOGLEFONTS = [\n 'Kalam', 'Permanent Marker', 'Patrick Hand', 'Oswald', 'Vibur', 'Felipa',\n];\n\nObject.assign(Font.prototype, {\n /**\n * The `font-family` property\n * @name module:AWT.Font#family\n * @type {string} */\n family: 'Arial',\n /**\n * The font size\n * __Warning__: Do not change `size` directly. Use {@link module:AWT.Font#setSize setSize()} instead.\n * @name module:AWT.Font#size\n * @type {number} */\n size: 17,\n /**\n * The font _bold_ value\n * @name module:AWT.Font#bold\n * @type {number} */\n bold: 0,\n /**\n * The font _italic_ value\n * @name module:AWT.Font#italic\n * @type {number} */\n italic: 0,\n /**\n * The font _variant_ value\n * @name module:AWT.Font#variant\n * @type {string}*/\n variant: '',\n /**\n * The font *_metrics* property contains the values for `ascent`, `descent` and `height`\n * attributes. Vertical font metrics are calculated in\n * {@link module:AWT.Font#_calcHeight|_calcHeight()} as needed.\n * @name module:AWT.Font#_metrics\n * @private\n * @type {{ascent: number, descent: number, height: number}} */\n _metrics: { ascent: -1, descent: -1, height: -1 },\n});\n\n/**\n * Contains parameters and methods to draw complex color gradients\n */\nexport class Gradient {\n /**\n * Gradient constructor\n * @param {string} c1 - The initial color, in any CSS-valid form.\n * @param {string} c2 - The final color, in any CSS-valid form.\n * @param {number} [angle=0] - The inclination of the gradient relative to the horizontal line.\n * @param {number} [cycles=1] - The number of times the gradient will be repeated.\n */\n constructor(c1, c2, angle, cycles) {\n if (c1)\n this.c1 = c1;\n if (c2)\n this.c2 = c2;\n if (typeof angle === 'number')\n this.angle = angle % 360;\n if (typeof cycles === 'number')\n this.cycles = cycles;\n }\n\n /**\n * Reads the properties of this Gradient from an XML element\n * @param {external:jQuery} $xml - The xml element to be parsed\n * @returns {module:AWT.Gradient}\n */\n setProperties($xml) {\n this.c1 = checkColor($xml.attr('source'), 'black');\n this.c2 = checkColor($xml.attr('dest'), 'white');\n this.angle = Number($xml.attr('angle') || 0) % 360;\n this.cycles = Number($xml.attr('cycles') || 1);\n return this;\n }\n\n /**\n * Gets a object with the basic attributes needed to rebuild this instance excluding functions,\n * parent references, constants and also attributes retaining the default value.\n * The resulting object is commonly usued to serialize elements in JSON format.\n * @returns {object} - The resulting object, with minimal attrributes\n */\n getAttributes() {\n return getAttr(this, [\n 'c1', 'c2', 'angle|0', 'cycles|1'\n ]);\n }\n\n /**\n * Reads the properties of this Gradient from a data object\n * @param {object} data - The data object to be parsed\n * @returns {module:AWT.Gradient}\n */\n setAttributes(data) {\n return setAttr(this, data, ['c1', 'c2', 'angle', 'cycles']);\n }\n\n /**\n * Creates a {@link https://developer.mozilla.org/en-US/docs/Web/API/CanvasGradient|CanvasGradient}\n * based on the provided context and rectangle.\n * @param {external:CanvasRenderingContext2D} ctx - The 2D rendering context\n * @param {module:AWT.Rectangle} rect - The rectangle where this gradient will be applied to\n * @returns {module:AWT.Gradient}\n */\n getGradient(ctx, rect) {\n const\n p2 = rect.getOppositeVertex(),\n gradient = ctx.createLinearGradient(rect.pos.x, rect.pos.y, p2.x, p2.y),\n step = 1 / Math.max(this.cycles, 1);\n for (let i = 0; i <= this.cycles; i++)\n gradient.addColorStop(i * step, i % 2 ? this.c1 : this.c2);\n return gradient;\n }\n\n /**\n * Gets the CSS 'linear-gradient' expression of this Gradient\n * @returns {string} - A string ready to be used as a value for the `linear-gradient` CSS attribute\n */\n getCss() {\n let result = `linear-gradient(${(this.angle + 90)}deg, ${this.c1}, ${this.c2}`;\n for (let i = 1; i < this.cycles; i++)\n result = `${result}, ${i % 2 > 0 ? this.c1 : this.c2}`;\n return `${result})`;\n }\n\n /**\n * Checks if any of the gradient colors has transparency\n * @returns {boolean} - `true` if this gradient uses colors with transparency, `false` otherwise.\n */\n hasTransparency() {\n return colorHasTransparency(this.c1) || colorHasTransparency(this.c2);\n }\n}\n\nObject.assign(Gradient.prototype, {\n /**\n * Initial color\n * @name module:AWT.Gradient#c1\n * @type {string} */\n c1: 'white',\n /**\n * Final color\n * @name module:AWT.Gradient#c2\n * @type {string} */\n c2: 'black',\n /**\n * Tilt angle\n * @name module:AWT.Gradient#angle\n * @type {number} */\n angle: 0,\n /**\n * Number of repetitions of the gradient\n * @name module:AWT.Gradient#cycles\n * @type {number} */\n cycles: 1,\n});\n\n/**\n * Contains properties used to draw lines in HTML `canvas` elements.\n * @see {@link http://bucephalus.org/text/CanvasHandbook/CanvasHandbook.html#line-caps-and-joins}\n */\nexport class Stroke {\n /**\n * Stroke constructor\n * @param {number} [lineWidth=1] - The line width of the stroke\n * @param {string} [lineCap='butt'] - The line ending type. Possible values are: `butt`, `round`\n * and `square`.\n * @param {string} [lineJoin='miter'] - The type of drawing used when two lines join. Possible\n * values are: `round`, `bevel` and `miter`.\n * @param {number} [miterLimit=10] - The ratio between the miter length and half `lineWidth`.\n */\n constructor(lineWidth, lineCap, lineJoin, miterLimit) {\n if (typeof lineWidth === 'number')\n this.lineWidth = lineWidth;\n if (lineCap)\n this.lineCap = lineCap;\n if (lineJoin)\n this.lineJoin = lineJoin;\n if (typeof miterLimit === 'number')\n this.miterLimit = miterLimit;\n }\n\n /**\n * Gets a object with the basic attributes needed to rebuild this instance excluding functions,\n * parent references, constants and also attributes retaining the default value.\n * The resulting object is commonly usued to serialize elements in JSON format.\n * @returns {object} - The resulting object, with minimal attrributes\n */\n getAttributes() {\n return getAttr(this, [\n 'lineWidth|1', 'lineCap|butt', 'lineJoin|miter', 'miterLimit|10',\n ]);\n }\n\n /**\n * Reads the properties of this Stroke from a data object\n * @param {object} data - The data object to be parsed\n * @returns {module:AWT.Stroke}\n */\n setAttributes(data) {\n return setAttr(this, data, ['lineWidth', 'lineCap', 'lineJoin', 'miterLimit']);\n }\n\n /**\n * Sets the properties of this stroke to a CanvasRenderingContext2D\n * @param {external:CanvasRenderingContext2D} ctx - The canvas 2D rendering context\n * @returns {external:CanvasRenderingContext2D}\n */\n setStroke(ctx) {\n ctx.lineWidth = this.lineWidth;\n ctx.lineCap = this.lineCap;\n ctx.lineJoin = this.lineJoin;\n ctx.miterLimit = this.miterLimit;\n return ctx;\n }\n}\n\nObject.assign(Stroke.prototype, {\n /**\n * The line width\n * @name module:AWT.Stroke#lineWidth\n * @type {number} */\n lineWidth: 1.0,\n /**\n * The line ending type (`butt`, `round` or `square`)\n * @name module:AWT.Stroke#lineCap\n * @type {string} */\n lineCap: 'butt',\n /**\n * The drawing used when two lines join (`round`, `bevel` or `miter`)\n * @name module:AWT.Stroke#lineJoin\n * @type {string} */\n lineJoin: 'miter',\n /**\n * Ratio between the miter length and half `lineWidth`\n * @name module:AWT.Stroke#miterLimit\n * @type {number} */\n miterLimit: 10.0,\n});\n\n/**\n * Contains the `x` andy `y` coordinates of a point, and provides some useful methods.\n */\nexport class Point {\n /**\n * Point constructor\n * @param {number|Point} x - When `x` is an `Point` object, a clone of it will be created.\n * @param {number} [y] - Not used when `x` is an `Point`\n */\n constructor(x, y) {\n if (x instanceof Point) {\n // Special case: constructor passing another point as unique parameter\n this.x = x.x;\n this.y = x.y;\n } else {\n this.x = x || 0;\n this.y = y || 0;\n }\n }\n\n /**\n * Reads the properties of this Point from an XML element\n * @param {external:jQuery} $xml - The xml element to be parsed\n * @returns {module:AWT.Point}\n */\n setProperties($xml) {\n this.x = Number($xml.attr('x'));\n this.y = Number($xml.attr('y'));\n return this;\n }\n\n /**\n * Gets a object with the basic attributes needed to rebuild this instance excluding functions,\n * parent references, constants and also attributes retaining the default value.\n * The resulting object is commonly usued to serialize elements in JSON format.\n * @returns {object} - The resulting object, with minimal attrributes\n */\n getAttributes() {\n return getAttr(this, ['x', 'y']);\n }\n\n /**\n * Reads the properties of this Point from a data object\n * @param {object} data - The data object to be parsed\n * @returns {module:AWT.Point}\n */\n setAttributes(data) {\n return setAttr(this, data, ['x', 'y']);\n }\n\n /**\n * Moves this Point to a new position, by a specified displacement\n * @param {Point|Dimension} delta - The amount to move\n * @returns {module:AWT.Point}\n */\n moveBy(delta) {\n this.x += delta.x || delta.width || 0;\n this.y += delta.y || delta.height || 0;\n return this;\n }\n\n /**\n * Moves this Point to a new position\n * @param {number|Point} newPos - The new position, or a x coordinate\n * @param {number} [y] - `null` or `undefined` when `newPos` is a Point\n * @returns {module:AWT.Point}\n */\n moveTo(newPos, y) {\n if (typeof newPos === 'number') {\n this.x = newPos;\n this.y = y;\n } else {\n this.x = newPos.x;\n this.y = newPos.y;\n }\n return this;\n }\n\n /**\n * Multiplies the `x` and `y` coordinates by a specified `delta`\n * @param {Point|Dimension} delta - The amount to multiply by.\n * @returns {module:AWT.Point}\n */\n multBy(delta) {\n this.x *= delta.x || delta.width || 0;\n this.y *= delta.y || delta.height || 0;\n return this;\n }\n\n /**\n * Checks if two points are at the same place\n * @param {module:AWT.Point} p - The Point to check against to\n * @returns {boolean}\n */\n equals(p) {\n return this.x === p.x && this.y === p.y;\n }\n\n /**\n * Calculates the distance between two points\n * @param {module:AWT.Point} point - The Point to calculate the distance against to\n * @returns {number} - The distance between the two points.\n */\n distanceTo(point) {\n return Math.sqrt(Math.pow(this.x - point.x, 2), Math.pow(this.y - point.y, 2));\n }\n\n /**\n * Clones this point\n * @returns {module:AWT.Point}\n */\n clone() {\n return new Point(this);\n }\n}\n\nObject.assign(Point.prototype, {\n /**\n * @name module:AWT.Point#x\n * @type {number} */\n x: 0,\n /**\n * @name module:AWT.Point#y\n * @type {number} */\n y: 0,\n});\n\n/**\n * This class encapsulates `width` and `height` properties.\n */\nexport class Dimension {\n /**\n * Dimension constructor\n * @param {number|Point} w - The width of this Dimension, or the upper-left vertex of a\n * virtual Rectangle\n * @param {number|Point} h - The height of this Dimension, or the bottom-right vertex of a\n * virtual Rectangle\n */\n constructor(w, h) {\n if (w instanceof Point && h instanceof Point) {\n this.width = h.x - w.x;\n this.height = h.y - w.y;\n } else {\n this.width = w || 0;\n this.height = h || 0;\n }\n }\n\n /**\n * Reads the properties of this Dimension from an XML element\n * @param {external:jQuery} $xml - The xml element to be parsed\n * @returns {module:AWT.Dimension}\n */\n setProperties($xml) {\n this.width = Number($xml.attr('width'));\n this.height = Number($xml.attr('height'));\n return this;\n }\n\n /**\n * Gets a object with the basic attributes needed to rebuild this instance excluding functions,\n * parent references, constants and also attributes retaining the default value.\n * The resulting object is commonly usued to serialize elements in JSON format.\n * @returns {object} - The resulting object, with minimal attrributes\n */\n getAttributes() {\n return getAttr(this, ['width', 'height']);\n }\n\n /**\n * Reads the properties of this Dimension from a data object\n * @param {object} data - The data object to be parsed\n * @returns {module:AWT.Dimension}\n */\n setAttributes(data) {\n return setAttr(this, data, ['width', 'height']);\n }\n\n /**\n * Check if two dimensions are equivalent\n * @param {module:AWT.Dimension} d\n * @returns {boolean}\n */\n equals(d) {\n return this.width === d.width && this.height === d.height;\n }\n\n /**\n * Multiplies the `w` and `h` co-ordinates by a specified `delta`\n * @param {Point|Dimension} delta\n * @returns {module:AWT.Dimension}\n */\n multBy(delta) {\n this.width *= delta.x || delta.width || 0;\n this.height *= delta.y || delta.height || 0;\n return this;\n }\n\n /**\n * Sets new values for width and height.\n * `width` can be a number or another `Dimension` object\n * @param {number|Dimension} width - The new width, or a full Dimension to copy it from.\n * @param {number} [height] - Not used when `width` is a Dimension\n * @returns {module:AWT.Dimension}\n */\n setDimension(width, height) {\n if (width instanceof Dimension) {\n height = width.height;\n width = width.width;\n }\n this.width = width;\n this.height = height;\n return this;\n }\n\n /**\n * Calculates the area of a Rectangle with this dimension\n * @returns {number} The resulting area\n */\n getSurface() {\n return this.width * this.height;\n }\n}\n\nObject.assign(Dimension.prototype, {\n /**\n * @name module:AWT.Dimension#width\n * @type {number} */\n width: 0,\n /**\n * @name module:AWT.Dimension#height\n * @type {number} */\n height: 0,\n});\n\n/**\n * Shape is a generic abstract class for rectangles, ellipses and stroke-free shapes.\n * @abstract\n */\nexport class Shape {\n /**\n * Shape constructor\n * @param {module:AWT.Point} pos - The top-left coordinates of this Shape\n */\n constructor(pos) {\n this.pos = pos || new Point();\n }\n\n /**\n * Shifts the shape a specified amount in horizontal and vertical directions\n * @param {Point|Dimension} delta - The amount to shift the Shape\n * @returns {module:AWT.Shape}\n */\n moveBy(delta) {\n this.pos.moveBy(delta);\n return this;\n }\n\n /**\n * Moves this shape to a new position\n * @param {module:AWT.Point} newPos - The new position of the shape\n * @returns {module:AWT.Shape}\n */\n moveTo(newPos) {\n this.pos.moveTo(newPos);\n return this;\n }\n\n /**\n * Gets the enclosing {@link module:AWT.Rectangle Rectangle} of this Shape.\n * @returns {module:AWT.Rectangle}\n */\n getBounds() {\n return new Rectangle(this.pos);\n }\n\n /**\n * Checks if two shapes are equivalent.\n * @param {module:AWT.Shape} p - The Shape to compare against\n * @returns {boolean}\n */\n equals(p) {\n return this.pos.equals(p.pos);\n }\n\n /**\n * Multiplies the dimension of the Shape by the specified `delta` amount.\n * @param {Point|Dimension} _delta - Object containing the X and Y ratio to be scaled.\n * @returns {module:AWT.Shape}\n */\n scaleBy(_delta) {\n // Nothing to scale in abstract shapes\n return this;\n }\n\n /**\n * Gets a clone of this shape moved to the `pos` component of the rectangle and scaled\n * by its `dim` value.\n * @param {module:AWT.Rectangle} rect - The rectangle to be taken as a base for moving and scaling\n * this shape.\n * @returns {module:AWT.Shape}\n */\n getShape(rect) {\n return this.clone().scaleBy(rect.dim).moveBy(rect.pos);\n }\n\n /**\n * Checks if the provided {@link module:AWT.Point} is inside this shape.\n * @param {module:AWT.Point} _p - The point to check\n * @returns {boolean}\n */\n contains(_p) {\n // Nothing to check in abstract shapes\n return false;\n }\n\n /**\n * Checks if the provided {@link module:AWT.Rectangle Rectangle} `r` intersects with this shape.\n * @param {module:AWT.Rectangle} _r\n * @returns {boolean}\n */\n intersects(_r) {\n // Nothing to check in abstract shapes\n return false;\n }\n\n /**\n * Fills the Shape with the current style in the provided HTML canvas context\n * @param {external:CanvasRenderingContext2D} ctx - The canvas 2D rendering context where to fill this shape.\n * @param {module:AWT.Rectangle} [dirtyRegion] - The context region to be updated. Used as clipping\n * region when drawing.\n * @returns {external:CanvasRenderingContext2D} - The provided rendering context\n */\n fill(ctx, dirtyRegion) {\n ctx.save();\n if (dirtyRegion && dirtyRegion.getSurface() > 0) {\n // Clip the dirty region\n ctx.beginPath();\n ctx.rect(dirtyRegion.pos.x, dirtyRegion.pos.y, dirtyRegion.dim.width, dirtyRegion.dim.height);\n ctx.clip();\n }\n // Prepare shape path and fill\n this.preparePath(ctx);\n ctx.fill();\n ctx.restore();\n return ctx;\n }\n\n /**\n * Draws this shape in the provided HTML canvas 2D rendering context.\n * @param {external:CanvasRenderingContext2D} ctx - The canvas 2D rendering context where to draw the shape.\n * @returns {external:CanvasRenderingContext2D} - The provided rendering context\n */\n stroke(ctx) {\n this.preparePath(ctx);\n ctx.stroke();\n return ctx;\n }\n\n /**\n * Prepares an HTML canvas 2D rendering context with a path that can be used to stroke a line,\n * to fill a surface or to define a clipping region.\n * @param {external:CanvasRenderingContext2D} ctx\n * @returns {external:CanvasRenderingContext2D} - The provided rendering context\n */\n preparePath(ctx) {\n // Nothing to do in abstract shapes\n return ctx;\n }\n\n /**\n * Creates a clipping region on the specified HTML canvas 2D rendering context\n * @param {external:CanvasRenderingContext2D} ctx - The rendering context\n * @param {string} [fillRule='nonzero'] - Can be 'nonzero' (default when not set) or 'evenodd'\n * @returns {external:CanvasRenderingContext2D} - The provided rendering context\n */\n clip(ctx, fillRule) {\n this.preparePath(ctx);\n ctx.clip(fillRule || 'nonzero');\n return ctx;\n }\n\n /**\n * Shorthand method for determining if a Shape is an {@link module:AWT.Rectangle Rectangle}\n * @returns {boolean}\n */\n isRect() {\n return false;\n }\n\n /**\n * Overwrites the original 'Object.toString' method with a more descriptive text\n * @returns {string}\n */\n toString() {\n return `Shape enclosed in ${this.getBounds().getCoords()}`;\n }\n\n /**\n * Reads the properties of this Shape from a data object\n * @param {object} data - The data object to be parsed\n * @returns {module:AWT.Shape}\n */\n setAttributes(data) {\n return Shape.buildShape(data);\n /*\n return setAttr(this, data, [\n 'type',\n { key: 'pos', fn: Point },\n ]);\n */\n }\n\n /**\n * Builds a shape based on the provided `data` object.\n * Data should contain a 'type' member, specifying the type of shape requested ('rect', 'ellipse', 'rectangle' or 'path')\n * @param {object} data - Specific data for this shape\n * @returns {module:AWT.Shape}\n */\n static buildShape(data) {\n const shapeType = (data.type === 'rect' && Rectangle) || (data.type === 'ellipse' && Ellipse) || (data.type === 'path' && Path) || null;\n if (!shapeType) {\n console.log('unknown shape:', data);\n } else\n return (new shapeType()).setAttributes(data);\n }\n}\n\nObject.assign(Shape.prototype, {\n /**\n * Shape type id\n * @name module:AWT.Shape#type\n * @type {string} */\n type: 'shape',\n /**\n * The current position of the shape\n * @name module:AWT.Shape#pos\n * @type {module:AWT.Point} */\n pos: new Point(),\n /**\n * The type of shape (Rectangle, ellipse, path...)\n * @name module:AWT.Shape#type\n * @type {string} */\n type: 'shape',\n});\n\n/**\n * The rectangular {@link module:AWT.Shape} accepts five different sets of parameters:\n * @example\n * // Calling Rectangle() with different sets of parameters\n * // A Point and a Dimension:\n * new Rectangle(pos, dim)\n * // Another Rectangle, to be cloned:\n * new Rectangle(rect)\n * // Two Point objects containing the coordinates of upper-left and lower-right vertexs:\n * new Rectangle(p0, p1)\n * // An array of four numbers with the coordinates of the same vertexs:\n * new Rectangle([x0, y0, x1, y1])\n * // Four single numbers, meaning the same coordinates as above:\n * new Rectangle(x0, y0, x1, y1)\n * @extends module:AWT.Shape\n */\nexport class Rectangle extends Shape {\n /**\n * Rectangle constructor\n * @param {Point|Rectangle|number|number[]} pos\n * @param {Dimension|number} [dim]\n * @param {number} [w]\n * @param {number} [h]\n */\n constructor(pos, dim, w, h) {\n let p = pos, d = dim;\n // Special case: constructor with a Rectangle as a unique parameter\n if (pos instanceof Rectangle) {\n d = new Dimension(pos.dim.width, pos.dim.height);\n p = new Point(pos.pos.x, pos.pos.y);\n } else if (pos instanceof Point) {\n p = new Point(pos.x, pos.y);\n if (dim instanceof Dimension)\n d = new Dimension(dim.width, dim.height);\n } else if (pos instanceof Array) {\n // Assume `pos` is an array of numbers indicating: x0, y0, x1, y1\n p = new Point(pos[0], pos[1]);\n d = new Dimension(pos[2] - pos[0], pos[3] - pos[1]);\n } else if (typeof w === 'number' && typeof h === 'number') {\n // width and height passed. Treat all parameters as co-ordinates:\n p = new Point(pos, dim);\n d = new Dimension(w, h);\n }\n super(p);\n\n if (d instanceof Dimension)\n this.dim = d;\n else if (d instanceof Point)\n this.dim = new Dimension(d.x - this.pos.x, d.y - this.pos.y);\n else\n this.dim = new Dimension();\n\n this.type = 'rect';\n }\n\n /**\n * Gets the enclosing {@link module:AWT.Rectangle Rectangle} of this Shape.\n * @returns {module:AWT.Rectangle}\n */\n getBounds() {\n return this;\n }\n\n /**\n * Sets this Rectangle the position and dimension of another one\n * @param {module:AWT.Rectangle} rect\n * @returns {module:AWT.Rectangle}\n */\n setBounds(rect) {\n if (!rect)\n rect = new Rectangle();\n this.pos.x = rect.pos.x;\n this.pos.y = rect.pos.y;\n this.dim.width = rect.dim.width;\n this.dim.height = rect.dim.height;\n return this;\n }\n\n /**\n * Checks if two shapes are equivalent.\n * @param {module:AWT.Shape} r - The Shape to compare against\n * @returns {boolean}\n */\n equals(r) {\n return r instanceof Rectangle && this.pos.equals(r.pos) && this.dim.equals(r.dim);\n }\n\n /**\n * Clones this Rectangle\n * @returns {module:AWT.Rectangle}\n */\n clone() {\n return new Rectangle(this);\n }\n\n /**\n * Multiplies the dimension of the Shape by the specified `delta` amount.\n * @param {Point|Dimension} delta - Object containing the X and Y ratio to be scaled.\n * @returns {module:AWT.Rectangle}\n */\n scaleBy(delta) {\n this.pos.multBy(delta);\n this.dim.multBy(delta);\n return this;\n }\n\n /**\n * Expands the boundaries of this shape. This affects the current position and dimension.\n * @param {number} dx - The amount to grow (or decrease) in horizontal direction\n * @param {number} dy - The amount to grow (or decrease) in vertical direction\n * @returns {module:AWT.Rectangle}\n */\n grow(dx, dy) {\n this.pos.x -= dx;\n this.pos.y -= dy;\n this.dim.width += 2 * dx;\n this.dim.height += 2 * dy;\n return this;\n }\n\n /**\n * Gets the {@link module:AWT.Point} corresponding to the lower-right vertex of the Rectangle.\n * @returns {module:AWT.Point}\n */\n getOppositeVertex() {\n return new Point(this.pos.x + this.dim.width, this.pos.y + this.dim.height);\n }\n\n /**\n * Adds the boundaries of another shape to the current one\n * @param {module:AWT.Shape} shape - The {@link module:AWT.Shape} to be added\n * @returns {module:AWT.Rectangle}\n */\n add(shape) {\n const\n myP2 = this.getOppositeVertex(),\n rectP2 = shape.getBounds().getOppositeVertex();\n\n this.pos.moveTo(\n Math.min(this.pos.x, shape.getBounds().pos.x),\n Math.min(this.pos.y, shape.getBounds().pos.y));\n this.dim.setDimension(\n Math.max(myP2.x, rectP2.x) - this.pos.x,\n Math.max(myP2.y, rectP2.y) - this.pos.y);\n return this;\n }\n\n //\n // Inherits the documentation of `contains` in Shape\n contains(p) {\n const p2 = this.getOppositeVertex();\n return p.x >= this.pos.x && p.x <= p2.x && p.y >= this.pos.y && p.y <= p2.y;\n }\n\n //\n // Inherits the documentation of `intersects` in Shape\n intersects(r) {\n const\n p1 = this.pos, p2 = this.getOppositeVertex(),\n r1 = r.pos, r2 = r.getOppositeVertex();\n return r2.x >= p1.x && r1.x <= p2.x && r2.y >= p1.y && r1.y <= p2.y;\n }\n\n //\n // Inherits the documentation of `preparePath` in Shape\n preparePath(ctx) {\n ctx.beginPath();\n ctx.rect(this.pos.x, this.pos.y, this.dim.width, this.dim.height);\n return ctx;\n }\n\n //\n // Inherits the documentation of `getSurface` in Shape\n getSurface() {\n return this.dim.getSurface();\n }\n\n //\n // Inherits the documentation of `isEmpty` in Shape\n isEmpty() {\n return this.getSurface() === 0;\n }\n\n //\n // Inherits the documentation of `isRect` in Shape\n isRect() {\n return true;\n }\n\n //\n // Inherits the documentation of `toString` in Shape\n toString() {\n return `Rectangle ${this.getCoords()}`;\n }\n\n /**\n * Gets a string with the co-ordinates of the upper-left and lower-right vertexs of this rectangle,\n * (with values rounded to int)\n * @returns {string}\n */\n getCoords() {\n return `[${Math.round(this.pos.x)},${Math.round(this.pos.y)},${Math.round(this.pos.x + this.dim.width)},${Math.round(this.pos.y + this.dim.height)}]`;\n }\n\n /**\n * Gets a object with the basic attributes needed to rebuild this instance excluding functions,\n * parent references, constants and also attributes retaining the default value.\n * The resulting object is commonly usued to serialize elements in JSON format.\n * @returns {object} - The resulting object, with minimal attrributes\n */\n getAttributes() {\n return getAttr(this, ['type', 'pos', 'dim']);\n }\n\n /**\n * Reads the properties of this Rectangle from a data object\n * @param {object} data - The data object to be parsed\n * @returns {module:AWT.Rectangle}\n */\n setAttributes(data) {\n return setAttr(this, data, [\n 'type',\n { key: 'pos', fn: Point },\n { key: 'dim', fn: Dimension },\n ]);\n }\n}\n\nObject.assign(Rectangle.prototype, {\n /**\n * Shape type id\n * @name module:AWT.Rectangle#type\n * @type {string} */\n type: 'rect',\n /**\n * The {@link module:AWT.Dimension Dimension} of the Rectangle\n * @name module:AWT.Rectangle#dim\n * @type {module:AWT.Dimension} */\n dim: new Dimension(),\n});\n\n/**\n * The Ellipse shape has the same constructor options as {@link module:AWT.Rectangle Rectangle}\n * @extends module:AWT.Rectangle\n */\nexport class Ellipse extends Rectangle {\n /**\n * Ellipse constructor\n * @param {Point|Rectangle|number|number[]} pos\n * @param {Dimension|number} [dim]\n * @param {number} [w]\n * @param {number} [h]\n */\n constructor(pos, dim, w, h) {\n super(pos, dim, w, h);\n }\n\n //\n // Inherits the documentation of `preparePath` in Rectangle\n preparePath(ctx) {\n\n // Using the solution 'drawEllipseWithBezier' proposed by Steve Tranby in:\n // [http://jsbin.com/sosugenegi/1/edit] as a response to:\n // [http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas]\n // Thanks Steve!!\n\n const kappa = 0.5522848,\n ox = kappa * this.dim.width / 2, // control point offset horizontal\n oy = kappa * this.dim.height / 2, // control point offset vertical\n xe = this.pos.x + this.dim.width, // x-end\n ye = this.pos.y + this.dim.height, // y-end\n xm = this.pos.x + this.dim.width / 2, // x-middle\n ym = this.pos.y + this.dim.height / 2; // y-middle\n\n ctx.beginPath();\n ctx.moveTo(this.pos.x, ym);\n ctx.bezierCurveTo(this.pos.x, ym - oy, xm - ox, this.pos.y, xm, this.pos.y);\n ctx.bezierCurveTo(xm + ox, this.pos.y, xe, ym - oy, xe, ym);\n ctx.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye);\n ctx.bezierCurveTo(xm - ox, ye, this.pos.x, ym + oy, this.pos.x, ym);\n ctx.closePath();\n return ctx;\n }\n\n //\n // Inherits the documentation of `contains` in Shape\n contains(p) {\n // First check if the point is inside the enclosing rectangle\n let result = super.contains(p);\n if (result) {\n const\n rx = this.dim.width / 2,\n ry = this.dim.height / 2,\n cx = this.pos.x + rx,\n cy = this.pos.y + ry;\n // Apply the general equation of an ellipse\n // See: [http://math.stackexchange.com/questions/76457/check-if-a-point-is-within-an-ellipse]\n // rx and ry are > 0 because we are inside the enclosing rect,\n // so don't care about division by zero\n result = Math.pow(p.x - cx, 2) / Math.pow(rx, 2) + Math.pow(p.y - cy, 2) / Math.pow(ry, 2) <= 1;\n }\n return result;\n }\n\n //\n // Inherits the documentation of `getSurface` in Rectangle\n getSurface() {\n return Math.PI * this.dim.width / 2 * this.dim.height / 2;\n }\n\n //\n // Inherits the documentation of `equals` in Rectangle\n equals(e) {\n return e instanceof Ellipse && super.equals(e);\n }\n\n //\n // Inherits the documentation of `clone` in Rectangle\n clone() {\n return new Ellipse(this.pos, this.dim);\n }\n\n //\n // Inherits the documentation of `isRect` in Rectangle\n isRect() {\n return false;\n }\n\n //\n // Inherits the documentation of `toString` in Shape\n toString() {\n return `Ellipse enclosed in ${this.getCoords()}`;\n }\n}\n\nObject.assign(Ellipse.prototype, {\n /**\n * Shape type id\n * @name module:AWT.Ellipse#type\n * @type {string} */\n type: 'ellipse',\n});\n\n/**\n * A `Path` is a {@link module:AWT.Shape} formed by a serie of strokes, represented by\n * {@link module:AWT.PathStroke} objects\n * @extends module:AWT.Shape\n */\nexport class Path extends Shape {\n /**\n * Path constructor\n * @param {module:AWT.PathStroke[]} strokes - The array of {@link module:AWT.PathStroke} objects defining this Path.\n */\n constructor(strokes) {\n super();\n // Deep copy of the array of strokes\n if (strokes)\n this.setStrokes(strokes);\n }\n\n setStrokes(strokes) {\n this.strokes = [];\n // In [Shaper](Shaper.html) objects, strokes have `action` instead of `type` and `data` instead of `points`\n strokes.forEach(str => this.strokes.push(new PathStroke(str.type || str.action, str.points || str.data)));\n // Calculate the enclosing rectangle\n this.enclosing = new Rectangle();\n this.enclosingPoints = [];\n this.calcEnclosingRect();\n this.pos = this.enclosing.pos;\n return this;\n }\n\n //\n // Inherits the documentation of `clone` in Shape\n clone() {\n return new Path(this.strokes.map(str => str.clone()));\n }\n\n /**\n * Adds a {@link module:AWT.PathStroke} to `strokes`\n * @param {module:AWT.PathStroke} stroke\n */\n addStroke(stroke) {\n this.strokes.push(stroke);\n return this;\n }\n\n /**\n * Calculates the polygon and the rectangle that (approximately) encloses this shape\n * @returns {module:AWT.Rectangle}\n */\n calcEnclosingRect() {\n this.enclosingPoints = [];\n let last = new Point();\n this.strokes.forEach(str => {\n str.getEnclosingPoints(last).forEach(pt => {\n last = new Point(pt);\n this.enclosingPoints.push(last);\n });\n });\n\n let l = this.enclosingPoints.length;\n if (l > 1 && this.enclosingPoints[0].equals(this.enclosingPoints[l - 1])) {\n this.enclosingPoints.pop();\n l--;\n }\n const\n p0 = new Point(this.enclosingPoints[0]),\n p1 = new Point(this.enclosingPoints[0]);\n\n for (let k = 1; k < l; k++) {\n const p = this.enclosingPoints[k];\n // Check if `p` is at left or above `p0`\n p0.x = Math.min(p.x, p0.x);\n p0.y = Math.min(p.y, p0.y);\n // Check if `p` is at right or below `p1`\n p1.x = Math.max(p.x, p1.x);\n p1.y = Math.max(p.y, p1.y);\n }\n this.enclosing.setBounds(new Rectangle(p0, new Dimension(p0, p1)));\n return this.enclosing;\n }\n\n //\n // Inherits the documentation of `getBounds` in Shape\n getBounds() {\n return this.enclosing;\n }\n\n //\n // Inherits the documentation of `moveBy` in Shape\n moveBy(delta) {\n this.strokes.forEach(str => str.moveBy(delta));\n this.enclosingPoints.forEach(pt => pt.moveBy(delta));\n this.enclosing.moveBy(delta);\n return this;\n }\n\n //\n // Inherits the documentation of `moveTo` in Shape\n moveTo(newPos) {\n return this.moveBy(new Dimension(newPos.x - this.pos.x, newPos.y - this.pos.y));\n }\n\n //\n // Inherits the documentation of `equals` in Shape\n // TODO: Implement comparision of complex paths\n equals(_p) {\n return false;\n }\n\n //\n // Inherits the documentation of `scaleBy` in Shape\n scaleBy(delta) {\n this.strokes.forEach(str => str.multBy(delta));\n this.enclosingPoints.forEach(pt => pt.multBy(delta));\n this.enclosing.scaleBy(delta);\n return this;\n }\n\n //\n // Inherits the documentation of `contains` in Shape\n contains(p) {\n let result = this.enclosing.contains(p);\n if (result) {\n // Let's see if the point really lies inside the polygon formed by enclosingPoints\n // Using the \"Ray casting algorithm\" described in [https://en.wikipedia.org/wiki/Point_in_polygon]\n const N = this.enclosingPoints.length;\n let\n xinters = 0,\n counter = 0,\n p1 = this.enclosingPoints[0];\n\n for (let i = 1; i <= N; i++) {\n const p2 = this.enclosingPoints[i % N];\n if (p.y > Math.min(p1.y, p2.y)) {\n if (p.y <= Math.max(p1.y, p2.y)) {\n if (p.x <= Math.max(p1.x, p2.x)) {\n if (p1.y !== p2.y) {\n xinters = (p.y - p1.y) * (p2.x - p1.x) / (p2.y - p1.y) + p1.x;\n if (p1.x === p2.x || p.x <= xinters)\n counter++;\n }\n }\n }\n }\n p1 = p2;\n }\n if (counter % 2 === 0)\n result = false;\n }\n return result;\n }\n\n //\n // Inherits the documentation of `intersects` in Shape\n // TODO: Implement a check algorithm based on the real shape\n intersects(r) {\n return this.enclosing.intersects(r);\n }\n\n //\n // Inherits the documentation of `preparePath` in Shape\n preparePath(ctx) {\n // TODO: Implement filling paths\n ctx.beginPath();\n this.strokes.forEach(str => str.stroke(ctx));\n return ctx;\n }\n\n /**\n * Gets a object with the basic attributes needed to rebuild this instance excluding functions,\n * parent references, constants and also attributes retaining the default value.\n * The resulting object is commonly usued to serialize elements in JSON format.\n * @returns {object} - The resulting object, with minimal attrributes\n */\n getAttributes() {\n return {\n type: this.type,\n strokes: this.strokes.map(s => s.getAttributes()).join('|'),\n };\n }\n\n /**\n * Reads the properties of this Path from a data object\n * @param {object} data - The data object to be parsed\n * @returns {module:AWT.Path}\n */\n setAttributes(data) {\n const strData = data.strokes.split('|');\n const strokes = strData.map(s => {\n const [type, points] = s.split(':');\n return new PathStroke(type, points ? points.split(',') : []);\n });\n return this.setStrokes(strokes);\n }\n}\n\nObject.assign(Path.prototype, {\n /**\n * Shape type id\n * @name module:AWT.Path#type\n * @type {string} */\n type: 'path',\n /**\n * The strokes forming this Path.\n * @name module:AWT.Path#strokes\n * @type {module:AWT.PathStroke[]} */\n strokes: [],\n /**\n * The {@link module:AWT.Rectangle Rectangle} enclosing this Path (when drawing, this Rectangle don't include border width!)\n * @name module:AWT.Path#enclosing\n * @type {module:AWT.Rectangle} */\n enclosing: new Rectangle(),\n /**\n * Set of vertexs of a polygon close to the real path of this shape\n * @name module:AWT.Path#enclosingPoints\n * @type {module:AWT.Point[]} */\n enclosingPoints: [],\n});\n\n/**\n * PathStroke is the basic component of {@link module:AWT.Path} objects\n */\nexport class PathStroke {\n /**\n * PathStroke constructor\n * @param {string} type - The type of stroke. Possible values are: `M` (move to), `L` (line to),\n * `Q` (quadratic to), `B` (bezier to) and `X` (close path).\n * @param {module:AWT.Point[]} points - The array of {@link module:AWT.Point} objects used in this Stroke.\n */\n constructor(type, points) {\n this.type = type;\n // Points are deep cloned, to avoid change the original values\n if (points && points.length > 0) {\n // Check if 'points' is an array of objects of type 'Point'\n if (points[0] instanceof Point)\n this.points = points.map(p => new Point(p));\n // otherwise assume that 'points' contains just numbers\n // to be readed in pairs of x and y co-ordinates\n else {\n this.points = [];\n for (let i = 0; i < points.length; i += 2)\n this.points.push(new Point(points[i], points[i + 1]));\n }\n }\n }\n\n /**\n * Calculates some of the points included in a quadratic Bézier curve\n * The number of points being calculated is defined in Utils.settings.BEZIER_POINTS\n * @see {@link https://en.wikipedia.org/wiki/B%C3%A9zier_curve}\n * @see {@link https://www.jasondavies.com/animated-bezier/}\n *\n * @param {module:AWT.Point} p0 - Starting point of the quadratic Bézier curve\n * @param {module:AWT.Point} p1 - Control point\n * @param {module:AWT.Point} p2 - Ending point\n * @param {number} [numPoints] - The number of intermediate points to calculate. When not defined,\n * the value will be obtained from {@link module:Utils.settings.BEZIER_POINTS}.\n * @returns {module:AWT.Point[]} - Array with some intermediate points from the resulting Bézier curve\n */\n static getQuadraticPoints(p0, p1, p2, numPoints) {\n if (!numPoints)\n numPoints = settings.BEZIER_POINTS;\n const\n result = [],\n pxa = new Point(),\n pxb = new Point();\n for (let i = 0; i < numPoints; i++) {\n const n = (i + 1) / (numPoints + 1);\n pxa.x = p0.x + (p1.x - p0.x) * n;\n pxa.y = p0.y - (p0.y - p1.y) * n;\n pxb.x = p1.x + (p2.x - p1.x) * n;\n pxb.y = p1.y + (p2.y - p1.y) * n;\n result.push(new Point(pxa.x + (pxb.x - pxa.x) * n, pxa.y - (pxa.y - pxb.y) * n));\n }\n return result;\n }\n\n /**\n * Calculates some of the points included in a cubic Bézier (curve with two control points)\n * The number of points being calculated is defined in Utils.settings.BEZIER_POINTS\n * @param {module:AWT.Point} p0 - Starting point of the cubic Bézier curve\n * @param {module:AWT.Point} p1 - First control point\n * @param {module:AWT.Point} p2 - Second control point\n * @param {module:AWT.Point} p3 - Ending point\n * @param {number} [numPoints] - The number of intermediate points to calculate. When not defined,\n * the value will be obtained from {@link module:Utils.settings.BEZIER_POINTS}.\n * @returns {module:AWT.Point[]} - Array with some intermediate points from the resulting Bézier curve\n */\n static getCubicPoints(p0, p1, p2, p3, numPoints) {\n const result = [];\n if (!numPoints)\n numPoints = settings.BEZIER_POINTS;\n const pr = PathStroke.getQuadraticPoints(p0, p1, p2, numPoints);\n const pq = PathStroke.getQuadraticPoints(p1, p2, p3, numPoints);\n for (let i = 0; i < numPoints; i++) {\n const n = (i + 1) / (numPoints + 1);\n result.push(new Point(pr[i].x + (pq[i].x - pr[i].x) * n, pr[i].y - (pr[0].y - pq[0].y) * n));\n }\n return result;\n }\n\n /**\n * Clones this PathStroke\n * @returns {module:AWT.PathStroke}\n */\n clone() {\n // The constructors of PathStroke always make a deep copy of the `points` array\n return new PathStroke(this.type, this.points);\n }\n\n /**\n * Increments or decrements by `delta` the x and y coordinates of all points\n * @param {Point|Dimension} delta - The amount to add to the `x` and `y`\n * coordinates of each point.\n */\n moveBy(delta) {\n if (this.points)\n this.points.forEach(pt => pt.moveBy(delta));\n return this;\n }\n\n /**\n * Multiplies each point coordinates by the `x` and `y` (or `w` and `h`) values of the\n * passed {@link module:AWT.Point} or {@link module:AWT.Dimension Dimension}.\n * @param {Point|Dimension} delta\n */\n multBy(delta) {\n if (this.points)\n this.points.forEach(pt => pt.multBy(delta));\n return this;\n }\n\n /**\n * Draws this PathStroke in the provided HTML canvas context\n * @param {external:CanvasRenderingContext2D} ctx - The HTML canvas 2D rendering context\n */\n stroke(ctx) {\n switch (this.type) {\n case 'M':\n ctx.moveTo(this.points[0].x, this.points[0].y);\n break;\n case 'L':\n ctx.lineTo(this.points[0].x, this.points[0].y);\n break;\n case 'Q':\n ctx.quadraticCurveTo(\n this.points[0].x, this.points[0].y,\n this.points[1].x, this.points[1].y);\n break;\n case 'B':\n ctx.bezierCurveTo(\n this.points[0].x, this.points[0].y,\n this.points[1].x, this.points[1].y,\n this.points[2].x, this.points[2].y);\n break;\n case 'X':\n ctx.closePath();\n break;\n }\n return ctx;\n }\n\n /**\n * Gets the set of points that will be included as a vertexs on the owner's shape\n * enclosing polygon.\n * @param {module:AWT.Point} from - The starting point for this stroke\n * @returns {module:AWT.Point[]}\n */\n getEnclosingPoints(from) {\n let result = [];\n switch (this.type) {\n case 'M':\n case 'L':\n result.push(this.points[0]);\n break;\n case 'Q':\n result = PathStroke.getQuadraticPoints(from, this.points[0], this.points[1]);\n result.push(this.points[1]);\n break;\n case 'B':\n result = PathStroke.getCubicPoints(from, this.points[0], this.points[1], this.points[2]);\n result.push(this.points[2]);\n break;\n }\n return result;\n }\n\n /**\n * Gets a object with the basic attributes needed to rebuild this instance excluding functions,\n * parent references, constants and also attributes retaining the default value.\n * The resulting object is commonly usued to serialize elements in JSON format.\n * @returns {object} - The resulting object, with minimal attrributes\n */\n getAttributes() {\n return `${this.type}:${this.points ? this.points.map(p => `${fx(p.x)},${fx(p.y)}`).join(',') : ''}`;\n }\n}\n\nObject.assign(PathStroke.prototype, {\n /**\n * The Stroke type. Possible values are: `M` (move to), `L` (line to), `Q` (quadratic to),\n * `B` (bezier to) and `X` (close path).\n * @name module:AWT.PathStroke#type\n * @type {string} */\n type: 'X',\n /**\n * The array of points used by this stroke. Can be `null`.\n * @name module:AWT.PathStroke#points\n * @type {module:AWT.Point[]} */\n points: null,\n});\n\n/**\n * This class encapsulates actions that can be linked to buttons, menus and other active objects\n */\nexport class Action {\n /**\n * Action constructor\n * @param {string} name - The name of this Action\n * @param {function} actionPerformed - The callback to be triggered by this Action\n */\n constructor(name, actionPerformed) {\n this.name = name;\n this.actionPerformed = actionPerformed;\n this._statusListeners = [];\n }\n\n /**\n * Here is where subclasses must define the callback to be triggered when\n * this Action object is called\n * @param {module:AWT.Action} _thisAction - Pointer to this Action object\n * @param {object} _event - The original action event that has originated this action\n */\n actionPerformed(_thisAction, _event) {\n return this;\n }\n\n /**\n * This is the method to be passed to DOM event triggers\n * @example\n * const myFunc = () => { alert('Hello!') }\n * const myAction = new Action('hello', myFunc)\n * $( \"#foo\" ).on( \"click\", myAction.processEvent)\n * @param {object} event - The event object passed by the DOM event trigger\n */\n processEvent(event) {\n return this.actionPerformed(this, event);\n }\n\n /**\n * Adds a status listener\n * @param {function} listener - The callback method to be called when the status of this\n * Action changes\n */\n addStatusListener(listener) {\n this._statusListeners.push(listener);\n }\n\n /**\n * Removes a previously registered status listener\n * @param {function} listener - The listener to be removed\n */\n removeStatusListener(listener) {\n this._statusListeners = this._statusListeners.map(l => l !== listener);\n }\n\n /**\n * Enables or disables this action\n * @param {boolean} enabled\n */\n setEnabled(enabled) {\n this.enabled = enabled;\n this._statusListeners.forEach(listener => listener.call(this, this));\n return this;\n }\n}\n\nObject.assign(Action.prototype, {\n /**\n * The action's name\n * @name module:AWT.Action#name\n * @type {string} */\n name: null,\n /**\n * An optional description\n * @name module:AWT.Action#description\n * @type {string} */\n description: null,\n /**\n * Action status. `true` means enabled, `false` disabled\n * @name module:AWT.Action#enabled\n * @type {boolean} */\n enabled: false,\n /**\n * Array of callback functions to be triggered when the `enabled` flag changes\n * @name module:AWT.Action#_statusListeners\n * @private\n * @type {function[]} */\n _statusListeners: null,\n});\n\n/**\n * This class provides a timer that will launch a function at specific intervals\n */\nexport class Timer {\n /**\n * Timer constructor\n * @param {function} actionPerformed - The function to be triggered when the timer is enabled.\n * @param {number} interval - The interval between action calls, specified in milliseconds.\n * @param {boolean} [enabled=false] - Flag to indicate if the timer will be initially enabled.\n */\n constructor(actionPerformed, interval, enabled) {\n this.actionPerformed = actionPerformed;\n this.interval = interval;\n this.setEnabled(enabled === true);\n }\n\n /**\n * Here is where subclasses must define the function to be performed when this timer ticks.\n * @param {module:AWT.Timer} _thisTimer\n */\n actionPerformed(_thisTimer) {\n return this;\n }\n\n /**\n * This is the method called by `window.setInterval`\n * @param {external:Event} _event\n */\n processTimer(_event) {\n this.ticks++;\n if (!this.repeats)\n this.stop();\n return this.actionPerformed.call(this);\n }\n\n /**\n * Enables or disables this timer\n * @param {boolean} enabled - Indicates if the timer should be enabled or disabled\n * @param {boolean} [retainCounter=false] - When `true`, the ticks counter will not be cleared\n */\n setEnabled(enabled, retainCounter) {\n if (!retainCounter)\n this.ticks = 0;\n if (enabled && this.timer !== null) {\n // Timer already running\n return;\n }\n\n if (enabled) {\n this.timer = window.setInterval(() => this.processTimer(null), this.interval);\n } else {\n if (this.timer !== null) {\n window.clearInterval(this.timer);\n this.timer = null;\n }\n }\n return this;\n }\n\n /**\n * Checks if this timer is running\n * @returns {boolean}\n */\n isRunning() {\n return this.timer !== null;\n }\n\n /**\n * Starts this timer\n * @param {boolean} [retainCounter=false] - When `true`, the ticks counter will not be cleared\n */\n start(retainCounter) {\n return this.setEnabled(true, retainCounter);\n }\n\n /**\n * Stops this timer\n * @param {boolean} [retainCounter=false] - When `true`, the ticks counter will not be cleared\n */\n stop(retainCounter) {\n return this.setEnabled(false, retainCounter);\n }\n}\n\nObject.assign(Timer.prototype, {\n /**\n * The timer interval, in milliseconds\n * @name module:AWT.Timer#interval\n * @type {number} */\n interval: 0,\n /**\n * The ticks counter\n * @name module:AWT.Timer#ticks\n * @type {number} */\n ticks: 0,\n /**\n * The object returned by `window.setInterval`\n * @name module:AWT.Timer#timer\n * @type {object} */\n timer: null,\n /**\n * When `true`, the timer should repeat until `stop` is called\n * @name module:AWT.Timer#repeats\n * @type {boolean} */\n repeats: true,\n});\n\n/**\n * Logic object that takes care of an \"invalidated\" rectangle that will be repainted\n * at the next update of a 2D object, usually an HTML Canvas.\n * Container has the same constructor options as {@link module:AWT.Rectangle Rectangle}\n * @extends module:AWT.Rectangle\n */\nexport class Container extends Rectangle {\n /**\n * Container constructor\n * @param {Point|Rectangle|number|number[]} pos\n * @param {Dimension|number} [dim]\n * @param {number} [w]\n * @param {number} [h]\n */\n constructor(pos, dim, w, h) {\n super(pos, dim, w, h);\n }\n\n /**\n * Adds the provided rectangle to the invalidated area.\n * @param {module:AWT.Rectangle} rect\n */\n invalidate(rect) {\n if (rect) {\n if (this.invalidatedRect === null)\n this.invalidatedRect = rect.clone();\n else\n this.invalidatedRect.add(rect);\n } else\n this.invalidatedRect = null;\n return this;\n }\n\n /**\n * Updates the invalidated area\n */\n update() {\n this.updateContent(this.invalidatedRect);\n this.invalidatedRect = null;\n return this;\n }\n\n /**\n * Containers should implement this method to update its graphic contents. It should\n * be called from {@link module:AWT.Container#update}\n * @param {module:AWT.Shape} _dirtyRegion - Specifies the area to be updated. When `null`, it's the whole\n * Container.\n */\n updateContent(_dirtyRegion) {\n // To be overrided by subclasses. Here does nothing.\n return this;\n }\n}\n\nObject.assign(Container.prototype, {\n /**\n * The currently \"invalidated\" area\n * @name module:AWT.Container#invalidatedRect\n * @type {module:AWT.Rectangle} */\n invalidatedRect: null,\n});\n\n/**\n * This object contains utility clases for painting graphics and images,\n * as found in the Java [Abstract Window Toolkit](http://docs.oracle.com/javase/7/docs/api/java/awt/package-summary.html)\n *\n * The objects defined here are: {@link module:AWT.Font Font}, {@link module:AWT.Gradient Gradient}, {@link module:AWT.Stroke Stroke},\n * {@link module:AWT.Point Point}, {@link module:AWT.Dimension Dimension}, {@link module:AWT.Shape Shape}, {@link module:AWT.Rectangle Rectangle},\n * {@link module:AWT.Ellipse Ellipse}, {@link module:AWT.Path Path}, {@link module:AWT.PathStroke PathStroke}, {@link module:AWT.Action Action},\n * {@link module:AWT.Timer Timer} and {@link module:AWT.Container Container}.\n */\nexport default {\n Font,\n Gradient,\n Stroke,\n Point,\n Dimension,\n Shape,\n Rectangle,\n Ellipse,\n Path,\n PathStroke,\n Action,\n Timer,\n Container\n};\n","/**\n * File : media/EventSoundsElement.js\n * Created : 01/04/2015\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\n/* global navigator, window, document, Blob, URL, MediaRecorder */\n\nimport { log } from '../Utils.js';\n\n/**\n * The AudioBuffer object provides sound recording and replaying to activities.\n */\nexport class AudioBuffer {\n /**\n * AudioBuffer constructor\n * @param {number} [seconds] - The maximum amount of time allowed to be recorded by this AudioBuffer\n */\n constructor(seconds) {\n if (navigator && navigator.mediaDevices && navigator.mediaDevices.getUserMedia)\n this.enabled = true;\n if (seconds)\n this.seconds = seconds;\n this.chunks = [];\n }\n\n /**\n * Starts playing the currently recorded audio, if any.\n */\n play() {\n this.stop();\n if (this.mediaPlayer) {\n this.mediaPlayer.currentTime = 0;\n this.mediaPlayer.play();\n } else {\n this.playWhenFinished = true;\n }\n }\n\n /**\n * Stops the current operation, either recording or playing audio\n */\n stop() {\n if (this.mediaRecorder && this.mediaRecorder.state === 'recording')\n this.mediaRecorder.stop();\n else if (this.mediaPlayer && !this.mediaPlayer.paused)\n this.mediaPlayer.pause();\n }\n\n /**\n * Starts recording audio, or stops the recording if already started.\n * @param {external:jQuery} [$div] - Optional `div` element where the recording is performed, as a jQuery ref.\n */\n record($div) {\n if (this.mediaRecorder && this.mediaRecorder.state === 'recording')\n this.mediaRecorder.stop();\n else if (this.enabled) {\n this.stop();\n this.mediaPlayer = null;\n\n navigator.mediaDevices.getUserMedia({ audio: true, video: false })\n .then(mediaStream => {\n\n this.mediaRecorder = new MediaRecorder(mediaStream);\n\n this.mediaRecorder.ondataavailable = ev => this.chunks.push(ev.data);\n\n this.mediaRecorder.onerror = err => {\n log('error', `Error recording audio: ${err}`);\n this.mediaRecorder = null;\n };\n\n this.mediaRecorder.onstart = () => {\n log('debug', 'Recording audio started');\n this.visualFeedbak(true, $div);\n };\n\n this.mediaRecorder.onstop = () => {\n log('debug', 'Recording audio finished');\n this.visualFeedbak(false, $div);\n\n if (this.timeoutID) {\n window.clearTimeout(this.timeoutID);\n this.timeoutID = null;\n }\n\n const options = {};\n if (this.chunks.length > 0 && this.chunks[0].type)\n options.type = this.chunks[0].type;\n const blob = new Blob(this.chunks, options);\n this.chunks = [];\n this.mediaPlayer = document.createElement('audio');\n this.mediaPlayer.src = URL.createObjectURL(blob);\n this.mediaPlayer.pause();\n this.mediaRecorder = null;\n if (this.playWhenFinished) {\n this.playWhenFinished = false;\n this.mediaPlayer.play();\n }\n };\n\n this.mediaRecorder.onwarning = ev => log('warn', `Warning recording audio: ${ev}`);\n\n this.playWhenFinished = false;\n\n this.mediaRecorder.start();\n\n this.timeoutID = window.setTimeout(() => {\n if (this.mediaRecorder);\n this.mediaRecorder.stop();\n }, this.seconds * 1000);\n })\n .catch(err => {\n log('error', err.toString());\n this.visualFeedbak(false, $div);\n });\n }\n }\n\n /**\n * Set visual feedback to the user while the system is recording audio\n * Currently changes the cursor pointer associated to the HTML element\n * containing the recorder.\n * @param {boolean} enabled - Flag indicating if the visual feedback should be active or inactive\n * @param {external:jQuery} [$div] - Optional `div` element where the recording is performed, as a jQuery ref.\n */\n visualFeedbak(enabled, $div) {\n if ($div)\n $div.css('cursor', enabled ? 'progress' : 'inherit');\n }\n\n /**\n * Clears all data associated to this AudioBuffer\n */\n clear() {\n this.stop();\n this.mediaPlayer = null;\n }\n}\n\nObject.assign(AudioBuffer.prototype, {\n /**\n * AudioBuffer is enabled only in browsers with `navigator.MediaDevices.getuserMedia`\n * @name module:media/AudioBuffer.AudioBuffer#enabled\n * @type {boolean}\n */\n enabled: false,\n /**\n * Maximum length of recordings allowed to this AudioBuffer (in seconds)\n * @name module:media/AudioBuffer.AudioBuffer#seconds\n * @type {number}\n */\n seconds: 20,\n /**\n * The object used to record audio data and convert it to a valid stream for the {@link module:media/ActiveMediaPlayer.ActiveMediaPlayer ActiveMediaPlayer}\n * @name module:media/AudioBuffer.AudioBuffer#mediaRecorder\n * @type {external:MediaRecorder}\n */\n mediaRecorder: null,\n /**\n * Array of data chunks collected during the recording\n * @name module:media/AudioBuffer.AudioBuffer#chunks\n * @type {external:Blob[]}\n */\n chunks: null,\n /**\n * The HTML audio element used to play the recorded sound\n * @name module:media/AudioBuffer.AudioBuffer#mediaPlayer\n * @type {external:HTMLAudioElement}\n */\n mediaPlayer: null,\n /**\n * The identifier of the timer launched to stop the recording when the maximum time is exceeded.\n * This member is `null` when no timeout function is associated to this AudioBuffer\n * @name module:media/AudioBuffer.AudioBuffer#timeoutID\n * @type {number}\n */\n timeoutID: null,\n /**\n * Instructs this AudioBuffer recorder to start playing the collected audio at the end of the\n * current `mediaRecorder` task.\n * @name module:media/AudioBuffer.AudioBuffer#playWhenFinished\n * @type {boolean}\n */\n playWhenFinished: false,\n});\n\n/**\n * Maximum amount of time allowed for recordings (in seconds)\n * @type {number}\n */\nAudioBuffer.MAX_RECORD_LENGTH = 180;\n\nexport default AudioBuffer;\n","/**\n * File : media/ActiveMediaPlayer.js\n * Created : 28/04/2015\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\n/* global navigator */\n\nimport $ from 'jquery';\nimport AudioBuffer from './AudioBuffer.js';\n\n/**\n * This kind of object encapsulates a realized {@link module:media/MediaContent.MediaContent} and provides methods to start,\n * stop, pause and record different types of media (audio, video, MIDI, voice recording...)\n */\nexport class ActiveMediaPlayer {\n /**\n * ActiveMediaPlayer constructor\n * @param {module:media/MediaContent.MediaContent} mc - - The content used by this player\n * @param {module:bags/MediaBag.MediaBag} mb - The project's MediaBag\n * @param {module:JClicPlayer.JClicPlayer} ps - An object implementing the\n * {@link http://projectestac.github.io/jclic/apidoc/edu/xtec/jclic/PlayStation.html PlayStation} interface,\n * usually a {@link module:JClicPlayer.JClicPlayer JClicPlayer}.\n */\n constructor(mc, mb, ps) {\n this.mc = mc;\n this.ps = ps;\n switch (mc.type) {\n case 'RECORD_AUDIO':\n if (ActiveMediaPlayer.AUDIO_BUFFERS) {\n this.clearAudioBuffer(mc.recBuffer);\n ActiveMediaPlayer.AUDIO_BUFFERS[mc.recBuffer] = new AudioBuffer(mc.length);\n }\n /* falls through */\n case 'PLAY_RECORDED_AUDIO':\n this.useAudioBuffer = true;\n break;\n case 'PLAY_AUDIO':\n case 'PLAY_VIDEO':\n case 'PLAY_MIDI':\n this.mbe = mb.getElement(mc.file, true);\n break;\n default:\n break;\n }\n }\n\n /**\n * Generates the objects that will play media\n */\n realize() {\n if (this.mbe) {\n this.mbe.build(mbe => {\n if (mbe.data && mbe.data.pause && !mbe.data.paused && !mbe.data.ended && mbe.data.currentTime)\n mbe.data.pause();\n if ((mbe.type === 'video' || mbe.type === 'anim') && mbe.data) {\n this.$visualComponent = $(mbe.data);\n this.$visualComponent.css('z-index', 20);\n }\n }, this.ps, false, this.mc.level);\n }\n }\n\n /**\n * Plays the media, realizing it if needed.\n * @param {module:boxes/ActiveBox.ActiveBox} [_setBx] - The active box where this media will be placed (when video)\n */\n playNow(_setBx) {\n // TODO: Remove unused param \"_setBx\"\n if (this.useAudioBuffer) {\n if (ActiveMediaPlayer.AUDIO_BUFFERS) {\n const $div = this.ps && this.ps.$div;\n const buffer = ActiveMediaPlayer.AUDIO_BUFFERS[this.mc.recBuffer];\n if (buffer) {\n if (this.mc.type === 'RECORD_AUDIO') {\n buffer.record($div);\n } else {\n buffer.play();\n }\n }\n }\n } else if (this.mbe) {\n this.mbe.build(() => {\n if (this.mbe.data) {\n if (this.mbe.type === 'midi') {\n this.mbe.data.playTo = this.mc.to || 0;\n } else {\n let armed = false;\n const $player = $(this.mbe.data);\n // Clear previous event handlers\n $player.off();\n // If there is a time fragment specified, prepare to stop when the `to` position is reached\n if (this.mc.to > 0) {\n $player.on('timeupdate', () => {\n if (armed && this.mbe.data.currentTime >= this.mc.to / 1000) {\n $player.off('timeupdate');\n this.mbe.data.pause();\n }\n });\n }\n // Launch the media despite of its readyState\n armed = true;\n }\n if (!this.mbe.data.paused && !this.mbe.data.ended && this.mbe.data.currentTime)\n this.mbe.data.pause();\n // Seek the media position\n this.mbe.data.currentTime = this.mc.from > 0 ? this.mc.from / 1000 : 0;\n this.mbe.data.play();\n }\n }, this.ps, true, this.mc.level);\n }\n }\n\n /**\n * Plays the media when available, without blocking the current thread.\n * @param {module:boxes/ActiveBox.ActiveBox} [setBx] - The active box where this media will be placed (when video)\n */\n play(setBx) {\n this.stopAllAudioBuffers();\n this.playNow(setBx);\n }\n\n /**\n * Stops the media playing\n */\n stop() {\n if (this.useAudioBuffer)\n this.stopAudioBuffer(this.mc.recBuffer);\n else if (this.mbe && this.mbe.data && this.mbe.data.pause && !this.mbe.data.paused && !this.mbe.data.ended && this.mbe.data.currentTime)\n this.mbe.data.pause();\n }\n\n /**\n * Frees all resources used by this player\n */\n clear() {\n this.stop();\n if (this.useAudioBuffer)\n this.clearAudioBuffer(this.mc.recBuffer);\n }\n\n /**\n * Clears the specified audio buffer\n * @param {number} buffer - Index of the buffer in {@link module:media/ActiveMediaPlayer.ActiveMediaPlayer#AUDIO_BUFFERS AUDIO_BUFFERS}\n */\n clearAudioBuffer(buffer) {\n if (ActiveMediaPlayer.AUDIO_BUFFERS &&\n buffer >= 0 && buffer < ActiveMediaPlayer.AUDIO_BUFFERS.length &&\n ActiveMediaPlayer.AUDIO_BUFFERS[buffer]) {\n ActiveMediaPlayer.AUDIO_BUFFERS[buffer].clear();\n ActiveMediaPlayer.AUDIO_BUFFERS[buffer] = null;\n }\n }\n\n /**\n * Clears all audio buffers\n */\n clearAllAudioBuffers() {\n if (ActiveMediaPlayer.AUDIO_BUFFERS)\n ActiveMediaPlayer.AUDIO_BUFFERS.forEach((_buffer, n) => this.clearAudioBuffer(n));\n }\n\n /**\n * Counts the number of active audio buffers\n * @returns {number}\n */\n countActiveBuffers() {\n return ActiveMediaPlayer.AUDIO_BUFFERS ? ActiveMediaPlayer.AUDIO_BUFFERS.reduce((c, ab) => c + ab ? 1 : 0, 0) : 0;\n }\n\n /**\n * Stops the playing or recording actions of all audio buffers\n */\n stopAllAudioBuffers() {\n if (ActiveMediaPlayer.AUDIO_BUFFERS)\n ActiveMediaPlayer.AUDIO_BUFFERS.forEach(ab => ab ? ab.stop() : null);\n }\n\n /**\n * Stops a specific audio buffer\n * @param {number} buffer - Index of the buffer in {@link module:media/ActiveMediaPlayer.ActiveMediaPlayer#AUDIO_BUFFERS AUDIO_BUFFERS}\n */\n stopAudioBuffer(buffer) {\n if (ActiveMediaPlayer.AUDIO_BUFFERS &&\n buffer >= 0 && buffer < ActiveMediaPlayer.AUDIO_BUFFERS.length &&\n ActiveMediaPlayer.AUDIO_BUFFERS[buffer])\n ActiveMediaPlayer.AUDIO_BUFFERS[buffer].stop();\n }\n\n /**\n * Checks the position of visual components after a displacement or resizing of its container\n * @param {module:boxes/ActiveBox.ActiveBox} _bxi - The container where this player is hosted\n */\n checkVisualComponentBounds(_bxi) {\n // does nothing\n }\n\n /**\n * Sets the visual component of this player visible or invisible\n * @param {boolean} _state - `true` for visible\n */\n setVisualComponentVisible(_state) {\n // TODO: Implement setVisualComponentVisible\n }\n\n /**\n * Sets the ActiveBox associated to this media player\n * @param {module:boxes/ActiveBox.ActiveBox} setBx - The new container of this media. Can be `null`.\n */\n linkTo(setBx) {\n this.bx = setBx;\n if (this.bx && this.$visualComponent)\n this.bx.setHostedComponent(this.$visualComponent);\n }\n}\n\nObject.assign(ActiveMediaPlayer.prototype, {\n /**\n * The MediaContent associated to this player.\n * @name module:media/ActiveMediaPlayer.ActiveMediaPlayer#mc\n * @type {module:media/MediaContent.MediaContent} */\n mc: null,\n /**\n * The player to which this player belongs.\n * @name module:media/ActiveMediaPlayer.ActiveMediaPlayer#ps\n * @type {module:JClicPlayer.JClicPlayer} */\n ps: null,\n /**\n * MediaPlayers should be linked to {@link module:boxes/ActiveBox.ActiveBox ActiveBox} objects.\n * @name module:media/ActiveMediaPlayer.ActiveMediaPlayer#bx\n * @type {module:boxes/ActiveBox.ActiveBox} */\n bx: null,\n /**\n * The visual component for videos, usually a `video` HTML element\n * @name module:media/ActiveMediaPlayer.ActiveMediaPlayer#$visualComponent\n * @type {external:jQuery} */\n $visualComponent: null,\n /**\n * When `true`, this player makes use of a recording audio buffer\n * @name module:media/ActiveMediaPlayer.ActiveMediaPlayer#useAudioBuffer\n * @type {boolean} */\n useAudioBuffer: false,\n /**\n * The {@link module:bads/MediaBagElement.MediaBagElement} containing the reference to the media to be played\n * @name module:media/ActiveMediaPlayer.ActiveMediaPlayer#mbe\n * @type {module:bags/MediaBagElement.MediaBagElement} */\n mbe: null,\n});\n\n/**\n * Recording of audio is enabled only when `navigator.getUserMedia` and `MediaRecorder` are defined\n * In 02-Mar-2016 this is implemented only in Firefox 41 and Chrome 49 or later.\n * See: {@link https://addpipe.com/blog/mediarecorder-api}\n * @type Boolean\n */\nActiveMediaPlayer.REC_ENABLED = typeof MediaRecorder !== 'undefined' && typeof navigator !== 'undefined';\n\nif (ActiveMediaPlayer.REC_ENABLED) {\n navigator.getUserMedia = navigator.getUserMedia ||\n navigator.webkitGetUserMedia ||\n navigator.mozGetUserMedia ||\n navigator.msGetUserMedia;\n}\n\n/**\n * Audio buffers used for recording and playing voice are stored in a static array because\n * they are common to all instances of {@link module:media/ActiveMediaPlayer.ActiveMediaPlayer ActiveMediaPlayer}\n * Only initialized when {@link module:media/ActiveMediaPlayer.ActiveMediaPlayer#REC_ENABLED REC_ENABLED} is `true`.\n * @type {external:AudioBuffer[]} */\nActiveMediaPlayer.AUDIO_BUFFERS = ActiveMediaPlayer.REC_ENABLED ? [] : null;\n\nexport default ActiveMediaPlayer;\n","/**\n * File : media/MediaContent.js\n * Created : 13/04/2015\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\n/* global Image */\n\nimport $ from 'jquery';\nimport { Point } from '../AWT.js';\nimport { nSlash, attrForEach, getBoolean, getAttr, setAttr, svgToURI } from '../Utils.js';\n\nimport generic from './icons/generic.svg';\nimport audio from './icons/audio.svg';\nimport mic from './icons/mic.svg';\nimport movie from './icons/movie.svg';\nimport music from './icons/music.svg';\nimport url from './icons/url.svg';\n\n/**\n * This object contains a description of any multimedia content (sound, video, MIDI, voice\n * recording..) or special actions (jump to another point in the sequence, link to an URL, etc.)\n * associated to an {@link module:boxes/ActiveBox.ActiveBox ActiveBox} object.\n */\nexport class MediaContent {\n /**\n * MediaContent constructor\n * @param {string} type - The type of media. Valid values are: `UNKNOWN`, `PLAY_AUDIO`, `PLAY_VIDEO`,\n * `PLAY_MIDI`, `PLAY_CDAUDIO`, `RECORD_AUDIO`, `PLAY_RECORDED_AUDIO`, `RUN_CLIC_ACTIVITY`,\n * `RUN_CLIC_PACKAGE`, `RUN_EXTERNAL`, `URL`, `EXIT` and `RETURN`\n * @param {string} [file] - Optional parameter indicating the media file name\n */\n constructor(type, file) {\n this.type = type;\n if (file)\n this.file = file;\n }\n\n /**\n * Loads the MediaContent settings from a specific JQuery XML element\n * @param {external:jQuery} $xml\n */\n setProperties($xml) {\n attrForEach($xml.get(0).attributes, (name, val) => {\n switch (name) {\n case 'type':\n this.type = val;\n break;\n case 'file':\n this.file = nSlash(val);\n break;\n case 'params':\n this.externalParam = nSlash(val);\n break;\n\n case 'pFrom':\n this.absLocationFrom = val;\n break;\n\n case 'buffer':\n this.recBuffer = Number(val);\n break;\n case 'level':\n case 'from':\n case 'to':\n case 'length':\n this[name] = Number(val);\n break;\n\n case 'px':\n case 'py':\n if (this.absLocation === null)\n this.absLocation = new Point(0, 0);\n if (name === 'px')\n this.absLocation.x = Number(val);\n else\n this.absLocation.y = Number(val);\n break;\n\n case 'stretch':\n case 'free':\n case 'catchMouseEvents':\n case 'loop':\n case 'autostart':\n this[name] = getBoolean(val);\n break;\n }\n });\n return this;\n }\n\n /**\n * Gets a object with the basic attributes needed to rebuild this instance excluding functions,\n * parent references, constants and also attributes retaining the default value.\n * The resulting object is commonly usued to serialize elements in JSON format.\n * @returns {object} - The resulting object, with minimal attrributes\n */\n getAttributes() {\n return getAttr(this, [\n 'type', 'file', 'externalParam',\n 'absLocation', // -> AWT.Point\n 'absLocationFrom', 'recBuffer',\n 'level|1', 'from', 'to', 'length',\n 'stretch', 'free', 'catchMouseEvents', 'loop', 'autostart'\n ]);\n }\n\n /**\n * Reads the properties of this MediaContent from a data object\n * @param {object} data - The data object to be parsed\n * @returns {module:media/MediaContent.MediaContent}\n */\n setAttributes(data) {\n return setAttr(this, data, [\n 'type', 'file', 'externalParam',\n { key: 'absLocation', fn: Point },\n 'absLocationFrom', 'recBuffer',\n 'level', 'from', 'to', 'length',\n 'stretch', 'free', 'catchMouseEvents', 'loop', 'autostart',\n ]);\n }\n\n /**\n * Compares this object with another MediaContent.\n * @param {module:media/MediaContent.MediaContent} mc - The Media Content to compare against to.\n * @returns {boolean} - `true` when both objects are equivalent.\n */\n isEquivalent(mc) {\n return this.type === mc.type &&\n (this.file === mc.file ||\n this.file !== null && mc.file !== null &&\n this.file.toLocaleLowerCase() === mc.file.toLocaleLowerCase()) &&\n this.from === mc.from &&\n this.to === mc.to &&\n this.recBuffer === mc.recBuffer;\n }\n\n /**\n * Gets a string representing this media content, useful for checking if two different elements\n * are equivalent.\n * @returns {string}\n */\n getDescription() {\n let result = `${this.type}`;\n if (this.file)\n result = `${result} ${this.file}${this.from >= 0 ? ` from:${this.from}` : ''}${this.to >= 0 ? ` to:${this.to}` : ''}`;\n else if (this.externalParam)\n result = `${result} ${this.externalParam}`;\n return result;\n }\n\n /**\n * Returns a simplified description of this media content. Useful for accessibility methods.\n * @returns {string}\n */\n toString() {\n return `${this.type}${this.file ? ` ${this.file}` : ''}`;\n }\n\n /**\n * Returns an image to be used as icon for representing this media content.\n * @returns {external:HTMLImageElement}\n */\n getIcon() {\n let icon = null;\n switch (this.type) {\n case 'PLAY_AUDIO':\n case 'PLAY_RECORDED_AUDIO':\n icon = 'audio';\n break;\n case 'RECORD_AUDIO':\n icon = 'mic';\n break;\n case 'PLAY_VIDEO':\n icon = 'movie';\n break;\n case 'PLAY_MIDI':\n icon = 'music';\n break;\n case 'URL':\n icon = 'url';\n break;\n default:\n icon = 'generic';\n break;\n }\n return icon ? MediaContent.ICONS[icon] : null;\n }\n}\n\nObject.assign(MediaContent.prototype, {\n /**\n * The type of media. Valid values are: `UNKNOWN`, `PLAY_AUDIO`, `PLAY_VIDEO`,\n * `PLAY_MIDI`, `PLAY_CDAUDIO`, `RECORD_AUDIO`, `PLAY_RECORDED_AUDIO`, `RUN_CLIC_ACTIVITY`,\n * `RUN_CLIC_PACKAGE`, `RUN_EXTERNAL`, `URL`, `EXIT` and `RETURN`\n * @name module:media/MediaContent.MediaContent#type\n * @type {string} */\n type: 'UNKNOWN',\n /**\n * The priority level is important when different medias want to play together. Objects with\n * highest priority level can mute lower ones.\n * @name module:media/MediaContent.MediaContent#level\n * @type {number} */\n level: 1,\n /**\n * Media file name\n * @name module:media/MediaContent.MediaContent#file\n * @type {string} */\n file: null,\n /**\n * Optional parameters passed to external calls\n * @name module:media/MediaContent.MediaContent#externalParams\n * @type {string} */\n externalParam: null,\n /**\n * Special setting used to play only a fragment of media. `-1` means not used (plays full\n * length, from the beginning)\n * @name module:media/MediaContent.MediaContent#from\n * @type {number} */\n from: -1,\n /**\n * Special setting used to play only a fragment of media. `-1` means not used (plays to the end\n * of the media)\n * @name module:media/MediaContent.MediaContent#to\n * @type {number} */\n to: -1,\n /**\n * When `type` is `RECORD_AUDIO`, this member stores the maximum length of the recorded\n * sound, in seconds.\n * @name module:media/MediaContent.MediaContent#length\n * @type {number} */\n length: 3,\n /**\n * When `type` is `RECORD_AUDIO`, this member stores the buffer ID where the recording\n * will be stored.\n * @name module:media/MediaContent.MediaContent#recBuffer\n * @type {number} */\n recBuffer: 0,\n /**\n * Whether to stretch or not the video size to fit the cell space.\n * @name module:media/MediaContent.MediaContent#stretch\n * @type {boolean} */\n stretch: false,\n /**\n * When `true`, the video plays out of the cell, centered on the activity window.\n * @name module:media/MediaContent.MediaContent#free\n * @type {boolean} */\n free: false,\n /**\n * Places the video window at a specific location.\n * @name module:media/MediaContent.MediaContent#absLocation\n * @type {module:AWT.Point} */\n absLocation: null,\n /**\n * When {@link module:media/MediaContent.MediaContent#absLocation} is not `null`, this field indicates from where to\n * measure its coordinates. Valid values are: `BOX`, `WINDOW` or `FRAME`.\n * @name module:media/MediaContent.MediaContent#absLocationFrom\n * @type {string} */\n absLocationFrom: null,\n /**\n * `true` when the video window must catch mouse clicks.\n * @name module:media/MediaContent.MediaContent#catchMouseEvents\n * @type {boolean} */\n catchMouseEvents: false,\n /**\n * Whether to repeat the media in loop, or just one time.\n * @name module:media/MediaContent.MediaContent#loop\n * @type {boolean} */\n loop: false,\n /**\n * When `true`, the media will automatically start playing when the associated {@link module:boxes/ActiveBox.ActiveBox ActiveBox}\n * become active.\n * @name module:media/MediaContent.MediaContent#autoStart\n * @type {boolean} */\n autoStart: false,\n});\n\n/**\n * Default icons for media types.\n * @type {object} */\nconst ICONS = {\n generic,\n audio,\n movie,\n mic,\n music,\n url,\n};\n\n/**\n * Collection of icon {@link external:HTMLImageElement} objects\n * @name module:media/MediaContent.MediaContent.ICONS\n * @type {object} */\nMediaContent.ICONS = {};\n\n// Load the icons\n$.each(ICONS, (key, value) => {\n const img = new Image();\n img.src = svgToURI(value);\n MediaContent.ICONS[key] = img;\n});\n\nexport default MediaContent;\n","/**\n * File : media/EventSoundsElement.js\n * Created : 01/04/2015\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\n/* global Audio */\n\nimport { startsWith, getTriState, getAttr, setAttr, DEFAULT } from '../Utils.js';\nimport ActiveMediaPlayer from './ActiveMediaPlayer.js';\nimport MediaContent from './MediaContent.js';\n\n/**\n * The EventSoundsElement object contains the description of a specific sound to be played when\n * one of the JClic events are fired.\n * For a full list of the JClic events see: {@link module:media/EventSounds.EventSounds EventSounds}\n */\nexport class EventSoundsElement {\n /**\n * EventSoundsElement constructor\n * @param {string} id - The identifier of this media sound\n * @param {string} [file] - An optional file name or URL containing the sound data\n */\n constructor(id, file) {\n this.id = id;\n if (file) {\n if (startsWith(file, 'data:'))\n this.audio = new Audio(file);\n else\n this.file = file;\n }\n }\n\n /**\n * Reads the properties of this object from an XML element\n * @param {external:jQuery} $xml - The XML element to be parsed\n */\n setProperties($xml) {\n this.file = $xml.attr('file');\n this.enabled = getTriState($xml.attr('enabled'));\n return this;\n }\n\n /**\n * Gets a object with the basic attributes needed to rebuild this instance excluding functions,\n * parent references, constants and also attributes retaining the default value.\n * The resulting object is commonly usued to serialize elements in JSON format.\n * @returns {object} - The resulting object, with minimal attrributes\n */\n getAttributes() {\n return getAttr(this, [\n `enabled|${DEFAULT}`,\n 'file',\n ]);\n }\n\n /**\n * Reads the properties of this EventSoundsElement from a data object\n * @param {object} data - The data object to be parsed\n * @returns {module:media/EventSoundsElement.EventSoundsElement}\n */\n setAttributes(data) {\n return setAttr(this, data, [\n 'enabled',\n 'file',\n ]);\n }\n\n /**\n * Instantiates this audio object\n * @param {module:JClicPlayer.JClicPlayer} ps\n * @param {module:bags/MediaBag.MediaBag} mediaBag\n */\n realize(ps, mediaBag) {\n if (!this.audio && this.player === null && this.file !== null) {\n this.player = new ActiveMediaPlayer(new MediaContent('PLAY_AUDIO', this.file), mediaBag, ps);\n this.player.realize();\n }\n }\n\n /**\n * Plays the audio associated to this event\n */\n play() {\n if (this.enabled) {\n if (this.audio) {\n this.audio.currentTime = 0;\n this.audio.play();\n } else if (this.player)\n this.player.play();\n }\n }\n\n /**\n * Stops playing the audio associated to this event\n */\n stop() {\n if (this.enabled) {\n if (this.audio)\n this.audio.pause();\n else if (this.player)\n this.player.stop();\n }\n }\n}\n\nObject.assign(EventSoundsElement.prototype, {\n /**\n * The name of the sound file used by this element\n * @name module:media/EventSoundsElement.EventSoundsElement#file\n * @type {string} */\n file: null,\n /**\n * Whether the sound for this event is enabled or not\n * @name module:media/EventSoundsElement.EventSoundsElement#enabled\n * @type {number} */\n enabled: DEFAULT,\n /**\n * Media player used to play this sound\n * @name module:media/EventSoundsElement.EventSoundsElement#player\n * @type {module:media/ActiveMediaPlayer.ActiveMediaPlayer} */\n player: null,\n /**\n * HTMLAudioElement used to play this sound\n * @name module:media/EventSoundsElement.EventSoundsElement#audio\n * @type {external:HTMLAudioElement} */\n audio: null,\n});\n\nexport default EventSoundsElement;\n","/**\n * File : media/EventSounds.js\n * Created : 01/04/2015\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\nimport $ from 'jquery';\nimport EventSoundsElement from './EventSoundsElement.js';\nimport { getTriState, getAttr, setAttr, DEFAULT } from '../Utils.js';\n\n// Use Webpack to import MP3 files\nimport start from './sounds/start.mp3';\nimport click from './sounds/click.mp3';\nimport actionOk from './sounds/actionOk.mp3';\nimport actionError from './sounds/actionError.mp3';\nimport finishedOk from './sounds/finishedOk.mp3';\nimport finishedError from './sounds/finishedError.mp3';\n\n/**\n * The EventSounds objects contains specific sounds to be played when JClic events are fired:\n * - start\n * - click\n * - actionError\n * - actionOk\n * - finishedError\n * - finishedOk\n *\n * The sounds are stored in an array of {@link module:media/EventSoundsElement EventSoundsElement} objects.\n */\nexport class EventSounds {\n /**\n * EventSounds constructor\n * @param {module:media/EventSounds.EventSounds} [parent] - Another EventSounds object that will act as a parent of this one,\n * used to resolve which sound must be played for events when not defined here.\n */\n constructor(parent) {\n if (parent) {\n this.elements = Object.assign({}, this.elements, parent.elements);\n this.enabled = parent.enabled;\n }\n }\n\n /**\n * Reads the object properties from an XML element\n * @param {external:jQuery} $xml - The XML element to be parsed\n */\n setProperties($xml) {\n this.enabled = getTriState($xml.attr('enabled'), this.enabled);\n $xml.children().each((_n, child) => {\n const id = child.getAttribute('id');\n this.elements[id] = new EventSoundsElement(id);\n this.elements[id].setProperties($(child));\n });\n return this;\n }\n\n /**\n * Gets a object with the basic attributes needed to rebuild this instance excluding functions,\n * parent references, constants and also attributes retaining the default value.\n * The resulting object is commonly usued to serialize elements in JSON format.\n * @returns {object} - The resulting object, with minimal attrributes\n */\n getAttributes() {\n return getAttr(this, [\n `enabled|${DEFAULT}`,\n 'elements',\n ]);\n }\n\n /**\n * Reads the properties of this EventSounds from a data object\n * @param {object} data - The data object to be parsed\n * @returns {module:media/EventSounds.EventSounds}\n */\n setAttributes(data) {\n return setAttr(this, data, [\n 'enabled',\n { key: 'elements', fn: EventSoundsElement, group: 'object' },\n ]);\n }\n\n /**\n * Instantiates the audio objects needed to play event sounds\n * @param {module:JClicPlayer.JClicPlayer} ps\n * @param {module:bags/MediaBag.MediaBag} mediaBag\n */\n realize(ps, mediaBag) {\n // Values are {EventSoundElement} objects\n $.each(this.elements, (key, value) => value.realize(ps, mediaBag));\n }\n\n /**\n * Plays a specific event sound\n * @param {string} eventName - The identifier of the event to be played\n */\n play(eventName) {\n if (this.globalEnabled && this.enabled) {\n const sound = this.elements[eventName];\n if (sound && sound.enabled)\n sound.play();\n }\n }\n}\n\n/**\n * Audio data for default event sounds\n * @name module:media/EventSounds.EventSounds.MEDIA\n * @type {object} */\nEventSounds.MEDIA = {\n start,\n click,\n actionOk,\n actionError,\n finishedOk,\n finishedError,\n};\n\nObject.assign(EventSounds.prototype, {\n /**\n * Collection of {@link module:media/EventSoundsElement EventSoundsElement} objects\n * @name module:media/EventSounds.EventSounds#elements\n * @type {object} */\n elements: {\n start: new EventSoundsElement('start', EventSounds.MEDIA.start),\n click: new EventSoundsElement('click', EventSounds.MEDIA.click),\n actionOk: new EventSoundsElement('actionOk', EventSounds.MEDIA.actionOk),\n actionError: new EventSoundsElement('actionError', EventSounds.MEDIA.actionError),\n finishedOk: new EventSoundsElement('finishedOk', EventSounds.MEDIA.finishedOk),\n finishedError: new EventSoundsElement('finishedError', EventSounds.MEDIA.finishedError)\n },\n /**\n * Whether this event sounds are enabled or not\n * @name module:media/EventSounds.EventSounds#enabled\n * @type {number} */\n enabled: DEFAULT,\n /**\n * This attribute is intended to be used at prototype level, to indicate a globally disabled\n * or enabled state.\n * @name module:media/EventSounds.EventSounds#globalEnabled\n * @type {boolean} */\n globalEnabled: true,\n});\n\nexport default EventSounds;\n","/**\n * File : boxes/BoxBase.js\n * Created : 12/04/2015\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Catalan Educational Telematic Network (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\nimport $ from 'jquery';\nimport { settings, attrForEach, getBoolean, checkColor, getAttr, setAttr, cloneObject, isSeparator } from '../Utils.js';\nimport { Stroke, Gradient, Font, Dimension } from '../AWT.js';\n\nconst defaultValues = settings.BoxBase;\n\n/**\n * This class contains all the main visual attributes needed to draw {@link module:boxes/AbstractBox.AbstractBox AbstractBox} objects:\n * background and foreground colors, gradients, colors for special states (inactive, alternative,\n * disabled...), margins, fonts, border strokes, etc.\n *\n * Objects derived from {@link module:boxes/AbstractBox.AbstractBox AbstractBox} can have inheritance: boxes that act as \"containers\"\n * of other boxes (like {@link module:boxes/BoxBag.BoxBag BoxBag}). Most of the attributes of `BoxBase` can be `null`,\n * meaning that the value of the ancestor -or the default value if the box has no ancestors- must\n * be used.\n */\nexport class BoxBase {\n /**\n * BoxBase constructor\n * @param {module:boxes/BoxBase.BoxBase} [parent] - Another BoxBase object used to determine the value of properties not\n * locally set.\n */\n constructor(parent) {\n this.parent = parent || null;\n }\n\n /**\n * Loads the BoxBase settings from a specific JQuery XML element\n * @param {external:jQuery} $xml - The XML element to parse\n */\n setProperties($xml) {\n //\n // Read attributes\n attrForEach($xml.get(0).attributes, (name, val) => {\n switch (name) {\n case 'shadow':\n case 'transparent':\n this[name] = getBoolean(val, false);\n break;\n case 'margin':\n this[name] = Number(val);\n break;\n case 'borderStroke':\n this.borderStroke = new Stroke(Number(val));\n break;\n case 'markerStroke':\n this.markerStroke = new Stroke(Number(val));\n break;\n }\n });\n //\n // Read inner elements\n $xml.children().each((_n, child) => {\n const $node = $(child);\n switch (child.nodeName) {\n case 'font':\n this.font = (new Font()).setProperties($node);\n break;\n\n case 'gradient':\n this.bgGradient = new Gradient().setProperties($node);\n break;\n\n case 'color':\n this.textColor = checkColor($node.attr('foreground'), this.textColor);\n this.backColor = checkColor($node.attr('background'), this.backColor);\n this.shadowColor = checkColor($node.attr('shadow'), this.shadowColor);\n this.inactiveColor = checkColor($node.attr('inactive'), this.inactiveColor);\n this.alternativeColor = checkColor($node.attr('alternative'), this.alternativeColor);\n this.borderColor = checkColor($node.attr('border'), this.borderColor);\n break;\n }\n });\n return this;\n }\n\n /**\n * Gets a object with the basic attributes needed to rebuild this instance excluding functions,\n * parent references, constants and also attributes retaining the default value.\n * The resulting object is commonly usued to serialize elements in JSON format.\n * @returns {object} - The resulting object, with minimal attrributes\n */\n getAttributes() {\n return getAttr(this, [\n 'shadow', 'transparent', 'margin',\n 'borderStroke', 'markerStroke', // AWT.Stroke\n 'font', // AWT.Font\n 'bgGradient', // AWT.Gradient\n `textColor|${BoxBase.prototype.textColor}`,\n `backColor|${BoxBase.prototype.backColor}`,\n `shadowColor|${BoxBase.prototype.shadowColor}`,\n `inactiveColor|${BoxBase.prototype.inactiveColor}`,\n `alternativeColor|${BoxBase.prototype.alternativeColor}`,\n `borderColor|${BoxBase.prototype.borderColor}`,\n ]);\n }\n\n /**\n * Reads the properties of this BoxBase from a data object\n * @param {object} data - The data object to be parsed\n * @returns {module:boxes/BoxBase.BoxBase}\n */\n setAttributes(data) {\n return setAttr(this, data, [\n 'shadow', 'transparent', 'margin',\n { key: 'borderStroke', fn: Stroke },\n { key: 'markerStroke', fn: Stroke },\n { key: 'font', fn: Font },\n { key: 'bgGradient', fn: Gradient },\n 'textColor',\n 'backColor',\n 'shadowColor',\n 'inactiveColor',\n 'alternativeColor',\n 'borderColor',\n ]);\n }\n\n /**\n * Gets the value of the specified property, scanning down to parents and prototype if not defined.\n * @param {string} property - The property to retrieve\n * @returns {any} - The object or value associated to this property\n */\n get(property) {\n if (this.hasOwnProperty(property) || this.parent === null)\n return this[property];\n else\n return this.parent.get(property);\n }\n\n /**\n * Sets the value of a specific property.\n * @param {string} property - The property name.\n * @param {any} value - Depends on the type of property\n */\n set(property, value) {\n this[property] = value;\n return this;\n }\n\n /**\n * Gets the value of the specified property, scanning down to parents if not defined, and returning\n * always an own property (not from prototype)\n * @param {string} property - The property to retrieve\n * @returns {any} - The object or value associated to this property\n */\n getOwn(property) {\n if (this.hasOwnProperty(property))\n return this[property];\n else if (this.parent !== null)\n return this.parent.getOwn(property);\n else {\n if (typeof this[property] === 'object')\n this[property] = cloneObject(BoxBase.prototype[property]);\n else\n this[property] = BoxBase.prototype[property];\n }\n return this[property];\n }\n\n /**\n * Gets the properties defined in this BoxBase as a collection of CSS attributes\n * @param {object} [css] - An optional set of initial CSS properties\n * @param {boolean} [inactive=false] - When `true`, get CSS attributes for an inactive cell\n * @param {boolean} [inverse=false] - When `true`, get CSS attributes for an inverse cell\n * @param {boolean} [alternative=false] - When `true`, get CSS attributes for an alternative cell\n * @returns {object}\n */\n getCSS(css, inactive = false, inverse = false, alternative = false) {\n // (css will be created by [AWT.Font.toCss](AWT.html) if null or undefined)\n const font = this.get('font');\n css = font.toCss(css);\n\n css['color'] = inverse ? this.get('backColor')\n : alternative ? this.get('alternativeColor')\n : this.get('textColor');\n\n const transparent = this.get('transparent');\n css['background-color'] = transparent ? 'transparent'\n : inactive ? this.get('inactiveColor')\n : inverse ? this.get('textColor') : this.get('backColor');\n\n const bgGradient = this.get('bgGradient');\n if (bgGradient && !transparent)\n css['background-image'] = bgGradient.getCss();\n\n if (this.shadow === 1) {\n const delta = Math.max(1, Math.round(font.size / 10));\n const color = this.get('shadowColor');\n css['text-shadow'] = `${delta}px ${delta}px 3px ${color}`;\n }\n return css;\n }\n\n /**\n * This utility method computes the width and height of text lines rendered on an HTML\n * __canvas__ element, reducing the font size of the BoxBase as needed when they exceed the maximum\n * width and/or height.\n * @param {external:CanvasRenderingContext2D} ctx - The canvas rendering context used to draw the text.\n * @param {string} text - The text to drawn.\n * @param {number} maxWidth - Maximum width\n * @param {number} maxHeight - Maximum height\n * @returns {object[]} - An array of objects representing lines of text. Each object has a `text`\n * member with the text displayed in the line, and a `size` member with the line {@link module:AWT.Dimension}\n */\n prepareText(ctx, text, maxWidth, maxHeight) {\n const\n result = [],\n font = this.get('font'),\n height = font.getHeight();\n let totalHeight = 0;\n\n // divide the text in lines\n const lines = text.trim().split('\\n');\n ctx.font = font.cssFont();\n for (let l = 0; l < lines.length; l++) {\n let line = lines[l].trim();\n let width = ctx.measureText(line).width;\n if (width > maxWidth) {\n // retain the last string offset that was inside maxWidth\n let\n lastOK = 0,\n lastOKWidth = 0;\n for (let p = 0; p < line.length; p++) {\n // Find next separator\n if (isSeparator(line[p])) {\n const w = ctx.measureText(line.substring(0, p).trim()).width;\n if (w > maxWidth)\n break;\n lastOK = p;\n lastOKWidth = w;\n }\n }\n if (lastOK > 0) {\n // Add a new line with the tail of the line\n lines.splice(l + 1, 0, line.substring(lastOK + 1).trim());\n // Adjust the current line\n line = lines[l] = line.substring(0, lastOK).trim();\n width = lastOKWidth;\n }\n else {\n // No solution found. Try resizing down the font.\n if (font.size > defaultValues.MIN_FONT_SIZE) {\n this.getOwn('font').zoom(-1);\n return this.prepareText(ctx, text, maxWidth, maxHeight);\n }\n }\n }\n\n // Add the line and the calculated dimension to `result`\n result.push({\n text: line,\n size: new Dimension(width, height)\n });\n\n totalHeight += height;\n\n if (totalHeight > maxHeight && font.size > defaultValues.MIN_FONT_SIZE) {\n // Max height exceeded. Try resizing down the font\n this.getOwn('font').zoom(-1);\n return this.prepareText(ctx, text, maxWidth, maxHeight);\n }\n }\n return result;\n }\n}\n\nObject.assign(BoxBase.prototype, {\n /**\n * The parent BoxBase object\n * @name module:boxes/BoxBase.BoxBase#parent\n * @type {module:boxes/BoxBase.BoxBase} */\n parent: null,\n /**\n * Default values\n * @name module:boxes/BoxBase.BoxBase#defaultValues\n * @type {object} */\n default: defaultValues,\n /**\n * Font size can be dynamically reduced to fit the available space if any element using this\n * `BoxBase` requests it. When this happen, this field contains the real font currently used\n * to draw text.\n * @name module:boxes/BoxBase.BoxBase#font\n * @type {module:AWT.Font} */\n font: new Font(),\n /**\n * The current font size of this BoxBase. Can be dynamically adjusted when drawing.\n * @name module:boxes/BoxBase.BoxBase#dynFontSize\n * @type {number} */\n dynFontSize: 0,\n /**\n * Counts the number of times the `dynFontSize` has been reset. This is useful to avoid excessive\n * recursive loops searching the optimal font size.\n * @name module:boxes/BoxBase.BoxBase#resetFontCounter\n * @type {number} */\n resetFontCounter: 0,\n /**\n * The background color\n * @name module:boxes/BoxBase.BoxBase#backColor\n * @type {string} */\n backColor: defaultValues.BACK_COLOR,\n /**\n * The background gradient. Default is `null`.\n * @name module:boxes/BoxBase.BoxBase#bgGradient\n * @type {module:AWT.Gradient} */\n bgGradient: null,\n /**\n * The color used to write text.\n * @name module:boxes/BoxBase.BoxBase#textColor\n * @type {string} */\n textColor: defaultValues.TEXT_COLOR,\n /**\n * The color used to draw a shadow below regular text.\n * @name module:boxes/BoxBase.BoxBase#shadowColor\n * @type {string} */\n shadowColor: defaultValues.SHADOW_COLOR,\n /**\n * The color of the border.\n * @name module:boxes/BoxBase.BoxBase#borderColor\n * @type {string} */\n borderColor: defaultValues.BORDER_COLOR,\n /**\n * The color used to draw text when a cell is in `inactive` state.\n * @name module:boxes/BoxBase.BoxBase#inactiveColor\n * @type {string} */\n inactiveColor: defaultValues.INACTIVE_COLOR,\n /**\n * The color used to draw text when a cell is in `alternative` state.\n * @name module:boxes/BoxBase.BoxBase#alternativeColor\n * @type {string} */\n alternativeColor: defaultValues.ALTERNATIVE_COLOR,\n /**\n * Whether the text should have a shadow or not\n * @name module:boxes/BoxBase.BoxBase#shadow\n * @type {boolean} */\n shadow: false,\n /**\n * Whether the cell's background (and its hosted component, if any) should be transparent\n * @name module:boxes/BoxBase.BoxBase#transparent\n * @type {boolean} */\n transparent: false,\n /**\n * Wheter the cell's background should be painted or not. This property has no effect on\n * hosted components.\n * @name module:boxes/BoxBase.BoxBase#dontFill\n * @type {boolean} */\n dontFill: false,\n /**\n * The margin to respect between text elements and the limits of the cell or other elements.\n * @name module:boxes/BoxBase.BoxBase#textMargin\n * @type {number} */\n textMargin: defaultValues.AC_MARGIN,\n /**\n * The stroke used to draw the border.\n * @name module:boxes/BoxBase.BoxBase#borderStroke\n * @type {module:AWT.Stroke} */\n borderStroke: new Stroke(defaultValues.BORDER_STROKE_WIDTH),\n /**\n * The stroke used to draw a border around marked cells.\n * @name module:boxes/BoxBase.BoxBase#markerStroke\n * @type {module:AWT.Stroke} */\n markerStroke: new Stroke(defaultValues.MARKER_STROKE_WIDTH),\n});\n\nBoxBase.DEFAULT_BOX_BASE = new BoxBase();\n\nexport default BoxBase;\n","/**\n * File : boxes/ActiveBoxContent.js\n * Created : 13/04/2015\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Catalan Educational Telematic Network (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\nimport $ from 'jquery';\nimport { Dimension } from '../AWT.js';\nimport { getAttr, setAttr, attrForEach, getBoolean, nSlash, startsWith, getMsg } from '../Utils.js';\nimport BoxBase from './BoxBase.js';\nimport MediaContent from '../media/MediaContent.js';\n\n/**\n * This class is used as a container for horizontal and vertical alignments of content inside a cell.\n */\nexport class AlignType {\n /**\n * AlignType constructor\n * @param {string} [h] - Horizontal alignment. Possible values are `left`, `center` and `right`\n * @param {string} [v] - Vertical alignment. Possible values are `top`, `center` and `bottom`\n */\n constructor(h, v) {\n if (h)\n this.h = h;\n if (v)\n this.v = v;\n }\n\n /**\n * Gets a object with the basic attributes needed to rebuild this instance excluding functions,\n * parent references, constants and also attributes retaining the default value.\n * The resulting object is commonly usued to serialize elements in JSON format.\n * @returns {object} - The resulting object, with minimal attrributes\n */\n getAttributes() {\n return getAttr(this, ['h|center', 'v|center']);\n }\n\n /**\n * Reads the properties of this AlignType from a data object\n * @param {object} data - The data object to be parsed\n * @returns {module:boxes/ActiveBoxContent.AlignType}\n */\n setAttributes(data) {\n return setAttr(this, data, ['h', 'v']);\n }\n}\n\nObject.assign(AlignType.prototype, {\n h: 'center',\n v: 'center',\n});\n\n/**\n * This class defines a content that can be displayed by {@link module:boxes/ActiveBox.ActiveBox ActiveBox} objects. This content\n * can be a text, an image, a fragment of an image or a combination of text and images. The style\n * (colors, font and size, borders, shadows, margins, etc.) are specified in the `style` attribute,\n * always pointing to a {@link module:boxes/BoxBase.BoxBase BoxBase} object.\n */\nexport class ActiveBoxContent {\n /**\n * ActiveBoxContent constructor\n * @param {string} [id] - An optional identifier.\n */\n constructor(id) {\n if (typeof id !== 'undefined')\n this.id = id;\n this.imgAlign = new AlignType();\n this.txtAlign = new AlignType();\n }\n\n /**\n *\n * Loads settings from a specific JQuery XML element\n * @param {external:jQuery} $xml - The XML element to be parsed\n * @param {module:bags/MediaBag.MediaBag} mediaBag - The media bag used to retrieve images and other media\n */\n setProperties($xml, mediaBag) {\n //\n // Read attributes\n attrForEach($xml.get(0).attributes, (name, val) => {\n switch (name) {\n case 'id':\n case 'item':\n this[name] = Number(val);\n break;\n\n case 'width':\n case 'height':\n if (this.dimension === null)\n this.dimension = new Dimension(0, 0);\n this.dimension[name] = Number(val);\n break;\n\n case 'txtAlign':\n case 'imgAlign':\n this[name] = this.readAlign(val);\n break;\n\n case 'hAlign':\n // Old style\n this['txtAlign'] = this.readAlign(val + ',center');\n this['imgAlign'] = this.readAlign(val + ',center');\n break;\n\n case 'border':\n case 'avoidOverlapping':\n this[name] = getBoolean(val);\n break;\n\n case 'image':\n this.image = nSlash(val);\n break;\n }\n });\n\n //\n // Read inner elements\n $xml.children().each((_n, child) => {\n const $node = $(child);\n switch (child.nodeName) {\n case 'style':\n this.style = new BoxBase(null).setProperties($node);\n break;\n case 'media':\n this.mediaContent = new MediaContent().setProperties($node);\n break;\n case 'p':\n if (this.text === null)\n this.text = '';\n else\n this.text += '\\n';\n this.text += child.textContent;\n break;\n }\n });\n\n if (mediaBag)\n this.realizeContent(mediaBag);\n\n return this;\n }\n\n /**\n * Gets a object with the basic attributes needed to rebuild this instance excluding functions,\n * parent references, constants and also attributes retaining the default value.\n * The resulting object is commonly usued to serialize elements in JSON format.\n * @returns {object} - The resulting object, with minimal attrributes\n */\n getAttributes() {\n return getAttr(this, [\n 'id', 'item', 'dimension', 'border', 'avoidOverlapping', 'image', 'text',\n 'objectType', // Used in TextActivityDocument\n 'txtAlign', 'imgAlign', // AlignType\n 'style', // BoxBase\n 'mediaContent', // MediaContent\n ]);\n }\n\n /**\n * Reads the properties of this ActiveBoxContent from a data object\n * @param {object|string} data - The data object to be parsed, or just the text content\n * @param {module:bags/MediaBag.MediaBag} mediaBag - The media bag used to retrieve images and other media\n * @returns {module:boxes/ActiveBoxContent.ActiveBoxContent}\n */\n setAttributes(data, mediaBag) {\n\n if (typeof data === 'string')\n this.text = data;\n else\n setAttr(this, data, [\n 'id', 'item', 'border', 'avoidOverlapping', 'image', 'text',\n 'objectType',\n { key: 'dimension', fn: Dimension },\n { key: 'txtAlign', fn: AlignType },\n { key: 'imgAlign', fn: AlignType },\n { key: 'style', fn: BoxBase },\n { key: 'mediaContent', fn: MediaContent },\n ]);\n\n if (mediaBag)\n this.realizeContent(mediaBag);\n\n return this;\n }\n\n /**\n * Decode expressions with combined values of horizontal and vertical alignments in the form:\n * \"(left|middle|right),(top|middle|bottom)\"\n * @param {string} str - The string to parse\n * @returns {module:boxes/ActiveBoxContent.ActiveBoxContent~alignType}\n */\n readAlign(str) {\n const align = new AlignType();\n if (str) {\n const v = str.split(',');\n align.h = v[0].replace('middle', 'center');\n align.v = v[1].replace('middle', 'center');\n }\n return align;\n }\n\n /**\n * Checks if this is an empty content (`text` and `img` are _null_)\n */\n isEmpty() {\n return this.text === null && this.img === null;\n }\n\n /**\n * Checks if two contents are equivalent\n * @param {module:boxes/ActiveBoxContent.ActiveBoxContent} abc - The content to compare with this.\n * @param {boolean} checkCase - When `true` the comparing will be case-sensitive.\n * @returns {boolean}\n */\n isEquivalent(abc, checkCase) {\n if (abc === this)\n return true;\n let result = false;\n if (abc !== null) {\n if (this.isEmpty() && abc.isEmpty())\n result = this.id === abc.id;\n else\n result = (this.text === null ? abc.text === null\n : checkCase ? this.text === abc.text\n : this.text.toLocaleLowerCase() === abc.text.toLocaleLowerCase()\n ) &&\n (this.mediaContent === null ? abc.mediaContent === null\n : this.mediaContent.isEquivalent(abc.mediaContent)\n ) &&\n this.img === abc.img &&\n (this.imgClip === null ? abc.imgClip === null\n : this.imgClip.equals(abc.imgClip));\n }\n return result;\n }\n\n /**\n * Sets the text content of this ActiveBox\n * @param {string} tx\n */\n setTextContent(tx) {\n // only plain text allowed!\n if (tx !== null) {\n this.text = tx;\n this.checkHtmlText();\n } else {\n this.text = null;\n this.innerHtmlText = null;\n }\n }\n\n /**\n * Checks if cell's text uses HTML, initializing the `innerHtmlText` member as needed.\n */\n checkHtmlText() {\n this.innerHtmlText = null;\n if (startsWith(this.text, '<html>', true)) {\n const htmlText = this.text.trim();\n const s = htmlText.toLocaleLowerCase();\n if (s.indexOf('<body') === -1) {\n const s2 = s.indexOf('</html>');\n if (s2 >= 0)\n this.innerHtmlText = htmlText.substring(6, s2);\n }\n }\n }\n\n /**\n * Sets a fragment of a main image as a graphic content of this cell.\n * Cells cannot have two graphic contents, so `image` (the specific image of this cell) should\n * be cleared with this setting.\n * @param {external:HTMLImageElement} img - The image data\n * @param {module:AWT.Shape} imgClip - A shape that clips the portion of image assigned to this content.\n * @param {string} [animatedGifFile] - When `img` is an animated GIF, its file name\n */\n setImgContent(img, imgClip, animatedGifFile) {\n this.img = img;\n this.image = null;\n this.imgClip = imgClip;\n if (animatedGifFile)\n this.animatedGifFile = animatedGifFile;\n }\n\n /**\n * Prepares the media content\n * @param {module:JClicPlayer.JClicPlayer} playStation - Usually a {@link module:JClicPlayer.JClicPlayer JClicPlayer}\n */\n prepareMedia(playStation) {\n if (!this.amp && this.mediaContent && this.mediaContent.type === 'PLAY_VIDEO') {\n this.amp = playStation.getActiveMediaPlayer(this.mediaContent);\n this.amp.realize();\n }\n }\n\n /**\n * Reads and initializes the image associated to this content\n * @param {module:bags/MediaBag.MediaBag} mediaBag - The media bag of the current project.\n */\n realizeContent(mediaBag, ps = null) {\n if (this.image !== null && this.image.length > 0) {\n this.mbe = mediaBag.getElement(this.image, true);\n if (this.mbe) {\n this.mbe.build(() => {\n this.img = this.mbe.data;\n this.animatedGifFile = this.mbe.animated ? this.mbe.getFullPath() : null;\n }, ps, true);\n }\n }\n if (this.mediaContent !== null) {\n if (this.image === null && (this.text === null || this.text.length === 0)) {\n this.img = this.mediaContent.getIcon();\n this.animatedGifFile = null;\n }\n }\n this.checkHtmlText(mediaBag);\n }\n\n /**\n * Gets a string representing this content, useful for checking if two different contents are\n * equivalent.\n * @returns {string}\n */\n getDescription() {\n const result = [];\n if (this.text && this.text.length)\n result.push(this.text);\n if (this.image)\n result.push(`${getMsg('image')} ${this.image}`);\n if (this.imgClip)\n result.push(this.imgClip.toString());\n if (this.mediaContent)\n result.push(this.mediaContent.getDescription());\n return result.join(' ');\n }\n\n /**\n *\n * Overwrites the original `Object.toString` method, returning `getDescription` instead\n * @returns {string}\n */\n toString() {\n const result = [];\n if (this.text && this.text.length)\n result.push(this.text);\n if (this.image)\n result.push(`${getMsg('image')} ${this.image}`);\n if (this.imgClip)\n result.push(`${getMsg('image fragment')} ${(this.id >= 0 ? this.id : this.item) + 1}`);\n return result.join(' ') || getMsg('cell');\n }\n}\n\nObject.assign(ActiveBoxContent.prototype, {\n /**\n * The {@link module:boxes/BoxBase.BoxBase BoxBase} attribute of this content. Can be `null`, meaning {@link module:boxes/ActiveBox.ActiveBox ActiveBox} will\n * try to find a suitable style scanning down through its own BoxBase, their parent's and, finally,\n * the default values defined in `BoxBase.prototype`.\n * @name module:boxes/ActiveBoxContent.ActiveBoxContent#style\n * @type {module:boxes/BoxBase.BoxBase} */\n style: null,\n /**\n * Optimal dimension of any {@link module:boxes/ActiveBox.ActiveBox ActiveBox} taking this content.\n * @name module:boxes/ActiveBoxContent.ActiveBoxContent#dimension\n * @type {module:AWT.Dimension} */\n dimension: null,\n /**\n * The {@link module:boxes/ActiveBox.ActiveBox ActiveBox} can have or not a border despite the settings of {@link module:boxes/BoxBase.BoxBase BoxBase}.\n * The default value `null` means not to take in consideration this setting.\n * @name module:boxes/ActiveBoxContent.ActiveBoxContent#border\n * @type {boolean|null} */\n border: null,\n /**\n * The text to display on the {@link module:boxes/ActiveBox.ActiveBox ActiveBox}. It can have up to two paragraphs.\n * @name module:boxes/ActiveBoxContent.ActiveBoxContent#text\n * @type {string} */\n text: null,\n /**\n * The name of the image file to display on the {@link module:boxes/ActiveBox.ActiveBox ActiveBox}.\n * @name module:boxes/ActiveBoxContent.ActiveBoxContent#image\n * @type {string} */\n image: null,\n /**\n * An optional shape used to clip the image.\n * @name module:boxes/ActiveBoxContent.ActiveBoxContent#imgClip\n * @type {module:AWT.Shape} */\n imgClip: null,\n /**\n * The media content associated with this object.\n * @name module:boxes/ActiveBoxContent.ActiveBoxContent#mediaContent\n * @type {module:media/MediaContent.MediaContent} */\n mediaContent: null,\n /**\n * @typedef ActiveBoxContent~alignType\n * @type {object}\n * @property {string} h - Valid values are: `left`, `middle`, `right`\n * @property {string} v - Valud values are: `top`, `middle`, `bottom` */\n /**\n * The horizontal and vertical alignment of the image inside the cell.\n * @name module:boxes/ActiveBoxContent.ActiveBoxContent#imgAlign\n * @type {module:boxes/ActiveBoxContent.AlignType} */\n imgAlign: null,\n /**\n * The horizontal and vertical alignment of the text inside the cell.\n * Valid values are: `left`, `middle`, `right`, `top` and `bottom`.\n * @name module:boxes/ActiveBoxContent.ActiveBoxContent#txtAlign\n * @type {module:boxes/ActiveBoxContent.AlignType} */\n txtAlign: null,\n /**\n * Whether to avoid overlapping of image and text inside the cell when both are present.\n * @name module:boxes/ActiveBoxContent.ActiveBoxContent#avoidOverlapping\n * @type {boolean} */\n avoidOverlapping: false,\n /**\n * Numeric identifier used in activities to resolve relationships between cells\n * @name module:boxes/ActiveBoxContent.ActiveBoxContent#id\n * @type {number} */\n id: -1,\n /**\n * Numeric identifier used in activities to resolve relationships between cells\n * @name module:boxes/ActiveBoxContent.ActiveBoxContent#item\n * @type {number} */\n item: -1,\n //\n // Transient properties build and modified at run-time\n /**\n * The realized image used by this box content.\n * @name module:boxes/ActiveBoxContent.ActiveBoxContent#img\n * @type {external:HTMLImageElement} */\n img: null,\n /**\n * When `img` is an animated GIF file, this field should contain its file name\n * @name module:boxes/ActiveBoxContent.ActiveBoxContent#animatedGifFile\n * @type {string} */\n animatedGifFile: null,\n /**\n * When not null, this content should be treated as an HTML element\n * @name module:boxes/ActiveBoxContent.ActiveBoxContent#innerHtmlText\n * @type {string} */\n innerHtmlText: null,\n /**\n * The {@link module:media/ActiveMediaPlayer.ActiveMediaPlayer ActiveMediaPlayer} associated with this content. Updated at run-time.\n * @name module:boxes/ActiveBoxContent.ActiveBoxContent#amp\n * @type {module:media/ActiveMediaPlayer.ActiveMediaPlayer} */\n amp: null,\n /**\n * The {@link module:bads/MediaBagElement.MediaBagElement} associated with this content, if any. Updated at run-time.\n * @name module:boxes/ActiveBoxContent.ActiveBoxContent#mbe\n * @type {module:bags/MediaBagElement.MediaBagElement} */\n mbe: null,\n});\n\n/**\n * An empty ActiveBoxContent\n * @type {module:boxes/ActiveBoxContent.ActiveBoxContent}\n */\nActiveBoxContent.EMPTY_CONTENT = new ActiveBoxContent();\n\nexport default ActiveBoxContent;\n","/**\n * File : shapers/Shaper.js\n * Created : 13/04/2015\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\nimport $ from 'jquery';\nimport { log, attrForEach, getBoolean, getAttr, setAttr } from '../Utils.js';\nimport { Shape, Rectangle, Ellipse, PathStroke, Path } from '../AWT.js';\n\n/**\n * The function of this class and its subclasses is to draw a set of \"shapes\" that will be used to\n * place {@link module:boxes/ActiveBox.ActiveBox ActiveBox} objects at a specific position, and to determine its dimension and\n * appearance.\n */\nexport class Shaper {\n /**\n * Shaper constructor\n * @param {number} nx - Number of columns (in grid-based shapers)\n * @param {number} ny - Number of rows (in grid-based shapers)\n */\n constructor(nx, ny) {\n this.reset(nx, ny);\n }\n\n /**\n * Registers a new type of shaper\n * @param {string} shaperName - The name used to identify this shaper\n * @param {function} shaperClass - The shaper class, usually extending Shaper\n * @returns {module:shapers/Shaper.Shaper} - The provided shaper class\n */\n static registerClass(shaperName, shaperClass) {\n Shaper.CLASSES[shaperName] = shaperClass;\n return shaperClass;\n }\n\n /**\n * Factory constructor that returns a Shaper of the requested class.\n * @param {string} className - The class name of the requested Shaper.\n * @param {number} nx - Number of columns (in grid-based shapers)\n * @param {number} ny - Number of rows (in grid-based shapers)\n * @returns {module:shapers/Shaper.Shaper}\n */\n static getShaper(className, nx, ny) {\n const cl = Shaper.CLASSES[(className || '').replace(/^edu\\.xtec\\.jclic\\.shapers\\./, '@')];\n if (!cl)\n log('error', `Unknown shaper: ${className}`);\n return cl ? new cl(nx, ny) : null;\n }\n\n /**\n * Initializes this Shaper to default values\n * @param {number} nCols - Number of columns\n * @param {number} nRows - Number of rows\n */\n reset(nCols, nRows) {\n this.nCols = nCols;\n this.nRows = nRows;\n this.nCells = nRows * nCols;\n this.initiated = false;\n this.shapeData = [];\n for (let i = 0; i < this.nCells; i++)\n this.shapeData[i] = new Shape();\n }\n\n /**\n * Loads this shaper settings from a specific JQuery XML element\n * @param {external:jQuery} $xml - The XML element with the shaper data\n */\n setProperties($xml) {\n attrForEach($xml.get(0).attributes, (name, value) => {\n switch (name) {\n case 'class':\n this.className = value;\n break;\n case 'cols':\n this.nCols = Number(value);\n break;\n case 'rows':\n this.nRows = Number(value);\n break;\n case 'baseWidthFactor':\n case 'toothHeightFactor':\n case 'scaleX':\n case 'scaleY':\n this[name] = Number(value);\n break;\n case 'randomLines':\n case 'showEnclosure':\n this[name] = getBoolean(value, true);\n break;\n }\n });\n\n // Reads the 'enclosing'\n // (main shape area where the other shape elements are placed)\n $xml.children('enclosing:first').each((_n, child) => {\n $(child).children('shape:first').each((_n, child2) => {\n let sh = Shaper.readShapeData(child2, this.scaleX, this.scaleY);\n this.enclosing = sh;\n this.showEnclosure = true;\n this.hasRemainder = true;\n });\n });\n\n // Read the shape elements\n $xml.children('shape').each((n, child) => {\n this.shapeData[n] = Shaper.readShapeData(child, this.scaleX, this.scaleY);\n });\n\n // Correction needed for '@Holes' shaper\n if (this.shapeData.length > 0 /* && this.shapeData.length !== this.nRows * this.nCols */) {\n //this.nRows = this.shapeData.length\n //this.nCols = 1\n //this.nCells = this.nCols * this.nRows\n this.nCells = this.shapeData.length;\n }\n return this;\n }\n\n /**\n * Reads an individual shape from an XML element.\n * Shapes are arrays of `stroke` objects.\n * Each `stroke` has an `action` (_move to_, _line to_, _quad to_...) and associated `data`.\n * @param {external:jQuery} $xml - The XML element with the shape data\n * @param {number} scaleX\n * @param {number} scaleY\n * @returns {module:AWT.Shape}\n */\n static readShapeData(xml, scaleX, scaleY) {\n const shd = [];\n let result = null;\n $.each(xml.textContent.split('|'), (_n, txt) => {\n const sd = txt.split(':');\n // Possible strokes are: `rectangle`, `ellipse`, `M`, `L`, `Q`, `B`, `X`\n // Also possible, but not currently used in JClic: `roundRectangle` and `pie`\n let data = sd.length > 1 ? sd[1].split(',') : null;\n //\n // Data should be always divided by the scale (X or Y)\n if (data)\n data = data.map((d, n) => d / (n % 2 ? scaleY : scaleX));\n\n switch (sd[0]) {\n case 'rectangle':\n result = new Rectangle(data[0], data[1], data[2], data[3]);\n break;\n case 'ellipse':\n result = new Ellipse(data[0], data[1], data[2], data[3]);\n break;\n default:\n // It's an `AWT.PathStroke`\n shd.push(new PathStroke(sd[0], data));\n break;\n }\n });\n\n return !result && shd.length > 0 ? new Path(shd) : result;\n }\n\n /**\n * Gets a object with the basic attributes needed to rebuild this instance excluding functions,\n * parent references, constants and also attributes retaining the default value.\n * The resulting object is commonly usued to serialize elements in JSON format.\n * @returns {object} - The resulting object, with minimal attrributes\n */\n getAttributes() {\n const fields = [\n 'className', 'nCols', 'nRows',\n 'baseWidthFactor', 'toothHeightFactor',\n 'scaleX', 'scaleY',\n 'randomLines',\n ];\n\n if (this.customShapes) {\n ['showEnclosure', 'hasRemainder',\n 'enclosing', 'shapeData', // Array of AWT.Rectangle, AWT.Ellipse or (AWT.Path -> AWT.PathStroke)\n ].forEach(f => fields.push(f));\n }\n\n return getAttr(this, fields);\n }\n\n /**\n * Builds a new shaper, based on the properties specified in a data object\n * @param {object} data - The data object to be parsed\n * @returns {module:shapers/Shaper.Shaper}\n */\n static factory(data) {\n const result = Shaper.getShaper(data.className, data.nCols, data.nRows);\n setAttr(result, data, [\n 'className', 'nCols', 'nRows',\n 'baseWidthFactor', 'toothHeightFactor',\n 'scaleX', 'scaleY',\n 'randomLines',\n 'showEnclosure', 'hasRemainder',\n { key: 'enclosing', fn: Shape },\n { key: 'shapeData', fn: Shape, group: 'array' },\n ]);\n\n result.nCells = result.shapeData.length || result.nCols * result.nRows;\n\n return result;\n }\n\n /**\n * Builds the individual shapes that will form this Shaper\n */\n buildShapes() {\n }\n\n /**\n * Gets a clone of the nth Shape object, scaled and located inside a Rectangle\n * @param {number} n\n * @param {module:AWT.Rectangle} rect\n * @returns {module:AWT.Shape}\n */\n getShape(n, rect) {\n if (!this.initiated)\n this.buildShapes();\n if (n >= this.nCells || this.shapeData[n] === null)\n return null;\n return this.shapeData[n].getShape(rect);\n }\n\n /**\n * Gets the nth Shape data object\n * @param {number} n\n * @returns {object}\n */\n getShapeData(n) {\n return n >= 0 && n < this.shapeData.length ? this.shapeData[n] : null;\n }\n\n /**\n * Gets the AWT.Rectangle that contains all shapes of this Shaper.\n * @returns {module:AWT.Rectangle}\n */\n getEnclosingShapeData() {\n return new Rectangle(0, 0, 1, 1);\n }\n\n /**\n * When `hasRemainder` is true, this method gets the rectangle containing the full surface where\n * the Shaper develops.\n * @param {module:AWT.Rectangle} rect - The frame where to move and scale all the shapes\n * @returns {module:AWT.Rectangle}\n */\n getRemainderShape(rect) {\n if (!this.hasRemainder)\n return null;\n\n if (!this.initiated)\n this.buildShapes();\n\n const sh = this.getEnclosingShapeData();\n const r = sh ? sh.getShape(rect) : new Rectangle();\n for (let i = 0; i < this.nCells; i++) {\n if (this.shapeData[i])\n r.add(this.shapeData[i].getShape(rect), false);\n }\n return r;\n }\n}\n\nObject.assign(Shaper.prototype, {\n /**\n * This shaper class name\n * @name module:shapers/Shaper.Shaper#className\n * @type {string} */\n className: 'Shaper',\n /**\n * Number of columns (useful in grid-based shapers)\n * @name module:shapers/Shaper.Shaper#nCols\n * @type {number} */\n nCols: 0,\n /**\n * Number of rows (useful in grid-based shapers)\n * @name module:shapers/Shaper.Shaper#nRows\n * @type {number} */\n nRows: 0,\n /**\n * Number of cells managed by this shaper\n * @name module:shapers/Shaper.Shaper#nCells\n * @type {number} */\n nCells: 0,\n /**\n * Contains the specific definition of each shape\n * @name module:shapers/Shaper.Shaper#shapeData\n * @type {object} */\n shapeData: null,\n /**\n * Flag used to check if the `Shaper` has been initialized against a real surface\n * @name module:shapers/Shaper.Shaper#initiated\n * @type {boolean} */\n initiated: false,\n //\n // Fields used only in JigSaw shapers\n /**\n * In {@link module:shapers/JigSaw.JigSaw JigSaw}, ratio between the base width of the tooth and the total length of the side.\n * @name module:shapers/Shaper.Shaper#baseWidthFactor\n * @type {number} */\n baseWidthFactor: 1.0 / 3,\n /**\n * In {@link module:shapers/JigSaw.JigSaw JigSaw}, ratio between the tooth height and the total length of the side.\n * @name module:shapers/Shaper.Shaper#toothHeightFactor\n * @type {number} */\n toothHeightFactor: 1.0 / 6,\n /**\n * In {@link module:shapers/JigSaw.JigSaw JigSaw}, whether the tooths take random directions or not\n * @name module:shapers/Shaper.Shaper#randomLines\n * @type {boolean} */\n randomLines: false,\n //\n // Fields used only in the `Holes` shaper\n /**\n * In {@link module:shapers/Holes.Holes Holes}, scale to be applied to horizontal positions and lengths to achieve the real\n * value of the shape placed on a real surface.\n * @name module:shapers/Shaper.Shaper#scaleX\n * @type {number} */\n scaleX: 1.0,\n /**\n * In {@link module:shapers/Holes.Holes Holes}, scale to be applied to vertical positions and lengths to achieve the real\n * value of the shape placed on a real surface.\n * @name module:shapers/Shaper.Shaper#scaleY\n * @type {number} */\n scaleY: 1.0,\n /**\n * In {@link module:shapers/Holes.Holes Holes}, the enclosing area where all shapes are placed.\n * @name module:shapers/Shaper.Shaper#enclosing\n * @type {module:AWT.Shape} */\n enclosing: null,\n /**\n * In {@link module:shapers/Holes.Holes Holes}, when `true`, the enclosing area will be drawn\n * @name module:shapers/Shaper.Shaper#showEnclosure\n * @type {boolean} */\n showEnclosure: false,\n /**\n * Flag indicating if this shaper organizes its cells in rows and columns\n * @name module:shapers/Shaper.Shaper#rectangularShapes\n * @type {boolean} */\n rectangularShapes: false,\n /**\n * Flag indicating if this Shaper deploys over a surface biggest than the rectangle enclosing\n * all its shapes\n * @name module:shapers/Shaper.Shaper#hasRemainder\n * @type {boolean} */\n hasRemainder: false,\n /**\n * Only the `Holes` shaper has this flag activated\n * @name module:shapers/Shaper.Shaper#customShapes\n * @type {boolean} */\n customShapes: false,\n});\n\n/**\n * List of known classes derived from Shaper. It should be filled by real shaper classes at\n * declaration time.\n * @type {object} */\nShaper.CLASSES = {};\n\nexport default Shaper;\n","/**\n * File : boxes/ActiveBagContent.js\n * Created : 13/04/2015\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\nimport $ from 'jquery';\nimport BoxBase from './BoxBase.js';\nimport ActiveBoxContent from './ActiveBoxContent.js';\nimport Shaper from '../shapers/Shaper.js';\nimport { Rectangle } from '../AWT.js';\nimport { settings, attrForEach, nSlash, getBoolean, getAttr, setAttr } from '../Utils.js';\n\n/**\n * This class packs a collection of {@link module:boxes/ActiveBoxContent.ActiveBoxContent ActiveBoxContent} objects and provides methods to access\n * and manage it. The two main members of `ActiveBagContent` are the {@link module:shapers/Shaper.Shaper Shaper}, responsible for\n * determining the position and shape of each {@link module:boxes/ActiveBox.ActiveBox ActiveBox}, and the {@link module:boxes/BoxBase.BoxBase BoxBase} (field `style`),\n * provider of a common visual style.\n */\nexport class ActiveBagContent {\n /**\n * ActiveBagContent constructor\n * @param {string} [id] - An optional text tag identifying this ActiveBagContent\n * @param {number} ncw - In grid-based distributions, number of columns.\n * @param {number} nch - In grid-based distributions, number of rows.\n */\n constructor(id, ncw, nch) {\n if (id)\n this.id = id;\n this.cells = [];\n this.ncw = Math.max(1, ncw);\n this.nch = Math.max(1, nch);\n }\n\n /**\n * Loads the object settings from a specific JQuery XML element\n * @param {external:jQuery} $xml - The XML element to parse\n * @param {module:bags/MediaBag.MediaBag} mediaBag - The project's MediaBag\n */\n setProperties($xml, mediaBag) {\n let bug = false;\n attrForEach($xml.get(0).attributes, (name, val) => {\n switch (name) {\n case 'id':\n this.id = val;\n break;\n case 'image':\n this.image = nSlash(val);\n break;\n // Bug in JClic beta 1: \"columns\" is number of rows, and \"rows\" is number of columns.\n // Was corrected in beta 2: If \"cols\" is specified, \"rows\" are rows and \"cols\" are columns.\n case 'rows':\n this.nch = Number(val);\n break;\n case 'columns':\n bug = true;\n /* falls through */\n case 'cols':\n this.ncw = Number(val);\n break;\n case 'cellWidth':\n this.w = Number(val);\n break;\n case 'cellHeight':\n this.h = Number(val);\n break;\n case 'border':\n this.border = getBoolean(val);\n break;\n }\n });\n\n if (bug) {\n let n = this.ncw;\n this.ncw = this.nch;\n this.nch = n;\n }\n\n $xml.children().each((_n, child) => {\n const $node = $(child);\n switch (child.nodeName) {\n case 'style':\n this.style = new BoxBase(null).setProperties($node);\n break;\n case 'shaper':\n const shaperClassName = $node.attr('class'),\n nCols = Math.max(1, $node.attr('cols')),\n nRows = Math.max(1, $node.attr('rows'));\n this.shaper = Shaper.getShaper(shaperClassName, nCols, nRows);\n this.shaper.setProperties($node);\n break;\n case 'ids':\n // Used in special cases where all cells have empty content with only 'ids'\n this.ids = child.textContent;\n this.ids.split(' ').forEach((id, i) => { this.cells[i] = new ActiveBoxContent(Number(id)); });\n break;\n case 'cell':\n this.cells.push(new ActiveBoxContent().setProperties($node, mediaBag));\n break;\n }\n });\n\n let n = this.cells.length;\n\n // Create cells when `cells` is empty\n if (n === 0 && this.shaper && this.shaper.nCells > 0) {\n this.initiallyEmptyCells = true;\n n = this.shaper.nCells;\n this.getActiveBoxContent(n - 1);\n }\n\n // Assign ids when cells have empty content (they are just shapes)\n if (n > 0) {\n let empty = true;\n for (let i = 0; i < n; i++) {\n const bxc = this.getActiveBoxContent(i);\n if (bxc.id !== -1 || bxc.item !== -1 || !bxc.isEmpty()) {\n empty = false;\n break;\n }\n }\n if (empty) {\n for (let i = 0; i < n; i++)\n this.getActiveBoxContent(i).id = i;\n }\n }\n\n // Link [BoxBase](BoxBase.html) objects of `cells` elements to `style`\n if (this.style)\n this.cells.forEach((abc) => { if (abc.style) abc.style.parent = this.style; });\n\n return this;\n }\n\n /**\n * Gets a object with the basic attributes needed to rebuild this instance excluding functions,\n * parent references, constants and also attributes retaining the default value.\n * The resulting object is commonly usued to serialize elements in JSON format.\n * @returns {object} - The resulting object, with minimal attrributes\n */\n getAttributes() {\n const fields = [\n 'id', 'image',\n 'ncw', 'nch',\n 'w', 'h', 'border',\n 'style', // BoxBase\n 'shaper', // Shaper\n ];\n if (!this.initiallyEmptyCells)\n fields.push(this.ids ? 'ids' : 'cells'); // ActiveBoxContent\n return getAttr(this, fields);\n }\n\n /**\n * Reads the properties of this ActiveBagContent from a data object\n * @param {object} data - The data object to be parsed\n * @param {module:bags/MediaBag.MediaBag} mediaBag - The project's MediaBag\n * @returns {module:boxes/ActiveBagContent.ActiveBagContent}\n */\n setAttributes(data, mediaBag) {\n setAttr(this, data, [\n 'id', 'image',\n 'ncw', 'nch',\n 'w', 'h', 'border',\n { key: 'style', fn: BoxBase },\n { key: 'shaper', fn: Shaper },\n 'ids',\n { key: 'cells', fn: ActiveBoxContent, group: 'array', params: [mediaBag] },\n ]);\n\n let n = this.cells.length;\n\n // Create cells when `cells` is empty\n if (n === 0 && this.shaper && this.shaper.nCells > 0) {\n this.initiallyEmptyCells = true;\n n = this.shaper.nCells;\n this.getActiveBoxContent(n - 1);\n if (this.ids)\n this.ids.split(' ').forEach((id, i) => { this.getActiveBoxContent(i).id = Number(id); });\n }\n\n // Assign ids when cells have empty content (they are just shapes)\n if (n > 0) {\n let empty = true;\n for (let i = 0; i < n; i++) {\n const bxc = this.getActiveBoxContent(i);\n if (bxc.id !== -1 || bxc.item !== -1 || !bxc.isEmpty()) {\n empty = false;\n break;\n }\n }\n if (empty) {\n for (let i = 0; i < n; i++)\n this.getActiveBoxContent(i).id = i;\n }\n }\n\n // Link [BoxBase](BoxBase.html) objects of `cells` elements to `style`\n if (this.style)\n this.cells.forEach(abc => { if (abc.style) abc.style.parent = this.style; });\n\n if (mediaBag)\n this.cells.forEach(abc => abc.realizeContent(mediaBag));\n\n return this;\n }\n\n /**\n * Prepares the media content of all elements\n * @param {module:JClicPlayer.JClicPlayer} playStation - The {@link module:JClicPlayer.JClicPlayer JClicPlayer}\n */\n prepareMedia(playStation) {\n this.cells.forEach(abc => abc.prepareMedia(playStation));\n }\n\n /**\n * Gets the estimated total width of this content bag\n * @returns {number}\n */\n getTotalWidth() {\n return this.w * this.ncw;\n }\n\n /**\n * Gets the estimated total height of this bag\n * @returns {number}\n */\n getTotalHeight() {\n return this.h * this.nch;\n }\n\n /**\n * Gets the total number of cells of this bag\n * @returns {number}\n */\n getNumCells() {\n return this.cells.length;\n }\n\n /**\n * Checks if the bag is empty\n * @returns {boolean}\n */\n isEmpty() {\n return this.cells.length === 0;\n }\n\n /**\n * Retrieves the {@link module:shapers/Shaper.Shaper Shaper} of this bag, creating a new one if it was _null_\n * @returns {module:shapers/Shaper.Shaper}\n */\n getShaper() {\n if (this.shaper === null)\n this.shaper = Shaper.getShaper('@Rectangular', this.ncw, this.nch);\n return this.shaper;\n }\n\n /**\n * Retrieves the {@link module:boxes/BoxBase.BoxBase BoxBase} of this bag, creating a new one if it was _null_\n * @returns {module:boxes/BoxBase.BoxBase}\n */\n getBoxBase() {\n if (this.style === null)\n this.style = new BoxBase();\n return this.style;\n }\n\n /**\n * Adds a new {@link module:boxes/ActiveBoxContent.ActiveBoxContent ActiveBoxContent} to this bag\n * @param {module:boxes/ActiveBoxContent.ActiveBoxContent} ab - The ActiveBoxContent to add\n */\n addActiveBoxContent(ab) {\n this.cells.push(ab);\n if (this.ncw === 0 || this.nch === 0) {\n this.ncw = this.nch = 1;\n }\n }\n\n /**\n * Gets the nth {@link module:boxes/ActiveBoxContent.ActiveBoxContent ActiveBoxContent} in `cells`\n * @param {number} i - The index of the content to be retrieved\n * @returns {module:boxes/ActiveBoxContent.ActiveBoxContent}\n */\n getActiveBoxContent(i) {\n if (i >= this.cells.length) {\n for (let j = this.cells.length; j <= i; j++)\n this.cells.push(new ActiveBoxContent());\n }\n return this.cells[i];\n }\n\n /**\n * Finds the ActiveBoxContent with specific `id` and `item` values\n * @param {number} id\n * @param {number} item\n * @returns {module:boxes/ActiveBoxContent.ActiveBoxContent}\n */\n getActiveBoxContentWith(id, item) {\n return this.cells.find(bxc => bxc.id === id && bxc.item === item);\n }\n\n /**\n * Sets the content of the cells based on a image spliced by a shaper\n * @param {module:bags/MediaBag.MediaBag} mb - The MediaBag used to retrieve the image\n * @param {module:shapers/Shaper.Shaper} sh - The Shaper used to splice the image\n * @param {boolean} roundSizes - When `true`, the size and coordinates of cells will be rounded\n * to the nearest integer values.\n */\n setImgContent(mb, sh, roundSizes) {\n if (sh)\n this.setShaper(sh);\n\n if (this.shaper.className === '@Holes')\n this.shaper.hasRemainder = true;\n\n this.ncw = this.shaper.nCols;\n this.nch = this.shaper.nRows;\n const mbe = mb.elements[this.image];\n if (mb && this.image && mbe && mbe.ready) {\n this.img = mbe.data;\n if (mbe.animated)\n this.animatedGifFile = mbe.getFullPath();\n this.w = this.img.width / this.ncw;\n this.h = this.img.height / this.nch;\n if (roundSizes) {\n this.w = Math.round(this.w);\n this.h = Math.round(this.h);\n }\n } else {\n this.img = null;\n this.w = Math.max(this.w, 10);\n this.h = Math.max(this.h, 10);\n }\n\n const r = new Rectangle(0, 0, this.w * this.ncw, this.h * this.nch);\n for (let i = 0; i < this.shaper.nCells; i++)\n this.getActiveBoxContent(i).setImgContent(this.img, this.shaper.getShape(i, r), this.animatedGifFile);\n\n if (this.shaper.hasRemainder) {\n this.backgroundContent = new ActiveBoxContent();\n this.backgroundContent.setImgContent(this.img, this.shaper.getRemainderShape(r));\n }\n }\n\n /**\n * Sets the content of this bag based on an array of strings\n * @param {string[]} txt - The array of strings to be used as content.\n * @param {number} setNcw - Number of columns\n * @param {number} setNch - Number of rows\n */\n setTextContent(txt, setNcw, setNch) {\n this.ncw = Math.max(1, setNcw);\n this.nch = Math.max(1, setNch);\n const n = this.ncw * this.nch;\n for (let i = 0; i < n; i++)\n this.getActiveBoxContent(i).setTextContent(i >= txt.length || txt[i] === null ? '' : txt[i]);\n }\n\n /**\n * Sets `id` values to a all the {@link module:boxes/ActiveBoxContent.ActiveBoxContent ActiveBoxContent} elements of his bag.\n * @param {number[]} ids -Array of numeric identifiers\n */\n setIds(ids) {\n for (let i = 0; i < ids.length && i < this.cells.length; i++)\n this.getActiveBoxContent(i).id = ids[i];\n }\n\n /**\n * Sets `value` to the `key` attribute of all cells\n * @param {string} key - The key where the value will be stored\n * @param {any} value - The supplied value. Can be of any type.\n */\n setCellsAttribute(key, value) {\n this.cells.forEach(abc => abc[key] = value);\n }\n\n /**\n *\n * Cheks if the `id` values of all {@link module:boxes/ActiveBoxContent.ActiveBoxContent ActiveBoxContent} objects are -1 and, if true,\n * sets new ids to them, with values between 0 and `maxId`\n * @param {number} maxId - The maximum value of identifiers\n */\n avoidAllIdsNull(maxId) {\n if (this.cells.every(abc => abc.id === -1)) {\n maxId = Math.max(1, maxId);\n this.cells.forEach((abc, n) => { abc.id = n % maxId; });\n }\n }\n}\n\nObject.assign(ActiveBagContent.prototype, {\n /**\n * The global identifier of this object: `primary`, `secondary`...\n * @name module:boxes/ActiveBagContent.ActiveBagContent#id\n * @type {string} */\n id: 'primary',\n /**\n * The name of the image file used as a common image of this bag\n * @name module:boxes/ActiveBagContent.ActiveBagContent#image\n * @type {string} */\n image: null,\n /**\n * The built image object\n * @name module:boxes/ActiveBagContent.ActiveBagContent#img\n * @type {external:HTMLImageElement} */\n img: null,\n /**\n * Name of the img source when is an animated GIF\n * @name module:boxes/ActiveBagContent.ActiveBagContent#animatedGifFile\n * @type {string} */\n animatedGifFile: null,\n /**\n * Number of columns when cells are distributed in a grid\n * @name module:boxes/ActiveBagContent.ActiveBagContent#ncw\n * @type {number} */\n ncw: 1,\n /**\n * Number of rows when cells are distributed in a grid\n * @name module:boxes/ActiveBagContent.ActiveBagContent#nch\n * @type {number} */\n nch: 1,\n /**\n * Optimal cell width\n * @name module:boxes/ActiveBagContent.ActiveBagContent#w\n * @type {number} */\n w: settings.DEFAULT_GRID_ELEMENT_SIZE,\n /**\n * Optimal cell height\n * @name module:boxes/ActiveBagContent.ActiveBagContent#h\n * @type {number} */\n h: settings.DEFAULT_GRID_ELEMENT_SIZE,\n /**\n * Whether the cells must have a border or not\n * @name module:boxes/ActiveBagContent.ActiveBagContent#border\n * @type {boolean} */\n border: true,\n /**\n * The BoxBase used for this bag of cell contents\n * @name module:boxes/ActiveBagContent.ActiveBagContent#style\n * @type {module:boxes/BoxBase.BoxBase} */\n style: null,\n /**\n * The Shaper used to define the specific shape of each cell\n * @name module:boxes/ActiveBagContent.ActiveBagContent#shaper\n * @type {module:shapers/Shaper.Shaper} */\n shaper: null,\n /**\n * An optional ActiveBoxContent object with background settings.\n * @name module:boxes/ActiveBagContent.ActiveBagContent#backgroundContent\n * @type {module:boxes/ActiveBoxContent.ActiveBoxContent} */\n backgroundContent: null,\n /**\n * The main Array of {@link module:boxes/ActiveBoxContent.ActiveBoxContent ActiveBoxContent} objects\n * @name module:boxes/ActiveBagContent.ActiveBagContent#cells\n * @type {module:boxes/ActiveBoxContent.ActiveBoxContent[]} */\n cells: null,\n /**\n * The default value to be assigned at the 'id' field of children\n * @name module:boxes/ActiveBagContent.ActiveBagContent#defaultIdValue\n * @type {number} */\n defaultIdValue: -1,\n /**\n * Used in special cases where all cells have empty content with only numeric identifiers\n * @name module:boxes/ActiveBagContent.ActiveBagContent#ids\n * @type {string} */\n ids: null,\n});\n\nexport default ActiveBagContent;\n","/**\n * File : automation/AutoContentProvider.js\n * Created : 13/04/2015\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\nimport {log, getAttr} from '../Utils.js';\n\n/**\n * This abstract class is the base for classes that create on-time automatic content for JClic\n * activities, usually using random parameters to assure different content in each session.\n *\n * Activities with `AutoContentProvider` objects rely on them to build new content on every start.\n */\nexport class AutoContentProvider {\n /**\n * AutoContentProvider constructor\n */\n constructor() {\n }\n\n /**\n * Dynamic constructor that returns a specific type of AutoContentProvider based on the `class`\n * attribute declared on an $xml element.\n * It should be called only from {@link module:Activity.Activity#setProperties Activity.setProperties}\n * @param {external.jQuery} $xml - The XML element to parse\n * @returns {module:automation/AutoContentProvider.AutoContentProvider}\n */\n static getProvider($xml) {\n let automation = null;\n if ($xml) {\n const\n className = ($xml.attr('class') || '').replace(/^edu\\.xtec\\.jclic\\.automation\\./, '@'),\n cl = AutoContentProvider.CLASSES[className];\n if (cl) {\n automation = new cl();\n automation.setProperties($xml);\n } else\n log('error', `Unknown AutoContentProvider class: ${className}`);\n }\n return automation;\n }\n\n /**\n * Loads the object settings from a specific jQuery XML element\n * @param {external:jQuery} $xml - The XML element to parse\n */\n setProperties($xml) {\n this.className = ($xml.attr('class') || '').replace(/^edu\\.xtec\\.jclic\\.automation\\./, '@');\n return this;\n }\n\n /**\n * Gets a object with the basic attributes needed to rebuild this instance excluding functions,\n * parent references, constants and also attributes retaining the default value.\n * The resulting object is commonly usued to serialize elements in JSON format.\n * @returns {object} - The resulting object, with minimal attrributes\n */\n getAttributes() {\n // To be overrided!\n return getAttr(this, ['className']);\n }\n\n /**\n * Builds a new AutoContentProvider, based on the properties specified in a data object\n * @param {object} data - The data object to be parsed\n * @param {object[]} params - Optional parameters to be passed to `setAttributes`\n * @returns {module:shapers/Shaper.Shaper}\n */\n static factory(data, params = []) {\n const cl = AutoContentProvider.CLASSES[data.className];\n return (new cl()).setAttributes(data, ...params);\n }\n\n /**\n * Initializes the content provider\n */\n init() {\n // To be implemented in real content providers\n }\n\n /**\n * Builds an {@link module:automation/AutoContentProvider/ActiveBagContentKit ActiveBagContentKit} and generates the automatized content.\n * @param {number} nRows - Number of rows to be processed\n * @param {number} nCols - Number of columns to be processed\n * @param {module:boxes/ActiveBagContent.ActiveBagContent[]} content - Array with one or more containers of {@link module:boxes/ActiveBoxContent.ActiveBoxContent ActiveBoxContent}\n * objects to be filled with new content.\n * @param {boolean} useIds - When `true`, the `id` field of {@link module:boxes/ActiveBoxContent.ActiveBoxContent ActiveBoxContent} objects is significant\n * @returns {boolean} - `true` if the process was OK. `false` otherwise.\n */\n generateContent(nRows, nCols, content, useIds) {\n return this.process(new AutoContentProvider.ActiveBagContentKit(nRows, nCols, content, useIds));\n }\n\n /**\n * Generates the automatized content\n * @param {module:automation/AutoContentProvider.ActiveBagContentKit} _kit - The objects to be filled with content\n * @returns {boolean} - `true` if the process was OK. `false` otherwise.\n */\n process(_kit) {\n // To be implemented in subclasses\n return false;\n }\n\n /**\n * Registers a new type of AutoContentProvider\n * @param {string} providerName - The name used to identify this AutoContentProvider\n * @param {function} providerClass - The activity class, usually extending AutoContentProvider\n * @returns {module:automation/AutoContentProvider.AutoContentProvider} - The provider class\n */\n static registerClass(providerName, providerClass) {\n AutoContentProvider.CLASSES[providerName] = providerClass;\n return providerClass;\n }\n}\n\nObject.assign(AutoContentProvider.prototype, {\n /**\n * This AutoContentProvider manages numeric expressions, so text literals should be\n * converted to numbers for comparisions, taking in account the\n * number format of the current locale (dot or comma as decimal separator)\n * @name module:automation/AutoContentProvider.AutoContentProvider#numericContent\n * @type {boolean} */\n numericContent: false,\n});\n\n/**\n * Utility class used to encapsulate multiple sets of box contents\n * @param {number} nRows - Number of rows to be processed\n * @param {number} nCols - Number of columns to be processed\n * @param {module:boxes/ActiveBagContent.ActiveBagContent[]} content - Array with one or more containers of {@link module:boxes/ActiveBoxContent.ActiveBoxContent ActiveBoxContent}\n * objects to be filled with new content.\n * @param {boolean} useIds - `true` when the `id` field of {@link module:boxes/ActiveBoxContent.ActiveBoxContent ActiveBoxContent} objects is significant.\n */\nAutoContentProvider.ActiveBagContentKit = class {\n constructor(nRows, nCols, content, useIds) {\n this.nRows = nRows;\n this.nCols = nCols;\n this.content = content;\n this.useIds = useIds;\n }\n};\n\n/**\n * Contains the current list of classes derived from AutoContentProvider.\n * This object should be updated by real automation classes at declaration time.\n * Currently, only two types of \"AutoContentProvider\" are defined: {@link module:automation/arith/Arith.Arith Arith} and TagReplace.\n * @type {object} */\nAutoContentProvider.CLASSES = {\n // TODO: Implement TagReplace\n '@tagreplace.TagReplace': AutoContentProvider\n};\n\n// TODO: Implement TagReplace\nAutoContentProvider.registerClass('@tagreplace.TagReplace', AutoContentProvider);\n\nexport default AutoContentProvider;\n","/**\n * File : boxes/TextGridContent.js\n * Created : 14/04/2015\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\nimport $ from 'jquery';\nimport { settings, attrForEach, getBoolean, getAttr, setAttr } from '../Utils.js';\nimport BoxBase from './BoxBase.js';\n\n/**\n * This class encapsulates the content of {@link module:boxes/TextGrid.TextGrid TextGrid} objects.\n *\n * It implements methods to set and retrieve individual characters on the grid, and parsing of\n * XML objects. It also contains information about the optimal size and other graphic properties\n * (fonts, colors, etc.) of the grid.\n */\nexport class TextGridContent {\n /**\n * TextGridContent constructor\n */\n constructor() {\n this.style = new BoxBase(null);\n this.text = [];\n }\n\n /**\n * Loads the object settings from a specific JQuery XML element\n * @param {external:jQuery} $xml\n */\n setProperties($xml) {\n // Read attributes\n attrForEach($xml.get(0).attributes, (name, val) => {\n switch (name) {\n case 'rows':\n // WARNING: Due to a bug in JClic, the meaning of \"rows\" and \"columns\" must be\n // interchanged:\n this.ncw = Number(val);\n break;\n case 'columns':\n this.nch = Number(val);\n break;\n case 'cellWidth':\n this.w = Number(val);\n break;\n case 'cellHeight':\n this.h = Number(val);\n break;\n case 'border':\n this.border = getBoolean(val);\n break;\n case 'wild':\n case 'randomChars':\n this[name] = val;\n break;\n }\n });\n\n // Read inner elements\n $xml.children('style:first').each((_n, child) => {\n this.style = new BoxBase().setProperties($(child));\n });\n\n $xml.find('text:first > row').each((_n, el) => this.text.push(el.textContent));\n\n for (let i = this.text.length; i < this.nch; i++)\n this.text[i] = '';\n\n return this;\n }\n\n /**\n * Gets a object with the basic attributes needed to rebuild this instance excluding functions,\n * parent references, constants and also attributes retaining the default value.\n * The resulting object is commonly usued to serialize elements in JSON format.\n * @returns {object} - The resulting object, with minimal attrributes\n */\n getAttributes() {\n return getAttr(this, [\n 'ncw', 'nch',\n 'w', 'h',\n 'text',\n 'style', // BoxBase\n 'border',\n 'wild|*',\n `randomChars|${settings.RANDOM_CHARS}`,\n ]);\n }\n\n /**\n * Reads the properties of this TextGridContent from a data object\n * @param {object|string} data - The data object to be parsed, or just the text content\n * @returns {module:boxes/TextGridContent.TextGridContent}\n */\n setAttributes(data) {\n return setAttr(this, data, [\n 'ncw', 'nch',\n 'w', 'h',\n 'text',\n { key: 'style', fn: BoxBase },\n 'border',\n 'wild',\n `randomChars`,\n ]);\n }\n\n /**\n * Counts the number of wildcard characters present in this TextGrid\n * @returns {number}\n */\n countWildChars() {\n let result = 0;\n if (this.text)\n for (let y = 0; y < this.nch; y++)\n for (let x = 0; x < this.ncw; x++)\n if (this.text[y].charAt(x) === this.wild)\n result++;\n return result;\n }\n\n /**\n * Counts the total number of characters, including wildcard characters.\n * @returns {number}\n */\n getNumChars() {\n return this.ncw * this.nch;\n }\n\n /**\n * Sets the specified character as a content of the cell located at specific coordinates\n * @param {number} x - The X coordinate of the cell\n * @param {number} y - The X coordinate of the cell\n * @param {string} ch - The character to be placed on the specified cell\n */\n setCharAt(x, y, ch) {\n if (x >= 0 && x < this.ncw && y >= 0 && y < this.nch)\n this.text[y] = this.text[y].substring(0, x) + ch + this.text[y].substring(x + 1);\n }\n}\n\nObject.assign(TextGridContent.prototype, {\n /**\n * Grid columns\n * @name module:boxes/TextGridContent.TextGridContent#ncw\n * @type {number} */\n ncw: 1,\n /**\n * Grid rows\n * @name module:boxes/TextGridContent.TextGridContent#nch\n * @type {number} */\n nch: 1,\n /**\n * Width of cells\n * @name module:boxes/TextGridContent.TextGridContent#w\n * @type {number} */\n w: 20,\n /**\n * Height of cells\n * @name module:boxes/TextGridContent.TextGridContent#h\n * @type {number} */\n h: 20,\n /**\n * Whether the cells must be surrounded by a border or not\n * @name module:boxes/TextGridContent.TextGridContent#border\n * @type {boolean} */\n border: false,\n /**\n * The {@link module:boxes/BoxBase.BoxBase BoxBase} object with visual settings of the text grid\n * @name module:boxes/TextGridContent.TextGridContent#style\n * @type {module:boxes/BoxBase.BoxBase} */\n style: null,\n /**\n * An array of String objects textning the chars of cells. One string per row, one character of\n * this string per cell.\n * @name module:boxes/TextGridContent.TextGridContent#text\n * @type {string[]} */\n text: null,\n /**\n * The letter used as wildcardtext\n * @name module:boxes/TextGridContent.TextGridContent#wild\n * @type {string} */\n wild: '*',\n /**\n * A String with the chars to take as source when randomly filling empty cells\n * @name module:boxes/TextGridContent.TextGridContent#randomChars\n * @type {string} */\n randomChars: settings.RANDOM_CHARS,\n});\n\nexport default TextGridContent;\n","/**\n * File : activities/text/Evaluator.js\n * Created : 14/04/2015\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\n/* global window */\n\nimport { log, attrForEach, getBoolean, setAttr, getAttr } from '../../Utils.js';\n\n/**\n * This class and its derivatives {@link module:activities/text/Evaluator.BasicEvaluator BasicEvaluator} and\n * {@link module:activities/text/Evaluator.ComplexEvaluator ComplexEvaluator} are used to evaluate the answers written by the final users\n * in text activities.\n */\nexport class Evaluator {\n /**\n * Evaluator constructor\n * @param {string} className - The class name of this evaluator.\n */\n constructor(className) {\n this.className = className;\n this.collator = (window.Intl && window.Intl.Collator) ?\n new window.Intl.Collator() :\n { compare: (a, b) => this.checkCase ? a === b : a.toUpperCase() === b.toUpperCase() };\n }\n\n /**\n * Factory constructor that returns a specific type of {@link module:activities/text/Evaluator.Evaluator Evaluator} based on the `class`\n * attribute declared in the $xml element.\n * @param {external:jQuery} $xml - The XML element to be parsed.\n * @returns {module:activities/text/Evaluator.Evaluator}\n */\n static getEvaluator($xml) {\n let ev = null;\n if ($xml) {\n const className = $xml.attr('class');\n const cl = Evaluator.CLASSES[className];\n if (cl) {\n ev = new cl(className);\n ev.setProperties($xml);\n } else\n log('error', `Unknown evaluator class: \"${className}\"`);\n }\n return ev;\n }\n\n /**\n * Loads the object settings from a specific JQuery XML element\n * @param {external:jQuery} $xml - The jQuery XML element to parse\n */\n setProperties($xml) {\n attrForEach($xml.get(0).attributes, (name, value) => {\n switch (name) {\n case 'class':\n this.className = value;\n break;\n case 'checkCase':\n case 'checkAccents':\n case 'checkPunctuation':\n case 'checkDoubleSpaces':\n case 'detail':\n this[name] = getBoolean(value);\n break;\n case 'checkSteps':\n case 'checkScope':\n this[name] = Number(value);\n break;\n }\n });\n return this;\n }\n\n /**\n * Builds a new Evaluator, based on the properties specified in a data object\n * @param {object} data - The data object to be parsed\n * @returns {module:activities/text/Evaluator.Evaluator}\n */\n static factory(data) {\n const cl = Evaluator.CLASSES[data.className];\n if (cl) {\n const result = new cl(data.className);\n return setAttr(result, data, [\n 'className',\n 'checkCase', 'checkAccents', 'checkPunctuation', 'checkDoubleSpaces', 'detail',\n 'checkSteps', 'checkScope',\n ]);\n }\n return null;\n }\n\n /**\n * Gets a object with the basic attributes needed to rebuild this instance excluding functions,\n * parent references, constants and also attributes retaining the default value.\n * The resulting object is commonly usued to serialize elements in JSON format.\n * @returns {object} - The resulting object, with minimal attrributes\n */\n getAttributes() {\n return getAttr(this, [\n 'className',\n 'checkCase', 'checkAccents', 'checkPunctuation', 'checkDoubleSpaces', 'detail',\n 'checkSteps', 'checkScope',\n ]);\n }\n\n /**\n * Initializes this evaluator\n * @param {string[]} _locales - An array of valid locales, to be used by Intl.Collator\n */\n init(_locales) {\n this.initiated = true;\n }\n\n /**\n * Checks the given text against a set of valid matches\n * @param {string} text - The text to be checked\n * @param {string|string[]} match - The valid expression or expressions with which to compare.\n * @returns {boolean} - `true` if the checked expression is valid, `false` otherwise.\n */\n checkText(text, match) {\n if (match instanceof Array)\n return match.some(m => this._checkText(text, m));\n else if (match)\n return this._checkText(text, match);\n else\n return false;\n }\n\n /**\n * Abstract method to be implemented in subclasses.\n * Performs the validation of a string against a single match.\n * @param {string} _text - The text to be checked\n * @param {string} _match - A valid expression with which to compare.\n * @returns {boolean} - `true` when the two expressions can be considered equivalent.\n */\n _checkText(_text, _match) {\n return false;\n }\n\n /**\n * Evaluates the given text against a set of valid matches, returning an array of flags useful\n * to indicate where the mistakes are located.\n * @param {string} text - The text to be checked\n * @param {string|string[]} match - The valid expression or expressions with which to compare.\n * @returns {number[]} - An array of flags (one number for character) indicating whether each\n * position is erroneous or ok.\n */\n evalText(text, match) {\n if (!(match instanceof Array))\n match = [match];\n return this._evalText(text, match);\n }\n\n /**\n * Abstract method to be implemented in subclasses.\n * Performs the evaluation of a string against an array of valid matches, returning an array of\n * flags useful to indicate where the mistakes are located.\n * @param {string} _text - The text to be checked\n * @param {string} _match - A valid expression with which to compare.\n * @returns {number[]} - An array of flags (one number for character) indicating whether each\n * position is erroneous or OK.\n */\n _evalText(_text, _match) {\n return [];\n }\n\n /**\n * Checks if the given array of flags (usually returned by `evalText`) can be considered as a\n * valid or erroneous answer.\n * @param {number[]} flags\n * @returns {boolean} - `true` when there is at least one flag and all flags are 0 (meaning no error).\n */\n isOk(flags) {\n return flags && flags.length > 0 && !flags.some(f => f !== 0);\n }\n}\n\nObject.assign(Evaluator.prototype, {\n /**\n * The type of evaluator.\n * @name module:activities/text/Evaluator.Evaluator#className\n * @type {string} */\n className: null,\n /**\n * Whether this evaluator has been initialized or not.\n * @name module:activities/text/Evaluator.Evaluator#initiated\n * @type {boolean} */\n initiated: false,\n /**\n * The Intl.Collator object used to compare strings, when available.\n * @name module:activities/text/Evaluator.Evaluator#collator\n * @type {external:Collator} */\n collator: null,\n /**\n * Whether uppercase and lowercase expressions must be considered equivalent or not.\n * @name module:activities/text/Evaluator.Evaluator#checkcase\n * @type {boolean} */\n checkCase: false,\n});\n\n/**\n * A basic evaluator that just compares texts, without looking for possible coincidences of text\n * fragments once erroneous characters removed.\n * @extends module:activities/text/Evaluator.Evaluator\n */\nexport class BasicEvaluator extends Evaluator {\n /**\n * BasicEvaluator constructor\n * @param {string} className - The class name of this evaluator.\n */\n constructor(className) {\n super(className);\n }\n\n /**\n * Initializes the {@link module:activities/text/Evaluator.Evaluator#collator collator}.\n * @override\n * @param {string[]} locales - An array of valid locales to be used by the Inlt.Collator object\n */\n init(locales) {\n // Call `init` method on ancestor\n super.init([locales]);\n\n // Get canonical locales\n if (window.Intl && window.Intl.Collator) {\n this.collator = new window.Intl.Collator(locales, {\n sensitivity: this.checkAccents ? this.checkCase ? 'case' : 'accent' : 'base',\n ignorePunctuation: !this.checkPunctuation\n });\n }\n }\n\n /**\n * Performs the validation of a string against a single match.\n * @override\n * @param {string} text - The text to be checked\n * @param {string} match - A valid expression with which to compare.\n * @returns {boolean} - `true` when the two expressions can be considered equivalent.\n */\n _checkText(text, match) {\n return this.collator.compare(this.getClearedText(text), this.getClearedText(match)) === 0;\n }\n\n /**\n * Performs the evaluation of a string against an array of valid matches, returning an array of\n * flags useful to indicate where the mistakes are located.\n * In BasicEvaluator, all characters are just marked as 1 (error) or 0 (OK). See\n * {@link module:activities/text/Evaluator.ComplexEvaluator ComplexEvaluator} for more detailed analysis of answers.\n * @override\n * @param {string} text - The text to be checked\n * @param {string} match - A valid expression with which to compare.\n * @returns {number[]} - An array of flags (one number for character) indicating whether each\n * position is erroneous or OK.\n */\n _evalText(text, match) {\n return Array(text.length).fill(this._checkText(text, match[0]) ? 0 : 1);\n }\n\n /**\n * Removes double spaces and erroneous characters from a given text expression.\n * @param {string} src - The text to be processed.\n * @param {boolean[]} skipped - An array of boolean indicating which characters should be removed\n * from the string.\n * @returns {string}\n */\n getClearedText(src, skipped) {\n if (this.checkPunctuation && this.checkDoubleSpaces)\n return src;\n\n if (!skipped)\n skipped = Array(src.length).fill(false);\n\n let sb = '';\n for (let i = 0, wasSpace = false; i < src.length; i++) {\n const ch = src.charAt(i);\n if (this.PUNCTUATION.indexOf(ch) >= 0 && !this.checkPunctuation) {\n if (!wasSpace)\n sb += ' ';\n else\n skipped[i] = true;\n wasSpace = true;\n } else if (ch === ' ') {\n if (this.checkDoubleSpaces || !wasSpace)\n sb += ch;\n else\n skipped[i] = true;\n wasSpace = true;\n } else {\n wasSpace = false;\n sb += ch;\n }\n }\n return sb;\n }\n}\n\nObject.assign(BasicEvaluator.prototype, {\n /**\n * Whether accented letters must be considered equivalent or not.\n * @name module:activities/text/Evaluator.BasicEvaluator#checkAccents\n * @type {boolean} */\n checkAccents: true,\n /**\n * Whether to check or not dots, commas and other punctuation marks when comparing texts.\n * @name module:activities/text/Evaluator.BasicEvaluator#checkPunctuation\n * @type {boolean} */\n checkPunctuation: true,\n /**\n * Whether to check or not the extra spaces added between words.\n * @name module:activities/text/Evaluator.BasicEvaluator#checkDoubleSpaces\n * @type {boolean} */\n checkDoubleSpaces: false,\n /**\n * String containing all the characters considered as punctuation marks (currently \".,;:\")\n * @name module:activities/text/Evaluator.BasicEvaluator#PUNCTUATION\n * @type {string} */\n PUNCTUATION: '.,;:',\n});\n\n/**\n * ComplexEvaluator acts like {@link module:activities/text/Evaluator.BasicEvaluator BasicEvaluator}, but providing feedback about\n * the location of mistakes on the user's answer.\n * @extends module:activities/text/Evaluator.BasicEvaluator\n */\nexport class ComplexEvaluator extends BasicEvaluator {\n /**\n * ComplexEvaluator constructor\n * @param {string} className - The class name of this evaluator.\n */\n constructor(className) {\n super(className);\n }\n\n /**\n * Performs the evaluation of a string against an array of valid matches, returning an array of\n * flags useful to indicate where the mistakes are located.\n * In BasicEvaluator, all characters are just marked as 1 (error) or 0 (OK). See\n * {@link module:activities/text/Evaluator.ComplexEvaluator ComplexEvaluator} for more detailed analysis of answers.\n * @override\n * @param {string} text - The text to be checked\n * @param {string} match - A valid expression with which to compare.\n * @returns {number[]} - An array of flags (one number for character) indicating whether each\n * position is erroneous or OK.\n */\n _evalText(text, match) {\n\n if (!this.detail)\n return super._evalText(text, match);\n\n const\n skipped = Array(text.length).fill(false),\n sText = this.getClearedText(text, skipped),\n numChecks = Array(match.length),\n flags = Array(match.length),\n returnFlags = Array(text.length);\n let\n maxCheck = -1,\n maxCheckIndex = -1;\n\n for (let i = 0; i < match.length; i++) {\n flags[i] = Array(text.length).fill(0);\n const ok = this.compareSegment(sText, sText.length, match[i], match[i].length, flags[i], false);\n numChecks[i] = this.countFlagsOk(flags[i]);\n if (ok) {\n maxCheckIndex = i;\n maxCheck = numChecks[i];\n }\n }\n\n if (maxCheckIndex === -1) {\n for (let i = 0; i < match.length; i++) {\n if (numChecks[i] > maxCheck) {\n maxCheck = numChecks[i];\n maxCheckIndex = i;\n }\n }\n }\n\n for (let i = 0, k = 0; i < text.length; i++)\n returnFlags[i] = skipped[i] ? 0 : flags[maxCheckIndex][k++];\n\n return returnFlags;\n }\n\n /**\n * Counts the number of flags on the provided array that are zero.\n * @param {number[]} flags\n * @returns {number}\n */\n countFlagsOk(flags) {\n return flags.reduce((n, v) => v == 0 ? ++n : n, 0);\n }\n\n /**\n * Compares two segments of text.\n * This function should make recursive calls.\n * @param {string} src - Text to be compared\n * @param {number} ls - Offset in `src` where to start the comparison\n * @param {string} ok - Text to match against.\n * @param {number} lok - Offset in `ok` where to start the comparison.\n * @param {number[]} attr - Array of integers that will be filled with information about the\n * validity or error of each character in `src`.\n * @param {boolean} iterate - When `true`, the segment will be iterated looking for other\n * coincident fragments.\n * @returns {boolean} - `true` if the comparison was valid.\n */\n compareSegment(src, ls, ok, lok, attr, iterate) {\n let\n is = 0,\n iok = 0,\n lastIs = 0,\n lastiok = true,\n result = true,\n chs = '',\n chok = '';\n\n if (ls === 0 || lok === 0 || src === null || ok === null)\n return false;\n\n for (; is < ls; is++, iok++) {\n chs = src.charAt(is);\n lastIs = is;\n if (iok >= 0 && iok < lok)\n chok = ok.charAt(iok);\n else\n chok = 0;\n if (this.collator.compare(chs, chok) === 0) {\n attr[is] = 0;\n lastiok = true;\n } else {\n result = false;\n attr[is] = 1;\n if (!iterate && lastiok && chok !== 0 && this.checkSteps > 0 && this.checkScope > 0) {\n const\n lbloc = 2 * this.checkSteps + 1,\n itcoinc = [];\n let i = 0, j = 0;\n for (; j < lbloc; j++) {\n itcoinc[j] = 0;\n i = iok + Math.floor((j + 1) / 2) * ((j & 1) !== 0 ? 1 : -1);\n if (i >= lok)\n continue;\n const is2 = i < 0 ? is - i : is;\n if (is2 >= ls)\n continue;\n const\n ls2 = Math.min(ls - is2, this.checkScope),\n iok2 = i < 0 ? 0 : i,\n lok2 = Math.min(lok - iok2, this.checkScope),\n flags2 = Array(src.length - is2).fill(0),\n result2 = this.compareSegment(src.substring(is2), ls2, ok.substring(iok2), lok2, flags2, true);\n itcoinc[j] = this.countFlagsOk(flags2);\n if (result2)\n break;\n }\n if (j === lbloc) {\n let jmax = this.checkSteps;\n for (j = 0; j < lbloc; j++)\n if (itcoinc[j] > itcoinc[jmax])\n jmax = j;\n i = iok + Math.floor((jmax + 1) / 2) * ((jmax & 1) !== 0 ? 1 : -1);\n }\n iok = i;\n lastiok = false;\n }\n }\n }\n if (iok !== lok) {\n result = false;\n attr[lastIs] = 1;\n }\n return result;\n }\n}\n\nObject.assign(ComplexEvaluator.prototype, {\n /**\n * Whether to detail or not the location of errors found on the analyzed text.\n * @name module:activities/text/Evaluator.ComplexEvaluator#detail\n * @type {boolean} */\n detail: true,\n /**\n * Number of times to repeat the evaluation process if an error is found, eliminating in each\n * cycle the extra characters that caused the error.\n * @name module:activities/text/Evaluator.ComplexEvaluator#checkSteps\n * @type {number} */\n checkSteps: 3,\n /**\n * When an eror is detected in the analyzed expression, this variable indicates the number of\n * characters the checking pointer will be moved forward and back looking for a coincident\n * expression.\n *\n * For example, comparing the answer \"_one lardzy dog_\" with the correct answer \"_one lazy dog_\"\n * will detect an error at position 6 (an \"r\" instead of \"z\"). If `checkSteps` is set to 2 or\n * greater, the \"_zy dog_\" expression at position 8 will be found and evaluated as valid, while\n * a value of 1 or less will not found any coincident expression beyond the error position, thus\n * evaluating all the remaining sentence as erroneous.\n * @name module:activities/text/Evaluator.ComplexEvaluator#checkScope\n * @type {number} */\n checkScope: 6,\n});\n\n// List of known Evaluator classes\nEvaluator.CLASSES = {\n '@BasicEvaluator': BasicEvaluator,\n '@ComplexEvaluator': ComplexEvaluator\n};\n\nexport default Evaluator;\n","/**\n * File : activities/text/TextActivityDocument.js\n * Created : 14/04/2015\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\n/* global structuredClone */\n\nimport $ from 'jquery';\nimport { log, attrForEach, checkColor, getBoolean, getAttr, setAttr, getVal, getNumber, settings } from '../../Utils.js';\nimport ActiveBoxContent from '../../boxes/ActiveBoxContent.js';\nimport MediaContent from '../../media/MediaContent.js';\n\n/**\n * This is the HTML DOM element used in text activities like {@link module:activities/text/FillInBlanks.FillInBlanks FillInBlanks},\n * {@link module:activities/text/IdentifyText.IdentifyText IdentifyText}, {@link module:activities/text/OrderText.OrderText OrderText} and {@link module:activities/text/Complete.Complete Complete}. It contains the main document of\n * the activity, usually with some elements marked as \"targets\". In {@link module:activities/text/FillInBlanks.FillInBlanks FillInBlanks}, this\n * targets are encapsulated in {@link module:activities/text/TextActivityDocument.TextTarget TextTarget} objects.\n */\nexport class TextActivityDocument {\n /**\n * TextActivityDocument constructor\n */\n constructor() {\n // Make a deep clone of the default style\n this.style = { 'default': structuredClone(TextActivityDocument.DEFAULT_DOC_STYLE) };\n this.p = [];\n }\n\n /**\n * Loads the document settings from a specific JQuery XML element\n * @param {external:jQuery} $xml - The XML element to parse\n * @param {module:bags/MediaBag.MediaBag} mediaBag - The media bag used to load images and media content\n */\n setProperties($xml, mediaBag) {\n // Read named styles\n // Sort styles according to its \"base\" dependencies\n const styles = $xml.children('style').toArray().sort((a, b) => {\n var aName = a.getAttribute('name'), aBase = a.getAttribute('base') || null;\n var bName = b.getAttribute('name'), bBase = b.getAttribute('base') || null;\n // Put 'default' always first, then each style below their base (if any)\n return aName === 'default' ? -1 : bName === 'default' ? 1\n : aBase === bName ? 1 : bBase === aName ? -1\n : !aBase ? -1 : !bBase ? 1 : 0;\n });\n\n // Process the ordered list of styles\n styles.forEach(style => {\n const attr = this.readDocAttributes($(style));\n // Grant always that basic attributes are defined\n this.style[attr.name] = attr.name === 'default' ? $.extend(true, this.style.default, attr) : attr;\n });\n\n // Read paragraphs\n $xml.find('section > p').each((_n, par) => {\n\n const p = { elements: [] };\n\n // Read paragraph attributes\n attrForEach(par.attributes, (name, value) => {\n switch (name) {\n case 'style':\n p[name] = value;\n break;\n case 'bidiLevel':\n case 'Alignment':\n p[name] = Number(value);\n break;\n }\n });\n\n // Read paragraph objects\n $(par).children().each((_n, child) => {\n let obj;\n const $child = $(child);\n switch (child.nodeName) {\n\n case 'cell':\n obj = new ActiveBoxContent().setProperties($child, mediaBag);\n break;\n\n case 'text':\n obj = { text: child.textContent.replace(/\\t/g, '	') };\n const attr = this.readDocAttributes($child);\n if (!$.isEmptyObject(attr)) {\n obj.attr = attr;\n }\n break;\n\n case 'target':\n obj = new TextTarget(this, child.textContent.replace(/\\t/g, '	'));\n obj.setProperties($child, mediaBag);\n this.numTargets++;\n break;\n\n default:\n log('error', `Unknown object in activity document: \"${child.nodeName}\"`);\n }\n if (obj) {\n obj.objectType = child.nodeName;\n p.elements.push(obj);\n }\n });\n\n this.p.push(p);\n });\n return this;\n }\n\n /**\n * Reads sets of text attributes, sometimes in form of named styles\n * @param {external:jQuery} $xml - The XML element to parse\n * @returns {object}\n */\n readDocAttributes($xml) {\n let\n attr = {},\n css = {};\n attrForEach($xml.get(0).attributes, (name, val) => {\n switch (name) {\n case 'background':\n val = checkColor(val, 'white');\n attr[name] = val;\n css['background-color'] = val;\n break;\n case 'foreground':\n val = checkColor(val, 'black');\n attr[name] = val;\n css['color'] = val;\n break;\n case 'family':\n css['font-family'] = val;\n /* falls through */\n case 'name':\n case 'style':\n // Attributes specific to named styles:\n attr[name] = val;\n break;\n case 'base':\n attr[name] = val;\n // If base style exists, merge it with current settings\n if (this.style[val]) {\n //attr = Object.apply({}, this.style[val], attr)\n attr = $.extend(true, {}, this.style[val], attr);\n if (this.style[val].css)\n //css = Object.apply({}, this.style[val].css, css)\n css = $.extend({}, this.style[val].css, css);\n }\n break;\n case 'bold':\n val = getBoolean(val);\n attr[name] = val;\n css['font-weight'] = val ? 'bold' : 'normal';\n break;\n case 'italic':\n val = getBoolean(val);\n attr[name] = val;\n css['font-style'] = val ? 'italic' : 'normal';\n break;\n case 'target':\n attr[name] = getBoolean(val);\n break;\n case 'size':\n attr[name] = Number(val);\n css['font-size'] = `${val}px`;\n break;\n case 'tabWidth':\n // `tab-size` CSS attribute is only set when the document has a specific `tabWidth`\n // setting. It must be accompanied of `white-space:pre` to successfully work.\n this.tabSpc = val;\n css['tab-size'] = this.tabSpc;\n css['white-space'] = 'pre-wrap';\n break;\n default:\n log('warn', `Unknown text attribute: \"${name}\" = \"${val}\"`);\n attr[name] = val;\n break;\n }\n });\n\n if (!$.isEmptyObject(css))\n attr['css'] = css;\n\n return attr;\n }\n\n /**\n * Gets a object with the basic attributes needed to rebuild this instance excluding functions,\n * parent references, constants and also attributes retaining the default value.\n * The resulting object is commonly usued to serialize elements in JSON format.\n * @returns {object} - The resulting object, with minimal attrributes\n */\n getAttributes() {\n // TODO: simplify the serialization of styles (now too verbose!)\n return getAttr(this, ['style', 'tabSpc', 'targetType', 'p']);\n }\n\n /**\n * Reads the properties of this TextActivityDocument from a data object\n * @param {object} data - The data object to be parsed, or just the text content\n * @returns {module:activities/text/TextActivityDocument.TextActivityDocument}\n */\n setAttributes(data, mediaBag) {\n\n setAttr(this, data, ['style', 'tabSpc', 'targetType', 'p']);\n\n // Build paragraphs:\n this.p.forEach(p => {\n if (p.elements)\n p.elements = p.elements.map(el => {\n if (el.objectType === 'cell')\n return (new ActiveBoxContent()).setAttributes(el, mediaBag);\n else if (el.objectType === 'target')\n return (new TextTarget(this)).setAttributes(el, mediaBag);\n else\n return el;\n });\n else\n p.elements = [];\n });\n return this;\n }\n\n /**\n * Gets the full text of this document in raw format\n * @returns {string} - The text of the document.\n */\n getRawText() {\n const $html = $('<div/>');\n // Process paragraphs\n this.p.forEach(p => {\n // Creates a new DOM paragraph\n const $p = $('<p/>');\n let empty = true;\n // Process the paragraph elements\n p.elements.forEach(element => {\n switch (element.objectType) {\n case 'text':\n case 'target':\n $p.append(element.text);\n break;\n case 'cell':\n // cells are not considered raw text of the document\n break;\n default:\n break;\n }\n empty = false;\n });\n if (empty) {\n // Don't leave paragraphs empty\n $p.html(' ');\n }\n // Adds the paragraph to the DOM element\n $html.append($p);\n });\n return $html.text().trim();\n }\n\n /**\n * Gets a `style` object filled with default attributes plus attributes present in the\n * requested style name.\n * @param {string} name - The requested style name\n * @returns {object} - The result of combining `default` with the requested style\n */\n getFullStyle(name) {\n const st = $.extend(true, {}, this.style.default);\n return $.extend(true, st, this.style[name] ? this.style[name] : {});\n //return Object.assign({}, this.style.default, this.style[name] ? this.style[name] : {})\n }\n}\n\n/**\n * Default style\n */\nTextActivityDocument.DEFAULT_DOC_STYLE = {\n background: '0xFFFFFF',\n foreground: '0x000000',\n family: 'Arial',\n bold: false,\n italic: false,\n size: 17,\n css: {\n 'background-color': '#FFFFFF',\n 'color': '#000000',\n 'font-family': 'Arial',\n 'font-weight': 'normal',\n 'font-style': 'normal',\n 'font-size': '17px',\n },\n};\n\nObject.assign(TextActivityDocument.prototype, {\n /**\n * Number of blank spaces between tabulators.\n * @name module:activities/text/TextActivityDocument.TextActivityDocument#tabSpc\n * @type {number} */\n tabSpc: 12,\n /**\n * Index of the last {@link module:boxes/ActiveBox.ActiveBox ActiveBox} activated.\n * @name module:activities/text/TextActivityDocument.TextActivityDocument#lastBoxId\n * @type {number} */\n lastBoxId: 0,\n /**\n * A bag of {@link module:activities/text/TextActivityDocument.TargetMarker TargetMarker} objects\n * @name module:activities/text/TextActivityDocument.TextActivityDocument#tmb\n * @type {object} */\n tmb: null,\n /**\n * Number of targets\n * @name module:activities/text/TextActivityDocument.TextActivityDocument#numTargets\n * @type {number} */\n numTargets: 0,\n /**\n * Type of targets used in this activity. Possible values are: `TT_FREE`, `TT_CHAR`, `TT_WORD`\n * and `TT_PARAGRAPH`.\n * @name module:activities/text/TextActivityDocument.TextActivityDocument#targetType\n * @type {string} */\n targetType: 'TT_FREE',\n /**\n * Collection of named styles of the document\n * @name module:activities/text/TextActivityDocument.TextActivityDocument#style\n * @type {object} */\n style: null,\n /**\n * The main document, represented as a collection of DOM objects\n * @name module:activities/text/TextActivityDocument.TextActivityDocument#p\n * @type {object} */\n p: null,\n});\n\n/**\n * This class contains the properties and methods of the document elements that are the real\n * targets of user actions in text activities.\n */\nexport class TextTarget {\n /**\n * TextTarget constructor\n * @param {module:activities/text/TextActivityDocument.TextActivityDocument} doc - The document to which this target belongs.\n * @param {string} text - Main text of this target.\n */\n constructor(doc, text = '') {\n this.doc = doc;\n this.text = text;\n this.numIniChars = text.length;\n this.answers = [text];\n this.maxLenResp = this.numIniChars;\n }\n\n /**\n * Resets the TextTarget status\n * @param {string} [status] - The `targetStatus` to be established. Default is `NOT_EDITED`\n */\n reset(status) {\n this.targetStatus = status ? status : 'NOT_EDITED';\n this.flagModified = false;\n }\n\n /**\n * Loads the text target settings from a specific JQuery XML element\n * @param {external:jQuery} $xml - The XML element to parse\n * @param {module:bags/MediaBag.MediaBag} mediaBag - The media bag used to load images and media content\n */\n setProperties($xml, mediaBag) {\n let firstAnswer = true;\n // Read specific nodes\n $xml.children().each((_n, child) => {\n const $node = $(child);\n switch (child.nodeName) {\n case 'answer':\n if (firstAnswer) {\n firstAnswer = false;\n this.answers = [];\n }\n if (this.answers === null)\n this.answers = [];\n this.answers.push(child.textContent);\n break;\n\n case 'optionList':\n $node.children('option').each((_n, opChild) => {\n this.isList = true;\n if (this.options === null)\n this.options = [];\n this.options.push(opChild.textContent);\n });\n break;\n\n case 'response':\n this.iniChar = getVal($node.attr('fill'), this.iniChar).charAt(0);\n // Use underscores instead of whitespace chars\n if (settings.WHITESPACES.indexOf(this.iniChar) >= 0)\n this.iniChar = '_';\n this.numIniChars = getNumber($node.attr('length'), this.numIniChars);\n this.maxLenResp = getNumber($node.attr('maxLength'), this.maxLenResp);\n this.iniText = getVal($node.attr('show'), this.iniText);\n break;\n\n case 'info':\n this.infoMode = getVal($node.attr('mode'), 'always');\n this.popupDelay = getNumber($node.attr('delay'), this.popupDelay);\n this.popupMaxTime = getNumber($node.attr('maxTime'), this.popupMaxTime);\n $node.children('media').each((_n, media) => {\n this.onlyPlay = true;\n this.popupContent = new ActiveBoxContent();\n this.popupContent.mediaContent = new MediaContent().setProperties($(media));\n });\n if (!this.popupContent) {\n $node.children('cell').each((_n, cell) => {\n this.popupContent = new ActiveBoxContent().setProperties($(cell), mediaBag);\n });\n }\n break;\n\n case 'text':\n this.text = child.textContent.replace(/\\t/g, '	');\n const attr = this.doc.readDocAttributes($(child));\n if (!$.isEmptyObject(attr))\n this.attr = attr;\n break;\n\n default:\n break;\n }\n });\n }\n\n /**\n * Gets a object with the basic attributes needed to rebuild this instance excluding functions,\n * parent references, constants and also attributes retaining the default value.\n * The resulting object is commonly usued to serialize elements in JSON format.\n * @returns {object} - The resulting object, with minimal attrributes\n */\n getAttributes() {\n return getAttr(this, [\n 'objectType', 'text', 'attr', 'isList',\n 'answers', 'options', 'iniChar', 'numIniChars', 'maxLenResp', 'iniText',\n 'infoMode', 'popupDelay', 'popupKey', 'popupMaxTime', 'onlyPlay',\n 'popupContent',\n ]);\n }\n\n /**\n * Reads the properties of this TextTarget from a data object\n * @param {object} data - The data object to be parsed, or just the text content\n * @returns {module:activities/text/TextActivityDocument.TextTarget}\n */\n setAttributes(data, mediaBag) {\n return setAttr(this, data, [\n 'objectType', 'text', 'attr', 'isList',\n 'answers', 'options', 'iniChar', 'numIniChars', 'maxLenResp', 'iniText',\n 'infoMode', 'popupDelay', 'popupKey', 'popupMaxTime', 'onlyPlay',\n { key: 'popupContent', fn: ActiveBoxContent, params: [mediaBag] },\n ]);\n }\n\n /**\n * Gets a string with all valid answers of this TextTarget. Useful for reporting users' activity.\n * @returns {string}\n */\n getAnswers() {\n return this.answers ? this.answers.join('|') : '';\n }\n\n /**\n * Sets specific colors to the target jQuery element, based on its `targetStatus` value. Red\n * color usually means error.\n */\n checkColors() {\n const $element = this.$comboList || this.$span;\n if ($element) {\n const style = this.doc.style[\n this.targetStatus === 'WITH_ERROR' ? 'targetError' :\n this.targetStatus === 'HIDDEN' ? 'default' : 'target'];\n if (style && style.css) {\n $element.css(style.css);\n }\n }\n }\n\n /**\n * Fills the `currentText` member with the text currently hosted in $span or selected in $comboList\n * @returns {string} - The current text of this target\n */\n readCurrentText() {\n if (this.$span)\n this.currentText = this.$span.text();\n else if (this.$comboList)\n this.currentText = this.$comboList.val();\n return this.currentText;\n }\n}\n\nObject.assign(TextTarget.prototype, {\n /**\n * The {@link module:activities/text/TextActivityDocument.TextActivityDocument TextActivityDocument} to which this target belongs\n * @name module:activities/text/TextActivityDocument.TextTarget#doc\n * @type {module:activities/text/TextActivityDocument.TextActivityDocument} */\n doc: null,\n /**\n * The current text displayed by this TextTarget\n * @name module:activities/text/TextActivityDocument.TextTarget#text\n * @type {string} */\n text: null,\n /**\n * A set of optional attributes for `text`\n * @name module:activities/text/TextActivityDocument.TextTarget#attr\n * @type {object} */\n attr: null,\n /**\n * `true` when the target is a drop-down list\n * @name module:activities/text/TextActivityDocument.TextTarget#isList\n * @type {boolean} */\n isList: false,\n /**\n * Number of characters initially displayed on the text field\n * @name module:activities/text/TextActivityDocument.TextTarget#numIniChars\n * @type {number} */\n numIniChars: 1,\n /**\n * Character used to fill-in the text field\n * @name module:activities/text/TextActivityDocument.TextTarget#iniChar\n * @type {string} */\n iniChar: '_',\n /**\n * Maximum length of the answer\n * @name module:activities/text/TextActivityDocument.TextTarget#maxLenResp\n * @type {number} */\n maxLenResp: 0,\n /**\n * Array of valid answers\n * @name module:activities/text/TextActivityDocument.TextTarget#answers\n * @type {string[]} */\n answers: null,\n /**\n * Set of specific options\n * @name module:activities/text/TextActivityDocument.TextTarget#options\n * @type {object} */\n options: null,\n /**\n * Text displayed by the target when the activity begins\n * @name module:activities/text/TextActivityDocument.TextTarget#iniText\n * @type {string} */\n iniText: null,\n /**\n * Type of additional information offered to the user. Possible values are: `no_info`, `always`,\n * `onError` and `onDemand`.\n * @name module:activities/text/TextActivityDocument.TextTarget#infoMode\n * @type {string} */\n infoMode: 'no_info',\n /**\n * Key that triggers the associated popup when `infoMode` is `onDemand`\n * @name module:activities/text/TextActivityDocument.TextTarget#popupKey\n * @type {string} */\n popupKey: 'F1',\n /**\n * An optional {@link module:boxes/ActiveBoxContent.ActiveBoxContent ActiveBoxContent} with information about this TextTarget\n * @name module:activities/text/TextActivityDocument.TextTarget#popupContent\n * @type {module:boxes/ActiveBoxContent.ActiveBoxContent} */\n popupContent: null,\n /**\n * Time (seconds) to wait before showing the additional information\n * @name module:activities/text/TextActivityDocument.TextTarget#popupDelay\n * @type {number} */\n popupDelay: 0,\n /**\n * Maximum amount of time (seconds) that the additional information will be shown\n * @name module:activities/text/TextActivityDocument.TextTarget#popupMaxTime\n * @type {number} */\n popupMaxTime: 0,\n /**\n * When this flag is `true` and `popupContent` contains audio, no visual feedback will be\n * provided (meaning that audio will be just played)\n * @name module:activities/text/TextActivityDocument.TextTarget#onlyPlay\n * @type {boolean} */\n onlyPlay: false,\n //\n // TRANSIENT PROPERTIES\n //\n /**\n * The drop-down list associated to this target\n * @name module:activities/text/TextActivityDocument.TextTarget#$comboList\n * @type {external:jQuery} */\n $comboList: null,\n /**\n * The span element associated to this target\n * @name module:activities/text/TextActivityDocument.TextTarget#$span\n * @type {external:jQuery} */\n $span: null,\n /**\n * The paragraph element where $span is currently located\n * @name module:activities/text/TextActivityDocument.TextTarget#$p\n * @type {external:jQuery} */\n $p: null,\n /**\n * The span element containing the popup\n * @name module:activities/text/TextActivityDocument.TextTarget#$popup\n * @type {external:jQuery} */\n $popup: null,\n /**\n * Current text in the $span element\n * @name module:activities/text/TextActivityDocument.TextTarget#currentText\n * @type {string} */\n currentText: '',\n /**\n * Ordinal number of this target in the collection of targets\n * @name module:activities/text/TextActivityDocument.TextTarget#num\n * @type {number} */\n num: 0,\n /**\n * Current ordinal position of this target in the document\n * (used in {@link module:activities/text/OrderText.OrderText OrderText} activities)\n * @name module:activities/text/TextActivityDocument.TextTarget#pos\n * @type {number} */\n pos: 0,\n /**\n * Current status of the target. Valid values are: `NOT_EDITED`, `EDITED`, `SOLVED`, `WITH_ERROR` and `HIDDEN`\n * @name module:activities/text/TextActivityDocument.TextTarget#targetStatus\n * @type {string} */\n targetStatus: 'NOT_EDITED',\n /**\n * Flag to control if the initial content of this TextTarget has been modified\n * @name module:activities/text/TextActivityDocument.TextTarget#flagModified\n * @type {boolean} */\n flagModified: false,\n /**\n * Pointer to the activity panel containing this TextTarget\n * @name module:activities/text/TextActivityDocument.TextTarget#parentPane\n * @type {module:activities/text/TextActivityBase.TextActivityBasePanel} */\n parentPane: null,\n});\n\nTextActivityDocument.TextTarget = TextTarget;\n\nexport default TextActivityDocument;\n","/**\n * File : Activity.js\n * Created : 07/04/2015\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\n/* global window */\n\nimport $ from 'jquery';\nimport { settings, log, getMsg, attrForEach, nSlash, getBoolean, getXmlText, checkColor, isNullOrUndef, getAttr, setAttr } from './Utils.js';\nimport { Rectangle, Gradient, Point, Dimension, Container } from './AWT.js';\nimport EventSounds from './media/EventSounds.js';\nimport ActiveBoxContent from './boxes/ActiveBoxContent.js';\nimport ActiveBagContent from './boxes/ActiveBagContent.js';\nimport BoxBase from './boxes/BoxBase.js';\nimport AutoContentProvider from './automation/AutoContentProvider.js';\nimport TextGridContent from './boxes/TextGridContent.js';\nimport Evaluator from './activities/text/Evaluator.js';\nimport TextActivityDocument from './activities/text/TextActivityDocument.js';\n\n// Event used for detecting touch devices\nconst TOUCH_TEST_EVENT = 'touchstart';\n\n/**\n * Activity is the abstract base class of JClic activities. It defines also the inner class\n * {@link module:Activity.ActivityPanel ActivityPanel}, wich is responsible for user interaction with the activity\n * content.\n * Activities should extend both `Activity` and `ActivityPanel` classes in order to become fully\n * operative.\n * @abstract\n */\nexport class Activity {\n /**\n * Activity constructor\n * @param {module:project/JClicProject.JClicProject} project - The {@link module:project/JClicProject.JClicProject JClicProject} to which this activity belongs\n */\n constructor(project) {\n this.project = project;\n this.eventSounds = new EventSounds(this.project.settings.eventSounds);\n this.messages = {};\n this.abc = {};\n }\n\n /**\n * Registers a new type of activity\n * @param {string} activityName - The name used to identify this activity\n * @param {function} activityClass - The activity class, usually extending Activity\n * @returns {module:Activity.Activity} - The provided activity class\n */\n static registerClass(activityName, activityClass) {\n Activity.CLASSES[activityName] = activityClass;\n return activityClass;\n }\n\n /**\n * Factory constructor that returns a specific type of Activity based on the `class` attribute\n * declared in `data`.\n * @param {object|external:jQuery} data - Can be a jQuery XML element, or an object obtained with a call to `getAttributes`\n * @param {module:project/JClicProject.JClicProject} project - The {@link module:project/JClicProject.JClicProject JClicProject} to which this activity belongs\n * @returns {module:Activity.Activity}\n */\n static getActivity(data, project) {\n let act = null;\n const isXml = data.jquery && true;\n if (data && project) {\n const className = isXml ? (data.attr('class') || '').replace(/^edu\\.xtec\\.jclic\\.activities\\./, '@') : data.className;\n const cl = Activity.CLASSES[className];\n if (cl) {\n act = new cl(project);\n if (isXml)\n act.setProperties(data);\n else\n act.setAttributes(data);\n } else\n log('error', `Unknown activity class: ${className}`);\n }\n return act;\n }\n\n /**\n * Loads this object settings from an XML element\n * @param {external:jQuery} $xml - The jQuery XML element to parse\n */\n setProperties($xml) {\n\n // Read attributes\n attrForEach($xml.get(0).attributes, (name, val) => {\n switch (name) {\n // Generic attributes:\n case 'name':\n val = nSlash(val);\n /* falls through */\n case 'code':\n case 'type':\n case 'description':\n this[name] = val;\n break;\n\n case 'class':\n this.className = val.replace(/^edu\\.xtec\\.jclic\\.activities\\./, '@');\n break;\n\n case 'inverse':\n this.invAss = getBoolean(val, false);\n break;\n\n case 'autoJump':\n case 'forceOkToAdvance':\n case 'amongParagraphs':\n this[name] = getBoolean(val, false);\n break;\n }\n });\n\n // Read specific nodes\n $xml.children().each((_n, child) => {\n const $node = $(child);\n switch (child.nodeName) {\n case 'settings':\n // Read more attributes\n attrForEach($node.get(0).attributes, (name, val) => {\n switch (name) {\n case 'infoUrl':\n case 'infoCmd':\n this[name] = val;\n break;\n\n case 'margin':\n case 'maxTime':\n case 'maxActions':\n this[name] = Number(val);\n break;\n\n case 'report':\n this.includeInReports = getBoolean(val, false);\n break;\n case 'countDownTime':\n case 'countDownActions':\n case 'reportActions':\n case 'useOrder':\n case 'dragCells':\n this[name] = getBoolean(val, false);\n break;\n }\n });\n\n // Read elements of _settings_\n $node.children().each((_n, child) => {\n const $node = $(child);\n switch (child.nodeName) {\n case 'skin':\n this.skinFileName = $node.attr('file');\n break;\n\n case 'helpWindow':\n this.helpMsg = getXmlText(this);\n this.showSolution = getBoolean($node.attr('showSolution'), false);\n this.helpWindow = this.helpMsg !== null || this.showSolution;\n break;\n\n case 'container':\n // Read settings related to the 'container'\n // (the main panel containing the activity and other elements)\n this.bgColor = checkColor($node.attr('bgColor'), settings.BoxBase.BACK_COLOR);\n\n $node.children().each((_n, child) => {\n const $child = $(child);\n switch (child.nodeName) {\n case 'image':\n this.bgImageFile = $child.attr('name');\n this.tiledBgImg = getBoolean($child.attr('tiled'), false);\n break;\n case 'counters':\n this.bTimeCounter = getBoolean($child.attr('time'), true);\n this.bActionsCounter = getBoolean($child.attr('actions'), true);\n this.bScoreCounter = getBoolean($child.attr('score'), true);\n break;\n case 'gradient':\n this.bgGradient = new Gradient().setProperties($child);\n break;\n }\n });\n break;\n\n case 'window':\n // Read settings related to the 'window'\n // (the panel where the activity deploys its content)\n this.activityBgColor = checkColor($node.attr('bgColor'), settings.DEFAULT_BG_COLOR);\n this.transparentBg = getBoolean($node.attr('transparent'), false);\n this.border = getBoolean($node.attr('border'), false);\n $node.children().each((_n, child) => {\n const $child = $(child);\n switch (child.nodeName) {\n case 'gradient':\n this.activityBgGradient = new Gradient().setProperties($child);\n break;\n case 'position':\n this.absolutePosition = new Point().setProperties($child);\n this.absolutePositioned = true;\n break;\n case 'size':\n this.windowSize = new Dimension().setProperties($child);\n break;\n }\n });\n break;\n\n case 'eventSounds':\n // eventSounds is already created in constructor,\n // just read properties\n this.eventSounds.setProperties($node);\n break;\n }\n });\n break;\n\n case 'messages':\n $node.children('cell').each((_n, child) => {\n const m = this.readMessage($(child));\n // Possible message types are: `initial`, `final`, `previous`, `finalError`\n this.messages[m.type] = m;\n });\n break;\n\n case 'automation':\n // Read the automation settings ('Arith' or other automation engines)\n this.acp = AutoContentProvider.getProvider($node, this.project);\n if (this.acp)\n this.numericContent = this.acp.numericContent;\n break;\n\n // Settings specific to panel-type activities (puzzles, associations...)\n case 'cells':\n // Read the [ActiveBagContent](ActiveBagContent.html) objects\n const cellSet = new ActiveBagContent().setProperties($node, this.project.mediaBag);\n // Valid ids:\n // - Panel activities: 'primary', 'secondary', solvedPrimary'\n // - Textpanel activities: 'acrossClues', 'downClues', 'answers'\n this.abc[cellSet.id] = cellSet;\n break;\n\n case 'scramble':\n // Read the 'shuffle' mode\n this.shuffles = Number($node.attr('times'));\n this.shuffleA = getBoolean($node.attr('primary'));\n this.shuffleB = getBoolean($node.attr('secondary'));\n break;\n\n case 'layout':\n attrForEach($node.get(0).attributes, (name, value) => {\n switch (name) {\n case 'position':\n this.boxGridPos = value;\n break;\n case 'wildTransparent':\n case 'upperCase':\n case 'checkCase':\n this[name] = getBoolean(value);\n }\n });\n break;\n\n // Element specific to 'Menu' activities:\n case 'menuElement':\n this.menuElements.push({\n caption: $node.attr('caption') || '',\n icon: $node.attr('icon') || null,\n projectPath: $node.attr('path') || null,\n sequence: $node.attr('sequence') || null,\n description: $node.attr('description') || ''\n });\n break;\n\n // Element specific to 'CrossWord' and\n // 'WordSearch' activities:\n case 'textGrid':\n // Read the 'textGrid' element into a 'TextGridContent'\n this.tgc = new TextGridContent().setProperties($node);\n break;\n\n // Read the clues of 'WordSearch' activities\n case 'clues':\n // Read the array of clues\n this.clues = [];\n this.clueItems = [];\n $node.children('clue').each((n, child) => {\n this.clueItems[n] = Number($(child).attr('id'));\n this.clues[n] = child.textContent;\n });\n break;\n\n // Elements specific to text activities:\n case 'checkButton':\n this.checkButtonText = child.textContent || 'check';\n break;\n\n case 'prevScreen':\n this.prevScreen = true;\n this.prevScreenMaxTime = $node.attr('maxTime') || -1;\n $node.children().each((_n, child) => {\n switch (child.nodeName) {\n case 'style':\n this.prevScreenStyle = new BoxBase().setProperties($(child));\n break;\n case 'p':\n if (this.prevScreenText === null)\n this.prevScreenText = '';\n this.prevScreenText += `<p>${child.textContent}</p>`;\n break;\n }\n });\n break;\n\n case 'evaluator':\n this.ev = Evaluator.getEvaluator($node);\n break;\n\n case 'document':\n // Read main document of text activities\n this.document = new TextActivityDocument().setProperties($node, this.project.mediaBag);\n break;\n }\n });\n return this;\n }\n\n /**\n * Read an activity message from an XML element\n * @param {external:jQuery} $xml - The XML element to be parsed\n * @returns {module:boxes/ActiveBoxContent.ActiveBoxContent}\n */\n readMessage($xml) {\n const msg = new ActiveBoxContent().setProperties($xml, this.project.mediaBag);\n //\n // Allowed types are: `initial`, `final`, `previous`, `finalError`\n msg.type = $xml.attr('type');\n if (isNullOrUndef(msg.style))\n msg.style = new BoxBase(null);\n return msg;\n }\n\n /**\n * Gets a object with the basic attributes needed to rebuild this instance excluding functions,\n * parent references, constants and also attributes retaining the default value.\n * The resulting object is commonly usued to serialize elements in JSON format.\n * @returns {object} - The resulting object, with minimal attrributes\n */\n getAttributes() {\n return getAttr(this, [\n 'name', 'className', 'code', 'type', 'description',\n 'invAss', 'numericContent',\n 'autoJump', 'forceOkToAdvance', 'amongParagraphs',\n 'infoUrl', 'infoCmd',\n `margin|${settings.DEFAULT_MARGIN}`, 'maxTime', 'maxActions',\n 'includeInReports|true', 'reportActions|false',\n 'countDownTime', 'countDownActions',\n 'useOrder', 'dragCells',\n 'skinFileName',\n 'showSolution|false', 'helpMsg',\n `bgColor|${settings.DEFAULT_BG_COLOR}`, 'bgImageFile', 'tiledBgImg',\n 'bTimeCounter|true', 'bActionsCounter|true', 'bScoreCounter|true',\n `activityBgColor|${settings.DEFAULT_BG_COLOR}`, 'transparentBg|false', 'border|true',\n 'shuffleA', 'shuffleB', 'shuffles', 'boxGridPos',\n 'wildTransparent', 'upperCase', 'checkCase',\n 'checkButtonText',\n 'prevScreen', 'prevScreenMaxTime', 'prevScreenText',\n 'bgGradient', 'activityBgGradient', // Gradient\n 'absolutePosition', // Point\n 'windowSize', // Dimension\n 'eventSounds', // EventSounds\n 'messages', // ActiveBoxContent{}\n 'acp', // AutoContentProvider\n 'abc', // ActiveBagContent{}\n 'menuElements', // Activity~menuElement\n 'tgc', // TextGridContent\n 'clues', // string[]\n 'clueItems', // number[]\n 'prevScreenStyle', // BoxBase\n 'ev', // Evaluator\n 'document', // TextActivityDocument\n ]);\n }\n\n /**\n * Load the activity settings from a data object\n * @param {object} data - The data object to parse\n */\n setAttributes(data, mediaBag = this.project.mediaBag) {\n setAttr(this, data, [\n 'name', 'className', 'code', 'type', 'description', 'invAss', 'numericContent',\n 'autoJump', 'forceOkToAdvance', 'amongParagraphs', 'infoUrl', 'infoCmd',\n 'margin', 'maxTime', 'maxActions', 'includeInReports', 'reportActions',\n 'countDownTime', 'countDownActions', 'useOrder', 'dragCells', 'skinFileName',\n 'showSolution', 'helpMsg', 'bgColor', 'bgImageFile', 'tiledBgImg',\n 'bTimeCounter', 'bActionsCounter', 'bScoreCounter',\n 'activityBgColor', 'transparentBg', 'border',\n 'shuffleA', 'shuffleB', 'shuffles', 'boxGridPos',\n 'wildTransparent', 'upperCase', 'checkCase', 'checkButtonText',\n 'prevScreen', 'prevScreenMaxTime', 'prevScreenText',\n { key: 'bgGradient', fn: Gradient },\n { key: 'activityBgGradient', fn: Gradient },\n { key: 'absolutePosition', fn: Point },\n { key: 'windowSize', fn: Dimension },\n { key: 'messages', fn: ActiveBoxContent, group: 'object', init: 'key', params: [mediaBag] },\n { key: 'abc', fn: ActiveBagContent, group: 'object', init: 'key', params: [mediaBag] },\n { key: 'acp', fn: AutoContentProvider, params: [mediaBag] },\n 'menuElements',\n { key: 'tgc', fn: TextGridContent },\n 'clues',\n 'clueItems',\n { key: 'prevScreenStyle', fn: BoxBase },\n { key: 'ev', fn: Evaluator },\n { key: 'document', fn: TextActivityDocument, params: [mediaBag] },\n ]);\n\n // Reused objects\n if (data.eventSounds)\n this.eventSounds.setAttributes(data.eventSounds);\n\n // Manual settings\n if (this.absolutePosition)\n this.absolutePositioned = true;\n\n return this;\n }\n\n /**\n * Initialises the {@link module:automation/AutoContentProvider.AutoContentProvider AutoContentProvider}, when defined.\n */\n initAutoContentProvider() {\n if (this.acp !== null)\n this.acp.init();\n }\n\n /**\n * Preloads the media content of the activity.\n * @param {module:JClicPlayer.JClicPlayer} ps - The {@link module:JClicPlayer.JClicPlayer} used to realize the media objects.\n */\n prepareMedia(ps) {\n this.eventSounds.realize(ps, this.project.mediaBag);\n $.each(this.messages, (_key, msg) => {\n if (msg !== null) msg.prepareMedia(ps);\n });\n $.each(this.abc, (_key, abc) => {\n if (abc !== null)\n abc.prepareMedia(ps);\n });\n return true;\n }\n\n /**\n * Whether the activity allows the user to request the solution.\n * @returns {boolean}\n */\n helpSolutionAllowed() {\n return false;\n }\n\n /**\n * Whether the activity allows the user to request help.\n * @returns {boolean}\n */\n helpWindowAllowed() {\n return this.helpWindow &&\n (this.helpSolutionAllowed() && this.showSolution || this.helpMsg !== null);\n }\n\n /**\n * Retrieves the minimum number of actions needed to solve this activity.\n * @returns {number}\n */\n getMinNumActions() {\n return 0;\n }\n\n /**\n * When this method returns `true`, the automatic jump to the next activity must be paused at\n * this activity.\n * @returns {boolean}\n */\n mustPauseSequence() {\n return this.getMinNumActions() !== 0;\n }\n\n /**\n * Whether or not the activity can be reset\n * @returns {boolean}\n */\n canReinit() {\n return true;\n }\n\n /**\n * Whether or not the activity has additional information to be shown.\n * @returns {boolean}\n */\n hasInfo() {\n return this.infoUrl !== null && this.infoUrl.length > 0 ||\n this.infoCmd !== null && this.infoCmd.length > 0;\n }\n\n /**\n * Whether or not the activity uses random to shuffle internal components\n * @returns {boolean}\n */\n hasRandom() {\n return false;\n }\n\n /**\n * When `true`, the activity must always be shuffled\n * @returns {boolean}\n */\n shuffleAlways() {\n return false;\n }\n\n /**\n * When `true`, the activity makes use of the keyboard\n * @returns {boolean}\n */\n needsKeyboard() {\n return false;\n }\n\n /**\n * Called when the activity must be disposed\n */\n end() {\n this.eventSounds.close();\n this.clear();\n }\n\n /**\n * Called when the activity must reset its internal components\n */\n clear() {\n }\n\n /**\n *\n * Getter method for `windowSize`\n * @returns {module:AWT.Dimension}\n */\n getWindowSize() {\n return new Dimension(this.windowSize);\n }\n\n /**\n * Setter method for `windowSize`\n * @param {module:AWT.Dimension} windowSize\n */\n setWindowSize(windowSize) {\n this.windowSize = new Dimension(windowSize);\n }\n\n /**\n * Builds the {@link module:Activity.ActivityPanel ActivityPanel} object.\n * Subclasses must update the `Panel` member of its prototypes to produce specific panels.\n * @param {module:JClicPlayer.JClicPlayer} ps - The {@link module:JClicPlayer.JClicPlayer JClicPlayer} used to build media objects.\n * @returns {module:Activity.ActivityPanel}\n */\n getActivityPanel(ps) {\n return new this.constructor.Panel(this, ps);\n }\n}\n\n/**\n * Classes derived from `Activity` should register themselves by adding a field to\n * `Activity.CLASSES` using `Activity.registerClass`\n * @type {object}\n */\nActivity.CLASSES = {\n '@panels.Menu': Activity\n};\n\nObject.assign(Activity.prototype, {\n /**\n * The {@link module:project/JClicProject.JClicProject JClicProject} to which this activity belongs\n * @name module:Activity.Activity#project\n * @type {module:project/JClicProject.JClicProject} */\n project: null,\n /**\n * The Activity name\n * @name module:Activity.Activity#name\n * @type {string} */\n name: settings.DEFAULT_NAME,\n /**\n * The class name of this Activity\n * @name module:Activity.Activity#className\n * @type {string} */\n className: null,\n /**\n * Code used in reports to filter queries. Default is `null`.\n * @name module:Activity.Activity#code\n * @type {string} */\n code: null,\n /**\n * Type of activity, used in text activities to distinguish between different variants of the\n * same activity. Possible values are: `orderWords`, `orderParagraphs`, `identifyWords` and\n * `identifyChars`.\n * @name module:Activity.Activity#type\n * @type {string} */\n type: null,\n /**\n * A short description of the activity\n * @name module:Activity.Activity#description\n * @type {string} */\n description: null,\n /**\n * The space between the activity components measured in pixels.\n * @name module:Activity.Activity#margin\n * @type {number} */\n margin: settings.DEFAULT_MARGIN,\n /**\n * The background color of the activity panel\n * @name module:Activity.Activity#bgColor\n * @type {string} */\n bgColor: settings.DEFAULT_BG_COLOR,\n /**\n * When set, gradient used to draw the activity window background\n * @name module:Activity.Activity#bgGradient\n * @type {module:AWT.Gradient} */\n bgGradient: null,\n /**\n * Whether the bgImage (if any) has to be tiled across the panel background\n * @name module:Activity.Activity#tiledBgImg\n * @type {boolean} */\n tiledBgImg: false,\n /**\n * Filename of the image used as a panel background.\n * @name module:Activity.Activity#bgImageFile\n * @type {string} */\n bgImageFile: null,\n /**\n * Whether to draw a border around the activity panel\n * @name module:Activity.Activity#border\n * @type {boolean} */\n border: true,\n /**\n * Whether to place the activity panel at the point specified by `absolutePosition` or leave\n * it centered on the main player's window.\n * @name module:Activity.Activity#absolutePositioned\n * @type {boolean} */\n absolutePositioned: false,\n /**\n * The position of the activity panel on the player.\n * @name module:Activity.Activity#absolutePosition\n * @type {module:AWT.Point} */\n absolutePosition: null,\n /**\n * Whether to generate usage reports\n * @name module:Activity.Activity#includeInReports\n * @type {boolean} */\n includeInReports: true,\n /**\n * Whether to send action events to the {@link module:Reporter.Reporter Reporter}\n * @name module:Activity.Activity#reportActions\n * @type {boolean} */\n reportActions: false,\n /**\n * Whether to allow help about the activity or not.\n * @name module:Activity.Activity#helpWindow\n * @type {boolean} */\n helpWindow: false,\n /**\n * Whether to show the solution on the help window.\n * @name module:Activity.Activity#showSolution\n * @type {boolean} */\n showSolution: false,\n /**\n * Message to be shown in the help window when `showSolution` is `false`.\n * @name module:Activity.Activity#helpMsg\n * @type {string} */\n helpMsg: '',\n /**\n * Specific set of {@link module:media/EventSounds.EventSounds EventSounds} used in the activity. The default is `null`, meaning\n * to use the default event sounds.\n * @name module:Activity.Activity#eventSounds\n * @type {module:media/EventSounds.EventSounds} */\n eventSounds: null,\n /**\n * Wheter the activity must be solved in a specific order or not.\n * @name module:Activity.Activity#useOrder\n * @type {boolean} */\n useOrder: false,\n /**\n * Wheter the cells of the activity will be dragged across the screen.\n * When `false`, a line will be painted to link elements.\n * @name module:Activity.Activity#dragCells\n * @type {boolean} */\n dragCells: false,\n /**\n * File name of the Skin used by the activity. The default value is `null`, meaning that the\n * activity will use the skin specified for the project.\n * @name module:Activity.Activity#skinFileName\n * @type {string} */\n skinFileName: null,\n /**\n * Maximum amount of time (seconds) to solve the activity. The default value is 0, meaning\n * unlimited time.\n * @name module:Activity.Activity#maxTime\n * @type {number}*/\n maxTime: 0,\n /**\n * Whether the time counter should display a countdown when `maxTime > 0`\n * @name module:Activity.Activity#countDownTime\n * @type {boolean} */\n countDownTime: false,\n /**\n * Maximum number of actions allowed to solve the activity. The default value is 0, meaning\n * unlimited actions.\n * @name module:Activity.Activity#maxActions\n * @type {number}*/\n maxActions: 0,\n /**\n * Whether the actions counter should display a countdown when `maxActions > 0`\n * @name module:Activity.Activity#countDownActions\n * @type {boolean} */\n countDownActions: false,\n /**\n * URL to be launched when the user clicks on the 'info' button. Default is `null`.\n * @name module:Activity.Activity#infoUrl\n * @type {string} */\n infoUrl: null,\n /**\n * System command to be launched when the user clicks on the 'info' button. Default is `null`.\n * Important: this parameter is currently not being used\n * @name module:Activity.Activity#infoCmd\n * @type {string} */\n infoCmd: null,\n /**\n * The content of the initial, final, previous and error messages shown by the activity.\n * @name module:Activity.Activity#messages\n * @type {module:boxes/ActiveBoxContent.ActiveBoxContent[]} */\n messages: null,\n /**\n * Preferred dimension of the activity window\n * @name module:Activity.Activity#windowSize\n * @type {module:AWT.Dimension} */\n windowSize: new Dimension(settings.DEFAULT_WIDTH, settings.DEFAULT_HEIGHT),\n /**\n * Whether the activity window has transparent background.\n * @name module:Activity.Activity#transparentBg\n * @type {boolean} */\n transparentBg: false,\n /**\n * The background color of the activity\n * @name module:Activity.Activity#activityBgColor\n * @type {string} */\n activityBgColor: settings.DEFAULT_BG_COLOR,\n /**\n * Gradient used to draw backgrounds inside the activity.\n * @name module:Activity.Activity#activityBgGradient\n * @type {module:AWT.Gradient} */\n activityBgGradient: null,\n /**\n * Whether to display or not the 'time' counter\n * @name module:Activity.Activity#bTimeCounter\n * @type {boolean} */\n bTimeCounter: true,\n /**\n * Whether to display or not the 'score' counter\n * @name module:Activity.Activity#bScoreCounter\n * @type {boolean} */\n bScoreCounter: true,\n /**\n * Whether to display or not the 'actions' counter\n * @name module:Activity.Activity#bActionsCounter\n * @type {boolean} */\n bActionsCounter: true,\n /**\n * Special object used to generate random content at the start of the activity\n * @name module:Activity.Activity#acp\n * @type {module:automation/AutoContentProvider.AutoContentProvider} */\n acp: null,\n //\n // Fields used only in certain activity types\n // ------------------------------------------\n //\n /**\n * Array of bags with the description of the content to be displayed on panels and cells.\n * @name module:Activity.Activity#abc\n * @type {module:boxes/ActiveBagContent.ActiveBagContent[]} */\n abc: null,\n /**\n * Content of the grid of letters used in crosswords and shuffled letters\n * @name module:Activity.Activity#tgc\n * @type {module:boxes/TextGridContent.TextGridContent} */\n tgc: null,\n /**\n * The main document used in text activities\n * @name module:Activity.Activity#document\n * @type {module:activities/text/TextActivityDocument.TextActivityDocument} */\n document: null,\n /**\n * Relative position of the text grid (uses the same position codes as box grids)\n * @name module:Activity.Activity#boxGridPos\n * @type {string} */\n boxGridPos: 'AB',\n /**\n * Number of times to shuffle the cells at the beginning of the activity\n * @name module:Activity.Activity#shuffles\n * @type {number} */\n shuffles: settings.DEFAULT_SHUFFLES,\n /**\n * Box grid A must be shuffled.\n * @name module:Activity.Activity#shuffleA\n * @type {boolean} */\n shuffleA: true,\n /**\n * Box grid B must be shuffled.\n * @name module:Activity.Activity#shuffleB\n * @type {boolean} */\n shuffleB: true,\n /**\n * Flag to indicate \"inverse resolution\" in complex associations\n * @name module:Activity.Activity#invAss\n * @type {boolean} */\n invAss: false,\n /**\n * Array of menu elements, used in activities of type {@link module:activities/panels/Menu.Menu Menu}\n * @name module:Activity.Activity#menuElements\n * @type {object[]} */\n menuElements: null,\n /**\n * This activity uses numeric expressions, so text literals should be\n * converted to numbers for comparisions, taking in account the\n * number format of the current locale (dot or comma as decimal separator)\n * @name module:Activity.Activity#numericContent\n * @type {boolean} */\n numericContent: false,\n});\n\n/**\n * This object is responsible for rendering the contents of the activity on the screen and\n * managing user's interaction.\n * Each type of Activity must implement its own `ActivityPanel`.\n * In JClic, {@link http://projectestac.github.io/jclic/apidoc/edu/xtec/jclic/Activity.Panel.html Activity.Panel}\n * extends {@link http://docs.oracle.com/javase/7/docs/api/javax/swing/JPanel.html javax.swing.JPanel}.\n * On this implementation, the JPanel will be replaced by an HTML `div` tag.\n * @extends module:AWT.Container\n */\nexport class ActivityPanel extends Container {\n /**\n * ActivityPanel constructor\n * @param {module:Activity.Activity} act - The {@link module:Activity.Activity Activity} to which this Panel belongs\n * @param {module:JClicPlayer.JClicPlayer} ps - Any object implementing the methods defined in the\n * {@link http://projectestac.github.io/jclic/apidoc/edu/xtec/jclic/PlayStation.html PlayStation}\n * Java interface.\n * @param {external:jQuery} [$div] - The jQuery DOM element where this Panel will deploy\n */\n constructor(act, ps, $div) {\n // ActivityPanel extends Container\n super();\n this.act = act;\n this.ps = ps;\n this.minimumSize = new Dimension(100, 100);\n this.preferredSize = new Dimension(500, 400);\n if ($div)\n this.$div = $div;\n else\n this.$div = $('<div/>', { class: 'JClicActivity', 'aria-label': getMsg('Activity panel') });\n this.act.initAutoContentProvider();\n }\n\n /**\n * Sets the size and position of this activity panel\n * @param {module:AWT.Rectangle} rect\n */\n setBounds(rect) {\n this.pos.x = rect.pos.x;\n this.pos.y = rect.pos.y;\n this.dim.width = rect.dim.width;\n this.dim.height = rect.dim.height;\n\n this.invalidate(rect);\n this.$div.css({\n position: 'relative',\n left: rect.pos.x,\n top: rect.pos.y,\n width: rect.dim.width,\n height: rect.dim.height\n });\n }\n\n /**\n * Prepares the visual components of the activity\n */\n buildVisualComponents() {\n this.playing = false;\n this.skin = null;\n if (this.act.skinFileName && this.act.skinFileName.length > 0 && this.act.skinFileName !== this.act.project.settings.skinFileName)\n this.skin = this.act.project.mediaBag.getSkinElement(this.act.skinFileName, this.ps);\n\n this.bgImage = null;\n if (this.act.bgImageFile && this.act.bgImageFile.length > 0) {\n const mbe = this.act.project.mediaBag.getElement(this.act.bgImageFile, true);\n if (mbe)\n this.bgImage = mbe.data;\n }\n\n this.backgroundColor = this.act.activityBgColor;\n\n if (this.act.transparentBg)\n this.backgroundTransparent = true;\n\n // TODO: fix bevel-border type\n if (this.act.border)\n this.border = true;\n\n const cssAct = {\n display: 'block',\n 'background-color': this.backgroundTransparent ? 'transparent' : this.backgroundColor\n };\n\n // Border shadow style Material Design, inspired in [http://codepen.io/Stenvh/pen/EaeWqW]\n if (this.border) {\n cssAct['box-shadow'] = '0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12)';\n cssAct['border-radius'] = '2px';\n cssAct['color'] = '#272727';\n }\n\n if (this.act.activityBgGradient)\n cssAct['background-image'] = this.act.activityBgGradient.getCss();\n\n this.$div.css(cssAct);\n }\n\n /**\n * Activities should implement this method to update the graphic content of its panel. The method\n * will be called from {@link module:AWT.Container#update} when needed.\n * @param {module:AWT.Rectangle} dirtyRegion - Specifies the area to be updated. When `null`,\n * it's the whole panel.\n */\n updateContent(dirtyRegion) {\n // To be overridden by subclasses. Here does nothing.\n return super.updateContent(dirtyRegion);\n }\n\n /**\n * Plays the specified event sound\n * @param {string} event - The type of event to be performed\n */\n playEvent(event) {\n this.act.eventSounds.play(event);\n }\n\n /**\n * Basic initialization procedure, common to all activities.\n */\n initActivity() {\n if (this.playing) {\n this.playing = false;\n this.ps.reportEndActivity(this.act, this.solved);\n }\n this.solved = false;\n this.ps.reportNewActivity(this.act, 0);\n this.attachEvents();\n this.enableCounters();\n }\n\n /**\n * Called when the activity starts playing\n */\n startActivity() {\n this.playing = true;\n }\n\n /**\n * Called by {@link module:JClicPlayer.JClicPlayer JClicPlayer} when this activity panel is fully visible, just after the\n * initialization process.\n */\n activityReady() {\n // To be overrided by subclasses\n }\n\n /**\n * Displays help about the activity\n */\n showHelp() {\n // To be overrided by subclasses\n }\n\n /**\n * Sets the real dimension of this ActivityPanel.\n * @param {module:AWT.Dimension} maxSize - The maximum surface available for the activity panel\n * @returns {module:AWT.Dimension}\n */\n setDimension(maxSize) {\n return new Dimension(\n Math.min(maxSize.width, this.act.windowSize.width),\n Math.min(maxSize.height, this.act.windowSize.height));\n }\n\n /**\n * Attaches the events specified in the `events` member to the `$div` member\n */\n attachEvents() {\n this.events.forEach(ev => this.attachEvent(this.$div, ev));\n // Prepare handler to check if we are in a touch device\n if (!settings.TOUCH_DEVICE && $.inArray(TOUCH_TEST_EVENT, this.events) === -1)\n this.attachEvent(this.$div, TOUCH_TEST_EVENT);\n }\n\n /**\n * Attaches a single event to the specified object\n * @param {external:jQuery} $obj - The object to which the event will be attached\n * @param {string} evt - The event name\n */\n attachEvent($obj, evt) {\n $obj.on(evt, this, event => {\n if (event.type === TOUCH_TEST_EVENT) {\n if (!settings.TOUCH_DEVICE)\n settings.TOUCH_DEVICE = true;\n if ($.inArray(TOUCH_TEST_EVENT, this.events) === -1) {\n // Disconnect handler\n $obj.off(TOUCH_TEST_EVENT);\n return;\n }\n }\n return event.data.processEvent.call(event.data, event);\n });\n }\n\n /**\n * Main handler used to process mouse, touch, keyboard and edit events.\n * @param {external:Event} event - The HTML event to be processed\n * @returns {boolean} - When this event handler returns `false`, jQuery will stop its\n * propagation through the DOM tree. See: {@link http://api.jquery.com/on}\n */\n processEvent(_event) {\n return false;\n }\n\n /**\n * Fits the panel within the `proposed` rectangle. The panel can occupy more space, but always\n * not surpassing the `bounds` rectangle.\n * @param {module:AWT.Rectangle} proposed - The proposed rectangle\n * @param {module:AWT.Rectangle} bounds - The maximum allowed bounds\n */\n fitTo(proposed, bounds) {\n const origin = new Point();\n if (this.act.absolutePositioned && this.act.absolutePosition !== null) {\n origin.x = Math.max(0, this.act.absolutePosition.x + proposed.pos.x);\n origin.y = Math.max(0, this.act.absolutePosition.y + proposed.pos.y);\n proposed.dim.width -= this.act.absolutePosition.x;\n proposed.dim.height -= this.act.absolutePosition.y;\n }\n const d = this.setDimension(new Dimension(\n Math.max(2 * this.act.margin + settings.MINIMUM_WIDTH, proposed.dim.width),\n Math.max(2 * this.act.margin + settings.MINIMUM_HEIGHT, proposed.dim.height)));\n if (!this.act.absolutePositioned) {\n origin.moveTo(\n Math.max(0, proposed.pos.x + (proposed.dim.width - d.width) / 2),\n Math.max(0, proposed.pos.y + (proposed.dim.height - d.height) / 2));\n }\n if (origin.x + d.width > bounds.dim.width)\n origin.x = Math.max(0, bounds.dim.width - d.width);\n if (origin.y + d.height > bounds.dim.height)\n origin.y = Math.max(0, bounds.dim.height - d.height);\n this.setBounds(new Rectangle(origin.x, origin.y, d.width, d.height));\n\n // Build accessible components at the end of current tree\n window.setTimeout(() => this.buildAccessibleComponents(), 0);\n }\n\n /**\n *\n * Builds the accessible components needed for this ActivityPanel\n * This method is called when all main elements are placed and visible, when the activity is ready\n * to start or when resized.\n */\n buildAccessibleComponents() {\n // Clear existing elements\n if (this.accessibleCanvas && this.$canvas && this.$canvas.children().length > 0) {\n // UPDATED May 2020: clearHitRegions has been deprecated!\n // this.$canvas.get(-1).getContext('2d').clearHitRegions();\n this.$canvas.empty();\n }\n // Create accessible elements in subclasses\n }\n\n /**\n * Forces the ending of the activity.\n */\n forceFinishActivity() {\n // to be overrided by subclasses\n }\n\n /**\n * Ordinary ending of the activity, usually called form `processEvent`\n * @param {boolean} result - `true` if the activity was successfully completed, `false` otherwise\n */\n finishActivity(result) {\n this.playing = false;\n this.solved = result;\n\n if (this.bc !== null)\n this.bc.end();\n\n if (result) {\n this.setAndPlayMsg('final', 'finishedOk');\n } else {\n this.setAndPlayMsg('finalError', 'finishedError');\n }\n this.ps.activityFinished(this.solved);\n this.ps.reportEndActivity(this.act, this.solved);\n }\n\n /**\n * Sets the message to be displayed in the skin message box and optionally plays a sound event.\n * @param {string} msgCode - Type of message (initial, final, finalError...)\n * @param {string} [eventSoundsCode] - Optional name of the event sound to be played.\n */\n setAndPlayMsg(msgCode, eventSoundsCode) {\n const msg = this.act.messages[msgCode] || null;\n this.ps.setMsg(msg);\n if (msg === null || msg.mediaContent === null)\n this.playEvent(eventSoundsCode);\n }\n\n /**\n * Ends the activity\n */\n end() {\n this.forceFinishActivity();\n if (this.playing) {\n if (this.bc !== null)\n this.bc.end();\n this.ps.reportEndActivity(this.act, this.solved);\n this.playing = false;\n this.solved = false;\n }\n this.clear();\n }\n\n /**\n * Miscellaneous cleaning operations\n */\n clear() {\n // to be overridden by subclasses\n }\n\n /**\n * Enables or disables the three counters (time, score and actions)\n * @param {boolean} eTime - Whether to enable or disable the time counter\n * @param {boolean} eScore - Whether to enable or disable the score counter\n * @param {boolean} eActions - Whether to enable or disable the actions counter\n */\n enableCounters(eTime, eScore, eActions) {\n if (typeof eTime === 'undefined')\n eTime = this.act.bTimeCounter;\n if (typeof eScore === 'undefined')\n eScore = this.act.bScoreCounter;\n if (typeof eActions === 'undefined')\n eActions = this.act.bActionsCounter;\n\n this.ps.setCounterEnabled('time', eTime);\n if (this.act.countDownTime)\n this.ps.setCountDown('time', this.act.maxTime);\n this.ps.setCounterEnabled('score', eScore);\n this.ps.setCounterEnabled('actions', eActions);\n if (this.act.countDownActions)\n this.ps.setCountDown('actions', this.act.maxActions);\n }\n\n /**\n * Shuffles the contents of the activity\n * @param {module:boxes/ActiveBoxBag.ActiveBoxBag[]} bg - The sets of boxes to be shuffled\n * @param {boolean} visible - The shuffle process must be animated on the screen (not yet implemented!)\n * @param {boolean} fitInArea - Shuffled pieces cannot go out of the current area\n */\n shuffle(bg, visible, fitInArea) {\n const steps = this.act.shuffles;\n let i = steps;\n while (i > 0) {\n const k = i > steps ? steps : i;\n bg.forEach(abb => { if (abb) abb.shuffleCells(k, fitInArea); });\n i -= steps;\n }\n }\n}\n\nObject.assign(ActivityPanel.prototype, {\n /**\n * The Activity this panel is related to\n * @name module:Activity.ActivityPanel#act\n * @type {module:Activity.Activity} */\n act: null,\n /**\n * The jQuery div element used by this panel\n * @name module:Activity.ActivityPanel#$div\n * @type {external:jQuery} */\n $div: null,\n /**\n * The jQuery main canvas element used by this panel\n * @name module:Activity.ActivityPanel#$canvas\n * @type {external:jQuery} */\n $canvas: null,\n /**\n * Always true, since canvas hit regions have been deprecated!\n * See: https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Hit_regions_and_accessibility\n * @name module:Activity.ActivityPanel#accessibleCanvas\n * @type {boolean}\n */\n accessibleCanvas: true,\n /**\n * The realized current {@link module:skins/Skin.Skin Skin}\n * @name module:Activity.ActivityPanel#skin\n * @type {module:skins/Skin.Skin} */\n skin: null,\n /**\n * Background element (currently a `span`) used to place animated GIFs when needed\n * @name module:Activity.ActivityPanel#$animatedBg\n * @type {external:jQuery} */\n $animatedBg: null,\n /**\n * Additional background element for animated GIFs, used in associations\n * @name module:Activity.ActivityPanel#$animatedBgB\n * @type {external:jQuery} */\n $animatedBgB: null,\n /**\n * `true` when the activity is solved, `false` otherwise\n * @name module:Activity.ActivityPanel#solved\n * @type {boolean} */\n solved: false,\n /**\n * The realized image used as a background\n * @name module:Activity.ActivityPanel#bgImage\n * @type {external:HTMLImageElement} */\n bgImage: null,\n /**\n * `true` while the activity is playing\n * @name module:Activity.ActivityPanel#playing\n * @type {boolean} */\n playing: false,\n /**\n * `true` if the activity is running for first time (not due to a click on the `replay` button)\n * @name module:Activity.ActivityPanel#firstRun\n * @type {boolean} */\n firstRun: true,\n /**\n * Currently selected item. Used in some types of activities.\n * @name module:Activity.ActivityPanel#currentItem\n * @type {number} */\n currentItem: 0,\n /**\n * The object used to connect cells and other elements in some types of activity\n * @name module:Activity.ActivityPanel#bc\n * @type {module:boxes/BoxConnector.BoxConnector} */\n bc: null,\n /**\n * The PlayStation used to realize media objects and communicate with the player services\n * (usually a {@link module:JClicPlayer.JClicPlayer JClicPlayer}\n * @name module:Activity.ActivityPanel#ps\n * @type {module:JClicPlayer.JClicPlayer} */\n ps: null,\n /**\n * The minimum size of this kind of ActivityPanel\n * @name module:Activity.ActivityPanel#minimumSize\n * @type {module:AWT.Dimension} */\n minimumSize: null,\n /**\n * The preferred size of this kind of ActivityPanel\n * @name module:Activity.ActivityPanel#preferredSize\n * @type {module:AWT.Dimension} */\n preferredSize: null,\n /**\n * List of events intercepted by this ActivityPanel. Current events are: 'keydown', 'keyup',\n * 'keypress', 'mousedown', 'mouseup', 'click', 'dblclick', 'mousemove', 'mouseenter',\n * 'mouseleave', 'mouseover', 'mouseout', 'touchstart', 'touchend', 'touchmove' and 'touchcancel'.\n * @name module:Activity.ActivityPanel#events\n * @type {string[]} */\n events: ['click'],\n backgroundColor: null,\n backgroundTransparent: false,\n border: null,\n});\n\n/**\n * The panel class associated to each type of activity\n * @type {module:Activity.ActivityPanel} */\nActivity.Panel = ActivityPanel;\n\nexport default Activity;\n","/**\n * File : PlayerHistory.js\n * Created : 28/04/2015\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\n/* global window */\n\nimport $ from 'jquery';\nimport { log, isEquivalent, getPath, isNullOrUndef } from './Utils.js';\n\n/**\n *\n * PlayerHistory uses an array to store the list of projects and activities done by the user.\n * This class allows {@link module:JClicPlayer.JClicPlayer JClicPlayer} objects to rewind a sequence or to go back to a caller menu.\n */\nexport class PlayerHistory {\n /**\n * PlayerHistory constructor\n * @param {module:JClicPlayer.JClicPlayer} player - The JClicPlayer associated to this history\n */\n constructor(player) {\n this.player = player;\n this.sequenceStack = [];\n if (window && window.history && player.options.browserHistory) {\n this.browserHistory = true;\n $(window).on('popstate', (ev) => {\n const state = ev.originalEvent.state;\n if (state)\n this.processPopStateEvent(state);\n });\n }\n }\n\n /**\n *\n * Process the `state` object received in a `popstate` event\n * @param {PlayerHistory#HistoryElement} state - The previously stored state\n */\n processPopStateEvent(state) {\n log('info', 'Processing History popstate event with state:', state);\n this.processingPop = true;\n if (state.projectPath === this.player.project.path &&\n isEquivalent(state.fullZipPath, this.player.zip ? this.player.zip.fullZipPath : null))\n this.player.load(null, state.activity, null);\n else\n this.player.load(state.fullZipPath || state.projectPath, state.activity, null);\n }\n\n /**\n * Push a new entry on the window.History stack,\n * only when `browserHistory` is true and there is no `popstate` event in progress\n */\n pushBrowserHistory() {\n if (this.browserHistory) {\n\n if (this.processingPop) {\n // A 'popstate' event is currently being processed, so just clear this flag and return\n this.processingPop = false;\n return;\n }\n\n const\n ase = this.player.project.activitySequence,\n act = ase.currentAct,\n title = this.player.actPanel.act.name || 'No name',\n state = new this.HistoryElement(\n this.player.project.path,\n ase.getSequenceForElement(act),\n act,\n this.player.zip ? this.player.zip.fullZipPath : null);\n\n // Push a new history entry, or update the current one if it has no `state`\n if (!window.history.state)\n window.history.replaceState(state, title);\n else\n window.history.pushState(state, title);\n }\n }\n\n /**\n *\n * Counts the number of {@link module:PlayerHistory.PlayerHistory#HistoryElement HistoryElement} objects stored in\n * {@link module:PlayerHistory.PlayerHistory#sequenceStack sequenceStack}\n * @returns {number}\n */\n storedElementsCount() {\n return this.sequenceStack.length;\n }\n\n /**\n *\n * Removes all elements from {@link module:PlayerHistory.PlayerHistory#sequenceStack sequenceStack}\n */\n clearHistory() {\n this.sequenceStack = [0];\n }\n\n /**\n * Adds the current project and activity to the top of the history stack.\n */\n push() {\n if (this.player.project !== null && this.player.project.path !== null) {\n const\n ase = this.player.project.activitySequence,\n act = ase.currentAct;\n if (act >= 0) {\n if (this.sequenceStack.length > 0) {\n const last = this.sequenceStack[this.sequenceStack.length - 1];\n if (last.projectPath === this.player.project.path && last.activity === act)\n return;\n }\n this.sequenceStack.push(\n new this.HistoryElement(\n this.player.project.path,\n ase.getSequenceForElement(act),\n act,\n this.player.zip ? this.player.zip.fullZipPath : null));\n }\n }\n }\n\n /**\n * Retrieves the {@link module:PlayerHistory.PlayerHistory#HistoryElement HistoryElement} placed at the top of the\n * stack (if any) and instructs {@link module:JClicPlayer.JClicPlayer JClicPlayer} to load it. The obtained effect is to\n * \"rewind\" or \"go back\", usually to an activity that acts as a menu.\n * @returns {boolean}\n */\n pop() {\n // todo: check return value\n if (this.sequenceStack.length > 0) {\n const e = this.sequenceStack.pop();\n if (e.projectPath === this.player.project.path &&\n isEquivalent(e.fullZipPath, this.player.zip ? this.player.zip.fullZipPath : null))\n this.player.load(null, e.activity, null);\n else\n if (this.testMode && e.projectPath !== null && e.projectPath.length > 0)\n log('info', `At this point, a jump to \"${e.projectPath}\" should be performed.`);\n else\n this.player.load(e.fullZipPath || e.projectPath, e.activity, null);\n }\n return true;\n }\n\n /**\n *\n * Processes the provided {@link module:bags/JumpInfo.JumpInfo JumpInfo} object, instructing {@link module:JClicPlayer.JClicPlayer JClicPlayer} to go back,\n * stop or jump to another point in the sequence.\n * @param {module:bags/JumpInfo.JumpInfo} ji - The object to be processed\n * @param {boolean} allowReturn - When this parameter is `true`, the jump instructed by `ji` (if any)\n * will be recorded, thus allowing to return to the current activity.\n * @returns {boolean} - `true` if the jump can be processed without errors, `false` otherwise.\n */\n processJump(ji, allowReturn) {\n let result = false;\n if (ji !== null && this.player.project !== null) {\n switch (ji.action) {\n case 'STOP':\n break;\n case 'RETURN':\n if (this.sequenceStack.length > 0 || !this.player.options.returnAsExit) {\n result = this.pop();\n break;\n }\n case 'EXIT':\n if (this.testMode)\n log('info', 'At this point, the program should exit.');\n else\n this.player.exit(ji.sequence);\n break;\n case 'JUMP':\n if (!ji.sequence && !ji.projectPath) {\n const ase = this.player.project.activitySequence.getElement(ji.actNum, true);\n if (ase !== null) {\n if (allowReturn)\n this.push();\n this.player.load(null, null, ase.activity);\n result = true;\n }\n } else {\n if (this.testMode && ji.projectPath !== null && ji.projectPath.length > 0) {\n log('info', `At this point, a jump to \"${ji.projectPath}\" should be performed.`);\n } else {\n result = this.jumpToSequence(ji.sequence,\n ji.projectPath ? getPath(this.player.project.basePath, ji.projectPath) : null,\n allowReturn);\n }\n }\n break;\n }\n }\n return result;\n }\n\n /**\n * Performs a jump to the specified sequence\n * @param {string} sequence - The {@link module:bags/ActivitySequence.ActivitySequence ActivitySequence} tag to jump to.\n * @param {string} [path] - When not `null`, indicates a new project file that must be loaded.\n * Otherwise, the `sequence` parameter refers to a tag on the {@link module:bags/ActivitySequence.ActivitySequence ActivitySequence} of the\n * current project.\n * @param {boolean} [allowReturn] - When this parameter is `true`, the jump will be recorded, thus\n * allowing to return to the current activity.\n */\n jumpToSequence(sequence, path = null, allowReturn = false) {\n if (isNullOrUndef(sequence) && isNullOrUndef(path))\n return false;\n if (isNullOrUndef(path))\n path = this.player.project.path;\n if (this.sequenceStack.length > 0) {\n const e = this.sequenceStack[this.sequenceStack.length - 1];\n if (!isNullOrUndef(sequence) && path === e.projectPath) {\n let same = sequence === e.sequence;\n if (path === this.player.project.path) {\n const ase = this.player.project.activitySequence.getElement(e.activity, false);\n same = ase !== null && sequence === ase.tag;\n }\n if (same)\n return this.pop();\n }\n }\n if (allowReturn)\n this.push();\n if (path === this.player.project.path)\n this.player.load(null, sequence, null);\n else\n this.player.load(path, sequence, null);\n return true;\n }\n}\n\nObject.assign(PlayerHistory.prototype, {\n /**\n * The {@link module:JClicPlayer.JClicPlayer JClicPlayer} object to which this `PlayerHistory` belongs\n * @name module:PlayerHistory.PlayerHistory#player\n * @type {module:JClicPlayer.JClicPlayer} */\n player: null,\n /**\n * This is the main member of the class. PlayerHistory puts and retrieves\n * on it information about the proects and activities done by the current user.\n * @name module:PlayerHistory.PlayerHistory#sequenceStack\n * @type {module:PlayerHistory.PlayerHistory#HistoryElement[]} */\n sequenceStack: [],\n /**\n * When in test mode, jumps are only simulated.\n * @name module:PlayerHistory.PlayerHistory#testMode\n * @type {boolean} */\n testMode: false,\n /**\n * When true, JClic history is in sync with browser history\n * @name PlayerHistory#browserHistory\n * @type {boolean} */\n browserHistory: false,\n /**\n * When true, a window.history event is currently being processed, so window.pushState should not be performed\n * @name PlayerHistory#processingPop\n * @type {boolean} */\n processingPop: false,\n /**\n * Inner class used to store history elements.\n * @name module:PlayerHistory.PlayerHistory#HistoryElement\n */\n HistoryElement: class {\n /**\n * HistoryElement constructor\n * @param {string} projectPath - The full path of the project file\n * @param {string} sequence - The nearest sequence tag\n * @param {number} activity - The index of the current activity on the project's {@link module:bags/ActivitySequence.ActivitySequence ActivitySequence}\n * @param {string} fullZipPath - If `projectPath` resides in a {@link external:JSZip JSZip} object,\n * the full path of the zip file.\n */\n constructor(projectPath, sequence, activity, fullZipPath) {\n this.projectPath = projectPath;\n this.sequence = sequence;\n this.activity = activity;\n this.fullZipPath = fullZipPath;\n }\n }\n});\n\nexport default PlayerHistory;\n","/**\n * File : media/ActiveMediaBag.js\n * Created : 28/04/2015\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\nimport ActiveMediaPlayer from './ActiveMediaPlayer.js';\nimport { settings } from '../Utils.js';\n\n/**\n * This class stores a collection of realized {@link module:media/ActiveMediaPlayer.ActiveMediaPlayer ActiveMediaPlayer} objects, related to a\n * {@link module:project/JClicProject.JClicProject JClicProject} or {@link module:Activity.Activity Activity}.\n */\nexport class ActiveMediaBag {\n /**\n * ActiveMediaBag constructor\n */\n constructor() {\n this.players = [];\n }\n\n /**\n * Creates a new {@link module:media/ActiveMediaPlayer.ActiveMediaPlayer ActiveMediaPlayer} linked to this media bag\n * @param {module:media/MediaContent.MediaContent} mc - The content used by the new player\n * @param {module:bags/MediaBag.MediaBag} mb - The project's MediaBag\n * @param {module:JClicPlayer.JClicPlayer} ps - An object implementing the\n * [PlayStation](http://projectestac.github.io/jclic/apidoc/edu/xtec/jclic/PlayStation.html) interface,\n * usually a {@link module:JClicPlayer.JClicPlayer JClicPlayer}.\n * @returns {module:media/ActiveMediaPlayer.ActiveMediaPlayer}\n */\n createActiveMediaPlayer(mc, mb, ps) {\n let amp = null;\n switch (mc.type) {\n case 'RECORD_AUDIO':\n if (mc.length <= 0 || mc.length >= settings.MAX_RECORD_LENGTH)\n break;\n /* falls through */\n case 'PLAY_RECORDED_AUDIO':\n if (mc.recBuffer < 0 || mc.recBuffer >= 10)\n break;\n /* falls through */\n case 'PLAY_AUDIO':\n case 'PLAY_MIDI':\n case 'PLAY_VIDEO':\n amp = new ActiveMediaPlayer(mc, mb, ps);\n break;\n }\n if (amp !== null)\n this.players.push(amp);\n return amp;\n }\n\n /**\n * Looks for an already existing {@link module:media/ActiveMediaPlayer.ActiveMediaPlayer ActiveMediaPlayer} equivalent to the requested.\n * When not found, a new one is created and and returned.\n * @param {module:media/MediaContent.MediaContent} mc - The content used by the new player\n * @param {module:bags/MediaBag.MediaBag} mb - The project's MediaBag\n * @param {module:JClicPlayer.JClicPlayer} ps - An object implementing the\n * {@link http://projectestac.github.io/jclic/apidoc/edu/xtec/jclic/PlayStation.html|PlayStation} interface,\n * usually a {@link module:JClicPlayer.JClicPlayer JClicPlayer}.\n * @returns {module:media/ActiveMediaPlayer.ActiveMediaPlayer}\n */\n getActiveMediaPlayer(mc, mb, ps) {\n return this.players.find(p => p.mc === mc || p.mc.isEquivalent(mc))\n || this.createActiveMediaPlayer(mc, mb, ps);\n }\n\n /**\n * Removes from the list of players the {@link module:media/ActiveMediaPlayer.ActiveMediaPlayer ActiveMediaPlayer} related to the specified {@link module:media/MediaContent.MediaContent}.\n * @param {module:media/MediaContent.MediaContent} mc - The media content to look for.\n */\n removeActiveMediaPlayer(mc) {\n const i = this.players.findIndex(p => p.mc === mc);\n if (i >= 0) {\n this.players[i].clear();\n // removes the element pointed by 'i'\n this.players.splice(i, 1);\n }\n }\n\n /**\n * Realizes all the media elements stored in this bag\n */\n realizeAll() {\n this.players.forEach(p => p.realize());\n }\n\n /**\n * Stops playing all media elements stored in this bag\n * @param {number} level - Level at and below what all media players will be muted.\n */\n stopAll(level) {\n if (typeof level === 'undefined')\n level = -1;\n this.players.forEach(amp => {\n if (level === -1 || amp.mc !== null && amp.mc.level <= level)\n amp.stop();\n });\n }\n\n /**\n * Removes all players from this media bag\n */\n removeAll() {\n this.players.forEach(p => p.clear());\n // Empty the `players` array\n this.players.length = 0;\n ActiveMediaPlayer.prototype.clearAllAudioBuffers();\n }\n}\n\nObject.assign(ActiveMediaBag.prototype, {\n /**\n * The collection of {@link module:media/ActiveMediaPlayer.ActiveMediaPlayer ActiveMediaPlayer} objects stored in this media bag.\n * @name module:media/ActiveMediaBag.ActiveMediaBag#players\n * @type {module:media/ActiveMediaPlayer.ActiveMediaPlayer[]} */\n players: [],\n});\n\nexport default ActiveMediaBag;\n","/**\n * File : skins/Skin.js\n * Created : 29/04/2015\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\n/* global Promise, window, document, navigator, ClipboardItem, Blob */\n\nimport $ from 'jquery';\nimport { appendStyleAtHead, cloneObject, getMsg, setLogLevel, log, getRootHead, toCssSize, $HTML, getPercent, getHMStime, settings } from '../Utils.js';\nimport { Container, Dimension, Rectangle } from '../AWT.js';\n\n// Use Webpack to import CSS and SVG files\nimport basicCSS from './assets/basic.css';\nimport waitAnimCSS from './assets/waitAnim.css';\nimport reportsCSS from './assets/reports.css';\nimport waitImgSmall from './assets/waitImgSmall.svg';\nimport waitImgBig from './assets/waitImgBig.svg';\nimport appLogo from './assets/appLogo.svg';\nimport closeDialogIcon from './assets/closeDialogIcon.svg';\nimport okDialogIcon from './assets/okDialogIcon.svg';\nimport copyIcon from './assets/copyIcon.svg';\n\n/**\n * This abstract class manages the layout, position ans size of the visual components of JClic:\n * player window, message box, counters, buttons, status... and also the appearance of the main\n * container.\n * The basic implementation of Skin is {@link module:skins/DefaultSkin.DefaultSkin DefaultSkin}.\n * @abstract\n * @extends module:AWT.Container\n */\nexport class Skin extends Container {\n /**\n * Skin constructor\n * @param {module:JClicPlayer.JClicPlayer} ps - The `PlayStation` (currently a {@link module:JClicPlayer.JClicPlayer JClicPlayer}) used to load and\n * realize the media objects needed tot build the Skin.\n * @param {string} [name] - The skin name\n * @param {object} [options] - Optional parameter with additional options\n */\n constructor(ps, name = null, options = {}) {\n\n // Skin extends [AWT.Container](AWT.html)\n super();\n\n // Save parameters for later use\n this.ps = ps;\n if (name !== null)\n this.name = name;\n this.options = options;\n\n if (this.options.skinId)\n this.skinId = this.options.skinId;\n\n if (!Skin.registerStyleSheet(this.skinId, ps)) {\n let css = this._getStyleSheets('default');\n let twoThirds = this._getStyleSheets('twoThirds');\n if (twoThirds.length > 0)\n css += ` @media (max-width:${this.twoThirdsMedia.width}px),(max-height:${this.twoThirdsMedia.height}px){${twoThirds}}`;\n let half = this._getStyleSheets('half');\n if (half.length > 0)\n css += ` @media (max-width:${this.halfMedia.width}px),(max-height:${this.halfMedia.height}px){${half}}`;\n appendStyleAtHead(css.replace(/\\.ID/g, `.${this.skinId}`), ps);\n }\n\n let msg = '';\n\n this.$div = $('<div/>', { class: this.skinId });\n this.$playerCnt = $('<div/>', { class: 'JClicPlayerCnt' });\n\n // Add waiting panel and progress bar\n this.$progress = $('<progress/>', { class: 'progressBar' })\n .css({ display: 'none' });\n this.$waitPanel = $('<div/>')\n .css({ display: 'none', 'background-color': 'rgba(255, 255, 255, .60)', 'z-index': 99 })\n .append($('<div/>', { class: 'waitPanel' }).css({ display: 'flex', 'flex-direction': 'column' })\n .append($('<div/>', { class: 'animImgBox' })\n .append($(this.waitImgBig), $(this.waitImgSmall)))\n .append(this.$progress));\n this.$playerCnt.append(this.$waitPanel);\n\n this.buttons = cloneObject(Skin.prototype.buttons);\n this.counters = cloneObject(Skin.prototype.counters);\n this.msgArea = cloneObject(Skin.prototype.msgArea);\n\n // Create dialog overlay and panel\n this.$dlgOverlay = $('<div/>', { class: 'dlgOverlay' }).css({\n 'z-index': 98,\n position: 'fixed',\n left: 0,\n top: 0,\n width: '100%',\n height: '100%',\n display: 'none',\n 'background-color': 'rgba(30,30,30,0.7)'\n }).on('click', () => {\n if (!this._isModalDlg)\n // Non-modal dialogs are closed on click outside the main area\n this._closeDlg(true);\n return false;\n });\n\n const $dlgDiv = $('<div/>', {\n class: 'dlgDiv',\n role: 'dialog',\n 'aria-labelledby': ps.getUniqueId('ReportsLb'),\n 'aria-describedby': ps.getUniqueId('ReportsCnt')\n }).css({\n display: 'inline-block',\n position: 'relative',\n top: '50%',\n left: '50%',\n transform: 'translate(-50%, -50%)'\n }).on('click', () => {\n // Clicks not passed to parent\n return false;\n });\n\n this.$dlgMainPanel = $('<div/>', { class: 'dlgMainPanel', id: ps.getUniqueId('ReportsCnt') });\n this.$dlgBottomPanel = $('<div/>', { class: 'dlgBottomPanel', role: 'navigation' });\n\n // Basic dialog structure:\n this.$div.append(\n this.$playerCnt,\n this.$dlgOverlay.append(\n $dlgDiv.append(\n this.$dlgMainPanel,\n this.$dlgBottomPanel)));\n\n msg = getMsg('JClic logo');\n this.$infoHead = $('<div/>', { class: 'infoHead' })\n .append($('<div/>', { class: 'headTitle unselectableText' })\n .append($(this.appLogo, { 'aria-label': msg }).css({ width: '1.5em', height: '1.5em', 'vertical-align': 'bottom' })\n .on('dblclick', () => {\n // Double click on JClic logo is a hidden method to increase verbosity on Javascript console\n setLogLevel('all');\n log('trace', 'Log level set to \"trace\"');\n }))\n .append($('<span/>').html('JClic.js')))\n .append($('<p/>').css({ 'margin-top': 0, 'margin-left': '3.5em' })\n .append($('<a/>', { href: 'https://projectes.xtec.cat/clic/' }).html('https://projectes.xtec.cat/clic/'))\n .append($('<br>'))\n .append($('<span/>').html(`${getMsg('Version')} ${settings.VERSION}`)));\n\n this.$reportsPanel = $('<div/>', { class: 'reportsPanel', role: 'document' });\n\n msg = getMsg('Copy data to clipboard');\n this.$copyBtn = $('<button/>', { title: msg, 'aria-label': msg })\n .append($(this.copyIcon).css({ width: '26px', height: '26px' }))\n .on('click', () => {\n const item = new ClipboardItem({\n 'text/plain': new Blob([`===> ${getMsg('The data has been copied in HTML format. Please paste them into a spreadsheet or in a rich text editor')} <===`], {type: 'text/plain'}),\n 'text/html': new Blob([this.$reportsPanel.html()], {type: 'text/html'}),\n });\n navigator.clipboard.write([item])\n .then(() => this.$copyBtn.parent().append(\n $('<div/>', { class: 'smallPopup' })\n .html(getMsg('The data has been copied to clipboard'))\n .fadeIn()\n .delay(3000)\n .fadeOut(function () { $(this).remove(); })))\n .catch(err => this.$copyBtn.parent().append(\n $('<div/>', { class: 'smallPopup' })\n .html(`ERROR: Unable to write data into the clipboard: ${err}`)\n .fadeIn()\n .delay(3000)\n .fadeOut(function () { $(this).remove(); })));\n });\n\n msg = getMsg('Close');\n this.$closeDlgBtn = $('<button/>', { title: msg, 'aria-label': msg })\n .append($(this.closeDialogIcon).css({ width: '26px', height: '26px' }))\n .on('click', () => this._closeDlg(true));\n\n msg = getMsg('OK');\n this.$okDlgBtn = $('<button/>', { title: msg, 'aria-label': msg })\n .append($(this.okDialogIcon).css({ width: '26px', height: '26px' }))\n .on('click', () => this._closeDlg(true));\n\n msg = getMsg('Cancel');\n this.$cancelDlgBtn = $('<button/>', { title: msg, 'aria-label': msg })\n .append($(this.closeDialogIcon).css({ width: '26px', height: '26px' }))\n .on('click', () => this._closeDlg(false));\n\n // Registers this Skin in the list of realized Skin objects\n Skin.skinStack.push(this);\n }\n\n /**\n * Registers a new type of skin\n * @param {string} skinName - The name used to identify this skin\n * @param {function} skinClass - The skin class, usually extending Skin\n * @returns {module:skins/Skin.Skin} - The provided skin class\n */\n static registerClass(skinName, skinClass) {\n Skin.CLASSES[skinName] = skinClass;\n return skinClass;\n }\n\n /**\n * Checks if the provided stylesheet ID is already registered in the root node where the current player is placed\n * @param {string} skinId - The unique identifier of the skin to check\n * @param {module:JClicPlayer.JClicPlayer} [ps] - An optional `PlayStation` (currently a {@link module:JClicPlayer.JClicPlayer JClicPlayer}) used as a base to find the root node\n * @returns {boolean} - _true_ when the skin stylesheet is already defined in the current root node, _false_ otherwise\n */\n static registerStyleSheet(skinId, ps) {\n let result = false;\n const root = getRootHead(ps);\n if (!root['__JClicID'])\n root.__JClicID = `SK${Skin.lastId++}`;\n\n let styles = Skin.rootStyles[root.__JClicID];\n if (!styles) {\n styles = [];\n Skin.rootStyles[root.__JClicID] = styles;\n }\n\n if (styles.indexOf(skinId) < 0) {\n log('trace', `Stylesheet \"${skinId}\" has been registered for root node labeled as \"${root.__JClicID}\"`);\n styles.push(skinId);\n } else\n result = true;\n\n return result;\n }\n\n /**\n * Gets the specified Skin from `skinStack`, or creates a new one if not found.\n * This function should be used only through `Skin.getSkin`\n * @param {string} skinName - The name of the searched skin\n * @param {module:JClicPlayer.JClicPlayer} ps - The PlayStation (usually a {@link module:JClicPlayer.JClicPlayer JClicPlayer}) used to build the new skin.\n * @param {object} [options] - Optional parameter with additional options\n * @returns {module:skins/Skin.Skin}\n */\n static getSkin(skinName = 'default', ps, options = {}) {\n skinName = skinName || 'default';\n\n // Correct old skin names\n if (skinName.charAt(0, 1) === '@' && skinName.endsWith('.xml'))\n skinName = skinName.substring(1, skinName.length - 4);\n\n // look for the skin in the stack of realized skins\n if (skinName && ps) {\n // TODO: Check also `options`!\n const sk = Skin.skinStack.find(s => s.name === skinName && s.ps === ps);\n if (sk)\n return sk;\n }\n\n // Locates the class of the requested Skin (or [DefaultSkin](DefaultSkin.html)\n // if not specified). When not found, a new one is created and registered in `skinStack`\n let cl = Skin.CLASSES[skinName];\n if (!cl) {\n // Process custom skin XML files\n const mbe = ps.project.mediaBag.getElement(skinName, false);\n if (mbe && mbe.data) {\n options = Object.assign({}, options, mbe.data);\n options.skinId = `JClic-${skinName.replace('.xml', '')}`;\n }\n\n if (!ps.zip\n && options.class === 'edu.xtec.jclic.skins.BasicSkin'\n && options.image\n && ps.project.mediaBag.getElement(options.image, false)\n && ps.project.mediaBag.getElement(options.image, false).data)\n cl = Skin.CLASSES.custom;\n else {\n log('warn', `Unknown skin class: ${skinName}`);\n cl = Skin.CLASSES.default;\n }\n }\n\n // Build and return the requested skin\n return new cl(ps, skinName, options);\n }\n\n /**\n * Returns the CSS styles used by this skin. This method should be called only from\n * the `Skin` constructor, and overridded by subclasses if needed.\n * @param {string} media - A specific media size. Possible values are: 'default', 'half' and 'twoThirds'\n * @returns {string}\n */\n _getStyleSheets(media = 'default') {\n return media === 'default' ? (this.basicCSS + this.waitAnimCSS + this.reportsCSS) : '';\n }\n\n /**\n * Attaches a {@link module:JClicPlayer.JClicPlayer JClicPlayer} object to this Skin\n * @param {module:JClicPlayer.JClicPlayer} player\n */\n attach(player) {\n this.detach();\n if (player !== null && player.skin !== null)\n player.skin.detach();\n this.player = player;\n this.$playerCnt.prepend(player.$div);\n this.setSkinSizes();\n player.$mainContainer.append(this.$div);\n }\n\n /**\n * Sets the 'size' CSS values (max, min and compulsory) to the main `div` of this skin\n * @param {boolean} full - `true` when the skin is in full screen mode\n */\n setSkinSizes(full) {\n const\n css = {},\n topHeight = this.player?.$topDiv.height() || 0,\n nilValue = this.player.fullScreenChecked ? 'inherit' : null;\n\n // When `full` no set, detect the current status\n if (typeof full === 'undefined')\n full = document && document.fullscreenElement ? true : false;\n\n toCssSize(full ? '100vw' : this.ps.options.minWidth, css, 'min-width', nilValue);\n toCssSize(full ? '100vh' : this.ps.options.minHeight, css, 'min-height', nilValue);\n toCssSize(full ? '100vw' : this.ps.options.maxWidth, css, 'max-width', nilValue);\n toCssSize(full ? '100vh' : this.ps.options.maxHeight, css, 'max-height', nilValue);\n toCssSize(full ? '100vw' : this.ps.options.width, css, 'width', '100%');\n toCssSize(full ? '100vh' : this.ps.options.height, css, 'height', topHeight > 0 ? '100%' : '100vh');\n this.$div.css(css);\n }\n\n /**\n * Detaches the `player` element from this Skin\n */\n detach() {\n if (this.player !== null) {\n this.player.$div.remove();\n this.$div.detach();\n this.player = null;\n }\n }\n\n /**\n * Updates the graphic contents of this skin.\n * This method should be called from {@link module:skins/Skin.Skin#update}\n * @override\n * @param {module:AWT.Rectangle} dirtyRegion - Specifies the area to be updated. When `null`, it's the\n * whole panel.\n */\n updateContent(dirtyRegion) {\n if (this.$msgBoxDivCanvas) {\n const ctx = this.$msgBoxDivCanvas.get(-1).getContext('2d');\n ctx.clearRect(0, 0, ctx.canvas.clientWidth, ctx.canvas.clientHeight);\n this.msgBox.update(ctx, dirtyRegion);\n }\n return super.updateContent();\n }\n\n /**\n * Resets all counters\n * @param {boolean} bEnabled - Leave it enabled/disabled\n */\n resetAllCounters(bEnabled) {\n $.each(this.counters, (_name, counter) => {\n if (counter !== null) {\n counter.value = 0;\n counter.countDown = 0;\n counter.enabled = bEnabled;\n counter.refreshDisplay();\n }\n });\n }\n\n /**\n * Sets/unsets the 'wait' state\n * @param {boolean} status - Whether to set or unset the wait status. When `undefined`, the\n * `waitCursorCount` member is evaluated to decide if the wait state should be activated or deactivated.\n */\n setWaitCursor(status) {\n if (typeof status === 'undefined') {\n if (this.$waitPanel)\n this.$waitPanel.css({\n display: this.waitCursorCount > 0 ? 'initial' : 'none'\n });\n } else {\n switch (status) {\n case true:\n this.waitCursorCount++;\n break;\n case false:\n if (--this.waitCursorCount < 0)\n this.waitCursorCount = 0;\n break;\n case 'reset':\n this.waitCursorCount = 0;\n break;\n }\n this.setWaitCursor();\n }\n }\n\n /**\n * Sets the current value of the progress bar\n * @param {number} val - The current value. Should be less or equal than `max`. When -1, the progress bar will be hidden.\n * @param {number} [max] - Optional parameter representing the maximum value. When passed, the progress bar will be displayed.\n */\n setProgress(val, max) {\n if (this.$progress) {\n this.currentProgress = val;\n if (val < 0)\n this.$progress.css({ display: 'none' });\n else {\n if (max) {\n this.maxProgress = max;\n this.$progress.attr('max', max).css({ display: 'initial' });\n }\n this.$progress.attr('value', val);\n }\n log('trace', `Progress: ${this.currentProgress}/${this.maxProgress}`);\n }\n }\n\n /**\n * Increments the progress bar value by the specified amount, only when the progress bar is running.\n * @param {number} [val] - The amount to increment. When not defined, it's 1.\n */\n incProgress(val) {\n if (this.currentProgress >= 0)\n this.setProgress(this.currentProgress + (val || 1));\n }\n\n /**\n * Shows a window with clues or help for the current activity\n * @param {external:jQuery} _$hlpComponent - A JQuery DOM element with the information to be shown.\n * It can be a string or number. When `null`, the help window (if any) must be closed.\n */\n showHelp(_$hlpComponent) {\n // TODO: Implement HelpWindow\n }\n\n /**\n * Shows a \"dialog\" panel, useful for displaying information or prompt something to users\n * @param {boolean} modal - When `true`, the dialog should be closed by any click outside the main panel\n * @param {object} options - This object should have two components: `main` and `bottom`, both\n * containing a jQuery HTML element (or array of elements) to be placed on the main and bottom panels\n * of the dialog.\n * @returns {external:Promise} - A Promise that will be fulfilled when the dialog is closed.\n */\n showDlg(modal, options) {\n return new Promise((resolve, reject) => {\n this._dlgOkValue = 'ok';\n this._dlgCancelValue = 'cancelled';\n this._isModalDlg = modal;\n\n this.$dlgMainPanel.children().detach();\n this.$dlgBottomPanel.children().detach();\n if (options.main)\n this.$dlgMainPanel.append(options.main);\n if (options.bottom)\n this.$dlgBottomPanel.append(options.bottom);\n\n this._closeDlg = resolved => {\n if (resolved && resolve)\n resolve(this._dlgOkValue);\n else if (!resolved && reject)\n reject(this._dlgCancelValue);\n this.$dlgOverlay.css({ display: 'none' });\n this.enableMainButtons(true);\n this._closeDlg = Skin.prototype._closeDlg;\n };\n this.enableMainButtons(false);\n this.$dlgOverlay.css({ display: 'initial' });\n });\n }\n\n /**\n * Enables or disables the `tabindex` attribute of the main buttons. Useful when a modal dialog\n * overlay is active, to avoid direct access to controls not related with the dialog.\n * @param {boolean} status - `true` to make main controls navigable, `false` otherwise\n */\n enableMainButtons(status) {\n this.$playerCnt.find('button').attr('tabindex', status ? '0' : '-1');\n }\n\n /**\n * Called when the dialog must be closed, usually only by Skin members.\n * This method is re-defined on each call to `showDlg`, so the `resolve` and `reject`\n * functions can be safely called.\n */\n _closeDlg() {\n // Do nothing\n }\n\n /**\n * Displays a dialog with a report of the current results achieved by the user.\n * @param {module:report/Reporter.Reporter} reporter - The reporter system currently in use\n * @returns {external:Promise} - The Promise returned by {@link module:skins/Skin.Skin.showDlg}.\n */\n showReports(reporter) {\n this.$reportsPanel.html(this.$printReport(reporter));\n return this.showDlg(false, {\n main: [this.$infoHead, this.$reportsPanel],\n bottom: [this.$copyBtn, this.$closeDlgBtn]\n });\n }\n\n /**\n * Formats the current report in a DOM tree, ready to be placed in `$reportsPanel`\n * @param {module:report/Reporter.Reporter} reporter - The reporter system currently in use\n * @returns {external:jQuery[]} - An array of jQuery objects containing the full report\n */\n $printReport(reporter) {\n let result = [];\n if (reporter) {\n const\n report = reporter.getData(),\n started = new Date(report.started);\n\n result.push($('<div/>', { class: 'subTitle', id: this.ps.getUniqueId('ReportsLb') }).html(getMsg('Current results')));\n\n const $t = $('<table/>', { class: 'JCGlobalResults' });\n $t.append(\n $HTML.doubleCell(\n getMsg('Session started:'),\n `${started.toLocaleDateString()} ${started.toLocaleTimeString()}`),\n $HTML.doubleCell(\n getMsg('Reports system:'),\n `${getMsg(report.descriptionKey)} ${report.descriptionDetail}`));\n if (report.userId)\n $t.append($HTML.doubleCell(\n getMsg('User:'),\n report.userId));\n else if (report.user) // SCORM user\n $t.append($HTML.doubleCell(\n getMsg('User:'),\n report.user));\n\n if (report.sequences > 0) {\n if (report.sessions.length > 1)\n $t.append($HTML.doubleCell(\n getMsg('Projects:'),\n report.sessions.length));\n $t.append(\n $HTML.doubleCell(\n getMsg('Sequences:'),\n report.sequences),\n $HTML.doubleCell(\n getMsg('Activities done:'),\n report.activitiesDone),\n $HTML.doubleCell(\n getMsg('Activities played at least once:'),\n `${report.playedOnce}/${report.reportable} (${getPercent(report.ratioPlayed / 100)})`));\n if (report.activitiesDone > 0) {\n $t.append($HTML.doubleCell(\n getMsg('Activities solved:'),\n `${report.activitiesSolved} (${getPercent(report.ratioSolved / 100)})`));\n if (report.actScore > 0)\n $t.append(\n $HTML.doubleCell(\n getMsg('Partial score:'),\n `${getPercent(report.partialScore / 100)} ${getMsg('(out of played activities)')}`),\n $HTML.doubleCell(\n getMsg('Global score:'),\n `${getPercent(report.globalScore / 100)} ${getMsg('(out of all project activities)')}`));\n $t.append(\n $HTML.doubleCell(\n getMsg('Total time in activities:'),\n getHMStime(report.time * 1000)),\n $HTML.doubleCell(\n getMsg('Actions done:'),\n report.actions));\n }\n result.push($t);\n\n report.sessions.forEach(sr => {\n if (sr.sequences.length > 0) {\n const $t = $('<table/>', { class: 'JCDetailed' });\n result.push($('<p/>').html(report.sessions.length > 1 ? `${getMsg('Project')} ${sr.projectName}` : ''));\n $t.append($('<thead/>').append($('<tr/>').append(\n $HTML.th(getMsg('sequence')),\n $HTML.th(getMsg('activity')),\n $HTML.th(getMsg('OK')),\n $HTML.th(getMsg('actions')),\n $HTML.th(getMsg('score')),\n $HTML.th(getMsg('time')))));\n\n sr.sequences.forEach(seq => {\n let $tr = $('<tr/>').append($('<td/>', { rowspan: seq.activities.length }).html(seq.sequence));\n seq.activities.forEach(act => {\n if (act.closed) {\n $tr.append($HTML.td(act.name));\n $tr.append(act.solved ? $HTML.td(getMsg('YES'), 'ok') : $HTML.td(getMsg('NO'), 'no'));\n $tr.append($HTML.td(act.actions));\n $tr.append($HTML.td(getPercent(act.precision / 100)));\n $tr.append($HTML.td(getHMStime(act.time * 1000)));\n } else {\n $tr.append($HTML.td(act.name, 'incomplete'));\n for (let r = 0; r < 4; r++)\n $tr.append($HTML.td('-', 'incomplete'));\n }\n $t.append($tr);\n $tr = $('<tr/>');\n });\n });\n\n $t.append($('<tr/>').append(\n $HTML.td(getMsg('Total:')),\n $HTML.td(`${sr.played} (${getPercent(sr.ratioPlayed / 100)})`),\n $HTML.td(`${sr.solved} (${getPercent(sr.ratioSolved / 100)})`),\n $HTML.td(sr.actions),\n $HTML.td(getPercent(sr.score / 100)),\n $HTML.td(getHMStime(sr.time * 1000))));\n\n result.push($t);\n }\n }, this);\n } else\n result.push($('<p/>').html(getMsg('No activities done!')));\n }\n return result;\n }\n\n /**\n * Enables or disables a specific counter\n * @param {string} counter - Which counter\n * @param {boolean} bEnabled - When `true`, the counter will be enabled.\n */\n enableCounter(counter, bEnabled) {\n if (this.counters[counter])\n this.counters[counter].setEnabled(bEnabled);\n }\n\n /**\n * Main method used to build the content of the skin. Resizes and places internal objects.\n */\n doLayout() {\n // Resize player\n this.player.doLayout();\n\n // Build ths canvas at the end of current thread, thus avoiding\n // invalid sizes due to incomplete layout of DOM objects\n if (this.$msgBoxDiv)\n window.setTimeout(() => {\n\n // Temporary remove canvas to let div get its natural size:\n if (this.$msgBoxDivCanvas)\n this.$msgBoxDivCanvas.remove();\n\n // Get current size of message box div without canvas\n const\n msgWidth = this.$msgBoxDiv.outerWidth(),\n msgHeight = this.$msgBoxDiv.outerHeight();\n\n // Replace existing canvas if size has changed\n if (this.$msgBoxDivCanvas === null ||\n this.msgBox.dim.widht !== msgWidth ||\n this.msgBox.dim.height !== msgHeight) {\n this.$msgBoxDivCanvas = $(`<canvas width=\"${msgWidth}\" height=\"${msgHeight}\"/>`);\n this.msgBox.setBounds(new Rectangle(0, 0, msgWidth + 1, msgHeight));\n this.msgBox.buildAccessibleElement(this.$msgBoxDivCanvas, this.$msgBoxDiv);\n }\n // restore canvas\n this.$msgBoxDiv.append(this.$msgBoxDivCanvas);\n this.updateContent();\n }, 0);\n }\n\n /**\n * adjusts the skin to the dimension of its `$div` container\n * @returns {module:AWT.Dimension} the new dimension of the skin\n */\n fit() {\n this.doLayout();\n return new Dimension(this.$div.width(), this.$div.height());\n }\n\n /**\n * Sets or unsets the player in fullscreen mode, when allowed, using the\n * {@link https://github.com/sindresorhus/screenfull.js|screenfull.js} library.\n * @param {boolean} status - Whether to set or unset the player in fullscreen mode. When `null`\n * or `undefined`, the status toggles between fullscreen and windowed modes.\n * @returns {boolean} `true` if the request was successful, `false` otherwise.\n */\n setScreenFull(status) {\n if (document && document.fullscreenEnabled && (\n status === true && !document.fullscreenElement ||\n status === false && !document.fullscreenElement ||\n status !== true && status !== false)) {\n // Save current value of fullScreen for later use\n const full = document.fullscreenElement ? true : false;\n if (!document.fullscreenElement) {\n const element = this.player.$mainContainer.get(-1);\n if (element && element.requestFullscreen)\n element.requestFullscreen();\n } else {\n if (document.exitFullscreen) {\n document.exitFullscreen();\n }\n }\n this.player.fullScreenChecked = true;\n // Firefox don't updates `document.fullscreenElement` in real time, so use the saved value instead\n this.setSkinSizes(!full);\n }\n }\n\n /**\n * Method used to notify this skin that a specific action has changed its enabled/disabled status\n * @param {module:AWT.Action} _action - The action originating the change event\n */\n actionStatusChanged(act) {\n if (act.name && this.buttons[act.name])\n this.setEnabled(this.buttons[act.name], act.enabled);\n }\n\n /**\n * Enables or disables an object\n * @param {external:jQuery} $object - A JQuery DOM element\n * @override\n * @param {boolean} enabled\n */\n setEnabled($object, enabled) {\n if ($object)\n $object.prop('disabled', enabled ? null : true);\n }\n\n /**\n * Compares two Skin objects\n * @param {module:skins/Skin.Skin} skin - The Skin to compare against this\n * @returns {boolean} - `true` if both skins are equivalent.\n */\n equals(skin) {\n return skin &&\n this.name === skin.name &&\n this.ps === skin.ps;\n }\n\n /**\n * Gets the {@link module:boxes/ActiveBox.ActiveBox ActiveBox} used to display the main messages of activities\n * @returns {module:boxes/ActiveBox.ActiveBox}\n */\n getMsgBox() {\n return this.msgBox;\n }\n}\n\n/**\n * Collection of realized __Skin__ objects.\n * @type {module:skins/Skin.Skin[]}\n */\nSkin.skinStack = [];\n\n/**\n * Collection of skin style sheets already registered on the current document\n * @type {object}\n */\nSkin.rootStyles = {};\n\n/**\n * Counter used to label root nodes with unique IDs\n * @type {number}\n */\nSkin.lastId = 1;\n\n/**\n * List of classes derived from Skin. It should be filled by real skin classes at declaration time.\n * @type {object}\n */\nSkin.CLASSES = {};\n\nObject.assign(Skin.prototype, {\n /**\n * Class name of this skin. It will be used as a base selector in the definition of all CSS styles.\n * @name module:skins/Skin.Skin#skinId\n * @type {string} */\n skinId: 'JClicBasicSkin',\n /**\n * The HTML div object used by this Skin\n * @name module:skins/Skin.Skin#$div\n * @type {external:jQuery} */\n $div: null,\n /**\n * The HTML div where JClic Player will be placed\n * @name module:skins/Skin.Skin#$playerCnt\n * @type {external:jQuery} */\n $playerCnt: null,\n /**\n * Current name of the skin.\n * @name module:skins/Skin.Skin#name\n * @type {string} */\n name: 'default',\n /**\n * Specific options of this skin\n * @name module:skins/Skin.Skin#options\n * @type {object} */\n options: {},\n /**\n * Waiting panel, displayed while loading resources.\n * @name module:skins/Skin.Skin#$waitPanel\n * @type {external:jQuery} */\n $waitPanel: null,\n /**\n * Graphic indicator of loading progress\n * @name module:skins/Skin.Skin#$progress\n * @type {external:jQuery} */\n $progress: null,\n /**\n * Current value of the progress bar\n * @name module:skins/Skin.Skin#currentProgress\n * @type {number} */\n currentProgress: -1,\n /**\n * Max value of the progress bar\n * @name module:skins/Skin.Skin#maxProgress\n * @type {number} */\n maxProgress: 0,\n /**\n * The box used to display the main messages of JClic activities\n * @name module:skins/Skin.DefaultSkin#msgBox\n * @type {module:boxes/ActiveBox.ActiveBox} */\n msgBox: null,\n /**\n * The `div` DOM object where `msgBox` is located\n * @name module:skins/Skin.DefaultSkin#$msgBoxDiv\n * @type {external:jQuery} */\n $msgBoxDiv: null,\n /*\n * An HTML `canvas` object created in `$msgBoxDiv`\n * @name module:skins/Skin.DefaultSkin#$msgBoxDivCanvas\n * @type {external:jQuery} */\n $msgBoxDivCanvas: null,\n /**\n * Main panel used to display modal and non-modal dialogs\n * @name module:skins/Skin.Skin#$dlgOverlay\n * @type {external:jQuery} */\n $dlgOverlay: null,\n /**\n * Main panel of dialogs, where relevant information must be placed\n * @name module:skins/Skin.Skin#$dlgMainPanel\n * @type {external:jQuery} */\n $dlgMainPanel: null,\n /**\n * Bottom panel of dialogs, used for action buttons\n * @name module:skins/Skin.Skin#$dlgBottomPanel\n * @type {external:jQuery} */\n $dlgBottomPanel: null,\n /**\n * Element usually used as header in dialogs, with JClic logo, name and version\n * @name module:skins/Skin.Skin#infoHead\n * @type {external:jQuery} */\n $infoHead: null,\n /**\n * Iconic button used to copy content to clipboard\n * @name module:skins/Skin.Skin#$copyBtn\n * @type {external:jQuery} */\n $copyBtn: null,\n /**\n * Iconic button used to close the dialog\n * @name module:skins/Skin.Skin#$closeDlgBtn\n * @type {external:jQuery} */\n $closeDlgBtn: null,\n /**\n * OK dialog button\n * @name module:skins/Skin.Skin#$okDlgBtn\n * @type {external:jQuery} */\n $okDlgBtn: null,\n /**\n * Cancel dialog button\n * @name module:skins/Skin.Skin#$cancelDlgBtn\n * @type {external:jQuery} */\n $cancelDlgBtn: null,\n /**\n * Value to be returned by the dialog promise when the presented task is fulfilled\n * @name module:skins/Skin.Skin#_dlgOkValue\n * @type {object} */\n _dlgOkValue: null,\n /**\n * Value to be returned in user-canceled dialogs\n * @name module:skins/Skin.Skin#_dlgCancelValue\n * @type {object} */\n _dlgCancelValue: null,\n /**\n * Flag indicating if the current dialog is modal or not\n * @name module:skins/Skin.Skin#_isModalDlg\n * @type {boolean} */\n _isModalDlg: false,\n /**\n * Div inside {@link module:skins/Skin.Skin#$dlgOverlay $dlgOverlay} where JClicPlayer will place the information to be shown\n * @name module:skins/Skin.Skin#$reportsPanel\n * @type {external:jQuery} */\n $reportsPanel: null,\n /**\n * The basic collection of buttons that most skins implement\n * @name module:skins/Skin.Skin#buttons\n * @type {object} */\n buttons: {\n 'prev': null,\n 'next': null,\n 'return': null,\n 'reset': null,\n 'info': null,\n 'help': null,\n 'audio': null,\n 'about': null,\n 'fullscreen': null,\n 'close': null\n },\n /**\n * The collection of counters\n * @name module:skins/Skin.Skin#counters\n * @type {object} */\n counters: {\n 'actions': null,\n 'score': null,\n 'time': null\n },\n /**\n * The collection of message areas\n * @name module:skins/Skin.Skin#msgArea\n * @type {object} */\n msgArea: {\n 'main': null,\n 'aux': null,\n 'mem': null\n },\n /**\n * The {@link module:JClicPlayer.JClicPlayer JClicPlayer} object associated to this skin\n * @name module:skins/Skin.Skin#player\n * @type {module:JClicPlayer.JClicPlayer} */\n player: null,\n /**\n * The {@link http://projectestac.github.io/jclic/apidoc/edu/xtec/jclic/PlayStation.html|PlayStation}\n * used by this Skin. Usually, the same as `player`\n * @name module:skins/Skin.Skin#ps\n * @type {module:JClicPlayer.JClicPlayer} */\n ps: null,\n /**\n * Counter to be incremented or decremented as `waitCursor` is requested or released.\n * @name module:skins/Skin.Skin#waitCursorCount\n * @type {number} */\n waitCursorCount: 0,\n //\n // Buttons and other graphical resources used by this skin.\n //\n /**\n * Main styles\n * @name module:skins/Skin.Skin#basicCSS\n * @type {string} */\n basicCSS,\n /**\n * Waiting screen styles\n * @name module:skins/Skin.Skin#waitAnimCSS\n * @type {string} */\n waitAnimCSS,\n /**\n * Animated image displayed while loading resources\n * Based on Ryan Allen's [svg-spinner](http://articles.dappergentlemen.com/2015/01/13/svg-spinner/)\n * @name module:skins/Skin.Skin#waitImgBig\n * @type {string} */\n waitImgBig,\n /**\n * Animated image displayed while loading resources (small)\n * @name module:skins/Skin.Skin#waitImgSmall\n * @type {string} */\n waitImgSmall,\n /**\n * Reports screen styles\n * @name module:skins/Skin.Skin#reportsCSS\n * @type {string} */\n reportsCSS,\n //\n // Icons used in buttons:\n //\n /**\n * Icon for 'close dialog' button\n * @name module:skins/Skin.Skin#closeDialogIcon\n * @type {string} */\n closeDialogIcon,\n /**\n * Icon for 'ok' button\n * @name module:skins/Skin.Skin#okDialogIcon\n * @type {string} */\n okDialogIcon,\n /**\n * Icon for 'copy' button\n * @name module:skins/Skin.Skin#copyIcon\n * @type {string} */\n copyIcon,\n /**\n * JClic logo\n * @name module:skins/Skin.Skin#appLogo\n * @type {string} */\n appLogo,\n /**\n * Screen sizes (width and height) below which will half sized elements will be used\n * @name module:skins/Skin.DefaultSkin#halfMedia\n * @type {object} */\n halfMedia: { width: 376, height: 282 },\n /**\n * Screen sizes (width and height) below which will two-thirds sized elements will be used\n * @name module:skins/Skin.DefaultSkin#twoThirdsMedia\n * @type {object} */\n twoThirdsMedia: { width: 420, height: 315 },\n});\n\nexport default Skin;\n","/**\n * File : project/ProjectSettings.js\n * Created : 01/04/2015\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\n/* global window */\n\nimport $ from 'jquery';\nimport EventSounds from '../media/EventSounds.js';\nimport { log, getXmlNodeText, parseXmlNode, reduceTextsToStrings, parseOldDate, cleanOldLanguageTag, getAttr, setAttr } from '../Utils.js';\n\n/**\n * This class contains miscellaneous settings of JClic projects.\n *\n * In addition to the members of this class, there can be other properties in JClic project files\n * that are not currently loaded:\n * - iconFileName\n * - descriptors\n * - area\n * - level\n * - locale\n * - authors\n * - organizations\n * - revisions\n */\nexport class ProjectSettings {\n /**\n * ProjectSettings constructor\n * @param {module:project/JClicProject.JClicProject} project - The project to which this settings belongs\n */\n constructor(project) {\n this.project = project;\n this.authors = [];\n this.organizations = [];\n this.revisions = [];\n this.languages = [];\n this.locales = [];\n this.description = {};\n this.tags = {};\n }\n\n /**\n * Reads the ProjectSettings values from a JQuery XML element\n * @param {external:jQuery} $xml - The XML element to parse\n */\n setProperties($xml) {\n let single_description = null;\n const multiple_descriptions = [];\n\n $xml.children().each((_n, child) => {\n switch (child.nodeName) {\n case 'title':\n this.title = child.textContent;\n break;\n case 'description':\n single_description = getXmlNodeText(child);\n break;\n case 'descriptions':\n $(child).children().each((_n, desc) => multiple_descriptions.push(parseXmlNode(desc)));\n break;\n case 'author':\n this.authors.push(reduceTextsToStrings(parseXmlNode(child)));\n break;\n case 'organization':\n this.organizations.push(reduceTextsToStrings(parseXmlNode(child)));\n break;\n case 'revision':\n const revision = reduceTextsToStrings(parseXmlNode(child));\n if (revision.date)\n revision.date = parseOldDate(revision.date);\n this.revisions.push(revision);\n break;\n case 'language':\n this.languages.push(cleanOldLanguageTag(child.textContent));\n break;\n case 'eventSounds':\n this.eventSounds = new EventSounds();\n this.eventSounds.setProperties($(child));\n break;\n case 'skin':\n this.skinFileName = $(child).attr('file');\n break;\n case 'descriptors':\n this.tags = parseXmlNode(child, true);\n if (this.tags['#text']) {\n this.tags.other = this.tags['#text'].textContent;\n delete this.tags['#text'];\n }\n break;\n case 'license':\n this.license = getXmlNodeText(child);\n break;\n case 'cover':\n case 'thumb':\n const img = getXmlNodeText(child);\n if (img.file)\n this[child.nodeName] = img.file;\n break;\n }\n });\n\n this.buildLocales();\n\n multiple_descriptions.forEach(d => {\n if (d.language && d.text)\n this.description[d.language] = d.text;\n });\n\n if (single_description && this.languages.length > 0 && !this.description[this.languages[0]])\n this.description[this.languages[0]] = single_description;\n\n return this;\n }\n\n buildLocales() {\n // Try to find an array of valid locales\n // See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl\n if (this.languages.length > 0 && window.Intl && window.Intl.getCanonicalLocales) {\n this.locales = [];\n this.languages.forEach(lang => {\n // Languages usually are stored in the form: \"English (en)\"\n const matches = /\\(([a-z,A-Z,-]+)\\)/.exec(lang);\n if (matches && matches.length > 1) {\n try {\n const canonicals = window.Intl.getCanonicalLocales(matches[1]);\n if (canonicals)\n this.locales = this.locales.concat(canonicals);\n } catch (_err) {\n log('error', `Invalid language: ${lang}`);\n }\n }\n });\n }\n return this;\n }\n\n /**\n * Gets a object with the basic attributes needed to rebuild this instance excluding functions,\n * parent references, constants and also attributes retaining the default value.\n * The resulting object is commonly usued to serialize elements in JSON format.\n * @returns {object} - The resulting object, with minimal attrributes\n */\n getAttributes() {\n return getAttr(this, [\n 'title', 'description',\n 'tags', 'languages', 'license',\n 'authors', 'organizations',\n 'revisions',\n 'cover', 'thumb',\n 'skinFileName', 'eventSounds'\n ]);\n }\n\n /**\n * Reads the properties of this ProjectSettings from a data object\n * @param {object} data - The data object to be parsed, or just the text content\n * @returns {module:project/ProjectSettings.ProjectSettings}\n */\n setAttributes(data) {\n setAttr(this, data, [\n 'title', 'description',\n 'tags', 'languages', 'license',\n 'authors', 'organizations',\n 'revisions',\n 'cover', 'thumb',\n 'skinFileName', 'eventSounds'\n ]);\n\n // Build Date objects in revisions\n if (this.revisions)\n this.revisions.forEach(rv => {\n if (rv.date)\n rv.date = new Date(rv.date);\n });\n\n return this.buildLocales();\n }\n}\n\nObject.assign(ProjectSettings.prototype, {\n /**\n * The JClicProject to which this ProjectSettings belongs\n * @name module:project/ProjectSettings.ProjectSettings#project\n * @type {module:project/JClicProject.JClicProject} */\n project: null,\n /**\n * The project title\n * @name module:project/ProjectSettings.ProjectSettings#title\n * @type {string} */\n title: 'Untitled',\n /**\n * The authors of this project.\n * Each author is represented by an object with the following attributes:\n * `name` (mandatory), `mail`, `rol`, `organization` and `url`\n * @name module:project/ProjectSettings.ProjectSettings#authors\n * @type {object[]} */\n authors: null,\n /**\n * Schools, companies and other institutions involved on this project.\n * Each organization is represented by an object with the following attributes:\n * `name` (mandatory), `mail`, `url`, `address`, `pc`, `city`, `state`, `country`, `comments`\n * @name module:project/ProjectSettings.ProjectSettings#organizations\n * @type {object[]} */\n organizations: null,\n /**\n * The history of revisions made to this project.\n * Revisions are represented by objects with the following attributes:\n * `date` (mandatory), `description`, `comments` and `author`\n * @name module:project/ProjectSettings.ProjectSettings#revisions\n * @type {object[]} */\n revisions: null,\n /**\n * Project's description, maybe in multiple languages.\n * @name module:project/ProjectSettings.ProjectSettings#description\n * @type {object} */\n description: null,\n /**\n * JClic projects can use more than one language, so use a string array\n * @name module:project/ProjectSettings.ProjectSettings#languages\n * @type {string[]} */\n languages: null,\n tags: null,\n cover: null,\n thumb: null,\n license: {\n type: 'by-nc-sa',\n url: 'https://creativecommons.org/licenses/by-nc-sa/4.0',\n },\n /**\n * Array of canonical locales, as defined in\n * {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl#Locale_identification_and_negotiation|Intl}\n * @name module:project/ProjectSettings.ProjectSettings#locales\n * @type {string[]} */\n locales: null,\n /**\n * The name of an optional 'skin' (visual aspect) can be set for the whole project, or for each {@link module:Activity.Activity Activity}\n * @name module:project/ProjectSettings.ProjectSettings#skinFileName\n * @type {string} */\n skinFileName: null,\n /**\n * The main {@link module:media/EventSounds.EventSounds EventSounds} object of the project\n * @name module:project/ProjectSettings.ProjectSettings#eventSounds\n * @type {module:media/EventSounds.EventSounds} */\n eventSounds: new EventSounds(),\n});\n\nexport default ProjectSettings;\n","/**\n * File : bags/JumpInfo.js\n * Created : 05/04/2015\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Catalan Educational Telematic Network (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\nimport { nSlash, getAttr, isEmpty } from '../Utils.js';\n\n/**\n * This class contains information about what things JClic sequence manager has to do in certain\n * circumstances, such as:\n * - an activity finishes\n * - the user clicks on the \"next\" or \"prev\" buttons\n * - the user clicks or a cell with special \"active content\"\n *\n * Different kinds of actions are possible for each of these events:\n * - RETURN: to go back to a previous point in the sequence.\n * - EXIT: to exit the program (thus navigating to another URL)\n * - STOP: to do nothing.\n * - JUMP: to jump to a specific point in the sequence of activities, or to another JClic project.\n * @see {@link module:bags/ActivitySequenceJump.ActivitySequenceJump ActivitySequenceJump}\n * @see {@link module:bags/ConditionalJumpInfo.ConditionalJumpInfo ConditionalJumpInfo}\n */\nexport class JumpInfo {\n /**\n * JumpInfo constructor\n * @param {string} action - Must be one of the described actions.\n * @param {number|string} [sq] - Can be the tag of the sequence element to jump to, or its\n * cardinal number in the list.\n */\n constructor(action, sq) {\n this.action = action;\n switch (typeof sq) {\n case 'string':\n this.sequence = sq;\n break;\n case 'number':\n this.actNum = sq;\n break;\n }\n }\n\n /**\n * Loads the object settings from a specific JQuery XML element\n * @param {external:jQuery} $xml - The XML element to parse\n */\n setProperties($xml) {\n this.id = $xml.attr('id');\n this.action = $xml.attr('action') || 'JUMP';\n if ($xml.attr('tag'))\n this.sequence = nSlash($xml.attr('tag'));\n if ($xml.attr('project'))\n this.projectPath = nSlash($xml.attr('project'));\n return this;\n }\n\n /**\n * Gets a object with the basic attributes needed to rebuild this instance excluding functions,\n * parent references, constants and also attributes retaining the default value.\n * The resulting object is commonly usued to serialize elements in JSON format.\n * @returns {object} - The resulting object, with minimal attrributes\n */\n getAttributes() {\n return getAttr(this, ['id', 'action', 'actNum', 'sequence', 'projectPath']);\n }\n\n /**\n * Loads the object settings from a data object\n * @param {object} data - The data object to parse\n */\n setAttributes(data) {\n ['id', 'action', 'actNum', 'sequence', 'projectPath'].forEach(t => {\n if (!isEmpty(data[t]))\n this[t] = data[t];\n });\n return this;\n }\n}\n\nObject.assign(JumpInfo.prototype, {\n /**\n * The JumpInfo identifier\n * - For regular jumps: 'forward', 'back'\n * - For conditional jumps: 'upper', 'lower'\n * @name module:bags/JumpInfo.JumpInfo#id\n * @type {string} */\n id: null,\n /**\n * The current action.\n * Possible values are: `JUMP`, `STOP`, `RETURN` and `EXIT`.\n * @name module:bags/JumpInfo.JumpInfo#action\n * @type {string} */\n action: null,\n /**\n * Activity number in the sequence list\n * @name module:bags/JumpInfo.JumpInfo#actNum\n * @type {number} */\n actNum: -1,\n /**\n * Current sequence tag\n * @name module:bags/JumpInfo.JumpInfo#sequence\n * @type {string} */\n sequence: null,\n /**\n * Path of another JClic project to jump to\n * @name module:bags/JumpInfo.JumpInfo#projectPath\n * @type {string} */\n projectPath: null,\n});\n\nexport default JumpInfo;\n","/**\n * File : bags/ConditionalJumpInfo.js\n * Created : 05/04/2015\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Catalan Educational Telematic Network (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\nimport JumpInfo from './JumpInfo.js';\nimport { getAttr, isEmpty } from '../Utils.js';\n\n/**\n * This special case of {@link module:bags/JumpInfo.JumpInfo JumpInfo} is used in {@link module:bags/ActivitySequenceJump.ActivitySequenceJump ActivitySequenceJump} objects to decide\n * the type of jump or action to be performed, based on the results obtained by the user when\n * playing previous JClic activities.\n *\n * In addition to the standard {@link module:bags/JumpInfo.JumpInfo JumpInfo} fields and methods, this class has two public\n * members where score and time thresholds are stored.\n *\n * The exact meaning of this members will depend on the type of `ConditionalJumpInfo` in the\n * {@link module:bags/ActivitySequenceJump.ActivitySequenceJump ActivitySequenceJump} (it can be `upperJump` or `lowerJump`).\n * @extends module:bags/JumpInfo.JumpInfo\n */\nexport class ConditionalJumpInfo extends JumpInfo {\n /**\n * ConditionalJumpInfo constructor\n * @param {string} action - Must be one of the described actions.\n * @param {number|string} [sq] - Can be the tag of the sequence element to jump to, or its\n * cardinal number in the list.\n * @param {number} [threshold] - Threshold above or below which the action will be triggered,\n * depending on the type of JumpInfo.\n * @param {number} [time] - Delay to be applied in automatic jumps.\n */\n constructor(action, sq, threshold, time) {\n super(action, sq);\n this.threshold = typeof threshold === 'number' ? threshold : -1;\n this.time = typeof threshold === 'number' ? time : -1;\n }\n\n /**\n * Loads this object settings from a specific JQuery XML element\n * @param {external:jQuery} $xml - The XML element to parse\n */\n setProperties($xml) {\n super.setProperties($xml);\n if ($xml.attr('threshold') !== undefined)\n this.threshold = $xml.attr('threshold');\n if ($xml.attr('time') !== undefined)\n this.time = $xml.attr('time');\n return this;\n }\n\n /**\n * Gets a object with the basic attributes needed to rebuild this instance excluding functions,\n * parent references, constants and also attributes retaining the default value.\n * The resulting object is commonly usued to serialize elements in JSON format.\n * @returns {object} - The resulting object, with minimal attrributes\n */\n getAttributes() {\n return Object.assign(super.getAttributes(), getAttr(this, ['threshold', 'time']));\n }\n\n /**\n * Loads this conditional jump settings from a data object\n * @param {object} data - The data object to parse\n */\n setAttributes(data) {\n super.setAttributes(data);\n ['threshold', 'time'].forEach(t => {\n if (!isEmpty(data[t]))\n this[t] = data[t];\n });\n return this;\n }\n}\n\nObject.assign(ConditionalJumpInfo.prototype, {\n /**\n * Threshold above or below which the action will be triggered, depending on the type of JumpInfo.\n * @name module:bags/ConditionalJumpInfo.ConditionalJumpInfo#threshold\n * @type {number} */\n threshold: -1,\n /**\n * Delay to be applied in automatic jumps.\n * @name module:bags/ConditionalJumpInfo.ConditionalJumpInfo#time\n * @type {number} */\n time: -1,\n});\n\nexport default ConditionalJumpInfo;\n","/**\n * File : bags/ActivitySequenceJump.js\n * Created : 05/04/2015\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Catalan Educational Telematic Network (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\nimport $ from 'jquery';\nimport JumpInfo from './JumpInfo.js';\nimport ConditionalJumpInfo from './ConditionalJumpInfo.js';\nimport { getAttr } from '../Utils.js';\n\n/**\n * This is a special case of {@link module:bags/JumpInfo.JumpInfo JumpInfo}, used only in {@link module:bags/ActivitySequenceElement.ActivitySequenceElement ActivitySequenceElement} objects.\n * Sequence elements can contain up to two ActivitySequenceJump objects: one to be processed\n * when the user clicks on the \"next\" button (or when the activity finishes, if in automatic mode),\n * and the other used with the \"prev\" button. ActivitySequenceJump objects define a default jump\n * or action to be performed, but can also have up to two {@link module:bags/ConditionalJumpInfo.ConditionalJumpInfo ConditionalJumpInfo} objects. These\n * define alternative jumps that are performed only when score or time are below or over a specific\n * threshold.\n * @extends module:bags/JumpInfo.JumpInfo\n */\nexport class ActivitySequenceJump extends JumpInfo {\n /**\n * ActivitySequenceJump constructor\n * @param {string} action - Must be one of the described actions.\n * @param {number|string} [sq] - Can be the tag of the sequence element to jump to, or its\n * cardinal number in the list.\n */\n constructor(action, sq) {\n super(action, sq);\n }\n\n /**\n * Loads the object settings from a specific JQuery XML element.\n * @param {external:jQuery} $xml - The XML element to parse\n */\n setProperties($xml) {\n super.setProperties($xml);\n\n // Read conditional jumps\n $xml.children('jump').each((_n, child) => {\n const condJmp = new ConditionalJumpInfo().setProperties($(child));\n if (condJmp.id === 'upper')\n this.upperJump = condJmp;\n else if (condJmp.id === 'lower')\n this.lowerJump = condJmp;\n });\n return this;\n }\n\n /**\n * Gets a object with the basic attributes needed to rebuild this instance excluding functions,\n * parent references, constants and also attributes retaining the default value.\n * The resulting object is commonly usued to serialize elements in JSON format.\n * @returns {object} - The resulting object, with minimal attrributes\n */\n getAttributes() {\n return Object.assign(super.getAttributes(), getAttr(this, ['upperJump', 'lowerJump']));\n }\n\n /**\n * Loads the jump settings from a data object\n * @param {object} data - The data object to parse\n */\n setAttributes(data) {\n super.setAttributes(data);\n\n ['upperJump', 'lowerJump'].forEach(cj => {\n if (data[cj])\n this[cj] = new ConditionalJumpInfo().setAttributes(data[cj]);\n });\n\n return this;\n }\n\n\n /**\n * Resolves what {@link module:bags/JumpInfo.JumpInfo JumpInfo} must be taken, based on a done time and average rating obtained\n * in activities.\n * @param {number} rating - Average rating obtained by the user in the activities done during the\n * last sequence stretch.\n * @param {number} time - Total time spend doing the activities.\n * @returns {module:bags/JumpInfo.JumpInfo}\n */\n resolveJump(rating, time) {\n let result = this;\n if (rating >= 0 && time >= 0) {\n if (this.upperJump !== null &&\n rating > this.upperJump.threshold &&\n (this.upperJump.time <= 0 || time < this.upperJump.time)) {\n result = this.upperJump;\n } else if (this.lowerJump !== null &&\n (rating < this.lowerJump.threshold ||\n this.lowerJump.time > 0 && time > this.lowerJump.time)) {\n result = this.lowerJump;\n }\n }\n return result;\n }\n}\n\nObject.assign(ActivitySequenceJump.prototype, {\n /**\n * Optional jump to be performed when the results (score and time) are above a specific threshold.\n * @name module:bags/ActivitySequenceJump.ActivitySequenceJump#upperJump\n * @type {module:bags/ConditionalJumpInfo.ConditionalJumpInfo} */\n upperJump: null,\n /**\n * Optional jump to be performed when the results (score or time) are below a specific threshold.\n * @name module:bags/ActivitySequenceJump.ActivitySequenceJump#lowerJump\n * @type {module:bags/ConditionalJumpInfo.ConditionalJumpInfo} */\n lowerJump: null,\n});\n\nexport default ActivitySequenceJump;\n","/**\n * File : bags/ActivitySequenceElement.js\n * Created : 05/04/2015\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\nimport $ from 'jquery';\nimport ActivitySequenceJump from './ActivitySequenceJump.js';\nimport { attrForEach, nSlash, getAttr, isEmpty } from '../Utils.js';\n\n/**\n *\n * This class is the basic component of {@link module:bags/ActivitySequence.ActivitySequence ActivitySequence} objects. It represents a specific\n * point in the project's sequence of JClic activities.\n *\n * For each point of the sequence, some options can be set:\n * - What activity must run at this point\n * - What to do or where to jump when the activity finishes\n * - The behavior of the \"next\" button\n * - The behavior of the \"prev\" button\n *\n * Sequence points can also have a \"tag\", used to refer to them with a unique name.\n */\nexport class ActivitySequenceElement {\n constructor() {\n }\n\n /**\n * Loads the object settings from a specific JQuery XML element\n * @param {external:jQuery} $xml\n */\n setProperties($xml) {\n\n // Iterate on all provided attributes\n attrForEach($xml.get(0).attributes, (name, val) => {\n switch (name) {\n case 'id':\n this['tag'] = nSlash(val);\n break;\n case 'name':\n this['activity'] = val;\n break;\n case 'description':\n // possible navButtons values are: `none`, `fwd`, `back` or `both`\n case 'navButtons':\n this[name] = val;\n break;\n case 'delay':\n this[name] = Number(val);\n break;\n }\n });\n\n // Iterate on 'jump' elements to load fwdJump and/or backJump\n $xml.children('jump').each((_n, data) => {\n const jmp = new ActivitySequenceJump().setProperties($(data));\n if (jmp.id === 'forward')\n this.fwdJump = jmp;\n else if (jmp.id === 'back')\n this.backJump = jmp;\n });\n return this;\n }\n\n /**\n * Gets a object with the basic attributes needed to rebuild this instance excluding functions,\n * parent references, constants and also attributes retaining the default value.\n * The resulting object is commonly usued to serialize elements in JSON format.\n * @returns {object} - The resulting object, with minimal attrributes\n */\n getAttributes() {\n return getAttr(this, ['tag', 'description', 'activity', 'fwdJump', 'backJump', 'navButtons', 'delay']);\n }\n\n /**\n * Loads sequence element settings from a data object\n * @param {object} data\n */\n setAttributes(data) {\n ['tag', 'description', 'activity', 'navButtons', 'delay'].forEach(t => {\n if (!isEmpty(data[t]))\n this[t] = data[t];\n });\n\n ['fwdJump', 'backJump'].forEach(jmp => {\n if (data[jmp]) {\n this[jmp] = new ActivitySequenceJump().setAttributes(data[jmp]);\n }\n });\n return this;\n }\n}\n\nObject.assign(ActivitySequenceElement.prototype, {\n /**\n * Optional unique identifier of this element in the {@link module:bags/ActivitySequence.ActivitySequence ActivitySequence}.\n * @name module:bags/ActivitySequenceElement.ActivitySequenceElement#tag\n * @type {string} */\n tag: null,\n /**\n * Optional description of this sequence element.\n * @name module:bags/ActivitySequenceElement.ActivitySequenceElement#description\n * @type {string} */\n description: null,\n /**\n * Name of the {@link module:Activity.Activity Activity} pointed by this element.\n * @name module:bags/ActivitySequenceElement.ActivitySequenceElement#activity\n * @type {string} */\n activity: '',\n /**\n * Jump to be processed by the 'next' button action\n * @name module:bags/ActivitySequenceElement.ActivitySequenceElement#fwdJump\n * @type {module:bags/ActivitySequenceJump.ActivitySequenceJump} */\n fwdJump: null,\n /**\n * Jump to be processed by the 'prev' button action.\n * @name module:bags/ActivitySequenceElement.ActivitySequenceElement#backJump\n * @type {module:bags/ActivitySequenceJump.ActivitySequenceJump} */\n backJump: null,\n /**\n * What buttons should be active at this point of the sequence. Valid values are:\n * - 'none'\n * - 'fwd'\n * - 'back'\n * - 'both'\n * @name module:bags/ActivitySequenceElement.ActivitySequenceElement#navButtons\n * @type {string} */\n navButtons: 'both',\n /**\n * Time delay (in seconds) before passing to the next/prev activity\n * @name module:bags/ActivitySequenceElement.ActivitySequenceElement#delay\n * @type {number} */\n delay: 0,\n});\n\nexport default ActivitySequenceElement;\n","/**\n * File : bags/ActivitySequence.js\n * Created : 05/04/2015\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\nimport $ from 'jquery';\nimport JumpInfo from './JumpInfo.js';\nimport ActivitySequenceElement from './ActivitySequenceElement.js';\nimport ActivitySequenceJump from './ActivitySequenceJump.js';\nimport { nSlash } from '../Utils.js';\n\n/**\n * This class stores the definition of the sequence to follow to show the activities of a\n * {@link module:project/JClicProject.JClicProject JClicProject}. The sequence are formed by an ordered list of objects of type\n * {@link module:bags/ActivitySequenceElement.ActivitySequenceElement ActivitySequenceElement}.\n * It stores also a transient pointer to the current sequence element.\n */\nexport class ActivitySequence {\n /**\n * ActivitySequence constructor\n * @param {module:project/JClicProject.JClicProject} project - The JClic project to which this ActivitySequence belongs\n */\n constructor(project) {\n this.project = project;\n this.elements = [];\n }\n\n /**\n * Loads the object settings from a specific JQuery XML element\n * @param {external:jQuery} $xml - The XML element to parse\n */\n setProperties($xml) {\n $xml.children('item').each((_i, data) => this.elements.push(new ActivitySequenceElement().setProperties($(data))));\n return this;\n }\n\n /**\n * Gets a object with the basic attributes needed to rebuild this instance excluding functions,\n * parent references, constants and also attributes retaining the default value.\n * The resulting object is commonly usued to serialize elements in JSON format.\n * @returns {object} - The resulting object, with minimal attrributes\n */\n getAttributes() {\n return this.elements.map(el => el.getAttributes());\n }\n\n /**\n * Loads the object settings from a data object\n * @param {object} data - The data object to parse\n */\n setAttributes(data) {\n data.forEach(el => this.elements.push(new ActivitySequenceElement().setAttributes(el)));\n return this;\n }\n\n /**\n * Returns the index of the specified element in the sequence.\n * @param {module:bags/ActivitySequenceElement.ActivitySequenceElement} ase - The element to search.\n * @returns {number} - The requested index, or `null` if not found.\n */\n getElementIndex(ase) {\n return ase === null ? -1 : this.elements.indexOf(ase);\n }\n\n /**\n * Returns the nth element of the sequence.\n * @param {number} n - Index of the requested element\n * @param {boolean} updateCurrentAct - when `true`, the `currentAct` index will be updated.\n * @returns {module:bags/ActivitySequenceElement.ActivitySequenceElement} - The requested element, or `null` if out of range.\n */\n getElement(n, updateCurrentAct) {\n let result = null;\n if (n >= 0 && n < this.elements.length) {\n result = this.elements[n];\n if (updateCurrentAct)\n this.currentAct = n;\n }\n return result;\n }\n\n /**\n * Search into the sequence for a element with the provided tag\n * @param {string} tag - The tag to search\n * @param {boolean} updateCurrentAct - when `true`, the `currentAct` index will be updated.\n * @returns {module:bags/ActivitySequenceElement.ActivitySequenceElement} - The requested element, or `null` if not found.\n */\n getElementByTag(tag, updateCurrentAct) {\n let\n result = null,\n resultIndex = -1;\n if (tag) {\n tag = nSlash(tag);\n this.elements.some((el, index) => {\n if (el.tag === tag) {\n result = el;\n resultIndex = index;\n }\n return resultIndex !== -1;\n });\n if (resultIndex !== -1 && updateCurrentAct)\n this.currentAct = resultIndex;\n }\n return result;\n }\n\n /**\n * Gets the sequence element pointed by the `currentAct` member.\n * @returns {module:bags/ActivitySequenceElement.ActivitySequenceElement} - The current sequence element, or `null` if not set.\n */\n getCurrentAct() {\n return this.getElement(this.currentAct, false);\n }\n\n /**\n * Checks if it's possible to go forward from the current position in the sequence.\n * @param {boolean} hasReturn - Indicates whether the history of jumps done since the beginning\n * of the JClic session is empty or not. When not empty, a `RETURN` action is still possible.\n * @returns {boolean} - `true` when the user is allowed to go ahead to a next activity,\n * `false` otherwise. */\n hasNextAct(hasReturn) {\n let result = false;\n const ase = this.getCurrentAct();\n if (ase) {\n if (ase.fwdJump === null)\n result = true;\n else\n switch (ase.fwdJump.action) {\n case 'STOP':\n break;\n case 'RETURN':\n result = hasReturn;\n break;\n default:\n result = true;\n }\n }\n return result;\n }\n\n /**\n * Checks if it's possible to go back from the current position in the sequence.\n * @param {boolean} hasReturn - Indicates whether the history of jumps done since the beginning\n * of the JClic session is empty or not. When not empty, a `RETURN` action is still possible.\n * @returns {boolean} - `true` when the user is allowed to go back to a previous activity,\n * `false` otherwise. */\n hasPrevAct(hasReturn) {\n let result = false;\n const ase = this.getCurrentAct();\n if (ase) {\n if (ase.backJump === null)\n result = true;\n else\n switch (ase.backJump.action) {\n case 'STOP':\n break;\n case 'RETURN':\n result = hasReturn;\n break;\n default:\n result = true;\n }\n }\n return result;\n }\n\n /**\n * Gets the current state for the 'next' and 'prev' buttons.\n * @returns {string} - One of the possible values of {@link module:bags/ActivitySequenceElement.ActivitySequenceElement#navButtons navButtons},\n * thus: `none`, `fwd`, `back` or `both`\n */\n getNavButtonsFlag() {\n let flag = 'none';\n const ase = this.getCurrentAct();\n if (ase)\n flag = ase.navButtons;\n return flag;\n }\n\n /**\n * Computes the jump to perform from the current position on the sequence\n * @param {boolean} back - When `true`, the request is for the 'go back' button. Otherwise, is\n * for the 'next' one.\n * @param {module:report/Reporter.Reporter} reporter - The reporting engine that will provide values about score average\n * and time spend on the activities, used only to compute conditional jumps.\n * @returns {module:bags/JumpInfo.JumpInfo} - The jump info if a valid jump is possible, `null` otherwise.\n */\n getJump(back, reporter) {\n const ase = this.getCurrentAct();\n let result = null;\n if (ase) {\n const asj = back ? ase.backJump : ase.fwdJump;\n if (asj === null) {\n let i = this.currentAct + (back ? -1 : 1);\n if (i >= this.elements.length || i < 0)\n i = 0;\n result = new JumpInfo('JUMP', i);\n } else {\n let\n rating = -1,\n time = -1;\n if (reporter !== null) {\n const seqRegInfo = reporter.getCurrentSequenceInfo();\n if (seqRegInfo !== null) {\n rating = Math.round(seqRegInfo.tScore);\n time = Math.round(seqRegInfo.tTime / 1000);\n }\n }\n result = asj.resolveJump(rating, time);\n }\n }\n return result;\n }\n\n /**\n * Finds the nearest sequence element with a valid 'tag', looking back in the `elements` list.\n * @param {number} num - The point of the sequence from which to start looking back.\n * @returns {string} - The nearest 'tag', or `null` if not found.\n */\n getSequenceForElement(num) {\n let tag = null;\n if (num >= 0 && num < this.elements.length)\n for (let i = num; tag === null && i >= 0; i--) {\n tag = this.getElement(i, false).tag;\n }\n return tag;\n }\n\n /**\n * Gets the first {@link module:bags/ActivitySequenceElement.ActivitySequenceElement ActivitySequenceElement} in the `elements` list pointing to the\n * specified activity name.\n * The search is always case-insensitive.\n * @param {string} activity - The name of the activity to search for.\n * @returns {module:bags/ActivitySequenceElement.ActivitySequenceElement} The requested element or `null` if not found.\n */\n getElementByActivityName(activity) {\n let result = null;\n if (activity !== null) {\n for (let i = 0; result === null && i < this.elements.length; i++) {\n const ase = this.getElement(i, false);\n if (ase.activity.toLowerCase() === activity.toLowerCase())\n result = ase;\n }\n }\n return result;\n }\n\n /**\n * Utility function to check if the current sequence element corresponds to the specified\n * activity. If negative, the `currentAct` will be accordingly set.\n * @param {string} activity - The name of the activity to check\n */\n checkCurrentActivity(activity) {\n let ase = this.getCurrentAct();\n if (ase === null || ase.activity.toUpperCase() !== activity.toUpperCase()) {\n for (let i = 0; i < this.elements.length; i++) {\n if (this.getElement(i, false).activity.toUpperCase() === activity.toUpperCase()) {\n this.currentAct = i;\n return false;\n }\n }\n ase = new ActivitySequenceElement();\n ase.activity = activity;\n ase.fwdJump = new ActivitySequenceJump('STOP');\n ase.backJump = new ActivitySequenceJump('STOP');\n this.elements.push(ase);\n this.currentAct = this.elements.length - 1;\n return false;\n }\n return true;\n }\n}\n\nObject.assign(ActivitySequence.prototype, {\n /**\n * The ordered list of {@link module:bags/ActivitySequenceElement.ActivitySequenceElement ActivitySequenceElement} objects\n * @name module:bags/ActivitySequence.ActivitySequence#elements\n * @type {module:bags/ActivitySequenceElement.ActivitySequenceElement[]} */\n elements: null,\n /**\n * The JClic project to which this ActivitySequence belongs.\n * @name module:bags/ActivitySequence.ActivitySequence#project\n * @type {module:project/JClicProject.JClicProject} */\n project: null,\n /**\n * Pointer to the {@link module:bags/ActivitySequenceElement.ActivitySequenceElement ActivitySequenceElement} currently running (points inside\n * the `elements` array).\n * @name module:bags/ActivitySequence.ActivitySequence#currentAct\n * @type {number} */\n currentAct: -1,\n});\n\nexport default ActivitySequence;\n","const __WEBPACK_NAMESPACE_OBJECT__ = require(\"@francesc/basic-midi-player-js\");","/**\n * File : media/MidiAudioPlayer.js\n * Created : 11/10/2018\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\n/* global window */\n\nimport MidiPlayer from '@francesc/basic-midi-player-js';\nimport { log } from '../Utils.js';\n\n// TODO: Use multiple instruments, at least one for each track\n// TODO: Use multiple midi channels (currently flattened to a single channel)\n// TODO: Use of channel 10 for percussion instruments\n// TODO: ... build a real MIDI player!!\n\n/**\n * A simple MIDI player based on MidiPlayerJS\n * https://github.com/grimmdude/MidiPlayerJS\n * See also: http://www.midijs.net (https://github.com/babelsberg/babelsberg-js/tree/master/midijs)\n */\nexport class MidiAudioPlayer {\n /**\n * MidiAudioPlayer constructor\n * @param {external:ArrayBuffer} data - The MIDI file content, in ArrayBuffer format\n * @param {object} [options={}] - Optional params related to the type of soundfont used. Valid options inside this object are:<br>\n * - `MIDISoundFontObject`: An object containing the full soundfont data. When this param is provided, no other one will be used.\n * - `MIDISoundFontBase`: The URL used as base for the current collection of MIDI soundfonts. Defaults to `https://clic.xtec.cat/dist/jclic.js/soundfonts/MusyngKite`\n * - `MIDISoundFontName`: The MIDI instrument name. Defaults to `acoustic_grand_piano`. See [MIDI.js Soundfonts](https://github.com/gleitz/midi-js-soundfonts) for full lists of MIDI instrument names.\n * - `MIDISoundFontExtension`: An extension to be added to `MIDISoundFontName` in order to build the full file name of the soundfont JS file. Defaults to `-mp3.js`\n */\n constructor(data, options = {}) {\n const AudioContext = window && (window.AudioContext || window.webkitAudioContext);\n if (AudioContext) {\n // Build instrument on first call to constructor\n MidiAudioPlayer.prepareInstrument(options, new AudioContext());\n this.data = data;\n this.player = new MidiPlayer.Player(ev => this.playEvent(ev));\n if (this.player)\n this.player.loadArrayBuffer(data);\n }\n }\n\n /**\n * Initializes the soundfont instrument, loading data from GitHub\n * NOTE: This will not work when off-line!\n * TODO: Provided a basic, simple, static soundfont\n * @param {object} options - Optional param with options related to the MIDI soundfont. See details in `constructor` description.\n * @param {external:AudioContext} audioContext - The AudioContext object (see: https://developer.mozilla.org/en-US/docs/Web/API/AudioContext)\n */\n static prepareInstrument(options = {}, audioContext) {\n if (MidiAudioPlayer.loadingInstrument === false) {\n MidiAudioPlayer.loadingInstrument = true;\n MidiAudioPlayer.audioContext = audioContext;\n MidiPlayer.Soundfont.instrument(\n MidiAudioPlayer.audioContext,\n options.MIDISoundFontObject || MidiAudioPlayer.MIDISoundFontObject ||\n `${options.MIDISoundFontBase || MidiAudioPlayer.MIDISoundFontBase}/${options.MIDISoundFontName || MidiAudioPlayer.MIDISoundFontName}${options.MIDISoundFontExtension || MidiAudioPlayer.MIDISoundFontExtension}`)\n .then(instrument => {\n log('info', 'MIDI soundfont instrument loaded');\n MidiAudioPlayer.instrument = instrument;\n })\n .catch(err => {\n log('error', `Error loading soundfont base instrument: ${err}`);\n });\n }\n }\n\n /**\n * Pauses the player\n */\n pause() {\n if (this.player) {\n this.player.pause();\n this.startedNotes = [];\n }\n }\n\n /**\n * Starts or resumes playing\n */\n play() {\n if (this.player) {\n this.startedNotes = [];\n this.player.play();\n }\n }\n\n /**\n * Gets the ' paused' state of the current player\n * @returns boolean\n */\n get paused() {\n return this.player && !this.player.isPlaying();\n }\n\n /**\n * Checks if the current player has ended or is already playing\n * @returns boolean\n */\n get ended() {\n return this.player && this.player.getSongTimeRemaining() <= 0;\n }\n\n /**\n * Gets the current time\n * @returns number\n */\n get currentTime() {\n return this.player && (this.player.getSongTime() * 1000) || 0;\n }\n\n /**\n * Sets the current time of this player (in milliseconds)\n * @param {number} time - The time position where the player pointer must be placed\n */\n set currentTime(time) {\n if (this.player)\n this.player.skipToSeconds(time / 1000);\n }\n\n /**\n * Plays a MIDI event\n * @param {object} ev - The event data. See http://grimmdude.com/MidiPlayerJS/docs/index.html for details\n */\n playEvent(ev) {\n if (this.player && MidiAudioPlayer.instrument) {\n // Check for specific interval\n if (this.playTo > 0 && this.currentTime >= this.playTo)\n this.pause();\n // Set main volume\n else if (ev.name === 'Controller Change' && ev.number === 7)\n this.mainVolume = ev.value / 127;\n // Process 'Note on' messages. Max gain set to 2.0 for better results with the used soundfont\n else if (ev.name === 'Note on' && ev.velocity > 0)\n this.startedNotes[ev.noteNumber] = MidiAudioPlayer.instrument.play(ev.noteName, MidiAudioPlayer.audioContext.currentTime, { gain: 2 * (this.mainVolume * ev.velocity / 100) });\n // Process 'Note off' messages\n else if (ev.name === 'Note off' && ev.noteNumber && this.startedNotes[ev.noteNumber]) {\n this.startedNotes[ev.noteNumber].stop();\n delete (this.startedNotes[ev.noteNumber]);\n }\n }\n }\n}\n\nObject.assign(MidiAudioPlayer.prototype, {\n /**\n * The MIDI file data used by this MIDI player\n * @name module:media/MidiAudioPlayer.MidiAudioPlayer#data\n * @type {external:ArrayBuffer} */\n data: null,\n /**\n * The grimmdude's MidiPlayer used by this player\n * @name module:media/MidiAudioPlayer.MidiAudioPlayer#player\n * @type {external:MidiPlayerJS} */\n player: null,\n /**\n * When >0, time position at which the music must end\n * @name module:media/MidiAudioPlayer.MidiAudioPlayer#playTo\n * @type {number} */\n playTo: 0,\n /**\n * Main volume of this track (set with a MIDI message of type `Controller Change` #7)\n * @name module:media/MidiAudioPlayer.MidiAudioPlayer#mainVolume\n * @type {number} */\n mainVolume: 1.0,\n /**\n * This array is used when processing 'Note off' events to stop notes that are currently playing.\n * It contains a collection of 'instrument.play' instances, one for each active note\n * @name module:media/MidiAudioPlayer.MidiAudioPlayer#startedNotes\n * @type {function[]} */\n startedNotes: [],\n});\n\n/**\n * The {@link external:AudioContext} used by this MIDI player.\n * @type {external:AudioContext}\n */\nMidiAudioPlayer.audioContext = null;\n\n/**\n * The \"Instrument\" object used by this MIDI player.\n * See: https://github.com/danigb/soundfont-player\n * @type {external:Instrument}\n */\nMidiAudioPlayer.instrument = null;\n\n/**\n * A flag used to avoid re-entrant calls to {@link module:media/MidiAudioPlayer.MidiAudioPlayer#prepareInstrument prepareInstrument}\n * @type {boolean}\n */\nMidiAudioPlayer.loadingInstrument = false;\n\n/**\n * An object containing the full soundfont data used by {@link module:media/MidiAudioPlayer.MidiAudioPlayer#instrument instrument}\n * When this member is set, no other settings related to the sounfFont will be used.\n * This value can be overwritten by the global parameter `MIDISoundFontObject`\n * @type {object}\n */\nMidiAudioPlayer.MIDISoundFontObject = null;\n\n/**\n * The URL used as base for the current collection of MIDI soundfonts.\n * This value can be overwritten by the global parameter `MIDISoundFontBase`\n * @type {string}\n */\nMidiAudioPlayer.MIDISoundFontBase = 'https://clic.xtec.cat/dist/jclic.js/soundfonts/MusyngKite';\n// Alternative sites are:\n// 'https://clic.xtec.cat/dist/jclic.js/soundfonts/FluidR3_GM'\n// 'https://raw.githubusercontent.com/gleitz/midi-js-soundfonts/gh-pages/FluidR3_GM'\n// 'https://raw.githubusercontent.com/gleitz/midi-js-soundfonts/gh-pages/MusyngKite'\n\n/**\n * The MIDI instrument name.\n * This value can be overwritten by the global parameter `MIDISoundFontName`\n * See [MIDI.js Soundfonts](https://github.com/gleitz/midi-js-soundfonts) for full lists of MIDI instrument names.\n * @type {string}\n */\nMidiAudioPlayer.MIDISoundFontName = 'acoustic_grand_piano';\n\n/**\n * An extension to be added to `MIDISoundFontName` in order to build the full file name of the soundfont JS file.\n * Current valid options are `-mp3.js` and `-ogg.js`\n * This value can be overwritten by the global parameter `MIDISoundFontExtension`\n * @type {string}\n */\nMidiAudioPlayer.MIDISoundFontExtension = '-mp3.js';\n\nexport default MidiAudioPlayer;\n","/**\n * File : bags/MediaBagElement.js\n * Created : 07/04/2015\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\n/* global URL, Uint8Array, XMLHttpRequest, Image, document */\n\nimport $ from 'jquery';\nimport MidiAudioPlayer from '../media/MidiAudioPlayer.js';\nimport { log, settings, nSlash, getAttr, isEmpty, getPathPromise, parseXmlNode, appendStyleAtHead } from '../Utils.js';\nimport { Font } from '../AWT.js';\n\n/**\n * This kind of objects are the components of {@link module:bags/MediaBag.MediaBag MediaBag}.\n *\n * Media elements have a name, a reference to a file (the `file` field) and, when initialized,\n * a `data` field pointing to a object containing the real media. They have also a flag indicating\n * if the data must be saved on the {@link module:project/JClicProject.JClicProject JClicProject} zip file or just maintained as a reference\n * to an external file.\n */\nexport class MediaBagElement {\n /**\n * MediaBagElement constructor\n * @param {string} basePath - Path to be used as a prefix of the file name\n * @param {string} file - The media file name\n * @param {external:JSZip} [zip] - An optional JSZip object from which the file must be extracted.\n */\n constructor(basePath, file, zip) {\n if (basePath)\n this.basePath = basePath;\n if (file) {\n this.file = nSlash(file);\n this.name = nSlash(file);\n this.ext = this.file.toLowerCase().split('.').pop();\n this.type = this.getFileType(this.ext);\n if (this.ext === 'gif')\n this.checkAnimatedGif();\n }\n if (zip)\n this.zip = zip;\n this.timeout = Date.now() + settings.LOAD_TIMEOUT;\n }\n\n\n /**\n * Private static array of {@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLAudioElement HTMLAudioElements},\n * to be reused between all media elements of type 'audio'. One for each priority level\n * @name module:bags/MediaBagElement#_audioPlayers\n * @type {external:HTMLAudioElement[]}\n */\n static _audioPlayers = [];\n\n /**\n * Gets the static {@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLAudioElement HTMLAudioElement}\n * associated to the requested priority level.\n * @param {number} level=1 - The priority level\n * @returns {external:HTMLAudioElement}\n */\n static getAudioPlayer(level = 1) {\n if (!MediaBagElement._audioPlayers[level])\n MediaBagElement._audioPlayers[level] = document.createElement('audio');\n return MediaBagElement._audioPlayers[level];\n }\n\n /**\n * Private static array of {@link bags/MediaBagElement MediaBagElements},\n * used to store a reference to the element using each `audioPlayer`\n * @name module:bags/MediaBagElement#_currentAudioElements\n * @type {bags/MediaBagElement[]}\n */\n static _currentAudioElements = [];\n\n /**\n * Clear all references to audio players and audio elements\n * To be called when a new activity starts\n */\n static resetAudioElements() {\n MediaBagElement._audioPlayers.fill(null);\n MediaBagElement._currentAudioElements.fill(null);\n }\n\n /**\n * Loads this object settings from a specific JQuery XML element\n * @param {external:jQuery} $xml - The XML element to parse\n */\n setProperties($xml) {\n this.name = nSlash($xml.attr('name'));\n this.file = nSlash($xml.attr('file'));\n this.ext = this.file.toLowerCase().split('.').pop();\n this.type = this.getFileType(this.ext);\n // Check if it's an animated GIF\n if (this.ext === 'gif') {\n const anim = $xml.attr('animated');\n if (typeof anim === 'undefined')\n this.checkAnimatedGif();\n else\n this.animated = anim === 'true';\n }\n if (this.type === 'font') {\n this.fontName = this.name === this.file && this.name.lastIndexOf('.') > 0 ?\n this.name.substring(0, this.name.lastIndexOf('.')) :\n this.name;\n }\n return this;\n }\n\n /**\n * Gets a object with the basic attributes needed to rebuild this instance excluding functions,\n * parent references, constants and also attributes retaining the default value.\n * The resulting object is commonly usued to serialize elements in JSON format.\n * @returns {object} - The resulting object, with minimal attrributes\n */\n getAttributes() {\n return getAttr(this, ['name', 'file', 'animated']);\n }\n\n /**\n * Loads the element properties from a data object\n * @param {object} data - The data object to parse\n */\n setAttributes(data) {\n ['name', 'file', 'animated'].forEach(attr => {\n if (!isEmpty(data[attr]))\n this[attr] = data[attr];\n });\n\n this.ext = this.file.toLowerCase().split('.').pop();\n this.type = this.getFileType(this.ext);\n\n // Check if it's an animated GIF\n if (this.ext === 'gif' && this.animated === 'undefined')\n this.checkAnimatedGif();\n\n if (this.type === 'font') {\n this.fontName = this.name === this.file && this.name.lastIndexOf('.') > 0 ?\n this.name.substring(0, this.name.lastIndexOf('.')) :\n this.name;\n }\n return this;\n }\n\n /**\n * Checks if the image associated with this MediaBagElement is an animated GIF\n *\n * Based on: {@link https://gist.github.com/marckubischta/261ad8427a214022890b}\n * Thanks to `@lakenen` and `@marckubischta`\n */\n checkAnimatedGif() {\n const request = new XMLHttpRequest();\n // Set `responseType` moved after calling `open`\n // see: https://stackoverflow.com/questions/20760635/why-does-setting-xmlhttprequest-responsetype-before-calling-open-throw\n // request.responseType = 'arraybuffer'\n request.addEventListener('load', () => {\n const\n arr = new Uint8Array(request.response),\n length = arr.length;\n\n // make sure it's a gif (GIF8)\n if (arr[0] !== 0x47 || arr[1] !== 0x49 ||\n arr[2] !== 0x46 || arr[3] !== 0x38) {\n this.animated = false;\n return;\n }\n\n // Ported from PHP [http://www.php.net/manual/en/function.imagecreatefromgif.php#104473]\n // an animated gif contains multiple \"frames\", with each frame having a\n // header made up of:\n // * a static 3-byte sequence (\\x00\\x21\\xF9\n // * one byte indicating the length of the header (usually \\x04)\n // * variable length header (usually 4 bytes)\n // * a static 2-byte sequence (\\x00\\x2C) (some variants may use \\x00\\x21 ?)\n // We read through the file as long as we haven't reached the end of the file\n // and we haven't yet found at least 2 frame headers\n for (let i = 0, len = length - 3, frames = 0; i < len && frames < 2; ++i) {\n if (arr[i] === 0x00 && arr[i + 1] === 0x21 && arr[i + 2] === 0xF9) {\n const\n blocklength = arr[i + 3],\n afterblock = i + 4 + blocklength;\n if (afterblock + 1 < length &&\n arr[afterblock] === 0x00 &&\n (arr[afterblock + 1] === 0x2C || arr[afterblock + 1] === 0x21)) {\n if (++frames > 1) {\n this.animated = true;\n log('debug', `Animated GIF detected: ${this.file}`);\n break;\n }\n }\n }\n }\n });\n\n this.getFullPathPromise()\n .then(fullPath => {\n request.open('GET', fullPath, true);\n request.responseType = 'arraybuffer';\n request.send();\n });\n }\n\n /**\n * Checks if the MediaBagElement has been initiated\n * @returns {boolean}\n */\n isEmpty() {\n return this.data === null;\n }\n\n /**\n * Determines the type of a file from its extension\n * @param {string} ext - The file name extension\n * @returns {string}\n */\n getFileType(ext) {\n let result = null;\n for (let type in settings.FILE_TYPES) {\n if (settings.FILE_TYPES[type].indexOf(ext) >= 0) {\n result = type;\n break;\n }\n }\n return result;\n }\n\n /**\n * Instantiates the media content\n * @param {function} callback - Callback method called when the referred resource is ready\n * @param {module:JClicPlayer.JClicPlayer} ps=null - An optional `PlayStation` (currently a {@link module:JClicPlayer.JClicPlayer JClicPlayer}) used to dynamically load fonts\n * @param {boolean} force=false - Used only in media of type 'audio'. When `true`, a static {@link MediaBagElement._audioPlayers audioPlayer element} will be loaded with this media source\n * @param {number} level=1 - Priority level of the media content to be built. Used only n audio elements.\n */\n build(callback, ps = null, force = false, level = 1) {\n // Mock data when running in NodeJS\n if (settings.NODEJS) {\n this.data = [];\n this.ready = true;\n }\n\n if (callback) {\n if (!this._whenReady)\n this._whenReady = [];\n this._whenReady.push(callback);\n }\n\n if (!this.data)\n this.getFullPathPromise()\n .then(fullPath => {\n switch (this.type) {\n case 'font':\n const\n format = this.ext === 'ttf' ? 'truetype' : this.ext === 'otf' ? 'embedded-opentype' : this.ext,\n css = `@font-face{font-family:\"${this.fontName}\";src:url(${fullPath}) format(\"${format}\");}`;\n\n appendStyleAtHead(css, ps);\n this.data = new Font(this.name);\n this.ready = true;\n break;\n\n case 'image':\n this.data = new Image();\n this.data.addEventListener('load', () => { this._onReady.call(this); }, { once: true });\n this.data.src = fullPath;\n break;\n\n case 'video':\n this.data = document.createElement(this.type);\n this.data.addEventListener('canplay', () => { this._onReady.call(this); }, { once: true });\n this.data.src = fullPath;\n this.data.load();\n this.data.pause();\n break;\n\n case 'audio':\n // HTML Audio objects will be created on demand, when the param 'force' is set to true\n if (force) {\n // Clean up state in current audio element, if any\n const currentAudioElement = MediaBagElement._currentAudioElements[level];\n if (currentAudioElement && currentAudioElement !== this) {\n currentAudioElement.data = null;\n currentAudioElement.ready = false;\n }\n // Register as a current audio element\n MediaBagElement._currentAudioElements[level] = this;\n // Configure the audio player\n const audioPlayer = MediaBagElement.getAudioPlayer(level);\n if (audioPlayer.src !== fullPath) {\n log('trace', `Loading static player #${level} with new audio: ${fullPath}`);\n this.data = audioPlayer;\n this.ready = false;\n audioPlayer.addEventListener('canplay', () => { this._onReady.call(this); }, { once: true });\n audioPlayer.src = fullPath;\n audioPlayer.load();\n audioPlayer.pause();\n }\n else\n log('trace', `Reusing existing audio in player #${level}: ${fullPath}`);\n }\n else\n this.ready = true;\n break;\n\n case 'anim':\n // TODO: Use [Ruffle](https://ruffle.rs/) to play Flash movies\n this.data = $(`<object type\"application/x-shockwave-flash\" width=\"300\" height=\"200\" data=\"${fullPath}\"/>`).get(-1);\n // Unable to check the loading progress in elements of type `object`. so we mark it always as `ready`:\n this.ready = true;\n break;\n\n case 'xml':\n $.get(fullPath, null, null, 'xml').done(xmlData => {\n const children = xmlData ? xmlData.children || xmlData.childNodes : null;\n this.data = children && children.length > 0 ? parseXmlNode(children[0]) : null;\n this._onReady();\n }).fail(err => {\n log('error', `Error loading ${this.name}: ${err}`);\n this._onReady();\n });\n break;\n\n case 'midi':\n const request = new XMLHttpRequest();\n request.onreadystatechange = () => {\n if (request.readyState === 4) {\n if (request.status === 200)\n this.data = new MidiAudioPlayer(request.response, ps && ps.options);\n else\n log('error', `Error loading ${this.name}: ${request.statusText}`);\n this._onReady();\n }\n };\n request.open('GET', fullPath, true);\n request.responseType = 'arraybuffer';\n request.send();\n break;\n\n default:\n log('trace', `Media currently not supported: ${this.name}`);\n this.ready = true;\n }\n\n if (this.ready)\n this._onReady();\n });\n else if (this.ready)\n this._onReady();\n\n return this;\n }\n\n /**\n * Checks if this media element is ready to start\n * @returns {boolean} - `true` if ready, `false` otherwise\n */\n checkReady() {\n if (this.data && !this.ready) {\n switch (this.type) {\n case 'image':\n this.ready = this.data.complete === true;\n break;\n case 'audio':\n case 'video':\n case 'anim':\n this.ready = this.data.readyState >= 1;\n break;\n default:\n this.ready = true;\n }\n }\n return this.ready;\n }\n\n /**\n * Checks if this resource has timed out.\n * @returns {boolean} - `true` if the resource has exhausted the allowed time to load, `false` otherwise\n */\n checkTimeout() {\n const result = Date.now() > this.timeout;\n if (result)\n log('warn', `Timeout while loading: ${this.name}`);\n return result;\n }\n\n /**\n * Notify listeners that the resource is ready\n */\n _onReady() {\n this.ready = true;\n if (this._whenReady) {\n this._whenReady.forEach(fn => fn.call(this, this));\n this._whenReady = null;\n }\n }\n\n /**\n * Gets the full path of the file associated to this element.\n * WARNING: This function should be called only after a successful call to `getFullPathPromise`\n * @returns {string}\n */\n getFullPath() {\n return this._fullPath;\n }\n\n /**\n * Gets a promise with the full path of the file associated to this element.\n * @returns {external:Promise}\n */\n getFullPathPromise() {\n return getPathPromise(this.basePath, this.file, this.zip)\n .then(fullPath => {\n // Process full URL only when running in a browser\n this._fullPath = settings.NODEJS\n ? fullPath\n : (new URL(fullPath, document.location.href)).toString();\n return this._fullPath;\n });\n }\n}\n\nObject.assign(MediaBagElement.prototype, {\n /**\n * The name of this element. Usually is the same as `file`\n * @name module:bags/MediaBagElement.MediaBagElement#name\n * @type {string} */\n name: '',\n /**\n * The name of the file where this element is stored\n * @name module:bags/MediaBagElement.MediaBagElement#file\n * @type {string} */\n file: '',\n /**\n * The font family name, used only in elements of type 'font'\n * @name module:bags/MediaBagElement.MediaBagElement#fontName\n * @type {string} */\n fontName: '',\n /**\n * The path to be used as base to access this media element\n * @name module:bags/MediaBagElement.MediaBagElement#basePath\n * @type {string} */\n basePath: '',\n /**\n * An optional JSZip object that can act as a container of this media\n * @name module:bags/MediaBagElement.MediaBagElement#zip\n * @type {external:JSZip} */\n zip: null,\n /**\n * When loaded, this field will store the realized media object\n * @name module:bags/MediaBagElement.MediaBagElement#data\n * @type {object} */\n data: null,\n /**\n * Flag indicating that `data` is ready to be used\n * @name module:bags/MediaBagElement.MediaBagElement#ready\n * @type {boolean} */\n ready: false,\n /**\n * Array of callback methods to be called when the resource becomes ready\n * @name module:bags/MediaBagElement.MediaBagElement#_whenReady\n * @private\n * @type {function[]} */\n _whenReady: null,\n /**\n * Normalized extension of `file`, useful to guess the media type\n * @name module:bags/MediaBagElement.MediaBagElement#ext\n * @type {string} */\n ext: '',\n /**\n * The resource type ('audio', 'image', 'midi', 'video', 'font')\n * @name module:bags/MediaBagElement.MediaBagElement#type\n * @type {string} */\n type: null,\n /**\n * Time set to load the resource before leaving\n * @name module:bags/MediaBagElement.MediaBagElement#timeout\n * @type {number} */\n timeout: 0,\n //\n /**\n * Flag used for animated GIFs\n * @name module:bags/MediaBagElement.MediaBagElement#animated\n * @type {boolean} */\n animated: false,\n /**\n * Full path obtained after a successful call to getFullPathPromise\n * @name module:bags/MediaBagElement.MediaBagElement#_fullPath\n * @private\n * @type {string}\n */\n _fullPath: null,\n});\n\nexport default MediaBagElement;\n","/**\n * File : bags/MediaBag.js\n * Created : 07/04/2015\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\nimport $ from 'jquery';\nimport MediaBagElement from './MediaBagElement.js';\nimport Skin from '../skins/Skin.js';\nimport { log, nSlash } from '../Utils.js';\n\n/**\n * This class stores and manages all the media components (images, sounds, animations, video,\n * MIDI files, etc.) needed to run the activities of a {@link module:project/JClicProject.JClicProject JClicProject}. The main member of\n * the class is `elements`. This is where {@link module:bads/MediaBagElement.MediaBagElement} objects are stored.\n */\nexport class MediaBag {\n /**\n * MediaBag constructor\n * @param {module:project/JClicProject.JClicProject} project - The JClic project to which this media bag belongs\n */\n constructor(project) {\n this.project = project;\n this.elements = {};\n }\n\n /**\n * Loads this object settings from a specific JQuery XML element\n * @param {external:jQuery} $xml - The XML element to parse\n */\n setProperties($xml) {\n $xml.children('media').each((_n, child) => {\n const mbe = new MediaBagElement(this.project.basePath, null, this.project.zip);\n mbe.setProperties($(child));\n this.elements[mbe.name] = mbe;\n });\n return this;\n }\n\n /**\n * Gets a object with the basic attributes needed to rebuild this instance excluding functions,\n * parent references, constants and also attributes retaining the default value.\n * The resulting object is commonly usued to serialize elements in JSON format.\n * @returns {object} - The resulting object, with minimal attrributes\n */\n getAttributes() {\n return Object.keys(this.elements).map(k => this.elements[k].getAttributes());\n }\n\n /**\n * Loads the MediaBag content from a data object\n * @param {object} data - The data object to parse\n */\n setAttributes(data) {\n if (data && data.length)\n data.forEach(el => {\n const mbe = new MediaBagElement(this.project.basePath, null, this.project.zip);\n mbe.setAttributes(el);\n this.elements[mbe.name] = mbe;\n });\n return this;\n }\n\n /**\n * Finds a {@link module:bads/MediaBagElement.MediaBagElement} by its name, creating a new one if not found and requested.\n * @param {string} name - The name of the element\n * @param {boolean} [create] - When `true`, a new MediaBagElement will be created if not found,\n * using 'name' as its file name.\n * @returns {module:bags/MediaBagElement.MediaBagElement}\n */\n getElement(name, create) {\n name = nSlash(name);\n let result = this.elements[name];\n if (create && !result)\n result = this.getElementByFileName(name, create);\n return result;\n }\n\n /**\n * Gets a {@link module:bads/MediaBagElement.MediaBagElement} by its file name.\n * @param {string} file - The requested file name\n * @param {boolean} [create] - When `true`, a new {@link module:bads/MediaBagElement.MediaBagElement} will be created if not\n * found.\n * @returns {module:bags/MediaBagElement.MediaBagElement}\n */\n getElementByFileName(file, create) {\n let result = null;\n if (file) {\n file = nSlash(file);\n for (let name in this.elements) {\n if (this.elements[name].file === file) {\n result = this.elements[name];\n break;\n }\n }\n if (!result && create) {\n result = new MediaBagElement(this.project.basePath, null, this.project.zip);\n result.name = file;\n result.file = file;\n result.ext = file.toLowerCase().split('#')[0].split('.').pop();\n result.type = result.getFileType(result.ext);\n this.elements[result.name] = result;\n }\n }\n return result;\n }\n\n /**\n * Get the names of the media elements that are of the given type.\n * When the search type is `font`, the `fontName` property is used instead of `name`\n * @param {string} type - The type of elements to search\n * @returns {string[]}\n */\n getElementsOfType(type) {\n const result = [];\n $.each(this.elements, (name, element) => {\n if (element.type === type)\n result.push(type === 'font' ? element.fontName : name);\n });\n return result;\n }\n\n /**\n * Preloads all resources.\n *\n * __Use with care!__ Calling this method will start loading all the resources defined in the\n * MediaBag, whether used or not in the current activity.\n * @param {string} type - The type of media to be build. When `null` or `undefined`, all\n * resources will be build.\n * @param {function} [callback] - Function to be called when each element is ready.\n * @param {module:JClicPlayer.JClicPlayer} [ps] - An optional `PlayStation` (currently a {@link module:JClicPlayer.JClicPlayer JClicPlayer}) used to dynamically load fonts\n * @returns {number} - The total number of elements that will be built\n */\n buildAll(type, callback, ps) {\n let count = 0;\n $.each(this.elements, (name, element) => {\n if (!type || element.type === type) {\n element.build(callback, ps, false);\n count++;\n }\n });\n return count;\n }\n\n /**\n * Checks if there are media waiting to be loaded\n * @returns {number} - The amount of media elements already loaded, or -1 if all elements are ready\n */\n countWaitingElements() {\n let\n ready = 0,\n allReady = true;\n\n // Only for debug purposes: return always 'false'\n // TODO: Check loading process!\n $.each(this.elements, (name, element) => {\n if (element.data && !element.ready && !element.checkReady() && !element.checkTimeout()) {\n log('debug', '... waiting for: %s', name);\n allReady = false;\n } else\n ready++;\n });\n return allReady ? -1 : ready;\n }\n\n /**\n * Loads a {@link module:skins/Skin.Skin Skin} object\n * @param {string} name - The skin name to be loaded\n * @param {string} ps - The {@link module:JClicPlayer.JClicPlayer JClicPlayer} linked to the skin\n * @returns {module:skins/Skin.Skin}\n */\n getSkinElement(name, ps) {\n return Skin.getSkin(name, ps);\n }\n}\n\nObject.assign(MediaBag.prototype, {\n /**\n * The collection of {@link module:bads/MediaBagElement.MediaBagElement} objects\n * @name module:bags/MediaBag.MediaBag#elements\n * @type {object} */\n elements: null,\n /**\n * The JClic project to which this MediaBag belongs\n * @name module:bags/MediaBag.MediaBag#project\n * @type {module:project/JClicProject.JClicProject} */\n project: null,\n});\n\nexport default MediaBag;\n","/**\n * File : project/JClicProject.js\n * Created : 01/04/2015\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\nimport $ from 'jquery';\nimport ProjectSettings from './ProjectSettings.js';\nimport ActivitySequence from '../bags/ActivitySequence.js';\nimport MediaBag from '../bags/MediaBag.js';\nimport Activity from '../Activity.js';\nimport { getBasePath, nSlash, getAttr, settings } from '../Utils.js';\nimport { Font } from '../AWT.js';\n\n/**\n * JClicProject contains all the components of a JClic project: activities, sequences, media\n * files, descriptors and metadata.\n *\n * This encapsulation is achieved by three auxiliary objects:\n * - {@link module:project/ProjectSettings.ProjectSettings ProjectSettings}: stores metadata like full title, description, authors, languages,\n * educational topics...\n * - {@link module:bags/ActivitySequence.ActivitySequence ActivitySequence}: defines the order in which the activities must be shown.\n * - {@link module:bags/MediaBag.MediaBag MediaBag}: contains the list of all media files used by the activities\n */\nexport class JClicProject {\n /**\n * JClicProject constructor\n */\n constructor() {\n this.settings = new ProjectSettings(this);\n this.activitySequence = new ActivitySequence(this);\n this._activities = {};\n this.mediaBag = new MediaBag(this);\n }\n\n /**\n * Loads the project settings from a main jQuery XML element\n * @param {external:jQuery} $xml - The XML element\n * @param {string} path - The full path of this project\n * @param {external:JSZip} [zip] - An optional JSZip object where this project is encapsulated\n * @param {object} [options] - An object with miscellaneous options\n * @returns {module:project/JClicProject.JClicProject}\n */\n setProperties($xml, path, zip, options) {\n if (path) {\n this.path = path;\n if (path.file)\n this.basePath = path;\n else\n this.basePath = getBasePath(path);\n }\n this.zip = zip;\n this.name = $xml.attr('name');\n this.version = $xml.attr('version');\n if ($xml.attr('type') !== undefined && $xml.attr('type') !== '')\n this.type = $xml.attr('type');\n if ($xml.attr('code') !== undefined && $xml.attr('code') !== '')\n this.code = $xml.attr('code');\n this.settings.setProperties($xml.children('settings'));\n this.activitySequence.setProperties($xml.children('sequence'));\n this.mediaBag.setProperties($xml.children('mediaBag'));\n this.reportableActs = 0;\n this._activities = {};\n const $node = $xml.children('activities');\n const $acts = $node.children('activity');\n const ownFonts = this.mediaBag.getElementsOfType('font');\n if (ownFonts.length > 0)\n options.ownFonts = (options.ownFonts || []).concat(ownFonts);\n // Skip checkTree when in NodeJS, due to a JSDOM error with jQuery in XML mode\n if (!settings.NODEJS)\n Font.checkTree($acts, options);\n $acts.each((_n, act) => {\n const $act = $(act);\n this._activities[nSlash($act.attr('name'))] = $act;\n if ($act.children('settings').attr('report') === 'true')\n this.reportableActs++;\n });\n return this;\n }\n\n /**\n * Gets a object with the basic attributes needed to rebuild this instance excluding functions,\n * parent references, constants and also attributes retaining the default value.\n * The resulting object is commonly usued to serialize elements in JSON format.\n * @returns {object} - The resulting object, with minimal attrributes\n */\n getAttributes() {\n const keys = Object.keys(this._activities);\n this.activities = {};\n keys.forEach(k => {\n const act = this._activities[k];\n this.activities[k] = act.jquery ? Activity.getActivity(act, this) : act;\n });\n\n return getAttr(this, ['name', 'version', 'type', 'code', 'settings', 'activitySequence', 'activities', 'mediaBag']);\n }\n\n /**\n * Gets a JSON string representing the content of this project. This string can be transformed later into a data\n * object suitable for `setAttributes`.\n * @param {number} [space] - The number of white spaces to place between items. Defaults to zero (meaning all the JSON rendered in one single line)\n * @returns {string} - The JSON text\n */\n getJSON(space = 0) {\n return JSON.stringify(\n this.getAttributes(),\n (_key, val) => val.toFixed ? Number(val.toFixed(4)) : val,\n space\n );\n }\n\n /**\n * Loads the project settings from a data object\n * @param {object} data - The data object\n * @param {string} path - The full path of this project\n * @param {external:JSZip} [zip] - An optional JSZip object where this project is encapsulated\n * @param {object} [options] - An object with miscellaneous options\n * @returns {module:project/JClicProject.JClicProject}\n */\n setAttributes(data, path, zip, options) {\n if (path) {\n this.path = path;\n if (path.file)\n this.basePath = path;\n else\n this.basePath = getBasePath(path);\n }\n this.zip = zip;\n this.name = data.name;\n this.version = data.version;\n if (data.type)\n this.type = data.type;\n if (data.code)\n this.code = data.code;\n this.settings.setAttributes(data.settings);\n this.activitySequence.setAttributes(data.activitySequence);\n this.mediaBag.setAttributes(data.mediaBag);\n this.reportableActs = 0;\n this._activities = data.activities;\n\n const ownFonts = this.mediaBag.getElementsOfType('font');\n if (ownFonts.length > 0)\n options.ownFonts = (options.ownFonts || []).concat(ownFonts);\n // TODO: Check fonts\n Font.checkTree(this._activities, options);\n this.reportableActs = Object.keys(this._activities)\n .filter(k => this._activities[k].includeInReports)\n .length;\n return this;\n }\n\n /**\n * Finds activities by name and builds the corresponding {@link module:Activity.Activity Activity} object.\n * @param {string} name - The name of the requested activity\n * @returns {module:Activity.Activity}\n */\n getActivity(name) {\n return Activity.getActivity(this._activities[nSlash(name)], this);\n }\n\n /**\n *\n * Builds the {@link module:skins/Skin.Skin Skin}, {@link module:media/EventSounds.EventSounds EventSounds} and {@link module:bags/MediaBag.MediaBag MediaBag} fonts associated to this project.\n * @param {module:JClicPlayer.JClicPlayer} ps - The PlayStation (usually a {@link module:JClicPlayer.JClicPlayer JClicPlayer}) linked to this project.\n */\n realize(ps) {\n // Build skin\n if (this.skin === null && this.settings.skinFileName !== null && this.settings.skinFileName.length > 0)\n this.skin = this.mediaBag.getSkinElement(this.settings.skinFileName, ps);\n\n this.settings.eventSounds.realize(ps, this.mediaBag);\n\n // Build all elements of type `font`\n this.mediaBag.buildAll('font', null, ps);\n }\n\n /**\n * Run finalizers on realized objects\n */\n end() {\n // TODO: Implement JClicProject.end()\n }\n}\n\nObject.assign(JClicProject.prototype, {\n /**\n * The project's name\n * @name module:project/JClicProject.JClicProject#name\n * @type {string} */\n name: 'unknown',\n /**\n * The version of the XML file format used to save the project (currently 0.1.3)\n * @name module:project/JClicProject.JClicProject#version\n * @type {string} */\n version: '0.1.3',\n /**\n * Optional property that can be used by reporting systems\n * @name module:project/JClicProject.JClicProject#type\n * @type {string} */\n type: null,\n /**\n * Optional property that can be used by reporting systems\n * @name module:project/JClicProject.JClicProject#code\n * @type {string} */\n code: null,\n /**\n * Object containing the project settings\n * @name module:project/JClicProject.JClicProject#settings\n * @type {module:project/ProjectSettings.ProjectSettings} */\n settings: null,\n /**\n * Object containing the order in which the activities should be played\n * @name module:project/JClicProject.JClicProject#activitySequence\n * @type {module:bags/ActivitySequence.ActivitySequence} */\n activitySequence: null,\n /**\n * Array of jQuery xml elements containing the data of each activity. Don't rely on this object\n * to retrieve real activities. Use the method {@link module:project/JClicProject.JClicProject#getActivity getActivity} instead.\n * @name module:project/JClicProject.JClicProject#_activities\n * @private\n * @type {external:jQuery[]} */\n _activities: null,\n /**\n * Number of activities suitable to be included reports\n * @name module:project/JClicProject.JClicProject#reportableActs\n * @type {number}\n */\n reportableActs: 0,\n /**\n * The collection of all media elements used in this project\n * @name module:project/JClicProject.JClicProject#mediaBag\n * @type {module:bags/MediaBag.MediaBag} */\n mediaBag: null,\n /**\n * The object that builds and manages the visual interface presented to users\n * @name module:project/JClicProject.JClicProject#skin\n * @type {module:skins/Skin.Skin} */\n skin: null,\n /**\n * Relative path or absolute URL to be used as a base to access files, usually in conjunction\n * with {@link module:JClicPlayer.JClicPlayer#basePath}\n * @name module:project/JClicProject.JClicProject#basePath\n * @type {string} */\n basePath: '',\n /**\n * Full path of this project\n * @name module:project/JClicProject.JClicProject#path\n * @type {string} */\n path: null,\n /**\n * The JSZip object where this project is stored (can be `null`)\n * @name module:project/JClicProject.JClicProject#zip\n * @type {external:JSZip} */\n zip: null,\n});\n\nexport default JClicProject;\n","/**\n * File : report/ActionReg.js\n * Created : 17/05/2016\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\nimport $ from 'jquery';\nimport { attrForEach, getBoolean } from '../Utils.js';\n\n/**\n * This class stores information about one specific action done by the current user while playing\n * an activity.\n *\n */\nexport class ActionReg {\n /**\n * ActionReg constructor\n * @param {string} type - Type of action (`click`, `write`, `move`, `select`...)\n * @param {string}+ source - Description of the object on which the action is done.\n * @param {string}+ dest - Description of the object that acts as a target of the action (used in pairings)\n * @param {boolean} ok - `true` if the action was OK, `false`, `null` or `undefined` otherwise\n */\n constructor(type, source, dest, ok) {\n this.type = type;\n this.source = source || null;\n this.dest = dest || null;\n this.ok = ok || false;\n this.time = (new Date()).valueOf();\n }\n\n /**\n * Provides the data associated with this action in XML format suitable for a\n * {@link http://clic.xtec.cat/en/jclic/reports/|JClic Reports Server}.\n * @returns {external:jQuery}\n */\n $getXML() {\n const attr = { ok: this.ok, time: this.time };\n if (this.type)\n attr.type = this.type;\n if (this.source)\n attr.source = this.source;\n if (this.dest)\n attr.dest = this.dest;\n return $('<action/>', attr);\n }\n\n /**\n * Fills this ActionReg with data provided in XML format\n * @param {external:jQuery} $xml - The XML element to be processed, already wrapped as jQuery object\n */\n setProperties($xml) {\n attrForEach($xml.get(0).attributes, (name, value) => {\n switch (name) {\n case 'type':\n case 'source':\n case 'dest':\n this[name] = value;\n break;\n case 'time':\n this[name] = Number(value);\n break;\n case 'ok':\n this[name] = getBoolean(value, false);\n break;\n }\n });\n }\n}\n\nObject.assign(ActionReg.prototype, {\n /**\n * The type of action (`click`, `write`, `move`, `select`...)\n * @name module:report/ActionReg.ActionReg#type\n * @type {string} */\n type: 'unknown',\n /**\n * Description of the object on which the action was done\n * @name module:report/ActionReg.ActionReg#source\n * @type {string} */\n source: null,\n /**\n * Description of the object that has acted as a target of the action (used in pairings)\n * @name module:report/ActionReg.ActionReg#dest\n * @type {string} */\n dest: null,\n /**\n * Time stamp taken when the action was done\n * @name module:report/ActionReg.ActionReg#time\n * @type {number} */\n time: 0,\n /**\n * `true` if the action was OK\n * @name module:report/ActionReg.ActionReg#isOk\n * @type {boolean} */\n isOk: false,\n});\n\nexport default ActionReg;\n","/**\n * File : report/ActivityReg.js\n * Created : 17/05/2016\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\nimport $ from 'jquery';\nimport { attrForEach, getBoolean } from '../Utils.js';\nimport ActionReg from './ActionReg.js';\n\n/**\n * This class stores miscellaneous data obtained by the current user playing an {@link module:Activity.Activity Activity}.\n */\nexport class ActivityReg {\n /**\n * ActivityReg constructor\n * @param {module:Activity.Activity} act - The {@link module:Activity.Activity Activity} referenced by this object.\n */\n constructor(act) {\n this.name = act.name;\n this.code = act.code;\n this.actions = [];\n this.startTime = (new Date()).valueOf();\n this.minActions = act.getMinNumActions();\n this.reportActions = act.reportActions;\n }\n\n /**\n * Provides the data associated with the current activity in an XML format suitable for a\n * {@link http://clic.xtec.cat/en/jclic/reports/|JClic Reports Server}.\n * @returns {external:jQuery}\n */\n $getXML() {\n const attr = {\n start: this.startTime,\n time: this.totalTime,\n solved: this.solved,\n score: this.score,\n minActions: this.minActions,\n actions: this.numActions\n };\n if (this.name)\n attr.name = this.name;\n if (this.code)\n attr.code = this.code;\n if (!this.closed)\n attr.closed = false;\n if (this.reportActions)\n attr.reportActions = true;\n\n const $result = $('<activity/>', attr);\n this.actions.forEach(ac => {\n $result.append(ac.$getXML());\n });\n return $result;\n }\n\n /**\n * Builds an object with relevant data about the results obtained by the current student in this activity\n * @returns {object} - The results of this activity\n */\n getData() {\n const result = {\n name: this.name,\n time: Math.round(this.totalTime / 10) / 100,\n solved: this.solved,\n score: this.score,\n minActions: this.minActions,\n actions: this.numActions,\n precision: this.getPrecision(),\n closed: this.closed\n };\n if (this.code)\n result.code = this.code;\n return result;\n }\n\n /**\n * Fills this ActivityReg with data provided in XML format\n * @param {external:jQuery} $xml -The XML element to be processed, already wrapped as jQuery object\n */\n setProperties($xml) {\n attrForEach($xml.get(0).attributes, (name, value) => {\n switch (name) {\n case 'name':\n case 'code':\n this[name] = value;\n break;\n case 'start':\n case 'time':\n case 'score':\n case 'minActions':\n case 'actions':\n this[name] = Number(value);\n break;\n case 'solved':\n case 'closed':\n case 'reportActions':\n this[name] = getBoolean(value, false);\n break;\n }\n });\n $xml.children('action').each((_n, child) => {\n const action = new ActionReg();\n action.setProperties($(child));\n this.actions.push(action);\n });\n }\n\n /**\n * Reports a new action done by the user while playing the current activity\n * @param {string} type - Type of action (`click`, `write`, `move`, `select`...)\n * @param {string}+ source - Description of the object on which the action is done.\n * @param {string}+ dest - Description of the object that acts as a target of the action (used in pairings)\n * @param {boolean} ok - `true` if the action was OK, `false`, `null` or `undefined` otherwise\n */\n newAction(type, source, dest, ok) {\n if (!this.closed) {\n this.lastAction = new ActionReg(type, source, dest, ok);\n this.actions.push(this.lastAction);\n }\n }\n\n /**\n * Retrieves a specific {@link module:report/ActionReg.ActionReg ActionReg} element from `actions`\n * @param {number} index - The nth action to be retrieved\n * @returns {module:report/ActionReg.ActionReg}\n */\n getActionReg(index) {\n return index >= this.actions.length ? null : this.actions[index];\n }\n\n /**\n * Closes the current activity, adjusting total time if needed\n */\n closeActivity() {\n if (!this.closed) {\n if (this.lastAction)\n this.totalTime = this.lastAction.time - this.startTime;\n else\n this.totalTime = (new Date()).valueOf() - this.startTime;\n this.closed = true;\n }\n }\n\n /**\n * calculates the final score obtained by the user in this activity.\n * The algorithm used takes in account the minimal number of actions needed, the actions\n * really done by the user, and if the activity was finally solved or not.\n * @returns {number}\n */\n getPrecision() {\n let result = 0;\n if (this.closed && this.minActions > 0 && this.numActions > 0) {\n if (this.solved) {\n if (this.numActions < this.minActions)\n result = 100;\n else\n result = Math.round(this.minActions * 100 / this.numActions);\n } else\n result = Math.round(100 * (this.score * this.score) / (this.minActions * this.numActions));\n }\n return result;\n }\n\n /**\n * This method should be called when the current activity finishes. Data about user's final results\n * on the activity will then be saved.\n * @param {number} score - The final score, usually in a 0-100 scale.\n * @param {number} numActions - The total number of actions done by the user to solve the activity\n * @param {boolean} solved - `true` if the activity was finally solved, `false` otherwise.\n */\n endActivity(score, numActions, solved) {\n if (!this.closed) {\n this.solved = solved;\n this.numActions = numActions;\n this.score = score;\n this.closeActivity();\n }\n }\n}\n\nObject.assign(ActivityReg.prototype, {\n /**\n * Name of the associated activity\n * @name module:report/ActivityReg.ActivityReg#name\n * @type {string} */\n name: '',\n /**\n * Optional code assigned to this activity, used for later filtering\n * @name module:report/ActivityReg.ActivityReg#code\n * @type {string} */\n code: '',\n /**\n * Timestamp when the user starts playing the activity\n * @name module:report/ActivityReg.ActivityReg#startTime\n * @type {number} */\n startTime: 0,\n /**\n * Total time spent by the user in the activity, measured in milliseconds\n * @name module:report/ActivityReg.ActivityReg#totalTime\n * @type {number} */\n totalTime: 0,\n /**\n * Collection of actions done by the user while playing the activity\n * @name module:report/ActivityReg.ActivityReg#actions\n * @type {module:report/ActionReg.ActionReg[]} */\n actions: [],\n /**\n * `true` only when the user has finished and solved the activity\n * @name module:report/ActivityReg.ActivityReg#solved\n * @type {boolean} */\n solved: false,\n /**\n * Last {@link module:report/ActionReg.ActionReg ActionReg} performed by the user in this activity\n * @name module:report/ActivityReg.ActivityReg#lastAction\n * @type {module:report/ActionReg.ActionReg} */\n lastAction: null,\n /**\n * Final score obtained by the current user in this activity\n * @name module:report/ActivityReg.ActivityReg#score\n * @type {number} */\n score: 0,\n /**\n * Minimum number of actions needed to solve the activity\n * @name module:report/ActivityReg.ActivityReg#minActions\n * @type {number} */\n minActions: 0,\n /**\n * `true` when the activity has finished, `false` for the activity that is currently playing\n * @name module:report/ActivityReg.ActivityReg#closed\n * @type {boolean} */\n closed: false,\n /**\n * `true` when this type of activity should record specific actions done by the users\n * @name module:report/ActivityReg.ActivityReg#reportActions\n * @type {boolean} */\n reportActions: false,\n /**\n * Number of actions done by the user playing this activity\n * @name module:report/ActivityReg.ActivityReg#numActions\n * @type {number} */\n numActions: 0,\n});\n\nexport default ActivityReg;\n","/**\n * File : report/SequenceReg.js\n * Created : 17/05/2016\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\nimport ActivityReg from './ActivityReg.js';\n\n/**\n * This class stores the results of the activities related to an {@link module:bags/ActivitySequenceElement.ActivitySequenceElement ActivitySequenceElement}.\n * It's main component is an array of {@link module:report/ActivityReg.ActivityReg ActivityReg} elements.\n */\nexport class SequenceReg {\n /**\n * SequenceReg constructor\n * @param {module:bags/ActivitySequenceElement.ActivitySequenceElement} ase - The {@link module:bags/ActivitySequenceElement.ActivitySequenceElement ActivitySequenceElement} related to this sequence.\n */\n constructor(ase) {\n this.name = ase.tag;\n this.description = ase.description;\n this.activities = [];\n this.currentActivity = null;\n this.totalTime = 0;\n this.closed = false;\n this.info = new SequenceRegInfo(this);\n }\n\n /**\n * Builds a complex object with data about the results of the activities done in this sequence\n * @returns {object} - The sequence results\n */\n getData() {\n const result = {\n sequence: this.name,\n activities: []\n };\n this.activities.forEach(act => result.activities.push(act.getData()));\n return result;\n }\n\n /**\n * Returns the `info` element associated to this SequenceReg.\n * @returns {module:report/SequenceReg.SequenceRegInfo}\n */\n getInfo() {\n return this.info.recalc();\n }\n\n /**\n * This method should be called when the current working session finishes.\n */\n endSequence() {\n if (this.currentActivity && this.activities.length > 0) {\n if (!this.currentActivity.closed)\n this.currentActivity.closeActivity();\n this.totalTime = this.currentActivity.startTime + this.currentActivity.totalTime - this.activities[0].startTime;\n this.info.valid = false;\n }\n }\n\n /**\n * This method should be invoked when the user starts a new activity\n * @param {module:Activity.Activity} act - The {@link module:Activity.Activity Activity} that has just started\n */\n newActivity(act) {\n if (!this.closed) {\n this.currentActivity = new ActivityReg(act);\n this.activities.push(this.currentActivity);\n this.info.valid = false;\n }\n }\n\n /**\n * This method should be called when the current activity finishes. Data about user's final results\n * on the activity will then be saved.\n * @param {number} score - The final score, usually in a 0-100 scale.\n * @param {number} numActions - The total number of actions done by the user to solve the activity\n * @param {boolean} solved - `true` if the activity was finally solved, `false` otherwise.\n */\n endActivity(score, numActions, solved) {\n if (this.currentActivity) {\n this.currentActivity.endActivity(score, numActions, solved);\n this.info.valid = false;\n }\n }\n\n /**\n * Reports a new action done by the user while playing the current activity\n * @param {string} type - Type of action (`click`, `write`, `move`, `select`...)\n * @param {string}+ source - Description of the object on which the action is done.\n * @param {string}+ dest - Description of the object that acts as a target of the action (used in pairings)\n * @param {boolean} ok - `true` if the action was OK, `false`, `null` or `undefined` otherwise\n */\n newAction(type, source, dest, ok) {\n if (this.currentActivity) {\n this.currentActivity.newAction(type, source, dest, ok);\n this.info.valid = false;\n }\n }\n}\n\nObject.assign(SequenceReg.prototype, {\n /**\n * The `tag` member of the associated {@link module:bags/ActivitySequenceElement.ActivitySequenceElement ActivitySequenceElement}\n * @name module:report/SequenceReg.SequenceReg#name\n * @type {string} */\n name: '',\n /**\n * Optional description given to the {@link module:bags/ActivitySequenceElement.ActivitySequenceElement ActivitySequenceElement}\n * @name module:report/SequenceReg.SequenceReg#description\n * @type {string} */\n description: '',\n /**\n * Collection of all the {@link module:report/ActivityReg.ActivityReg ActivityReg} elements done during this sequence.\n * @name module:report/SequenceReg.SequenceReg#activities\n * @type {module:report/ActivityReg.ActivityReg[]} */\n activities: [],\n /**\n * Registry linked to the {@link module:Activity.Activity Activity} that is currently running\n * @name module:report/SequenceReg.SequenceReg#currentActivity\n * @type {module:report/ActivityReg.ActivityReg} */\n currentActivity: null,\n /**\n * Total time spent on the activities of this sequence\n * @name module:report/SequenceReg.SequenceReg#totalTime\n * @type {number} */\n totalTime: 0,\n /**\n * Flag indicating if the sequence is closed or already available for more activities\n * @name module:report/SequenceReg.SequenceReg#closed\n * @type {boolean} */\n closed: false,\n /**\n * Object with global information associated to this sequence\n * @name module:report/SequenceReg.SequenceReg#info\n * @type {module:report/SequenceReg.SequenceRegInfo} */\n info: null,\n});\n\n/**\n * This object stores the global results of a {@link module:report/SequenceReg.SequenceReg SequenceReg}\n */\nexport class SequenceRegInfo {\n /**\n * SequenceRegInfo constructor\n * @param {module:report/SequenceReg.SequenceReg} sqReg - The {@link module:report/SequenceReg.SequenceReg SequenceReg} associated tho this `Info` object.\n */\n constructor(sqReg) {\n this.sqReg = sqReg;\n }\n\n /**\n * Clears all global data associated with this sequence\n */\n clear() {\n this.nActivities = this.nActClosed = this.nActSolved = this.nActScore = 0;\n this.ratioSolved = this.nActions = this.tScore = this.tTime = 0;\n this.valid = false;\n }\n\n /**\n * Computes the value of all global variables based on the data stored in `activities`\n * @returns {module:report/SequenceReg.SequenceRegInfo} - This \"info\" object\n */\n recalc() {\n if (!this.valid) {\n this.clear();\n this.nActivities = this.sqReg.activities.length;\n if (this.nActivities > 0) {\n this.sqReg.activities.forEach(ar => {\n if (ar.closed) {\n this.nActClosed++;\n this.tTime += ar.totalTime;\n this.nActions += ar.numActions;\n if (ar.solved)\n this.nActSolved++;\n const r = ar.getPrecision();\n if (r >= 0) {\n this.tScore += r;\n this.nActScore++;\n }\n }\n });\n if (this.nActClosed > 0)\n this.ratioSolved = this.nActSolved / this.nActClosed;\n if (this.nActScore > 0)\n this.tScore = Math.round(this.tScore / this.nActScore);\n }\n this.valid = true;\n }\n return this;\n }\n}\n\nObject.assign(SequenceRegInfo.prototype, {\n /**\n * The {@link module:report/SequenceReg.SequenceReg SequenceReg} associated to this \"info\" object\n * @name module:report/SequenceReg.SequenceRegInfo#sqReg\n * @type {module:report/SequenceReg.SequenceReg} */\n sqReg: null,\n /**\n * When `false`, data must be recalculated\n * @name module:report/SequenceReg.SequenceRegInfo#valid\n * @type {boolean} */\n valid: false,\n /**\n * Number of activities played in this sequence\n * @name module:report/SequenceReg.SequenceRegInfo#nActivities\n * @type {number} */\n nActivities: 0,\n /**\n * Number of activities already closed\n * @name module:report/SequenceReg.SequenceRegInfo#nActClosed\n * @type {number} */\n nActClosed: 0,\n /**\n * Number of activities solved\n * @name module:report/SequenceReg.SequenceRegInfo#nActSolved\n * @type {number} */\n nActSolved: 0,\n /**\n * Number of activities with score > 0\n * @name module:report/SequenceReg.SequenceRegInfo#nActScore\n * @type {number} */\n nActScore: 0,\n /**\n * Percentage of solved activities\n * @name module:report/SequenceReg.SequenceRegInfo#ratioSolved\n * @type {number} */\n ratioSolved: 0,\n /**\n * Number of actions done by the user while in this sequence\n * @name module:report/SequenceReg.SequenceRegInfo#nActions\n * @type {number} */\n nActions: 0,\n /**\n * Sum of the scores of all the activities played\n * @name module:report/SequenceReg.SequenceRegInfo#tScore\n * @type {number} */\n tScore: 0,\n /**\n * Sum of the playing time reported by each activity (not always equals to the sequence's total time)\n * @name module:report/SequenceReg.SequenceRegInfo#tTime\n * @type {number} */\n tTime: 0,\n});\n\nSequenceReg.Info = SequenceRegInfo;\n\nexport default SequenceReg;\n","/**\n * File : report/SessionReg.js\n * Created : 17/05/2016\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Catalan Educational Telematic Network (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\nimport SequenceReg from './SequenceReg.js';\n\n/**\n * This class encapsulates data of a user's working session, usually associated to a single {@link module:project/JClicProject.JClicProject JClicProject}\n * It's main component is `sequences`, an array of {@link module:report/SequenceReg.SequenceReg SequenceReg} objects.\n */\nexport class SessionReg {\n /**\n * SessionReg constructor\n * @param {module:project/JClicProject.JClicProject} project - The JClicProject referenced by this session.\n * @param {string} [code] - Optional code to be used by this SessionReg\n */\n constructor(project, code) {\n this.projectName = project.name;\n this.code = code || project.code;\n this.sequences = [];\n this.actNames = [];\n this.started = new Date();\n this.info = new SessionRegInfo(this);\n this.reportableActs = project.reportableActs;\n }\n\n /**\n * Builds a complex object with the results of all activities done during this working session\n * @param {boolean} recalcInfo - When `true`, global variables (number of sequences, score, total time...)\n * will be recalculated from the data stored in the {@link module:report/SequenceReg.SequenceReg SequenceReg} objects.\n * @param {boolean} includeEmpty - When `true`, sequences without reported activities will be also included in the results\n * @returns {object} - An object containing the full session data\n */\n getData(recalcInfo, includeEmpty) {\n if (recalcInfo)\n this.info.recalc();\n\n const result = {\n projectName: this.projectName,\n played: this.info.nActivities,\n ratioPlayed: Math.round(this.info.ratioPlayed * 100),\n solved: this.info.nActSolved,\n ratioSolved: Math.round(this.info.ratioSolved * 100),\n actions: this.info.nActions,\n score: this.info.tScore,\n time: Math.round(this.info.tTime / 10) / 100,\n sequences: []\n };\n\n this.sequences.forEach(s => {\n const seq = s.getData();\n if (includeEmpty || seq.activities.length > 0)\n result.sequences.push(seq);\n });\n return result;\n }\n\n /**\n * Returns the `info` element associated to this SessionReg.\n * @returns {module:report/SessionReg.SessionRegInfo}\n */\n getInfo() {\n return this.info.recalc();\n }\n\n /**\n * Closes this session\n */\n end() {\n this.endSequence();\n }\n\n /**\n * This method should be called when the current working session finishes.\n */\n endSequence() {\n if (this.currentSequence && this.currentSequence.totalTime === 0)\n this.currentSequence.endSequence();\n this.currentSequence = null;\n this.info.valid = false;\n }\n\n /**\n * This method should be invoked when a new sequence starts\n * @param {module:bags/ActivitySequenceElement.ActivitySequenceElement} ase - The {@link module:bags/ActivitySequenceElement.ActivitySequenceElement ActivitySequenceElement} referenced by this sequence.\n */\n newSequence(ase) {\n this.endSequence();\n this.currentSequence = new SequenceReg(ase);\n this.sequences.push(this.currentSequence);\n this.info.valid = false;\n }\n\n /**\n * This method should be invoked when the user starts a new activity\n * @param {module:Activity.Activity} act - The {@link module:Activity.Activity Activity} that has just started\n */\n newActivity(act) {\n if (this.currentSequence) {\n // Save activity name if not yet registered\n if (this.actNames.indexOf(act.name) === -1)\n this.actNames.push(act.name);\n this.currentSequence.newActivity(act);\n this.info.valid = false;\n }\n }\n\n /**\n * This method should be called when the current activity finishes. Data about user's final results\n * on the activity will then be saved.\n * @param {number} score - The final score, usually in a 0-100 scale.\n * @param {number} numActions - The total number of actions done by the user to solve the activity\n * @param {boolean} solved - `true` if the activity was finally solved, `false` otherwise.\n */\n endActivity(score, numActions, solved) {\n if (this.currentSequence) {\n this.currentSequence.endActivity(score, numActions, solved);\n this.info.valid = false;\n }\n }\n\n /**\n * Reports a new action done by the user while playing the current activity\n * @param {string} type - Type of action (`click`, `write`, `move`, `select`...)\n * @param {string}+ source - Description of the object on which the action is done.\n * @param {string}+ dest - Description of the object that acts as a target of the action (used in pairings)\n * @param {boolean} ok - `true` if the action was OK, `false`, `null` or `undefined` otherwise\n */\n newAction(type, source, dest, ok) {\n if (this.currentSequence) {\n this.currentSequence.newAction(type, source, dest, ok);\n this.info.valid = false;\n }\n }\n\n /**\n * Gets the name of the current sequence\n * @returns {string}\n */\n getCurrentSequenceTag() {\n return this.currentSequence ? this.currentSequence.name : null;\n }\n\n /**\n * Gets information about the current sequence\n * @returns {module:report/SequenceReg.SequenceRegInfo}\n */\n getCurrentSequenceInfo() {\n return this.currentSequence ? this.currentSequence.getInfo() : null;\n }\n}\n\nObject.assign(SessionReg.prototype, {\n /**\n * Number of activities suitable to be reported in this session\n * @name module:report/SessionReg.SessionReg#reportableActs\n * @type {number} */\n reportableActs: 0,\n /**\n * Array with unique names of the activities being reported in this session\n * @name module:report/SessionReg.SessionReg#actNames\n * @type {string[]} */\n actNames: null,\n /**\n * List of sequences done in this session\n * @name module:report/SessionReg.SessionReg#sequences\n * @type {module:report/SequenceReg.SequenceReg[]} */\n sequences: null,\n /**\n * The sequence currently active\n * @name module:report/SessionReg.SessionReg#currentSequence\n * @type {module:report/SequenceReg.SequenceReg} */\n currentSequence: null,\n /**\n * Starting date and time of this session\n * @name module:report/SessionReg.SessionReg#started\n * @type {external:Date} */\n started: null,\n /**\n * Name of the {@link module:project/JClicProject.JClicProject JClicProject} associated to this session\n * @name module:report/SessionReg.SessionReg#projectName\n * @type {string} */\n projectName: '',\n /**\n * Current session info\n * @name module:report/SessionReg.SessionReg#info\n * @type {module:report/SessionReg.SessionRegInfo} */\n info: null,\n /**\n * Optional code to be used with this session\n * @name module:report/SessionReg.SessionReg#code\n * @type {string} */\n code: null,\n});\n\n/**\n * This object stores the global results of a {@link module:report/SessionReg.SessionReg SessionReg}\n */\nexport class SessionRegInfo {\n /**\n * SessionRegInfo constructor\n * @param {module:report/SessionReg.SessionReg} sReg - The {@link module:report/SessionReg.SessionReg SessionReg} associated tho this `Info` object.\n */\n constructor(sReg) {\n this.sReg = sReg;\n }\n\n /**\n * Clears all data associated with this working session\n */\n clear() {\n this.numSequences = this.nActivities = this.nActSolved = this.nActScore = 0;\n this.ratioSolved = this.ratioPlayed = this.nActions = this.tScore = this.tTime = 0;\n this.valid = false;\n }\n\n /**\n * Computes the value of all global variables based on the data stored in `sequences`\n * @returns {module:report/SessionReg.SessionRegInfo} - This \"info\" object\n */\n recalc() {\n if (!this.valid) {\n this.clear();\n this.sReg.sequences.forEach(sr => {\n const sri = sr.getInfo();\n if (sri.nActivities > 0) {\n this.numSequences++;\n if (sri.nActClosed > 0) {\n this.nActivities += sri.nActClosed;\n this.nActions += sri.nActions;\n if (sri.nActScore > 0) {\n this.nActScore += sri.nActScore;\n this.tScore += sri.tScore * sri.nActScore;\n }\n this.tTime += sri.tTime;\n this.nActSolved += sri.nActSolved;\n }\n }\n });\n if (this.nActScore > 0)\n this.tScore = Math.round(this.tScore / this.nActScore);\n if (this.nActivities > 0) {\n this.ratioSolved = this.nActSolved / this.nActivities;\n if (this.sReg.reportableActs > 0)\n this.ratioPlayed = this.sReg.actNames.length / this.sReg.reportableActs;\n }\n this.valid = true;\n }\n return this;\n }\n}\n\nObject.assign(SessionRegInfo.prototype, {\n /**\n * The SessionReg linked to this Info object\n * @name module:report/SessionReg.SessionRegInfo#sReg\n * @type {module:report/SessionReg.SessionReg} */\n sReg: null,\n /**\n * When `false`, this session info needs to be recalculated\n * @name module:report/SessionReg.SessionRegInfo#valid\n * @type {boolean} */\n valid: false,\n /**\n * Number of sequences played\n * @name module:report/SessionReg.SessionRegInfo#numSequences\n * @type {number} */\n numSequences: 0,\n /**\n * Number of activities played\n * @name module:report/SessionReg.SessionRegInfo#nActivities\n * @type {number} */\n nActivities: 0,\n /**\n * Number of activities solved\n * @name module:report/SessionReg.SessionRegInfo#nActSolved\n * @type {number} */\n nActSolved: 0,\n /**\n * Number of activities with score > 0\n * @name module:report/SessionReg.SessionRegInfo#nActScore\n * @type {number} */\n nActScore: 0,\n /**\n * Percentage of solved activities\n * @name module:report/SessionReg.SessionRegInfo#ratioSolved\n * @type {number} */\n ratioSolved: 0,\n /**\n * Percentage of reportable activities played\n * @name module:report/SessionReg.SessionRegInfo#ratioPlayed\n * @type {number} */\n ratioPlayed: 0,\n /**\n * Number of actions done by the user while in this working session\n * @name module:report/SessionReg.SessionRegInfo#nActions\n * @type {number} */\n nActions: 0,\n /**\n * Sum of the scores of all the activities played\n * @name module:report/SessionReg.SessionRegInfo#tScore\n * @type {number} */\n tScore: 0,\n /**\n * Sum of the playing time reported by each activity (not always equals to the session's total time)\n * @name module:report/SessionReg.SessionRegInfo#tTime\n * @type {number} */\n tTime: 0,\n});\n\nSessionReg.Info = SessionRegInfo;\n\nexport default SessionReg;\n","/**\n * File : report/Encryption.js\n * Created : 18/06/2015\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\n/**\n *\n * Utilities to encrypt and decrypt strings using simple methods, just to avoid write\n * passwords in plain text in data and configuration files. Do not use it as a\n * secure cryptographic system!\n *\n * Based on {@link https://github.com/projectestac/jclic/blob/master/src/utilities/edu/xtec/util/Encryption.java Encryption}\n * utilities, created by Albert Llastarri for {@link https://github.com/projectestac/jclic JClic}.\n *\n * IMPORTANT: This is a shortened version of Encryption with only the methods needed to decrypt\n * stored passwords. Full version is on file `src/misc/encryption/Encryption.js`\n *\n * @abstract\n */\nexport class Encryption {\n /**\n * Decrypts the given code\n * @param {string} txt - Code to be decrypted\n * @returns {string}\n */\n static Decrypt(txt) {\n if (txt === null || txt.length === 0)\n return null;\n const s = Encryption.decodify(txt);\n return s === Encryption.BLANK ? '' : s;\n }\n\n /**\n * @param {string} cA (was char[])\n * @param {number} fromIndex\n * @returns {string} (was char)\n */\n static hexCharArrayToChar(cA, fromIndex) {\n let n = 0;\n for (let i = 0; i <= 3; i++) {\n const j = Number.parseInt(cA[fromIndex + i], 16);\n if (isNaN(j))\n throw 'Invalid expression!';\n else\n n = n * 16 + j;\n }\n return String.fromCharCode(n);\n }\n\n /**\n * @param {string} cA - (was char[])\n * @param {number} fromIndex\n * @returns {number}\n */\n static hexCharArrayToInt(cA, fromIndex) {\n let n = 0;\n for (let i = 0; i <= 1; i++) {\n const j = Number.parseInt(cA[fromIndex + i], 16);\n if (isNaN(j))\n throw 'Invalid expression!';\n else\n n = n * 16 + j;\n }\n return n;\n }\n\n /**\n * @param {string} cA - (was char[])\n * @returns {string}\n */\n static decodifyZerosField(cA) {\n let\n sb = '',\n num = Number.parseInt(cA[0], 32),\n k = 0,\n i = 0;\n\n for (i = 0; num !== 0; i++) {\n while (num > 0) {\n sb = sb + cA[i * 3 + 1] + cA[i * 3 + 2];\n num--;\n k++;\n }\n if (cA.length > i * 3 + 3)\n num = Number.parseInt(cA[i * 3 + 3], 32);\n else\n num = 0;\n }\n for (let j = i * 3 + 1; j < cA.length; j++)\n sb = sb + cA[j];\n\n return Number.parseInt(k, 32) + sb;\n }\n\n /**\n * @param {string} cA - (was char[])\n * @returns {string} (was StringBuilder)\n */\n static decompressZeros(cA) {\n cA = Encryption.decodifyZerosField(cA);\n let\n numBytesZeros = Number.parseInt(cA[0], 32),\n iniNoZeros = numBytesZeros * 2 + 1,\n bFi = false,\n sb = '';\n\n for (let i = 0; i < numBytesZeros && !bFi; i++) {\n const zeros = Encryption.hexCharArrayToInt(cA, 1 + i * 2);\n let s = zeros.toString(2);\n while (s.length < 8)\n s = '0' + s;\n for (let j = 0; j <= 7 && !bFi; j++) {\n if (s[j] === '1')\n sb = sb + '0';\n else if (iniNoZeros < cA.length)\n sb = sb + cA[iniNoZeros++];\n else\n bFi = true;\n }\n }\n return sb;\n }\n\n /**\n * @param {string} sb1 - (was StringBuilder)\n * @returns {string}\n */\n static decodifyFromHex(sb1) {\n let sb = '', j = 0;\n for (let i = 0; j < sb1.length; i++) {\n const c = Encryption.hexCharArrayToChar(sb1, j);\n sb = sb + c;\n j += 4;\n }\n return sb;\n }\n\n /**\n * @param {string} s\n * @returns {string} (was char[])\n */\n static unchangeOrder(s) {\n let m = 0, n = s.length - 1;\n const cA = [];\n for (let p = 0; p < s.length; p++)\n cA[p] = '';\n for (let i = 0; i < s.length; i++)\n if (i % 2 === 0)\n cA[i] = s[m++];\n else\n cA[i] = s[n--];\n return cA.join('');\n }\n\n /**\n * @param {string} word\n * @returns {string}\n */\n static codify(word) {\n if (word.length > 24)\n throw 'Password is too large!';\n return Encryption.changeOrder(Encryption.compressZeros(Encryption.codifyToHexWord(word)));\n }\n\n /**\n * @param {string} word\n * @returns {string}\n */\n static decodify(word) {\n try {\n return Encryption.decodifyFromHex(Encryption.decompressZeros(Encryption.unchangeOrder(word)));\n } catch (_ex) { //The supplied word was not codified using this system\n return '';\n }\n }\n}\n\n/**\n* Default bank password\n* @type {string}\n*/\nEncryption.BLANK = '___blank___##';\n\nexport default Encryption;\n","/**\n * File : report/SCORM.js\n * Created : 18/07/2016\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\n/* global window */\n\nimport $ from 'jquery';\nimport { log } from '../Utils.js';\n\n/**\n * This class detects if JClic.js is running in an SCORM environment and, if true,\n * exposes the methods needed to notify the results of activities.\n * Both SCORM 1.2 and 2004 are supported.\n */\nexport class SCORM {\n /**\n * SCORM constructor\n * @param {object} API - The global SCORM API object\n * @param {module:report/Reporter.Reporter} reporter - The {@link module:Reporter.Reporter Reporter} associated to this SCORM object\n */\n constructor(API, reporter) {\n this.API = API;\n // Check if 'API' has a function named 'Initialized'\n if (typeof API.Initialize === 'function')\n this.is2004 = true;\n else {\n // SCORM 1.2\n this.prefix = 'LMS';\n this.core = 'cmi.core.';\n }\n this.reporter = reporter;\n }\n\n /**\n * Recursive function used to find the SCORM \"API\" object\n * @param {object} win - The 'window' object to scan for global SCORM API objects\n * @param {number} tries - Recursive attempts currently achieved\n * @returns {object} - The global SCORM API object, or `null` if not found\n */\n static scanForAPI(win, tries) {\n if (win.API_1484_11 && win.API_1184_11.Initialize && win.API_1184_11.SetValue && win.API_1184_11.Commit)\n return win.API_1184_11;\n else if (win.API && win.API.LMSInitialize && win.API.LMSSetValue && win.API.LMSCommit)\n return win.API;\n else if (win.parent && win.parent !== win && tries++ < SCORM.DISCOVER_MAX_TRIES)\n return SCORM.scanForAPI(win.parent, tries);\n else\n return null;\n }\n\n /**\n * Checks for the presence of a SCORM API on the current browser session.\n * @param {module:report/Reporter.Reporter} reporter - The {@link module:Reporter.Reporter Reporter} linked to the requested SCORM object\n * @returns {module:report/SCORM.SCORM} - A valid SCORM object, or `null` if no SCORM API was found.\n */\n static getSCORM(reporter) {\n let result = null;\n try {\n let api = SCORM.scanForAPI(window, 0);\n if (api === null && window.opener)\n api = SCORM.scanForAPI(window.opener, 0);\n\n if (api) {\n result = new SCORM(api, reporter);\n if (!result.initialize())\n result = null;\n }\n } catch (ex) {\n result = null;\n log('warn', 'Unable to use SCORM: %s', ex.toString());\n }\n return result;\n }\n\n /**\n * Initializes communication with the SCORM API\n * @returns {boolean}\n */\n initialize() {\n let result = false;\n try {\n result = this.API[this.prefix + 'Initialize']('');\n if (result) {\n this.studentId = this.getValue(this.core + (this.is2004 ? 'learner_id' : 'student_id'));\n this.studentName = this.getValue(this.core + (this.is2004 ? 'learner_name' : 'student_name'));\n this.setValue(this.core + 'score.min', 0);\n this.setValue(this.core + 'score.max', 100);\n $(window).on('unload', () => {\n this.commitInfo();\n this.terminate();\n this.API = null;\n });\n }\n log('debug', 'SCORM initialized');\n } catch (ex) {\n log('error', `Error initializing SCORM API: ${ex.message}`);\n }\n return result;\n }\n\n /**\n * Terminates communication with the SCORM API\n * @returns {boolean}\n */\n terminate() {\n let result = false;\n try {\n result = this.API[this.is2004 ? 'Terminate' : 'LMSFinish']('');\n } catch (ex) {\n log('error', `Error terminating SCORM API: ${ex.message}`);\n }\n return result;\n }\n\n /**\n * Commits the current information to the SCORM API\n */\n commitInfo() {\n const\n info = this.reporter.getInfo(),\n score = Math.round(info.globalScore * 100),\n time = this.getTimeExpression(info.tTime);\n\n this.setValue(this.core + 'score.raw', score);\n this.setValue(this.core + 'session_time', time);\n this.commit();\n log('debug', `SCORM results reported: ${score} (${time})`);\n }\n\n /**\n * Commits current pending data to the SCORM API\n * @returns {boolean}\n */\n commit() {\n let result = false;\n try {\n result = this.API[this.prefix + 'Commit']('');\n } catch (ex) {\n log('error', `Error commiting data to the SCORM API: ${ex.message}`);\n }\n return result;\n }\n\n /**\n * Sends a specific value to the SCORM API\n * @param {string} key - A SCORM valid key\n * @param {string|number} value - The value associated with this key\n * @returns {string}\n */\n setValue(key, value) {\n let result = false;\n try {\n result = this.API[this.prefix + 'SetValue'](key, value);\n } catch (ex) {\n log('error', `Error setting value \"${value}\" to \"${key}\" in SCORM API: ${ex.message}`);\n }\n return result;\n }\n\n /**\n * Gets a specific value from the SCORM API\n * @param {string} key - A SCORM valid key\n * @returns {string} - The value associated with the provided key, or `null` if not found\n */\n getValue(key) {\n let result = false;\n try {\n result = this.API[this.prefix + 'GetValue'](key);\n } catch (ex) {\n log('error', `Error retrieving \"${key}\" from SCORM API: ${ex.message}`);\n }\n return result;\n }\n\n /**\n * Gets a string expression of the given time (in milliseconds) suitable for a SCORM transaction.\n * @see {@link http://www.ostyn.com/standards/scorm/samples/ISOTimeForSCORM.htm}\n * @param {number} millis - The amount of time, in milliseconds\n * @returns {string} - An ISO8601 valid expression\n */\n getTimeExpression(millis) {\n const\n d = new Date(millis),\n h = d.getUTCHours(),\n m = d.getUTCMinutes(),\n s = d.getUTCSeconds();\n\n return this.is2004 ?\n `PT${h}H${m}M${s}S` :\n `${('0000' + h).slice(-4)}:${('00' + m).slice(-2)}:${('00' + s).slice(-2)}`;\n }\n\n /**\n * Gets the SCORM type of this SCORM object\n * @returns {string}\n */\n getScormType() {\n return `SCORM ${this.is2004 ? '2004' : '1.2'}`;\n }\n}\n\nObject.assign(SCORM.prototype, {\n /**\n * True when the API is of type SCORM 2004, false for SCORM 1.2\n * @name module:report/SCORM.SCORM#is2004\n * @type {boolean} */\n is2004: false,\n /**\n * The Reporter associated to this SCORM object\n * @name module:report/SCORM.SCORM#reporter\n * @type {module:report/Reporter.Reporter} */\n reporter: null,\n /**\n * Prefix to be used in SCORM function names. Should be 'LMS' for SCORM 1.2\n * @name module:report/SCORM.SCORM#prefix\n * @type {string} */\n prefix: '',\n /**\n * Prefix used in core SCORM keys. Should be 'cmi.core.' for 1.2 and 'cmi.' for 2004\n * @name module:report/SCORM.SCORM#core\n * @type {string} */\n core: 'cmi.',\n /**\n * SCORM API object used to communicate with the LMS\n * @name module:report/SCORM.SCORM#API\n * @type {object} */\n API: null,\n /**\n * The student ID retrieved from the SCORM API\n * @name module:report/SCORM.SCORM#studentId\n * @type {string} */\n studentId: '',\n /**\n * The student name retrieved from the SCORM API\n * @name module:report/SCORM.SCORM#studentName\n * @type {string} */\n studentName: '',\n});\n\n/**\n * Maximum recursive attempts allowed to find the global SCORM API object\n * @type {number} */\nSCORM.DISCOVER_MAX_TRIES = 50;\n\nexport default SCORM;\n","/**\n * File : report/Reporter.js\n * Created : 17/05/2016\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\n/* global Promise, window */\n\nimport $ from 'jquery';\nimport SessionReg from './SessionReg.js';\nimport Encryption from './EncryptMin.js';\nimport Scorm from './SCORM.js';\nimport { log, getMsg, getVal } from '../Utils.js';\n\n/**\n * This class implements the basic operations related with the processing of times and scores\n * done by users playing JClic activities. These operations include: identification of users,\n * compilation of data coming from the activities, storage of this data for later use, and\n * presentation of summarized results.\n */\nexport class Reporter {\n /**\n * Reporter constructor\n * @param {module:JClicPlayer.JClicPlayer} ps - The {@link module:JClicPlayer.JClicPlayer JClicPlayer} used to retrieve localized messages\n */\n constructor(ps) {\n this.ps = ps;\n this.sessions = [];\n this.started = new Date();\n this.initiated = false;\n this.info = new ReporterInfo(this);\n }\n\n /**\n * Registers a new type of reporter\n * @param {string} reporterName - The name used to identify this reporter\n * @param {function} reporterClass - The reporter class, usually extending Reporter\n * @returns {module:report/Reporter.Reporter} - The provided reporter class\n */\n static registerClass(reporterName, reporterClass) {\n Reporter.CLASSES[reporterName] = reporterClass;\n return reporterClass;\n }\n\n /**\n * Creates a new Reporter of the requested class\n * The resulting object must be prepared to operate with a call to its `init` method.\n * @param {string} className - Class name of the requested reporter. When `null`, a basic Reporter is created.\n * @param {module:JClicPlayer.JClicPlayer} ps - The {@link module:JClicPlayer.JClicPlayer JClicPlayer} used to retrieve localized messages\n * @returns {module:report/Reporter.Reporter}\n */\n static getReporter(className, ps) {\n let result = null;\n if (className === null) {\n className = 'Reporter';\n if (ps.options.hasOwnProperty('reporter'))\n className = ps.options.reporter;\n }\n if (Reporter.CLASSES.hasOwnProperty(className))\n result = new Reporter.CLASSES[className](ps);\n else\n log('error', 'Unknown reporter class: %s', className);\n\n return result;\n }\n\n /**\n * Returns the `info` element associated to this Reporter.\n * @returns {module:report/Reporter.ReporterInfo}\n */\n getInfo() {\n return this.info.recalc();\n }\n\n /**\n * Gets a specific property from this reporting system\n * @param {string} key - Requested property\n * @param {string}+ defaultValue - Default return value when requested property does not exist\n * @returns {string}\n */\n getProperty(key, defaultValue) {\n return defaultValue;\n }\n\n /**\n * Gets a specific boolean property from this reporting system\n * @param {string} key - Requested property\n * @param {boolean}+ defaultValue - Default return when requested property does not exist\n * @returns {boolean}\n */\n getBooleanProperty(key, defaultValue) {\n const s = this.getProperty(key, defaultValue === true ? 'true' : 'false');\n return key === null ? defaultValue : s === 'true' ? true : false;\n }\n\n /**\n * Gets the list of groups or organizations currently registered in the system. This\n * method should be implemented by classes derived of `Reporter`.\n * @returns {external:Promise} - When fulfilled, an array of group data is returned as a result\n */\n getGroups() {\n return Promise.reject('No groups defined!');\n }\n\n /**\n * Gets the list of users currently registered in the system, optionally filtered by\n * a specific group ID. This method should be implemented by classes derived of `Reporter`.\n * @param {string}+ groupId - Optional group ID to be used as a filter criteria\n * @returns {external:Promise} - When fulfilled, an object with a collection of user data records\n * is returned\n */\n getUsers(groupId) {\n return Promise.reject('No users defined in ' + groupId);\n }\n\n /**\n * Gets extended data associated with a specific user. This is a method intended to be\n * implemented in subclasses.\n * @param {string} _userId - The requested user ID\n * @returns {external:Promise} - When fulfilled, an object with user data is returned.\n */\n getUserData(_userId) {\n return Promise.reject('Unknown user!');\n }\n\n /**\n * Gets extended data associated with a specific group or organization. This\n * is a method intended to be implemented in subclasses.\n * @param {string} _groupId - The requested group ID\n * @returns {external:Promise} - When fulfilled, an object with group data is returned.\n */\n getGroupData(_groupId) {\n return Promise.reject('Unknown group!');\n }\n\n /**\n * Checks if this reporting system manages its own database of users and groups. Defaults to `false`\n * @returns {boolean}\n */\n userBased() {\n if (this.bUserBased === null)\n this.bUserBased = this.getBooleanProperty('USER_TABLES', false);\n return this.bUserBased;\n }\n\n /**\n * Allows the current user to create a new group, and asks his name\n * @returns {external:Promise} - When fulfilled, the chosen name for the new group is returned.\n */\n promptForNewGroup() {\n // TODO: Implement promptForNewGroup\n return Promise.reject('Remote creation of groups not yet implemented!');\n }\n\n /**\n * Allows the current user to create a new user ID, and asks his ID and password\n * @returns {external:Promise} - When fulfilled, an object with the new user ID and password\n * is returned.\n */\n promptForNewUser() {\n // TODO: Implement promptForNewUser\n return Promise.reject('Remote creation of users not yet implemented!');\n }\n\n /**\n * Allows the current user to select its group or organization from the current groups list\n * @returns {external:Promise}\n */\n promptGroupId() {\n return new Promise((resolve, reject) => {\n if (!this.userBased())\n reject('This system does not manage users!');\n else {\n this.getGroups().then((groupList) => {\n // Creation of new groups not yet implemented!\n if (!groupList || groupList.length < 1)\n reject('No groups defined!');\n else {\n let sel = 0;\n const $groupSelect = $('<select/>').attr({ size: Math.max(3, Math.min(15, groupList.length)) });\n groupList.forEach(g => $groupSelect.append($('<option/>').attr({ value: g.id }).text(g.name)));\n $groupSelect.change(ev => { sel = ev.target.selectedIndex; });\n this.ps.skin.showDlg(true, {\n main: [\n $('<h2/>', { class: 'subtitle' }).html(getMsg('Select group:')),\n $groupSelect],\n bottom: [\n this.ps.skin.$okDlgBtn,\n this.ps.skin.$cancelDlgBtn]\n }).then(() => {\n resolve(groupList[sel].id);\n }).catch(reject);\n }\n }).catch(reject);\n }\n });\n }\n\n /**\n * Asks for a valid user ID fulfilling the promise if found, rejecting it otherwise\n * @param {boolean}+ forcePrompt - Prompt also if `userId` is already defined (default is `false`)\n * @returns {external:Promise}\n */\n promptUserId(forcePrompt) {\n return new Promise((resolve, reject) => {\n if (this.userId !== null && !forcePrompt)\n resolve(this.userId);\n else if (!this.userBased())\n reject('This system does not manage users!');\n else {\n const $pwdInput = $('<input/>', { type: 'password', size: 8, maxlength: 64 });\n if (this.getBooleanProperty('SHOW_USER_LIST', true)) {\n this.promptGroupId().then(groupId => {\n this.getUsers(groupId).then(userList => {\n // Creation of new users not yet implemented\n // let userCreationAllowed = this.getBooleanProperty('ALLOW_CREATE_USERS', false)\n if (!userList || userList.length < 1)\n reject('Group ' + groupId + ' has no users!');\n else {\n let sel = -1;\n const $userSelect = $('<select/>').attr({ size: Math.max(3, Math.min(15, userList.length)) });\n userList.forEach(u => $userSelect.append($('<option/>').attr({ value: u.id }).text(u.name)));\n $userSelect.change(ev => { sel = ev.target.selectedIndex; });\n this.ps.skin.showDlg(true, {\n main: [\n $('<h2/>', { class: 'subtitle' }).html(getMsg('Select user:')),\n $userSelect,\n $('<h2/>', { class: 'subtitle' }).html(getMsg('Password:')).append($pwdInput)],\n bottom: [\n this.ps.skin.$okDlgBtn,\n this.ps.skin.$cancelDlgBtn]\n }).then(() => {\n if (sel >= 0) {\n if (userList[sel].pwd && Encryption.Decrypt(userList[sel].pwd) !== $pwdInput.val()) {\n window.alert(getMsg('Incorrect password'));\n reject('Incorrect password');\n } else {\n this.userId = userList[sel].id;\n resolve(this.userId);\n }\n } else\n reject('No user has been selected');\n }).catch(reject);\n }\n }).catch(reject);\n }).catch(reject);\n } else {\n const $userInput = $('<input/>', { type: 'text', size: 8, maxlength: 64 });\n this.ps.skin.showDlg(true, {\n main: [\n $('<div/>').css({ 'text-align': 'right' })\n .append($('<h2/>', { class: 'subtitle' }).html(getMsg('User:'))\n .append($userInput))\n .append($('<h2/>', { class: 'subtitle' }).html(getMsg('Password:'))\n .append($pwdInput))],\n bottom: [\n this.ps.skin.$okDlgBtn,\n this.ps.skin.$cancelDlgBtn]\n }).then(() => {\n this.getUserData($userInput.val()).then(user => {\n if (user.pwd && Encryption.Decrypt(user.pwd) !== $pwdInput.val()) {\n window.alert(getMsg('Incorrect password'));\n reject('Incorrect password');\n } else {\n this.userId = user.id;\n resolve(this.userId);\n }\n }).catch(reject);\n }).catch(reject);\n }\n }\n });\n }\n\n /**\n * Builds a complex object containing all the results reported while playing activities\n * @returns {object} - The current results\n */\n getData() {\n\n // Force the re-calculation of all scores\n this.info.recalc();\n\n const result = {\n started: this.started.toISOString(),\n descriptionKey: this.descriptionKey,\n descriptionDetail: this.descriptionDetail,\n projects: this.info.numSessions,\n sequences: this.info.numSequences,\n activitiesDone: this.info.nActivities,\n playedOnce: this.info.nActPlayed,\n reportable: this.info.reportableActs,\n ratioPlayed: Math.round(this.info.ratioPlayed * 100),\n activitiesSolved: this.info.nActSolved,\n ratioSolved: Math.round(this.info.ratioSolved * 100),\n actScore: this.info.nActScore,\n partialScore: Math.round(this.info.partialScore * 100),\n globalScore: Math.round(this.info.globalScore * 100),\n time: Math.round(this.info.tTime / 10) / 100,\n actions: this.info.nActions,\n sessions: []\n };\n\n if (this.userId)\n result.userId = this.userId;\n else if (this.SCORM)\n result.user = this.SCORM.studentName + (this.SCORM.studentId === '' ? '' : ` (${this.SCORM.studentId})`);\n\n this.sessions.forEach(sr => {\n if (sr.getInfo().numSequences > 0)\n result.sessions.push(sr.getData(false, false));\n });\n\n return result;\n }\n\n /**\n * Initializes this report system with an optional set of parameters.\n * Returns a Promise, fulfilled when the reporter is fully initialized.\n * @param {object} [options] - Initial settings passed to the reporting system\n * @returns {external:Promise}\n */\n init(options) {\n if (!options)\n options = this.ps.options;\n this.userId = getVal(options.user);\n this.sessionKey = getVal(options.key);\n this.sessionContext = getVal(options.context);\n this.groupCodeFilter = getVal(options.groupCodeFilter);\n this.userCodeFilter = getVal(options.userCodeFilter);\n if (options.SCORM !== false) {\n this.SCORM = Scorm.getSCORM(this);\n if (this.SCORM !== null && this.descriptionKey === Reporter.prototype.descriptionKey)\n this.descriptionKey = this.SCORM.getScormType();\n }\n this.initiated = true;\n log('debug', 'Basic Reporter initialized');\n return Promise.resolve(true);\n }\n\n /**\n * Closes this reporting system\n * @returns {external:Promise} - A Promise object to be fullfilled when all pending tasks are finished.\n */\n end() {\n log('debug', 'Basic Reporter ending');\n this.endSession();\n return Promise.resolve(true);\n }\n\n /**\n * Finalizes the current sequence\n */\n endSequence() {\n if (this.currentSession) {\n this.currentSession.endSequence();\n this.info.valid = false;\n }\n }\n\n /**\n * Finalizes the current session\n */\n endSession() {\n this.endSequence();\n this.currentSession = null;\n }\n\n /**\n * Creates a new group (method to be implemented in subclasses)\n * @param {object} _gd\n */\n newGroup(_gd) {\n throw \"No database!\";\n }\n\n /**\n * Creates a new user (method to be implemented in subclasses)\n * @param {object} _ud\n */\n newUser(_ud) {\n throw \"No database!\";\n }\n\n /**\n * This method should be invoked when a new session starts.\n * @param {module:project/JClicProject.JClicProject} jcp - The {@link module:project/JClicProject.JClicProject JClicProject} this session refers to.\n */\n newSession(jcp) {\n this.endSession();\n this.currentSession = new SessionReg(jcp);\n this.sessions.push(this.currentSession);\n this.info.valid = false;\n }\n\n /**\n * This method should be invoked when a new sequence starts\n * @param {module:bags/ActivitySequenceElement.ActivitySequenceElement} ase - The {@link module:bags/ActivitySequenceElement.ActivitySequenceElement ActivitySequenceElement} referenced by this sequence.\n */\n newSequence(ase) {\n if (this.currentSession) {\n this.currentSession.newSequence(ase);\n this.info.valid = false;\n if (this.SCORM)\n this.SCORM.commitInfo();\n }\n }\n\n /**\n * This method should be invoked when the user starts a new activity\n * @param {module:Activity.Activity} act - The {@link module:Activity.Activity Activity} reporter has just started\n */\n newActivity(act) {\n if (this.currentSession) {\n this.currentSession.newActivity(act);\n this.info.valid = false;\n }\n }\n\n /**\n * This method should be called when the current activity finishes. Data about user's final results\n * on the activity will then be saved.\n * @param {number} score - The final score, usually in a 0-100 scale.\n * @param {number} numActions - The total number of actions done by the user to solve the activity\n * @param {boolean} solved - `true` if the activity was finally solved, `false` otherwise.\n */\n endActivity(score, numActions, solved) {\n if (this.currentSession) {\n this.currentSession.endActivity(score, numActions, solved);\n this.info.valid = false;\n }\n }\n\n /**\n * Reports a new action done by the user while playing the current activity\n * @param {string} type - Type of action (`click`, `write`, `move`, `select`...)\n * @param {string}+ source - Description of the object on which the action is done.\n * @param {string}+ dest - Description of the object reporter acts as a target of the action (usually in pairings)\n * @param {boolean} ok - `true` if the action was OK, `false`, `null` or `undefined` otherwhise\n */\n newAction(type, source, dest, ok) {\n if (this.currentSession) {\n this.currentSession.newAction(type, source, dest, ok);\n this.info.valid = false;\n }\n }\n\n /**\n * Gets information about the current sequence\n * @returns {module:report/SequenceReg.SequenceRegInfo}\n */\n getCurrentSequenceInfo() {\n return this.currentSession === null ? null : this.currentSession.getCurrentSequenceInfo();\n }\n\n /**\n * Gets the name of the current sequence\n * @returns {string}\n */\n getCurrentSequenceTag() {\n return this.currentSession === null ? null : this.currentSession.getCurrentSequenceTag();\n }\n}\n\nObject.assign(Reporter.prototype, {\n /**\n * The {@link module:report/Reporter.ReporterInfo ReporterInfo} used to calculate and store global results.\n * @name module:report/Reporter.Reporter#info\n * @type {module:report/Reporter.ReporterInfo} */\n info: null,\n /**\n * The {@link module:JClicPlayer.JClicPlayer JClicPlayer} used to retrieve messages\n * @name module:report/Reporter.Reporter#ps\n * @type {module:JClicPlayer.JClicPlayer} */\n ps: null,\n /**\n * A valid SCORM bridge, or `null` if no SCORM API detected.\n * @name module:report/Reporter.Reporter#SCORM */\n SCORM: null,\n /**\n * User ID currently associated with this reporting system\n * @name module:report/Reporter.Reporter#userId\n * @type {string} */\n userId: null,\n /**\n * Optional key to be added as a field in session records\n * @name module:report/Reporter.Reporter#sessionKey\n * @type {string} */\n sessionKey: null,\n /**\n * A second optional key to be reported as a field in session records\n * @name module:report/Reporter.Reporter#sessionContext\n * @type {string} */\n sessionContext: null,\n /**\n * Optional filter key to be used in the group selection dialog\n * @name module:report/Reporter.Reporter#groupCodeFilter\n * @type {string} */\n groupCodeFilter: null,\n /**\n * Another optional filter key to be used in the user selection dialog\n * @name module:report/Reporter.Reporter#userCodeFilter\n * @type {string} */\n userCodeFilter: null,\n /**\n * Description of this reporting system\n * @name module:report/Reporter.Reporter#descriptionKey\n * @type {string} */\n descriptionKey: 'Results are not currently being saved',\n /**\n * Additional info to display after the reporter's `description`\n * @name module:report/Reporter.Reporter#descriptionDetail\n * @type {string} */\n descriptionDetail: '',\n /**\n * Starting date and time of this report\n * @name module:report/Reporter.Reporter#started\n * @type {external:Date} */\n started: null,\n /**\n * Array of sessions included in this report\n * @name module:report/Reporter.Reporter#sessions\n * @type {module:report/SessionReg.SessionReg[]} */\n sessions: [],\n /**\n * Currently active session\n * @name module:report/Reporter.Reporter#currentSession\n * @type {module:report/SessionReg.SessionReg} */\n currentSession: null,\n /**\n * `true` if the system was successfully initiated, `false` otherwise\n * @name module:report/Reporter.Reporter#initiated\n * @type {boolean} */\n initiated: false,\n /**\n * `true` if the system is connected to a database with user's data.\n * When `false`, a generic ID will be used.\n * @name module:report/Reporter.Reporter#bUserBased\n * @type {boolean} */\n bUserBased: null,\n /**\n * Maximum number of incorrect UserID attempts\n * @name module:report/Reporter.Reporter#MAX_USERID_PROMPT_ATTEMPTS\n * @type {number} */\n MAX_USERID_PROMPT_ATTEMPTS: 3,\n});\n\n/**\n * This object stores the global results of a {@link module:Reporter.Reporter Reporter}\n */\nexport class ReporterInfo {\n /**\n * ReporterInfo constructor\n * @param {module:report/Reporter.Reporter} rep - The {@link module:Reporter.Reporter Reporter} associated tho this `Info` object.\n */\n constructor(rep) {\n this.rep = rep;\n }\n\n /**\n * Clears all data associated with this ReporterInfo\n */\n clear() {\n this.numSessions = this.numSequences = this.nActivities = this.reportableActs = this.nActSolved =\n this.nActPlayed = this.nActScore = this.nActions = this.ratioSolved = this.ratioPlayed =\n this.tScore = this.tTime = this.partialScore = this.globalScore = 0;\n this.valid = false;\n }\n\n /**\n * Computes the value of all global variables based on the data stored in `sessions`\n * @returns {module:report/Reporter.ReporterInfo} - This \"info\" object\n */\n recalc() {\n if (!this.valid) {\n this.clear();\n this.rep.sessions.forEach(ses => {\n const inf = ses.getInfo();\n this.reportableActs += inf.sReg.reportableActs;\n if (inf.numSequences > 0) {\n this.numSessions++;\n this.numSequences += inf.numSequences;\n if (inf.nActivities > 0) {\n this.nActivities += inf.nActivities;\n this.nActPlayed += inf.sReg.actNames.length;\n this.nActSolved += inf.nActSolved;\n this.nActions += inf.nActions;\n if (inf.nActScore > 0) {\n this.tScore += inf.tScore * inf.nActScore;\n this.nActScore += inf.nActScore;\n }\n this.tTime += inf.tTime;\n }\n }\n });\n if (this.nActivities > 0) {\n this.ratioSolved = this.nActSolved / this.nActivities;\n if (this.reportableActs > 0)\n this.ratioPlayed = this.nActPlayed / this.reportableActs;\n this.partialScore = this.tScore / (this.nActScore * 100);\n this.globalScore = this.partialScore * this.ratioPlayed;\n }\n this.valid = true;\n }\n return this;\n }\n}\n\nObject.assign(ReporterInfo.prototype, {\n /**\n * The Reporter linked to this Info object\n * @name module:report/Reporter.ReporterInfo#rep\n * @type {module:report/Reporter.Reporter}\n */\n rep: null,\n /**\n * When `false`, data must be recalculated\n * @name module:report/Reporter.ReporterInfo#valid\n * @type {boolean} */\n valid: false,\n /**\n * Number of sessions registered\n * @name module:report/Reporter.ReporterInfo#numSessions\n * @type {number} */\n numSessions: 0,\n /**\n * Number of sequences played\n * @name module:report/Reporter.ReporterInfo#numSequences\n * @type {number} */\n numSequences: 0,\n /**\n * Number of activities played\n * @name module:report/Reporter.ReporterInfo#nActivities\n * @type {number} */\n nActivities: 0,\n /**\n * Number of activities in existing in the played projects suitable to be reported\n * @name module:report/Reporter.ReporterInfo#reportableActs\n * @type {number} */\n reportableActs: 0,\n /**\n * Number of activities solved\n * @name module:report/Reporter.ReporterInfo#nActSolved\n * @type {number} */\n nActSolved: 0,\n /**\n * Number of different activities played\n * @name module:report/Reporter.ReporterInfo#nActPlayed\n * @type {number} */\n nActPlayed: 0,\n /**\n * Global score obtained in all sessions registered by this reporter\n * @name module:report/Reporter.ReporterInfo#nActScore\n * @type {number} */\n nActScore: 0,\n /**\n * Number of actions done by the user while in this working session\n * @name module:report/Reporter.ReporterInfo#nActions\n * @type {number} */\n nActions: 0,\n /**\n * Percentage of solved activities\n * @name module:report/Reporter.ReporterInfo#ratioSolved\n * @type {number} */\n ratioSolved: 0,\n /**\n * Percentage of reportable activities played\n * @name module:report/Reporter.ReporterInfo#ratioPlayed\n * @type {number} */\n ratioPlayed: 0,\n /**\n * Sum of the scores of all the activities played\n * @name module:report/Reporter.ReporterInfo#tScore\n * @type {number} */\n tScore: 0,\n /**\n * Global score obtained\n * @name module:report/Reporter.ReporterInfo#partialScore\n * @type {number} */\n partialScore: 0,\n /**\n * Sum of the playing time reported by each activity (not always equals to the sum of all session's time)\n * @name module:report/Reporter.ReporterInfo#tTime\n * @type {number} */\n tTime: 0,\n /**\n * Final score based on the percent of reportable activities played. If the user plays all the\n * activities, this result equals to `partialScore`.\n * @name module:report/Reporter.ReporterInfo#globalScore\n * @type {number} */\n globalScore: 0,\n});\n\nReporter.Info = ReporterInfo;\n\n/**\n * Static list of classes derived from Reporter. It should be filled by Reporter classes at declaration time.\n * @type {object}\n */\nReporter.CLASSES = { 'Reporter': Reporter };\n\nexport default Reporter;\n","/**\n * File : JClicPlayer.js\n * Created : 28/04/2015\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2022 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\n/* global JSON, Promise, location, window, document */\n\nimport $ from 'jquery';\nimport JSZip from 'jszip';\nimport JSZipUtils from 'jszip-utils';\nimport { log, init, settings, getPath, endsWith, getBasePath, getRelativePath, isNullOrUndef, mReplace, toCssSize } from './Utils.js';\nimport { Container, Point, Action, Timer, Rectangle } from './AWT.js';\nimport PlayerHistory from './PlayerHistory.js';\nimport ActiveMediaBag from './media/ActiveMediaBag.js';\nimport Skin from './skins/Skin.js';\nimport EventSounds from './media/EventSounds.js';\nimport JClicProject from './project/JClicProject.js';\nimport JumpInfo from './bags/JumpInfo.js';\nimport ActiveBoxContent from './boxes/ActiveBoxContent.js';\nimport Reporter from './report/Reporter.js';\nimport MediaBagElement from './bags/MediaBagElement.js';\n\n/**\n * JClicPlayer is one of the the main classes of the JClic system. It implements the\n * {@link http://projectestac.github.io/jclic/apidoc/edu/xtec/jclic/PlayStation.html PlayStation}\n * interface, needed to host JClic activities.\n * JClicPlayer offers to {@link module:Activity.ActivityPanel ActivityPanel} objects all the necessary resources and functions:\n * media bags (to load and realize images and other media contents), sequence control, management\n * of the reporting system, user interface, display of system messages, etc.\n * @extends module:AWT.Container\n */\nexport class JClicPlayer extends Container {\n\n /**\n * JClicPlayer constructor\n * @param {external:jQuery} $topDiv - The HTML `div` element where this JClicPlayer will deploy.\n * @param {object} [options] - A set of optional customized options.\n */\n constructor($topDiv, options) {\n\n // JClicPlayer extends Container\n super();\n // Build cascading options\n options = init(options);\n this.options = $.extend(Object.create(this.options), options);\n // Generate unique ID\n this.id = `JC${(0x10000 + Math.round(Math.random() * 0xFFFF)).toString(16).toUpperCase().substring(1)}`;\n // Identify the HTML element where this player will deploy\n this.$topDiv = $topDiv || $('<div/>');\n // Avoid side effects of 'align=center' in old HTML pages\n this.$topDiv.css({ 'text-align': 'initial' });\n\n // Special case: $topDiv inside a TD (like in http://clic.xtec.cat/gali)\n if (this.$topDiv.parent().is('td')) {\n // Set explicit width and height to fill-in the TD\n this.$topDiv.css({\n width: toCssSize(this.options.width, null, null, '100%'),\n height: toCssSize(this.options.height, null, null, '100%'),\n });\n }\n\n // Build the main container\n this.$mainContainer = $('<div/>', { class: 'JClicContainer', id: this.id })\n .css({ width: '100%', height: '100%' })\n .appendTo(this.$topDiv);\n\n // Intitialize other elements\n this.localFS = location && location.protocol === 'file:';\n this.$div = $('<div/>', { class: 'JClicPlayer' });\n this.project = new JClicProject();\n this.activeMediaBag = new ActiveMediaBag();\n this.counterVal = { score: 0, actions: 0, time: 0 };\n this.bgImageOrigin = new Point();\n this.buildActions();\n this.history = new PlayerHistory(this);\n this.audioEnabled = this.options.audioEnabled;\n this.navButtonsAlways = this.options.navButtonsAlways;\n this.defaultSkin = Skin.getSkin(this.options.skin, this);\n this.setSkin(Skin.getSkin('@empty.xml', this));\n this.initTimers();\n this.listenTouchEvents();\n log('info', 'JClicPlayer ready');\n }\n\n /**\n *\n * Detects swipe-right, swipe-left and double touch gestures on touch devices,\n * associating them with 'next activity', 'previous activity' and 'toggle full screen' actions\n */\n listenTouchEvents() {\n\n // Enable listeners only in touch devices\n //if ('ontouchstart' in window) {\n\n let startTouch = null;\n let startTouchTime = 0;\n let thisDiv = this.$div[0];\n const { minSwipeX, maxSwipeY, rightToLeft } = this.options;\n\n // Generic handler for touch events\n const touchEventHandler = event => {\n // Process only single-finger events targeted to our main 'div'\n if (event.target === thisDiv && event.changedTouches && event.changedTouches.length === 1) {\n const touch = event.changedTouches[0];\n const dx = startTouch ? touch.clientX - startTouch.clientX : 0;\n const dy = startTouch ? touch.clientY - startTouch.clientY : 0;\n const dist = Math.sqrt(dx * dx + dy * dy);\n\n switch (event.type) {\n case 'touchstart':\n const currentTime = new Date();\n // Detect double taps, done in less than 800 ms and at short distance\n if (\n document && document.fullscreenEnabled\n && startTouch && startTouchTime\n && currentTime - startTouchTime < 800\n && dist < minSwipeX\n ) {\n event.preventDefault();\n log('info', 'Toggle full screen mode from double touch');\n this.skin.setScreenFull();\n startTouch = null;\n }\n else {\n startTouch = touch;\n startTouchTime = currentTime;\n }\n break;\n\n case 'touchend':\n // Discard non-horizontal gestures and those that do not have sufficient length\n if (startTouch && Math.abs(dx) > minSwipeX && Math.abs(dy) < maxSwipeY) {\n const actionName = dx < 0 && !rightToLeft ? 'next' : 'prev';\n const action = this.actions[actionName];\n if (action && action.enabled) {\n event.preventDefault();\n log('info', `Performing action \"${actionName}\" from touch gesture`);\n action.actionPerformed(event);\n }\n startTouch = null;\n }\n // Cancel double touch detection when long gestures detected\n else if (dist > minSwipeX)\n startTouch = null;\n break;\n\n case 'touchcancel':\n startTouch = null;\n break;\n }\n }\n else\n // Cancel any started gesture\n startTouch = null;\n };\n\n // Handle touch events\n thisDiv.addEventListener('touchstart', touchEventHandler);\n thisDiv.addEventListener('touchend', touchEventHandler);\n thisDiv.addEventListener('touchcancel', touchEventHandler);\n //}\n }\n\n /**\n * Generates an unique ID for elements being used with this player\n * @param {string} lb - The element's label\n * @returns {string}\n */\n getUniqueId(lb) {\n return `${this.id}-${lb}`;\n }\n\n /**\n * Builds the {@link module:AWT.Action} objects for this player\n */\n buildActions() {\n this.actions = {\n 'next': new Action('next', () => this.history.processJump(this.project.activitySequence.getJump(false, this.reporter), false)),\n 'prev': new Action('prev', () => this.history.processJump(this.project.activitySequence.getJump(true, this.reporter), false)),\n 'return': new Action('return', () => this.history.pop()),\n 'reset': new Action('reset', () => { if (this.actPanel && this.actPanel.act.canReinit()) this.initActivity(); }),\n 'help': new Action('help', () => { if (this.actPanel) this.actPanel.showHelp(); }),\n 'info': new Action('info', () => {\n if (this.actPanel && this.actPanel.act.hasInfo()) {\n if (this.actPanel.act.infoUrl)\n this.displayURL(this.act.infoUrl, true);\n else if (this.actPanel.act.infoCmd)\n this.runCmd(this.actPanel.act.infoCmd);\n }\n }),\n 'reports': new Action('reports', () => this.showReports()),\n 'audio': new Action('audio', () => {\n this.audioEnabled = !this.audioEnabled;\n if (!this.audioEnabled)\n this.stopMedia();\n EventSounds.prototype.globalEnabled = this.audioEnabled;\n })\n };\n\n $.each(this.actions, (key, value) => {\n value.addStatusListener(action => { if (this.skin) this.skin.actionStatusChanged(action); });\n });\n }\n\n /**\n * Resets the main components of this player\n */\n reset() {\n log('info', 'Restoring player');\n this.removeActivity();\n this.end();\n this.activeMediaBag = new ActiveMediaBag();\n this.history.clearHistory();\n this.setSkin(null);\n this.setMsg(null);\n this.setCounterValue('score', 0);\n this.setCounterValue('actions', 0);\n this.setCounterValue('time', 0);\n if (this.skin)\n this.skin.setWaitCursor('reset');\n }\n\n /**\n * Instructs the player to stop working\n */\n stop() {\n this.stopMedia(-1);\n }\n\n /**\n * Executes miscellaneous finalization routines.\n * @returns {external:Promise} - A promise to be fullfilled when all pending tasks are finished.\n */\n end() {\n let result = null;\n this.stopMedia();\n this.closeHelpWindow();\n if (this.reporter) {\n result = this.reporter.end();\n this.reporter = null;\n }\n if (this.actPanel) {\n this.actPanel.end();\n this.actPanel.$div.remove();\n this.actPanel = null;\n }\n if (this.project) {\n this.project.end();\n this.project = null;\n }\n if (this.activeMediaBag)\n this.activeMediaBag.removeAll();\n return result || Promise.resolve(true);\n }\n\n /**\n * Creates and initializes the {@link module:Reporter.Reporter Reporter} member\n * @returns {external:Promise}\n */\n initReporter() {\n if (this.reporter) {\n this.reporter.end();\n this.reporter = null;\n }\n this.reporter = Reporter.getReporter(null, this);\n return this.reporter.init();\n }\n\n /**\n * Creates and initializes objects of type {@link module:AWT.Timer}\n */\n initTimers() {\n // Main timer\n if (this.timer)\n this.timer.stop();\n this.timer = new Timer(() => {\n this.incCounterValue('time');\n if (this.actPanel && this.actPanel.act.maxTime > 0\n && this.actPanel.playing\n && this.counterVal['time'] >= this.actPanel.act.maxTime)\n this.actPanel.finishActivity(false);\n }, 1000, false);\n\n // One-time timer, for delayed actions\n if (this.delayedTimer)\n this.delayedTimer.stop();\n this.delayedTimer = new Timer(() => {\n if (this.delayedAction)\n this.delayedAction.processEvent(this.delayedAction, null);\n }, 1000, false);\n this.delayedTimer.repeats = false;\n }\n\n /**\n * Opens the reports dialog\n */\n showReports() {\n if (this.skin) this.skin.showReports(this.reporter);\n }\n\n /**\n * Closes the help dialog window\n */\n closeHelpWindow() {\n if (this.skin) this.skin._closeDlg(false);\n }\n\n /**\n * Sets the current skin\n * @param {module:skins/Skin.Skin} [newSkin] - The skin to use. When `null`, `defaultSkin` will be used.\n */\n setSkin(newSkin) {\n newSkin = newSkin || (this.project && this.project.skin ? this.project.skin : this.defaultSkin);\n if (newSkin && (this.skin === null || newSkin.name !== this.skin.name)) {\n newSkin.attach(this);\n this.skin = newSkin;\n this.skin.doLayout();\n }\n }\n\n /**\n * Sets the current project of this player, without starting any activity\n * @param {module:project/JClicProject.JClicProject} project - The project to be set\n */\n setProject(project) {\n if (this.project) {\n if (this.project !== project)\n this.project.end();\n this.removeActivity();\n }\n this.project = project || new JClicProject();\n this.project.realize(this);\n }\n\n /**\n * Loads the specified project and starts playing at the specified activity or sequence tag.\n * @param {string|JClicProject} [project] - The project to load (if it's a string) or to use (if it's an object of type {@link module:project/JClicProject.JClicProject JClicProject}).\n * When it's a `string`, it can be the absolute or relative path to:\n * - A `.jclic` project file, in XML format\n * - A `.jclic.json` project file in JSON format\n * - A `.jclic.zip` compressed project file (containing one file of type '.jclic' or '.jclic.json')\n * - A `.scorm.zip` file, as exported by JClic Author.\n * - A `project.json` file, as exported by JClic Author\n * When `null` or `undefined`, refers to the current project.\n * @param {string|number} [sequence] - Sequence tag or numeric order in the {@link module:bags/ActivitySequence.ActivitySequence ActivitySequence}\n * to be loaded. If _sequence_ and _activity_ are both `null`, the first {@link module:bags/ActivitySequenceElement.ActivitySequenceElement ActivitySequenceElement}\n * will be loaded.\n * @param {string} [activity] - Name of the activity to be loaded (usually `null`)\n */\n load(project, sequence, activity) {\n\n this.forceFinishActivity();\n this.setWaitCursor(true);\n\n // The ActivityPanel object to be obtained as a result of the loading process\n let actp = null;\n\n // step one: load the project\n if (project) {\n if (typeof project === 'string') {\n\n // Param `project` is a file name or URL (otherwise, is a realized `JClicProject` object)\n const fullPath = getPath(this.basePath, project);\n\n // Previous step: Check if `project` points to a \"project.json\" file\n if (fullPath.endsWith('project.json')) {\n log('info', `Loading JSON info from: ${fullPath}`);\n $.getJSON(fullPath).done(({ mainFile }) => {\n // Read the `mainFile` field of `project.json`\n if (mainFile && endsWith(mainFile, '.jclic') || endsWith(mainFile, '.jclic.json')) {\n // Load project's main file\n this.load(getPath(getBasePath(fullPath), mainFile), sequence, activity);\n } else {\n log('error', `Invalid or null \"mainFile\" specified in ${fullPath} - \"project.json\".`);\n }\n }).fail((jqhxr, textStatus, error) => {\n const errMsg = `${textStatus} (${error}) while loading ${project}`;\n log(errMsg);\n window.alert(`Error!\\n${errMsg}`);\n }).always(\n () => this.setWaitCursor(false)\n );\n return;\n }\n\n // Step 0: Check if `project` points to a ZIP file\n if (fullPath.endsWith('.zip')) {\n // TODO: Implement register of zip files in PlayerHistory\n this.zip = null;\n log('info', `Loading ZIP file: ${fullPath}`);\n\n // Launch loading of ZIP file in a separated thread\n JSZipUtils.getBinaryContent(fullPath, (err, data) => {\n if (err) {\n this.setWaitCursor(false);\n log('error', `Error loading ZIP file: ${err.toString()}`);\n return;\n }\n new JSZip().loadAsync(data).then(zip => {\n this.zip = zip;\n this.zip.fullZipPath = fullPath;\n this.zip.zipBasePath = getBasePath(fullPath);\n let fileName = null;\n // Check if ZIP contains a \"project.json\" file (as in the \".scorm.zip\" files generated by JClic Author)\n if (this.zip.files['project.json']) {\n this.zip.files['project.json'].async('string').then(content => {\n try {\n const json = JSON.parse(content);\n // Read the `mainFile` field of `project.json`\n if (endsWith(json['mainFile'], '.jclic')) {\n // Load project's main file\n this.load(getPath(this.zip.zipBasePath, json['mainFile']), sequence, activity);\n } else {\n log('error', `Invalid or null \"mainFile\" specified in ${fullPath} - \"project.json\".`);\n }\n } catch (err) {\n log('error', `Error reading \"project.json\" in ${fullPath}: ${err ? err.toString() : 'unknown error'}`);\n }\n }).catch(reason => {\n log('error', `Error reading ZIP file: ${reason ? reason.toString() : 'unknown reason'}`);\n });\n } else {\n // Find first file with extension '.jclic' inside the zip file\n fileName = Object.keys(this.zip.files).find(fn => fn.endsWith('.jclic')) || null;\n if (fileName)\n this.load(getPath(this.zip.zipBasePath, fileName), sequence, activity);\n else\n log('error', 'This ZIP file does not contain any JClic project!');\n }\n this.setWaitCursor(false);\n }).catch(reason => {\n log('error', `Error reading ZIP file: ${reason ? reason.toString() : 'unknown reason'}`);\n this.setWaitCursor(false);\n });\n });\n return;\n } else if (this.localFS && window.JClicObject && !window.JClicObject.projectFiles[fullPath]) {\n const scriptTag = document.createElement('script');\n scriptTag.src = `${fullPath}.js`;\n scriptTag.onload = () => {\n // 25 Mar 20201:\n // Workaround for a bug on Chrome and Firefox XML parsers, throwing errors whith hexadecimal character entities\n if (window.JClicObject.projectFiles[fullPath]) {\n window.JClicObject.projectFiles[fullPath] = mReplace([\n [/
/g, '\\r'],\n [/
/g, '\\n'],\n [/	/g, '\\t'],\n ], window.JClicObject.projectFiles[fullPath]);\n this.load(project, sequence, activity);\n }\n };\n document.head.appendChild(scriptTag);\n this.setWaitCursor(false);\n return;\n }\n\n // Step one: load the project file\n const processProjectFile = fp => {\n const isXml = fp.indexOf('data:text/xml;') === 0 || fp.endsWith('.jclic');\n\n const loader = isXml ? $.get(fp, null, null, 'xml') : $.getJSON(fp);\n\n loader.done(data => {\n if (data === null || typeof data !== 'object') {\n log('error', `Bad data. Project not loaded: ${project}`);\n return;\n }\n const prj = new JClicProject();\n if (isXml)\n prj.setProperties($(data).find('JClicProject'), fullPath, this.zip, this.options);\n else\n prj.setAttributes(data, fullPath, this.zip, this.options);\n\n log('info', `Project file loaded and parsed: ${project}`);\n const elements = prj.mediaBag.buildAll(null, element => {\n log('trace', `\"${element.name}\" ready.`);\n this.incProgress(1);\n }, this);\n log('info', `Media elements to be loaded: ${elements}`);\n this.setProgress(0, elements);\n let loops = 0;\n const interval = 500;\n this.setWaitCursor(true);\n const checkMedia = window.setInterval(() => {\n // Wait for a maximum time of two minutes\n if (++loops > this.options.maxWaitTime / interval) {\n window.clearInterval(checkMedia);\n this.setProgress(-1);\n this.setWaitCursor(false);\n log('error', 'Error loading media');\n }\n const waitingObjects = prj.mediaBag.countWaitingElements();\n // player.setProgress(waiting)\n if (waitingObjects === -1) {\n window.clearInterval(checkMedia);\n this.setProgress(-1);\n this.setWaitCursor(false);\n // Call `load` again, passing the loaded [JClicProject](JClicProject.html) as a parameter\n this.load(prj, sequence, activity);\n }\n }, interval);\n }).fail((jqXHR, textStatus, errorThrown) => {\n const errMsg = `${textStatus} (${errorThrown}) while loading ${project}`;\n log(errMsg);\n window.alert(`Error!\\n${errMsg}`);\n }).always(() => this.setWaitCursor(false));\n };\n\n\n log('info', `Loading project: ${project}`);\n let fp = fullPath;\n\n // Special case for ZIP files\n if (this.zip) {\n const fName = getRelativePath(fp, this.zip.zipBasePath);\n if (this.zip.files[fName]) {\n this.zip.file(fName).async('string').then(text => {\n processProjectFile(`data:${fName.endsWith('.jclic') ? 'text/xml' : 'application/json'};charset=UTF-8,${encodeURIComponent(text)}`);\n }).catch(reason => {\n log('error', `Unable to extract \"${fName}\" from ZIP file because of: ${reason ? reason.toString() : 'unknown reason'}`);\n this.setWaitCursor(false);\n });\n return;\n }\n }\n // Special case for local file systems (using `file` protocol)\n else if (this.localFS) {\n // Check if file is already loaded in the global variable `JClicObject`\n if (window.JClicObject && window.JClicObject.projectFiles[fullPath]) {\n fp = `data:${fullPath.endsWith('.jclic') ? 'text/xml' : 'application/json'};charset=UTF-8,${encodeURIComponent(window.JClicObject.projectFiles[fullPath])}`;\n } else {\n log('error', `Unable to load: ${fullPath}.js`);\n this.setWaitCursor(false);\n return;\n }\n }\n processProjectFile(fp);\n return;\n }\n\n // From here, assume that `project` is a [JClicProject](JClicProject.html)\n this.setProject(project);\n\n // If none specified, start with the first element of the sequence\n if (!sequence && !activity)\n sequence = '0';\n\n // start reporter session\n if (this.reporter)\n this.reporter.newSession(project);\n\n }\n\n // Step two: load the ActivitySequenceElement\n if (!isNullOrUndef(sequence)) {\n log('info', `Loading sequence: ${sequence}`);\n this.navButtonsDisabled = false;\n // Try to load sequence by tag\n let ase = null;\n if (typeof sequence === 'string')\n ase = this.project.activitySequence.getElementByTag(sequence, true);\n if (ase === null) {\n // Try to treat 'sequence' as a number\n const n = parseInt(sequence, 10);\n if (typeof n === 'number')\n ase = this.project.activitySequence.getElement(n, true);\n }\n\n if (ase !== null) {\n // Success! We have a real [ActivitySequenceElement](ActivitySequenceElement.html)\n if (this.reporter)\n this.reporter.newSequence(ase);\n activity = ase.activity;\n }\n }\n\n // Step three: load the activity\n if (activity) {\n const act = this.project.getActivity(activity);\n if (act) {\n // Success! We have a real [Activity](Activity.html)\n log('info', `Loading activity: ${activity}`);\n // Clean static references to previous audio elements\n MediaBagElement.resetAudioElements();\n act.prepareMedia(this);\n this.project.activitySequence.checkCurrentActivity(act.name);\n actp = act.getActivityPanel(this);\n actp.buildVisualComponents();\n } else {\n log('error', `Missing activity: ${activity}`);\n }\n }\n\n // Step four: put the activity panel on place\n\n // Remove the current ActivityPanel\n if (this.actPanel !== null) {\n this.actPanel.end();\n this.actPanel.$div.remove();\n this.actPanel = null;\n this.setCounterValue('time', 0);\n }\n\n // Attach the new ActivityPanel\n if (actp) {\n // Sets the actPanel member to this ActivityPanel\n this.actPanel = actp;\n\n if (this.options.fade > 0)\n this.actPanel.$div.css('display', 'none');\n\n // Places the JQuery DOM element of actPanel within the player main panel\n this.$div.prepend(this.actPanel.$div);\n if (this.skin)\n this.skin.resetAllCounters(false);\n\n // Sets the current skin\n if (this.actPanel.skin)\n this.setSkin(this.actPanel.skin);\n else if (this.project.skin) {\n this.setSkin(this.project.skin);\n this.lastProjectSkin = this.project.skin;\n }\n else if (this.lastProjectSkin)\n this.setSkin(this.lastProjectSkin);\n else\n this.setSkin(null);\n\n if (this.skin) {\n // Enable or disable actions\n const hasReturn = this.history.storedElementsCount() > 0 || this.options.returnAsExit;\n const navBtnFlag = this.navButtonsAlways ?\n 'both' : this.navButtonsDisabled ?\n 'none' : this.project.activitySequence.getNavButtonsFlag();\n this.actions['next'].setEnabled((navBtnFlag === 'fwd' || navBtnFlag === 'both') &&\n this.project.activitySequence.hasNextAct(hasReturn));\n this.actions['prev'].setEnabled((navBtnFlag === 'back' || navBtnFlag === 'both') &&\n this.project.activitySequence.hasPrevAct(hasReturn));\n this.actions['return'].setEnabled(hasReturn);\n this.actions['help'].setEnabled(this.actPanel.act.helpWindowAllowed());\n this.actions['reset'].setEnabled(this.actPanel.act.canReinit());\n this.actions['info'].setEnabled(this.actPanel.act.hasInfo());\n }\n this.doLayout();\n this.initActivity();\n\n this.history.pushBrowserHistory();\n\n this.actPanel.$div.fadeIn(this.options.fade, () => this.activityReady());\n }\n this.setWaitCursor(false);\n }\n\n /**\n * Forces the current activity to stop playing.\n */\n forceFinishActivity() {\n this.timer.stop();\n this.delayedTimer.stop();\n if (this.actPanel) {\n this.closeHelpWindow();\n this.actPanel.forceFinishActivity();\n this.stopMedia();\n this.activeMediaBag.removeAll();\n }\n }\n\n /**\n *\n * Removes the current {@link module:Activity.ActivityPanel ActivityPanel} from this player\n */\n removeActivity() {\n this.forceFinishActivity();\n if (this.actPanel) {\n this.actPanel.end();\n this.actPanel.$div.remove();\n this.actPanel = null;\n this.setMsg(null);\n this.doLayout();\n }\n }\n\n /**\n *\n * Initializes the activity\n */\n initActivity() {\n this.setWaitCursor(true);\n this.timer.stop();\n this.delayedTimer.stop();\n this.setCounterValue('time', 0);\n this.stopMedia();\n if (this.actPanel) {\n this.actPanel.initActivity();\n this.timer.start();\n if (!this.actPanel.act.mustPauseSequence())\n this.startAutoPassTimer();\n log('info', `Activity \"${this.actPanel.act.name}\" running`);\n }\n this.setWaitCursor(false);\n }\n\n /**\n * Called by {@link module:JClicPlayer.JClicPlayer#load} when the {@link module:Activity.ActivityPanel ActivityPanel} is fully visible, just\n * after the JQuery animation effect.\n */\n activityReady() {\n if (this.actPanel) {\n this.actPanel.activityReady();\n log('info', 'Activity ready');\n }\n }\n\n /**\n * Starts the activity. This method is usually called from text activities with previous text.\n */\n startActivity() {\n this.setWaitCursor(true);\n if (this.actPanel)\n this.actPanel.startActivity();\n this.setWaitCursor(false);\n }\n\n /**\n * Configures the layout and visual aspect of the player area.\n */\n doLayout() {\n\n // Main player area settings\n const\n width = this.dim.width = this.$div.width(),\n height = this.dim.height = this.$div.height(),\n mainCss = {\n 'background-color': this.actPanel ? this.actPanel.act.bgColor : 'azure',\n 'background-image': ''\n };\n\n if (this.actPanel) {\n const act = this.actPanel.act;\n if (act.bgGradient)\n // Canvas version also available\n mainCss['background-image'] = act.bgGradient.getCss();\n\n if (act.bgImageFile && act.bgImageFile.length > 0) {\n this.project.mediaBag.getElement(act.bgImageFile, true).getFullPathPromise().then(bgImageUrl => {\n this.$div.css({\n 'background-image': 'url(\\'' + bgImageUrl + '\\')',\n 'background-repeat': act.tiledBgImg ? 'repeat' : 'no-repeat',\n 'background-position': act.tiledBgImg ? '' : 'center center'\n });\n });\n }\n\n // Activity panel settings\n // Calc the maximum rectangle available for the activity panel\n const\n m = settings.BoxBase.AC_MARGIN,\n proposedRect = new Rectangle(m, m, width - 2 * m, height - 2 * m);\n\n if (this.actPanel.bgImage && !act.tiledBgImg && act.absolutePositioned) {\n // Special case: when the activity has a background image not tiled, and an absolute\n // position has been specified, the ActivityPanel must be placed at this absolute\n // position, relative to the background image\n this.bgImageOrigin.x = (width - this.actPanel.bgImage.width) / 2;\n this.bgImageOrigin.y = (height - this.actPanel.bgImage.height) / 2;\n proposedRect.pos.moveTo(this.bgImageOrigin);\n proposedRect.dim.width -= this.bgImageOrigin.x - m;\n proposedRect.dim.height -= this.bgImageOrigin.y - m;\n proposedRect.dim.width = Math.min(proposedRect.dim.width, width);\n proposedRect.dim.height = Math.min(proposedRect.dim.height, height);\n }\n\n // ActivityPanel will calculate and set its position and size based on the maximum and optimal\n // available space\n /* TODO: Try with a computed rectangle instead of \"this\", to avoid the loss of the right margin\n * in narrow displays */\n this.actPanel.fitTo(proposedRect, this);\n }\n this.$div.css(mainCss);\n }\n\n /**\n * Plays the specified media.\n * @param {module:media/MediaContent.MediaContent} mediaContent - The media to be played\n * @param {module:boxes/ActiveBox.ActiveBox} [mediaPlacement] - The cell where the graphic component of this media should be placed (used with video objects)\n * @param {function[]} [delayedActions] - If set, store the the action in this array for future execution\n */\n playMedia(mediaContent, mediaPlacement = null, delayedActions = null) {\n\n let ji = null;\n const fn = mediaContent.file;\n let action = null;\n\n switch (mediaContent.type) {\n case 'PLAY_AUDIO':\n case 'PLAY_VIDEO':\n case 'PLAY_MIDI':\n case 'RECORD_AUDIO':\n case 'PLAY_RECORDED_AUDIO':\n if (this.audioEnabled) {\n const amp = this.activeMediaBag.getActiveMediaPlayer(mediaContent, this.project.mediaBag, this);\n if (amp)\n action = () => amp.play(mediaPlacement);\n }\n break;\n\n case 'RUN_CLIC_PACKAGE':\n ji = new JumpInfo('JUMP', fn);\n if (mediaContent.externalParam) {\n // Relative path computed in History.processJump\n ji.projectPath = mediaContent.externalParam;\n }\n action = () => this.history.processJump(ji, true);\n break;\n\n case 'RUN_CLIC_ACTIVITY':\n this.history.push();\n action = () => this.load(null, null, fn);\n break;\n\n case 'RETURN':\n if (this.history.storedElementsCount() > 0 || !this.options.returnAsExit) {\n action = () => this.history.pop();\n break;\n }\n case 'EXIT':\n ji = new JumpInfo('EXIT', fn);\n action = () => this.history.processJump(ji, false);\n break;\n\n case 'RUN_EXTERNAL':\n action = () => this.runCmd(fn);\n break;\n\n case 'URL':\n if (fn)\n // When mediaContent.level is 2 or more, the URL will be opened in a separate window.\n action = () => this.displayURL(fn, mediaContent.level > 1);\n break;\n\n default:\n log('error', `Unknown media type: ${mediaContent.type}`);\n break;\n }\n\n // Execute the action or pass callback\n if (delayedActions && action)\n delayedActions.push(action);\n else if (action)\n action();\n }\n\n /**\n * Stops currently playing media\n * @param {number} [level=-1] - Sets the threshold above which all media objects with equal\n * or greater `level` will also also be muted.\n */\n stopMedia(level) {\n if (typeof level !== 'number')\n level = -1;\n this.activeMediaBag.stopAll(level);\n }\n\n /**\n * Launches the specified system command.\n * Currently not implemented.\n * @param {string} cmd\n */\n runCmd(cmd) {\n log('warn', `Unsupported call to external command: \"${cmd}\"`);\n }\n\n /**\n * Called from {@link module:Activity.Activity Activity} when finished.\n * @param {boolean} _completedOK - `true` when the activity was successfully completed, `false`\n * otherwise.\n */\n activityFinished(_completedOK) {\n this.closeHelpWindow();\n log('info', 'Activity finished');\n this.timer.stop();\n this.startAutoPassTimer();\n }\n\n /**\n * Starts the automatic jump to next activity, when applicable.\n */\n startAutoPassTimer() {\n const ase = this.project.activitySequence.getCurrentAct();\n if (ase !== null && ase.delay > 0 && !this.delayedTimer.isRunning() && !this.navButtonsDisabled) {\n this.delayedAction = this.actions['next'];\n this.delayedTimer.interval = ase.delay * 1000;\n this.delayedTimer.start();\n }\n }\n\n /**\n *\n * Sets the current main message.\n * @param {module:boxes/ActiveBoxContent.ActiveBoxContent} abc - The content of the message\n */\n setMsg(abc) {\n const ab = this.skin ? this.skin.getMsgBox() : null;\n if (ab) {\n ab.clear();\n this.skin.invalidate(ab).update();\n ab.setContent(abc ? abc : ActiveBoxContent.EMPTY_CONTENT);\n // TODO: Move this method to Skin\n this.skin.invalidate(ab).update();\n ab.playMedia(this);\n }\n }\n\n /**\n * Launches the active media content associated to the main message, if any.\n */\n playMsg() {\n if (this.skin && this.skin.getMsgBox())\n this.skin.getMsgBox().playMedia(this);\n }\n\n /**\n * Sets a value to the specified counter\n * @param {string} counter - The id of the counter ('score', 'actions' or 'time')\n * @param {number} newValue - The value to be set\n */\n setCounterValue(counter, newValue) {\n this.counterVal[counter] = newValue;\n if (this.skin && this.skin.counters[counter])\n this.skin.counters[counter].setValue(newValue);\n }\n\n /**\n * Gets the current value for the specified counter\n * @param {string} counter - The id of the counter ('score', 'actions' or 'time')\n * @returns {number}\n */\n getCounterValue(counter) {\n return this.counterVal[counter];\n }\n\n /**\n * Enables or disables a specific counter\n * @param {string} counter - The id of the counter ('score', 'actions' or 'time')\n * @param {boolean} bEnabled - When `true`, the counter will be enabled.\n */\n setCounterEnabled(counter, bEnabled) {\n if (this.skin) {\n this.skin.enableCounter(counter, bEnabled);\n this.setCountDown(counter, 0);\n }\n }\n\n /**\n * Increments by 1 the value of the specified counter\n * @param {string} counter - The id of the counter ('score', 'actions' or 'time')\n */\n incCounterValue(counter) {\n this.counterVal[counter]++;\n\n const\n actp = this.actPanel,\n cnt = this.skin ? this.skin.counters[counter] : null;\n\n if (cnt)\n cnt.setValue(this.counterVal[counter]);\n if (counter === 'actions' && actp !== null && actp.act.maxActions > 0 && actp.playing && this.counterVal['actions'] >= actp.act.maxActions)\n window.setTimeout(() => { actp.finishActivity(actp.solved); }, 0);\n }\n\n /**\n * Sets the specified counter in count-down status, starting at `maxValue`.\n * @param {string} counter - The id of the counter ('score', 'actions' or 'time')\n * @param {number} maxValue - The value from which to start counting down\n */\n setCountDown(counter, maxValue) {\n //this.counterVal[counter] = maxValue\n if (this.skin && this.skin.counters[counter])\n this.skin.counters[counter].setCountDown(maxValue);\n }\n\n /**\n * Set/unset the panel in 'wait' state\n * @param {boolean} status\n */\n setWaitCursor(status) {\n if (this.skin)\n this.skin.setWaitCursor(status);\n }\n\n /**\n * Sets the current value of the progress bar\n * @param {number} val - The current value. Should be less or equal than `max`. When -1, the progress bar will be hidden.\n * @param {number} [max] - Optional parameter representing the maximum value. When passed, the progress bar will be displayed.\n */\n setProgress(val, max) {\n if (this.skin)\n this.skin.setProgress(val, max);\n }\n\n /**\n * Increments the progress bar value by the specified amount, only when the progress bar is running.\n * @param {number} [val=1] - The amount to increment. When not defined, it's 1.\n */\n incProgress(val = 1) {\n if (this.skin)\n this.skin.incProgress(val);\n }\n\n /**\n * Builds an {@link module:media/ActiveMediaPlayer.ActiveMediaPlayer ActiveMediaPlayer} for the specified {@link module:media/MediaContent.MediaContent}\n * @param {module:media/MediaContent.MediaContent} mediaContent - The media content to be played\n * @returns {module:media/ActiveMediaPlayer.ActiveMediaPlayer}\n */\n getActiveMediaPlayer(mediaContent) {\n return this.activeMediaBag && mediaContent ? this.activeMediaBag.getActiveMediaPlayer(mediaContent, this.project.mediaBag, this) : null;\n }\n\n /**\n * Notifies the reporting system that a new activity has started\n * @param {module:Activity.Activity} act - The activity that is sending the notification\n */\n reportNewActivity(act) {\n const ase = this.project.activitySequence.getCurrentAct();\n if (this.reporter) {\n if (ase.tag === this.reporter.getCurrentSequenceTag())\n // Notify that the sequence has changed\n this.reporter.newSequence(ase);\n if (act.includeInReports)\n this.reporter.newActivity(act);\n }\n this.setCounterValue('actions', 0);\n this.setCounterValue('score', 0);\n }\n\n /**\n * Notifies the reporting system that a new action has been performed on the current activity\n * @param {module:Activity.Activity} act - The activity that is sending the notification\n * @param {string} type - Type of action (match, move, switch...)\n * @param {string} source - Object acting as a source of the action (cell, grid, clue...)\n * @param {string} dest - When applicable, object acting as a receiver of the action (cell, grid...)\n * @param {boolean} ok - Whether the action was OK or not\n * @param {number} currentScore - The current score of the activity\n */\n reportNewAction(act, type, source, dest, ok, currentScore) {\n if (this.reporter && act.includeInReports && act.reportActions)\n this.reporter.newAction(type, source, dest, ok);\n if (currentScore >= 0) {\n this.incCounterValue('actions');\n this.setCounterValue('score', currentScore);\n }\n }\n\n /**\n * Notifies the reporting system that the current activity has finished\n * @param {module:Activity.Activity} act - The activity that is sending the notification\n * @param {boolean} solved - Whether the activity was successfully completed or not.\n */\n reportEndActivity(act, solved) {\n if (this.reporter && act.includeInReports)\n this.reporter.endActivity(this.counterVal['score'], this.counterVal['actions'], solved);\n }\n\n /**\n * Shows the help info provided by the activity\n * @param {external:jQuery} $hlpComponent - The jQuery DOM component to be shown.\n * @returns {boolean} - True when the component was successfully displayed\n */\n showHelp($hlpComponent) {\n return this.skin ? this.skin.showHelp($hlpComponent) : false;\n }\n\n /**\n * Navigates to the requested URL\n * @param {string} url - The URL to navigate to\n * @param {boolean} inFrame - When `true` opens in a new frame\n */\n displayURL(url, inFrame) {\n if (url) {\n if (inFrame)\n window.open(url, this.options.infoUrlFrame);\n else {\n this.end().then(() => { window.location.href = url; });\n }\n }\n }\n\n /**\n * Only when `exitUrl` has been specified in `options`, navigates to the specified URL\n * @param {string} url - The URL to navigate to.\n */\n exit(url) {\n this.displayURL(url || this.options.exitUrl, false);\n }\n\n /**\n * Sets a title in a specific HTML element, if provided.\n * @param {string} docTitle\n */\n setWindowTitle(docTitle) {\n log('info', `running ${docTitle}`);\n }\n}\n\nObject.assign(JClicPlayer.prototype, {\n /**\n * Object with miscellaneous options.\n * @name module:JClicPlayer.JClicPlayer#options\n * @type {object} */\n options: {\n //\n // Max waiting time to have all media loaded (milliseconds)\n maxWaitTime: 120000,\n //\n // Name of the frame where to open links\n infoUrlFrame: '_blank',\n //\n // URL where to navigate to on exit\n exitUrl: null,\n //\n // When `true` and no elements on sequence stack, RETURN acts as EXIT\n returnAsExit: false,\n //\n // At the beginning, the audio should be enabled or disabled\n audioEnabled: true,\n //\n // Navigation buttons are always visible (for debugging purposes)\n navButtonsAlways: false,\n //\n // Time (milliseconds) of the fade-in animation of the activity panel. When 0, no animation\n // is performed\n fade: 300,\n // Minimum horizontal swipe length to be considered an activity change gesture\n minSwipeX: 40,\n // Maximum vertical swipe length to be considered an activity change gesture\n maxSwipeY: 100,\n // Read swipe gestures as in right-to-left languages (default is left-to-right)\n rightToLeft: false,\n },\n /**\n * Unique ID of this player, randomly generated by the constructor\n * @name module:JClicPlayer.JClicPlayer#id\n * @type {string} */\n id: 'JC0000',\n /**\n * The JQuery \"div\" element used by this player as stage for activities\n * @name module:JClicPlayer.JClicPlayer#$div\n * @type {external:jQuery} */\n $div: null,\n /**\n * The JQuery top container where this player will deploy\n * @name module:JClicPlayer.JClicPlayer#$topDiv\n * @type {external:jQuery} */\n $topDiv: null,\n /**\n * The main container of all JClic components\n * @name module:JClicPlayer.JClicPlayer#$mainContainer\n * @type {external:jQuery} */\n $mainContainer: null,\n /**\n * Flag indicatig that this player has switched to full screen at least once\n * @name module:JClicPlayer.JClicPlayer#fullScreenChecked\n * @type {boolean} */\n fullScreenChecked: false,\n /**\n * The {@link module:project/JClicProject.JClicProject JClicProject} currently hosted in this player\n * @name module:JClicPlayer.JClicPlayer#project\n * @type {module:project/JClicProject.JClicProject} */\n project: null,\n /**\n * Relative path or absolute URL to be used as a base to access files\n * @name module:JClicPlayer.JClicPlayer#basePath\n * @type {string} */\n basePath: '',\n /**\n * A {@link external:JSZip} object pointing to a `jclic.zip` or `jclic.scorm.zip` file containing\n * the current project.\n * Two extra properties will be added to this object when loaded:\n * - __zip.fullZipPath__ {string} - The full path of the ZIP file\n * - __zip.zipBasePath__ {string} - The path to the folder containing the ZIP file\n * @name module:JClicPlayer.JClicPlayer#zip\n * @type {external:JSZip} */\n zip: null,\n /**\n * This flag indicates if the player is running inside a document loaded by `file:` protocol\n * @name module:JClicPlayer.JClicPlayer#localFS\n * @type {boolean}\n */\n localFS: false,\n /**\n * The {@link module:Activity.ActivityPanel ActivityPanel} currently running on this player.\n * @name module:JClicPlayer.JClicPlayer#actPanel\n * @type {module:Activity.Activity#Panel} */\n actPanel: null,\n /**\n * This object records the list of the activities played during the current session.\n * @name module:JClicPlayer.JClicPlayer#history\n * @type {module:PlayerHistory.PlayerHistory} */\n history: null,\n /**\n * The Skin currently used by this player.\n * @name module:JClicPlayer.JClicPlayer#skin\n * @type {module:skins/Skin.Skin} */\n skin: null,\n /**\n * The default Skin to be used if none specified\n * @name module:JClicPlayer.JClicPlayer#defaultSkin\n * @type {module:skins/Skin.Skin} */\n defaultSkin: null,\n /**\n * The last skin directly specified by a {@link module:project/JClicProject.JClicProject JClicProject}\n * @name module:JClicPlayer.JClicPlayer#defaultSkin\n * @type {module:skins/Skin.Skin} */\n lastProjectSkin: null,\n /**\n * Object containing references to realized media objects, ready to play.\n * @name module:JClicPlayer.JClicPlayer#activeMediaBag\n * @type {module:media/ActiveMediaBag.ActiveMediaBag} */\n activeMediaBag: null,\n /**\n * Object responsible for passing the scores obtained by users to a external reporting systems\n * when playing activities.\n * @name module:JClicPlayer.JClicPlayer#reporter\n * @type {module:report/Reporter.Reporter} */\n reporter: null,\n /**\n * Collection of {@link module:AWT.Action} objects used by this player.\n * @name module:JClicPlayer.JClicPlayer#actions\n * @type {module:AWT.Action[]} */\n actions: {},\n /**\n * Main timer object used to feed the time counter. Ticks every second.\n * @name module:JClicPlayer.JClicPlayer#timer\n * @type {module:AWT.Timer} */\n timer: null,\n /**\n * Timer for delayed actions\n * @name module:JClicPlayer.JClicPlayer#delayedTimer\n * @type {module:AWT.Timer} */\n delayedTimer: null,\n /**\n * This variable holds the action to be executed by `delayedTimer`\n * @name module:JClicPlayer.JClicPlayer#delayedAction\n * @type {module:AWT.Action} */\n delayedAction: null,\n /**\n * @typedef JClicPlayer~counterValType\n * @type {object}\n * @property {number} score\n * @property {number} actions\n * @property {number} time */\n /**\n * Current values of the counters\n * @name module:JClicPlayer.JClicPlayer#counterVal\n * @type {module:JClicPlayer.JClicPlayer~counterValType} */\n counterVal: { score: 0, actions: 0, time: 0 },\n /**\n * Point indicating the upper-left corner of the current background image\n * @name module:JClicPlayer.JClicPlayer#bgImageOrigin\n * @type {module:AWT.Point} */\n bgImageOrigin: null,\n /**\n * Whether the player must play all sounds (including system sounds) and other media content\n * of the activities.\n * @name module:JClicPlayer.JClicPlayer#audioEnabled\n * @type {boolean} */\n audioEnabled: true,\n /**\n * Whether the navigation buttons `next` and `back` are enabled o disabled.\n * @name module:JClicPlayer.JClicPlayer#navButtonsDisabled\n * @type {boolean} */\n navButtonsDisabled: false,\n /**\n * When this flag is `true`, the navigation buttons are always enabled despite\n * of the indications made by the activities or the sequence control system.\n * This is used only to debug projects with complicated sequence chaining.\n * @name module:JClicPlayer.JClicPlayer#navButtonsAlways\n * @type {boolean} */\n navButtonsAlways: false,\n});\n\nexport default JClicPlayer;\n","/**\n * File : boxes/AbstractBox.js\n * Created : 18/04/2015\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\nimport { Rectangle, Point, Dimension, Stroke } from '../AWT.js';\nimport BoxBase from './BoxBase.js';\n\n/**\n * This abstract class is the base for most graphic components of JClic. It describes an area\n * (by default an {@link module:AWT.Rectangle}) with some special properties that determine how it must\n * be drawn on screen.\n *\n * Some types of boxes can act as containers for other boxes, establishing a hierarchy of dependences.\n * @abstract\n * @extends module:AWT.Rectangle\n */\nexport class AbstractBox extends Rectangle {\n /**\n * AbstractBox constructor\n * @param {module:AbstractBox} parent - The AbstractBox to which this one belongs\n * @param {module:AWT.Container} container - The container where this box is placed.\n * @param {module:BoxBase} boxBase - The object where colors, fonts, border and other graphic properties\n * of this box are defined.\n */\n constructor(parent, container, boxBase) {\n // AbstractBox extends AWT.Rectangle\n super();\n this.container = container;\n this.parent = parent;\n this.boxBase = boxBase;\n this.shape = this;\n this.specialShape = false;\n this.visible = true;\n }\n\n /**\n * Setter method for `parent`\n * @param {module:boxes/AbstractBox.AbstractBox} parent - The new parent of this box\n */\n setParent(parent) {\n this.parent = parent;\n }\n\n /**\n * Gets the current parent of this box\n * @returns {module:boxes/AbstractBox.AbstractBox}\n */\n getParent() {\n return this.parent;\n }\n\n /**\n * Finisher method\n */\n end() {\n }\n\n /**\n * Setter method for `container`\n * @param {module:AWT.Container} newContainer - The new Container assigned to this box\n */\n setContainer(newContainer) {\n this.container = newContainer;\n if (this.$hostedComponent && this.container && this.container.$div) {\n this.$hostedComponent.detach();\n this.container.$div.append(this.$hostedComponent);\n }\n }\n\n /**\n * Gets the `container` attribute of this box, without checking its parent\n * @returns {module:AWT.Container}\n */\n getContainerX() {\n return this.container;\n }\n\n /**\n * Gets the container associated to this box, asking its parents when `null`.\n * @returns {module:AWT.Container}\n */\n getContainerResolve() {\n let ab = this;\n while (ab.container === null && ab.parent !== null)\n ab = ab.parent;\n return ab.container;\n }\n\n /**\n * Invalidates the zone corresponding to this box in the associated {@link module:AWT.Container}, if any.\n * @param {module:AWT.Rectangle} rect - The rectangle to be invalidated. When `null`, it's the full\n * container area.\n */\n invalidate(rect) {\n const cnt = this.getContainerResolve();\n if (cnt)\n cnt.invalidate(rect);\n }\n\n /**\n * Sets the {@link module:boxes/BoxBase.BoxBase BoxBase} of this box\n * @param {module:boxes/BoxBase.BoxBase} boxBase - The new BoxBase\n */\n setBoxBase(boxBase) {\n this.boxBase = boxBase;\n this.invalidate();\n }\n\n /**\n * Gets the real {@link module:boxes/BoxBase.BoxBase BoxBase} associated to this box, scanning down parent relationships.\n * @returns {module:boxes/BoxBase.BoxBase}\n */\n getBoxBaseResolve() {\n let ab = this;\n while (!ab.boxBase && ab.parent)\n ab = ab.parent;\n return ab.boxBase || BoxBase.DEFAULT_BOX_BASE;\n }\n\n /**\n * Sets the shape used to draw the content of this box\n * @param {module:AWT.Shape} sh - The shape to be set\n */\n setShape(sh) {\n this.shape = sh;\n this.specialShape = true;\n this.invalidate();\n super.setBounds(sh.getBounds());\n this.invalidate();\n }\n\n /**\n * Gets the current shape used in this box\n * @returns {module:AWT.Shape}\n */\n getShape() {\n return this.shape;\n }\n\n /**\n * Check if this box contains the specified point\n * @override\n * @param {module:AWT.Point} p - The point to be checked\n * @returns {boolean}\n */\n contains(p) {\n return this.shape === this ? super.contains(p) : this.shape.contains(p);\n }\n\n /**\n * Sets a new size and/or dimension to this box\n * @override\n * @param {AWT.Rectangle|number} rect - An AWT.Rectangle object, or the `x` coordinate of the\n * upper-left corner of a new rectangle.\n * @param {number} [y] - `y` coordinate of the upper-left corner of the new rectangle.\n * @param {number} [w] - Width of the new rectangle.\n * @param {number} [h] - Height of the new rectangle.\n */\n setBounds(rect, y, w, h) {\n if (typeof rect === 'number')\n // arguments are co-ordinates and size\n rect = new Rectangle(rect, y, w, h);\n // Rectangle comparision\n if (this.equals(rect))\n return;\n\n const sizeChanged = !this.dim.equals(rect.dim);\n if (this.specialShape) {\n if (sizeChanged) {\n this.shape.scaleBy(new Dimension(rect.dim.width / this.dim.width, rect.dim.height / this.dim.height));\n this.setShape(this.shape);\n }\n if (!this.pos.equals(rect.pos)) {\n this.shape.moveTo(rect.pos);\n }\n this.setShape(this.shape);\n } else\n super.setBounds(rect);\n\n if (this.$hostedComponent)\n this.setHostedComponentBounds(sizeChanged);\n\n return this;\n }\n\n /**\n * Sets a new location for this box. In JClic this method was named `setLocation`\n * @param {AWT.Point|number} newPos - A point or the `x` coordinate of a new point.\n * @param {number} [y] - The `y` coordinate of a new point.\n */\n moveTo(newPos, y) {\n if (typeof newPos === 'number')\n newPos = new Point(newPos, y);\n this.setBounds((new Rectangle(this)).moveTo(newPos));\n }\n\n /**\n * Sets a new location to this box. In JClic this method was named `translate`.\n * @param {number} dx - The displacement on the X axis\n * @param {number} dy - The displacement on the Y axis\n */\n moveBy(dx, dy) {\n this.setBounds((new Rectangle(this)).moveBy(dx, dy));\n }\n\n /**\n * Changes the size of this box\n * @param {number} width\n * @param {number} height\n */\n setSize(width, height) {\n this.setBounds(new Rectangle(this.pos, new Dimension(width, height)));\n }\n\n /**\n * Checks if this box has border\n * @returns {boolean}\n */\n hasBorder() {\n return this.border;\n }\n\n /**\n * Sets/unsets a border to this box\n * @param {boolean} newVal - `true` to set a border.\n */\n setBorder(newVal) {\n if (!newVal)\n this.invalidate();\n this.border = newVal;\n if (newVal)\n this.invalidate();\n }\n\n /**\n * Checks if this box is fully visible\n * @returns {boolean}\n */\n isVisible() {\n return this.visible;\n }\n\n /**\n * Sets this box visible or invisible\n * @param {boolean} newVal - `true` for visible\n */\n setVisible(newVal) {\n this.visible = newVal;\n this.setHostedComponentVisible();\n this.invalidate();\n }\n\n /**\n * Makes {@link module:boxes/AbstractBox.AbstractBox#$hostedComponent} visible or invisible, based on the value of\n * the AbstractBox `visible` flag.\n */\n setHostedComponentVisible() {\n if (this.$hostedComponent)\n this.$hostedComponent.css('visibility', this.visible ? 'visible' : 'hidden');\n }\n\n /**\n * Checks if this box is temporary hidden\n * @returns {boolean}\n */\n isTemporaryHidden() {\n return this.temporaryHidden;\n }\n\n /**\n * Makes this box temporary hidden (newVal `true`) or resets its original state (newVal `false`)\n * @param {boolean} newVal\n */\n setTemporaryHidden(newVal) {\n this.temporaryHidden = newVal;\n }\n\n /**\n * Checks if this box is currently inactive.\n * @returns {boolean}\n */\n isInactive() {\n return this.inactive;\n }\n\n /**\n * Makes this box active (`false`) or inactive (`true`)\n * @param {boolean} newVal\n */\n setInactive(newVal) {\n this.inactive = newVal;\n if (this.$hostedComponent) {\n this.setHostedComponentColors();\n this.setHostedComponentVisible();\n } else {\n if (this.$accessibleElement) {\n const disabled = this.isInactive() && !this.accessibleAlwaysActive;\n this.$accessibleElement.prop({\n disabled: disabled,\n tabindex: disabled ? -1 : 0\n });\n }\n this.invalidate();\n }\n }\n\n /**\n * Checks if this box is in `inverted` state.\n * @returns {boolean}\n */\n isInverted() {\n return this.inverted;\n }\n\n\n /**\n * Puts this box in `inverted` mode or restores its original state.\n * @param {boolean} newVal\n */\n setInverted(newVal) {\n this.inverted = newVal;\n if (this.$hostedComponent)\n this.setHostedComponentColors();\n else\n this.invalidate();\n }\n\n /**\n * Checks if this box is `marked`\n * @returns {boolean}\n */\n isMarked() {\n return this.marked;\n }\n\n /**\n * Sets this box in `marked` mode, or restores its original state.\n * @param {boolean} newVal\n */\n setMarked(newVal) {\n if (!newVal)\n this.invalidate();\n this.marked = newVal;\n if (this.$hostedComponent) {\n this.setHostedComponentColors();\n this.setHostedComponentBorder();\n } else if (newVal)\n this.invalidate();\n }\n\n /**\n * Checks if this box has the input focus\n * @returns {boolean}\n */\n isFocused() {\n return this.focused;\n }\n\n /**\n *\n * Sets or unsets the input focus to this box.\n * @param {boolean} newVal\n */\n setFocused(newVal) {\n if (!newVal)\n this.invalidate();\n this.focused = newVal;\n if (newVal)\n this.invalidate();\n // Put hosted component on top\n if (this.$hostedComponent)\n this.$hostedComponent.css('z-index', this.focused ? 20 : 2);\n }\n\n /**\n * Checks if this box is in `alternative` state.\n * @returns {boolean}\n */\n isAlternative() {\n return this.alternative;\n }\n\n /**\n * Sets this box in `alternative` mode, or restores its original state.\n * @param {boolean} newVal\n */\n setAlternative(newVal) {\n this.alternative = newVal;\n this.invalidate();\n }\n\n /**\n * Draws the content of this box on an HTML `canvas` element. At this level, only background\n * and border are painted/stroked. Derived classes should implement specific drawing tasks in\n * {@link module:boxes/AbstractBox.AbstractBox#updateContent}.\n * @param {external:CanvasRenderingContext2D} ctx - The canvas rendering context used to draw the\n * box content.\n * @param {module:AWT.Rectangle} [dirtyRegion=null] - The area that must be repainted. `null` refers to the whole box.\n */\n update(ctx, dirtyRegion = null) {\n if (this.isEmpty() || !this.isVisible() || this.isTemporaryHidden())\n return false;\n\n if (dirtyRegion && !this.shape.intersects(dirtyRegion))\n return false;\n\n /**\n * TODO: Implement clipping\n Shape saveClip=new Area(g2.getClip())\n Area clip=new Area(saveClip)\n clip.intersect(new Area(shape))\n g2.setClip(clip)\n */\n\n const style = this.getBoxBaseResolve();\n if (!style.transparent && !style.dontFill && !this.tmpTrans) {\n if (!style.bgGradient || style.bgGradient.hasTransparency()) {\n // Prepare the rendering context\n ctx.fillStyle = this.inactive ?\n style.inactiveColor :\n this.inverted ? style.textColor : style.backColor;\n // Fill the shape\n this.shape.fill(ctx, dirtyRegion);\n }\n if (style.bgGradient) {\n ctx.fillStyle = style.bgGradient.getGradient(ctx, this.shape.getBounds());\n this.shape.fill(ctx, dirtyRegion);\n }\n // Reset the canvas context\n ctx.fillStyle = 'black';\n }\n\n if (!this.$hostedComponent)\n this.updateContent(ctx, dirtyRegion);\n\n this.drawBorder(ctx);\n return true;\n }\n\n /**\n * Here is where classes derived from {@link module:boxes/AbstractBox.AbstractBox AbstractBox} should implement the drawing of its\n * content. Background and border are already painted in {@link module:boxes/AbstractBox.AbstractBox#update}.\n * @param {external:CanvasRenderingContext2D} _ctx - The canvas rendering context used to draw the\n * box content.\n * @param {module:AWT.Rectangle} [_dirtyRegion] - The area that must be repainted. `null` refers to the whole box.\n */\n //\n // Abstract method, to be implemented in subclasses\n updateContent(_ctx, _dirtyRegion) {\n }\n\n /**\n * Draws the box border\n * @param {external:CanvasRenderingContext2D} ctx - The canvas rendering context where the border\n * will be drawn.\n */\n drawBorder(ctx) {\n if (this.border || this.marked) {\n const style = this.getBoxBaseResolve();\n\n // Prepare stroke settings\n ctx.strokeStyle = style.borderColor;\n style[this.marked ? 'markerStroke' : 'borderStroke'].setStroke(ctx);\n if (this.marked)\n ctx.globalCompositeOperation = 'xor';\n\n // Draw border\n this.shape.stroke(ctx);\n\n // Reset ctx default values\n if (this.marked)\n ctx.globalCompositeOperation = 'source-over';\n ctx.strokeStyle = 'black';\n Stroke.prototype.setStroke(ctx);\n }\n }\n\n /**\n * Returns the enclosing Rectangle of this box including its border (if any)\n * @returns {module:AWT.Rectangle}\n */\n getBorderBounds() {\n const result = new Rectangle(this.getBounds());\n if (this.border || this.marked) {\n const style = this.getBoxBaseResolve();\n const w = style[this.marked ? 'markerStroke' : 'borderStroke'].lineWidth;\n result.moveBy(-w / 2, -w / 2);\n result.dim.width += w;\n result.dim.height += w;\n }\n return result;\n }\n\n /**\n * Sets the {@link module:boxes/AbstractBox.AbstractBox#$hostedComponent $hostedComponent} member.\n * @param {external:jQuery} $hc - The jQuery DOM component hosted by this box.\n */\n setHostedComponent($hc) {\n if (this.$hostedComponent)\n this.$hostedComponent.detach();\n\n this.$hostedComponent = $hc;\n\n if (this.$hostedComponent) {\n this.setContainer(this.container);\n this.setHostedComponentColors();\n this.setHostedComponentBorder();\n this.setHostedComponentBounds(true);\n this.setHostedComponentVisible();\n this.setFocused(this.focused);\n }\n }\n\n /**\n * Gets the current {@link module:boxes/AbstractBox.AbstractBox#$hostedComponent|$hostedComponent} member\n * @returns {external:jQuery}\n */\n getHostedComponent() {\n return this.$hostedComponent;\n }\n\n /**\n * Sets {@link module:boxes/AbstractBox.AbstractBox#$hostedComponent|$hostedComponent} colors and other css properties\n * based on the current {@link module:boxes/BoxBase.BoxBase BoxBase} of this box.\n */\n setHostedComponentColors() {\n if (this.$hostedComponent) {\n const style = this.getBoxBaseResolve();\n const css = style.getCSS(null, this.inactive, this.inverted, this.alternative);\n // Check if cell has background gradient and animated gif\n if (this.$hostedComponent.data('background-image') && css['background-image'])\n css['background-image'] = `${this.$hostedComponent.data('background-image')},${css['background-image']}`;\n this.$hostedComponent.css(css);\n }\n }\n\n /**\n * Sets the {@link module:boxes/AbstractBox.AbstractBox#$hostedComponent|$hostedComponent} border, based on the current\n * {@link module:boxes/BoxBase.BoxBase BoxBase} of this box.\n */\n setHostedComponentBorder() {\n if (this.$hostedComponent && (this.border || this.marked)) {\n const style = this.getBoxBaseResolve();\n this.$hostedComponent.css({\n 'border-width': `${style.get(this.marked ? 'markerStroke' : 'borderStroke').lineWidth}px`,\n 'border-style': 'solid',\n 'border-color': style.get('borderColor')\n });\n }\n }\n\n /**\n * Places and resizes {@link module:boxes/AbstractBox.AbstractBox#$hostedComponent|$hostedComponent}, based on the size\n * and position of this box.\n * @param {boolean} _sizeChanged - `true` when this {@link module:boxes/ActiveBox.ActiveBox ActiveBox} has changed its size\n */\n setHostedComponentBounds(_sizeChanged) {\n if (this.$hostedComponent) {\n const\n r = this.getBounds(),\n b = this.border || this.marked ? this.getBoxBaseResolve().get(this.marked ? 'markerStroke' : 'borderStroke').lineWidth : 0;\n this.$hostedComponent.css({\n position: 'absolute',\n width: r.dim.width - 2 * b + 'px',\n height: r.dim.height - 2 * b + 'px',\n top: r.pos.y + 'px',\n left: r.pos.x + 'px'\n });\n }\n }\n}\n\nObject.assign(AbstractBox.prototype, {\n /**\n * The parent AbstractBox (can be `null`)\n * @name module:boxes/AbstractBox.AbstractBox#parent\n * @type {module:boxes/AbstractBox.AbstractBox} */\n parent: null,\n /**\n * The Container to which this AbstractBox belongs\n * @name module:boxes/AbstractBox.AbstractBox#container\n * @type {module:AWT.Container} */\n container: null,\n /**\n * The {@link module:boxes/BoxBase.BoxBase BoxBase} related to this AbstractBox. When `null`, the parent can provide an\n * alternative one.\n * @name module:boxes/AbstractBox.AbstractBox#boxBase\n * @type {module:boxes/BoxBase.BoxBase} */\n boxBase: null,\n /**\n * Whether this box has a border or not\n * @name module:boxes/AbstractBox.AbstractBox#border\n * @type {boolean} */\n border: false,\n /**\n * The shape of this box (the box Rectangle or a special Shape, if set)\n * @name module:boxes/AbstractBox.AbstractBox#shape\n * @type {module:AWT.Shape} */\n shape: null,\n /**\n * Whether this box has a shape that is not a rectangle\n * @name module:boxes/AbstractBox.AbstractBox#specialShape\n * @type {boolean} */\n specialShape: false,\n /**\n * Whether this box is visible or not\n * @name module:boxes/AbstractBox.AbstractBox#visible\n * @type {boolean} */\n visible: true,\n /**\n * Used to temporary hide a box while other drawing operations are done\n * @name module:boxes/AbstractBox.AbstractBox#temporaryHidden\n * @type {boolean} */\n temporaryHidden: false,\n /**\n * Cells with this attribute will be transparent but with painted border\n * @name module:boxes/AbstractBox.AbstractBox#tmpTrans\n * @type {boolean}*/\n tmpTrans: false,\n /**\n * Whether this box is active or inactive\n * @name module:boxes/AbstractBox.AbstractBox#inactive\n * @type {boolean} */\n inactive: false,\n /**\n * Whether this box must be displayed with inverted or regular colors\n * @name module:boxes/AbstractBox.AbstractBox#inverted\n * @type {boolean} */\n inverted: false,\n /**\n * Whether this box must be displayed with alternative or regular color and font settings\n * @name module:boxes/AbstractBox.AbstractBox#alternative\n * @type {boolean} */\n alternative: false,\n /**\n * Whether this box is marked (selected) or not\n * @name module:boxes/AbstractBox.AbstractBox#marked\n * @type {boolean} */\n marked: false,\n /**\n * Whether this box holds the input focus\n * @name module:boxes/AbstractBox.AbstractBox#focused\n * @type {boolean} */\n focused: false,\n /**\n * Text to be used in accessible contexts\n * @name module:boxes/AbstractBox.AbstractBox#accessibleText\n * @type {string} */\n accessibleText: '',\n /**\n * Describes the main role of this box on the activity. Useful in wai-aria descriptions.\n * @name module:boxes/AbstractBox.AbstractBox#role\n * @type {string} */\n role: 'cell',\n /**\n * DOM element used to display this cell content in wai-aria contexts\n * @name module:boxes/AbstractBox.AbstractBox#$accessibleElement\n * @type {external:jQuery} */\n $accessibleElement: null,\n /**\n * Flag indicating that $accessibleElement should be always active\n * @name module:boxes/AbstractBox.AbstractBox#accessibleAlwaysActive\n * @type {boolean} */\n accessibleAlwaysActive: false,\n /**\n * An external JQuery DOM element hosted by this box\n * @name module:boxes/AbstractBox.AbstractBox#$hostedComponent\n * @type {external:jQuery} */\n $hostedComponent: null,\n});\n\nexport default AbstractBox;\n","/**\n * File : boxes/BoxBag.js\n * Created : 21/04/2015\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Catalan Educational Telematic Network (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\nimport AbstractBox from './AbstractBox.js';\nimport { Rectangle, Dimension, Point } from '../AWT.js';\nimport { settings } from '../Utils.js';\n\n/**\n * BoxBag is a class derived from {@link module:boxes/AbstractBox.AbstractBox AbstractBox} that contains a collection of \"boxes\"\n * (objects also derived from {@link module:boxes/AbstractBox.AbstractBox AbstractBox}). This class implements methods to add, remove\n * and retrieve boxes, and to manage some of its properties like visibility, status, location and size.\n * @extends module:boxes/AbstractBox.AbstractBox\n */\nexport class BoxBag extends AbstractBox {\n /**\n * BoxBag constructor\n * @param {module:boxes/AbstractBox.AbstractBox} [parent] - The AbstractBox to which this box bag belongs\n * @param {module:AWT.Container} [container] - The container where this box bag is placed.\n * @param {module:boxes/BoxBase.BoxBase} [boxBase] - The object where colors, fonts, border and other graphic properties\n */\n constructor(parent, container, boxBase) {\n // BoxBag extends AbstractBox\n super(parent, container, boxBase);\n this.preferredBounds = new Rectangle();\n this.cells = [];\n }\n\n /**\n * Static method that sets the position and dimension of a `Resizable` object based on a\n * preferred maximum dimension and a margin.\n * @param {module:AWT.Dimension} preferredMaxSize - The preferred maximum size\n * @param {Resizable} rs - A resizable object implementing the methods described in the\n * {@link http://projectestac.github.io/jclic/apidoc/edu/xtec/jclic/boxes/Resizable.html Resizable}\n * interface of JClic. Currently a {@link module:boxes/BoxBag.BoxBag BoxBag} or {@link module:boxes/TextGrid.TextGrid TextGrid}.\n * @param {number} margin - The margin between the available area and the BoxBag\n * @returns {module:AWT.Dimension} - The resulting size of the container\n */\n static layoutSingle(preferredMaxSize, rs, margin) {\n\n // Avoid exceptions when rs is null\n if (!rs)\n return preferredMaxSize;\n\n // optimal, maximal and minimal dimensions\n let\n d = rs.getPreferredSize(),\n minSize = rs.getMinimumSize(),\n maxSize = preferredMaxSize;\n\n // remove margins\n maxSize.width -= 2 * margin;\n maxSize.height -= 2 * margin;\n // correct maxSize if less than minSize\n if (minSize.width > maxSize.width || minSize.height > maxSize.height) {\n maxSize = minSize;\n }\n // compute scale factor\n let scale = d.width > maxSize.width ? maxSize.width / d.width : 1;\n if (scale * d.height > maxSize.height)\n scale = maxSize.height / d.height;\n\n // resize the `Resizable` object\n d = rs.getScaledSize(scale);\n rs.setBounds(margin, margin, d.width, d.height);\n\n // restore margins\n d.width += 2 * margin;\n d.height += 2 * margin;\n\n return d;\n }\n\n /**\n * Static method that sets the position and dimension of two `Resizable` objects based on a\n * preferred maximum size, a layout schema and a margin.\n * @param {module:AWT.Dimension} desiredMaxSize - The preferred maximum size\n * @param {Resizable} rsA - First resizable object implementing the methods described in the\n * {@link http://projectestac.github.io/jclic/apidoc/edu/xtec/jclic/boxes/Resizable.html Resizable}\n * interface of JClic. Currently a {@link module:boxes/BoxBag.BoxBag BoxBag} or {@link module:boxes/TextGrid.TextGrid TextGrid}.\n * @param {Resizable} rsB - Second resizable object\n * @param {string} boxGridPos - The layout schema. Possible values are:\n * - \"AB\" (_A_ at left, _B_ at right)\n * - \"BA\" (_B_ at left, _A_ at right)\n * - \"AUB\" (_A_ above _B_)\n * - \"BUA\" (_A_ below _B_).\n * @param {number} margin - The margin between the available area and the BoxBag\n * @returns {module:AWT.Dimension} - The resulting size of the container\n */\n static layoutDouble(desiredMaxSize, rsA, rsB, boxGridPos, margin) {\n // number of horizontal and vertical grid lines\n let\n isHLayout = false,\n nbh = 1,\n nbv = 1;\n switch (boxGridPos) {\n case 'AB':\n case 'BA':\n nbh = 2;\n nbv = 1;\n isHLayout = true;\n break;\n case 'AUB':\n case 'BUA':\n nbh = 1;\n nbv = 2;\n isHLayout = false;\n break;\n }\n const\n ra = rsA.getBounds(),\n rb = rsB.getBounds();\n\n // optimal dimensions\n let\n da = rsA.getPreferredSize(),\n db = rsB.getPreferredSize();\n\n const d = new Dimension(\n isHLayout ? da.width + db.width : Math.max(da.width, db.width),\n isHLayout ? Math.max(da.height, db.height) : da.height + db.height\n );\n\n // minimal dimensions\n const\n minSizeA = rsA.getMinimumSize(),\n minSizeB = rsB.getMinimumSize(),\n minSize = new Dimension(\n isHLayout ? minSizeA.width + minSizeB.width : Math.max(minSizeA.width, minSizeB.width),\n isHLayout ? Math.max(minSizeA.height, minSizeB.height) : minSizeA.height + minSizeB.height\n ),\n maxSize = desiredMaxSize;\n\n // remove margins\n maxSize.width -= (1 + nbh) * margin;\n maxSize.height -= (1 + nbv) * margin;\n\n // correct maxSize if less than minSize\n if (minSize.width > maxSize.width || minSize.height > maxSize.height)\n maxSize.setDimension(minSize);\n\n // compute scale factor\n let scale = d.width > maxSize.width ? maxSize.width / d.width : 1;\n if (scale * d.height > maxSize.height)\n scale = maxSize.height / d.height;\n\n //\n // correct possible minimal infractions\n // ...\n // resize\n da = rsA.getScaledSize(scale);\n db = rsB.getScaledSize(scale);\n\n // set margins to center one box relative to the other\n let\n dah = db.width > da.width ? (db.width - da.width) / 2 : 0,\n dbh = da.width > db.width ? (da.width - db.width) / 2 : 0,\n dav = db.height > da.height ? (db.height - da.height) / 2 : 0,\n dbv = da.height > db.height ? (da.height - db.height) / 2 : 0;\n\n switch (boxGridPos) {\n case 'AB':\n rsA.setBounds(margin, margin + dav, da.width, da.height);\n rsB.setBounds(2 * margin + da.width, margin + dbv, db.width, db.height);\n break;\n case 'BA':\n rsB.setBounds(margin, margin + dbv, db.width, db.height);\n rsA.setBounds(2 * margin + db.width, margin + dav, da.width, da.height);\n break;\n case 'AUB':\n rsA.setBounds(margin + dah, margin, da.width, da.height);\n rsB.setBounds(margin + dbh, 2 * margin + da.height, db.width, db.height);\n break;\n case 'BUA':\n rsB.setBounds(margin + dbh, margin, db.width, db.height);\n rsA.setBounds(margin + dah, 2 * margin + db.height, da.width, da.height);\n break;\n default:\n rsA.setBounds(\n Math.round(margin + scale * ra.pos.x),\n Math.round(margin + scale * ra.pos.y),\n da.width, da.height);\n rsB.setBounds(\n Math.round(margin + scale * rb.pos.x),\n Math.round(margin + scale * rb.pos.y),\n da.width, da.height);\n break;\n }\n\n // recompute 'd' adding margins\n const r = new Rectangle(rsA.getBounds());\n r.add(rsB.getBounds());\n d.width = r.dim.width + 2 * margin;\n d.height = r.dim.height + 2 * margin;\n\n return d;\n }\n\n /**\n * Gets the preferred size of this `BoxBag`\n * @returns {module:AWT.Dimension}\n */\n getPreferredSize() {\n return this.preferredBounds.dim;\n }\n\n /**\n * Gets the minimum size requested by this `BoxBag`\n * @returns {module:AWT.Dimension}\n */\n getMinimumSize() {\n const d = this.getPreferredSize();\n return new Dimension(\n Math.max(settings.MIN_CELL_SIZE, d.width),\n Math.max(settings.MIN_CELL_SIZE, d.height));\n }\n\n /**\n * Scales the current size of this box bag, multiplying all values by a specific factor\n * @param {number} scale - The scale factor\n * @returns {module:AWT.Dimension}\n */\n getScaledSize(scale) {\n const d = this.getPreferredSize();\n return new Dimension(Math.round(scale * d.width), Math.round(scale * d.height));\n }\n\n /**\n * Adds an {@link module:boxes/AbstractBox.AbstractBox AbstractBox} to the collection of cells\n * @param {module:boxes/AbstractBox.AbstractBox} bx - The box to add\n */\n addBox(bx) {\n this.cells.push(bx);\n bx.setParent(this);\n\n if (this.cells.length === 1)\n Rectangle.prototype.setBounds.call(this, bx);\n else\n this.add(bx);\n\n this.preferredBounds.setBounds(this.getBounds());\n }\n\n /**\n * Returns the index of a specific box in the `cells` array\n * @param {module:boxes/AbstractBox.AbstractBox} bx\n * @returns {number}\n */\n boxIndex(bx) {\n return bx === null ? -1 : this.cells.indexOf(bx);\n }\n\n /**\n * Returns the box at a specific index in the `cells` array\n * @param {number} n - The index\n * @returns {module:boxes/AbstractBox.AbstractBox}\n */\n getBox(n) {\n return n < 0 || n >= this.cells.length ? null : this.cells[n];\n }\n\n /**\n * Gets the background box\n * @returns {module:boxes/AbstractBox.AbstractBox}\n */\n getBackgroundBox() {\n return this.backgroundBox;\n }\n\n /**\n * Sets the background box\n * @param {module:boxes/AbstractBox.AbstractBox} bx\n */\n setBackgroundBox(bx) {\n this.backgroundBox = bx;\n if (bx !== null) {\n bx.setParent(this);\n bx.isBackground = true;\n }\n // Add the `backgroundbox` rectangle to the global BoxBag rectangle\n Rectangle.prototype.add.call(this, bx);\n this.preferredBounds.setBounds(this.getBounds());\n }\n\n /**\n * Recalculates the total size of this BoxBag (useful after direct additions o deletions of\n * elements in the `cells` array).\n * Updates `preferredBounds` and the current position and size of the box bag.\n */\n recalcSize() {\n let r = this.backgroundBox ? new Rectangle(this.backgroundBox.pos, this.backgroundBox.dim) : null;\n this.cells.forEach(cell => {\n if (!r)\n r = new Rectangle(cell.pos, cell.dim);\n else\n r.add(cell);\n });\n if (!r)\n r = new Rectangle(this.pos.x, this.pos.y, 0, 0);\n this.preferredBounds.setRect(r);\n this.x = r.pos.x;\n this.y = r.pos.y;\n this.dim.width = r.dim.width;\n this.dim.height = r.dim.height;\n }\n\n /**\n * Returns the number of cells stored in this BoxBag\n * @returns {number}\n */\n getNumCells() {\n return this.cells.length;\n }\n\n /**\n * Sets the specified key - value pair to all cells of this bag.\n * @param {string} key - The key to be established\n * @param {any} value - The value, of any type\n */\n setCellAttr(key, value) {\n this.cells.forEach(bx => bx[key] = value);\n if (this.backgroundBox)\n this.backgroundBox[key] = value;\n }\n\n /**\n * Overrides {@link module:boxes/AbstractBox.AbstractBox#setBorder} iterating over all the cells stored in this box bag.\n * @override\n * @param {boolean} newVal - Whether to set or unset the border\n */\n setBorder(newVal) {\n this.cells.forEach(bx => bx.setBorder(newVal));\n }\n\n /**\n * Overrides {@link module:boxes/AbstractBox.AbstractBox#setVisible} iterating over all the cells stored in this box bag.\n * @override\n * @param {boolean} newVal - Whether to set the cells visible or not\n */\n setVisible(newVal) {\n this.cells.forEach(bx => bx.setVisible(newVal));\n }\n\n /**\n * Overrides {@link module:boxes/AbstractBox.AbstractBox#setAlternative} iterating over all the cells stored in this box bag.\n * @override\n * @param {boolean} newVal - Whether to set or unset the cells in \"alternative\" mode\n */\n setAlternative(newVal) {\n super.setAlternative(newVal);\n this.cells.forEach(bx => bx.setAlternative(newVal));\n }\n\n /**\n * Overrides {@link module:boxes/AbstractBox.AbstractBox#setBounds} adjusting the position and size of all cells\n * @override\n * @param {(AWT.Rectangle|number)} rect - An AWT.Rectangle object, or the `x` coordinate of the\n * upper-left corner of a new rectangle.\n * @param {number} [ry] - `y` coordinate of the upper-left corner of the new rectangle.\n * @param {number} [rw] - Width of the new rectangle.\n * @param {number} [rh] - Height of the new rectangle.\n */\n setBounds(rect, ry, rw, rh) {\n if (typeof rect === 'number') {\n // Arguments are co-ordinates and size\n rect = new Rectangle(rect, ry, rw, rh);\n }\n if (rect.getSurface() > 0 && !rect.equals(this)) {\n const\n scaleW = rect.dim.width / this.dim.width,\n scaleH = rect.dim.height / this.dim.height,\n dx = rect.pos.x - this.pos.x,\n dy = rect.pos.y - this.pos.y;\n this.cells.forEach(bx => {\n const p = new Point(bx.pos.x - this.pos.x, bx.pos.y - this.pos.y);\n bx.setBounds(\n dx + this.pos.x + scaleW * p.x,\n dy + this.pos.y + scaleH * p.y,\n scaleW * bx.dim.width,\n scaleH * bx.dim.height);\n // Clear pos0\n bx.pos0 = null;\n });\n if (this.backgroundBox !== null) {\n const\n bx = this.backgroundBox,\n p = new Point(bx.pos.x - this.pos.x, bx.pos.y - this.pos.y);\n bx.setBounds(\n dx + this.pos.x + scaleW * p.x,\n dy + this.pos.y + scaleH * p.y,\n scaleW * bx.dim.width,\n scaleH * bx.dim.height);\n }\n }\n super.setBounds(rect);\n }\n\n /**\n * Performs graphics operations for each cell.\n * Overrides {@link module:boxes/AbstractBox.AbstractBox#update}\n * @override\n * @param {external:CanvasRenderingContext2D} ctx - The canvas rendering context used to draw the\n * box contents.\n * @param {module:AWT.Rectangle} [dirtyRegion] - The area that must be repainted. `null` refers to the whole box.\n */\n update(ctx, dirtyRegion) {\n if (this.isEmpty() || !this.isVisible() || this.isTemporaryHidden())\n return false;\n\n if (dirtyRegion && !this.intersects(dirtyRegion))\n return false;\n\n if (this.backgroundBox !== null)\n this.backgroundBox.update(ctx, dirtyRegion);\n\n this.cells.forEach(bx => {\n if (!bx.isMarked())\n bx.update(ctx, dirtyRegion);\n });\n\n // Make a second loop to repaint marked cells\n this.cells.forEach(bx => {\n if (bx.isMarked())\n bx.update(ctx, dirtyRegion);\n });\n return true;\n }\n\n /**\n * Finds the first visible {@link module:boxes/AbstractBox.AbstractBox AbstractBox} located under the specified point\n * @param {module:AWT.Point} p\n * @returns {module:boxes/AbstractBox.AbstractBox}\n */\n findBox(p) {\n let result = null;\n for (let i = this.cells.length - 1; i >= 0; i--) {\n const bx = this.getBox(i);\n if (bx.isVisible() && bx.contains(p)) {\n result = bx;\n break;\n }\n }\n return result;\n }\n\n /**\n * Count the number of cells of this BoxBag that are in \"inactive\" state\n * @returns {number}\n */\n countInactiveCells() {\n return this.cells.reduce((n, bx) => bx.isInactive() ? ++n : n, 0);\n }\n}\n\nObject.assign(BoxBag.prototype, {\n /**\n * The array of cells\n * @name module:boxes/BoxBag.BoxBag#cells\n * @type {module:boxes/AbstractBox.AbstractBox[]} */\n cells: [],\n /**\n * Rectangle containing the preferred bounds of the BoxBag\n * @name module:boxes/BoxBag.BoxBag#preferredBounds\n * @type {module:AWT.Rectangle} */\n preferredBounds: new Rectangle(),\n /**\n * An optional box used as a background by this BoxBag\n * @name module:boxes/BoxBag.BoxBag#backgroundBox\n * @type {module:boxes/AbstractBox.AbstractBox} */\n backgroundBox: null,\n});\n\nexport default BoxBag;\n","/**\n * File : boxes/ActiveBoxBag.js\n * Created : 21/04/2015\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\nimport $ from 'jquery';\nimport BoxBag from './BoxBag.js';\nimport { Point } from '../AWT.js';\n\n/**\n * This class is a special case of {@link module:boxes/BoxBag.BoxBag BoxBag} containing only objects of type {@link module:boxes/ActiveBox.ActiveBox ActiveBox}.\n * In addition to the members and methods of `BoxBag`, it implements specific methods to deal with\n * {@link module:boxes/ActiveBagContent.ActiveBagContent ActiveBagContent} objects and with the other specific members of `ActiveBox` like its \"ids\"\n * (`idOrder`, `idLoc` and `idAss`).\n * @extends module:boxes/BoxBag.BoxBag\n */\nexport class ActiveBoxBag extends BoxBag {\n /**\n * ActiveBoxBag constructor\n * @param {module:boxes/AbstractBox.AbstractBox} [parent] - The AbstractBox to which this box bag belongs\n * @param {module:AWT.Container} [container] - The container where this box bag is placed.\n * @param {module:boxes/BoxBase.BoxBase} [boxBase] - The object where colors, fonts, border and other graphic properties\n * of this box bag are defined.\n */\n constructor(parent, container, boxBase) {\n // ActiveBoxBag extends BoxBag\n super(parent, container, boxBase);\n }\n\n /**\n * Adds an {@link module:boxes/ActiveBox.ActiveBox ActiveBox} to this bag\n * @param {module:boxes/ActiveBox.ActiveBox} bx - The ActiveBox to be added to this bag\n */\n addActiveBox(bx) {\n bx.idLoc = this.cells.length;\n bx.idOrder = bx.idLoc;\n return this.addBox(bx);\n }\n\n /**\n * Finds an ActiveBox by its relative location (`idLoc` field)\n * @param {number} idLoc\n * @returns {module:boxes/ActiveBox.ActiveBox}\n */\n getActiveBox(idLoc) {\n return this.getBox(idLoc);\n }\n\n /**\n * Gets the background box\n * @returns {module:boxes/ActiveBox.ActiveBox}\n */\n getBackgroundActiveBox() {\n return this.getBackgroundBox();\n }\n\n /**\n * Sets the content of members of this ActiveBoxBag, based on one or more {@link module:boxes/ActiveBagContent.ActiveBagContent ActiveBagContent}\n * objects.\n * @param {module:boxes/ActiveBagContent.ActiveBagContent} abc - The main bag of content\n * @param {module:boxes/ActiveBagContent.ActiveBagContent} [altAbc] - The alternative bag of content\n * @param {number} [fromIndex] - Starts taking the cell content located at this position on the bag\n * @param {number} [toCell] - Starts filling the box located at this position on the ActiveBoxBag\n * @param {number} [numCells] - Acts only with a limited number of elements.\n */\n setContent(abc, altAbc, fromIndex, toCell, numCells) {\n if (!fromIndex)\n fromIndex = 0;\n if (!toCell)\n toCell = 0;\n if (!numCells)\n numCells = this.cells.length;\n\n for (let i = 0; i < numCells; i++) {\n const bx = this.getActiveBox(toCell + i);\n bx.setContent(abc, fromIndex + i);\n bx.setAlternative(false);\n if (altAbc)\n bx.setAltContent(altAbc, fromIndex + i);\n }\n\n if (abc.backgroundContent !== null && this.getBackgroundActiveBox() !== null) {\n const bx = this.getBackgroundActiveBox();\n bx.setContent(abc.backgroundContent);\n if (abc.style !== bx.boxBase)\n bx.setBoxBase(abc.style);\n }\n }\n\n /**\n * Finds an ActiveBox by location\n * @param {module:AWT.Point} point - The location to search for\n * @returns {module:boxes/ActiveBox.ActiveBox}\n */\n findActiveBox(point) {\n return this.findBox(point);\n }\n\n /**\n * Clears the content of all boxes\n */\n clearAllBoxes() {\n this.cells.forEach(bx => bx.clear());\n }\n\n /**\n * Clears the content of all boxes and background box\n */\n clearAll() {\n this.clearAllBoxes();\n if (this.backgroundBox !== null)\n this.getBackgroundActiveBox().clear();\n }\n\n /**\n * Count the number of cells that are at its original place\n * @returns {number}\n */\n countCellsAtPlace() {\n return this.cells.reduce((n, bx) => bx.isAtPlace() ? ++n : n, 0);\n }\n\n /**\n * Finds the {@link module:boxes/ActiveBox.ActiveBox ActiveBox} that has the specified `idLoc` attribute\n * @param {number} idLoc - The idLoc to search for\n * @returns {module:boxes/ActiveBox.ActiveBox}\n */\n getActiveBoxWithIdLoc(idLoc) {\n return this.cells.find(bx => bx.idLoc === idLoc) || null;\n }\n\n /**\n * Checks if the place occupied by a cell corresponds to a cell with equivalent content.\n * @param {module:boxes/ActiveBox.ActiveBox} bx - The box to check\n * @param {boolean} checkCase - If `true`, check case when comparing texts\n * @returns {boolean}\n */\n cellIsAtEquivalentPlace(bx, checkCase) {\n return bx.isAtPlace() ||\n bx.isEquivalent(this.getActiveBoxWithIdLoc(bx.idOrder), checkCase);\n }\n\n /**\n * Count the number of cells that are at its original place or equivalent\n * @param {boolean} checkCase - - If `true`, check case when comparing texts\n * @returns {number}\n */\n countCellsAtEquivalentPlace(checkCase) {\n return this.cells.reduce((n, bx) => this.cellIsAtEquivalentPlace(bx, checkCase) ? ++n : n, 0);\n }\n\n /**\n * Counts the number of cells that have the provided `idAss` attribute\n * @param {number} idAss - The `idAss` attribute to search\n * @returns {number}\n */\n countCellsWithIdAss(idAss) {\n return this.cells.reduce((n, bx) => bx.idAss === idAss ? ++n : n, 0);\n }\n\n /**\n * Resets the default `idAss` attribute on all cells\n */\n setDefaultIdAss() {\n this.cells.map(bx => bx.setDefaultIdAss());\n }\n\n /**\n * Shuffles the cells\n * @param {number} times - Number of times to shuffle\n * @param {boolean} fitInArea - Ensure that all cells are inside the bag rectangle\n */\n shuffleCells(times, fitInArea) {\n let nc = this.cells.length;\n if (nc >= 2) {\n // Array of AWT.Point objects\n const\n pos = [],\n idLoc = [],\n p = new Point();\n\n for (let i = 0; i < nc; i++) {\n const bx = this.getActiveBox(i);\n pos[i] = new Point(bx.pos);\n idLoc[i] = bx.idLoc;\n }\n\n for (let i = 0; i < times; i++) {\n const\n r1 = Math.floor(Math.random() * nc),\n r2 = Math.floor(Math.random() * nc);\n if (r1 !== r2) {\n p.moveTo(pos[r1]);\n pos[r1].moveTo(pos[r2]);\n pos[r2].moveTo(p);\n const j = idLoc[r1];\n idLoc[r1] = idLoc[r2];\n idLoc[r2] = j;\n }\n }\n\n for (let i = 0; i < nc; i++) {\n const\n bx = this.getActiveBox(i),\n px = pos[i].x,\n py = pos[i].y;\n bx.moveTo(new Point(px, py));\n if (fitInArea)\n this.fitCellsInArea([bx]);\n bx.idLoc = idLoc[i];\n }\n }\n }\n\n /**\n * Fits cells inside the ActiveBoxBag area. Useful when non-rectangular cells exchange its positions.\n * @param {module:boxes/ActiveBox.ActiveBox[]} boxes - The boxes to be checked\n */\n fitCellsInArea(boxes) {\n const\n maxX = this.pos.x + this.dim.width,\n maxY = this.pos.y + this.dim.height;\n\n boxes.forEach(bx => {\n // Save original position\n if (!bx.pos0)\n bx.pos0 = new Point(bx.pos);\n\n const\n px = Math.min(Math.max(bx.pos.x, this.pos.x), maxX - bx.dim.width),\n py = Math.min(Math.max(bx.pos.y, this.pos.y), maxY - bx.dim.height);\n if (px !== bx.pos.x || py !== bx.pos.y)\n bx.moveTo(new Point(px, py));\n });\n }\n\n /**\n * Exchange the positions of two cells inside the ActiveBoxBag area.\n * @param {module:boxes/ActiveBox.ActiveBox} bxa - The first box\n * @param {module:boxes/ActiveBox.ActiveBox} bxb - The second box\n * @param {boolean} fitInArea - Ensure that all cells are inside the bag rectangle\n */\n swapCellPositions(bxa, bxb, fitInArea) {\n // Save backup of bxb significant properties\n const\n posB = new Point(bxb.pos),\n posB0 = bxb.pos0,\n idLocB = bxb.idLoc;\n\n bxb.moveTo(bxa.pos0 || bxa.pos);\n bxb.pos0 = bxa.pos0;\n bxb.idLoc = bxa.idLoc;\n\n bxa.moveTo(posB0 || posB);\n bxa.pos0 = posB0;\n bxa.idLoc = idLocB;\n\n if (fitInArea)\n this.fitCellsInArea([bxa, bxb]);\n }\n\n /**\n * Resets the IDs of all cells\n */\n resetIds() {\n this.cells.forEach((bx, i) => {\n if (bx) {\n bx.idOrder = i;\n bx.idAss = i;\n bx.idLoc = i;\n }\n });\n }\n\n /**\n * Gets the index of box located in the `cells` array after the provided index, having the\n * provided `idAssValid` value as `idAss` attribute.\n * When `idAssValid` is `null` or `undefined`, search for the next cell with `idAss>0`\n * @param {number} currentItem - The index after to which start scanning\n * @param {string} [idAssValid] - The `idAss` attribute value to search\n * @returns {number}\n */\n getNextItem(currentItem, idAssValid) {\n const IDASSNOTUSED = -12345;\n if (!idAssValid)\n idAssValid = IDASSNOTUSED;\n let i = currentItem + 1;\n for (; i < this.cells.length; i++) {\n const bx = this.cells[i];\n if (!bx)\n break;\n if (idAssValid !== IDASSNOTUSED) {\n if (idAssValid === bx.idAss)\n break;\n } else if (bx.idAss >= 0)\n break;\n }\n return i;\n }\n\n /**\n * Builds a group of hidden `buton` elements that will act as a accessible objects associated\n * to the canvas area of this ActiveBoxBag.\n * The buttons will only be created when `CanvasRenderingContext2D` has a method named `addHitRegion`.\n * See https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Hit_regions_and_accessibility\n * for more information and supported browsers.\n * @param {external:jQuery} $canvas - The `canvas` where this `ActiveBoxBag` will deploy, wrapped up in a jQuery object\n * @param {external:jQuery} $clickReceiver - The DOM element that will be notified when a button is clicked.\n * @param {string} [eventType] - Type of event sent to $clickReceiver. Default is `click`.\n * @returns {external:jQuery} - The $accessibleDiv member, containing the accessible elements associated to this ActiveBoxBag.\n */\n buildAccessibleElements($canvas, $clickReceiver, eventType) {\n this.$accessibleDiv = this.accessibleText !== '' ? $('<div/>', { 'aria-label': this.accessibleText, tabindex: 0 }) : null;\n $canvas.append(this.$accessibleDiv);\n this.cells\n .map(a => a)\n .sort((a, b) => a.idLoc > b.idLoc ? 1 : -1)\n .forEach(bx => bx.buildAccessibleElement($canvas, $clickReceiver, this.$accessibleDiv, eventType));\n return this.$accessibleDiv;\n }\n}\n\nObject.assign(ActiveBoxBag.prototype, {\n /**\n * `div` containing the accessible elements associated to this ActiveBoxBag\n * @name module:boxes/ActiveBoxBag.ActiveBoxBag#$accessibleDiv\n * @type {external:jQuery} */\n $accessibleDiv: null,\n});\n\nexport default ActiveBoxBag;\n","/**\n * File : boxes/ActiveBox.js\n * Created : 18/04/2015\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\n/* global document */\n\nimport $ from 'jquery';\nimport AbstractBox from './AbstractBox.js';\nimport ActiveBoxContent from './ActiveBoxContent.js';\nimport ActiveBagContent from './ActiveBagContent.js';\nimport { Rectangle, Point, Container } from '../AWT.js';\nimport { settings, log, getMsg } from '../Utils.js';\n\n/**\n * Objects of this class are widely used in JClic activities: cells in puzzles and associations,\n * messages and other objects are active boxes.\n *\n * The specific content, size and location of `ActiveBox` objects is determined by its\n * {@link module:boxes/ActiveBoxContent.ActiveBoxContent ActiveBoxContent} member. Most ActiveBoxes have only one content, but some of them can\n * have a secondary or \"alternative\" content stored in the `altContent` field. This content is\n * used only when the `alternative` flag of the ActiveBox is `on`.\n *\n * Active boxes can host video and interactive media content (specified in the `mediaContent`\n * member of the {@link module:boxes/ActiveBoxContent.ActiveBoxContent ActiveBoxContent} through its `hostedMediaPlayer` member.\n * @extends module:boxes/AbstractBox.AbstractBox\n */\nexport class ActiveBox extends AbstractBox {\n /**\n * ActiveBox constructor\n * @param {module:boxes/AbstractBox.AbstractBox} [parent] - The AbstractBox to which this ActiveBox belongs\n * @param {module:AWT.Container} [container] - The container where this box is placed.\n * @param {module:boxes/BoxBase.BoxBase} [boxBase] - The object where colors, fonts, border and other graphic properties\n * of this box are defined.\n * @param {number} [setIdLoc] - A numeric identifier, used to locate this box in a set of sibling objects.\n * @param {module:AWT.Rectangle} [rect] - The initial bounds of the box.\n */\n constructor(parent, container, boxBase, setIdLoc, rect) {\n // ActiveBox extends AbstractBox\n super(parent, container, boxBase);\n this.clear();\n if (typeof setIdLoc === 'number') {\n this.idLoc = setIdLoc;\n this.idAss = 0;\n this.idOrder = 0;\n }\n if (rect)\n this.setBounds(rect);\n }\n\n /**\n * Factory constructor that creates a new cell inside a JQuery DOM element.\n * @param {external:jQuery} $dom - The DOM element that will act as a container\n * @param {module:boxes/ActiveBoxContent.ActiveBoxContent} abc - The cell's content. Must not be null and have the `dimension`\n * member initialized.\n * @returns {module:boxes/ActiveBox.ActiveBox}\n */\n static createCell($dom, abc) {\n if (abc && abc.dimension) {\n const\n box = new ActiveBox(),\n $canvas = $('<canvas width=\"' + abc.dimension.width + '\" height=\"' + abc.dimension.height + '\"/>'),\n rect = new Rectangle(0, 0, abc.dimension.width, abc.dimension.height);\n box.container = new Container();\n box.container.$div = $dom;\n box.setContent(abc);\n box.setBounds(rect);\n $dom.append($canvas);\n // Create accessible, focusable elements only for cells with media content\n // TODO: remove focus mark on blur in cells placed on fillInBlanks activities\n if (abc.mediaContent)\n box.buildAccessibleElement($canvas, $dom);\n box.update($canvas.get(-1).getContext('2d'), rect);\n return box;\n }\n }\n\n /**\n * Returns the current content used by the box\n * @returns {module:boxes/ActiveBoxContent.ActiveBoxContent}\n */\n getCurrentContent() {\n return this.isAlternative() ? this.altContent : this.content;\n }\n\n /**\n * Returns the current content, creating an empty one if needed.\n * @returns {module:boxes/ActiveBoxContent.ActiveBoxContent}\n */\n getContent() {\n if (!this.content)\n this.setContent(new ActiveBoxContent());\n return this.content;\n }\n\n /**\n * Clears the current content\n */\n clear() {\n this.content = null;\n this.altContent = null;\n this.idOrder = -1;\n this.setInactive(true);\n if (!this.hasHostedComponent)\n this.setHostedComponent(null);\n this.setHostedMediaPlayer(null);\n if (this.$accessibleElement)\n this.$accessibleElement.html('');\n if (this.tmpTrans)\n this.tmpTrans = false;\n this.invalidate();\n }\n\n /**\n * Checks if two ActiveBox objects have equivalent content\n * @param {module:boxes/ActiveBox.ActiveBox} bx - The ActiveBox to check against this.\n * @param {boolean} [checkCase] - When `true`, the comparing will be case-sensitive.\n * @returns {boolean} - `true` if both cells are equivalent.\n */\n isEquivalent(bx, checkCase) {\n return bx !== null &&\n this.content !== null &&\n this.content.isEquivalent(bx.content, checkCase);\n }\n\n /**\n * Same functionality as {@link module:boxes/ActiveBox.ActiveBox#isEquivalent isEquivalent}, but comparing the current content.\n * @param {module:boxes/ActiveBox.ActiveBox} bx - The ActiveBox to check against this.\n * @param {boolean} [checkCase] - When `true`, the comparing will be case-sensitive.\n * @returns {boolean}\n */\n isCurrentContentEquivalent(bx, checkCase) {\n return bx !== null &&\n this.getCurrentContent() !== null &&\n this.getCurrentContent().isEquivalent(bx.getCurrentContent(), checkCase);\n }\n\n /**\n * Swaps the location of two active boxes\n * @param {module:boxes/ActiveBox.ActiveBox} bx - The ActiveBox to swap with this one.\n */\n exchangeLocation(bx) {\n const\n pt = new Point(this.pos),\n idLoc0 = this.idLoc;\n this.moveTo(bx.pos);\n bx.moveTo(pt);\n this.idLoc = bx.idLoc;\n bx.idLoc = idLoc0;\n }\n\n /**\n * Copy the content of another ActiveBox into this one\n * @param {module:boxes/ActiveBox.ActiveBox} bx - The ActiveBox from which to take the content\n */\n copyContent(bx) {\n this.idOrder = bx.idOrder;\n this.idAss = bx.idAss;\n this.content = bx.content;\n this.altContent = bx.altContent;\n if (this.content) {\n if (this.content.style)\n this.setBoxBase(this.content.style);\n if (this.content.border !== null && bx.hasBorder() !== this.content.border)\n this.setBorder(this.content.border);\n }\n this.setInactive(bx.isInactive());\n this.setInverted(bx.isInverted());\n this.setAlternative(bx.isAlternative());\n this.setHostedComponent(bx.getHostedComponent());\n this.hasHostedComponent = bx.hasHostedComponent;\n this.setHostedMediaPlayer(bx.hostedMediaPlayer);\n if (this.hostedMediaPlayer)\n this.hostedMediaPlayer.setVisualComponentVisible(!this.isInactive() && this.isVisible());\n if (this.$accessibleElement)\n this.$accessibleElement.html(this.toString());\n }\n\n /**\n *\n * Exhanges the content of this ActiveBox with another one\n * @param {module:boxes/ActiveBox.ActiveBox} bx - The ActiveBox with which to exchange the content.\n */\n exchangeContent(bx) {\n const bx0 = new ActiveBox(this.getParent(), this.getContainerX(), this.boxBase);\n bx0.copyContent(this);\n this.copyContent(bx);\n bx.copyContent(bx0);\n }\n\n /**\n *\n * Sets the text content of this ActiveBox.\n * @param {string} tx - The text to set.\n */\n setTextContent(tx) {\n // only plain text!\n if (!tx)\n tx = '';\n if (!this.content)\n this.content = new ActiveBoxContent();\n this.content.text = tx;\n this.content.mediaContent = null;\n this.content.img = null;\n\n this.setHostedComponent(null);\n this.setInactive(false);\n this.checkHostedComponent();\n this.setHostedMediaPlayer(null);\n\n if (this.$accessibleElement)\n this.$accessibleElement.html(this.toString());\n }\n\n /**\n * Sets the default value to `idAss`\n */\n setDefaultIdAss() {\n this.idAss = this.content === null ? -1 : this.content.id;\n }\n\n /**\n * Checks if this ActiveBox is at its original place.\n * @returns {boolean}\n */\n isAtPlace() {\n return this.idOrder === this.idLoc;\n }\n\n /**\n * Sets the {@link module:boxes/ActiveBoxContent.ActiveBoxContent ActiveBoxContent} of this ActiveBox\n * @param {ActiveBoxContent|ActiveBagContent} abc - Object containing the content to set.\n * @param {number} i - When `abc` is an {@link module:boxes/ActiveBagContent.ActiveBagContent ActiveBagContent}, this field indicates an\n * index in the content array.\n */\n setContent(abc, i) {\n if (abc instanceof ActiveBagContent) {\n if (i < 0)\n i = this.idOrder;\n if (i >= abc.getNumCells())\n return;\n if (abc.style !== this.boxBase)\n this.setBoxBase(abc.style);\n\n // `abc` is now an [ActiveBoxContent](ActiveBoxContent.html)\n abc = abc.getActiveBoxContent(i);\n }\n this.setHostedComponent(null);\n this.setHostedMediaPlayer(null);\n this.content = abc;\n if (abc) {\n if (abc.animatedGifFile && !this.specialShape) {\n const url = `url(${abc.animatedGifFile})`;\n const $hc = $('<span/>').css({\n 'background-image': url,\n 'background-position': 'center',\n 'background-repeat': 'no-repeat'\n });\n // Save background image for later use\n $hc.data('background-image', url);\n\n if (abc.imgClip !== null) {\n $hc.css({\n 'background-origin': 'border-box',\n 'background-position': `${-abc.imgClip.pos.x}px ${-abc.imgClip.pos.y}px`\n // TODO: Use background-size only when the original image must be compressed\n //,'background-size': abc.imgClip.dim.width + 'px ' + abc.imgClip.dim.height + 'px'\n });\n }\n this.setHostedComponent($hc);\n }\n\n if (abc.style !== this.boxBase)\n this.setBoxBase(abc.style);\n\n if (abc.innerHtmlText)\n this.setHostedComponent($('<div/>').html(abc.innerHtmlText));\n\n if (abc.hasOwnProperty('border') && this.hasBorder() !== abc.border)\n this.setBorder(abc.border);\n this.setInactive(false);\n if (abc.amp)\n this.setHostedMediaPlayer(abc.amp);\n this.checkHostedComponent();\n this.checkAutoStartMedia();\n } else\n this.clear();\n\n this.invalidate();\n if (this.$accessibleElement)\n this.$accessibleElement.html(this.toString());\n }\n\n /**\n * Sets the {@link module:boxes/ActiveBoxContent.ActiveBoxContent ActiveBoxContent} that will act as an alternative content (`altContent` field)\n * of this ActiveBox,\n * @param {ActiveBoxContent|ActiveBagContent} abc - Object containing the content to set.\n * @param {number} i - When `abc` is an {@link module:boxes/ActiveBagContent.ActiveBagContent ActiveBagContent}, this field indicates an\n * index in the content array.\n */\n setAltContent(abc, i) {\n if (abc instanceof ActiveBagContent) {\n if (i < 0)\n i = this.idOrder;\n // `abc` is now an [ActiveBoxContent](ActiveBoxContent.html)\n abc = abc.getActiveBoxContent(i);\n }\n this.altContent = abc;\n this.checkHostedComponent();\n if (this.isAlternative() && this.hostedMediaPlayer)\n this.setHostedMediaPlayer(null);\n\n if (this.$accessibleElement) {\n this.$accessibleElement.html(this.toString());\n this.$accessibleElement.prop('disabled', true);\n }\n }\n\n /**\n * Sets the current content of this ActiveBox\n * @param {module:boxes/ActiveBoxContent.ActiveBoxContent} abc - The content to set.\n */\n setCurrentContent(abc) {\n if (this.isAlternative())\n this.setAltContent(abc);\n else\n this.setContent(abc);\n this.invalidate();\n }\n\n /**\n * Puts this ActiveBox in \"alternative\" mode, meaning that `altContent` will be used instead of `content`\n */\n switchToAlt() {\n if (this.isAlternative() || !this.altContent || this.altContent.isEmpty())\n return false;\n this.setHostedComponent(null);\n this.setHostedMediaPlayer(null);\n this.setAlternative(true);\n this.tmpTrans = false;\n this.checkHostedComponent();\n this.checkAutoStartMedia();\n\n if (this.$accessibleElement)\n this.$accessibleElement.html(this.toString());\n\n return true;\n }\n\n /**\n * Checks the presence of content susceptible to be treated as HTML DOM embedded in this ActiveBox.\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Drawing_DOM_objects_into_a_canvas}\n */\n checkHostedComponent() {\n if (this.hasHostedComponent)\n return;\n const\n abc = this.getCurrentContent(),\n style = this.getBoxBaseResolve();\n if (!this.isInactive() && abc && abc.innerHtmlText)\n style.getCSS()['text-align'] = abc.txtAlign.h.replace('middle', 'center');\n }\n\n /**\n * Checks if the call has a {@link module:media/MediaContent.MediaContent} set to `autostart`, and launches it when found.\n */\n checkAutoStartMedia() {\n const cnt = this.getContent();\n if (cnt && cnt.mediaContent && cnt.mediaContent.autoStart && cnt.amp) {\n cnt.amp.playNow(this);\n }\n }\n\n /**\n * Draws the content of this Activebox on the specified canvas context.\n * @override\n * @param {external:CanvasRenderingContext2D} ctx - The canvas rendering context used to draw the\n * box content.\n * @param {module:AWT.Rectangle} [dirtyRegion] - The area that must be repainted. `null` refers to the whole box.\n */\n updateContent(ctx, dirtyRegion) {\n\n const\n abc = this.getCurrentContent(),\n style = this.getBoxBaseResolve();\n\n if (this.isInactive() || !abc || this.dim.width < 2 || this.dim.height < 2) {\n this._focusAccessibleElement(ctx);\n return true;\n }\n\n if (dirtyRegion && !this.intersects(dirtyRegion))\n return false;\n\n let imgRect = null;\n\n if (abc.img && !this.tmpTrans) {\n try {\n if (abc.imgClip) {\n const r = abc.imgClip.getBounds();\n let img = abc.img;\n if (!abc.imgClip.isRect()) {\n // Prepare a temporary `canvas` object that will contain the clipped image\n const tmpCanvas = document.createElement('canvas');\n tmpCanvas.width = r.pos.x + r.dim.width;\n tmpCanvas.height = r.pos.y + r.dim.height;\n const tmpCtx = tmpCanvas.getContext('2d');\n // Set the clipping region\n abc.imgClip.clip(tmpCtx);\n // Draw the original image\n tmpCtx.drawImage(abc.img, 0, 0);\n // Use the temporary canvas as a source image\n // (as seen on: [http://stackoverflow.com/questions/7242006/html5-copy-a-canvas-to-image-and-back])\n img = tmpCanvas;\n }\n ctx.drawImage(img,\n Math.max(0, r.pos.x), Math.max(0, r.pos.y), Math.min(img.width, r.dim.width), Math.min(img.height, r.dim.height),\n this.pos.x, this.pos.y, this.dim.width, this.dim.height);\n } else {\n let\n imgw = abc.img.naturalWidth || this.dim.width,\n imgh = abc.img.naturalHeight || this.dim.height,\n compress = false,\n scale = 1.0;\n if (settings.COMPRESS_IMAGES &&\n (this.dim.width > 0 && this.dim.height > 0) &&\n (imgw > this.dim.width || imgh > this.dim.height)) {\n\n scale = Math.min(this.dim.width / imgw, this.dim.height / imgh);\n imgw *= scale;\n imgh *= scale;\n compress = true;\n }\n const xs = abc.imgAlign.h === 'left' ? 0\n : abc.imgAlign.h === 'right' ? this.dim.width - imgw\n : (this.dim.width - imgw) / 2;\n const ys = abc.imgAlign.v === 'top' ? 0\n : abc.imgAlign.v === 'bottom' ? this.dim.height - imgh\n : (this.dim.height - imgh) / 2;\n if (compress) {\n ctx.drawImage(abc.img, this.pos.x + xs, this.pos.y + ys, imgw, imgh);\n } else\n ctx.drawImage(abc.img, this.pos.x + xs, this.pos.y + ys);\n\n if (abc.avoidOverlapping && abc.text)\n imgRect = new Rectangle(\n Math.max(0, xs), Math.max(0, ys),\n Math.min(this.dim.width, imgw), Math.min(this.dim.height, imgh));\n }\n } catch (ex) {\n log('warn', `Unable to draw image \"${abc.image}\": ${ex.message}`);\n }\n }\n if (abc.text && abc.text.length > 0) {\n let\n px = this.pos.x,\n py = this.pos.y,\n pWidth = this.dim.width,\n pHeight = this.dim.height;\n\n if (imgRect) {\n // There is an image in the ActiveBox\n // Try to compute the current space available for text\n const\n prx = [0, imgRect.pos.x, imgRect.pos.x + imgRect.dim.width, pWidth],\n pry = [0, imgRect.pos.y, imgRect.pos.y + imgRect.dim.height, pHeight],\n rr = [\n // Calc four rectangles inside BoxBag, sourronding imgRect\n // Top rectangle:\n new Rectangle(prx[0], pry[0], prx[3], pry[1]),\n // Bottom rectangle:\n new Rectangle(prx[0], pry[2], prx[3], pry[3] - pry[2]),\n // Left rectangle:\n new Rectangle(prx[0], pry[0], prx[1], pry[3]),\n // Right rectangle:\n new Rectangle(prx[2], pry[0], prx[3] - prx[2], pry[3])\n ];\n //\n // Find the rectangle with highest surface, and in accordance\n // with the `txtAlign` values of the current\n // [ActiveBoxContent](ActiveBoxContent)\n let rmax = rr[0];\n let maxSurface = rmax.dim.width * rmax.dim.height;\n for (let i = 1; i < rr.length; i++) {\n let s = rr[i].dim.width * rr[i].dim.height;\n if (s > maxSurface - 1) {\n if (Math.abs(s - maxSurface) <= 1) {\n let b = false;\n switch (i) {\n case 1:\n b = abc.txtAlign.v === 'bottom';\n break;\n case 2:\n b = abc.txtAlign.h === 'left';\n break;\n case 3:\n b = abc.txtAlign.h === 'right';\n break;\n }\n if (!b)\n continue;\n }\n maxSurface = s;\n rmax = rr[i];\n }\n }\n // Finally, this is the surface available to draw text:\n px += rmax.pos.x;\n py += rmax.pos.y;\n pWidth = rmax.dim.width;\n pHeight = rmax.dim.height;\n }\n\n // Calc available width and height, discounting margins\n const\n availWidth = Math.max(5, pWidth - 2 * style.textMargin),\n availHeight = Math.max(5, pHeight - 2 * style.textMargin);\n\n // Calc the size of each line\n const lines = style.prepareText(ctx, abc.text, availWidth, availHeight);\n\n ctx.font = style.font.cssFont();\n ctx.textBaseline = 'alphabetic';\n const\n lineHeight = style.font.getHeight(),\n totalHeight = lineHeight * lines.length;\n\n // Calc the vertical co-ordinate of the first line\n // Default is 'middle'\n let y = py + style.textMargin + (abc.txtAlign.v === 'top' ? 0\n : abc.txtAlign.v === 'bottom' ? availHeight - totalHeight\n : (availHeight - totalHeight) / 2) + style.font.getMetrics().ascent;\n\n for (let l = 0; l < lines.length; l++, y += lineHeight) {\n // Calc the horizontal position of each line\n // Default is 'middle'\n const x = px + style.textMargin + (abc.txtAlign.h === 'left' ? 0\n : abc.txtAlign.h === 'right' ?\n availWidth - lines[l].size.width\n : (availWidth - lines[l].size.width) / 2);\n\n if (style.shadow) {\n // Render text shadow\n const d = Math.max(1, style.font.size / 10);\n ctx.fillStyle = style.shadowColor;\n ctx.fillText(lines[l].text, x + d, y + d);\n }\n // Render text\n ctx.fillStyle = this.isInverted() ? style.backColor\n : this.isAlternative() ? style.alternativeColor : style.textColor;\n ctx.fillText(lines[l].text, x, y);\n }\n\n this._focusAccessibleElement(ctx);\n\n }\n return true;\n }\n\n /**\n * Draw focus on accessible element if needed\n * @param {external:CanvasRenderingContext2D} ctx - The canvas rendering context used to draw the\n * box content.\n */\n _focusAccessibleElement(ctx) {\n if (settings.CANVAS_DRAW_FOCUS && this.$accessibleElement) {\n this.shape.preparePath(ctx);\n ctx.drawFocusIfNeeded(this.$accessibleElement.get(-1));\n }\n }\n\n\n /**\n * Gets the `description` field of the current {@link module:boxes/ActiveBoxContent.ActiveBoxContent ActiveBoxContent}\n * @returns {string}\n */\n getDescription() {\n return this.content ? this.content.getDescription() : '';\n }\n\n /**\n * Gets a descriptive text for this ActiveBox\n * @returns {string}\n */\n toString() {\n return (this.role !== 'cell' ? getMsg(this.role) : '') + (this.getCurrentContent() || '-').toString();\n }\n\n /**\n * Plays the action or media associated with this ActiveBox\n * @param {module:JClicPlayer.JClicPlayer} ps - Usually, a {@link module:JClicPlayer.JClicPlayer JClicPlayer}\n * @param {function[]} delayedActions - If set, store the the action in this array for future execution\n */\n playMedia(ps, delayedActions = null) {\n const abc = this.getCurrentContent();\n if (abc && abc.mediaContent) {\n log('debug', `Playing: ${abc.mediaContent.toString()}`);\n ps.playMedia(abc.mediaContent, this, delayedActions);\n return true;\n }\n return false;\n }\n\n /**\n * Sets the hosted media player of this ActiveBox\n * @param {module:media/ActiveMediaPlayer.ActiveMediaPlayer} amp - The media player.\n */\n setHostedMediaPlayer(amp) {\n const old = this.hostedMediaPlayer;\n this.hostedMediaPlayer = amp;\n if (old && old !== amp)\n old.linkTo(null);\n if (amp)\n amp.linkTo(this);\n }\n\n /**\n * Sets a new size and/or dimension to this box.\n * @override\n * @param {AWT.Rectangle|number} rect - An AWT.Rectangle object, or the `x` coordinate of the\n * upper-left corner of a new rectangle.\n * @param {number} [y] - `y` coordinate of the upper-left corner of the new rectangle.\n * @param {number} [w] - Width of the new rectangle.\n * @param {number} [h] - Height of the new rectangle.\n */\n setBounds(rect, y, w, h) {\n if (typeof rect === 'number')\n // arguments are co-ordinates and size\n rect = new Rectangle(rect, y, w, h);\n // Rectangle comparision\n if (this.equals(rect))\n return;\n super.setBounds(rect);\n if (this.hostedMediaPlayer)\n this.hostedMediaPlayer.checkVisualComponentBounds(this);\n }\n\n /**\n * Places and resizes {@link module:boxes/AbstractBox.AbstractBox#$hostedComponent $hostedComponent}, based on the size\n * and position of this box.\n * @override\n * @param {boolean} sizeChanged - `true` when this {@link module:boxes/ActiveBox.ActiveBox ActiveBox} has changed its size\n */\n setHostedComponentBounds(sizeChanged) {\n if (this.$hostedComponent) {\n super.setHostedComponentBounds(sizeChanged);\n const abc = this.getCurrentContent();\n if (sizeChanged && abc && abc.animatedGifFile && abc.img) {\n const\n img = abc.img,\n w = Math.max(img.naturalWidth, this.dim.width),\n h = Math.max(img.naturalHeight, this.dim.height);\n let scale = 1, bgSize = '';\n if (abc.imgClip) {\n const r = abc.imgClip.getBounds();\n if (this.dim.width < r.dim.width || this.dim.height < r.dim.height) {\n scale = Math.min(this.dim.width / r.dim.width, this.dim.height / r.dim.height);\n bgSize = `${w * scale}px ${h * scale}px`;\n }\n this.$hostedComponent.css({\n 'background-position': `${-abc.imgClip.pos.x * scale}px ${-abc.imgClip.pos.y * scale}px`,\n 'background-size': bgSize\n });\n } else {\n if (this.dim.width < w || this.dim.height < h) {\n scale = Math.min(this.dim.width / w, this.dim.height / h);\n bgSize = `${w * scale}px ${h * scale}px`;\n }\n this.$hostedComponent.css({\n 'background-size': bgSize\n });\n }\n }\n }\n }\n\n /**\n * Builds a hidden `buton` that will act as a accessible element associated to the canvas area\n * of this ActiveBox.\n * The button will be created only when `CanvasRenderingContext2D` has a method named `addHitRegion`.\n * See https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Hit_regions_and_accessibility\n * for more information and supported browsers.\n * @param {external:jQuery} $canvas - The `canvas` where this `ActiveBox` will deploy, wrapped up in a jQuery object\n * @param {external:jQuery} $clickReceiver - The DOM element that will be notified when `$accessibleElement` is activated.\n * @param {external:jQuery} [$canvasGroup] - Optional DOM element containing the accessible element. Useful to group cells in associations. When `null`, the element belongs to $canvas.\n * @param {string} [eventType] - Type of event sent to $clickReceiver. Default is `click`.\n * @returns {external:jQuery} - The accessible element associated to this ActiveBox.\n */\n buildAccessibleElement($canvas, $clickReceiver, $canvasGroup, eventType) {\n if (this.$accessibleElement)\n this.$accessibleElement.remove();\n\n const canvas = $canvas.get(-1);\n if (canvas.width > 0 && canvas.height > 0) {\n const\n id = Math.round(Math.random() * 100000),\n disabled = this.isInactive() && !this.accessibleAlwaysActive;\n this.$accessibleElement = $('<button/>', {\n tabindex: disabled ? -1 : 0,\n id: `AE${id}`\n })\n .prop('disabled', disabled ? true : null)\n .html(this.toString())\n .on('click', ev => {\n // Check if event was produced by a mouse click\n if (ev.originalEvent && (ev.originalEvent.pageX !== 0 || ev.originalEvent.pageY !== 0)) {\n // Mouse clicks should be processed odirectly by the canvas, so ignore this accessible event\n return true;\n }\n log('debug', `Click on accessible element: ${this.toString()}`);\n const\n $event = $.Event(eventType || 'click'),\n bounds = this.getBounds(),\n offset = $canvas.offset();\n $event.pageX = offset.left + bounds.pos.x + bounds.dim.width / 2;\n $event.pageY = offset.top + bounds.pos.y + bounds.dim.height / 2;\n $clickReceiver.trigger($event);\n return false;\n });\n const $dest = $canvasGroup || $canvas;\n $dest.append(this.$accessibleElement);\n if (settings.CANVAS_DRAW_FOCUS) {\n this.$accessibleElement.on('focus blur', ev => {\n log('debug', `${ev.type} accessible element: ${this.toString()}`);\n if (this.container)\n this.container.update();\n this.updateContent(canvas.getContext('2d'), null);\n });\n }\n }\n return this.$accessibleElement;\n }\n}\n\nObject.assign(ActiveBox.prototype, {\n /**\n * Identifier used to set the relative position of this box in a set.\n * @name module:boxes/ActiveBox.ActiveBox#idOrder\n * @type {number} */\n idOrder: -1,\n /**\n * Identifier used to set a relative position in the space.\n * @name module:boxes/ActiveBox.ActiveBox#idLoc\n * @type {number} */\n idLoc: -1,\n /**\n * Identifier used to establish relationships between cells of different sets (in associations)\n * @name module:boxes/ActiveBox.ActiveBox#idAss\n * @type {number} */\n idAss: -1,\n /**\n * Backup of the original position of the cell, useful when the real position must be restored after a temporary change.\n * @name module:boxes/ActiveBox.ActiveBox#pos0\n * @type {module:AWT.Point} */\n pos0: null,\n /**\n * Main content of this box\n * @name module:boxes/ActiveBox.ActiveBox#content\n * @type {module:boxes/ActiveBoxContent.ActiveBoxContent} */\n content: null,\n /**\n * Alternative content of this box\n * @name module:boxes/ActiveBox.ActiveBox#altContent\n * @type {module:boxes/ActiveBoxContent.ActiveBoxContent} */\n altContent: null,\n /**\n * Flag to check if this box has a 'hosted component'\n * @name module:boxes/ActiveBox.ActiveBox#hostedComponent\n * @type {boolean} */\n hasHostedComponent: false,\n /**\n * The media player associated to this box\n * @name module:boxes/ActiveBox.ActiveBox#hostedMediaPlayer\n * @type {module:media/ActiveMediaPlayer.ActiveMediaPlayer} */\n hostedMediaPlayer: null,\n /**\n * Indicates that this box is used as a background. When drawing, the clipping region must be respected.\n * @name module:boxes/ActiveBox.ActiveBox#isBackground\n * @type {boolean} */\n isBackground: false,\n});\n\nexport default ActiveBox;\n\n","/**\n * File : boxes/ActiveBoxGrid.js\n * Created : 19/05/2015\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Catalan Educational Telematic Network (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\nimport ActiveBoxBag from './ActiveBoxBag.js';\nimport ActiveBox from './ActiveBox.js';\nimport { Rectangle, Dimension, Point } from '../AWT.js';\nimport { settings, roundTo } from '../Utils.js';\n\n/**\n * This class extends {@link module:boxes/ActiveBoxbag.ActiveBoxBag ActiveBoxBag} with constructors that take an argument of type\n * {@link module:shapers/Shaper.Shaper Shaper} used to build all its {@link module:boxes/ActiveBox.ActiveBox ActiveBox}components. It also maintains information\n * about the number of \"rows\" and \"columns\", useful to compute valid (integer) values when\n * resizing or moving its components.\n * @extends module:boxes/ActiveBoxBag.ActiveBoxBag\n */\nexport class ActiveBoxGrid extends ActiveBoxBag {\n /**\n * ActiveBxGrid constructor\n * @param {module:boxes/AbstractBox.AbstractBox} parent - The AbstractBox to which this box grid belongs\n * @param {module:AWT.Container} container - The container where this box grid is placed.\n * @param {module:boxes/BoxBase} boxBase - The object where colors, fonts, border and other graphic properties\n * @param {number} px - `X` coordinate of the upper left corner of this box grid\n * @param {number} py - `Y` coordinate of the upper left corner of this box grid\n * @param {number} setWidth - Total width of the box grid\n * @param {number} setHeight - Total height of the box grid\n * @param {module:shapers/Shaper.Shaper} sh - Shaper used to build the ActiveBox objects\n */\n constructor(parent, container, boxBase, px, py, setWidth, setHeight, sh) {\n // ActiveBoxGrid derives from ActiveBoxBag\n super(parent, container, boxBase);\n\n this.nCols = sh.nCols;\n this.nRows = sh.nRows;\n\n // This will be the enclosing rectangle of this ActiveBox bag\n const r = new Rectangle(\n new Point(px, py),\n new Dimension(\n Math.round(setWidth / this.nCols) * this.nCols,\n Math.round(setHeight / this.nRows) * this.nRows));\n\n // Create all the [ActiveBox](ActiveBox.html) objects based on the\n // shapes provided by the [Shaper](Shaper.html)\n for (let i = 0; i < sh.nCells; i++) {\n const\n tmpSh = sh.getShape(i, r),\n bx = new ActiveBox(this, container, boxBase, i, tmpSh.getBounds());\n if (!sh.rectangularShapes)\n bx.setShape(tmpSh);\n this.addActiveBox(bx);\n }\n\n // If the Shaper has `remainder` (extra space), set the background box of this\n // [BoxBag](BoxBag.html)\n if (sh.hasRemainder) {\n const\n tmpSh = sh.getRemainderShape(r),\n bx = new ActiveBox(this, container, boxBase, 0, tmpSh.getBounds());\n bx.setShape(tmpSh);\n this.setBackgroundBox(bx);\n }\n }\n\n /**\n * This factory constructor creates a new empty grid with the number of cells indicated by the\n * {@link module:boxes/ActiveBagContent.ActiveBagContent ActiveBagContent} `abc`, not filling the cells with any content.\n * @param {module:boxes/AbstractBox.AbstractBox} parent - The AbstractBox to which this box grid belongs\n * @param {module:AWT.Container} container - The container where this box grid is placed.\n * @param {number} px - `X` coordinate of the upper left corner of this box grid\n * @param {number} py - `Y` coordinate of the upper left corner of this box grid\n * @param {module:boxes/ActiveBagContent.ActiveBagContent} abc - Used only to get the number of cells and the shaper (when `sh` is `null`)\n * @param {module:shapers/Shaper.Shaper} sh - Shaper used to build the ActiveBox objects\n * @param {module:boxes/BoxBase.BoxBase} boxBase - The object where colors, fonts, border and other graphic properties\n * of this box grid are defined.\n * @returns {module:boxes/ActiveBoxGrid.ActiveBoxGrid}\n */\n static createEmptyGrid(parent, container, px, py, abc, sh, boxBase) {\n const result = abc ? new ActiveBoxGrid(parent, container,\n boxBase || abc.style,\n px, py,\n abc.getTotalWidth(), abc.getTotalHeight(),\n sh || abc.getShaper()) : null;\n\n if (result)\n result.setBorder(abc.border);\n\n return result;\n }\n\n /**\n * Gets the minimum size of this grid\n * @returns {module:AWT.Dimension}\n */\n getMinimumSize() {\n return new Dimension(\n settings.MIN_CELL_SIZE * this.nCols,\n settings.MIN_CELL_SIZE * this.nRows);\n }\n\n /**\n * Gets a scaled size of this grid, rounded to the nearest integer values\n * @param {number} scale - The scale factor\n * @returns {module:AWT.Dimension}\n */\n getScaledSize(scale) {\n return new Dimension(\n roundTo(scale * this.preferredBounds.dim.width, this.nCols),\n roundTo(scale * this.preferredBounds.dim.height, this.nRows));\n }\n\n /**\n * Returns the logical coordinates of the provided {@link module:boxes/ActiveBox.ActiveBox ActiveBox}.\n * The units of the result are not pixels, but ordinal numbers (relative positions) of columns\n * and rows in the grid.\n * @param {module:boxes/ActiveBox.ActiveBox} bx - The box to process\n * @returns {module:AWT.Point}\n */\n getCoord(bx) {\n return new Point(bx.idLoc % this.nCols, Math.floor(bx.idLoc / this.nCols));\n }\n\n /**\n * Calculates the logical distance between two {@link module:boxes/ActiveBox.ActiveBox ActiveBox} objects.\n * Resulting units are not pixels, but ordinal numbers (relative positions) of columns and rows\n * in the grid.\n * @param {module:boxes/ActiveBox.ActiveBox} src - First box\n * @param {module:boxes/ActiveBox.ActiveBox} dest - Second box\n * @returns {module:AWT.Point}\n */\n getCoordDist(src, dest) {\n const\n ptSrc = this.getCoord(src),\n ptDest = this.getCoord(dest);\n return new Point(ptDest.x - ptSrc.x, ptDest.y - ptSrc.y);\n }\n}\n\nObject.assign(ActiveBoxGrid.prototype, {\n /**\n * Number of columns of this box grid\n * @name module:boxes/ActiveBoxGrid.ActiveBoxGrid#nCols\n * @type {number} */\n nCols: 1,\n /**\n * Number of rows of this box grid\n * @name module:boxes/ActiveBoxGrid.ActiveBoxGrid#nRows\n * @type {number} */\n nRows: 1,\n});\n\nexport default ActiveBoxGrid;\n","/**\n * File : boxes/BoxConnector.js\n * Created : 26/05/2015\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Catalan Educational Telematic Network (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\nimport { Point, Dimension, Rectangle } from '../AWT.js';\n\nconst DEFAULT_COMPOSITE_OP = 'source-over';\n\n/**\n * BoxConnector allows users to visually connect two {@link module:boxes/ActiveBox.ActiveBox ActiveBox} objects of an\n * {@link module:Activity.ActivityPanel ActivityPanel}. There are two modes of operation:\n *\n * - Drawing a line between an origin point (usually the point where the user clicks on) and a\n * destination point.\n * - Dragging the ActiveBox from one location to another.\n *\n * The connecting lines can have arrowheads at its endings.\n */\nexport class BoxConnector {\n /**\n * BoxConnector constructor\n * @param {module:AWT.Container} parent - The Container to which this BoxConnector belongs\n * @param {external:jQuery} $canvas - The HTML `canvas` element where this BoxConnector will draw.\n */\n constructor(parent, $canvas) {\n this.parent = parent;\n this.ctx = $canvas.get(-1).getContext('2d', { willReadFrequently: true });\n this.dim = new Dimension(this.ctx.canvas.width, this.ctx.canvas.height);\n this.origin = new Point();\n this.dest = new Point();\n this.relativePos = new Point();\n }\n\n /**\n * Displaces the ending point of the connector\n * @param {number} dx - Displacement on the X axis\n * @param {number} dy - Displacement on the Y axis\n */\n moveBy(dx, dy) {\n this.moveTo(Point(this.dest.x + dx, this.dest.y + dy));\n }\n\n /**\n * Moves the ending point of the connector to a new position\n * @param {module:AWT.Point} pt - The new position\n * @param {boolean} forcePaint - When `true`, forces the repaint of all the area also if there is\n * no movement at all.\n */\n moveTo(pt, forcePaint) {\n if (!this.active || !forcePaint && this.dest.equals(pt))\n return;\n\n // Restore the background\n if (this.bgRect) {\n if (this.bgImg) {\n this.ctx.putImageData(\n this.bgImg,\n 0, 0,\n this.bgRect.pos.x, this.bgRect.pos.y,\n this.bgRect.dim.width, this.bgRect.dim.height);\n } else if (this.parent)\n this.parent.updateContent();\n }\n\n this.dest.moveTo(pt);\n\n // Calculate the bounds of the invalidated area after the move:\n // Start with the origin point or box area\n const pt1 = new Point(this.origin.x - this.relativePos.x, this.origin.y - this.relativePos.y);\n this.bgRect = new Rectangle(pt1, this.bx ? this.bx.dim : new Dimension());\n // Add the destination point or box area\n const pt2 = new Point(pt.x - this.relativePos.x, pt.y - this.relativePos.y);\n this.bgRect.add(new Rectangle(pt2, this.bx ? this.bx.dim : new Dimension()));\n // Add a generous border around the area\n this.bgRect.grow(10, 10);\n\n if (this.bx !== null) {\n // Move the ActiveBox\n this.bx.moveTo(new Point(pt.x - this.relativePos.x, pt.y - this.relativePos.y));\n this.bx.setTemporaryHidden(false);\n this.bx.update(this.ctx, null);\n this.bx.setTemporaryHidden(true);\n } else {\n // Draw the connecting line\n this.drawLine();\n this.linePainted = true;\n }\n }\n\n /**\n * Starts the box connector operation\n * @param {module:AWT.Point} pt - Starting point\n * @param {module:boxes/ActiveBox.ActiveBox} [box] - Passed only when the BoxConnector runs in drag&drop mode\n */\n begin(pt, box) {\n if (this.active)\n this.end();\n this.origin.moveTo(pt);\n this.dest.moveTo(pt);\n this.linePainted = false;\n this.active = true;\n\n if (box) {\n // Remember what box will be moved, hide it from the panel and repaint all\n this.bx = box;\n this.relativePos.moveTo(pt.x - box.pos.x, pt.y - box.pos.y);\n this.bx.setFocused(true);\n this.bx.setTemporaryHidden(true);\n this.linePainted = false;\n this.parent.invalidate().update();\n }\n\n // Save the full image currently displayed on the panel (with the box hidden)\n try {\n this.bgImg = this.ctx.getImageData(0, 0, this.dim.width, this.dim.height);\n } catch (_ex) {\n // Avoid \"canvas tainted by cross-origin data\" errors\n // Setting bgImg to null is less efficient, but works\n this.bgImg = null;\n }\n this.bgRect = null;\n\n // Make a first movement to make the box appear\n if (box)\n this.moveTo(pt, true);\n }\n\n /**\n * Finalizes the operation of this box connector until a new call to `begin`\n */\n end() {\n if (!this.active)\n return;\n\n this.active = false;\n this.linePainted = false;\n this.bgRect = null;\n this.bgImg = null;\n\n if (this.bx) {\n // Restore the original position and attributes of the box\n this.bx.setFocused(false);\n this.bx.moveTo(this.origin.x - this.relativePos.x, this.origin.y - this.relativePos.y);\n this.bx.setTemporaryHidden(false);\n this.bx = null;\n this.relativePos.moveTo(0, 0);\n }\n\n // Repaint all\n this.ctx.clearRect(0, 0, this.dim.width, this.dim.height);\n this.parent.invalidate().update();\n }\n\n /**\n * Strokes a line between `origin` and `dest`, optionally ended with an arrowhead.\n */\n drawLine() {\n if (this.compositeOp !== DEFAULT_COMPOSITE_OP) {\n this.ctx.strokeStyle = this.xorColor;\n this.ctx.globalCompositeOperation = this.compositeOp;\n } else\n this.ctx.strokeStyle = this.lineColor;\n\n this.ctx.lineWidth = this.lineWidth;\n\n this.ctx.beginPath();\n this.ctx.moveTo(this.origin.x, this.origin.y);\n this.ctx.lineTo(this.dest.x, this.dest.y);\n this.ctx.stroke();\n\n if (this.arrow) {\n // Draws the arrow head\n const\n beta = Math.atan2(this.origin.x - this.dest.x, this.dest.x - this.origin.x),\n arp = new Point(this.dest.x - this.arrowLength * Math.cos(beta + this.arrowAngle),\n this.dest.y + this.arrowLength * Math.sin(beta + this.arrowAngle));\n this.ctx.beginPath();\n this.ctx.moveTo(this.dest.x, this.dest.y);\n this.ctx.lineTo(arp.x, arp.y);\n this.ctx.stroke();\n\n arp.moveTo(this.dest.x - this.arrowLength * Math.cos(beta - this.arrowAngle),\n this.dest.y + this.arrowLength * Math.sin(beta - this.arrowAngle));\n this.ctx.beginPath();\n this.ctx.moveTo(this.dest.x, this.dest.y);\n this.ctx.lineTo(arp.x, arp.y);\n this.ctx.stroke();\n }\n if (this.compositeOp !== DEFAULT_COMPOSITE_OP) {\n // reset default settings\n this.ctx.globalCompositeOperation = DEFAULT_COMPOSITE_OP;\n }\n }\n}\n\nObject.assign(BoxConnector.prototype, {\n /**\n * The background image, saved and redrawn on each movement\n * @name module:boxes/BoxConnector.BoxConnector#bgImg\n * @type {external:HTMLImageElement} */\n bgImg: null,\n /**\n * The rectangle of {@link module:Activity.ActivityPanel ActivityPanel} saved in `bgImg`\n * @name module:boxes/BoxConnector.BoxConnector#bgRect\n * @type {module:AWT.Rectangle} */\n bgRect: null,\n /**\n * Initial position of the connector\n * @name module:boxes/BoxConnector.BoxConnector#origin\n * @type {module:AWT.Point} */\n origin: null,\n /**\n * Current (while moving) and final position of the connector\n * @name module:boxes/BoxConnector.BoxConnector#dest\n * @type {module:AWT.Point} */\n dest: null,\n /**\n * When `true`, the connector must end on arrowhead\n * @name module:boxes/BoxConnector.BoxConnector#arrow\n * @type {boolean} */\n arrow: false,\n /**\n * `true` while the connector is active\n * @name module:boxes/BoxConnector.BoxConnector#active\n * @type {boolean} */\n active: false,\n /**\n * `true` while the line has already been painted (used for XOR expressions)\n * @name module:boxes/BoxConnector.BoxConnector#linePainted\n * @type {boolean} */\n linePainted: false,\n /**\n * The arrowhead length (in pixels)\n * @name module:boxes/BoxConnector.BoxConnector#arrowLength\n * @type {number} */\n arrowLength: 10,\n /**\n * The arrowhead angle\n * @name module:boxes/BoxConnector.BoxConnector#arrowAngle\n * @type {number} */\n arrowAngle: Math.PI / 6,\n /**\n * The main color used in XOR operations\n * @name module:boxes/BoxConnector.BoxConnector#lineColor\n * @type {string} */\n lineColor: 'black',\n /**\n * The complementary color used in XOR operations\n * @name module:boxes/BoxConnector.BoxConnector#xorColor\n * @type {string} */\n xorColor: 'white',\n /**\n * The global composite operator used when drawing in XOR mode. Default is \"difference\".\n * For a list of possible values see:\n * {@link https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation}\n * @name module:boxes/BoxConnector.BoxConnector#compositeOp\n * @type {string} */\n compositeOp: 'difference',\n /**\n * The default {@link https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation composite operator}\n * (\"source-over\").\n * @name module:boxes/BoxConnector.BoxConnector#DEFAULT_COMPOSITE_OP\n * @static\n * @type {string} */\n DEFAULT_COMPOSITE_OP: DEFAULT_COMPOSITE_OP,\n /**\n * Relative position of point B regarding A\n * @name module:boxes/BoxConnector.BoxConnector#relativePos\n * @type {module:AWT.Point} */\n relativePos: null,\n /**\n * The ActiveBox to connect or move\n * @name module:boxes/BoxConnector.BoxConnector#bx\n * @type {module:boxes/ActiveBox.ActiveBox} */\n bx: null,\n /**\n * The Graphics context where the BoxConnector will paint\n * @name module:boxes/BoxConnector.BoxConnector#ctx\n * @type {external:CanvasRenderingContext2D} */\n ctx: null,\n /**\n * The dimension of the HTML canvas where to draw\n * @name module:boxes/BoxConnector.BoxConnector#dim\n * @type {module:AWT.Dimension} */\n dim: null,\n /**\n * The container to which this connector belongs\n * @name module:boxes/BoxConnector.BoxConnector#parent\n * @type {module:AWT.Container} */\n parent: null,\n /**\n * Width of the connector line\n * @name module:boxes/BoxConnector.BoxConnector#lineWidth\n * @type {number} */\n lineWidth: 1.5,\n});\n\nexport default BoxConnector;\n","/**\n * File : activities/associations/SimpleAssociation.js\n * Created : 02/06/2015\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Catalan Educational Telematic Network (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\nimport $ from 'jquery';\nimport { Activity, ActivityPanel } from '../../Activity.js';\nimport ActiveBoxGrid from '../../boxes/ActiveBoxGrid.js';\nimport BoxBag from '../../boxes/BoxBag.js';\nimport BoxConnector from '../../boxes/BoxConnector.js';\nimport { Rectangle, Point } from '../../AWT.js';\nimport { getMsg } from '../../Utils.js';\n\n/**\n * This class of {@link module:Activity.Activity Activity} uses two panels (`primary` and `secondary`) formed by\n * {@link module:boxes/ActiveBox.ActiveBox ActiveBox} objects filled with data stored in {@link module:boxes/ActiveBagContent.ActiveBagContent ActiveBagContent} repositories.\n *\n * Both panels have the same number of elements, associated one-to-one. A third {@link module:boxes/ActiveBagContent.ActiveBagContent ActiveBagContent}\n * can be used as alternative content, that will be revealed in the `primary` panel as the pairings\n * of its cells are solved.\n * @extends module:Activity.Activity\n */\nexport class SimpleAssociation extends Activity {\n /**\n * SimpleAssociation constructor\n * @param {module:project/JClicProject.JClicProject} project - The JClic project to which this activity belongs\n */\n constructor(project) {\n super(project);\n }\n\n /**\n * Retrieves the minimum number of actions needed to solve this activity.\n * @override\n * @returns {number}\n */\n getMinNumActions() {\n return this.abc.primary.getNumCells();\n }\n\n /**\n * Whether or not the activity uses random to shuffle internal components\n * @override\n * @returns {boolean}\n */\n hasRandom() {\n return true;\n }\n\n /**\n * When `true`, the activity must always be shuffled\n * @override\n * @returns {boolean}\n */\n shuffleAlways() {\n return true;\n }\n\n /**\n * Whether the activity allows the user to request help.\n * @override\n * @returns {boolean}\n */\n helpSolutionAllowed() {\n return true;\n }\n}\n\nObject.assign(SimpleAssociation.prototype, {\n /**\n * When `true`, the cell's `idAss` field will be used to check pairing matches.\n * @name module:activities/associations/SimpleAssociation.SimpleAssociation#useIdAss\n * @type {boolean} */\n useIdAss: false,\n});\n\n/**\n * The {@link module:Activity.ActivityPanel ActivityPanel} where {@link module:activities/associations/SimpleAssociation.SimpleAssociation SimpleAssociation} activities are played.\n * @extends module:Activity.ActivityPanel ActivityPanel\n */\nexport class SimpleAssociationPanel extends ActivityPanel {\n /**\n * SimpleAssociationPanel constructor\n * @param {module:Activity.Activity} act - The {@link module:Activity.Activity Activity} to which this Panel belongs\n * @param {module:JClicPlayer.JClicPlayer} ps - Any object implementing the methods defined in the\n * [PlayStation](http://projectestac.github.io/jclic/apidoc/edu/xtec/jclic/PlayStation.html) Java interface.\n * @param {external:jQuery} [$div] - The jQuery DOM element where this Panel will deploy\n */\n constructor(act, ps, $div) {\n super(act, ps, $div);\n }\n\n /**\n * Performs miscellaneous cleaning operations\n * @override\n */\n clear() {\n if (this.bgA) {\n this.bgA.end();\n this.bgA = null;\n }\n if (this.bgB) {\n this.bgB.end();\n this.bgB = null;\n }\n }\n\n /**\n * Prepares the visual components of the activity\n * @override\n */\n buildVisualComponents() {\n if (this.firstRun)\n super.buildVisualComponents();\n\n this.clear();\n\n const\n abcA = this.act.abc['primary'],\n abcB = this.act.abc['secondary'],\n solved = this.act.abc['solvedPrimary'];\n\n if (abcA && abcB) {\n if (abcA.image) {\n abcA.setImgContent(this.act.project.mediaBag, null, false);\n if (abcA.animatedGifFile && !abcA.shaper.rectangularShapes && !this.act.shuffleA)\n this.$animatedBg = $('<span/>').css({\n 'background-image': `url(${abcA.animatedGifFile})`,\n 'background-position': 'center',\n 'background-repeat': 'no-repeat',\n position: 'absolute'\n }).appendTo(this.$div);\n }\n\n if (abcB.image) {\n abcB.setImgContent(this.act.project.mediaBag, null, false);\n if (abcB.animatedGifFile && !abcB.shaper.rectangularShapes && !this.act.shuffleB)\n this.$animatedBgB = $('<span/>').css({\n 'background-image': `url(${abcB.animatedGifFile})`,\n 'background-position': 'center',\n 'background-repeat': 'no-repeat',\n position: 'absolute'\n }).appendTo(this.$div);\n }\n\n if (solved && solved.image)\n solved.setImgContent(this.act.project.mediaBag, null, false);\n\n if (this.act.acp !== null) {\n const contentKit = [abcA, abcB];\n if (solved)\n contentKit.push(solved);\n this.act.acp.generateContent(abcA.nch, abcA.ncw, contentKit, false);\n }\n\n this.bgA = ActiveBoxGrid.createEmptyGrid(null, this, this.act.margin, this.act.margin, abcA);\n this.bgB = ActiveBoxGrid.createEmptyGrid(null, this, this.act.margin, this.act.margin, abcB);\n\n this.bgA.setContent(abcA, solved ? solved : null);\n if (this.$animatedBg)\n this.bgA.setCellAttr('tmpTrans', true);\n\n this.bgB.setContent(abcB);\n if (this.$animatedBgB)\n this.bgB.setCellAttr('tmpTrans', true);\n\n this.bgA.accessibleText = getMsg('source');\n this.bgB.accessibleText = getMsg('target');\n\n this.bgA.setVisible(true);\n this.bgB.setVisible(true);\n }\n }\n\n /**\n * Basic initialization procedure\n * @override\n */\n initActivity() {\n super.initActivity();\n if (!this.firstRun)\n this.buildVisualComponents();\n else\n this.firstRun = false;\n\n if (this.bgA && this.bgB) {\n // Scramble cells\n const shuffleArray = [];\n if (this.act.shuffleA)\n shuffleArray.push(this.bgA);\n if (this.act.shuffleB)\n shuffleArray.push(this.bgB);\n if (shuffleArray.length > 0) {\n this.shuffle(shuffleArray, true, true);\n }\n\n if (this.useOrder)\n this.currentItem = this.bgA.getNextItem(-1);\n\n this.invalidate().update();\n this.setAndPlayMsg('initial', 'start');\n this.playing = true;\n }\n }\n\n /**\n * Updates the graphic content of this panel.\n * This method will be called from {@link module:AWT.Container#update} when needed.\n * @override\n * @param {module:AWT.Rectangle} dirtyRegion - Specifies the area to be updated. When `null`,\n * it's the whole panel.\n */\n updateContent(dirtyRegion) {\n super.updateContent(dirtyRegion);\n if (this.bgA && this.bgB && this.$canvas) {\n const\n canvas = this.$canvas.get(-1),\n ctx = canvas.getContext('2d');\n if (!dirtyRegion)\n dirtyRegion = new Rectangle(0, 0, canvas.width, canvas.height);\n ctx.clearRect(dirtyRegion.pos.x, dirtyRegion.pos.y, dirtyRegion.dim.width, dirtyRegion.dim.height);\n this.bgA.update(ctx, dirtyRegion);\n this.bgB.update(ctx, dirtyRegion);\n }\n return this;\n }\n\n /**\n * Sets the real dimension of this panel.\n * @override\n * @param {module:AWT.Dimension} preferredMaxSize - The maximum surface available for the activity panel\n * @returns {module:AWT.Dimension}\n */\n setDimension(preferredMaxSize) {\n return !this.bgA || !this.bgB || this.getBounds().equals(preferredMaxSize) ?\n preferredMaxSize :\n BoxBag.layoutDouble(preferredMaxSize, this.bgA, this.bgB, this.act.boxGridPos, this.act.margin);\n }\n\n /**\n * Sets the size and position of this activity panel\n * @override\n * @param {module:AWT.Rectangle} rect\n */\n setBounds(rect) {\n if (this.$canvas)\n this.$canvas.remove();\n\n super.setBounds(rect);\n if (this.bgA || this.bgB) {\n // Create the main canvas\n this.$canvas = $(`<canvas width=\"${rect.dim.width}\" height=\"${rect.dim.height}\"/>`).css({\n position: 'absolute',\n top: 0,\n left: 0\n });\n // Resize animated gif background A\n if (this.$animatedBg && this.bgA) {\n const bgRect = this.bgA.getBounds();\n this.$animatedBg.css({\n left: bgRect.pos.x,\n top: bgRect.pos.y,\n width: bgRect.dim.width + 'px',\n height: bgRect.dim.height + 'px',\n 'background-size': `${bgRect.dim.width}px ${bgRect.dim.height}px`\n });\n }\n // Resize animated gif background B\n if (this.$animatedBgB && this.bgB) {\n const bgRectB = this.bgB.getBounds();\n this.$animatedBgB.css({\n left: bgRectB.pos.x,\n top: bgRectB.pos.y,\n width: bgRectB.dim.width + 'px',\n height: bgRectB.dim.height + 'px',\n 'background-size': `${bgRectB.dim.width}px ${bgRectB.dim.height}px`\n });\n }\n this.$div.append(this.$canvas);\n\n // Create a [BoxConnector](BoxConnector.html) and attach it to the canvas context\n this.bc = new BoxConnector(this, this.$canvas);\n\n // Repaint all\n this.invalidate().update();\n }\n }\n\n /**\n * Builds the accessible components needed for this ActivityPanel\n * This method is called when all main elements are placed and visible, when the activity is ready\n * to start or when resized.\n * @override\n */\n buildAccessibleComponents() {\n if (this.$canvas && this.accessibleCanvas) {\n super.buildAccessibleComponents();\n if (this.bgA)\n this.bgA.buildAccessibleElements(this.$canvas, this.$div, 'mousedown');\n if (this.bgB)\n this.bgB.buildAccessibleElements(this.$canvas, this.$div, 'mousedown');\n }\n }\n\n /**\n * Main handler used to process mouse, touch, keyboard and edit events\n * @override\n * @param {external:Event} event - The HTML event to be processed\n * @returns {boolean} - When this event handler returns `false`, jQuery will stop its\n * propagation through the DOM tree. See: {@link http://api.jquery.com/on}\n */\n processEvent(event) {\n if (this.bc && this.playing) {\n //\n // The [AWT.Point](AWT.html#Point) where the mouse or touch event has been originated\n // and two [ActiveBox](ActiveBox.html) pointers used for the [BoxConnector](BoxConnector.html)\n // `origin` and `dest` points.\n let p = null, bx1, bx2;\n //\n // _touchend_ event don't provide pageX nor pageY information\n if (event.type === 'touchend')\n p = this.bc.active ? this.bc.dest.clone() : new Point();\n else {\n // Touch events can have more than one touch, so `pageX` must be obtained from `touches[0]`\n const\n x = event.originalEvent && event.originalEvent.touches ? event.originalEvent.touches[0].pageX : event.pageX,\n y = event.originalEvent && event.originalEvent.touches ? event.originalEvent.touches[0].pageY : event.pageY;\n p = new Point(x - this.$div.offset().left, y - this.$div.offset().top);\n }\n\n // Flag for tracking `mouseup` events\n let up = false,\n // Flag for assuring that only one media plays per event (avoid event sounds overlapping\n // cell's media sounds)\n m = false,\n // Flag for tracking clicks on the background of grid A\n clickOnBg0 = false,\n // Array to be filled with actions to be executed at the end of event processing\n delayedActions = [];\n\n switch (event.type) {\n case 'touchcancel':\n // Canvel movement\n if (this.bc.active)\n this.bc.end();\n break;\n\n case 'mouseup':\n // Don't consider drag moves below 3 pixels. Can be a \"trembling click\"\n if (this.bc.active && p.distanceTo(this.bc.origin) <= 3) {\n break;\n }\n up = true;\n /* falls through */\n case 'touchend':\n case 'touchstart':\n case 'mousedown':\n if (!this.bc.active) {\n // A new pairing starts\n //\n // Pairings can never start with a `mouseup` event\n if (up)\n break;\n\n this.ps.stopMedia(1);\n //\n // Determine if click was done on panel A or panel B\n bx1 = this.bgA ? this.bgA.findActiveBox(p) : null;\n bx2 = this.bgB ? this.bgB.findActiveBox(p) : null;\n if (bx1 && (!this.act.useOrder || bx1.idOrder === this.currentItem) ||\n !this.act.useOrder && bx2 && bx2.idAss !== -1) {\n // Start the [BoxConnector](BoxConnector.html)\n if (this.act.dragCells)\n this.bc.begin(p, bx1 || bx2);\n else\n this.bc.begin(p);\n // Play cell media or event sound\n m = m || (bx1 || bx2).playMedia(this.ps, delayedActions);\n if (!m)\n this.playEvent('click');\n\n // Move the focus to the opposite accessible group\n let bg = bx1 ? this.bgA : this.bgB;\n if (bg && bg.$accessibleDiv) {\n bg = bx1 ? this.bgB : this.bgA;\n if (bg && bg.$accessibleDiv)\n bg.$accessibleDiv.trigger('focus');\n }\n }\n } else {\n this.ps.stopMedia(1);\n // Pairing completed\n //\n // Find the active boxes behind `bc.origin` and `p`\n const origin = this.bc.origin;\n this.bc.end();\n bx1 = this.bgA ? this.bgA.findActiveBox(origin) : null;\n if (bx1) {\n bx2 = this.bgB ? this.bgB.findActiveBox(p) : null;\n } else {\n bx2 = this.bgB ? this.bgB.findActiveBox(origin) : null;\n if (bx2) {\n bx1 = this.bgA ? this.bgA.findActiveBox(p) : null;\n clickOnBg0 = true;\n }\n }\n // Check if the pairing was correct\n if (bx1 && bx2 && bx1.idAss !== -1 && bx2.idAss !== -1 && this.act.abc['secondary']) {\n let ok = false;\n const\n src = bx1.getDescription(),\n dest = bx2.getDescription(),\n matchingDest = this.act.abc['secondary'].getActiveBoxContent(bx1.idOrder);\n if (bx1.idOrder === bx2.idOrder || bx2.getContent().isEquivalent(matchingDest, true)) {\n // Pairing is OK. Play media and disable involved cells\n ok = true;\n bx1.idAss = -1;\n bx2.idAss = -1;\n if (this.act.abc['solvedPrimary']) {\n bx1.switchToAlt(this.ps);\n m = m || bx1.playMedia(this.ps, delayedActions);\n } else {\n if (clickOnBg0)\n m = m || bx1.playMedia(this.ps, delayedActions);\n else\n m = m || bx2.playMedia(this.ps, delayedActions);\n bx1.clear();\n }\n bx2.clear();\n\n if (this.act.useOrder && this.bgA)\n // Load next item\n this.currentItem = this.bgA.getNextItem(this.currentItem);\n }\n // Check results and notify action\n const cellsPlaced = this.bgB ? this.bgB.countCellsWithIdAss(-1) : 0;\n this.ps.reportNewAction(this.act, 'MATCH', src, dest, ok, cellsPlaced);\n // End activity or play event sound\n if (ok && cellsPlaced === this.bgB.getNumCells())\n this.finishActivity(true);\n else if (!m)\n this.playEvent(ok ? 'actionOk' : 'actionError');\n }\n this.update();\n\n // Move the focus to the `source` accessible group\n if (this.bgA && this.bgA.$accessibleDiv)\n this.bgA.$accessibleDiv.trigger('focus');\n }\n break;\n\n case 'mousemove':\n case 'touchmove':\n this.bc.moveTo(p);\n break;\n }\n delayedActions.forEach(action => action());\n event.preventDefault();\n }\n }\n}\n\nObject.assign(SimpleAssociationPanel.prototype, {\n /**\n * The {@link module:boxes/ActiveBoxbag.ActiveBoxBag ActiveBoxBag} object containing the information to be displayed in the `primary` panel\n * @name module:activities/associations/SimpleAssociation.SimpleAssociationPanel#bgA\n * @type {module:boxes/ActiveBoxBag.ActiveBoxBag} */\n bgA: null,\n /**\n * The {@link module:boxes/ActiveBoxbag.ActiveBoxBag ActiveBoxBag} object containing the information to be displayed in the `secondary` panel\n * @name module:activities/associations/SimpleAssociation.SimpleAssociationPanel#bgB\n * @type {module:boxes/ActiveBoxBag.ActiveBoxBag} */\n bgB: null,\n /**\n * The box connector\n * @name module:activities/associations/SimpleAssociation.SimpleAssociationPanel#bc\n * @type {module:boxes/BoxConnector.BoxConnector} */\n bc: null,\n /**\n * List of mouse, touch and keyboard events intercepted by this panel\n * @override\n * @name module:activities/associations/SimpleAssociation.SimpleAssociationPanel#events\n * @type {string[]} */\n events: ['mousedown', 'mouseup', 'mousemove', 'touchstart', 'touchend', 'touchmove', 'touchcancel'],\n});\n\n/**\n * Panel class associated to this type of activity: {@link module:activities/associations/SimpleAssociation.SimpleAssociationPanel SimpleAssociationPanel}\n * @type {class} */\nSimpleAssociation.Panel = SimpleAssociationPanel;\n\n// Register activity class\nexport default Activity.registerClass('@associations.SimpleAssociation', SimpleAssociation);\n","/**\n * File : activities/associations/ComplexAssociation.js\n * Created : 03/06/2015\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\n\nimport Activity from '../../Activity.js';\nimport { Point } from '../../AWT.js';\nimport { SimpleAssociation, SimpleAssociationPanel } from './SimpleAssociation.js';\n\n/**\n * This is a special case of {@link module:activities/associations/SimpleAssociation.SimpleAssociation SimpleAssociation} where the elements of the 'secondary' panel\n * can have zero, one or more associated elements in the 'primary' panel.\n * @extends module:activities/associations/SimpleAssociation.SimpleAssociation\n */\nexport class ComplexAssociation extends SimpleAssociation {\n /**\n * ComplexAssociation constructor\n * @param {module:project/JClicProject.JClicProject} project - The JClic project to which this activity belongs\n */\n constructor(project) {\n super(project);\n this.useIdAss = true;\n }\n\n /**\n * Loads this object settings from an XML element\n * @override\n * @param {external:jQuery} $xml - The jQuery XML element to parse\n */\n setProperties($xml) {\n super.setProperties($xml);\n this.abc['primary'].avoidAllIdsNull(this.abc['secondary'].getNumCells());\n }\n\n /**\n * Retrieves the minimum number of actions needed to solve this activity.\n * @override\n * @returns {number}\n */\n getMinNumActions() {\n if (this.invAss)\n return this.abc['secondary'].getNumCells();\n else\n return this.abc['primary'].getNumCells() - this.nonAssignedCells;\n }\n}\n\nObject.assign(ComplexAssociation.prototype, {\n /**\n * Number of unassigned cells\n * @name module:activities/associations/ComplexAssociation.ComplexAssociation#nonAssignedCells\n * @type {number} */\n nonAssignedCells: 0,\n /**\n * Uses cell's `idAss` field to check if pairings match\n * @name module:activities/associations/ComplexAssociation.ComplexAssociation#useIdAss\n * @type {boolean} */\n useIdAss: false,\n});\n\n/**\n * The {@link module:Activity.ActivityPanel ActivityPanel} where {@link module:activities/associations/ComplexAssociation.ComplexAssociation ComplexAssociation} activities are played.\n * @extends module:activities/associations/SimpleAssociation.SimpleAssociationPanel\n */\nexport class ComplexAssociationPanel extends SimpleAssociationPanel {\n /**\n * ComplexAssociationPanel prototype\n * @param {module:Activity.Activity} act - The {@link module:Activity.Activity Activity} to which this Panel belongs\n * @param {module:JClicPlayer.JClicPlayer} ps - Any object implementing the methods defined in the\n * [PlayStation](http://projectestac.github.io/jclic/apidoc/edu/xtec/jclic/PlayStation.html) Java interface.\n * @param {external:jQuery} [$div] - The jQuery DOM element where this Panel will deploy\n */\n constructor(act, ps, $div) {\n super(act, ps, $div);\n }\n\n /**\n * Prepares the visual components of the activity\n * @override\n */\n buildVisualComponents() {\n super.buildVisualComponents();\n\n const\n abcA = this.act.abc['primary'],\n abcB = this.act.abc['secondary'];\n\n if (abcA && abcB) {\n if (this.act.invAss)\n this.invAssCheck = Array(abcB.getNumCells()).fill(false);\n this.bgA.setDefaultIdAss();\n this.act.nonAssignedCells = 0;\n this.bgA.cells.forEach(bx => {\n if (bx.idAss === -1) {\n this.act.nonAssignedCells++;\n bx.switchToAlt(this.ps);\n }\n });\n }\n }\n\n /**\n * Checks if all inverse associations are done\n * @returns {boolean}\n */\n checkInvAss() {\n if (!this.act.invAss || !this.invAssCheck)\n return false;\n return this.invAssCheck.every(chk => chk);\n }\n\n /**\n * Main handler used to process mouse, touch, keyboard and edit events\n * @override\n * @param {external:Event} event - The HTML event to be processed\n * @returns {boolean} - When this event handler returns `false`, jQuery will stop its\n * propagation through the DOM tree. See: {@link http://api.jquery.com/on}\n */\n processEvent(event) {\n if (this.bc && this.playing) {\n //\n // The [AWT.Point](AWT.html#Point) where the mouse or touch event has been originated\n // and two [ActiveBox](ActiveBox.html) pointers used for the [BoxConnector](BoxConnector.html)\n // `origin` and `dest` points.\n let p = null, bx1, bx2;\n\n //\n // _touchend_ event don't provide pageX nor pageY information\n if (event.type === 'touchend') {\n p = this.bc.active ? this.bc.dest.clone() : new Point();\n } else {\n // Touch events can have more than one touch, so `pageX` must be obtained from `touches[0]`\n let\n x = event.originalEvent && event.originalEvent.touches ? event.originalEvent.touches[0].pageX : event.pageX,\n y = event.originalEvent && event.originalEvent.touches ? event.originalEvent.touches[0].pageY : event.pageY;\n p = new Point(x - this.$div.offset().left, y - this.$div.offset().top);\n }\n\n let\n // Flag for tracking `mouseup` events\n up = false,\n // Flag for assuring that only one media plays per event (avoid event sounds overlapping\n // cell's media sounds)\n m = false,\n // Flag for tracking clicks on the background of grid A\n clickOnBg0 = false,\n // Array to be filled with actions to be executed at the end of event processing\n delayedActions = [];\n\n switch (event.type) {\n case 'touchcancel':\n // Canvel movement\n if (this.bc.active)\n this.bc.end();\n break;\n\n case 'mouseup':\n // Don't consider drag moves below 3 pixels. Can be a \"trembling click\"\n if (this.bc.active && p.distanceTo(this.bc.origin) <= 3) {\n break;\n }\n up = true;\n /* falls through */\n case 'touchend':\n case 'touchstart':\n case 'mousedown':\n if (!this.bc.active) {\n // New pairing starts\n //\n // Pairings can never start with a `mouseup` event\n if (up)\n break;\n\n this.ps.stopMedia(1);\n // Determine if click was done on panel A or panel B\n bx1 = this.bgA ? this.bgA.findActiveBox(p) : null;\n bx2 = this.bgB ? this.bgB.findActiveBox(p) : null;\n if (bx1 && bx1.idAss !== -1 && (!this.act.useOrder || bx1.idOrder === this.currentItem) ||\n !this.act.useOrder && bx2) {\n // Start the [BoxConnector](BoxConnector.html)\n if (this.act.dragCells)\n this.bc.begin(p, bx1 || bx2);\n else\n this.bc.begin(p);\n // Play cell media or event sound\n m = m || (bx1 || bx2).playMedia(this.ps, delayedActions);\n if (!m)\n this.playEvent('click');\n }\n\n // Move the focus to the opposite accessible group\n let bg = bx1 ? this.bgA : this.bgB;\n if (bg && bg.$accessibleDiv) {\n bg = bx1 ? this.bgB : this.bgA;\n if (bg && bg.$accessibleDiv)\n bg.$accessibleDiv.trigger('focus');\n }\n } else {\n this.ps.stopMedia(1);\n // Pairing completed\n //\n // Find the active boxes behind `bc.origin` and `p`\n const origin = this.bc.origin;\n this.bc.end();\n bx1 = this.bgA ? this.bgA.findActiveBox(origin) : null;\n if (bx1) {\n bx2 = this.bgB ? this.bgB.findActiveBox(p) : null;\n } else {\n bx2 = this.bgB ? this.bgB.findActiveBox(origin) : null;\n if (bx2) {\n bx1 = this.bgA ? this.bgA.findActiveBox(p) : null;\n clickOnBg0 = true;\n }\n }\n // Check if the pairing was correct\n if (bx1 && bx2 && bx1.idAss !== -1 && !bx2.isInactive() && this.act.abc['secondary']) {\n const\n src = bx1.getDescription(),\n dest = bx2.getDescription(),\n matchingDest = this.act.abc['secondary'].getActiveBoxContent(bx1.idAss);\n let ok = false;\n\n if (bx1.idAss === bx2.idOrder || bx2.getContent().isEquivalent(matchingDest, true)) {\n // Pairing was OK. Play media and disable involved cells\n ok = true;\n bx1.idAss = -1;\n if (this.act.abc['solvedPrimary']) {\n bx1.switchToAlt(this.ps);\n m = m || bx1.playMedia(this.ps, delayedActions);\n } else {\n if (clickOnBg0)\n m = m || bx1.playMedia(this.ps, delayedActions);\n else\n m = m || bx2.playMedia(this.ps, delayedActions);\n bx1.clear();\n }\n if (this.act.invAss) {\n this.invAssCheck[bx2.idOrder] = true;\n bx2.clear();\n }\n if (this.act.useOrder && this.bgA)\n // Load next item\n this.currentItem = this.bgA.getNextItem(this.currentItem);\n }\n // Check results and notify action\n if (this.bgA) {\n const cellsPlaced = this.bgA.countCellsWithIdAss(-1);\n this.ps.reportNewAction(this.act, 'MATCH', src, dest, ok, cellsPlaced - this.act.nonAssignedCells);\n // End activity or play event sound\n if (ok && (this.checkInvAss() || cellsPlaced === this.bgA.getNumCells()))\n this.finishActivity(true);\n else if (!m)\n this.playEvent(ok ? 'actionOk' : 'actionError');\n }\n } else if (this.bgB && (clickOnBg0 && this.bgA && this.bgA.contains(p) || !clickOnBg0 && this.bgB.contains(p))) {\n // click on grid, out of cell\n const srcOut = bx1 ? bx1.getDescription() : bx2 ? bx2.getDescription() : 'null';\n this.ps.reportNewAction(this.act, 'MATCH', srcOut, 'null', false, this.bgB.countCellsWithIdAss(-1));\n this.playEvent('actionError');\n }\n this.update();\n\n // Move the focus to the `source` accessible group\n if (this.bgA && this.bgA.$accessibleDiv)\n this.bgA.$accessibleDiv.trigger('focus');\n }\n break;\n\n case 'mousemove':\n case 'touchmove':\n this.bc.moveTo(p);\n break;\n }\n delayedActions.forEach(action => action());\n event.preventDefault();\n }\n }\n}\n\nObject.assign(ComplexAssociationPanel.prototype, {\n /**\n * Array for storing checked associations\n * @name module:activities/associations/ComplexAssociation.ComplexAssociationPanel#invAssCheck\n * @type {boolean[]} */\n invAssCheck: null,\n});\n\n/**\n * Panel class associated to this type of activity: {@link module:activities/associations/ComplexAssociation.ComplexAssociationPanel ComplexAssociationPanel}\n * @type {class} */\nComplexAssociation.Panel = ComplexAssociationPanel;\n\n// Register activity class\nexport default Activity.registerClass('@associations.ComplexAssociation', ComplexAssociation);\n","/**\n * File : shapers/Rectangular.js\n * Created : 19/05/2015\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Catalan Educational Telematic Network (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\nimport Shaper from './Shaper.js';\nimport { Rectangle, Point, Dimension } from '../AWT.js';\n\n/**\n *\n * This is the simplest {@link module:shapers/Shaper.Shaper Shaper}. It divides the graphic object in a set of rectangular\n * shapes distributed in the specified number of rows and columns.\n * @extends module:shapers/Shaper.Shaper\n */\nexport class Rectangular extends Shaper {\n /**\n * Rectangular constructor\n * @param {number} nx - Number of columns\n * @param {number} ny - Number of rows\n */\n constructor(nx, ny) {\n super(nx, ny);\n }\n\n /**\n * Builds the rectangular shapes based on the number of rows and columns\n * @override\n */\n buildShapes() {\n const\n w = 1 / this.nCols,\n h = 1 / this.nRows;\n for (let y = 0; y < this.nRows; y++) {\n for (let x = 0; x < this.nCols; x++) {\n this.shapeData[y * this.nCols + x] = new Rectangle(new Point(x * w, y * h), new Dimension(w, h));\n }\n }\n this.initiated = true;\n }\n}\n\nObject.assign(Rectangular.prototype, {\n /**\n * Overrides same flag in {@link module:/shapers/Shaper.Shaper#rectangularShapes Shaper#rectangularShapes}\n * @name module:shapers/Rectangular.Rectangular#rectangularShapes\n * @override\n * @type {boolean} */\n rectangularShapes: true,\n});\n\n// Register this class in the list of known shapers\nexport default Shaper.registerClass('@Rectangular', Rectangular);\n","/**\n * File : activities/memory/MemoryGame.js\n * Created : 04/06/2015\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\nimport $ from 'jquery';\nimport { Activity, ActivityPanel } from '../../Activity.js';\nimport ActiveBoxGrid from '../../boxes/ActiveBoxGrid.js';\nimport BoxBag from '../../boxes/BoxBag.js';\nimport BoxConnector from '../../boxes/BoxConnector.js';\nimport { Rectangle, Point } from '../../AWT.js';\nimport Rectangular from '../../shapers/Rectangular.js';\n\n/**\n * This class of {@link module:Activity.Activity Activity} shows a panel with duplicate {@link module:boxes/ActiveBox.ActiveBox ActiveBox} objects initially\n * hidden and shuffled. To complete the activity, all object pairs must be found. Only two objects\n * are revealed in every move, so the user must remember the content of each cell.\n *\n * The cell pairs can have identical content, defined in the `primary` {@link module:boxes/ActiveBagContent.ActiveBagContent ActiveBagContent} of\n * the activity, or two different contents. In this case, the `secondary` bag elements will have\n * content related to each `primary` element.\n * @extends module:Activity.Activity\n */\nexport class MemoryGame extends Activity {\n /**\n * MemoryGame constructor\n * @param {module:project/JClicProject.JClicProject} project - The {@link module:project/JClicProject.JClicProject JClicProject} to which this activity belongs\n */\n constructor(project) {\n super(project);\n }\n\n /**\n * Retrieves the minimum number of actions needed to solve this activity.\n * @override\n * @returns {number}\n */\n getMinNumActions() {\n return this.abc.primary.getNumCells();\n }\n\n /**\n * Whether or not the activity uses random to shuffle internal components\n * @override\n * @returns {boolean}\n */\n hasRandom() {\n return true;\n }\n\n /**\n * When `true`, the activity must always be shuffled\n * @override\n * @returns {boolean}\n */\n shuffleAlways() {\n return true;\n }\n}\n\n/**\n * The {@link module:Activity.ActivityPanel ActivityPanel} where {@link module:activities/memory/MemoryGame.MemoryGame MemoryGame} activities are played.\n * @extends module:Activity.ActivityPanel\n */\nexport class MemoryGamePanel extends ActivityPanel {\n /**\n * MemoryGamePanel constructor\n * @param {module:Activity.Activity} act - The {@link module:Activity.Activity Activity} to which this Panel belongs\n * @param {module:JClicPlayer.JClicPlayer} ps - Any object implementing the methods defined in the\n * [PlayStation](http://projectestac.github.io/jclic/apidoc/edu/xtec/jclic/PlayStation.html) Java interface.\n * @param {external:jQuery} [$div] - The jQuery DOM element where this Panel will deploy\n */\n constructor(act, ps, $div) {\n super(act, ps, $div);\n }\n\n /**\n * Miscellaneous cleaning operations\n * @override\n */\n clear() {\n if (this.bg) {\n this.bg.end();\n this.bg = null;\n }\n }\n\n /**\n * Prepares the visual components of the activity\n * @override\n */\n buildVisualComponents() {\n if (this.firstRun)\n super.buildVisualComponents();\n this.clear();\n\n const\n abcA = this.act.abc['primary'],\n abcB = this.act.abc['secondary'];\n\n if (abcA) {\n if (abcA.image)\n abcA.setImgContent(this.act.project.mediaBag, null, false);\n if (abcB && abcB.image)\n abcB.setImgContent(this.act.project.mediaBag, null, false);\n if (this.act.acp !== null) {\n const contentKit = [abcA];\n if (abcB)\n contentKit.push(abcB);\n this.act.acp.generateContent(abcA.nch, abcA.ncw, contentKit, false);\n }\n\n let ncw = abcA.ncw, nch = abcA.nch;\n if (this.act.boxGridPos === 'AB' || this.act.boxGridPos === 'BA')\n ncw *= 2;\n else\n nch *= 2;\n\n this.bg = new ActiveBoxGrid(null, this, abcA.style,\n this.act.margin, this.act.margin,\n abcA.w * ncw, abcA.h * nch, new Rectangular(ncw, nch));\n\n const nc = abcA.getNumCells();\n this.bg.setBorder(abcA.border);\n this.bg.setContent(abcA, null, 0, 0, nc);\n this.bg.setContent(abcB ? abcB : abcA, null, 0, nc, nc);\n for (let i = 0; i < 2; i++) {\n for (let j = 0; j < nc; j++) {\n const bx = this.bg.getActiveBox(i * nc + j);\n bx.idAss = j;\n bx.setInactive(true);\n }\n }\n this.bg.setVisible(true);\n }\n }\n\n /**\n * Basic initialization procedure\n * @override\n */\n initActivity() {\n super.initActivity();\n\n if (!this.firstRun)\n this.buildVisualComponents();\n else\n this.firstRun = false;\n\n if (this.bg) {\n this.shuffle([this.bg], true, true);\n this.invalidate().update();\n this.setAndPlayMsg('initial', 'start');\n this.playing = true;\n }\n }\n\n /**\n * Updates the graphic content of this panel.\n * This method will be called from {@link module:AWT.Container#update} when needed.\n * @override\n * @param {module:AWT.Rectangle} dirtyRegion - Specifies the area to be updated. When `null`,\n * it's the whole panel.\n */\n updateContent(dirtyRegion) {\n super.updateContent(dirtyRegion);\n if (this.bg && this.$canvas) {\n const\n canvas = this.$canvas.get(-1),\n ctx = canvas.getContext('2d');\n if (!dirtyRegion)\n dirtyRegion = new Rectangle(0, 0, canvas.width, canvas.height);\n ctx.clearRect(dirtyRegion.pos.x, dirtyRegion.pos.y, dirtyRegion.dim.width, dirtyRegion.dim.height);\n this.bg.update(ctx, dirtyRegion);\n }\n return this;\n }\n\n /**\n * Sets the real dimension of this panel.\n * @override\n * @param {module:AWT.Dimension} preferredMaxSize - The maximum surface available for the activity panel\n * @returns {module:AWT.Dimension}\n */\n setDimension(preferredMaxSize) {\n if (!this.bg || this.getBounds().equals(preferredMaxSize))\n return preferredMaxSize;\n return BoxBag.layoutSingle(preferredMaxSize, this.bg, this.act.margin);\n }\n\n /**\n * Sets the size and position of this activity panel\n * @override\n * @param {module:AWT.Rectangle} rect\n */\n setBounds(rect) {\n if (this.$canvas)\n this.$canvas.remove();\n\n super.setBounds(rect);\n if (this.bg) {\n // Create the main canvas\n this.$canvas = $(`<canvas width=\"${rect.dim.width}\" height=\"${rect.dim.height}\"/>`).css({\n position: 'absolute',\n top: 0,\n left: 0\n });\n this.$div.append(this.$canvas);\n\n // Create a [BoxConnector](BoxConnector.html) and attach it to the canvas context\n this.bc = new BoxConnector(this, this.$canvas);\n\n // Repaint all\n this.invalidate().update();\n }\n }\n\n /**\n * Builds the accessible components needed for this ActivityPanel\n * This method is called when all main elements are placed and visible, when the activity is ready\n * to start or when resized.\n * @override\n */\n buildAccessibleComponents() {\n if (this.$canvas && this.accessibleCanvas && this.bg) {\n super.buildAccessibleComponents();\n this.bg.setCellAttr('accessibleAlwaysActive', true);\n this.bg.buildAccessibleElements(this.$canvas, this.$div, 'mousedown');\n }\n }\n\n /**\n * Main handler used to process mouse, touch, keyboard and edit events\n * @override\n * @param {external:Event} event - The HTML event to be processed\n * @returns {boolean} - When this event handler returns `false`, jQuery will stop its\n * propagation through the DOM tree. See: {@link http://api.jquery.com/on}\n */\n processEvent(event) {\n if (this.bc && this.playing) {\n //\n // The [AWT.Point](AWT.html#Point) where the mouse or touch event has been originated\n let p = null;\n //\n // Two [ActiveBox](ActiveBox.html) pointers used for the [BoxConnector](BoxConnector.html)\n // `origin` and `dest` points.\n let bx1, bx2,\n // Array to be filled with actions to be executed at the end of event processing\n delayedActions = [];\n //\n // _touchend_ event don't provide pageX nor pageY information\n if (event.type === 'touchend')\n p = this.bc.active ? this.bc.dest.clone() : new Point();\n else {\n // Touch events can have more than one touch, so `pageX` must be obtained from `touches[0]`\n const\n x = event.originalEvent && event.originalEvent.touches ? event.originalEvent.touches[0].pageX : event.pageX,\n y = event.originalEvent && event.originalEvent.touches ? event.originalEvent.touches[0].pageY : event.pageY;\n p = new Point(x - this.$div.offset().left, y - this.$div.offset().top);\n }\n\n // Flag for tracking `mouseup` events\n let up = false;\n switch (event.type) {\n case 'touchcancel':\n // Canvel movement\n if (this.bc.active)\n this.bc.end();\n break;\n\n case 'mouseup':\n case 'touchend':\n // Don't consider drag moves below 3 pixels. Can be a \"trembling click\"\n if (this.bc.active && p.distanceTo(this.bc.origin) <= 3)\n break;\n\n up = true;\n /* falls through */\n case 'touchstart':\n case 'mousedown':\n if (!this.bc.active) {\n // New pairing starts\n //\n // Pairings can never start with a `mouseup` event\n if (up)\n break;\n\n this.ps.stopMedia(1);\n //\n // Find the ActiveBox behind the clicked point\n bx1 = this.bg ? this.bg.findActiveBox(p) : null;\n if (bx1 && bx1.idAss !== -1) {\n // Play cell media or event sound\n if (!bx1.playMedia(this.ps, delayedActions))\n this.playEvent('click');\n bx1.setInactive(false);\n // Start the [BoxConnector](BoxConnector.html)\n this.update();\n if (this.act.dragCells)\n this.bc.begin(p, bx1);\n else\n this.bc.begin(p);\n }\n } else {\n this.ps.stopMedia(1);\n // Pairing completed\n //\n // Find the active boxes behind `bc.origin` and `p`\n if (this.act.dragCells)\n bx1 = this.bc.bx;\n else\n bx1 = this.bg ? this.bg.findActiveBox(this.bc.origin) : null;\n this.bc.end();\n bx2 = this.bg ? this.bg.findActiveBox(p) : null;\n //\n // Check if the pairing was OK\n if (bx1 && bx1.idAss !== -1 && bx2 && bx2.idAss !== -1) {\n if (bx1 !== bx2) {\n let ok = false;\n if (bx1.idAss === bx2.idAss ||\n bx1.getContent().isEquivalent(bx2.getContent(), true)) {\n ok = true;\n bx1.idAss = -1;\n bx1.setInactive(false);\n bx2.idAss = -1;\n bx2.setInactive(false);\n } else {\n bx1.setInactive(true);\n if (this.act.dragCells)\n bx2.setInactive(true);\n else {\n bx2.setInactive(false);\n // Start the [BoxConnector](BoxConnector.html)\n this.update();\n if (this.act.dragCells)\n this.bc.begin(p, bx1);\n else\n this.bc.begin(p);\n }\n }\n let m = bx2.playMedia(this.ps, delayedActions);\n if (this.bg) {\n const cellsAtPlace = this.bg.countCellsWithIdAss(-1);\n this.ps.reportNewAction(this.act, 'MATCH', bx1.getDescription(), bx2.getDescription(), ok, cellsAtPlace / 2);\n if (ok && cellsAtPlace === this.bg.getNumCells())\n this.finishActivity(true);\n else if (!m)\n this.playEvent(ok ? 'actionOk' : 'actionError');\n }\n } else {\n this.playEvent('CLICK');\n bx1.setInactive(true);\n }\n } else if (bx1 !== null)\n bx1.setInactive(true);\n\n this.invalidate().update();\n }\n break;\n\n case 'mousemove':\n case 'touchmove':\n this.bc.moveTo(p);\n break;\n }\n delayedActions.forEach(action => action());\n event.preventDefault();\n }\n }\n}\n\nObject.assign(MemoryGamePanel.prototype, {\n /**\n * The {@link module:boxes/ActiveBoxbag.ActiveBoxBag ActiveBoxBag} containing the information to be displayed.\n * @name module:activities/memory/MemoryGame.MemoryGamePanel#bg\n * @type {module:boxes/ActiveBoxBag.ActiveBoxBag} */\n bg: null,\n /**\n * The {@link module:boxes/BoxConnector.BoxConnector BoxConnector} used to reveal pairs of cells\n * @name module:activities/memory/MemoryGame.MemoryGamePanel#bc\n * @type {module:boxes/BoxConnector.BoxConnector} */\n bc: null,\n /**\n * List of mouse, touch and keyboard events intercepted by this panel\n * @override\n * @name module:activities/memory/MemoryGame.MemoryGamePanel#events\n * @type {string[]} */\n events: ['mousedown', 'mouseup', 'mousemove', 'touchstart', 'touchend', 'touchmove', 'touchcancel'],\n});\n\n/**\n * Panel class associated to this type of activity: {@link module:activities/memory/MemoryGame.MemoryGamePanel MemoryGamePanel}\n * @type {class} */\nMemoryGame.Panel = MemoryGamePanel;\n\n// Register activity class\nexport default Activity.registerClass('@memory.MemoryGame', MemoryGame);\n","/**\n * File : activities/panels/Explore.js\n * Created : 04/06/2015\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\nimport $ from 'jquery';\nimport { Activity, ActivityPanel } from '../../Activity.js';\nimport ActiveBoxGrid from '../../boxes/ActiveBoxGrid.js';\nimport BoxBag from '../../boxes/BoxBag.js';\nimport { Rectangle, Point } from '../../AWT.js';\nimport Rectangular from '../../shapers/Rectangular.js';\n\n/**\n * This class of {@link module:Activity.Activity Activity} shows a panel with {@link module:boxes/ActiveBox.ActiveBox ActiveBox} objects. Users can click\n * on this objects to obtain associated information. This associated information, displayed in\n * a second panel, can be text graphics, sound, video... or a combination of them.\n * @extends module:Activity.Activity\n */\nexport class Explore extends Activity {\n /**\n * Explore constructor\n * @param {module:project/JClicProject.JClicProject} project - The {@link module:project/JClicProject.JClicProject JClicProject} to which this activity belongs\n */\n constructor(project) {\n super(project);\n }\n\n /**\n * Activities of this type never end, so automatic sequences must pause here\n * @override\n * @returns {boolean}\n */\n mustPauseSequence() {\n return true;\n }\n\n /**\n * Retrieves the minimum number of actions needed to solve this activity\n * @override\n * @returns {number}\n */\n getMinNumActions() {\n return 0;\n }\n\n /**\n * Usually this activity don't use random to shuffle internal components, but in some cases\n * can make use of it.\n * @override\n * @returns {boolean}\n */\n hasRandom() {\n return true;\n }\n}\n\n/**\n * The {@link module:Activity.ActivityPanel ActivityPanel} where {@link module:activities/panels/Explore.Explore Explore} activities are played.\n * @extends module:Activity.ActivityPanel\n */\nexport class ExplorePanel extends ActivityPanel {\n /**\n * ExplorePanel constructor\n * @param {module:Activity.Activity} act - The {@link module:Activity.Activity Activity} to which this Panel belongs\n * @param {module:JClicPlayer.JClicPlayer} ps - Any object implementing the methods defined in the\n * [PlayStation](http://projectestac.github.io/jclic/apidoc/edu/xtec/jclic/PlayStation.html) Java interface.\n * @param {external:jQuery} [$div] - The jQuery DOM element where this Panel will deploy\n */\n constructor(act, ps, $div) {\n super(act, ps, $div);\n }\n\n /**\n * Miscellaneous cleaning operations\n * @override\n */\n clear() {\n if (this.bgA) {\n this.bgA.end();\n this.bgA = null;\n }\n if (this.bgB) {\n this.bgB.end();\n this.bgB = null;\n }\n }\n\n /**\n * Prepares the visual components of the activity\n * @override\n */\n buildVisualComponents() {\n if (this.firstRun)\n super.buildVisualComponents();\n this.clear();\n const\n abcA = this.act.abc['primary'],\n abcB = this.act.abc['secondary'];\n\n if (abcA && abcB) {\n if (abcA.image) {\n abcA.setImgContent(this.act.project.mediaBag, null, false);\n if (abcA.animatedGifFile && !abcA.shaper.rectangularShapes && !this.act.shuffleA)\n this.$animatedBg = $('<span/>').css({\n 'background-image': `url(${abcA.animatedGifFile})`,\n 'background-position': 'center',\n 'background-repeat': 'no-repeat',\n position: 'absolute'\n }).appendTo(this.$div);\n }\n\n if (abcB.image)\n abcB.setImgContent(this.act.project.mediaBag, null, false);\n\n if (this.act.acp !== null)\n this.act.acp.generateContent(abcA.nch, abcA.ncw, [abcA, abcB], false);\n\n this.bgA = ActiveBoxGrid.createEmptyGrid(null, this, this.act.margin, this.act.margin, abcA);\n const w = (this.act.boxGridPos === 'AUB' || this.act.boxGridPos === 'BUA') ? abcA.getTotalWidth() : abcB.w;\n this.bgB = new ActiveBoxGrid(null, this, abcB.style, this.act.margin, this.act.margin, w, abcB.h, new Rectangular(1, 1));\n\n this.bgA.setContent(abcA);\n this.bgA.setDefaultIdAss();\n if (this.$animatedBg)\n this.bgA.setCellAttr('tmpTrans', true);\n this.bgB.getActiveBox(0).setInactive(false);\n this.bgA.setVisible(true);\n this.bgB.setVisible(true);\n }\n }\n\n /**\n * Basic initialization procedure\n * @override\n */\n initActivity() {\n super.initActivity();\n if (!this.firstRun)\n this.buildVisualComponents();\n else\n this.firstRun = false;\n\n if (this.bgA && this.bgB) {\n // Scramble cells\n if (this.act.shuffleA)\n this.shuffle([this.bgA], true, true);\n\n if (this.useOrder)\n this.currentItem = this.bgA.getNextItem(-1);\n\n this.setAndPlayMsg('initial', 'start');\n this.invalidate().update();\n this.playing = true;\n }\n }\n\n /**\n * Updates the graphic content of this panel.\n * This method will be called from {@link module:AWT.Container#update} when needed.\n * @override\n * @param {module:AWT.Rectangle} dirtyRegion - Specifies the area to be updated. When `null`,\n * it's the whole panel.\n */\n updateContent(dirtyRegion) {\n super.updateContent(dirtyRegion);\n if (this.bgA && this.bgB && this.$canvas) {\n const\n canvas = this.$canvas.get(-1),\n ctx = canvas.getContext('2d');\n if (!dirtyRegion)\n dirtyRegion = new Rectangle(0, 0, canvas.width, canvas.height);\n ctx.clearRect(dirtyRegion.pos.x, dirtyRegion.pos.y, dirtyRegion.dim.width, dirtyRegion.dim.height);\n this.bgA.update(ctx, dirtyRegion);\n this.bgB.update(ctx, dirtyRegion);\n }\n return this;\n }\n\n /**\n * Sets the real dimension of this panel.\n * @override\n * @param {module:AWT.Dimension} preferredMaxSize - The maximum surface available for the activity panel\n * @returns {module:AWT.Dimension}\n */\n setDimension(preferredMaxSize) {\n return !this.bgA || !this.bgB || this.getBounds().equals(preferredMaxSize) ?\n preferredMaxSize :\n BoxBag.layoutDouble(preferredMaxSize, this.bgA, this.bgB, this.act.boxGridPos, this.act.margin);\n }\n\n /**\n * Sets the size and position of this activity panel\n * @override\n * @param {module:AWT.Rectangle} rect\n */\n setBounds(rect) {\n if (this.$canvas)\n this.$canvas.remove();\n super.setBounds(rect);\n\n if (this.bgA || this.bgB) {\n // Create the main canvas\n this.$canvas = $(`<canvas width=\"${rect.dim.width}\" height=\"${rect.dim.height}\"/>`).css({\n position: 'absolute',\n top: 0,\n left: 0\n });\n // Resize animated gif background\n if (this.$animatedBg) {\n const bgRect = this.bgA.getBounds();\n this.$animatedBg.css({\n left: bgRect.pos.x,\n top: bgRect.pos.y,\n width: `${bgRect.dim.width}px`,\n height: `${bgRect.dim.height}px`,\n 'background-size': `${bgRect.dim.width}px ${bgRect.dim.height}px`\n });\n }\n this.$div.append(this.$canvas);\n // Repaint all\n this.invalidate().update();\n }\n }\n\n /**\n * Builds the accessible components needed for this ActivityPanel\n * This method is called when all main elements are placed and visible, when the activity is ready\n * to start or when resized.\n * @override\n */\n buildAccessibleComponents() {\n if (this.$canvas && this.accessibleCanvas) {\n super.buildAccessibleComponents();\n if (this.bgA)\n this.bgA.buildAccessibleElements(this.$canvas, this.$div);\n if (this.bgB)\n this.bgB.buildAccessibleElements(this.$canvas, this.$div);\n }\n }\n\n /**\n * Main handler used to process mouse, touch, keyboard and edit events\n * @override\n * @param {external:Event} event - The HTML event to be processed\n * @returns {boolean} - When this event handler returns `false`, jQuery will stop its\n * propagation through the DOM tree. See: {@link http://api.jquery.com/on}\n */\n processEvent(event) {\n if (this.playing) {\n const p = new Point(\n event.pageX - this.$div.offset().left,\n event.pageY - this.$div.offset().top),\n // Array to be filled with actions to be executed at the end of event processing\n delayedActions = [];\n\n switch (event.type) {\n case 'click':\n this.ps.stopMedia(1);\n const bx1 = this.bgA.findActiveBox(p);\n if (bx1) {\n const bx2 = this.bgB.getActiveBox(0);\n if (bx1.idAss !== -1 && (!this.act.useOrder || bx1.idOrder === this.currentItem)) {\n bx2.setContent(this.act.abc['secondary'], bx1.idAss);\n if (!bx2.playMedia(this.ps, delayedActions) && !bx1.playMedia(this.ps, delayedActions))\n this.playEvent('CLICK');\n if (this.act.useOrder)\n this.currentItem = this.bgA.getNextItem(this.currentItem);\n this.ps.reportNewAction(this.act, 'SELECT', bx1.getDescription(), bx2.getDescription(), true, 0);\n // Modified May 2020: Focusing `accessibleElement` will always draw a border on bx2\n // if (bx2.$accessibleElement)\n // bx2.$accessibleElement.focus();\n\n // Clic 3.0 behavior, applied only to one-cell activities:\n if (bx1.idAss === 0 && this.bgA.getNumCells() === 1) {\n const seq = this.act.project.activitySequence;\n const ase = seq.getCurrentAct();\n if (ase && seq.hasNextAct(true) && ase.delay > 0\n && (seq.getNavButtonsFlag() !== 'both' && seq.getNavButtonsFlag() !== 'fwd')) {\n this.finishActivity(true);\n }\n }\n\n } else {\n bx2.clear();\n bx2.setInactive(false);\n }\n this.update();\n }\n break;\n }\n delayedActions.forEach(action => action());\n event.preventDefault();\n }\n }\n}\n\nObject.assign(ExplorePanel.prototype, {\n /**\n * The {@link module:boxes/ActiveBoxbag.ActiveBoxBag ActiveBoxBag} object containing the information to be displayed in the `primary` panel\n * @name module:activities/panels/Explore.ExplorePanel#bgA\n * @type {module:boxes/ActiveBoxBag.ActiveBoxBag} */\n bgA: null,\n /**\n * The {@link module:boxes/ActiveBoxbag.ActiveBoxBag ActiveBoxBag} object containing the information associated to `primary` elements.\n * Only one of this elements will be showed for each click done in the `primary` panel.\n * @name module:activities/panels/Explore.ExplorePanel#bgB\n * @type {module:boxes/ActiveBoxBag.ActiveBoxBag} */\n bgB: null,\n /**\n * List of mouse, touch and keyboard events intercepted by this panel\n * @override\n * @name module:activities/panels/Explore.ExplorePanel#events\n * @type {string[]} */\n events: ['click'],\n});\n\n/**\n * Panel class associated to this type of activity: {@link module:activities/panels/Explore.ExplorePanel ExplorePanel}\n * @type {class} */\nExplore.Panel = ExplorePanel;\n\n// Register activity class\nexport default Activity.registerClass('@panels.Explore', Explore);\n","/**\n * File : activities/panels/Identify.js\n * Created : 03/06/2015\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\n/* global window */\n\nimport $ from 'jquery';\nimport { Activity, ActivityPanel } from '../../Activity.js';\nimport ActiveBoxGrid from '../../boxes/ActiveBoxGrid.js';\nimport BoxBag from '../../boxes/BoxBag.js';\nimport { Rectangle, Point } from '../../AWT.js';\n\n/**\n * The aim of this type of {@link module:Activity.Activity Activity} is to identify {@link module:boxes/ActiveBox.ActiveBox ActiveBox} elements in a panel\n * that satisfy a specific condition, usually exposed in the main message.\n * @extends module:Activity.Activity\n */\nexport class Identify extends Activity {\n /**\n * Identify constructor\n * @param {module:project/JClicProject.JClicProject} project - The {@link module:project/JClicProject.JClicProject JClicProject} to which this activity belongs\n */\n constructor(project) {\n super(project);\n }\n\n /**\n * Retrieves the minimum number of actions needed to solve this activity\n * @override\n * @returns {number}\n */\n getMinNumActions() {\n return this.cellsToMatch;\n }\n\n /**\n * Whether or not the activity uses random to shuffle internal components\n * @override\n * @returns {boolean}\n */\n hasRandom() {\n return true;\n }\n}\n\nObject.assign(Identify.prototype, {\n /**\n * Number of not assigned cells (calculated in {@link module:activities/panels/Identify.IdentifyPanel#buildVisualComponents buildVisualComponents})\n * @name module:activities/panels/Identify.Identify#nonAssignedCells\n * @type {number} */\n nonAssignedCells: 0,\n /**\n * Number of cells the user must identify to complete the activity (calculated in\n * {@link module:activities/panels/Identify.IdentifyPanel#buildVisualComponents buildVisualComponents})\n * @name module:activities/panels/Identify.Identify#cellsToMatch\n * @type {number} */\n cellsToMatch: 1,\n});\n\n/**\n * The {@link module:Activity.ActivityPanel ActivityPanel} where {@link module:activities/panels/Identify.Identify Identify} activities are played.\n * @extends module:Activity.ActivityPanel\n */\nexport class IdentifyPanel extends ActivityPanel {\n /**\n * IdentifyPanel constructor\n * @param {module:Activity.Activity} act - The {@link module:Activity.Activity Activity} to which this Panel belongs\n * @param {module:JClicPlayer.JClicPlayer} ps - Any object implementing the methods defined in the\n * [PlayStation](http://projectestac.github.io/jclic/apidoc/edu/xtec/jclic/PlayStation.html) Java interface.\n * @param {external:jQuery} [$div] - The jQuery DOM element where this Panel will deploy\n */\n constructor(act, ps, $div) {\n super(act, ps, $div);\n }\n\n /**\n * Miscellaneous cleaning operations\n * @override\n */\n clear() {\n if (this.bg) {\n this.bg.end();\n this.bg = null;\n }\n }\n\n /**\n * Prepares the visual components of the activity\n * @override\n */\n buildVisualComponents() {\n if (this.firstRun)\n super.buildVisualComponents();\n this.clear();\n const\n abc = this.act.abc['primary'],\n solved = this.act.abc['solvedPrimary'];\n if (abc) {\n if (abc.image) {\n abc.setImgContent(this.act.project.mediaBag, null, false);\n if (abc.animatedGifFile && !abc.shaper.rectangularShapes && !this.act.shuffleA)\n this.$animatedBg = $('<span/>').css({\n 'background-image': `url(${abc.animatedGifFile})`,\n 'background-position': 'center',\n 'background-repeat': 'no-repeat',\n position: 'absolute'\n }).appendTo(this.$div);\n }\n\n if (solved && solved.image)\n solved.setImgContent(this.act.project.mediaBag, null, false);\n\n if (this.act.acp !== null) {\n const contentKit = [abc];\n if (solved) {\n contentKit.push(null);\n contentKit.push(solved);\n }\n this.act.acp.generateContent(abc.nch, abc.ncw, contentKit, false);\n }\n this.bg = ActiveBoxGrid.createEmptyGrid(null, this,\n this.act.margin, this.act.margin,\n abc);\n this.bg.setContent(abc, solved || null);\n this.bg.setAlternative(false);\n if (this.$animatedBg)\n this.bg.setCellAttr('tmpTrans', true);\n this.bg.setDefaultIdAss();\n this.act.nonAssignedCells = 0;\n this.act.cellsToMatch = 0;\n const n = this.bg.getNumCells();\n for (let i = 0; i < n; i++) {\n const\n bx = this.bg.getActiveBox(i),\n id = bx.idAss;\n if (id === 1)\n this.act.cellsToMatch++;\n else if (id === -1) {\n this.act.nonAssignedCells++;\n bx.switchToAlt(this.ps);\n }\n }\n this.bg.setVisible(true);\n }\n }\n\n /**\n * Basic initialization procedure\n * @override\n */\n initActivity() {\n super.initActivity();\n if (!this.firstRun)\n this.buildVisualComponents();\n else\n this.firstRun = false;\n\n if (this.bg) {\n if (this.act.shuffleA)\n this.shuffle([this.bg], true, true);\n\n if (this.useOrder)\n this.currentItem = this.bg.getNextItem(-1);\n\n this.setAndPlayMsg('initial', 'start');\n this.invalidate().update();\n this.playing = true;\n }\n }\n\n /**\n * Updates the graphic content of this panel.\n * This method will be called from {@link module:AWT.Container#update} when needed.\n * @override\n * @param {module:AWT.Rectangle} dirtyRegion - Specifies the area to be updated. When `null`,\n * it's the whole panel.\n */\n updateContent(dirtyRegion) {\n super.updateContent(dirtyRegion);\n\n if (this.bg && this.$canvas) {\n const\n canvas = this.$canvas.get(-1),\n ctx = canvas.getContext('2d');\n if (!dirtyRegion)\n dirtyRegion = new Rectangle(0, 0, canvas.width, canvas.height);\n ctx.clearRect(dirtyRegion.pos.x, dirtyRegion.pos.y, dirtyRegion.dim.width, dirtyRegion.dim.height);\n this.bg.update(ctx, dirtyRegion);\n }\n return super.updateContent(dirtyRegion);\n }\n\n /**\n * Sets the real dimension of this panel.\n * @override\n * @param {module:AWT.Dimension} preferredMaxSize - The maximum surface available for the activity panel\n * @returns {module:AWT.Dimension}\n */\n setDimension(preferredMaxSize) {\n return this.getBounds().equals(preferredMaxSize) ?\n preferredMaxSize :\n BoxBag.layoutSingle(preferredMaxSize, this.bg, this.act.margin);\n }\n\n /**\n * Sets the size and position of this activity panel\n * @override\n * @param {module:AWT.Rectangle} rect\n */\n setBounds(rect) {\n if (this.$canvas)\n this.$canvas.remove();\n\n super.setBounds(rect);\n if (this.bg) {\n this.$canvas = $(`<canvas width=\"${rect.dim.width}\" height=\"${rect.dim.height}\"/>`).css({\n position: 'absolute',\n top: 0,\n left: 0\n });\n // Resize animated gif background\n if (this.$animatedBg) {\n const bgRect = this.bg.getBounds();\n this.$animatedBg.css({\n left: bgRect.pos.x,\n top: bgRect.pos.y,\n width: `${bgRect.dim.width}px`,\n height: `${bgRect.dim.height}px`,\n 'background-size': `${bgRect.dim.width}px ${bgRect.dim.height}px`\n });\n }\n this.$div.append(this.$canvas);\n this.invalidate().update();\n window.setTimeout(() => this.bg ? this.bg.buildAccessibleElements(this.$canvas, this.$div) : null, 0);\n }\n }\n\n /**\n * Builds the accessible components needed for this ActivityPanel\n * This method is called when all main elements are placed and visible, when the activity is ready\n * to start or when resized.\n * @override\n */\n buildAccessibleComponents() {\n if (this.bg && this.$canvas && this.accessibleCanvas) {\n super.buildAccessibleComponents();\n this.bg.buildAccessibleElements(this.$canvas, this.$div);\n }\n }\n\n /**\n * Main handler used to process mouse, touch, keyboard and edit events\n * @override\n * @param {external:Event} event - The HTML event to be processed\n * @returns {boolean} - When this event handler returns `false`, jQuery will stop its\n * propagation through the DOM tree. See: {@link http://api.jquery.com/on}\n */\n processEvent(event) {\n if (this.playing) {\n const p = new Point(\n event.pageX - this.$div.offset().left,\n event.pageY - this.$div.offset().top);\n // Flag for assuring that only one media plays per event (avoid event sounds overlapping\n // cell's media sounds)\n let m = false;\n // Array to be filled with actions to be executed at the end of event processing\n const delayedActions = [];\n\n switch (event.type) {\n case 'click':\n this.ps.stopMedia(1);\n // Find the box behind the clicked point\n const bx = this.bg ? this.bg.findActiveBox(p) : null;\n if (bx) {\n if (bx.idAss !== -1) {\n // Check if it's a valid move\n let ok = false;\n const src = bx.getDescription();\n m = m || bx.playMedia(this.ps, delayedActions);\n if (bx.idAss === 1 && (!this.act.useOrder || bx.idOrder === this.currentItem)) {\n ok = true;\n bx.idAss = -1;\n if (bx.switchToAlt(this.ps))\n m = m || bx.playMedia(this.ps, delayedActions);\n else\n bx.clear();\n if (this.act.useOrder)\n this.currentItem = this.bg.getNextItem(this.currentItem, 1);\n }\n const cellsOk = this.bg.countCellsWithIdAss(-1);\n this.ps.reportNewAction(this.act, 'SELECT', src, null, ok, cellsOk - this.act.nonAssignedCells);\n if (ok && cellsOk === this.act.cellsToMatch + this.act.nonAssignedCells)\n this.finishActivity(true);\n else if (!m)\n this.playEvent(ok ? 'actionOk' : 'actionError');\n this.update();\n } else {\n this.playEvent('actionError');\n }\n }\n break;\n }\n delayedActions.forEach(action => action());\n event.preventDefault();\n }\n }\n}\n\nObject.assign(IdentifyPanel.prototype, {\n /**\n * The {@link module:boxes/ActiveBoxbag.ActiveBoxBag ActiveBoxBag} containing the information to be displayed on the panel.\n * @name module:activities/panels/Identify.IdentifyPanel#bg\n * @type {module:boxes/ActiveBoxBag.ActiveBoxBag} */\n bg: null,\n /**\n * List of mouse, touch and keyboard events intercepted by this panel\n * @override\n * @name module:activities/panels/Identify.IdentifyPanel#events\n * @type {string[]} */\n events: ['click'],\n});\n\n/**\n * Panel class associated to this type of activity: {@link module:activities/panels/Identify.IdentifyPanel IdentifyPanel}\n * @type {class} */\nIdentify.Panel = IdentifyPanel;\n\n// Register activity class\nexport default Activity.registerClass('@panels.Identify', Identify);\n","/**\n * File : activities/panels/InformationScreen.js\n * Created : 19/05/2015\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\n/* global window */\n\nimport $ from 'jquery';\nimport { Activity, ActivityPanel } from '../../Activity.js';\nimport ActiveBoxGrid from '../../boxes/ActiveBoxGrid.js';\nimport BoxBag from '../../boxes/BoxBag.js';\nimport { Rectangle, Point } from '../../AWT.js';\n\n/**\n * This class of {@link module:Activity.Activity Activity} just shows a panel with {@link module:boxes/ActiveBox.ActiveBox ActiveBox} objects.\n * Because active boxes can act as a links to specific points in the project's sequence of\n * activities, this kind of activity is often used as a menu where users can choose from different\n * options.\n * @extends module:Activity.Activity\n */\nexport class InformationScreen extends Activity {\n /**\n * InformationScreen constructor\n * @param {module:project/JClicProject.JClicProject} project - The {@link module:project/JClicProject.JClicProject JClicProject} to which this activity belongs\n */\n constructor(project) {\n super(project);\n // This kind of activities are not reported\n this.includeInReports = false;\n this.reportActions = false;\n }\n}\n\n/**\n * The {@link module:Activity.ActivityPanel ActivityPanel} where {@link module:activities/panels/InformationScreen.InformationScreen InformationScreen} activities should display its content\n * @extends module:Activity.ActivityPanel\n */\nexport class InformationScreenPanel extends ActivityPanel {\n /**\n * InformationScreenPanel constructor\n * @param {module:Activity.Activity} act - The {@link module:Activity.Activity Activity} to which this Panel belongs\n * @param {module:JClicPlayer.JClicPlayer} ps - Any object implementing the methods defined in the\n * [PlayStation](http://projectestac.github.io/jclic/apidoc/edu/xtec/jclic/PlayStation.html) Java interface.\n * @param {external:jQuery} [$div] - The jQuery DOM element where this Panel will deploy\n */\n constructor(act, ps, $div) {\n super(act, ps, $div);\n }\n\n /**\n * Miscellaneous cleaning operations\n * @override\n */\n clear() {\n if (this.bg) {\n this.bg.end();\n this.bg = null;\n }\n }\n\n /**\n * Prepares the visual components of the activity\n * @override\n */\n buildVisualComponents() {\n if (this.firstRun)\n super.buildVisualComponents();\n this.clear();\n const abc = this.act.abc['primary'];\n if (abc) {\n if (abc.image) {\n abc.setImgContent(this.act.project.mediaBag, null, false);\n if (abc.animatedGifFile && !abc.shaper.rectangularShapes)\n this.$animatedBg = $('<span/>').css({\n 'background-image': `url(${abc.animatedGifFile})`,\n 'background-position': 'center',\n 'background-repeat': 'no-repeat',\n position: 'absolute'\n }).appendTo(this.$div);\n }\n\n if (this.act.acp !== null)\n this.act.acp.generateContent(abc.nch, abc.ncw, [abc], false);\n\n this.bg = ActiveBoxGrid.createEmptyGrid(null, this,\n this.act.margin, this.act.margin,\n abc);\n this.bg.setContent(abc);\n if (this.$animatedBg)\n this.bg.setCellAttr('tmpTrans', true);\n this.bg.setVisible(true);\n }\n }\n\n /**\n * Basic initialization procedure\n * @override\n */\n initActivity() {\n super.initActivity();\n if (!this.firstRun)\n this.buildVisualComponents();\n else\n this.firstRun = false;\n\n this.invalidate().update();\n this.setAndPlayMsg('initial', 'start');\n this.playing = true;\n }\n\n /**\n * Updates the graphic content of this panel.\n * This method will be called from {@link module:AWT.Container#update} when needed.\n * @override\n * @param {module:AWT.Rectangle} dirtyRegion - Specifies the area to be updated. When `null`,\n * it's the whole panel.\n */\n updateContent(dirtyRegion) {\n super.updateContent(dirtyRegion);\n if (this.bg && this.$canvas) {\n const\n canvas = this.$canvas.get(-1),\n ctx = canvas.getContext('2d');\n if (!dirtyRegion)\n dirtyRegion = new Rectangle(0, 0, canvas.width, canvas.height);\n ctx.clearRect(dirtyRegion.pos.x, dirtyRegion.pos.y, dirtyRegion.dim.width, dirtyRegion.dim.height);\n this.bg.update(ctx, dirtyRegion);\n }\n return this;\n }\n\n /**\n * Sets the real dimension of this panel.\n * @override\n * @param {module:AWT.Dimension} preferredMaxSize - The maximum surface available for the activity panel\n * @returns {module:AWT.Dimension}\n */\n setDimension(preferredMaxSize) {\n return this.getBounds().equals(preferredMaxSize) ?\n preferredMaxSize :\n BoxBag.layoutSingle(preferredMaxSize, this.bg, this.act.margin);\n }\n\n /**\n * Sets the size and position of this activity panel\n * @override\n * @param {module:AWT.Rectangle} rect\n */\n setBounds(rect) {\n if (this.$canvas)\n this.$canvas.remove();\n\n super.setBounds(rect);\n if (this.bg) {\n this.$canvas = $('<canvas width=\"' + rect.dim.width + '\" height=\"' + rect.dim.height + '\"/>').css({\n position: 'absolute',\n top: 0,\n left: 0\n });\n // Resize animated gif background\n if (this.$animatedBg) {\n const bgRect = this.bg.getBounds();\n this.$animatedBg.css({\n left: bgRect.pos.x,\n top: bgRect.pos.y,\n width: `${bgRect.dim.width}px`,\n height: `${bgRect.dim.height}px`,\n 'background-size': `${bgRect.dim.width}px ${bgRect.dim.height}px`\n });\n }\n this.$div.append(this.$canvas);\n this.invalidate().update();\n window.setTimeout(() => this.bg ? this.bg.buildAccessibleElements(this.$canvas, this.$div) : null, 0);\n }\n }\n\n /**\n * Builds the accessible components needed for this ActivityPanel\n * This method is called when all main elements are placed and visible, when the activity is ready\n * to start or when resized.\n * @override\n */\n buildAccessibleComponents() {\n if (this.$canvas && this.accessibleCanvas && this.bg) {\n super.buildAccessibleComponents();\n this.bg.buildAccessibleElements(this.$canvas, this.$div);\n }\n }\n\n /**\n * Main handler used to process mouse, touch, keyboard and edit events\n * @override\n * @param {external:Event} event - The HTML event to be processed\n * @returns {boolean} - When this event handler returns `false`, jQuery will stop its\n * propagation through the DOM tree. See: {@link http://api.jquery.com/on}\n */\n processEvent(event) {\n if (this.playing) {\n const p = new Point(\n event.pageX - this.$div.offset().left,\n event.pageY - this.$div.offset().top);\n // Array to be filled with actions to be executed at the end of event processing\n const delayedActions = [];\n this.ps.stopMedia(1);\n const bx = this.bg.findActiveBox(p);\n if (bx) {\n if (!bx.playMedia(this.ps, delayedActions))\n this.playEvent('click');\n }\n delayedActions.forEach(action => action());\n event.preventDefault();\n }\n }\n}\n\nObject.assign(InformationScreenPanel.prototype, {\n /**\n * The {@link module:boxes/ActiveBoxbag.ActiveBoxBag ActiveBoxBag} containing the information to be displayed.\n * @name module:activities/panels/InformationScreen.InformationScreenPanel#bg\n * @type {module:boxes/ActiveBoxBag.ActiveBoxBag} */\n bg: null,\n /**\n * List of mouse, touch and keyboard events intercepted by this panel\n * @override\n * @name module:activities/panels/InformationScreen.InformationScreenPanel#events\n * @type {string[]} */\n events: ['click'],\n});\n\n/**\n * Panel class associated to this type of activity: {@link module:activities/panels/InformationScreen.InformationScreenPanel InformationScreenPanel}\n * @type {class} */\nInformationScreen.Panel = InformationScreenPanel;\n\n// Register activity class\nexport default Activity.registerClass('@panels.InformationScreen', InformationScreen);\n","/**\n * File : activities/panels/Menu.js\n * Created : 20/07/2017\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\nimport $ from 'jquery';\nimport { Activity, ActivityPanel } from '../../Activity.js';\nimport MediaContent from '../../media/MediaContent.js';\nimport { log } from '../../Utils.js';\n\n// Use Webpack to import PNG files\nimport ico00 from './icons/ico00.png';\nimport ico01 from './icons/ico01.png';\nimport ico02 from './icons/ico02.png';\nimport ico03 from './icons/ico03.png';\nimport icoFolder from './icons/icofolder.png';\n\n/**\n * This class of {@link module:Activity.Activity Activity} is only used in legacy JClic project libraries. It contains\n * one or more buttons pointing to specific JClic projects or to other `Menu` activity panels.\n * @extends module:Activity.Activity\n */\nexport class Menu extends Activity {\n /**\n * Menu constructor\n * @param {module:project/JClicProject.JClicProject} project - The {@link module:project/JClicProject.JClicProject JClicProject} to which this activity belongs\n */\n constructor(project) {\n super(project);\n this.menuElements = [];\n // This kind of activities are not reported\n this.includeInReports = false;\n this.reportActions = false;\n }\n}\n\n/**\n * The {@link module:Activity.ActivityPanel ActivityPanel} where Menu will show its content.\n * @extends module:Activity.ActivityPanel\n */\nexport class MenuPanel extends ActivityPanel {\n /**\n * MenuPanel constructor\n * @param {module:Activity.Activity} act - The {@link module:Activity.Activity Activity} to which this Panel belongs\n * @param {module:JClicPlayer.JClicPlayer} ps - Any object implementing the methods defined in the\n * [PlayStation](http://projectestac.github.io/jclic/apidoc/edu/xtec/jclic/PlayStation.html) Java interface.\n * @param {external:jQuery} [$div] - The jQuery DOM element where this Panel will deploy\n */\n constructor(act, ps, $div) {\n super(act, ps, $div);\n // This kind of activity will always clean the \"last project skin\" setting\n ps.lastProjectSkin = null;\n }\n\n /**\n * Prepares the visual components of the activity\n * @override\n */\n buildVisualComponents() {\n if (this.firstRun)\n super.buildVisualComponents();\n // This `div` will contain the action buttons\n const $btnDiv = $('<div/>').css({\n 'width': '100%',\n 'max-height': '100%',\n 'position': 'absolute',\n 'top': '50%',\n 'transform': 'translateY(-50%)',\n 'display': 'flex',\n 'flex-wrap': 'wrap',\n 'overflow-y': 'auto',\n 'place-content': 'center',\n 'overflow-y': 'auto'\n });\n this.act.menuElements.forEach((me) => {\n // Create a button for each menu element\n const caption = me.description || me.caption || 'JClic';\n const $btn = $('<button/>', {\n class: 'StockBtn',\n title: caption,\n 'aria-label': caption\n }).css({\n 'min-width': '80px',\n 'max-width': '200px',\n 'min-height': '80px',\n 'margin': '4px',\n 'padding': '4px',\n 'display': 'flex',\n 'flex-direction': 'column',\n 'justify-content': 'center',\n 'align-items': 'center'\n });\n\n // Set the button icon\n const\n iconSrc = MenuPanel.icons[me.icon || '@ico00.png'],\n $img = $('<img/>', { src: iconSrc || '' }).css({\n 'max-width': '180px',\n 'max-height': '100px',\n 'margin': '4px'\n });\n if (!iconSrc) {\n // It's not a stock image, so load `src` when available\n const mbe = this.act.project.mediaBag.getElement(me.icon, true);\n mbe.getFullPathPromise().then(imgFullPath => $img.attr('src', imgFullPath));\n }\n $btn.append($img);\n\n // Set the button text\n $btn.append($('<span/>').css({\n 'max-width': '180px',\n 'overflow': 'hidden',\n 'white-space': 'nowrap',\n 'text-overflow': 'ellipsis'\n }).html(me.caption));\n\n // Set a click listener method\n // $btn.on('click', function...) does not work!\n $btn[0].addEventListener('click', (ev) => {\n const mc = new MediaContent(me.projectPath ? 'RUN_CLIC_PACKAGE' : 'RUN_CLIC_ACTIVITY', me.sequence);\n if (me.projectPath)\n mc.externalParam = me.projectPath;\n log('info', `Launching ${me.projectPath || ''} ${me.sequence || ''}`);\n this.ps.playMedia(mc);\n ev.preventDefault();\n });\n\n // Place the created button on the container\n $btnDiv.append($btn);\n });\n\n // Add the buttons container on the main panel `div`\n this.$div.empty().append($btnDiv);\n }\n\n /**\n * Sets the real dimension of this panel.\n * @override\n * @param {module:AWT.Dimension} preferredMaxSize - The maximum surface available for the activity panel\n * @returns {module:AWT.Dimension}\n */\n setDimension(preferredMaxSize) {\n return preferredMaxSize;\n }\n\n /**\n * Basic initialization procedure\n * @override\n */\n initActivity() {\n super.initActivity();\n\n if (!this.firstRun)\n this.buildVisualComponents();\n else\n this.firstRun = false;\n\n this.setAndPlayMsg('initial', 'start');\n this.playing = true;\n }\n}\n\n/**\n * Default icons used in buttons, inherited from JClic\n * @type {object}\n */\nMenuPanel.icons = {\n '@ico00.png': ico00,\n '@ico01.png': ico01,\n '@ico02.png': ico02,\n '@ico03.png': ico03,\n '@icofolder.png': icoFolder,\n};\n\n/**\n * Panel class associated to this type of activity: {@link module:activities/panels/Menu.MenuPanel MenuPanel}\n * @type {class} */\nMenu.Panel = MenuPanel;\n\n// Register activity class\nexport default Activity.registerClass('@panels.Menu', Menu);\n\n\n","/**\n * File : activities/puzzles/DoublePuzzle.js\n * Created : 22/05/2015\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\nimport $ from 'jquery';\nimport { Activity, ActivityPanel } from '../../Activity.js';\nimport ActiveBoxGrid from '../../boxes/ActiveBoxGrid.js';\nimport BoxBag from '../../boxes/BoxBag.js';\nimport BoxConnector from '../../boxes/BoxConnector.js';\nimport { Rectangle, Point } from '../../AWT.js';\nimport { getMsg } from '../../Utils.js';\n\n/**\n * The aim of this class of {@link module:Activity.Activity Activity} is to put in order the shuffled elements of an\n * {@link module:boxes/ActiveBagContent.ActiveBagContent ActiveBagContent} that contains an image, sounds, text... or any other media content.\n *\n * The activity uses two panels: one with the shuffled cells, and other initially empty where\n * this cells must be placed in order.\n * @extends module:Activity.Activity\n */\nexport class DoublePuzzle extends Activity {\n /**\n * DoublePuzzle constructor\n * @param {module:project/JClicProject.JClicProject} project - The {@link module:project/JClicProject.JClicProject JClicProject} to which this activity belongs\n */\n constructor(project) {\n super(project);\n }\n\n /**\n * Retrieves the minimum number of actions needed to solve this activity.\n * @override\n * @returns {number}\n */\n getMinNumActions() {\n return this.abc.primary.getNumCells();\n }\n\n /**\n * Whether or not the activity uses random to shuffle internal components\n * @override\n * @returns {boolean}\n */\n hasRandom() {\n return true;\n }\n\n /**\n * When `true`, the activity must always be shuffled\n * @override\n * @returns {boolean}\n */\n shuffleAlways() {\n return true;\n }\n\n /**\n * Whether the activity allows the user to request help.\n * @override\n * @returns {boolean}\n */\n helpSolutionAllowed() {\n return true;\n }\n}\n\n/**\n * The {@link module:Activity.ActivityPanel ActivityPanel} where {@link module:activities/puzzles/DoublePuzzle.DoublePuzzle DoublePuzzle} activities are played.\n * @extends module:Activity.ActivityPanel\n */\nexport class DoublePuzzlePanel extends ActivityPanel {\n /**\n * DoublePuzzlePanel constructor\n * @param {module:Activity.Activity} act - The {@link module:Activity.Activity Activity} to which this Panel belongs\n * @param {module:JClicPlayer.JClicPlayer} ps - Any object implementing the methods defined in the\n * [PlayStation](http://projectestac.github.io/jclic/apidoc/edu/xtec/jclic/PlayStation.html)\n * Java interface.\n * @param {external:jQuery} [$div] - The jQuery DOM element where this Panel will deploy\n */\n constructor(act, ps, $div) {\n super(act, ps, $div);\n }\n\n /**\n * Miscellaneous cleaning operations\n * @override\n */\n clear() {\n if (this.bgA) {\n this.bgA.end();\n this.bgA = null;\n }\n if (this.bgB) {\n this.bgB.end();\n this.bgB = null;\n }\n }\n\n /**\n * Prepares the visual components of the activity\n * @override\n */\n buildVisualComponents() {\n if (this.firstRun)\n super.buildVisualComponents();\n this.clear();\n\n const abc = this.act.abc['primary'];\n if (abc) {\n if (abc.image)\n abc.setImgContent(this.act.project.mediaBag, null, false);\n\n if (this.act.acp !== null)\n this.act.acp.generateContent(abc.nch, abc.ncw, [abc], false);\n\n this.bgA = ActiveBoxGrid.createEmptyGrid(null, this, this.act.margin, this.act.margin, abc);\n this.bgB = ActiveBoxGrid.createEmptyGrid(null, this, this.act.margin, this.act.margin, abc);\n\n this.bgA.setContent(abc);\n\n this.bgA.accessibleText = getMsg('source');\n this.bgB.accessibleText = getMsg('target');\n\n this.bgA.setVisible(true);\n this.bgB.setVisible(true);\n\n const bgbA = this.bgA.getBackgroundActiveBox();\n const bgbB = this.bgB.getBackgroundActiveBox();\n if (bgbA && bgbB)\n bgbB.exchangeContent(bgbA);\n }\n }\n\n /**\n * Basic initialization procedure\n * @override\n */\n initActivity() {\n super.initActivity();\n if (!this.firstRun)\n this.buildVisualComponents();\n else\n this.firstRun = false;\n\n if (this.bgA && this.bgB) {\n this.shuffle([this.bgA], true, true);\n if (this.useOrder)\n this.currentItem = this.bgA.getNextItem(-1);\n this.setAndPlayMsg('initial', 'start');\n this.invalidate().update();\n this.playing = true;\n }\n }\n\n /**\n * Updates the graphic content of this panel.\n * This method will be called from {@link module:AWT.Container#update} when needed.\n * @override\n * @param {module:AWT.Rectangle} dirtyRegion - Specifies the area to be updated. When `null`,\n * it's the whole panel.\n */\n updateContent(dirtyRegion) {\n super.updateContent();\n if (this.bgA && this.bgB && this.$canvas) {\n const\n canvas = this.$canvas.get(-1),\n ctx = canvas.getContext('2d');\n if (!dirtyRegion)\n dirtyRegion = new Rectangle(0, 0, canvas.width, canvas.height);\n ctx.clearRect(dirtyRegion.pos.x, dirtyRegion.pos.y, dirtyRegion.dim.width, dirtyRegion.dim.height);\n this.bgA.update(ctx, dirtyRegion);\n this.bgB.update(ctx, dirtyRegion);\n }\n return this;\n }\n\n /**\n * Sets the real dimension of this panel.\n * @override\n * @param {module:AWT.Dimension} preferredMaxSize - The maximum surface available for the activity panel\n * @returns {module:AWT.Dimension}\n */\n setDimension(preferredMaxSize) {\n return !this.bgA || !this.bgB || this.getBounds().equals(preferredMaxSize) ?\n preferredMaxSize :\n BoxBag.layoutDouble(preferredMaxSize, this.bgA, this.bgB, this.act.boxGridPos, this.act.margin);\n }\n\n /**\n * Sets the size and position of this activity panel\n * @override\n * @param {module:AWT.Rectangle} rect\n */\n setBounds(rect) {\n if (this.$canvas)\n this.$canvas.remove();\n\n super.setBounds(rect);\n if (this.bgA || this.bgB) {\n // Create the main canvas\n this.$canvas = $(`<canvas width=\"${rect.dim.width}\" height=\"${rect.dim.height}\"/>`).css({\n position: 'absolute',\n top: 0,\n left: 0\n });\n this.$div.append(this.$canvas);\n\n // Create a [BoxConnector](BoxConnector.html) and attach it to the canvas context\n this.bc = new BoxConnector(this, this.$canvas);\n\n // Repaint all\n this.invalidate().update();\n }\n }\n\n /**\n * Builds the accessible components needed for this ActivityPanel\n * This method is called when all main elements are placed and visible, when the activity is ready\n * to start or when resized.\n * @override\n */\n buildAccessibleComponents() {\n if (this.$canvas && this.accessibleCanvas) {\n super.buildAccessibleComponents();\n if (this.bgA)\n this.bgA.buildAccessibleElements(this.$canvas, this.$div, 'mousedown');\n if (this.bgB) {\n this.bgB.setCellAttr('accessibleAlwaysActive', true);\n this.bgB.buildAccessibleElements(this.$canvas, this.$div, 'mousedown');\n }\n }\n }\n\n /**\n * Main handler used to process mouse, touch, keyboard and edit events\n * @override\n * @param {external:Event} event - The HTML event to be processed\n * @returns {boolean} - When this event handler returns `false`, jQuery will stop its\n * propagation through the DOM tree. See: {@link http://api.jquery.com/on}\n */\n processEvent(event) {\n if (this.bc && this.playing) {\n //\n // The [AWT.Point](AWT.html#Point) where the mouse or touch event has been originated\n let p = null;\n //\n // Two [ActiveBox](ActiveBox.html) pointers used for the [BoxConnector](BoxConnector.html)\n // `origin` and `dest` points.\n let bx1, bx2;\n // Array to be filled with actions to be executed at the end of event processing\n const delayedActions = [];\n //\n // _touchend_ event don't provide pageX nor pageY information\n if (event.type === 'touchend')\n p = this.bc.active ? this.bc.dest.clone() : new Point();\n else {\n // Touch events can have more than one touch, so `pageX` must be obtained from `touches[0]`\n const\n x = event.originalEvent && event.originalEvent.touches ? event.originalEvent.touches[0].pageX : event.pageX,\n y = event.originalEvent && event.originalEvent.touches ? event.originalEvent.touches[0].pageY : event.pageY;\n p = new Point(x - this.$div.offset().left, y - this.$div.offset().top);\n }\n\n // Flag for tracking `mouseup` events\n let up = false;\n switch (event.type) {\n case 'touchcancel':\n // Canvel movement\n if (this.bc.active)\n this.bc.end();\n break;\n\n case 'mouseup':\n // Don't consider drag moves below 3 pixels. Can be a \"trembling click\"\n if (this.bc.active && p.distanceTo(this.bc.origin) <= 3)\n break;\n\n up = true;\n /* falls through */\n case 'touchend':\n case 'touchstart':\n case 'mousedown':\n if (!this.bc.active) {\n //\n // A new pairing starts\n //\n // Pairings can never start with a `mouseup` event\n if (up)\n break;\n\n this.ps.stopMedia(1);\n //\n // Find the ActiveBox behind the clicked point\n bx1 = this.bgA.findActiveBox(p);\n if (bx1 && !bx1.isInactive() && (!this.act.useOrder || bx1.idOrder === this.currentItem)) {\n // Start the [BoxConnector](BoxConnector.html)\n if (this.act.dragCells)\n this.bc.begin(p, bx1);\n else\n this.bc.begin(p);\n // Play cell media or event sound\n if (!bx1.playMedia(this.ps, delayedActions))\n this.playEvent('click');\n\n // Move the focus to the opposite accessible group\n if (this.bgB.$accessibleDiv)\n this.bgB.$accessibleDiv.trigger('focus');\n }\n } else {\n this.ps.stopMedia(1);\n // Pairing completed\n //\n // Find the active boxes behind `bc.origin` and `p`\n if (this.act.dragCells)\n bx1 = this.bc.bx;\n else\n bx1 = this.bgA.findActiveBox(this.bc.origin);\n bx2 = this.bgB.findActiveBox(p);\n\n // BoxConnector ends here\n this.bc.end();\n\n // Check if the pairing was OK\n if (bx1 && bx2 && bx2.isInactive()) {\n let ok = false;\n const\n src = `${bx1.getDescription()} (${bx1.idOrder})`,\n dest = `(${bx2.idOrder})`,\n target = this.act.abc['primary'].getActiveBoxContent(bx2.idOrder);\n if (bx1.getContent().isEquivalent(target, true)) {\n // Pairing OK\n ok = true;\n bx1.exchangeContent(bx2);\n bx1.setVisible(false);\n if (this.act.useOrder)\n this.currentItem = this.bgA.getNextItem(this.currentItem);\n }\n // Check results and notify action\n const cellsAtPlace = this.bgA.countInactiveCells();\n this.ps.reportNewAction(this.act, 'PLACE', src, dest, ok, cellsAtPlace);\n // Finish activity or play event sound\n if (ok && cellsAtPlace === this.bgA.getNumCells())\n this.finishActivity(true);\n else\n this.playEvent(ok ? 'actionOk' : 'actionError');\n }\n this.update();\n\n // Move the focus to the `source` accessible group\n if (this.bgA.$accessibleDiv)\n this.bgA.$accessibleDiv.trigger('focus');\n }\n break;\n\n case 'mousemove':\n case 'touchmove':\n this.bc.moveTo(p);\n break;\n }\n delayedActions.forEach(action => action());\n event.preventDefault();\n }\n }\n}\n\nObject.assign(DoublePuzzlePanel.prototype, {\n /**\n * The {@link module:boxes/ActiveBoxbag.ActiveBoxBag ActiveBoxBag} object containing the information to be displayed in the `primary` panel\n * @name module:activities/puzzles/DoublePuzzle.DoublePuzzlePanel#bgA\n * @type {module:boxes/ActiveBoxBag.ActiveBoxBag} */\n bgA: null,\n /**\n * The secondary {@link module:boxes/ActiveBoxbag.ActiveBoxBag ActiveBoxBag}, initially empty.\n * @name module:activities/puzzles/DoublePuzzle.DoublePuzzlePanel#bgB\n * @type {module:boxes/ActiveBoxBag.ActiveBoxBag} */\n bgB: null,\n /**\n * The box connector\n * @name module:activities/puzzles/DoublePuzzle.DoublePuzzlePanel#bc\n * @type {module:boxes/BoxConnector.BoxConnector} */\n bc: null,\n /**\n * List of mouse, touch and keyboard events intercepted by this panel\n * @override\n * @name module:activities/puzzles/DoublePuzzle.DoublePuzzlePanel#events\n * @type {string[]} */\n events: ['mousedown', 'mouseup', 'mousemove', 'touchstart', 'touchend', 'touchmove', 'touchcancel'],\n});\n\n/**\n * Panel class associated to this type of activity: {@link module:activities/puzzles/DoublePuzzle.DoublePuzzlePanel DoublePuzzlePanel}\n * @type {class} */\nDoublePuzzle.Panel = DoublePuzzlePanel;\n\n// Register activity class\nexport default Activity.registerClass('@puzzles.DoublePuzzle', DoublePuzzle);\n\n","/**\n * File : activities/puzzles/ExchangePuzzle.js\n * Created : 30/05/2015\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\nimport $ from 'jquery';\nimport { Activity, ActivityPanel } from '../../Activity.js';\nimport ActiveBoxGrid from '../../boxes/ActiveBoxGrid.js';\nimport BoxBag from '../../boxes/BoxBag.js';\nimport BoxConnector from '../../boxes/BoxConnector.js';\nimport { Rectangle, Point } from '../../AWT.js';\n\n/**\n * This class of {@link module:Activity.Activity Activity} shows only one panel with shuffled {@link module:boxes/ActiveBox.ActiveBox ActiveBox} objects.\n * To solve the activity, each cell must exchange its location with another one. When all cells are\n * on place, the activity is done.\n * @extends module:Activity.Activity\n */\nexport class ExchangePuzzle extends Activity {\n /**\n * ExchangePuzzle constructor\n * @param {module:project/JClicProject.JClicProject} project - The {@link module:project/JClicProject.JClicProject JClicProject} to which this activity belongs\n */\n constructor(project) {\n super(project);\n }\n\n /**\n * Retrieves the minimum number of actions needed to solve this activity.\n * @override\n * @returns {number}\n */\n getMinNumActions() {\n return this.abc.primary.getNumCells();\n }\n\n /**\n * Whether or not the activity uses random to shuffle internal components\n * @override\n * @returns {boolean}\n */\n hasRandom() {\n return true;\n }\n\n /**\n * When `true`, the activity must always be shuffled\n * @override\n * @returns {boolean}\n */\n shuffleAlways() {\n return true;\n }\n\n /**\n * Whether the activity allows the user to request help.\n * @override\n * @returns {boolean}\n */\n helpSolutionAllowed() {\n return true;\n }\n}\n\n/**\n * The {@link module:Activity.ActivityPanel ActivityPanel} where activities of type {@link module:activities/puzzles/ExchangePuzzle.ExchangePuzzle ExchangePuzzle} are played.\n * @extends module:Activity.ActivityPanel\n */\nclass ExchangePuzzlePanel extends ActivityPanel {\n /**\n * ExchangePuzzlePanel constructor\n * @param {module:Activity.Activity} act - The {@link module:Activity.Activity Activity} to which this Panel belongs\n * @param {module:JClicPlayer.JClicPlayer} ps - Any object implementing the methods defined in the\n * [PlayStation](http://projectestac.github.io/jclic/apidoc/edu/xtec/jclic/PlayStation.html) Java interface.\n * @param {external:jQuery} [$div] - The jQuery DOM element where this Panel will deploy\n */\n constructor(act, ps, $div) {\n super(act, ps, $div);\n }\n\n /**\n * Miscellaneous cleaning operations\n * @override\n */\n clear() {\n if (this.bg) {\n this.bg.end();\n this.bg = null;\n }\n }\n\n /**\n * Prepares the visual components of the activity\n * @override\n */\n buildVisualComponents() {\n if (this.firstRun)\n super.buildVisualComponents();\n this.clear();\n\n const abc = this.act.abc['primary'];\n if (abc) {\n if (abc.image)\n abc.setImgContent(this.act.project.mediaBag, null, false);\n\n if (this.act.acp !== null)\n this.act.acp.generateContent(abc.nch, abc.ncw, [abc], false);\n\n this.bg = ActiveBoxGrid.createEmptyGrid(null, this, this.act.margin, this.act.margin, abc);\n this.bg.setContent(abc);\n this.bg.setVisible(true);\n }\n }\n\n /**\n * Basic initialization procedure\n * @override\n */\n initActivity() {\n super.initActivity();\n if (!this.firstRun)\n this.buildVisualComponents();\n else\n this.firstRun = false;\n\n if (this.bg) {\n this.shuffle([this.bg], true, true);\n if (this.useOrder)\n this.currentItem = this.bg.getNextItem(-1);\n this.setAndPlayMsg('initial', 'start');\n this.invalidate().update();\n this.playing = true;\n }\n }\n\n /**\n * Updates the graphic content of this panel.\n * This method will be called from {@link module:AWT.Container#update} when needed.\n * @override\n * @param {module:AWT.Rectangle} dirtyRegion - Specifies the area to be updated. When `null`,\n * it's the whole panel.\n */\n updateContent(dirtyRegion) {\n super.updateContent(dirtyRegion);\n if (this.bg && this.$canvas) {\n const\n canvas = this.$canvas.get(-1),\n ctx = canvas.getContext('2d');\n if (!dirtyRegion)\n dirtyRegion = new Rectangle(0, 0, canvas.width, canvas.height);\n ctx.clearRect(dirtyRegion.pos.x, dirtyRegion.pos.y, dirtyRegion.dim.width, dirtyRegion.dim.height);\n this.bg.update(ctx, dirtyRegion);\n }\n return this;\n }\n\n /**\n * Sets the real dimension of this panel.\n * @override\n * @param {module:AWT.Dimension} preferredMaxSize - The maximum surface available for the activity panel\n * @returns {module:AWT.Dimension}\n */\n setDimension(preferredMaxSize) {\n return !this.bg || this.getBounds().equals(preferredMaxSize) ?\n preferredMaxSize :\n BoxBag.layoutSingle(preferredMaxSize, this.bg, this.act.margin);\n }\n\n /**\n * Sets the size and position of this activity panel\n * @override\n * @param {module:AWT.Rectangle} rect\n */\n setBounds(rect) {\n if (this.$canvas)\n this.$canvas.remove();\n\n super.setBounds(rect);\n if (this.bg) {\n // Create the main canvas\n this.$canvas = $(`<canvas width=\"${rect.dim.width}\" height=\"${rect.dim.height}\"/>`).css({\n position: 'absolute',\n top: 0,\n left: 0\n });\n this.$div.append(this.$canvas);\n\n // Create a [BoxConnector](BoxConnector.html) and attach it to the canvas context\n this.bc = new BoxConnector(this, this.$canvas);\n\n // Repaint all\n this.invalidate().update();\n }\n }\n\n /**\n * Builds the accessible components needed for this ActivityPanel\n * This method is called when all main elements are placed and visible, when the activity is ready\n * to start or when resized.\n * @override\n */\n buildAccessibleComponents() {\n if (this.$canvas && this.accessibleCanvas && this.bg) {\n super.buildAccessibleComponents();\n this.bg.buildAccessibleElements(this.$canvas, this.$div, 'mousedown');\n }\n }\n\n /**\n * Main handler used to process mouse, touch, keyboard and edit events\n * @override\n * @param {external:Event} event - The HTML event to be processed\n * @returns {boolean} - When this event handler returns `false`, jQuery will stop its\n * propagation through the DOM tree. See: {@link http://api.jquery.com/on}\n */\n processEvent(event) {\n if (this.bc && this.playing) {\n\n //\n // The [AWT.Point](AWT.html#Point) where the mouse or touch event has been originated\n let p = null;\n //\n // Two [ActiveBox](ActiveBox.html) pointers used for the [BoxConnector](BoxConnector.html)\n // `origin` and `dest` points.\n let bx1, bx2;\n // Array to be filled with actions to be executed at the end of event processing\n const delayedActions = [];\n //\n // _touchend_ event don't provide pageX nor pageY information\n if (event.type === 'touchend')\n p = this.bc.active ? this.bc.dest.clone() : new Point();\n else {\n // Touch events can have more than one touch, so `pageX` must be obtained from `touches[0]`\n const\n x = event.originalEvent && event.originalEvent.touches ? event.originalEvent.touches[0].pageX : event.pageX,\n y = event.originalEvent && event.originalEvent.touches ? event.originalEvent.touches[0].pageY : event.pageY;\n p = new Point(x - this.$div.offset().left, y - this.$div.offset().top);\n }\n\n // Flag for tracking `mouseup` events\n let up = false;\n\n switch (event.type) {\n case 'touchcancel':\n // Canvel movement\n if (this.bc.active)\n this.bc.end();\n break;\n\n case 'mouseup':\n // Don't consider drag moves below 3 pixels. Can be a \"trembling click\"\n if (this.bc.active && p.distanceTo(this.bc.origin) <= 3)\n break;\n\n up = true;\n /* falls through */\n case 'touchend':\n case 'touchstart':\n case 'mousedown':\n if (!this.bc.active) {\n // New pairing starts\n //\n // Pairings never can start with a `mouseup` event\n if (up)\n break;\n\n this.ps.stopMedia(1);\n // Find the ActiveBox behind the clicked point\n bx1 = this.bg.findActiveBox(p);\n if (bx1) {\n // Start the [BoxConnector](BoxConnector.html)\n if (this.act.dragCells)\n this.bc.begin(p, bx1);\n else\n this.bc.begin(p);\n // Play cell media or event sound\n if (!bx1.playMedia(this.ps, delayedActions))\n this.playEvent('click');\n }\n } else {\n this.ps.stopMedia(1);\n // Pairing completed\n //\n // Find the active boxes behind `bc.origin` and `p`\n if (this.act.dragCells)\n bx1 = this.bc.bx;\n else\n bx1 = this.bg.findActiveBox(this.bc.origin);\n this.bc.end();\n bx2 = this.bg.findActiveBox(p);\n //\n // Check if the pairing was OK\n if (bx1 && bx2) {\n const\n src = `${bx1.getDescription()} (${bx1.idOrder})`,\n dest = `(${bx2.idLoc})`;\n let ok = (bx1.idOrder === bx2.idLoc);\n this.bg.swapCellPositions(bx1, bx2, true);\n // Check results and notify action\n const cellsAtPlace = this.bg.countCellsAtEquivalentPlace(true);\n this.ps.reportNewAction(this.act, 'PLACE', src, dest, ok, cellsAtPlace);\n // End activity or play event sound\n if (ok && cellsAtPlace === this.bg.getNumCells())\n this.finishActivity(true);\n else\n this.playEvent(ok ? 'actionOk' : 'actionError');\n }\n this.update();\n }\n break;\n\n case 'mousemove':\n case 'touchmove':\n this.bc.moveTo(p);\n break;\n }\n delayedActions.forEach(action => action());\n event.preventDefault();\n }\n }\n}\n\nObject.assign(ExchangePuzzlePanel.prototype, {\n /**\n * The {@link module:boxes/ActiveBoxbag.ActiveBoxBag ActiveBoxBag} object containing the information to be displayed in the panel.\n * @name module:activities/puzzles/ExchangePuzzle.ExchangePuzzlePanel#bg\n * @type {module:boxes/ActiveBoxBag.ActiveBoxBag} */\n bg: null,\n /**\n * The box connector\n * @name module:activities/puzzles/ExchangePuzzle.ExchangePuzzlePanel#bc\n * @type {module:boxes/BoxConnector.BoxConnector} */\n bc: null,\n /**\n * List of mouse, touch and keyboard events intercepted by this panel\n * @override\n * @name module:activities/puzzles/ExchangePuzzle.ExchangePuzzlePanel#events\n * @type {string[]} */\n events: ['mousedown', 'mouseup', 'mousemove', 'touchstart', 'touchend', 'touchmove', 'touchcancel'],\n});\n\n/**\n * Panel class associated to this type of activity: {@link module:activities/puzzles/ExchangePuzzle.ExchangePuzzlePanel ExchangePuzzlePanel}\n * @type {class} */\nExchangePuzzle.Panel = ExchangePuzzlePanel;\n\n// Register activity class\nexport default Activity.registerClass('@puzzles.ExchangePuzzle', ExchangePuzzle);\n","/**\n * File : activities/puzzles/HolePuzzle.js\n * Created : 01/06/2015\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\nimport $ from 'jquery';\nimport { Activity, ActivityPanel } from '../../Activity.js';\nimport ActiveBoxGrid from '../../boxes/ActiveBoxGrid.js';\nimport BoxBag from '../../boxes/BoxBag.js';\nimport { Rectangle, Point } from '../../AWT.js';\nimport Rectangular from '../../shapers/Rectangular.js';\n\n/**\n * This class of {@link module:Activity.Activity Activity} shows only one panel with shuffled {@link module:boxes/ActiveBox.ActiveBox ActiveBox} cells.\n *\n * One of the cells is out of the main panel, thus allowing its neighbors occupy their space.\n * Only immediate neighbors of the \"hole\" can move into it.\n *\n * When all cells are on place, the initially \"expulsed\" cell comes back home and the activity is done.\n * @extends module:Activity.Activity\n */\nexport class HolePuzzle extends Activity {\n /**\n * HolePuzzle constructor\n * @param {module:project/JClicProject.JClicProject} project - The {@link module:project/JClicProject.JClicProject JClicProject} to which this activity belongs\n */\n constructor(project) {\n super(project);\n }\n\n /**\n * Retrieves the minimum number of actions needed to solve this activity.\n * @override\n * @returns {number}\n */\n getMinNumActions() {\n return this.abc.primary.getNumCells();\n }\n\n /**\n * Whether or not the activity uses random to shuffle internal components\n * @override\n * @returns {boolean}\n */\n hasRandom() {\n return true;\n }\n\n /**\n * When `true`, the activity must always be shuffled\n * @override\n * @returns {boolean}\n */\n shuffleAlways() {\n return true;\n }\n\n /**\n * Whether the activity allows the user to request help\n * @override\n * @returns {boolean}\n */\n helpSolutionAllowed() {\n return true;\n }\n}\n\n/**\n * The {@link module:Activity.ActivityPanel ActivityPanel} where {@link module:activities/puzzles/HolePuzzle.HolePuzzle HolePuzzle} activities are played\n * @extends module:Activity.ActivityPanel\n */\nexport class HolePuzzlePanel extends ActivityPanel {\n /**\n * HolePuzzlePanel constructor\n * @param {module:Activity.Activity} act - The {@link module:Activity.Activity Activity} to which this Panel belongs\n * @param {module:JClicPlayer.JClicPlayer} ps - Any object implementing the methods defined in the\n * [PlayStation](http://projectestac.github.io/jclic/apidoc/edu/xtec/jclic/PlayStation.html) Java interface.\n * @param {external:jQuery} [$div] - The jQuery DOM element where this Panel will deploy\n */\n constructor(act, ps, $div) {\n super(act, ps, $div);\n }\n\n /**\n * Miscellaneous cleaning operations\n * @override\n */\n clear() {\n if (this.bg) {\n this.bg.end();\n this.bg = null;\n }\n if (this.parkBg) {\n this.parkBg.end();\n this.parkBg = null;\n }\n }\n\n /**\n * Prepares the visual components of the activity\n * @override\n */\n buildVisualComponents() {\n if (this.firstRun)\n super.buildVisualComponents();\n this.clear();\n\n const abc = this.act.abc['primary'];\n if (abc) {\n if (abc.image)\n abc.setImgContent(this.act.project.mediaBag, null, false);\n\n if (this.act.acp !== null)\n this.act.acp.generateContent(abc.nch, abc.ncw, [abc], false);\n\n this.bg = ActiveBoxGrid.createEmptyGrid(null, this, this.act.margin, this.act.margin, abc);\n this.bg.setContent(abc);\n this.bg.setVisible(true);\n\n this.hiddenBoxIndex = Math.floor(Math.random() * this.bg.getNumCells());\n this.hiddenBox = this.bg.getActiveBox(this.hiddenBoxIndex);\n this.hiddenBox.setVisible(false);\n this.parkBg = new ActiveBoxGrid(null, this, abc.style, this.act.margin, this.act.margin,\n this.hiddenBox.dim.width, this.hiddenBox.dim.height, new Rectangular(1, 1));\n this.parkBg.setContent(abc, null, this.hiddenBoxIndex, 0, 1);\n this.parkBg.setBorder(this.bg.hasBorder());\n this.parkBg.setVisible(true);\n }\n }\n\n /**\n * Basic initialization procedure\n * @override\n */\n initActivity() {\n super.initActivity();\n if (!this.firstRun)\n this.buildVisualComponents();\n else\n this.firstRun = false;\n\n if (this.bg) {\n //\n // This activity has an special shuffle method. Cells can move only to places near the 'hole'\n if (this.act.shuffles % 2 !== 1)\n this.act.shuffles++;\n for (var i = 0; i < this.act.shuffles; i++) {\n const pth = this.bg.getCoord(this.hiddenBox);\n const v = Math.floor(Math.random() * 2) === 0 ? 1 : -1;\n\n if (Math.floor(Math.random() * 2) === 0) {\n pth.x += v;\n if (pth.x < 0 || pth.x >= this.bg.nCols)\n pth.x -= 2 * v;\n } else {\n pth.y += v;\n if (pth.y < 0 || pth.y >= this.bg.nRows)\n pth.y -= 2 * v;\n }\n var dstBx = this.bg.getActiveBoxWithIdLoc(pth.y * this.bg.nCols + pth.x);\n if (dstBx !== null)\n this.hiddenBox.exchangeLocation(dstBx);\n }\n this.setAndPlayMsg('initial', 'start');\n this.invalidate().update();\n this.playing = true;\n }\n }\n\n /**\n * Updates the graphic content of this panel.\n * This method will be called from {@link module:AWT.Container#update} when needed.\n * @override\n * @param {module:AWT.Rectangle} dirtyRegion - Specifies the area to be updated. When `null`,\n * it's the whole panel.\n */\n updateContent(dirtyRegion) {\n super.updateContent(dirtyRegion);\n if (this.bg && this.parkBg && this.$canvas) {\n const\n canvas = this.$canvas.get(-1),\n ctx = canvas.getContext('2d');\n if (!dirtyRegion)\n dirtyRegion = new Rectangle(0, 0, canvas.width, canvas.height);\n ctx.clearRect(dirtyRegion.pos.x, dirtyRegion.pos.y, dirtyRegion.dim.width, dirtyRegion.dim.height);\n this.bg.update(ctx, dirtyRegion);\n this.parkBg.update(ctx, dirtyRegion);\n }\n return this;\n }\n\n /**\n * Sets the real dimension of this panel.\n * @override\n * @param {module:AWT.Dimension} preferredMaxSize - The maximum surface available for the activity panel\n * @returns {module:AWT.Dimension}\n */\n setDimension(preferredMaxSize) {\n return !this.bg || !this.parkBg || this.getBounds().equals(preferredMaxSize) ?\n preferredMaxSize :\n BoxBag.layoutDouble(preferredMaxSize, this.bg, this.parkBg, this.act.boxGridPos, this.act.margin);\n }\n\n /**\n * Sets the size and position of this activity panel\n * @override\n * @param {module:AWT.Rectangle} rect\n */\n setBounds(rect) {\n if (this.$canvas)\n this.$canvas.remove();\n\n super.setBounds(rect);\n if (this.bg && this.parkBg) {\n // Create the main canvas\n this.$canvas = $(`<canvas width=\"${rect.dim.width}\" height=\"${rect.dim.height}\"/>`).css({\n position: 'absolute',\n top: 0,\n left: 0\n });\n this.$div.append(this.$canvas);\n\n // Repaint all\n this.invalidate().update();\n }\n }\n\n /**\n * Builds the accessible components needed for this ActivityPanel\n * This method is called when all main elements are placed and visible, when the activity is ready\n * to start or when resized.\n * @override\n */\n buildAccessibleComponents() {\n if (this.$canvas && this.accessibleCanvas && this.bg) {\n super.buildAccessibleComponents();\n this.bg.buildAccessibleElements(this.$canvas, this.$div);\n }\n }\n\n /**\n * Main handler used to process mouse, touch, keyboard and edit events\n * @override\n * @param {external:Event} event - The HTML event to be processed\n * @returns {boolean} - When this event handler returns `false`, jQuery will stop its\n * propagation through the DOM tree. See: {@link http://api.jquery.com/on}\n */\n processEvent(event) {\n if (this.playing) {\n const p = new Point(\n event.pageX - this.$div.offset().left,\n event.pageY - this.$div.offset().top);\n // Array to be filled with actions to be executed at the end of event processing\n const delayedActions = [];\n\n switch (event.type) {\n case 'click':\n this.ps.stopMedia(1);\n // Find the box behind the clicked point\n const bx = this.bg.findActiveBox(p);\n if (bx) {\n if (bx.isVisible()) {\n // Check if it's a valid move\n const pt = this.bg.getCoordDist(bx, this.hiddenBox);\n if (Math.abs(pt.x) + Math.abs(pt.y) === 1) {\n // Ok, the cell is adjacent to the hole. Complete the move.\n let m = bx.playMedia(this.ps, delayedActions);\n const\n src = `${bx.getDescription()} (${bx.idOrder})`,\n dest = `(${this.hiddenBox.idLoc})`;\n bx.exchangeLocation(this.hiddenBox);\n const ok = bx.idOrder === bx.idLoc;\n // Check results and notify action\n const cellsAtPlace = this.bg.countCellsAtEquivalentPlace(true);\n this.ps.reportNewAction(this.act, 'SELECT', src, dest, ok, cellsAtPlace);\n if (ok && cellsAtPlace === this.bg.getNumCells()) {\n // Activity completed!\n this.hiddenBox.setVisible(true);\n this.parkBg.setVisible(false);\n this.finishActivity(true);\n } else\n if (!m)\n this.playEvent('click');\n }\n this.update();\n } else {\n this.playEvent('actionError');\n }\n }\n break;\n }\n delayedActions.forEach(action => action());\n event.preventDefault();\n }\n }\n}\n\nObject.assign(HolePuzzlePanel.prototype, {\n /**\n * The {@link module:boxes/ActiveBoxbag.ActiveBoxBag ActiveBoxBag} object containing the information to be displayed in the panel.\n * @name module:activities/puzzles/HolePuzzle.HolePuzzlePanel#bg\n * @type {module:boxes/ActiveBoxBag.ActiveBoxBag} */\n bg: null,\n /**\n * An auxiliary box bag with only one box, used to store the \"missing piece\" of\n * the puzzle.\n * @name module:activities/puzzles/HolePuzzle.HolePuzzlePanel#parkBg\n * @type {module:boxes/ActiveBoxGrid.ActiveBoxGrid} */\n parkBg: null,\n /**\n * The hidden cell\n * @name module:activities/puzzles/HolePuzzle.HolePuzzlePanel#hiddenBox\n * @type {module:boxes/ActiveBox.ActiveBox} */\n hiddenBox: null,\n /**\n * Index of the hidden cell on the ActiveBagContent\n * @name module:activities/puzzles/HolePuzzle.HolePuzzlePanel#hiddenBoxIndex\n * @type {number} */\n hiddenBoxIndex: -1,\n /**\n * List of mouse, touch and keyboard events intercepted by this panel\n * @override\n * @name module:activities/puzzles/HolePuzzle.HolePuzzlePanel#events\n * @type {string[]} */\n events: ['click'],\n});\n\n/**\n * Panel class associated to this type of activity: {@link module:activities/puzzles/HolePuzzle.HolePuzzlePanel HolePuzzlePanel}\n * @type {class} */\nHolePuzzle.Panel = HolePuzzlePanel;\n\n// Register activity class\nexport default Activity.registerClass('@puzzles.HolePuzzle', HolePuzzle);\n","/**\n * File : activities/text/TextActivityBase.js\n * Created : 16/05/2015\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\n/* global window */\n\nimport $ from 'jquery';\nimport { stringToWords } from '../../Utils.js';\nimport { Activity, ActivityPanel } from '../../Activity.js';\nimport ActiveBox from '../../boxes/ActiveBox.js';\nimport BoxBase from '../../boxes/BoxBase.js';\n\n/**\n * This class and its visual component {@link module:activities/text/TextActivityBase.TextActivityBasePanel TextActivityBasePanel} are the base for text\n * activities like {@link module:activities/text/FillInBlanks.FillInBlanks FillInBlanks}, {@link module:activities/text/IdentifyText.IdentifyText IdentifyText}, {@link module:activities/text/OrderText.OrderText OrderText} and {@link module:activities/text/Complete.Complete Complete}.\n * @extends module:Activity.Activity\n */\nexport class TextActivityBase extends Activity {\n /**\n * TextActivityBase constructor\n * @param {module:project/JClicProject.JClicProject} project - The project to which this activity belongs\n */\n constructor(project) {\n super(project);\n }\n\n /**\n * Retrieves the minimum number of actions needed to solve this activity\n * @override\n * @returns {number}\n */\n getMinNumActions() {\n return this.document ? this.document.numTargets : 0;\n }\n}\n\nObject.assign(TextActivityBase.prototype, {\n /**\n * This is the object used to evaluate user's answers in text activities.\n * @name module:activities/text/TextActivityBase.TextActivityBase#ev\n * @type {module:activities/text/Evaluator.Evaluator} */\n ev: null,\n /**\n * This is the label used by text activities for the `check` button, when present.\n * @name module:activities/text/TextActivityBase.TextActivityBase#checkButtonText\n * @type {string} */\n checkButtonText: null,\n /**\n * When `true`, a text will be shown before the beginning of the activity.\n * @name module:activities/text/TextActivityBase.TextActivityBase#prevScreen\n * @type {boolean} */\n prevScreen: false,\n /**\n * Optional text to be shown before the beginning of the activity. When `null`, this text is\n * the main document.\n * @name module:activities/text/TextActivityBase.TextActivityBase#prevScreenText\n * @type {string} */\n prevScreenText: null,\n /**\n * The style of the optional text to be shown before the beginning of the activity.\n * @name module:activities/text/TextActivityBase.TextActivityBase#prevScreenStyle\n * @type {module:boxes/BoxBase.BoxBase} */\n prevScreenStyle: null,\n /**\n * Maximum amount of time for showing the previous document.\n * @name module:activities/text/TextActivityBase.TextActivityBase#prevScreenMaxTime\n * @type {number} */\n prevScreenMaxTime: -1,\n});\n\n/**\n * The {@link module:Activity.ActivityPanel ActivityPanel} where text activities (based on {@link module:activities/text/TextActivityBase.TextActivityBase TextActivityBase}) are played.\n * @extends module:Activity.ActivityPanel\n */\n//export class TextActivityBasePanel extends Activity.Panel {\nexport class TextActivityBasePanel extends ActivityPanel {\n /**\n * TextActivityBasePanel constructor\n * @param {module:Activity.Activity} act - The {@link module:Activity.Activity Activity} to which this Panel belongs\n * @param {module:JClicPlayer.JClicPlayer} ps - Any object implementing the methods defined in the\n * [PlayStation](http://projectestac.github.io/jclic/apidoc/edu/xtec/jclic/PlayStation.html) Java interface.\n * @param {external:jQuery} [$div] - The jQuery DOM element where this Panel will deploy\n */\n constructor(act, ps, $div) {\n super(act, ps, $div);\n this.targets = [];\n }\n\n /**\n * Fills a jQuery DOM element (usually a 'div') with the specified {@link module:activities/text/TextActivityDocument.TextActivityDocument TextActivityDocument}.\n * @param {external:jQuery} $div - The jQuery DOM object to be filled with the document.\n * @param {module:activities/text/TextActivityDocument.TextActivityDocument} doc - The document\n */\n setDocContent($div, doc) {\n\n // Empties the container of any pre-existing content\n // and sets the background and other attributes indicated by the main\n // style of the document.\n // It also sets the 'overflow' CSS attribute to 'auto', which will display a\n // vertical scroll bar when needed\n $div.empty().css(doc.style['default'].css).css({ display: 'flex', 'flex-direction': 'column' });\n\n const $scroller = $('<div/>').css({ 'flex-grow': 1, overflow: 'auto' });\n const $doc = $('<div/>', { class: 'JClicTextDocument' }).css({ 'padding': 4 }).css(doc.style['default'].css);\n\n let currentPStyle = null;\n const popupSpans = [];\n\n //\n // Process paragraphs\n doc.p.forEach(p => {\n // Creates a new DOM paragraph\n const $p = $('<p/>').css({ margin: 0 });\n let empty = true;\n\n // Check if the paragraph has its own style\n if (p.style) {\n currentPStyle = doc.style[p.style].css;\n $p.css(currentPStyle);\n } else\n currentPStyle = null;\n\n // Check if the paragraph has a special alignment\n if (p.Alignment) {\n const al = Number(p.Alignment);\n $p.css({ 'text-align': al === 1 ? 'center' : al === 2 ? 'right' : 'left' });\n }\n\n // Process the paragraph elements\n p.elements.forEach(element => {\n // Elements will be inserted as 'span' DOM elements, or as simple text if they don't\n // have specific attributes.\n let $span;\n switch (element.objectType) {\n case 'text':\n const parsedText = $('<span/>').html(element.text).text();\n const fragments = this.spanText\n ? stringToWords(parsedText)\n : [{ text: parsedText, sep: '' }];\n fragments.forEach(({ text, sep }) => {\n let initialCSS = { ...this.act.document.style['default'].css };\n if (element?.attr?.style)\n initialCSS = { ...initialCSS, ...doc.style[element.attr.style].css };\n if (element?.attr?.css)\n initialCSS = { ...initialCSS, ...element.attr.css };\n const txtBlocs = this.spanChars ? [...text] : [text];\n txtBlocs.forEach((str) => {\n if (element.attr) {\n // Text uses a specific style and/or individual attributes\n $span = $('<span/>').html(str).css(initialCSS);\n // Save initialCSS for later use\n $span.initialCSS = initialCSS;\n $p.append(this.$createSpanElement($span));\n } else {\n if (this.spanText) {\n $span = $('<span/>').html(str);\n $p.append(this.$createSpanElement($span));\n }\n else\n $p.append(str);\n }\n });\n if (sep !== '')\n $p.append(sep);\n });\n break;\n\n case 'cell':\n // Create a new ActiveBox based on this ActiveBoxContent\n $span = $('<span/>');\n const box = ActiveBox.createCell($span.css({ position: 'relative' }), element);\n $span.css({ 'display': 'inline-block', 'vertical-align': 'middle' });\n if (element.mediaContent) {\n $span.on('click', event => {\n event.preventDefault();\n this.ps.stopMedia(1);\n box.playMedia(this.ps);\n return false;\n });\n }\n $p.append($span);\n break;\n\n case 'target':\n $span = $('<span/>');\n if (this.showingPrevScreen) {\n $span.text(element.text);\n $p.append($span);\n break;\n }\n\n const target = element;\n let $popup = null;\n // Process target popups\n if (target.infoMode !== 'no_info' && target.popupContent) {\n $popup = $('<span/>').css({ position: 'absolute', 'padding-top': '2pt', display: 'none' });\n // Create a new ActiveBox based on popupContent\n const popupBox = ActiveBox.createCell($popup, target.popupContent);\n if (target.popupContent.mediaContent) {\n $popup.on('click', event => {\n event.preventDefault();\n this.ps.stopMedia(1);\n if (popupBox)\n popupBox.playMedia(this.ps);\n else if (target.popupContent.mediaContent)\n this.ps.playMedia(target.popupContent.mediaContent);\n return false;\n });\n }\n target.$popup = $popup;\n // Save for later setting of top-margin\n popupSpans.push({ p: $p, span: $popup, box: popupBox });\n }\n\n $span = this.$createTargetElement(target, $span);\n target.num = this.targets.length;\n target.pos = target.num;\n this.targets.push(target);\n if ($span) {\n $span.css(doc.style['default'].css);\n if (currentPStyle)\n $span.css(currentPStyle);\n if (this.targetsMarked) {\n if (target.attr) {\n // Default style name for targets is 'target'\n if (!target.attr.style)\n target.attr.style = 'target';\n $span.css(doc.style[target.attr.style].css);\n // Check if target has specific attributes\n if (target.attr.css)\n $span.css(target.attr.css);\n } else if (doc.style['target'])\n $span.css(doc.style['target'].css);\n } else {\n target.targetStatus = 'HIDDEN';\n }\n\n // Catch on-demand popups with `F1`, cancel with `Escape`\n if ($popup !== null && target.infoMode === 'onDemand') {\n $span.on('keydown', ev => {\n if (ev.key === target.popupKey) {\n ev.preventDefault();\n this.showPopup($popup, target.popupMaxTime, target.popupDelay);\n } else if (ev.key === 'Escape') {\n ev.preventDefault();\n this.showPopup(null);\n }\n });\n }\n }\n\n if ($popup && $span) {\n if (target.isList)\n $p.append($span).append($popup);\n else\n $p.append($popup).append($span);\n } else if ($span)\n $p.append($span);\n\n target.$p = $p;\n break;\n }\n empty = false;\n });\n if (empty)\n // Don't leave paragraphs empty\n $p.html(' ');\n\n // Adds the paragraph to the DOM element\n $doc.append($p);\n });\n\n $div.append($scroller.append($doc));\n\n if (this.act.checkButtonText && !this.showingPrevScreen) {\n this.$checkButton = $('<button/>', { class: 'StockBtn' })\n .html(this.act.checkButtonText)\n .css({ width: '100%', 'flex-shrink': 0 })\n .on('click', () => this.evaluatePanel());\n $div.append(this.$checkButton);\n }\n\n // Place popups below its target baseline\n popupSpans.forEach(pspan => pspan.span.css({ 'margin-top': pspan.p.css('font-size') }));\n\n // Init Evaluator\n if (this.act.ev)\n this.act.ev.init(this.act.project.settings.locales);\n\n return $div;\n }\n\n /**\n * Creates a target DOM element.\n * This method can be overridden in subclasses to create specific types of targets.\n * @param {module:activities/text/TextActivityDocument.TextTarget} target - The target related to the DOM object to be created\n * @param {external:jQuery} $span - An initial DOM object (usually a `span`) that can be used\n * to store the target, or replaced by another type of object.\n * @returns {external:jQuery} - The jQuery DOM element loaded with the target data.\n */\n $createTargetElement(target, $span) {\n $span.text(target.text);\n target.$span = $span;\n return $span;\n }\n\n /**\n * Creates a 'span' element, used to isolate elements of text not involved in targets.\n * Used only when {@link spanText} is true.\n * @param {external:jQuery} $span - An initial DOM object (usually a `span`) that can be used\n * to store the target, or replaced by another type of object.\n * @returns {external:jQuery} - The jQuery DOM element loaded with the span data.\n */\n $createSpanElement($span) {\n return $span;\n }\n\n /**\n * Basic initialization procedure, common to all activities.\n * @override\n */\n initActivity() {\n if (this.act.prevScreen)\n this.preInitActivity();\n else\n this.startActivity();\n }\n\n /**\n * Called when the activity starts playing\n * @override\n */\n startActivity() {\n super.initActivity();\n this.setAndPlayMsg('initial', 'start');\n this.setDocContent(this.$div, this.act.document);\n this.playing = true;\n }\n\n /**\n * Called when the text activity has a 'previous screen' information to be shown before the\n * activity starts\n */\n preInitActivity() {\n if (!this.act.prevScreen)\n return;\n\n const prevScreenEnd = () => {\n this.showingPrevScreen = false;\n this.$div.off('click');\n if (this.prevScreenTimer) {\n window.clearTimeout(this.prevScreenTimer);\n this.prevScreenTimer = null;\n }\n this.startActivity();\n return true;\n };\n\n this.showingPrevScreen = true;\n this.$div.empty();\n\n if (!this.act.prevScreenText) {\n this.setDocContent(this.$div, this.act.document);\n } else {\n if (!this.act.prevScreenStyle)\n this.act.prevScreenStyle = new BoxBase();\n this.$div.css(this.act.prevScreenStyle.getCSS()).css('overflow', 'auto');\n const $html = $('<div/>', { class: 'JClicTextDocument' })\n .css({ 'padding': 4 })\n .css(this.act.prevScreenStyle.getCSS())\n .append(this.act.prevScreenText);\n this.$div.append($html);\n }\n\n this.enableCounters(true, false, false);\n this.ps.setCounterValue('time', 0);\n\n this.ps.setMsg(this.act.messages['previous']);\n\n if (this.act.prevScreenMaxTime > 0) {\n this.ps.setCountDown('time', this.act.prevScreenMaxTime);\n this.prevScreenTimer = window.setTimeout(prevScreenEnd, this.act.prevScreenMaxTime * 1000);\n }\n\n this.$div.on('click', prevScreenEnd);\n this.ps.playMsg();\n }\n\n /**\n * Called when the user clicks on the check button\n * @returns {boolean} - `true` when the panel is OK, `false` otherwise.\n */\n evaluatePanel() {\n this.finishActivity(true);\n return true;\n }\n\n /**\n * Ordinary ending of the activity, usually called form `processEvent`\n * @override\n * @param {boolean} result - `true` if the activity was successfully completed, `false` otherwise\n */\n finishActivity(result) {\n if (this.$checkButton)\n this.$checkButton.prop('disabled', true);\n this.targets.forEach(t => {\n if (t.$comboList)\n t.$comboList.prop('disabled', true);\n });\n this.showPopup(null);\n super.finishActivity(result);\n }\n\n /**\n * Main handler used to process mouse, touch, keyboard and edit events\n * @override\n * @param {external:Event} _event - The HTML event to be processed\n * @returns {boolean} - When this event handler returns `false`, jQuery will stop its\n * propagation through the DOM tree. See: {@link http://api.jquery.com/on}\n */\n processEvent(_event) {\n return this.playing;\n }\n\n /**\n * @param {external:jQuery} $popup - The popup to display, or _null _ to just hide the current popup\n * @param {number} maxTime - The maximum time to mantain the popup on screen, in seconds\n * @param {number} waitTime - When set, indicates the number of seconds to wait before show the popup\n */\n showPopup($popup, maxTime, waitTime) {\n // Hide current popup\n if (this.$currentPopup) {\n this.$currentPopup.css({ display: 'none' });\n this.$currentPopup = null;\n if (this.currentPopupTimer) {\n window.clearTimeout(this.currentPopupTimer);\n this.currentPopupTimer = 0;\n }\n }\n\n // Clear popupWaitTimer\n if (this.popupWaitTimer) {\n window.clearTimeout(this.popupWaitTimer);\n this.popupWaitTimer = 0;\n }\n\n // Prepare popup timer\n if (waitTime) {\n this.popupWaitTimer = window.setTimeout(() => {\n this.showPopup($popup, maxTime);\n }, waitTime * 1000);\n return;\n }\n\n if ($popup) {\n $popup.css({ display: '' });\n $popup.trigger('click');\n\n this.$currentPopup = $popup;\n if (maxTime) {\n this.currentPopupTimer = window.setTimeout(() => {\n $popup.css({ display: 'none' });\n if (this.$currentPopup === $popup) {\n this.$currentPopup = null;\n this.currentPopupTimer = 0;\n }\n }, maxTime * 1000);\n }\n }\n }\n}\n\nObject.assign(TextActivityBasePanel.prototype, {\n /**\n * Array of jQuery DOM elements (usually of type 'span') containing the targets of this activity\n * @name module:activities/text/TextActivityBase.TextActivityBasePanel#targets\n * @type {external:jQuery[]} */\n targets: null,\n /**\n * Flag indicating if targets must be visually marked at the beginning of the activity.\n * Should be `true` except for {@link module:activities/text/IdentifyText.IdentifyText IdentifyText} activities.\n * @name module:activities/text/TextActivityBase.TextActivityBasePanel#targetsMarked\n * @type {boolean} */\n targetsMarked: true,\n /**\n * The button used to check the activity, only when `Activity.checkButtonText` is not null\n * @name module:activities/text/TextActivityBase.TextActivityBasePanel#$checkButton\n * @type {external:jQuery}*/\n $checkButton: null,\n /**\n * System timer used to close the previous document when act.maxTime is reached.\n * @name module:activities/text/TextActivityBase.TextActivityBasePanel#prevScreenTimer\n * @type {number} */\n prevScreenTimer: null,\n /**\n * The popup currently been displayed\n * @name module:activities/text/TextActivityBase.TextActivityBasePanel#$currentPopup\n * @type {external:jQuery} */\n $currentPopup: null,\n /**\n * A timer controlling the time the current popup will be displayed\n * @name module:activities/text/TextActivityBase.TextActivityBasePanel#currentPopupTimer\n * @type {number} */\n currentPopupTimer: 0,\n /**\n * A timer prepared to display a popup after a while\n * @name module:activities/text/TextActivityBase.TextActivityBasePanel#popupWaitTimer\n * @type {number} */\n popupWaitTimer: 0,\n /**\n * When true, all text outside of targets and cells will be inserted as independent words or letters,\n * using 'span' elements. {@link module:activities/text/TextActivityBase.TextActivityBasePanel#$createSpanElement} can be used\n * to customize these elements.\n * @name module:activities/text/TextActivityBase.TextActivityBasePanel#spanText\n * @type {boolean} */\n spanText: false,\n /**\n * When true, text spanning will be done at char level: each single letter will be a clickacle span.\n * Used only in activities of type \"itentify letters\"\n * @name module:activities/text/TextActivityBase.TextActivityBasePanel#spanChars\n * @type {boolean} */\n spanChars: false,\n});\n\n/**\n * Panel class associated to this type of activity: {@link module:activities/text/TextActivityBase.TextActivityBasePanel TextActivityBasePanel}\n * @type {class} */\nTextActivityBase.Panel = TextActivityBasePanel;\n\nexport default TextActivityBase;\n","/**\n * File : activities/text/Complete.js\n * Created : 20/06/2015\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\nimport Activity from '../../Activity.js';\nimport { TextActivityBase, TextActivityBasePanel } from './TextActivityBase.js';\n\n/**\n * This type of text activity suggests users to complete a given text, without any help on where to\n * write the missing words or phrases.\n * @extends module:activities/text/TextActivityBase.TextActivityBase\n */\nexport class Complete extends TextActivityBase {\n /**\n * Complete constructor\n * @param {module:project/JClicProject.JClicProject} project - The project to which this activity belongs\n */\n constructor(project) {\n super(project);\n }\n}\n\n/**\n * The {@link module:activities/text/TextActivityBase.TextActivityBasePanel TextActivityBasePanel} where {@link module:activities/text/Complete.Complete Complete} activities are played.\n * @extends module:activities/text/TextActivityBasePanel.TextActivityBasePanel\n */\nexport class CompletePanel extends TextActivityBasePanel {\n /**\n * CompletePanel constructor\n * @param {module:Activity.Activity} act - The {@link module:Activity.Activity Activity} to which this Panel belongs\n * @param {module:JClicPlayer.JClicPlayer} ps - Any object implementing the methods defined in the\n * [PlayStation](http://projectestac.github.io/jclic/apidoc/edu/xtec/jclic/PlayStation.html) Java interface.\n * @param {external:jQuery} [$div] - The jQuery DOM element where this Panel will deploy\n */\n constructor(act, ps, $div) {\n super(act, ps, $div);\n }\n\n /**\n * Creates a target DOM element for the provided target.\n * @override\n * @param {module:activities/text/TextActivityDocument.TextTarget} _target - The target related to the DOM object to be created\n * @param {external:jQuery} _$span - - An initial DOM object (usually a `span`) that can be used\n * to store the target, or replaced by another type of object.\n * @returns {external:jQuery} - The jQuery DOM element loaded with the target data.\n */\n $createTargetElement(_target, _$span) {\n // Targets are always hidden in this type of activities\n return null;\n }\n\n /**\n * Called when the activity starts playing\n * @override\n */\n startActivity() {\n super.startActivity();\n this.$div.find('.JClicTextDocument').attr('contenteditable', 'true').attr('spellcheck', 'false');\n }\n\n /**\n * Evaluates all the targets in this panel. This method is usually called from the `Check` button.\n * @override\n * @returns {boolean} - `true` when all targets are OK, `false` otherwise.\n */\n evaluatePanel() {\n // TODO: Mark errors!\n const\n currentText = this.$div.find('.JClicTextDocument').text().trim(),\n originalText = this.act.document.getRawText(),\n ok = this.act.ev.checkText(currentText, originalText);\n\n this.ps.reportNewAction(this.act, 'WRITE', currentText, originalText, ok, this.targets.length);\n\n if (ok) {\n this.finishActivity(true);\n return true;\n } else {\n this.playEvent('finishedError');\n }\n return false;\n }\n\n /**\n * Ordinary ending of the activity, usually called form `processEvent`\n * @param {boolean} result - `true` if the activity was successfully completed, `false` otherwise\n */\n finishActivity(result) {\n this.$div.find('.JClicTextDocument').attr('contenteditable', 'false');\n return super.finishActivity(result);\n }\n}\n\n/**\n * Panel class associated to this type of activity: {@link module:activities/text/Complete.CompletePanel CompletePanel}\n * @type {class} */\nComplete.Panel = CompletePanel;\n\n// Register activity class\nexport default Activity.registerClass('@text.Complete', Complete);\n","/**\n * File : activities/text/FillInBlanks.js\n * Created : 20/06/2015\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Catalan Educational Telematic Network (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\nimport Activity from '../../Activity.js';\nimport $ from 'jquery';\nimport { fillString, setSelectionRange, getCaretCharacterOffsetWithin } from '../../Utils.js';\nimport { TextActivityBase, TextActivityBasePanel } from './TextActivityBase.js';\n\n/**\n * In this type of activity the text document has some blanks that must be filled-in. The blanks\n * can be drop-down boxes or text fields (empty or pre-filled with an initial text). Blanks can\n * also have associated clues, shown as \"pop-ups\".\n * @extends module:activities/text/TextActivityBase.TextActivityBase\n */\nexport class FillInBlanks extends TextActivityBase {\n /**\n * FillInBlanks constructor\n * @param {module:project/JClicProject.JClicProject} project - The {@link module:project/JClicProject.JClicProject JClicProject} to which this activity belongs\n */\n constructor(project) {\n super(project);\n }\n\n /**\n * This kind of activity usually makes use of the keyboard\n * @override\n * @returns {boolean}\n */\n needsKeyboard() {\n return true;\n }\n}\n\nObject.assign(FillInBlanks.prototype, {\n /**\n * Whether to jump or not to the next target when the current one is solved.\n * @name module:activities/text/FillInBlanks.FillInBlanks#autoJump\n * @type {boolean} */\n autoJump: false,\n /**\n * Whether to block or not the jump to other targets until the current one\n * is resolved.\n * @name module:activities/text/FillInBlanks.FillInBlanks#forceOkToAdvance\n * @type {boolean} */\n forceOkToAdvance: false,\n});\n\n/**\n * The {@link module:activities/text/TextActivityBase.TextActivityBasePanel} where {@link module:activities/text/FillInBlanks.FillInBlanks FillInBlanks} activities are played.\n * @extends module:activities/text/TextActivityBase.TextActivityBasePanel\n */\nexport class FillInBlanksPanel extends TextActivityBasePanel {\n /**\n * FillInBlanksPanel constructor\n * @param {module:Activity.Activity} act - The {@link module:Activity.Activity Activity} to which this Panel belongs\n * @param {module:JClicPlayer.JClicPlayer} ps - Any object implementing the methods defined in the\n * [PlayStation](http://projectestac.github.io/jclic/apidoc/edu/xtec/jclic/PlayStation.html) Java interface.\n * @param {external:jQuery} [$div] - The jQuery DOM element where this Panel will deploy\n */\n constructor(act, ps, $div) {\n super(act, ps, $div);\n }\n\n /**\n * Creates a target DOM element for the provided target. This DOM element can be an editable\n * `span` or a `select` with specific `option` elements (when the target is a drop-down list)\n * @override\n * @param {module:activities/text/TextActivityDocument.TextTarget} target - The target related to the DOM object to be created\n * @param {external:jQuery} $span - - An initial DOM object (usually a `span`) that can be used\n * to store the target, or replaced by another type of object.\n * @returns {external:jQuery} - The jQuery DOM element loaded with the target data.\n */\n $createTargetElement(target, $span) {\n\n $span.addClass('JClicTextTarget');\n\n const idLabel = `target${`000${this.targets.length - 1}`.slice(-3)}`;\n if (target.isList && target.options && target.options.length > 0) {\n // Use a `select` element\n $span = $('<select/>', { id: idLabel, name: idLabel });\n if (target.options[0].trim() !== '')\n $('<option selected/>', { value: '', text: '' }).appendTo($span);\n target.options.forEach(op => $('<option/>', { value: op, text: op }).appendTo($span));\n target.$comboList = $span.on('focus change', event => {\n event.textTarget = target;\n this.processEvent(event);\n });\n } else {\n // Use a `span` element with the `contentEditable` attribute set `on`\n target.currentText = target.iniText ?\n target.iniText\n : fillString(target.iniChar, target.numIniChars);\n\n target.$span = $span.text(target.currentText).attr({\n contenteditable: 'true',\n id: idLabel,\n autocomplete: 'off',\n spellcheck: 'false'\n }).on('focus input blur', event => {\n event.textTarget = target;\n this.processEvent(event);\n }).on('keydown keyup', event => {\n // Catch `enter` key in Firefox\n if (event.keyCode === 13) {\n event.preventDefault();\n if (event.type === 'keydown') {\n // Simulate a `blur` event\n event.textTarget = target;\n event.type = 'blur';\n this.processEvent(event);\n }\n }\n });\n }\n return $span;\n }\n\n /**\n * Evaluates all the targets in this panel. This method is usually called from the `Check` button.\n * @override\n * @returns {boolean} - `true` when all targets are OK, `false` otherwise.\n */\n evaluatePanel() {\n let targetsOk = 0;\n const numTargets = this.targets.length;\n this.targets.forEach(target => {\n const\n result = this.act.ev.evalText(target.readCurrentText(), target.answers),\n ok = this.act.ev.isOk(result);\n target.targetStatus = ok ? 'SOLVED' : 'WITH_ERROR';\n if (ok)\n targetsOk++;\n this.markTarget(target, result);\n this.ps.reportNewAction(this.act, 'WRITE', target.currentText, target.getAnswers(), ok, targetsOk);\n });\n if (targetsOk === numTargets) {\n this.finishActivity(true);\n return true;\n } else\n this.playEvent('finishedError');\n return false;\n }\n\n /**\n * Checks if the specified TextTarget has a valid answer in its `currentText` field\n * @param {module:activities/text/TextActivityDocument.TextTarget} target - The target to check\n * @param {boolean} onlyCheck - When `true`, the cursor will no be re-positioned\n * @param {number} [jumpDirection] - `1` to go forward, `-1` to go back.\n * @returns {boolean} - `true` when the target contains a valid answer\n */\n checkTarget(target, onlyCheck, jumpDirection) {\n const\n result = this.act.ev.evalText(target.currentText, target.answers),\n ok = this.act.ev.isOk(result);\n\n target.targetStatus = ok ? 'SOLVED' : 'WITH_ERROR';\n if (onlyCheck)\n return ok;\n\n this.markTarget(target, result);\n const targetsOk = this.countSolvedTargets(false, false);\n if (target.currentText.length > 0)\n this.ps.reportNewAction(this.act, 'WRITE', target.currentText, target.getAnswers(), ok, targetsOk);\n if (ok && targetsOk === this.targets.length) {\n this.finishActivity(true);\n return ok;\n } else if (target.currentText.length > 0)\n this.playEvent(ok ? 'actionOk' : 'actionError');\n\n if (jumpDirection && jumpDirection !== 0) {\n let p = target.num + jumpDirection;\n if (p >= this.targets.length)\n p = 0;\n else if (p < 0)\n p = this.targets.length - 1;\n\n const destTarget = this.targets[p];\n if (destTarget.$span) {\n destTarget.$span.trigger('focus');\n setSelectionRange(destTarget.$span.get(-1), 0, 0);\n } else if (destTarget.$comboList)\n destTarget.$comboList.trigger('focus');\n }\n return ok;\n }\n\n /**\n * Counts the number of targets with `SOLVED` status\n * @param {boolean} checkNow - When `true`, all targets will be evaluated. Otherwise, only the\n * current value of `targetStatus` will be checked.\n * @param {boolean} [mark] - When `true`, errors in the target answer will be marked.\n * @returns {number} - The number of targets currently solved.\n */\n countSolvedTargets(checkNow, mark) {\n return this.targets.reduce((n, target) => {\n if (checkNow) {\n target.readCurrentText();\n this.checkTarget(target, !mark);\n }\n return target.targetStatus === 'SOLVED' ? ++n : n;\n }, 0);\n }\n\n /**\n * Visually marks the target as 'solved OK' or 'with errors'.\n * @param {module:activities/text/TextActivityDocument.TextTarget} target - The text target to be marked.\n * @param {number[]} attributes - - Array of flags indicating the status (OK or error) for each\n * character in `target.currentText`.\n */\n markTarget(target, attributes) {\n if (target.$comboList || this.act.ev.isOk(attributes))\n target.checkColors();\n else if (target.$span) {\n // Identify text fragments\n const\n txt = target.currentText,\n fragments = [];\n let\n currentStatus = -1,\n currentFragment = -1,\n i = 0;\n for (; i < attributes.length && i < txt.length; i++) {\n if (attributes[i] !== currentStatus) {\n fragments[++currentFragment] = '';\n currentStatus = attributes[i];\n }\n fragments[currentFragment] += txt.charAt(i);\n }\n if (i < txt.length)\n fragments[currentFragment] += txt.substring(i);\n // Empty and re-fill $span\n target.$span.empty();\n currentStatus = attributes[0];\n fragments.forEach(fragment => {\n $('<span/>')\n .text(fragment)\n .css(target.doc.style[currentStatus === 0 ? 'target' : 'targetError'].css)\n .appendTo(target.$span);\n currentStatus ^= 1;\n });\n }\n // Target has been marked, so clear the 'modified' flag\n target.flagModified = false;\n }\n\n /**\n * Called by {@link module:JClicPlayer.JClicPlayer JClicPlayer} when this activity panel is fully visible, just after the\n * initialization process.\n * @override\n */\n activityReady() {\n super.activityReady();\n\n // Prevent strange behavior with GoogleChrome when `white-space` CSS attribute is set to\n // `pre-wrap` (needed for tabulated texts)\n $('.JClicTextTarget').css('white-space', 'normal');\n if (this.targets.length > 0 && this.targets[0].$span)\n this.targets[0].$span.trigger('focus');\n }\n\n /**\n * Ordinary ending of the activity, usually called form `processEvent`\n * @override\n * @param {boolean} result - `true` if the activity was successfully completed, `false` otherwise\n */\n finishActivity(result) {\n this.targets.forEach(target => {\n if (target.$span)\n target.$span.removeAttr('contenteditable').trigger('blur');\n else if (target.$comboList)\n target.$comboList.prop('disabled', true).trigger('blur');\n });\n return super.finishActivity(result);\n }\n\n /**\n * Main handler used to process mouse, touch, keyboard and edit events.\n * @override\n * @param {external:Event} event - The HTML event to be processed\n * @returns {boolean} - When this event handler returns `false`, jQuery will stop its\n * propagation through the DOM tree. See: {@link http://api.jquery.com/on}\n */\n processEvent(event) {\n if (!super.processEvent(event))\n return false;\n\n const target = event.textTarget;\n let $span = null, pos = 0;\n switch (event.type) {\n case 'focus':\n if (target) {\n if (target.$span && target.$span.children().length > 0) {\n // Clear inner spans used to mark errors\n $span = target.$span;\n pos = Math.min(\n target.currentText.length,\n getCaretCharacterOffsetWithin($span.get(-1)));\n $span.empty();\n $span.text(target.currentText);\n setSelectionRange($span.get(-1), pos, pos);\n target.flagModified = true;\n } else if (target.$comboList)\n target.$comboList.css(target.doc.style['target'].css);\n\n if (target.$popup && (target.infoMode === 'always' || target.infoMode === 'onError' && target.targetStatus === 'WITH_ERROR'))\n this.showPopup(target.$popup, target.popupMaxTime, target.popupDelay);\n else\n this.showPopup(null);\n }\n break;\n\n case 'blur':\n if (target.flagModified && !this.$checkButton)\n this.checkTarget(target, false, 1);\n break;\n\n case 'input':\n if (target && target.$span) {\n $span = target.$span;\n let txt = $span.html();\n // Check for `enter` key\n if (/(<br>|\\n|\\r)/.test(txt)) {\n txt = txt.replace(/(<br>|\\n|\\r)/g, '');\n $span.html(txt);\n target.currentText = $span.text();\n return this.$checkButton ? false : this.checkTarget(target, false, 1);\n }\n // Check if text has changed\n // From here, use 'text' instead of 'html' to avoid HTML entities\n txt = $span.text();\n if (txt !== target.currentText) {\n // Span text has changed!\n target.flagModified = true;\n const added = txt.length - target.currentText.length;\n if (added > 0) {\n if (txt.indexOf(target.iniChar) >= 0) {\n // Remove filling chars\n pos = getCaretCharacterOffsetWithin($span.get(-1));\n for (let i = 0; i < added; i++) {\n const p = txt.indexOf(target.iniChar);\n if (p < 0)\n break;\n txt = txt.substring(0, p) + txt.substring(p + 1);\n if (p < pos)\n pos--;\n }\n $span.text(txt);\n setSelectionRange($span.get(-1), pos, pos);\n }\n\n // Check if current text exceeds max length\n if (txt.length > target.maxLenResp) {\n pos = getCaretCharacterOffsetWithin($span.get(-1));\n txt = txt.substring(0, target.maxLenResp);\n pos = Math.min(pos, txt.length);\n $span.text(txt);\n setSelectionRange($span.get(-1), pos, pos);\n }\n } else if (txt === '') {\n txt = target.iniChar;\n $span.text(txt);\n setSelectionRange($span.get(-1), 0, 0);\n }\n target.currentText = txt;\n }\n }\n break;\n\n case 'change':\n if (target && target.$comboList) {\n target.currentText = target.$comboList.val();\n target.flagModified = true;\n return this.$checkButton ? false : this.checkTarget(target, false, 1);\n }\n break;\n\n default:\n break;\n }\n return true;\n }\n}\n\nObject.assign(FillInBlanksPanel.prototype, {\n /**\n * Flag indicating if the activity is open or locked\n * @name module:activities/text/FillInBlanks.FillInBlanksPanel#locked\n * @type {boolean} */\n locked: true,\n});\n\n/**\n * Panel class associated to this type of activity: {@link module:activities/text/FillInBlanks.FillInBlanksPanel FillInBlanksPanel}\n * @type {class} */\nFillInBlanks.Panel = FillInBlanksPanel;\n\n// Register activity class\nexport default Activity.registerClass('@text.FillInBlanks', FillInBlanks);\n","/**\n * File : boxes/TextGrid.js\n * Created : 12/06/2015\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\nimport { Rectangle, Timer, Point, Dimension, Stroke } from '../AWT.js';\nimport { roundTo } from '../Utils.js';\nimport AbstractBox from './AbstractBox.js';\nimport TextGridContent from './TextGridContent.js';\n\n/**\n * Default values\n * @type {object}\n */\nexport const defaults = {\n MIN_CELL_SIZE: 12,\n DEFAULT_CELL_SIZE: 20,\n MIN_INTERNAL_MARGIN: 2\n};\n\n/**\n * Binary flags used to mark status\n * @type {object}\n */\nexport const flags = {\n NORMAL: 0,\n INVERTED: 1,\n HIDDEN: 2,\n LOCKED: 4,\n MARKED: 8,\n TRANSPARENT: 16\n};\n\n/**\n * This class is a special type of {@link module:boxes/AbstractBox.AbstractBox AbstractBox} that displays a grid of single\n * characters.\n *\n * It's used {@link module:activities/textGrid/CrossWord.CrossWord CrossWord} and {@link module:activities/textGrid/WordSearch.WordSearch WordSearch} activities.\n * @extends module:boxes/AbstractBox.AbstractBox\n */\nexport class TextGrid extends AbstractBox {\n /**\n * TextGrid constructor\n * @param {module:boxes/AbstractBox.AbstractBox} parent - The AbstractBox to which this text grid belongs\n * @param {module:AWT.Container} container - The container where this text grid is placed.\n * @param {module:boxes/BoxBase.BoxBase} boxBase - The object where colors, fonts, border and other graphic properties\n * @param {number} x - `X` coordinate of the upper left corner of this grid\n * @param {number} y - `Y` coordinate of the upper left corner of this grid\n * @param {number} ncw - Number of columns of the grid\n * @param {number} nch - Nomber of rows of the grid\n * @param {number} cellW - Width of the cells\n * @param {number} cellH - Height of the cells\n * @param {boolean} border - When `true`, a border must be drawn between the cells\n */\n constructor(parent, container, boxBase, x, y, ncw, nch, cellW, cellH, border) {\n // *TextGrid* extends [AbstractBox](AbstractBox.html)\n super(parent, container, boxBase);\n this.pos.x = x;\n this.pos.y = y;\n this.nCols = Math.max(1, ncw);\n this.nRows = Math.max(1, nch);\n this.cellWidth = Math.max(cellW, defaults.MIN_CELL_SIZE);\n this.cellHeight = Math.max(cellH, defaults.MIN_CELL_SIZE);\n this.dim.width = cellW * this.nCols;\n this.dim.height = cellH * this.nRows;\n this.setChars(' ');\n this.preferredBounds = new Rectangle(this.pos, this.dim);\n this.setBorder(border);\n this.cursorTimer = new Timer(() => this.blink(0), 500, false);\n this.cursorEnabled = false;\n this.useCursor = false;\n this.wildTransparent = false;\n this.cursor = new Point();\n }\n\n /**\n * Factory constructor that creates an empty grid based on a {@link module:boxes/TextGridContent.TextGridContent TextGridContent}\n * @param {module:boxes/AbstractBox.AbstractBox} parent - The AbstractBox to which the text grid belongs\n * @param {module:AWT.Container} container - The container where the text grid will be placed.\n * @param {number} x - `X` coordinate of the upper left corner of the grid\n * @param {number} y - `Y` coordinate of the upper left corner of the grid\n * @param {module:boxes/TextGridContent.TextGridContent} tgc - Object with the content and other settings of the grid\n * @param {boolean} wildTransparent - When `true`, the wildcard character will be transparent\n * @returns {module:boxes/TextGrid.TextGrid}\n */\n static createEmptyGrid(parent, container, x, y, tgc, wildTransparent) {\n const result = new TextGrid(parent, container, tgc.style,\n x, y, tgc.ncw, tgc.nch, tgc.w, tgc.h, tgc.border);\n result.wild = tgc.wild;\n result.randomChars = tgc.randomChars;\n result.wildTransparent = wildTransparent;\n return result;\n }\n\n /**\n * Sets the characters to be placed in the cells of this TextGrid\n * @param {string} text\n */\n setChars(text) {\n this.chars = [];\n this.answers = [];\n this.attributes = [];\n for (let py = 0; py < this.nRows; py++) {\n const line = py < text.length ? text[py] : '';\n this.chars[py] = line.split('');\n this.answers[py] = [];\n this.attributes[py] = [];\n for (let px = 0; px < this.nCols; px++) {\n if (px >= line.length)\n this.chars[py][px] = ' ';\n this.answers[py][px] = this.chars[py][px];\n this.attributes[py][px] = flags.NORMAL;\n }\n }\n }\n\n /**\n * Substitutes the current content of all cells with wildcards with a randomly generated char.\n * @see TextGridContent#randomChars\n */\n randomize() {\n for (let py = 0; py < this.nRows; py++)\n for (let px = 0; px < this.nCols; px++)\n if (this.chars[py][px] === this.wild)\n this.chars[py][px] = this.randomChars.charAt(\n Math.floor(Math.random() * this.randomChars.length));\n }\n\n /**\n * Clears or sets global attributes to all cells\n * @param {boolean} lockWild - When `true`, the wildcard cells will be marked with special\n * attributes (used in CrossWords to mark black cells)\n * @param {boolean} clearChars - When `true`, the current content of cells will be erased.\n */\n setCellAttributes(lockWild, clearChars) {\n let atr = flags.LOCKED;\n if (this.wildTransparent)\n atr |= flags.TRANSPARENT;\n else\n atr |= flags.INVERTED | flags.HIDDEN;\n for (let py = 0; py < this.nRows; py++) {\n for (let px = 0; px < this.nCols; px++) {\n if (lockWild && this.chars[py][px] === this.wild)\n this.attributes[py][px] = atr;\n else {\n this.attributes[py][px] = flags.NORMAL;\n if (clearChars)\n this.chars[py][px] = ' ';\n }\n }\n }\n }\n\n /**\n * Sets or unsets the `locked` properties (black cell) to a specific cell.\n * @param {number} px - The logical 'X' coordinate of the cell\n * @param {number} py - The logical 'Y' coordinate of the cell\n * @param {boolean} locked - When true, the `locked` attribute will be on.\n */\n setCellLocked(px, py, locked) {\n if (px >= 0 && px < this.nCols && py >= 0 && py < this.nRows) {\n this.attributes[py][px] = locked ?\n flags.LOCKED |\n (this.wildTransparent ?\n flags.TRANSPARENT :\n flags.INVERTED |\n flags.HIDDEN) :\n flags.NORMAL;\n }\n }\n\n /**\n * For a specific cell located at column `rx` and row `ry`, finds the number of words delimited\n * by wildchars located behind its current position and in the same row and column. Used in\n * {@link module:activities/textGrid/CrossWord.CrossWord CrossWord} activities to find the definition for a specific cell.\n *\n * The result is returned as 'x' and 'y' properties of a logical point.\n * @param {number} rx - The 'X' position of the cell\n * @param {number} ry - The 'Y' position of the cell\n * @returns {module:AWT.Point} - The logical positions of the definition for this cell inside the list\n * of current definitions of its row and column. '0' means first definition of its row/column,\n * '1' the second one, etc.\n */\n getItemFor(rx, ry) {\n if (!this.isValidCell(rx, ry))\n return null;\n\n const point = new Point();\n let\n inBlack = false,\n startCount = false;\n\n for (let px = 0; px < rx; px++) {\n if ((this.attributes[ry][px] & flags.LOCKED) !== 0) {\n if (!inBlack) {\n if (startCount)\n point.x++;\n inBlack = true;\n }\n } else {\n startCount = true;\n inBlack = false;\n }\n }\n inBlack = false;\n startCount = false;\n for (let py = 0; py < ry; py++) {\n if ((this.attributes[py][rx] & flags.LOCKED) !== 0) {\n if (!inBlack) {\n if (startCount)\n point.y++;\n inBlack = true;\n }\n } else {\n startCount = true;\n inBlack = false;\n }\n }\n return point;\n }\n\n /**\n * Whether the blinking cursor must be enabled or disabled.\n * @param {boolean} status\n */\n setCursorEnabled(status) {\n this.cursorEnabled = status;\n if (status === true)\n this.startCursorBlink();\n else\n this.stopCursorBlink();\n }\n\n /**\n * Starts the {@link module:AWT.Timer} that makes the cursor blink.\n */\n startCursorBlink() {\n if (this.useCursor && this.cursorEnabled && this.cursorTimer && !this.cursorTimer.isRunning()) {\n this.blink(1);\n this.cursorTimer.start();\n }\n }\n\n /**\n * Stops the {@link module:AWT.Timer} that makes the cursor blink.\n */\n stopCursorBlink() {\n if (this.cursorTimer && this.cursorTimer.isRunning()) {\n this.cursorTimer.stop();\n this.blink(-1);\n }\n }\n\n /**\n * Moves the cursor in the specified x and y directions.\n * @param {number} dx - Amount to move in the 'X' axis\n * @param {number} dy - Amount to move in the 'Y' axis\n * @param {boolean} skipLocked - Skip locked cells (wildcards in {@link module:activities/textGrid/CrossWord.CrossWord CrossWord})\n */\n moveCursor(dx, dy, skipLocked) {\n if (this.useCursor) {\n const point = this.findNextCellWithAttr(this.cursor.x, this.cursor.y,\n skipLocked ? flags.LOCKED : flags.NORMAL,\n dx, dy, false);\n\n if (!this.cursor.equals(point))\n this.setCursorAt(point.x, point.y, skipLocked);\n }\n }\n\n /**\n * Finds the coordinates of the nearest non-locked cell (non-wildcard) moving on the indicated\n * 'X' and 'Y' directions.\n * @param {module:AWT.Point} - Logical coordinates of the starting point\n * @param {number} dx - 0 means no movement, 1 go right, -1 go left.\n * @param {number} dy - 0 means no movement, 1 go down, -1 go up.\n * @returns {module:AWT.Point}\n */\n findFreeCell(from, dx, dy) {\n let result = null;\n if (from && (dx !== 0 || dy !== 0)) {\n const scan = new Point(from);\n while (result === null) {\n scan.x += dx;\n scan.y += dy;\n if (scan.x < 0 || scan.x >= this.nCols || scan.y < 0 || scan.y >= this.nRows)\n break;\n if (!this.getCellAttribute(scan.x, scan.y, flags.LOCKED))\n result = scan;\n }\n }\n return result;\n }\n\n /**\n * Finds the first cell with the specified attributes at the specified state, starting\n * at specified point.\n * @param {number} startX - Starting X coordinate\n * @param {number} startY - Starting Y coordinate\n * @param {number} attr - Attribute to check. See {@link module:boxes/TextGrid.TextGrid.flags}.\n * @param {number} dx - 0 means no movement, 1 go right, -1 go left.\n * @param {number} dy - 0 means no movement, 1 go down, -1 go up.\n * @param {boolean} attrState - Desired state (enabled or disabled) of `attr`\n * @returns {module:AWT.Point}\n */\n findNextCellWithAttr(startX, startY, attr, dx, dy, attrState) {\n const point = new Point(startX + dx, startY + dy);\n while (true) {\n if (point.x < 0) {\n point.x = this.nCols - 1;\n if (point.y > 0)\n point.y--;\n else\n point.y = this.nRows - 1;\n } else if (point.x >= this.nCols) {\n point.x = 0;\n if (point.y < this.nRows - 1)\n point.y++;\n else\n point.y = 0;\n }\n if (point.y < 0) {\n point.y = this.nRows - 1;\n if (point.x > 0)\n point.x--;\n else\n point.x = this.nCols - 1;\n } else if (point.y >= this.nRows) {\n point.y = 0;\n if (point.x < this.nCols - 1)\n point.x++;\n else\n point.x = 0;\n }\n if (point.x === startX && point.y === startY ||\n this.getCellAttribute(point.x, point.y, attr) === attrState)\n break;\n point.x += dx;\n point.y += dy;\n }\n return point;\n }\n\n /**\n * Sets the blinking cursor at a specific point\n * @param {number} px - X coordinate\n * @param {number} py - Y coordinate\n * @param {boolean} skipLocked - Skip locked (wildcard) cells\n */\n setCursorAt(px, py, skipLocked) {\n this.stopCursorBlink();\n if (this.isValidCell(px, py)) {\n this.cursor.x = px;\n this.cursor.y = py;\n this.useCursor = true;\n if (skipLocked && this.getCellAttribute(px, py, flags.LOCKED)) {\n this.moveCursor(1, 0, skipLocked);\n } else {\n if (this.cursorEnabled)\n this.startCursorBlink();\n }\n }\n }\n\n /**\n * Sets the `useCursor` property of this text grid\n * @param {boolean} value\n */\n setUseCursor(value) {\n this.useCursor = value;\n }\n\n /**\n * Gets the current position of the blinking cursor\n * @returns {module:AWT.Point}\n */\n getCursor() {\n return this.cursor;\n }\n\n /**\n * Counts the number of cells of this grid with the specified character\n * @param {string} ch\n * @returns {number}\n */\n countCharsLike(ch) {\n let result = 0;\n for (let py = 0; py < this.nRows; py++)\n for (let px = 0; px < this.nCols; px++)\n if (this.chars[py][px] === ch)\n result++;\n return result;\n }\n\n /**\n * Gets the number of cells of this grid\n * @returns {number}\n */\n getNumCells() {\n return this.nRows * this.nCols;\n }\n\n /**\n * Counts the number of coincidences between the `answers` array and the current content of this grid\n * @param {boolean} checkCase - Make comparisions case-sensitive\n * @returns {number}\n */\n countCoincidences(checkCase) {\n let result = 0;\n if (this.answers)\n for (let py = 0; py < this.nRows; py++)\n for (let px = 0; px < this.nCols; px++)\n if (this.isCellOk(px, py, checkCase))\n result++;\n return result;\n }\n\n /**\n * Checks if a specific cell is equivalent to the content of `answers` at its position\n * @param {number} px - X coordinate\n * @param {number} py - Y coordinate\n * @param {boolean} checkCase - Make comparisions case-sensitive\n * @returns {boolean}\n */\n isCellOk(px, py, checkCase) {\n let result = false;\n if (this.isValidCell(px, py)) {\n const ch = this.chars[py][px];\n if (ch !== this.wild) {\n const ch2 = this.answers[py][px];\n if (ch === ch2 ||\n !checkCase && ch.toUpperCase() === ch2.toUpperCase())\n result = true;\n }\n }\n return result;\n }\n\n /**\n * Gets the logical coordinates (in 'cell' units) of a device point into the grid\n * @param {module:AWT.Point} devicePoint\n * @returns {module:AWT.Point}\n */\n getLogicalCoords(devicePoint) {\n if (!this.contains(devicePoint))\n return null;\n const\n px = Math.floor((devicePoint.x - this.pos.x) / this.cellWidth),\n py = Math.floor((devicePoint.y - this.pos.y) / this.cellHeight);\n\n return this.isValidCell(px, py) ? new Point(px, py) : null;\n }\n\n /**\n * Checks if the specified logical coordinates are inside the valid bounds of the grid.\n * @param {number} px - 'X' coordinate\n * @param {number} py - 'Y' coordinate\n * @returns {boolean}\n */\n isValidCell(px, py) {\n return px < this.nCols && py < this.nRows && px >= 0 && py >= 0;\n }\n\n /**\n * Sets the specified character as a content of the cell at specified coordinates\n * @param {number} px - 'X' coordinate\n * @param {number} py - 'Y' coordinate\n * @param {string} ch - The character to set.\n */\n setCharAt(px, py, ch) {\n if (this.isValidCell(px, py)) {\n this.chars[py][px] = ch;\n this.repaintCell(px, py);\n }\n }\n\n /**\n * Gets the character of the cell at the specified coordinates\n * @param {number} px - 'X' coordinate\n * @param {number} py - 'Y' coordinate\n * @returns {string}\n */\n getCharAt(px, py) {\n return this.isValidCell(px, py) ? this.chars[py][px] : ' ';\n }\n\n /**\n * Gets the text formed by the letters between two cells that share a straight line on the grid.\n * The text can be formed horizontally, vertically and diagonal, both in left-to-right or\n * right-to-left direction.\n * @param {number} x0 - 'X' coordinate of the first cell\n * @param {number} y0 - 'Y' coordinate of the first cell\n * @param {number} x1 - 'X' coordinate of the second cell\n * @param {number} y1 - 'Y' coordinate of the second cell\n * @returns {string}\n */\n getStringBetween(x0, y0, x1, y1) {\n let sb = '';\n if (this.isValidCell(x0, y0) && this.isValidCell(x1, y1)) {\n let\n dx = x1 - x0,\n dy = y1 - y0;\n if (dx === 0 || dy === 0 || Math.abs(dx) === Math.abs(dy)) {\n const steps = Math.max(Math.abs(dx), Math.abs(dy));\n if (steps > 0) {\n dx /= steps;\n dy /= steps;\n }\n for (let i = 0; i <= steps; i++)\n sb += this.getCharAt(x0 + dx * i, y0 + dy * i);\n }\n }\n return sb;\n }\n\n /**\n * Sets a specific attribute to all cells forming a straight line between two cells on the grid.\n * @param {number} x0 - 'X' coordinate of the first cell\n * @param {number} y0 - 'Y' coordinate of the first cell\n * @param {number} x1 - 'X' coordinate of the second cell\n * @param {number} y1 - 'Y' coordinate of the second cell\n * @param {number} attribute - The binary flag representing this attribute. See {@link module:boxes/TextGrid.TextGrid.flags}.\n * @param {boolean} value - Whether to set or unset the attribute.\n */\n setAttributeBetween(x0, y0, x1, y1, attribute, value) {\n if (this.isValidCell(x0, y0) && this.isValidCell(x1, y1)) {\n let\n dx = x1 - x0,\n dy = y1 - y0;\n\n if (dx === 0 || dy === 0 || Math.abs(dx) === Math.abs(dy)) {\n const steps = Math.max(Math.abs(dx), Math.abs(dy));\n if (steps > 0) {\n dx /= steps;\n dy /= steps;\n }\n for (let i = 0; i <= steps; i++)\n this.setAttribute(x0 + dx * i, y0 + dy * i, attribute, value);\n }\n }\n }\n\n /**\n * Sets or unsets a specifi attrobut to a cell.\n * @param {number} px - The 'X' coordinate of the cell\n * @param {number} py - The 'Y' coordinate of the cell\n * @param {number} attribute - The binary flag representing this attribute. See {@link module:boxes/TextGrid.TextGrid.flags}.\n * @param {boolean} state - Whether to set or unset the attribute.\n */\n setAttribute(px, py, attribute, state) {\n if (this.isValidCell(px, py)) {\n if (this.attribute === flags.MARKED && !state)\n this.repaintCell(px, py);\n this.attributes[py][px] &= ~attribute;\n this.attributes[py][px] |= state ? attribute : 0;\n if (attribute !== flags.MARKED || state)\n this.repaintCell(px, py);\n }\n }\n\n /**\n * Sets the specified attribute to all cells.\n * @param {number} attribute - The binary flag representing this attribute. See {@link module:boxes/TextGrid.TextGrid.flags}.\n * @param {boolean} state - Whether to set or unset the attribute.\n */\n setAllCellsAttribute(attribute, state) {\n for (let py = 0; py < this.nRows; py++)\n for (let px = 0; px < this.nCols; px++)\n this.setAttribute(px, py, attribute, state);\n }\n\n /**\n * Gets the specified attribute of a cell\n * @param {number} px - The 'X' coordinate of the cell\n * @param {number} py - The 'Y' coordinate of the cell\n * @param {number} attribute - The binary flag representing this attribute. See {@link module:boxes/TextGrid.TextGrid.flags}.\n * @returns {boolean} - `true` if the cell has this attribute, `false` otherwise.\n */\n getCellAttribute(px, py, attribute) {\n return this.isValidCell(px, py) ? (this.attributes[py][px] & attribute) !== 0 : false;\n }\n\n /**\n * Gets the rectangle enclosing a specific cell\n * @param {number} px - The 'X' coordinate of the cell\n * @param {number} py - The 'Y' coordinate of the cell\n * @returns {module:AWT.Rectangle}\n */\n getCellRect(px, py) {\n return new Rectangle(this.pos.x + px * this.cellWidth, this.pos.y + py * this.cellHeight, this.cellWidth, this.cellHeight);\n }\n\n /**\n * Gets the rectangle enclosing a specific cell, including the border thick.\n * @param {number} px - The 'X' coordinate of the cell\n * @param {number} py - The 'Y' coordinate of the cell\n * @returns {module:AWT.Rectangle}\n */\n getCellBorderBounds(px, py) {\n const isMarked = this.getCellAttribute(px, py, flags.MARKED);\n if (!this.border && !isMarked)\n return this.getCellRect(px, py);\n\n const\n style = this.getBoxBaseResolve(),\n strk = isMarked ? style.markerStroke : style.borderStroke;\n\n return this.getCellRect(px, py).grow(strk.lineWidth, strk.lineWidth);\n }\n\n /**\n * Repaints a cell\n * @param {number} px - The 'X' coordinate of the cell\n * @param {number} py - The 'Y' coordinate of the cell\n */\n repaintCell(px, py) {\n if (this.container)\n this.container.invalidate(this.getCellBorderBounds(px, py)).update();\n }\n\n /**\n * Gets the preferred size of this grid\n * @returns {module:AWT.Dimension}\n */\n getPreferredSize() {\n return this.preferredBounds.dim;\n }\n\n /**\n * Gets the minimum size of this grid\n * @returns {module:AWT.Dimension}\n */\n getMinimumSize() {\n return new Dimension(defaults.MIN_CELL_SIZE * this.nCols, defaults.MIN_CELL_SIZE * this.nRows);\n }\n\n /**\n * Scales the grid to a new size\n * @param {number} scale - The factor used to multiply all coordinates and sizes\n * @returns {module:AWT.Dimension}\n */\n getScaledSize(scale) {\n return new Dimension(\n roundTo(scale * this.preferredBounds.dim.width, this.nCols),\n roundTo(scale * this.preferredBounds.dim.height, this.nRows));\n }\n\n /**\n * Overrides {@link module:boxes/AbstractBox.AbstractBox#setBounds}\n * @override\n * @param {AWT.Rectangle|number} rect - An AWT.Rectangle object, or the `x` coordinate of the\n * upper-left corner of a new rectangle.\n * @param {number} [y] - `y` coordinate of the upper-left corner of the new rectangle.\n * @param {number} [w] - Width of the new rectangle.\n * @param {number} [h] - Height of the new rectangle.\n */\n setBounds(rect, y, w, h) {\n super.setBounds(rect, y, w, h);\n this.cellWidth = this.dim.width / this.nCols;\n this.cellHeight = this.dim.height / this.nRows;\n }\n\n /**\n * Overrides {@link module:boxes/AbstractBox.AbstractBox#updateContent}\n * @override\n * @param {external:CanvasRenderingContext2D} ctx - The canvas rendering context used to draw the\n * grid.\n * @param {module:AWT.Rectangle} [dirtyRegion] - The area that must be repainted. `null` refers to the whole box.\n */\n updateContent(ctx, dirtyRegion) {\n const style = this.getBoxBaseResolve();\n\n // test font size\n ctx.font = style.font.cssFont();\n ctx.textBaseline = 'alphabetic';\n style.prepareText(ctx, 'W',\n this.cellWidth - 2 * defaults.MIN_INTERNAL_MARGIN,\n this.cellHeight - 2 * defaults.MIN_INTERNAL_MARGIN);\n\n const ch = [];\n const ry = (this.cellHeight - style.font.getHeight()) / 2 + style.font.getMetrics().ascent;\n\n for (let py = 0; py < this.nRows; py++) {\n for (let px = 0; px < this.nCols; px++) {\n const bxr = this.getCellBorderBounds(px, py);\n if (bxr.intersects(dirtyRegion)) {\n const attr = this.attributes[py][px];\n if ((attr & flags.TRANSPARENT) === 0) {\n const isInverted = (attr & flags.INVERTED) !== 0;\n const isMarked = (attr & flags.MARKED) !== 0;\n const isCursor = this.useCursor && this.cursor.x === px && this.cursor.y === py;\n const boxBounds = this.getCellRect(px, py);\n ctx.fillStyle = isCursor && this.cursorBlink ?\n style.inactiveColor :\n isInverted ? style.textColor : style.backColor;\n boxBounds.fill(ctx);\n ctx.strokeStyle = 'black';\n if ((attr & flags.HIDDEN) === 0) {\n ch[0] = this.chars[py][px];\n if (ch[0]) {\n const dx = boxBounds.pos.x + (this.cellWidth - ctx.measureText(ch[0]).width) / 2;\n const dy = boxBounds.pos.y + ry;\n\n if (style.shadow) {\n // Render text shadow\n const d = Math.max(1, style.font.size / 10);\n ctx.fillStyle = style.shadowColor;\n ctx.fillText(ch[0], dx + d, dy + d);\n }\n // Render text\n ctx.fillStyle = isInverted ? style.backColor\n : this.isAlternative() ? style.alternativeColor : style.textColor;\n ctx.fillText(ch[0], dx, dy);\n }\n }\n if (this.border || isMarked) {\n ctx.strokeStyle = style.borderColor;\n style[isMarked ? 'markerStroke' : 'borderStroke'].setStroke(ctx);\n if (isMarked)\n ctx.globalCompositeOperation = 'xor';\n\n // Draw border\n boxBounds.stroke(ctx);\n\n // Reset ctx default values\n if (isMarked)\n ctx.globalCompositeOperation = 'source-over';\n }\n ctx.strokeStyle = 'black';\n Stroke.prototype.setStroke(ctx);\n }\n }\n }\n }\n return true;\n }\n\n /**\n * Makes the cursor blink, alternating between two states. This method should be called only by\n * {@link module:boxes/TextGrid.TextGrid#cursorTimer}\n * @param {boolean} status\n */\n blink(status) {\n // TODO: Move blink and timer to ActivityPanel\n if (this.useCursor) {\n this.cursorBlink = status === 1 ? true : status === -1 ? false : !this.cursorBlink;\n this.repaintCell(this.cursor.x, this.cursor.y);\n }\n }\n\n /**\n * Stops the cursor timer if not `null` and active\n */\n end() {\n if (this.cursorTimer) {\n this.cursorTimer.stop();\n this.cursorTimer = null;\n }\n }\n}\n\nObject.assign(TextGrid.prototype, {\n /**\n * Number of rows\n * @name module:boxes/TextGrid.TextGrid#nRows\n * @type {number} */\n nRows: 1,\n /**\n * Number of columns\n * @name module:boxes/TextGrid.TextGrid#nCols\n * @type {number} */\n nCols: 1,\n /**\n * Two-dimension array of characters\n * @name module:boxes/TextGrid.TextGrid#chars\n * @type {string[][]} */\n chars: null,\n /**\n * Two-dimension array with the expected characters, used to check user's answers.\n * @name module:boxes/TextGrid.TextGrid#answers\n * @type {string[][]} */\n answers: null,\n /**\n * Two-dimension array of bytes used as containers of boolean attributes\n * @name module:boxes/TextGrid.TextGrid#attributes\n * @see TextGrid.flags\n * @type {number[][]} */\n attributes: null,\n /**\n * The cell width, in pixels\n * @name module:boxes/TextGrid.TextGrid#cellWidth\n * @type {number} */\n cellWidth: 20,\n /**\n * The cell height, in pixels\n * @name module:boxes/TextGrid.TextGrid#cellHeight\n * @type {number} */\n cellHeight: 20,\n /**\n * The preferred bounds of this grid\n * @name module:boxes/TextGrid.TextGrid#preferredBounds\n * @type {module:AWT.Rectangle} */\n preferredBounds: null,\n /**\n * The character to be used as wildcard\n * @name module:boxes/TextGrid.TextGrid#wild\n * @type {string} */\n wild: TextGridContent.prototype.wild,\n /**\n * Characters that can be used when randomizing the content of this grid\n * @name module:boxes/TextGrid.TextGrid#randomChars\n * @see TextGridContent#randomChars\n * @type {string} */\n randomChars: TextGridContent.prototype.randomChars,\n /**\n * Whether the blinking cursor is enabled or disabled\n * @name module:boxes/TextGrid.TextGrid#cursorEnabled\n * @type {boolean} */\n cursorEnabled: false,\n /**\n * Whether this grid uses a blinking cursor or not\n * @name module:boxes/TextGrid.TextGrid#useCursor\n * @type {boolean} */\n useCursor: false,\n /**\n * The current position of the cursor\n * @name module:boxes/TextGrid.TextGrid#cursor\n * @type {module:AWT.Point} */\n cursor: null,\n /**\n * `true` when the cursor is \"blinking\" (cell drawn with {@link module:boxes/BoxBase.BoxBase BoxBase} `inverse` attributes)\n * @name module:boxes/TextGrid.TextGrid#cursorBlink\n * @type {boolean} */\n cursorBlink: false,\n /**\n * Controls the blinking of the cursor\n * @name module:boxes/TextGrid.TextGrid#cursorTimer\n * @type {module:AWT.Timer} */\n cursorTimer: null,\n /**\n * Whether the wildcard character is transparent or opaque\n * @name module:boxes/TextGrid.TextGrid#wildTransparent\n * @type {boolean} */\n wildTransparent: false,\n});\n\n/**\n * TextGrid default values\n * @name module:boxes/TextGrid.TextGrid.defaults\n * @constant\n * @type {object} */\nTextGrid.defaults = defaults;\n\n/**\n * Binary flags used to mark status\n * @name module:boxes/TextGrid.TextGrid.flags\n * @constant\n * @type {object} */\nTextGrid.flags = flags;\n\nexport default TextGrid;\n","/**\n * File : activities/textGrid/CrossWord.js\n * Created : 17/06/2015\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\n/* global window */\n\nimport $ from 'jquery';\nimport { Activity, ActivityPanel } from '../../Activity.js';\nimport BoxBase from '../../boxes/BoxBase.js';\nimport BoxBag from '../../boxes/BoxBag.js';\nimport TextGrid from '../../boxes/TextGrid.js';\nimport AbstractBox from '../../boxes/AbstractBox.js';\nimport ActiveBox from '../../boxes/ActiveBox.js';\nimport { Rectangle, Point } from '../../AWT.js';\nimport { settings, svgToURI } from '../../Utils.js';\n\n// Use Webpack to import SVG files\nimport hIcon from './icons/hIcon.svg';\nimport vIcon from './icons/vIcon.svg';\n\n/**\n * This class of {@link module:Activity.Activity Activity} shows a {@link module:boxes/TextGrid.TextGrid TextGrid} initially empty, with some cells\n * marked in negative color that act as word stoppers. A blinking \"cursor\" indicates the cell that\n * will receive the next character entered by the user on the keyboard.\n *\n * The letter in each cell of the grid is always shared by two words: one in horizontal direction\n * and the other one in vertical direction. Two {@link module:boxes/ActiveBox.ActiveBox ActiveBox} objects are placed next to the\n * {@link module:boxes/TextGrid.TextGrid TextGrid}, hosting the definitions of the horizontal and vertical words crossing at the\n * cell currently marked by the cursor.\n *\n * Two special buttons placed near this boxes allow to write on the grid horizontally or vertically.\n * The aim of the activity is to fill all the text grid with the correct words.\n * @extends module:Activity.Activity\n */\nexport class CrossWord extends Activity {\n /**\n * CrossWord constructor\n * @param {module:project/JClicProject.JClicProject} project - The JClic project to which this activity belongs\n */\n constructor(project) {\n super(project);\n }\n\n /**\n * Retrieves the minimum number of actions needed to solve this activity\n * @override\n * @returns {number}\n */\n getMinNumActions() {\n return this.tgc.getNumChars() - this.tgc.countWildChars();\n }\n\n /**\n * Crossword activities always make use of the keyboard\n * @override\n * @returns {boolean}\n */\n needsKeyboard() {\n return true;\n }\n}\n\nObject.assign(CrossWord.prototype, {\n /**\n * Whether all letters of the {@link module:boxes/TextGrid.TextGrid TextGrid} should be displayed in upper case\n * @name module:activities/textGrid/CrossWord.CrossWord#upperCase\n * @type {boolean} */\n upperCase: true,\n /**\n * Whether the case is significant to evaluate answers\n * @name module:activities/textGrid/CrossWord.CrossWord#checkCase\n * @type {boolean} */\n checkCase: true,\n /**\n * When `true`, the wildcard character of the {@link module:boxes/TextGrid.TextGrid TextGrid} will be transparent.\n * @name module:activities/textGrid/CrossWord.CrossWord#wildTransparent\n * @type {boolean} */\n wildTransparent: false,\n});\n\n/**\n * The {@link module:Activity.ActivityPanel ActivityPanel} where {@link module:activities/textGrid/CrossWord.CrossWord CrossWord} activities are played.\n * @extends module:Activity.ActivityPanel\n */\nexport class CrossWordPanel extends ActivityPanel {\n /**\n * CrossWordPanel constructor\n * @param {module:Activity.Activity} act - The {@link module:Activity.Activity Activity} to which this Panel belongs\n * @param {module:JClicPlayer.JClicPlayer} ps - Any object implementing the methods defined in the\n * [PlayStation](http://projectestac.github.io/jclic/apidoc/edu/xtec/jclic/PlayStation.html) Java interface.\n * @param {external:jQuery} [$div] - The jQuery DOM element where this Panel will deploy\n */\n constructor(act, ps, $div) {\n super(act, ps, $div);\n }\n\n /**\n * Performs miscellaneous cleaning operations\n * @override\n */\n clear() {\n if (this.grid) {\n this.grid.end();\n this.grid = null;\n }\n if (this.style) {\n this.style.end();\n this.style = null;\n }\n }\n\n /**\n * Creates a {@link module:boxes/BoxBag.BoxBag BoxBag} with a label (\"Horizontal\" or \"Vertical\") and an {@link module:boxes/ActiveBox.ActiveBox ActiveBox}\n * that will be used to display clues.\n * @param {string} type - `acrossClues` for horizontal clues, 'downClues' for vertical.\n * @returns {module:boxes/BoxBag.BoxBag}\n */\n createBoxBag(type) {\n const\n bxb = new BoxBag(null, this, null),\n sb = new AbstractBox(bxb, this, this.icoBB);\n\n sb.setBounds(0, 0, this.LABEL_WIDTH, this.act.abc[type].h);\n const $btn = $('<button/>', { class: 'StockBtn' }).css({\n 'width': this.LABEL_WIDTH,\n 'height': this.act.abc[type].h,\n 'background-image': `url(${type === 'acrossClues' ? this.hIcon : this.vIcon})`,\n 'background-repeat': 'no-repeat',\n 'background-position': 'center',\n 'border-radius': '6px',\n 'z-index': 10\n }).on('click', () => {\n this.advance = type === 'acrossClues' ?\n this.advance === 'ADVANCE_RIGHT' ?\n 'NO_ADVANCE' : 'ADVANCE_RIGHT' :\n this.advance === 'ADVANCE_DOWN' ?\n 'NO_ADVANCE' : 'ADVANCE_DOWN';\n this.setBtnStatus();\n }).on('keypress', event => {\n if (String.fromCharCode(event.charCode || event.keyCode) === ' ')\n event.stopPropagation();\n }).appendTo(this.$div);\n\n sb.setHostedComponent($btn);\n bxb.addBox(sb);\n\n const ab = new ActiveBox(bxb, null, null, type, new Rectangle(this.LABEL_WIDTH + this.act.margin, 0, this.act.abc[type].w, this.act.abc[type].h));\n bxb.addBox(ab);\n bxb.setBoxBase(this.act.abc[type].style);\n\n if (type === 'acrossClues') { // Horizontal\n this.hClue = ab;\n this.hClueBtn = sb;\n } else {\n this.vClue = ab;\n this.vClueBtn = sb;\n }\n return bxb;\n }\n\n /**\n * Prepares the visual components of the activity\n * @override\n */\n buildVisualComponents() {\n if (this.firstRun)\n super.buildVisualComponents();\n this.clear();\n\n const\n tgc = this.act.tgc,\n abcH = this.act.abc['acrossClues'],\n abcV = this.act.abc['downClues'];\n\n if (abcH.image)\n abcH.setImgContent(this.act.project.mediaBag, null, false);\n if (abcV.image)\n abcV.setImgContent(this.act.project.mediaBag, null, false);\n\n if (this.act.acp !== null) {\n this.act.acp.generateContent(0, 0, this.act.abc, false);\n }\n\n if (tgc) {\n this.grid = TextGrid.createEmptyGrid(null, this, this.act.margin, this.act.margin, tgc, this.act.wildTransparent);\n this.style = new BoxBag(null, this, null);\n const\n bxbh = this.createBoxBag('acrossClues'),\n bxbv = this.createBoxBag('downClues');\n if (this.act.boxGridPos === 'AUB' || this.act.boxGridPos === 'BUA')\n bxbv.moveTo(new Point(bxbh.dim.width + this.act.margin, 0));\n else\n bxbv.moveTo(new Point(0, bxbh.dim.height + this.act.margin));\n this.style.addBox(bxbh);\n this.style.addBox(bxbv);\n this.grid.setVisible(true);\n this.style.setVisible(true);\n }\n }\n\n /**\n * Basic initialization procedure\n * @override\n */\n initActivity() {\n super.initActivity();\n if (!this.firstRun)\n this.buildVisualComponents();\n else\n this.firstRun = false;\n\n if (this.grid) {\n this.grid.setChars(this.act.tgc.text);\n this.numLetters = this.act.getMinNumActions();\n this.grid.setCellAttributes(true, true);\n this.grid.setCursorEnabled(true);\n this.setCursorAt(0, 0);\n this.advance = 'ADVANCE_RIGHT';\n this.setBtnStatus();\n this.setAndPlayMsg('initial', 'start');\n this.invalidate().update();\n this.$div.attr(\"tabindex\", 0);\n this.$div.trigger('focus');\n this.playing = true;\n }\n }\n\n /**\n * Calculates the current score\n * @returns {number}\n */\n getCurrentScore() {\n return this.grid ? this.grid.countCoincidences(this.act.checkCase) : 0;\n }\n\n /**\n * Updates the graphic content of this panel.\n * This method will be called from {@link module:AWT.Container#update} when needed.\n * @override\n * @param {module:AWT.Rectangle} dirtyRegion - Specifies the area to be updated. When `null`,\n * it's the whole panel.\n */\n updateContent(dirtyRegion) {\n super.updateContent(dirtyRegion);\n if (this.grid && this.$canvas) {\n const\n canvas = this.$canvas.get(-1),\n ctx = canvas.getContext('2d');\n if (!dirtyRegion)\n dirtyRegion = new Rectangle(0, 0, canvas.width, canvas.height);\n ctx.clearRect(dirtyRegion.pos.x, dirtyRegion.pos.y, dirtyRegion.dim.width, dirtyRegion.dim.height);\n this.grid.update(ctx, dirtyRegion);\n this.style.update(ctx, dirtyRegion);\n }\n return this;\n }\n\n /**\n * Sets the real dimension of this panel.\n * @override\n * @param {module:AWT.Dimension} preferredMaxSize - The maximum surface available for the activity panel\n * @returns {module:AWT.Dimension}\n */\n setDimension(preferredMaxSize) {\n return !this.grid || !this.style || this.getBounds().equals(preferredMaxSize) ?\n preferredMaxSize :\n BoxBag.layoutDouble(preferredMaxSize, this.grid, this.style, this.act.boxGridPos, this.act.margin);\n }\n\n /**\n * Sets the size and position of this activity panel\n * @override\n * @param {module:AWT.Rectangle} rect\n */\n setBounds(rect) {\n if (this.$canvas) {\n this.$canvas.remove();\n this.$canvas = null;\n }\n super.setBounds(rect);\n\n if (this.grid) {\n // Create the main canvas\n this.$canvas = $(`<canvas width=\"${rect.dim.width}\" height=\"${rect.dim.height}\"/>`).css({\n position: 'absolute',\n top: 0,\n left: 0\n });\n this.$div.append(this.$canvas);\n // Repaint all\n this.invalidate().update();\n }\n }\n\n /**\n * Main handler used to process mouse, touch, keyboard and edit events\n * @override\n * @param {external:Event} event - The HTML event to be processed\n * @returns {boolean} - When this event handler returns `false`, jQuery will stop its\n * propagation through the DOM tree. See: {@link http://api.jquery.com/on}\n */\n processEvent(event) {\n if (this.playing) {\n switch (event.type) {\n case 'click':\n //\n // The [AWT.Point](AWT.html#Point) where the mouse or touch event has been originated\n // Touch events can have more than one touch, so `pageX` must be obtained from `touches[0]`\n const\n x = event.originalEvent && event.originalEvent.touches ? event.originalEvent.touches[0].pageX : event.pageX,\n y = event.originalEvent && event.originalEvent.touches ? event.originalEvent.touches[0].pageY : event.pageY,\n p = new Point(x - this.$div.offset().left, y - this.$div.offset().top),\n // Array to be filled with actions to be executed at the end of event processing\n delayedActions = [];\n\n this.ps.stopMedia(1);\n if (this.grid.contains(p)) {\n const pt = this.grid.getLogicalCoords(p);\n if (pt !== null) {\n this.setCursorAt(pt.x, pt.y);\n if (settings.TOUCH_DEVICE) {\n // We are in a touch device, so prompt user to write text:\n const d = this.advance === 'ADVANCE_DOWN';\n const txt = window.prompt(`${d ? 'Vertical' : 'Horizontal'} word:`, '');\n this.writeChars(txt);\n }\n }\n } else if (this.hClue.contains(p))\n this.hClue.playMedia(this.ps, delayedActions);\n else if (this.vClue.contains(p))\n this.vClue.playMedia(this.ps, delayedActions);\n else\n break;\n\n this.update();\n delayedActions.forEach(action => action());\n break;\n\n case 'keypress':\n const code = event.charCode || event.keyCode;\n if (code && this.grid.getCursor()) {\n event.preventDefault();\n this.writeChars(String.fromCharCode(code));\n }\n break;\n\n case 'keydown':\n let dx = 0, dy = 0;\n switch (event.keyCode) {\n case settings.VK.RIGHT:\n dx = 1;\n break;\n case settings.VK.LEFT:\n dx = -1;\n break;\n case settings.VK.DOWN:\n dy = 1;\n break;\n case settings.VK.UP:\n dy = -1;\n break;\n }\n if (dx || dy) {\n event.preventDefault();\n this.moveCursor(dx, dy);\n this.update();\n }\n break;\n }\n }\n }\n\n /**\n * Moves the cursor the specified `dx` and `dy` amount (in logical coordinates)\n * @param {number} dx - Amount of cells to horizontally move on\n * @param {number} dy - Amount of cells to vertically move on\n */\n moveCursor(dx, dy) {\n if (this.grid) {\n this.grid.moveCursor(dx, dy, true);\n this.cursorPosChanged();\n }\n }\n\n /**\n * Places the cursor at the specified location (in logical coordinates)\n * @param {number} x\n * @param {number} y\n */\n setCursorAt(x, y) {\n this.grid.setCursorAt(x, y, true);\n this.cursorPosChanged();\n }\n\n /**\n * Method called when the cursor moves to a different location\n */\n cursorPosChanged() {\n const pt = this.grid.getCursor();\n if (pt !== null && this.style !== null) {\n const items = this.grid.getItemFor(pt.x, pt.y);\n if (items !== null) {\n this.hClue.setContent(this.act.abc['acrossClues'].getActiveBoxContentWith(pt.y, items.x));\n this.vClue.setContent(this.act.abc['downClues'].getActiveBoxContentWith(pt.x, items.y));\n }\n }\n }\n\n /**\n * Writes a string on the grid starting at the current cursor position and\n * following the direction marked by the `advance` field\n * @param {string} txt - Text to write\n */\n writeChars(txt) {\n if (txt && txt.length > 0) {\n for (let i = 0; i < txt.length; i++) {\n const cur = this.grid.getCursor();\n let ch = txt.charAt(i);\n if (this.act.upperCase)\n ch = ch.toLocaleUpperCase();\n this.grid.setCharAt(cur.x, cur.y, ch);\n const\n ok = this.grid.isCellOk(cur.x, cur.y, this.act.checkCase),\n r = this.getCurrentScore();\n this.ps.reportNewAction(this.act, 'WRITE', ch, `X:${cur.x} Y:${cur.y}`, ok, r);\n // End activity or play event sound\n if (r === this.numLetters) {\n this.grid.setCursorEnabled(false);\n this.grid.stopCursorBlink();\n this.finishActivity(true);\n } else {\n this.playEvent('click');\n if (this.advance === 'ADVANCE_DOWN')\n this.moveCursor(0, 1);\n else if (this.advance === 'ADVANCE_RIGHT')\n this.moveCursor(1, 0);\n }\n }\n }\n this.update();\n }\n\n /**\n * Sets the status of horizontal and vertical buttons based on the value of `advance`\n */\n setBtnStatus() {\n if (this.hClueBtn)\n this.hClueBtn.setInactive(this.advance !== 'ADVANCE_RIGHT');\n if (this.vClueBtn)\n this.vClueBtn.setInactive(this.advance !== 'ADVANCE_DOWN');\n }\n}\n\nObject.assign(CrossWordPanel.prototype, {\n /**\n * The default width of the 'Horizontal' and 'Vertical' buttons (currently 40 pixels)\n * @name module:activities/textGrid/CrossWord.CrossWordPanel#LABEL_WIDTH\n * @type {number} */\n LABEL_WIDTH: 40,\n /**\n * The text grid of this ActivityPanel\n * @name module:activities/textGrid/CrossWord.CrossWordPanel#grid\n * @type {module:boxes/TextGrid.TextGrid} */\n grid: null,\n /**\n * A BoxBag used to place the across and down clues, and the `toggle direction` button.\n * @name module:activities/textGrid/CrossWord.CrossWordPanel#style\n * @type {module:boxes/BoxBag.BoxBag} */\n style: null,\n /**\n * The total number of letters of this cross word\n * @name module:activities/textGrid/CrossWord.CrossWordPanel#numLetters\n * @type {number} */\n numLetters: 0,\n /**\n * Flag indicating the type of automatic advance of the cursor.\n * Possible values are: `NO_ADVANCE` (default), 'ADVANCE_RIGHT' and 'ADVANCE_DOWN'.\n * TODO: Implement 'ADVANCE_LEFT' for LTR languages\n * @name module:activities/textGrid/CrossWord.CrossWordPanel#advance\n * @type {string} */\n advance: 'NO_ADVANCE',\n /**\n * The ActiveBox object used to display the 'across' clues\n * @name module:activities/textGrid/CrossWord.CrossWordPanel#hClue\n * @type {module:boxes/ActiveBox.ActiveBox} */\n hClue: null,\n /**\n * The ActiveBox object used to display the 'down' clues\n * @name module:activities/textGrid/CrossWord.CrossWordPanel#vClue\n * @type {module:boxes/ActiveBox.ActiveBox} */\n vClue: null,\n /**\n * Button used to set the advance mode to 'ADVANCE_RIGHT'\n * @name module:activities/textGrid/CrossWord.CrossWordPanel#hClueBtn\n * @type {module:boxes/ActiveBox.ActiveBox} */\n hClueBtn: null,\n /**\n * Button used to set the advance mode to 'ADVANCE_BOTTOM'\n * @name module:activities/textGrid/CrossWord.CrossWordPanel#vClueBtn\n * @type {module:boxes/ActiveBox.ActiveBox} */\n vClueBtn: null,\n /**\n * Mouse and touch events intercepted by this panel\n * @override\n * @name module:activities/textGrid/CrossWord.CrossWordPanel#events\n * @type {string[]} */\n events: ['click', 'keydown', 'keypress'],\n /**\n * Graphic icon for the horizontal direction button, represented as a string containing\n * an SVG file codified in base64.\n * @name module:activities/textGrid/CrossWord.CrossWordPanel#hIcon\n * @type {string} */\n hIcon: svgToURI(hIcon),\n /**\n * Graphic icon for the vertical direction button, represented as a string containing\n * an SVG file codified in base64.\n * @name module:activities/textGrid/CrossWord.CrossWordPanel#vIcon\n * @type {string} */\n vIcon: svgToURI(vIcon),\n /**\n * Sizes of the icons (currently 36 x 36 pixel)\n * @name module:activities/textGrid/CrossWord.CrossWordPanel#icoSize\n * @type {object} */\n icoSize: { w: 36, h: 36 },\n /**\n * BoxBase with the style to be used by the direction buttons.\n * @name module:activities/textGrid/CrossWord.CrossWordPanel#icoBB\n * @type {module:boxes/BoxBase.BoxBase} */\n icoBB: new BoxBase().set('backColor', '#4285F4').set('inactiveColor', '#70A2F6').set('dontFill', true)\n});\n\n/**\n * Panel class associated to this type of activity: {@link module:activities/textGrid/CrossWord.CrossWordPanel CrossWordPanel}\n * @type {class} */\nCrossWord.Panel = CrossWordPanel;\n\n// Register activity class\nexport default Activity.registerClass('@textGrid.CrossWord', CrossWord);\n","/**\n * File : activities/textGrid/WordSearch.js\n * Created : 15/06/2015\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\nimport $ from 'jquery';\nimport { Activity, ActivityPanel } from '../../Activity.js';\nimport ActiveBoxGrid from '../../boxes/ActiveBoxGrid.js';\nimport BoxBag from '../../boxes/BoxBag.js';\nimport BoxConnector from '../../boxes/BoxConnector.js';\nimport { Rectangle, Point } from '../../AWT.js';\nimport TextGrid from '../../boxes/TextGrid.js';\n\n/**\n * This class of {@link module:Activity.Activity Activity} shows a {@link module:boxes/TextGrid.TextGrid TextGrid} with some words placed in horizontal,\n * vertical or diagonal direction, written right or upside down. The remaining grid cells will be\n * filled with randomly selected characters.\n *\n * The aim of the activity is to find all the words hidden on the text grid.\n * The content of an optional {@link module:boxes/ActiveBagContent.ActiveBagContent ActiveBagContent} can be revealed on an auxiliary panel as\n * words are found.\n * @extends module:Activity.Activity\n */\nexport class WordSearch extends Activity {\n /**\n * WordSearch constructor\n * @param {module:project/JClicProject.JClicProject} project - The JClic project to which this activity belongs\n */\n constructor(project) {\n super(project);\n }\n\n /**\n * Retrieves the minimum number of actions needed to solve this activity\n * @override\n * @returns {number}\n */\n getMinNumActions() {\n return this.clues.length;\n }\n\n /**\n * This type of activity permits the user to display the solution\n * @override\n * @returns {boolean}\n */\n helpSolutionAllowed() {\n return true;\n }\n\n /**\n * This kind of activity uses random numbers to generate the filling characters\n * @override\n * @returns {boolean}\n */\n hasRandom() {\n return true;\n }\n}\n\nObject.assign(WordSearch.prototype, {\n /**\n * String array containing all the valid clues.\n * @name module:activities/textGrid/WordSearch.WordSearch#clues\n * @type {string[]} */\n clues: null,\n /**\n * Array of integers containing __for each clue__ the index\n * of an associated {@link module:boxes/ActiveBoxContent.ActiveBoxContent ActiveBoxContent} located on the secondary {@link module:boxes/ActiveBoxbag.ActiveBoxBag ActiveBoxBag}.\n * This associated element is optional.\n * @name module:activities/textGrid/WordSearch.WordSearch#clueItems\n * @type {number[]} */\n clueItems: null,\n /**\n * Objects that indicate if box grids A and B must be shuffled.\n * (defaults to _false_ in WordSearch activities)\n * @name module:activities/textGrid/WordSearch.WordSearch#shuffleA\n * @type {boolean} */\n shuffleA: false,\n /**\n * Objects that indicate if box grids A and B must be shuffled.\n * (defaults to _false_ in WordSearch activities)\n * @name module:activities/textGrid/WordSearch.WordSearch#shuffleB\n * @type {boolean} */\n shuffleB: false,\n});\n\n/**\n * The {@link module:Activity.ActivityPanel ActivityPanel} where {@link module:activities/textGrid/WordSearch.WordSearch WordSearch} activities are played.\n * @extends module:Activity.ActivityPanel\n */\nexport class WordSearchPanel extends ActivityPanel {\n /**\n * WordSearchPanel constructor\n * @param {module:Activity.Activity} act - The {@link module:Activity.Activity Activity} to which this Panel belongs\n * @param {module:JClicPlayer.JClicPlayer} ps - Any object implementing the methods defined in the\n * [PlayStation](http://projectestac.github.io/jclic/apidoc/edu/xtec/jclic/PlayStation.html) Java interface.\n * @param {external:jQuery} [$div] - The jQuery DOM element where this Panel will deploy\n */\n constructor(act, ps, $div) {\n super(act, ps, $div);\n this.resolvedClues = [];\n }\n\n /**\n * Performs miscellaneous cleaning operations\n * @override\n */\n clear() {\n if (this.grid) {\n this.grid.end();\n this.grid = null;\n }\n if (this.bgAlt) {\n this.bgAlt.end();\n this.bgAlt = null;\n }\n }\n\n /**\n * Prepares the visual components of the activity\n * @override\n */\n buildVisualComponents() {\n if (this.firstRun)\n super.buildVisualComponents();\n this.clear();\n\n const\n tgc = this.act.tgc,\n abcAlt = this.act.abc['secondary'];\n if (abcAlt) {\n if (abcAlt.image) {\n abcAlt.setImgContent(this.act.project.mediaBag, null, false);\n if (abcAlt.animatedGifFile && !abcAlt.shaper.rectangularShapes && !this.act.shuffleB)\n this.$animatedBg = $('<span/>').css({\n 'background-image': `url(${abcAlt.animatedGifFile})`,\n 'background-position': 'center',\n 'background-repeat': 'no-repeat',\n position: 'absolute'\n }).appendTo(this.$div);\n }\n\n if (this.act.acp !== null)\n this.act.acp.generateContent(0, 0, [abcAlt], false);\n }\n\n if (tgc) {\n this.grid = TextGrid.createEmptyGrid(null, this, this.act.margin, this.act.margin, tgc, false);\n if (abcAlt) {\n this.bgAlt = ActiveBoxGrid.createEmptyGrid(null, this, this.act.margin, this.act.margin, abcAlt);\n if (this.$animatedBg && this.bgAlt.backgroundBox)\n this.bgAlt.backgroundBox['tmpTrans'] = true;\n }\n this.grid.setVisible(true);\n }\n }\n\n /**\n * Basic initialization procedure\n * @override\n */\n initActivity() {\n super.initActivity();\n if (!this.firstRun)\n this.buildVisualComponents();\n else\n this.firstRun = false;\n\n if (this.grid) {\n this.grid.setChars(this.act.tgc.text);\n this.grid.randomize();\n this.grid.setAllCellsAttribute(TextGrid.flags.INVERTED, false);\n\n this.resolvedClues = Array(this.act.clueItems.length).fill(false);\n\n if (this.bgAlt) {\n this.bgAlt.setContent(this.act.abc['secondary']);\n if (this.$animatedBg)\n this.bgAlt.clearAllBoxes();\n if (this.act.shuffleB)\n this.shuffle([this.bgAlt], true, true);\n this.bgAlt.setVisible(this.$animatedBg !== null || this.act.invAss);\n }\n\n this.setAndPlayMsg('initial', 'start');\n this.invalidate().update();\n this.playing = true;\n }\n }\n\n /**\n * Updates the graphic content of this panel.\n * This method will be called from {@link module:AWT.Container#update} when needed.\n * @override\n * @param {module:AWT.Rectangle} dirtyRegion - Specifies the area to be updated. When `null`,\n * it's the whole panel.\n */\n updateContent(dirtyRegion) {\n super.updateContent(dirtyRegion);\n if (this.grid && this.$canvas) {\n const\n canvas = this.$canvas.get(-1),\n ctx = canvas.getContext('2d');\n if (!dirtyRegion)\n dirtyRegion = new Rectangle(0, 0, canvas.width, canvas.height);\n ctx.clearRect(dirtyRegion.pos.x, dirtyRegion.pos.y, dirtyRegion.dim.width, dirtyRegion.dim.height);\n this.grid.update(ctx, dirtyRegion);\n if (this.bgAlt)\n this.bgAlt.update(ctx, dirtyRegion);\n }\n return this;\n }\n\n /**\n * Sets the real dimension of this panel.\n * @override\n * @param {module:AWT.Dimension} preferredMaxSize - The maximum surface available for the activity panel\n * @returns {module:AWT.Dimension}\n */\n setDimension(preferredMaxSize) {\n if (!this.grid || this.getBounds().equals(preferredMaxSize))\n return preferredMaxSize;\n if (this.bgAlt)\n return BoxBag.layoutDouble(preferredMaxSize, this.grid, this.bgAlt, this.act.boxGridPos, this.act.margin);\n else\n return BoxBag.layoutSingle(preferredMaxSize, this.grid, this.act.margin);\n }\n\n /**\n * Sets the size and position of this activity panel\n * @override\n * @param {module:AWT.Rectangle} rect\n */\n setBounds(rect) {\n if (this.$canvas)\n this.$canvas.remove();\n super.setBounds(rect);\n if (this.grid) {\n // Create the main canvas\n this.$canvas = $(`<canvas width=\"${rect.dim.width}\" height=\"${rect.dim.height}\"/>`).css({\n position: 'absolute',\n top: 0,\n left: 0\n });\n // Resize animated gif background\n if (this.$animatedBg && this.bgAlt) {\n const bgRect = this.bgAlt.getBounds();\n this.$animatedBg.css({\n left: bgRect.pos.x,\n top: bgRect.pos.y,\n width: `${bgRect.dim.width}px`,\n height: `${bgRect.dim.height}px`,\n 'background-size': `${bgRect.dim.width}px ${bgRect.dim.height}px`\n });\n }\n this.$div.append(this.$canvas);\n\n // Create a [BoxConnector](BoxConnector.html) and attach it to the canvas context\n this.bc = new BoxConnector(this, this.$canvas);\n\n // Repaint all\n this.invalidate().update();\n }\n }\n\n /**\n * Calculates the current score\n * @returns {number}\n */\n getCurrentScore() {\n return this.resolvedClues.reduce((n, resolved) => resolved ? ++n : n, 0);\n }\n\n /**\n * Main handler used to process mouse, touch, keyboard and edit events\n * @override\n * @param {external:Event} event - The HTML event to be processed\n * @returns {boolean} - When this event handler returns `false`, jQuery will stop its\n * propagation through the DOM tree. See: {@link http://api.jquery.com/on}\n */\n processEvent(event) {\n if (this.bc && this.playing) {\n //\n // The [AWT.Point](AWT.html#Point) where the mouse or touch event has been originated\n let p = null;\n //\n // _touchend_ event don't provide pageX nor pageY information\n if (event.type === 'touchend')\n p = this.bc.active ? this.bc.dest.clone() : new Point();\n else {\n // Touch events can have more than one touch, so `pageX` must be obtained from `touches[0]`\n const\n x = event.originalEvent.touches ? event.originalEvent.touches[0].pageX : event.pageX,\n y = event.originalEvent.touches ? event.originalEvent.touches[0].pageY : event.pageY;\n p = new Point(x - this.$div.offset().left, y - this.$div.offset().top);\n }\n\n // Flag for tracking `mouseup` events\n let up = false;\n // Flag for assuring that only one media plays per event (avoid event sounds overlapping\n // cell's media sounds)\n let m = false;\n // Array to be filled with actions to be executed at the end of event processing\n const delayedActions = [];\n\n switch (event.type) {\n case 'touchcancel':\n // Canvel movement\n if (this.bc.active)\n this.bc.end();\n break;\n\n case 'mouseup':\n // Don't consider drag moves below 3 pixels. Can be a \"trembling click\"\n if (this.bc.active && p.distanceTo(this.bc.origin) <= 3)\n break;\n\n up = true;\n /* falls through */\n case 'touchend':\n case 'touchstart':\n case 'mousedown':\n if (!this.bc.active) {\n // A new word selection starts\n //\n // Selection of words can never start with a `mouseup` event\n if (up)\n break;\n\n this.ps.stopMedia(1);\n if (this.grid.contains(p)) {\n this.playEvent('click');\n this.bc.begin(p);\n }\n } else {\n this.ps.stopMedia(1);\n // Word selection completed\n //\n // Find the active boxes behind `bc.origin` and `p`\n const\n pt1 = this.grid.getLogicalCoords(this.bc.origin),\n pt2 = this.grid.getLogicalCoords(this.bc.dest);\n this.bc.end();\n const s = this.grid.getStringBetween(pt1.x, pt1.y, pt2.x, pt2.y);\n if (s !== null && s.length > 0) {\n let ok = false, c = 0;\n for (; c < this.act.clues.length; c++) {\n if (s === this.act.clues[c]) {\n ok = true;\n break;\n }\n }\n const repeated = this.resolvedClues[c];\n if (ok && !repeated) {\n this.resolvedClues[c] = true;\n this.grid.setAttributeBetween(pt1.x, pt1.y, pt2.x, pt2.y, TextGrid.flags.INVERTED, true);\n if (this.bgAlt !== null) {\n const k = this.act.clueItems[c];\n if (k >= 0 && k < this.bgAlt.getNumCells()) {\n const bx = this.bgAlt.getActiveBox(this.act.clueItems[c]);\n if (bx) {\n bx.setVisible(this.$animatedBg === null && !this.act.invAss);\n m = bx.playMedia(this.ps, delayedActions);\n }\n }\n }\n }\n if (!repeated) {\n const r = this.getCurrentScore();\n this.ps.reportNewAction(this.act, 'ACTION_SELECT', s, null, ok, r);\n if (r === this.act.clues.length)\n this.finishActivity(true);\n else if (!m)\n this.playEvent(ok ? 'actionOK' : 'actionError');\n this.invalidate();\n } else if (!ok && !m)\n this.playEvent('actionError');\n } else\n this.playEvent('actionError');\n\n this.update();\n }\n break;\n\n case 'mousemove':\n case 'touchmove':\n this.bc.moveTo(p);\n break;\n }\n delayedActions.forEach(action => action());\n event.preventDefault();\n }\n }\n}\n\nObject.assign(WordSearchPanel.prototype, {\n /**\n * The {@link module:boxes/TextGrid.TextGrid TextGrid} object of this ActivityPanel\n * @name module:activities/textGrid/WordSearch.WordSearchPanel#grid\n * @type {module:boxes/TextGrid.TextGrid} */\n grid: null,\n /**\n * An optional {@link module:boxes/ActiveBoxbag.ActiveBoxBag ActiveBoxBag} used to display information associated with the hidden words.\n * @name module:activities/textGrid/WordSearch.WordSearchPanel#bgAlt\n * @type {module:boxes/ActiveBoxBag.ActiveBoxBag} */\n bgAlt: null,\n /**\n * An array of boolean values indicating which clues have been found\n * @name module:activities/textGrid/WordSearch.WordSearchPanel#resolvedClues\n * @type {boolean[]} */\n resolvedClues: null,\n /**\n * The box connector object\n * @name module:activities/textGrid/WordSearch.WordSearchPanel#bc\n * @type {module:boxes/BoxConnector.BoxConnector} */\n bc: null,\n /**\n * Mouse and touch events intercepted by this panel\n * @override\n * @name module:activities/textGrid/WordSearch.WordSearchPanel#events\n * @type {string[]} */\n events: ['mousedown', 'mouseup', 'mousemove', 'touchstart', 'touchend', 'touchmove', 'touchcancel'],\n});\n\n/**\n * Panel class associated to this type of activity: {@link module:activities/textGrid/WordSearch.WordSearchPanel WordSearchPanel}\n * @type {class} */\nWordSearch.Panel = WordSearchPanel;\n\n// Register activity class\nexport default Activity.registerClass('@textGrid.WordSearch', WordSearch);\n","/**\n * File : activities/text/Identify.js\n * Created : 20/06/2015\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\nimport Activity from '../../Activity.js';\nimport { TextActivityBase, TextActivityBasePanel } from './TextActivityBase.js';\n\n/**\n * This type of text activity suggests users to click on specific words or single letters of a\n * given text, without any help on where these elements are placed.\n * @extends module:activities/text/TextActivityBase.TextActivityBase\n */\nexport class IdentifyText extends TextActivityBase {\n /**\n * IdentifyText constructor\n * @param {module:project/JClicProject.JClicProject} project - The project to which this activity belongs\n */\n constructor(project) {\n super(project);\n }\n}\n\n/**\n * The {@link module:activities/text/TextActivityBase.TextActivityBasePanel TextActivityBasePanel} where {@link module:activities/text/IdentifyText.IdentifyText IdentifyText} activities are played.\n * @extends module:activities/text/TextActivityBase.TextActivityBasePanel\n */\nclass IdentifyTextPanel extends TextActivityBasePanel {\n /**\n * IdentifyTextPanel constructor\n * @param {module:Activity.Activity} act - The {@link module:Activity.Activity Activity} to which this Panel belongs\n * @param {module:JClicPlayer.JClicPlayer} ps - Any object implementing the methods defined in the\n * [PlayStation](http://projectestac.github.io/jclic/apidoc/edu/xtec/jclic/PlayStation.html) Java interface.\n * @param {external:jQuery} [$div] - The jQuery DOM element where this Panel will deploy\n */\n constructor(act, ps, $div) {\n super(act, ps, $div);\n this.spanText = true;\n this.spanChars = act.type === 'identifyChars';\n this.spansChecked = new Set();\n }\n\n /**\n * Creates a target DOM element for the provided target.\n * @override\n * @param {module:activities/text/TextActivityDocument.TextTarget} target - The target related to the DOM object to be created\n * @param {external:jQuery} $span - - An initial DOM object (usually a `span`) that can be used\n * to store the target, or replaced by another type of object.\n * @returns {external:jQuery} - The jQuery DOM element loaded with the target data.\n */\n $createTargetElement(target, $span) {\n super.$createTargetElement(target, $span);\n const idLabel = `target${`000${this.targets.length - 1}`.slice(-3)}`;\n $span.on('click', event => {\n event.textTarget = target;\n event.idLabel = idLabel;\n this.processEvent(event);\n });\n return $span;\n }\n\n $createSpanElement($span) {\n $span.on('click', event => {\n event.$spanElement = $span;\n this.processEvent(event);\n });\n return $span;\n }\n\n /**\n * Basic initialization procedure\n * @override\n */\n initActivity() {\n super.initActivity(this);\n this.$div.find('.JClicTextDocument > p').css('cursor', 'pointer');\n this.$div.find('.JClicTextDocument > span').css('cursor', 'pointer');\n // Clean possible previous errors\n this.spansChecked.forEach($spanElement => $spanElement.css($spanElement.initialCSS || this.act.document.style['default'].css));\n this.spansChecked.clear();\n this.playing = true;\n }\n\n /**\n * Counts the number of targets that are solved\n * @returns {number}\n */\n countSolvedTargets() {\n return this.targets.filter(({ targetStatus }) => targetStatus === 'SOLVED').length;\n }\n\n /**\n * Evaluates all the targets in this panel. This method is usually called from the `Check` button.\n * @override\n * @returns {boolean} - `true` when all targets are OK, `false` otherwise.\n */\n evaluatePanel() {\n let targetsOk = 0;\n this.targets.forEach(target => {\n const ok = target.targetStatus === 'SOLVED';\n if (ok)\n targetsOk++;\n target.checkColors();\n this.ps.reportNewAction(this.act, 'SELECT', target.text, target.pos, ok, targetsOk);\n });\n\n\n if (targetsOk === this.targets.length && this.spansChecked.size === 0) {\n this.finishActivity(true);\n return true;\n } else {\n // Mark selected spans as error\n this.spansChecked.forEach($spanElement => $spanElement.css(this.act.document.style['targetError'].css));\n this.playEvent('finishedError');\n }\n return false;\n }\n\n /**\n * Ordinary ending of the activity, usually called form `processEvent`\n * @override\n * @param {boolean} result - `true` if the activity was successfully completed, `false` otherwise\n */\n finishActivity(result) {\n this.$div.find('.JClicTextDocument > p').css('cursor', 'pointer');\n return super.finishActivity(result);\n }\n\n /**\n * Main handler used to process mouse, touch, keyboard and edit events.\n * @override\n * @param {external:Event} event - The HTML event to be processed\n * @returns {boolean} - When this event handler returns `false`, jQuery will stop its\n * propagation through the DOM tree. See: {@link http://api.jquery.com/on}\n */\n processEvent(event) {\n if (!super.processEvent(event) ||\n event.timeStamp === this.lastTimeStamp)\n return false;\n\n if (event.timeStamp)\n this.lastTimeStamp = event.timeStamp;\n\n const target = event.textTarget;\n const $spanElement = event.$spanElement;\n\n switch (event.type) {\n case 'click':\n let text, pos, ok = false;\n if (target) {\n if (target.targetStatus === 'SOLVED')\n target.targetStatus = 'HIDDEN';\n else {\n target.targetStatus = 'SOLVED';\n ok = true;\n }\n text = target.text;\n pos = target.pos;\n // TODO: Just on/off target colors, don't mark it as error!\n target.checkColors();\n } else {\n if ($spanElement) {\n $spanElement.checked = !$spanElement.checked;\n if ($spanElement.checked) {\n this.spansChecked.add($spanElement);\n $spanElement.css(this.act.document.style.target.css);\n }\n else {\n this.spansChecked.delete($spanElement);\n $spanElement.css($spanElement.initialCSS || this.act.document.style.default.css);\n }\n text = $spanElement.text();\n }\n else\n text = 'unknown';\n pos = 0;\n }\n\n if (!this.$checkButton) {\n // Check and notify action\n const cellsAtPlace = this.countSolvedTargets();\n this.ps.reportNewAction(this.act, 'SELECT', text, pos, ok, cellsAtPlace);\n\n // End activity or play event sound\n if (ok && this.spansChecked.size === 0 && cellsAtPlace === this.targets.length)\n this.finishActivity(true);\n else\n this.playEvent(ok ? 'actionOk' : 'actionError');\n }\n event.preventDefault();\n break;\n\n default:\n break;\n }\n return true;\n }\n}\n\nObject.assign(IdentifyTextPanel.prototype, {\n /**\n * Flag indicating if targets must be visually marked when the activity begins. In this type of\n * activity should be always `false` to avoid revealing the words o letters that must be found.\n * @name module:activities/text/IdentifyText.IdentifyTextPanel#targetsMarked\n * @type {boolean} */\n targetsMarked: false,\n /**\n * Used to avoid duplicate event processing\n * @name module:activities/text/IdentifyText.IdentifyTextPanel#lastTimeStamp\n * @type {number}\n */\n lastTimeStamp: 0,\n /**\n * Set of non-target spans currently selected by the player.\n * This attribute should be empty to solve the activity.\n * @name module:activities/text/IdentifyText.IdentifyTextPanel#spansChecked\n * @type {set} */\n spansChecked: new Set(),\n});\n\n/**\n * Panel class associated to this type of activity: {@link module:activities/text/IdentifyText.IdentifyTextPanel IdentifyTextPanel}\n * @type {class} */\nIdentifyText.Panel = IdentifyTextPanel;\n\n// Register activity class\nexport default Activity.registerClass('@text.Identify', IdentifyText);\n","/**\n * File : activities/text/OrderText.js\n * Created : 20/06/2015\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\nimport $ from 'jquery';\nimport Activity from '../../Activity.js';\nimport { TextActivityBase, TextActivityBasePanel } from './TextActivityBase.js';\nimport BoxConnector from '../../boxes/BoxConnector.js';\nimport { Point } from '../../AWT.js';\n\n/**\n * In this type of text activity users must put in order some words or paragraphs that have been\n * initially shuffled.\n * @extends module:activities/text/TextActivityBase.TextActivityBase\n */\nexport class OrderText extends TextActivityBase {\n /**\n * OrderText constructor\n * @param {module:project/JClicProject.JClicProject} project - The project to which this activity belongs\n */\n constructor(project) {\n super(project);\n }\n\n /**\n * Whether or not the activity uses random to shuffle internal components\n * @override\n * @returns {boolean}\n */\n hasRandom() {\n return true;\n }\n\n /**\n * When `true`, the activity must always be shuffled\n * @override\n * @returns {boolean}\n */\n shuffleAlways() {\n return true;\n }\n\n /**\n * Whether the activity allows the user to request help.\n * @override\n * @returns {boolean}\n */\n helpSolutionAllowed() {\n return true;\n }\n}\n\nObject.assign(OrderText.prototype, {\n /**\n * Whether to allow or not to shuffle words among different paragraphs.\n * @name module:activities/text/OrderText.OrderText#amongParagraphs\n * @type {boolean} */\n amongParagraphs: false,\n /**\n * The box connector\n * @name module:activities/text/OrderText.OrderText#bc\n * @type {module:boxes/BoxConnector.BoxConnector} */\n bc: null,\n});\n\n/**\n * The {@link module:activities/text/TextActivityBase.TextActivityBasePanel TextActivityBasePanel} where {@link module:activities/text/OrderText.OrderText OrderText} activities are played.\n * @extends module:activities/text/TextActivityBase.TextActivityBasePanel\n */\nexport class OrderTextPanel extends TextActivityBasePanel {\n /**\n * OrderTextPanel constructor\n * @param {module:Activity.Activity} act - The {@link module:Activity.Activity Activity} to which this Panel belongs\n * @param {module:JClicPlayer.JClicPlayer} ps - Any object implementing the methods defined in the\n * [PlayStation](http://projectestac.github.io/jclic/apidoc/edu/xtec/jclic/PlayStation.html) Java interface.\n * @param {external:jQuery} [$div] - The jQuery DOM element where this Panel will deploy\n */\n constructor(act, ps, $div) {\n super(act, ps, $div);\n }\n\n /**\n * Prepares the text panel\n * @override\n */\n buildVisualComponents() {\n this.act.document.style['target'].css.cursor = 'pointer';\n super.buildVisualComponents();\n }\n\n /**\n * Sets the size and position of this activity panel\n * @override\n * @param {module:AWT.Rectangle} rect\n */\n setBounds(rect) {\n if (this.$canvas)\n this.$canvas.remove();\n\n super.setBounds(rect);\n if (!this.act.dragCells) {\n // Create the main canvas\n this.$canvas = $(`<canvas width=\"${rect.dim.width}\" height=\"${rect.dim.height}\"/>`).css({\n position: 'absolute',\n top: 0,\n left: 0,\n 'pointer-events': 'none'\n });\n this.$div.append(this.$canvas);\n\n // Create a [BoxConnector](BoxConnector.html) and attach it to the canvas context\n this.bc = new BoxConnector(this, this.$canvas);\n this.bc.compositeOp = this.bc.DEFAULT_COMPOSITE_OP;\n\n // Repaint all\n this.invalidate().update();\n }\n }\n\n /**\n * Creates a target DOM element for the provided target.\n * @override\n * @param {module:activities/text/TextActivityDocument.TextTarget} target - The target related to the DOM object to be created\n * @param {external:jQuery} $span - - An initial DOM object (usually a `span`) that can be used\n * to store the target, or replaced by another type of object.\n * @returns {external:jQuery} - The jQuery DOM element loaded with the target data.\n */\n $createTargetElement(target, $span) {\n super.$createTargetElement(target, $span);\n const idLabel = `target${`000${this.targets.length - 1}`.slice(-3)}`;\n $span.addClass('JClicTextTarget').on('click', event => {\n event.textTarget = target;\n event.idLabel = idLabel;\n this.processEvent(event);\n });\n return $span;\n }\n\n /**\n * Swaps the position of two targets in the document\n * @param {module:activities/text/TextActivityDocument.TextTarget} t1 - One target\n * @param {module:activities/text/TextActivityDocument.TextTarget} t2 - Another target\n */\n swapTargets(t1, t2) {\n const\n $span1 = t1.$span,\n $span2 = t2.$span,\n $marker = $('<span/>');\n $marker.insertAfter($span2);\n $span2.detach();\n $span2.insertAfter($span1);\n $span1.detach();\n $span1.insertAfter($marker);\n $marker.remove();\n\n const\n pos = t1.pos,\n $p = t1.$p;\n t1.pos = t2.pos;\n t1.$p = t2.$p;\n t2.pos = pos;\n t2.$p = $p;\n }\n\n /**\n * Basic initialization procedure\n * @override\n */\n initActivity() {\n super.initActivity();\n if (!this.firstRun)\n this.buildVisualComponents();\n else\n this.firstRun = false;\n }\n\n /**\n * Called when the activity starts playing\n * @override\n */\n startActivity() {\n super.startActivity();\n if (!this.showingPrevScreen) {\n if (this.act.type === 'orderWords' && !this.act.amongParagraphs) {\n // Group targets by paragraph\n const groups = [];\n let\n lastTarget = null,\n currentGroup = [];\n this.targets.forEach(t => {\n if (lastTarget !== null && lastTarget.$p !== t.$p) {\n groups.push(currentGroup);\n currentGroup = [];\n }\n currentGroup.push(t);\n lastTarget = t;\n });\n if (currentGroup.length > 0)\n groups.push(currentGroup);\n\n // Scramble group by group\n groups.forEach(group => this.shuffleTargets(group, this.act.shuffles));\n } else\n this.shuffleTargets(this.targets, this.act.shuffles);\n\n this.playing = true;\n }\n this.setBounds(this);\n }\n\n /**\n * Randomly shuffles a set of targets\n * @param {module:activities/text/TextActivityDocument.TextTarget[]} targets - The set of targets to shuffle (can be all\n * document targets or just the targets belonging to the same paragraph, depending on the value of\n * `amongParagraphs` in {@link module:Activity.Activity Activity}.\n * @param {number} steps - The number of times to shuffle the elements\n */\n shuffleTargets(targets, steps) {\n const nt = targets.length;\n if (nt > 1) {\n let repeatCount = 100;\n for (let i = 0; i < steps; i++) {\n const\n r1 = Math.floor(Math.random() * nt),\n r2 = Math.floor(Math.random() * nt);\n if (r1 !== r2) {\n this.swapTargets(targets[r1], targets[r2]);\n } else {\n if (--repeatCount)\n i++;\n }\n }\n }\n }\n\n /**\n * Sets the current target\n * @param {module:activities/text/TextActivityDocument.TextTarget} target - The currently selected target. Can be `null`.\n */\n setCurrentTarget(target) {\n const targetCss = this.act.document.getFullStyle('target').css;\n if (this.currentTarget && this.currentTarget.$span)\n this.currentTarget.$span.css(targetCss);\n if (target && target.$span) {\n target.$span.css({\n color: targetCss['background-color'],\n 'background-color': targetCss.color\n });\n }\n this.currentTarget = target;\n }\n\n /**\n * Counts the number of targets that are at right position\n * @returns {number}\n */\n countSolvedTargets() {\n return this.targets.filter(({ num, pos }) => num === pos).length;\n }\n\n /**\n * Evaluates all the targets in this panel. This method is usually called from the `Check` button.\n * @override\n * @returns {boolean} - `true` when all targets are OK, `false` otherwise.\n */\n evaluatePanel() {\n if (this.bc && this.bc.active)\n this.bc.end();\n this.setCurrentTarget(null);\n\n let targetsOk = 0;\n this.targets.forEach(target => {\n const ok = target.num === target.pos;\n target.targetStatus = ok ? 'SOLVED' : 'WITH_ERROR';\n if (ok)\n targetsOk++;\n target.checkColors();\n this.ps.reportNewAction(this.act, 'PLACE', target.text, target.pos, ok, targetsOk);\n });\n if (targetsOk === this.targets.length) {\n this.finishActivity(true);\n return true;\n } else {\n this.playEvent('finishedError');\n }\n return false;\n }\n\n /**\n * Ordinary ending of the activity, usually called form `processEvent`\n * @override\n * @param {boolean} result - `true` if the activity was successfully completed, `false` otherwise\n */\n finishActivity(result) {\n $('.JClicTextTarget').css('cursor', 'pointer');\n return super.finishActivity(result);\n }\n\n /**\n * Main handler used to process mouse, touch, keyboard and edit events.\n * @override\n * @param {external:Event} event - The HTML event to be processed\n * @returns {boolean} - When this event handler returns `false`, jQuery will stop its\n * propagation through the DOM tree. See: {@link http://api.jquery.com/on}\n */\n processEvent(event) {\n if (!super.processEvent(event))\n return false;\n\n const target = event.textTarget;\n let p = null;\n if (this.bc && this.playing && !this.showingPrevScreen) {\n //\n // _touchend_ event don't provide pageX nor pageY information\n if (event.type === 'touchend')\n p = this.bc.active ? this.bc.dest.clone() : new Point();\n else {\n // Touch events can have more than one touch, so `pageX` must be obtained from `touches[0]`\n const\n x = event.originalEvent.touches ? event.originalEvent.touches[0].pageX : event.pageX,\n y = event.originalEvent.touches ? event.originalEvent.touches[0].pageY : event.pageY;\n p = new Point(x - this.$div.offset().left, y - this.$div.offset().top);\n }\n\n switch (event.type) {\n case 'click':\n if (target && target !== this.currentTarget) {\n if (this.currentTarget) {\n if (this.bc && this.bc.active)\n this.bc.end();\n this.swapTargets(target, this.currentTarget);\n this.setCurrentTarget(null);\n\n if (!this.$checkButton) {\n // Check and notify action\n const\n cellsAtPlace = this.countSolvedTargets(),\n ok = target.pos === target.num;\n this.ps.reportNewAction(this.act, 'PLACE', target.text, target.pos, ok, cellsAtPlace);\n\n // End activity or play event sound\n if (ok && cellsAtPlace === this.targets.length)\n this.finishActivity(true);\n else\n this.playEvent(ok ? 'actionOk' : 'actionError');\n }\n } else {\n this.setCurrentTarget(target);\n this.bc.begin(p);\n this.playEvent('click');\n }\n }\n break;\n\n case 'mousemove':\n this.bc.moveTo(p);\n break;\n\n default:\n break;\n }\n event.preventDefault();\n return true;\n }\n }\n}\n\n// Properties and methods specific to OrderTextPanel\nObject.assign(OrderTextPanel.prototype, {\n /**\n * Currently selected text target\n * @name module:activities/text/OrderText.OrderTextPanel#currentTarget\n * @type {module:activities/text/TextActivityDocument.TextActivityDocument.TextTarget} */\n currentTarget: null,\n /**\n * The box connector\n * @name module:activities/text/OrderText.OrderTextPanel#bc\n * @type {module:boxes/BoxConnector.BoxConnector} */\n bc: null,\n /**\n * List of mouse, touch and keyboard events intercepted by this panel\n * @override\n * @name module:activities/text/OrderText.OrderTextPanel#events\n * @type {string[]} */\n events: ['click', 'mousemove'],\n});\n\n/**\n * Panel class associated to this type of activity: {@link module:activities/text/OrderText.OrderTextPanel OrderTextPanel}\n * @type {class} */\nOrderText.Panel = OrderTextPanel;\n\n// Register activity class\nexport default Activity.registerClass('@text.Order', OrderText);\n","/**\n * File : activities/text/WrittenAnswer.js\n * Created : 04/06/2015\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\nimport $ from 'jquery';\nimport { Activity, ActivityPanel } from '../../Activity.js';\nimport ActiveBoxGrid from '../../boxes/ActiveBoxGrid.js';\nimport BoxBag from '../../boxes/BoxBag.js';\nimport { Rectangle, Point } from '../../AWT.js';\nimport { compareMultipleOptions } from '../../Utils.js';\nimport Rectangular from '../../shapers/Rectangular.js';\n\n/**\n * This class of {@link module:Activity.Activity Activity} shows a panel with {@link module:boxes/ActiveBox.ActiveBox ActiveBox} objects acting as cells\n * with questions. The answers to these questions must be written in a separate text field.\n *\n * The ActiveBox objects are filled with data stored in {@link module:boxes/ActiveBagContent.ActiveBagContent ActiveBagContent} repositories.\n *\n * A second {@link module:boxes/ActiveBagContent.ActiveBagContent ActiveBagContent} can be used as alternative content, revealed as the questions\n * are solved.\n * @extends module:Activity.Activity\n */\nexport class WrittenAnswer extends Activity {\n /**\n * WrittenAnswer constructor\n * @param {module:project/JClicProject.JClicProject} project - The JClic project to which this activity belongs\n */\n constructor(project) {\n super(project);\n }\n\n /**\n * Loads this object settings from an XML element\n * @override\n * @param {external:jQuery} $xml - The jQuery XML element to parse\n */\n setProperties($xml) {\n super.setProperties($xml);\n this.abc['primary'].avoidAllIdsNull(this.abc['answers'].getNumCells());\n }\n\n /**\n * Retrieves the minimum number of actions needed to solve this activity\n * @override\n * @returns {number}\n */\n getMinNumActions() {\n return this.invAss ?\n this.abc['answers'].getNumCells() :\n this.abc['primary'].getNumCells() - this.nonAssignedCells;\n }\n\n /**\n * This activity uses random values to shuffle its internal components\n * @override\n * @returns {boolean}\n */\n hasRandom() {\n return true;\n }\n\n /**\n * This activity makes use of the keyboard\n * @override\n * @returns {boolean}\n */\n needsKeyboard() {\n return true;\n }\n\n /**\n * This activity can permit the user to display the solution\n * @override\n * @returns {boolean}\n */\n helpSolutionAllowed() {\n return true;\n }\n}\n\nObject.assign(WrittenAnswer.prototype, {\n /**\n * Number of unassigned cells\n * @name module:activities/text/WrittenAnswer.WrittenAnswer#nonAssignedCells\n * @type {number} */\n nonAssignedCells: 0,\n /**\n * Whether to use or not the cell's `idAss` field to check if pairings match\n * @name module:activities/text/WrittenAnswer.WrittenAnswer#useIdAss\n * @type {boolean} */\n useIdAss: true,\n});\n\n/**\n * The {@link module:Activity.ActivityPanel ActivityPanel} where {@link module:activities/text/WrittenAnswer.WrittenAnswer WrittenAnswer} activities are played.\n * @extends module:Activity.ActivityPanel\n */\nexport class WrittenAnswerPanel extends ActivityPanel {\n /**\n * WrittenAnswerPanel constructor\n * @param {module:Activity.Activity} act - The {@link module:Activity.Activity Activity} to which this Panel belongs\n * @param {module:JClicPlayer.JClicPlayer} ps - Any object implementing the methods defined in the\n * [PlayStation](http://projectestac.github.io/jclic/apidoc/edu/xtec/jclic/PlayStation.html) Java interface.\n * @param {external:jQuery} [$div] - The jQuery DOM element where this Panel will deploy\n */\n constructor(act, ps, $div) {\n super(act, ps, $div);\n }\n\n /**\n * Performs miscellaneous cleaning operations\n * @override\n */\n clear() {\n if (this.bgA) {\n this.bgA.end();\n this.bgA = null;\n }\n if (this.bgB) {\n this.bgB.end();\n this.bgB = null;\n }\n }\n\n /**\n * Prepares the visual components of the activity\n * @override\n */\n buildVisualComponents() {\n if (this.firstRun)\n super.buildVisualComponents();\n\n this.clear();\n\n const\n abcA = this.act.abc['primary'],\n abcB = this.act.abc['answers'],\n solved = this.act.abc['solvedPrimary'];\n\n if (abcA && abcB) {\n if (this.act.invAss)\n this.invAssCheck = Array(abcB.getNumCells()).fill(false);\n\n if (abcA.image) {\n abcA.setImgContent(this.act.project.mediaBag, null, false);\n if (abcA.animatedGifFile && !abcA.shaper.rectangularShapes && !this.act.shuffleA)\n this.$animatedBg = $('<span/>').css({\n 'background-image': 'url(' + abcA.animatedGifFile + ')',\n 'background-position': 'center',\n 'background-repeat': 'no-repeat',\n position: 'absolute'\n }).appendTo(this.$div);\n }\n\n if (solved && solved.image)\n solved.setImgContent(this.act.project.mediaBag, null, false);\n\n if (this.act.acp !== null) {\n const contentKit = [abcA, abcB];\n if (solved)\n contentKit.push(solved);\n this.act.acp.generateContent(abcA.nch, abcA.ncw, contentKit, false);\n }\n\n this.bgA = ActiveBoxGrid.createEmptyGrid(null, this, this.act.margin, this.act.margin, abcA);\n\n let w = abcB.w;\n if (this.act.boxGridPos === 'AUB' || this.act.boxGridPos === 'BUA')\n w = abcA.getTotalWidth();\n //\n // bgB will be used only as a placeholder for `$textField`\n this.bgB = new ActiveBoxGrid(null, this, abcB.style, this.act.margin, this.act.margin, w, abcB.h, new Rectangular(1, 1));\n this.$form = $('<form/>', { id: 'form1' /*, action: '#' */ });\n // Modified 05/Feb/2020: jQuery not catching submit event when on first activity\n this.$form[0].addEventListener('submit', event => {\n event.preventDefault();\n if (this.playing)\n this.setCurrentCell(this.currentCell);\n return false;\n });\n\n this.$textField = $('<input/>', { type: 'text', size: 200 })\n .css(abcB.style.getCSS())\n .css({\n position: 'absolute', top: 0, left: 0,\n border: 0, padding: 0, margin: 0,\n 'text-align': 'center'\n })\n .attr({\n autocomplete: 'off',\n autocorrect: 'off',\n autocapitalize: 'off',\n spellcheck: 'false',\n });\n\n this.$div.append(this.$form.append(this.$textField));\n this.bgA.setContent(abcA, solved || null);\n this.bgA.setDefaultIdAss();\n if (this.$animatedBg)\n this.bgA.setCellAttr('tmpTrans', true);\n\n this.act.nonAssignedCells = 0;\n for (let i = 0; i < this.bgA.getNumCells(); i++) {\n var bx = this.bgA.getActiveBox(i);\n if (bx.idAss === -1) {\n this.act.nonAssignedCells++;\n bx.switchToAlt(this.ps);\n }\n }\n this.bgA.setVisible(true);\n this.bgB.setVisible(false);\n }\n }\n\n /**\n * Basic initialization procedure\n * @override\n */\n initActivity() {\n super.initActivity();\n if (!this.firstRun)\n this.buildVisualComponents();\n else\n this.firstRun = false;\n\n if (this.bgA && this.bgB) {\n // Scramble cells\n if (this.act.shuffleA)\n this.shuffle([this.bgA], true, true);\n\n if (this.useOrder)\n this.currentItem = this.bgA.getNextItem(-1);\n\n this.setAndPlayMsg('initial', 'start');\n this.invalidate().update();\n this.playing = true;\n }\n }\n\n /**\n * Called by [JClicPlayer](JClicPlayer.html) when this activity panel is fully visible, just\n * after the initialization process.\n * @override\n */\n activityReady() {\n super.activityReady();\n this.setCurrentCell(0);\n }\n\n /**\n * Updates the graphic content of this panel.\n * This method will be called from {@link module:AWT.Container#update} when needed.\n * @override\n * @param {module:AWT.Rectangle} dirtyRegion - Specifies the area to be updated. When `null`,\n * it's the whole panel.\n */\n updateContent(dirtyRegion) {\n super.updateContent(dirtyRegion);\n if (this.bgA && this.$canvas) {\n const\n canvas = this.$canvas.get(-1),\n ctx = canvas.getContext('2d');\n if (!dirtyRegion)\n dirtyRegion = new Rectangle(0, 0, canvas.width, canvas.height);\n ctx.clearRect(dirtyRegion.pos.x, dirtyRegion.pos.y, dirtyRegion.dim.width, dirtyRegion.dim.height);\n this.bgA.update(ctx, dirtyRegion);\n }\n return this;\n }\n\n /**\n * Sets the real dimension of this panel.\n * @override\n * @param {module:AWT.Dimension} preferredMaxSize - The maximum surface available for the activity panel\n * @returns {module:AWT.Dimension}\n */\n setDimension(preferredMaxSize) {\n return (!this.bgA || !this.bgB || this.getBounds().equals(preferredMaxSize)) ?\n preferredMaxSize :\n BoxBag.layoutDouble(preferredMaxSize, this.bgA, this.bgB, this.act.boxGridPos, this.act.margin);\n }\n\n /**\n * Sets the size and position of this activity panel\n * @override\n * @param {module:AWT.Rectangle} rect\n */\n setBounds(rect) {\n if (this.$canvas)\n this.$canvas.remove();\n\n super.setBounds(rect);\n if (this.bgA || this.bgB) {\n const r = rect.clone();\n if (this.act.boxGridPos === 'AUB')\n r.height -= this.bgB.pos.y + this.act.margin / 2;\n else if (this.act.boxGridPos === 'AB')\n r.width -= this.bgB.pos.x + this.act.margin / 2;\n\n // Create the main canvas\n this.$canvas = $('<canvas width=\"' + r.dim.width + '\" height=\"' + r.dim.height + '\"/>').css({\n position: 'absolute',\n top: 0,\n left: 0\n });\n\n // Resize animated gif background\n if (this.bgA && this.$animatedBg) {\n var bgRect = this.bgA.getBounds();\n this.$animatedBg.css({\n left: bgRect.pos.x,\n top: bgRect.pos.y,\n width: bgRect.dim.width + 'px',\n height: bgRect.dim.height + 'px',\n 'background-size': bgRect.dim.width + 'px ' + bgRect.dim.height + 'px'\n });\n this.$canvas.insertAfter(this.$animatedBg);\n } else\n this.$div.prepend(this.$canvas);\n\n if (this.$textField) {\n this.$textField.css({\n top: this.bgB.pos.y,\n left: this.bgB.pos.x,\n width: this.bgB.dim.width,\n height: this.bgB.dim.height,\n zIndex: 9\n });\n }\n // Repaint all\n this.invalidate().update();\n }\n }\n\n /**\n * Builds the accessible components needed for this ActivityPanel\n * This method is called when all main elements are placed and visible, when the activity is ready\n * to start or when resized.\n * @override\n */\n buildAccessibleComponents() {\n if (this.$canvas && this.accessibleCanvas) {\n super.buildAccessibleComponents();\n if (this.bgA)\n this.bgA.buildAccessibleElements(this.$canvas, this.$div, 'click');\n // bgB has a regular input element, so it's already accessible\n }\n }\n\n /**\n * Checks if all inverse associations are done\n * @returns {boolean}\n */\n checkInvAss() {\n return this.act.invAss && this.invAssCheck && this.invAssCheck.every(chk => chk);\n }\n\n /**\n * Updates the currently selected cell, evaluating the answer written by the user on the text field.\n * @param {number} i - Index into the {@link module:boxes/ActiveBoxbag.ActiveBoxBag ActiveBoxBag} of the cell to make active\n * @param {function[]} delayedActions - If set, store the the action in this array for future execution\n */\n setCurrentCell(i, delayedActions = null) {\n if (!this.playing)\n return;\n\n let\n bx = null,\n m = false;\n\n if (this.currentCell !== -1) {\n let ok = false;\n bx = this.bgA ? this.bgA.getActiveBoxWithIdLoc(this.currentCell) : null;\n if (bx) {\n bx.setMarked(false);\n const\n src = bx.getDescription(),\n id = bx.idAss,\n txCheck = id >= 0 ? this.act.abc['answers'].getActiveBoxContent(id).text : '',\n txAnswer = this.$textField.val().trim();\n if (compareMultipleOptions(txAnswer, txCheck, false, this.act.numericContent)) {\n ok = true;\n bx.idAss = -1;\n // When in multiple-answer, fill-in textField with the first valid option:\n const p = txCheck.indexOf('|');\n if (p >= 0)\n this.$textField.val(txCheck.substring(0, p));\n\n if (this.act.abc['solvedPrimary']) {\n bx.switchToAlt(this.ps);\n m = bx.playMedia(this.ps, delayedActions);\n } else\n bx.clear();\n if (this.act.invAss && id >= 0 && id < this.invAssCheck.length) {\n this.invAssCheck[id] = true;\n }\n if (this.act.useOrder)\n this.currentItem = this.bgA.getNextItem(this.currentItem);\n }\n\n const cellsPlaced = this.bgA.countCellsWithIdAss(-1);\n if (txAnswer.length > 0) {\n this.ps.reportNewAction(this.act, 'WRITE', src, txAnswer, ok, cellsPlaced);\n }\n if (ok && (this.checkInvAss() || cellsPlaced === this.bgA.getNumCells())) {\n this.finishActivity(true);\n this.$textField.prop('disabled', true);\n this.invalidate().update();\n return;\n } else if (!m && txAnswer.length > 0)\n this.playEvent(ok ? 'actionOk' : 'actionError');\n }\n }\n\n bx = this.bgA ?\n this.act.useOrder ?\n this.bgA.getBox(this.currentItem) :\n this.bgA.getActiveBoxWithIdLoc(i) :\n null;\n\n if (this.bgA && (!bx || bx.idAss === -1)) {\n for (var j = 0; j < this.bgA.getNumCells(); j++) {\n bx = this.bgA.getActiveBoxWithIdLoc(j);\n if (bx.idAss !== -1)\n break;\n }\n if (bx && bx.idAss === -1) {\n this.finishActivity(false);\n this.$textField.prop('disabled', true);\n this.invalidate().update();\n return;\n }\n }\n // Draw border only if it has more than one cell\n if (bx && this.bgA && this.bgA.getNumCells() > 1)\n bx.setMarked(true);\n if (bx)\n this.currentCell = bx.idLoc;\n this.$textField.val('');\n this.$textField.trigger('focus');\n this.invalidate().update();\n if (bx)\n bx.playMedia(this.ps, delayedActions);\n }\n\n /**\n * Main handler used to process mouse, touch, keyboard and edit events\n * @override\n * @param {external:Event} event - The HTML event to be processed\n * @returns {boolean} - When this event handler returns `false`, jQuery will stop its\n * propagation through the DOM tree. See: {@link http://api.jquery.com/on}\n */\n processEvent(event) {\n if (this.playing) {\n // Array to be filled with actions to be executed at the end of event processing\n const delayedActions = [];\n switch (event.type) {\n case 'click':\n event.preventDefault();\n this.ps.stopMedia(1);\n const p = new Point(\n event.pageX - this.$div.offset().left,\n event.pageY - this.$div.offset().top);\n\n // Avoid clicks on the text field\n if (this.bgB.contains(p)) {\n this.$textField.trigger('focus');\n break;\n }\n\n const bx = this.bgA ? this.bgA.findActiveBox(p) : null;\n if (bx && !bx.isInactive()) {\n if (bx.getContent() && bx.getContent().mediaContent === null)\n this.playEvent('CLICK');\n this.setCurrentCell(bx.idLoc, delayedActions);\n }\n break;\n\n case 'change':\n event.preventDefault();\n this.setCurrentCell(this.currentCell, delayedActions);\n break;\n }\n delayedActions.forEach(action => action());\n return false;\n }\n }\n}\n\nObject.assign(WrittenAnswerPanel.prototype, {\n /**\n * The input text field where users write the answers\n * @name module:activities/text/WrittenAnswer.WrittenAnswerPanel#$textField\n * @type {external:jQuery} */\n $textField: null,\n /**\n * Array for storing checked associations\n * @name module:activities/text/WrittenAnswer.WrittenAnswerPanel#invAssCheck\n * @type {boolean[]} */\n invAssCheck: null,\n /**\n * The {@link module:boxes/ActiveBoxbag.ActiveBoxBag ActiveBoxBag} object containing the questions\n * @name module:activities/text/WrittenAnswer.WrittenAnswerPanel#bgA\n * @type {module:boxes/ActiveBoxBag.ActiveBoxBag} */\n bgA: null,\n /**\n * An optional {@link module:boxes/ActiveBoxbag.ActiveBoxBag ActiveBoxBag} with content displayed as cells are solved.\n * @name module:activities/text/WrittenAnswer.WrittenAnswerPanel#bgB\n * @type {module:boxes/ActiveBoxBag.ActiveBoxBag} */\n bgB: null,\n /**\n * The currently selected cell\n * @name module:activities/text/WrittenAnswer.WrittenAnswerPanel#currentCell\n * @type {number} */\n currentCell: -1,\n /**\n * Mouse events intercepted by this panel\n * @override\n * @name module:activities/text/WrittenAnswer.WrittenAnswerPanel#events\n * @type {string[]} */\n events: ['click', 'change'],\n});\n\n/**\n * Panel class associated to this type of activity: {@link module:activities/text/WrittenAnswer.WrittenAnswerPanel WrittenAnswerPanel}\n * @type {class} */\nWrittenAnswer.Panel = WrittenAnswerPanel;\n\n// Register activity class\nexport default Activity.registerClass('@text.WrittenAnswer', WrittenAnswer);\n","/**\n * File : automation/arith/Arith.js\n * Created : 28/05/2015\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\n/* global Intl */\n\nimport $ from 'jquery';\nimport AutoContentProvider from '../AutoContentProvider.js';\nimport { getNumber, getBoolean, getAttr, setAttr, attrForEach } from '../../Utils.js';\n\n//\n// Miscellaneous constants used by Arith:\nconst\n NMAXLOOPS = 60,\n OPSTR = ['+', '-', String.fromCharCode(215), ':'],\n RES = -12345,\n // Use comma as a decimal separator, based on current locale settings\n // See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl\n DOTASCOMMA = Intl && Intl.NumberFormat().format(1.1).indexOf(',') > 0;\n\n/**\n * Arith provides randomly generated mental arithmetics operations, ready to be used in JClic activities.\n *\n * The operations can be additions, subtractions, multiplications or divides. The unknown of these\n * operations can be the result of the operation (`A op B = ?`), any of the two operators\n * (`A op ? = C` or `? op B = C`) or also the operator itself (`A ? B = C`).\n * @extends module:automation/AutoContentProvider.AutoContentProvider\n */\nexport class Arith extends AutoContentProvider {\n /**\n * Arith constructor\n */\n constructor() {\n super();\n this.className = '@arith.Arith';\n this.numericContent = true;\n this.opA = new Arith.Operator();\n this.opB = new Arith.Operator();\n }\n\n /**\n * Formats the number with a fixed number of decimals, optionally filling the result with leading\n * zeroes to have a fixed number of digits.\n * @param {number} val - The value to format\n * @param {number} dec - Number of decimals\n * @param {number} pre - Minimal number of digits before dot.\n * @returns {string}\n */\n static DecFormat(val, dec, pre) {\n let result = val.toFixed(dec);\n if (pre) {\n let n = result.indexOf('.');\n if (n < 0)\n n = result.length;\n for (; n < pre; n++)\n result = `0${result}`;\n }\n return result;\n }\n\n /**\n * Loads the object settings from a specific JQuery XML element\n * @override\n * @param {external:jQuery} $xml - The XML element to parse\n */\n setProperties($xml) {\n $xml.children().each((_n, child) => {\n const $node = $(child);\n let xNum = '';\n switch (child.nodeName) {\n case 'operand':\n switch ($node.attr('id')) {\n case 'A':\n this.opA.setProperties($node);\n break;\n case 'B':\n this.opB.setProperties($node);\n break;\n }\n break;\n case 'operations':\n this.use_add = getBoolean($node.attr('plus'));\n this.use_subst = getBoolean($node.attr('minus'));\n this.use_mult = getBoolean($node.attr('multiply'));\n this.use_div = getBoolean($node.attr('divide'));\n break;\n case 'unknown':\n this.exp_abx = getBoolean($node.attr('result'));\n this.exp_xbc = getBoolean($node.attr('first'));\n this.exp_axc = getBoolean($node.attr('last'));\n this.exp_axbc = getBoolean($node.attr('operand'));\n this.exp_caxb = getBoolean($node.attr('inverse'));\n break;\n case 'result':\n xNum = $node.attr('from');\n this.resultLimInf = getNumber(xNum === 'x' ? 0 : xNum, this.resultLimInf);\n xNum = $node.attr('to');\n this.resultLimSup = getNumber(xNum === 'x' ? 0 : xNum, this.resultLimSup);\n this.resultCarry = getBoolean($node.attr('notCarry'), this.resultCarry);\n this.resultNoDup = !getBoolean($node.attr('duplicates'), !this.resultNoDup);\n let s = $node.attr('order');\n this.resultOrder = s === 'ascending' ? 'SORTASC' : s === 'descending' ? 'SORTDESC' : 'NOSORT';\n s = $node.attr('condition');\n this.opCond = s === 'firstBig' ? 'AGB' : s === 'lastBig' ? 'BGA' : 'INDIF';\n break;\n }\n });\n return this;\n }\n\n /**\n * Gets a object with the basic attributes needed to rebuild this instance excluding functions,\n * parent references, constants and also attributes retaining the default value.\n * The resulting object is commonly usued to serialize elements in JSON format.\n * @returns {object} - The resulting object, with minimal attrributes\n */\n getAttributes() {\n return getAttr(this, [\n 'className',\n 'opA', 'opB', // Operator\n 'use_add', 'use_subst', 'use_mult', 'use_div',\n 'exp_abx|true', 'exp_axc|false', 'exp_xbc|false', 'exp_axbc|false', 'exp_caxb|false',\n 'resultLimInf|0', 'resultLimSup|9999', 'resultCarry|false', 'resultNoDup|false', 'resultOrder|NOSORT',\n 'opCond|INDIF'\n ]);\n }\n\n /**\n * Reads the properties of this Arith object from a dataset\n * @param {object} data - The data object to be parsed\n * @returns {object}\n */\n setAttributes(data) {\n return setAttr(this, data, [\n 'className',\n { key: 'opA', fn: Arith.Operator },\n { key: 'opB', fn: Arith.Operator },\n 'use_add', 'use_subst', 'use_mult', 'use_div',\n 'exp_abx', 'exp_axc', 'exp_xbc', 'exp_axbc', 'exp_caxb',\n 'resultLimInf', 'resultLimSup', 'resultCarry', 'resultNoDup', 'resultOrder',\n 'opCond',\n ]);\n }\n\n /**\n * Fills the `n` parameter (an {@link module:automation/arith/Arith.Num Num}) with a value in accordance with the\n * specifications of `op` (an {@link module:automation/arith/Arith.Operator Operator}), between two limits.\n * @param {module:automation/arith/Arith.Num} n - The number\n * @param {module:automation/arith/Arith.Operator} op - The operator\n * @param {number} limInf2 - Lower limit\n * @param {number} limSup2 - Upper limit\n * @returns {boolean} - `true` if all was OK\n */\n genNum(n, op, limInf2, limSup2) {\n let solved = false;\n n.c = op.numDec;\n const exp = n.c === 0 ? 1 : n.c === 1 ? 10 : 100;\n\n let ls = op.limSup;\n if (limSup2 !== RES && limSup2 < ls)\n ls = limSup2;\n let li = op.limInf;\n if (limInf2 !== RES && limInf2 > li)\n li = limInf2;\n\n if (op.fromList > 0) {\n n.vf = op.lst[Math.floor(Math.random() * op.fromList)];\n solved = true;\n }\n if (!solved) {\n const r = Math.floor(Math.random() * 100);\n if (op.wZero && r <= 10) {\n n.vf = 0;\n solved = true;\n } else if (op.wOne && r > 10 && r <= 20) {\n n.vf = 1;\n solved = true;\n } else if (op.wMinusOne && r > 20 && r <= 30) {\n n.vf = -1;\n solved = true;\n }\n }\n if (!solved) {\n if (li > ls) {\n const k = li;\n li = ls;\n ls = k;\n }\n let rang = Math.floor(ls - li + 1);\n if (rang < 0)\n rang = 1;\n let v = (Math.floor(Math.random() * rang) + li) * exp;\n if (exp > 1)\n v += Math.floor(Math.random() * exp);\n n.vf = v / exp;\n }\n return true;\n }\n\n /**\n * Fills the provided {@link module:automation/arith/Arith.Operator Operator} with real values\n * @param {module:automation/arith/Arith.Operator} o - The operator to use to generate the operation\n * @returns {boolean} - `true` if all was OK\n */\n genOp(o) {\n let i, ri2, rs2, q, va, vb, bufa, bufb;\n const\n ops = [],\n rlinf = this.resultLimInf,\n rlsup = this.resultLimSup;\n\n let nops = 0;\n if (this.use_add)\n ops[nops++] = 'SUM';\n if (this.use_subst)\n ops[nops++] = 'REST';\n if (this.use_mult)\n ops[nops++] = 'MULT';\n if (this.use_div)\n ops[nops++] = 'DIV';\n\n const op = ops[Math.floor(Math.random() * nops)];\n switch (op) {\n case 'SUM':\n for (i = 0; i < NMAXLOOPS; i++) {\n this.genNum(o.numA, this.opA, this.RES, rlsup);\n ri2 = o.numA.vf < rlinf ? rlinf - Math.floor(o.numA.vf) : this.RES;\n rs2 = rlsup - Math.floor(o.numA.vf);\n switch (this.opCond) {\n case 'AGB':\n if (rs2 === this.RES || rs2 > o.numA.vf)\n rs2 = Math.floor(o.numA.vf);\n break;\n case 'BGA':\n if (ri2 === this.RES || ri2 < o.numA.vf)\n ri2 = Math.floor(o.numA.vf);\n break;\n }\n this.genNum(o.numB, this.opB, ri2, rs2);\n o.numR.vf = o.numA.vf + o.numB.vf;\n if (o.numR.vf >= rlinf && o.numR.vf <= rlsup)\n break;\n }\n o.numR.c = o.numA.c > o.numB.c ? o.numA.c : o.numB.c;\n o.op = 0;\n if (this.resultCarry && o.numA.vf > 0 && o.numB.vf > 0) {\n q = o.numR.c === 2 ? 100 : o.numR.c === 1 ? 10 : 1;\n\n bufa = Arith.DecFormat(Math.floor(o.numA.vf * q + 0.5), 0, 10).split('');\n bufb = Arith.DecFormat(Math.floor(o.numB.vf * q + 0.5), 0, 10).split('');\n for (i = 0; i < 10; i++)\n if (bufa[i] !== '0' || bufb[i] !== '0')\n break;\n for (; i < 10; i++) {\n va = parseInt(bufa[i]);\n vb = parseInt(bufb[i]);\n if (va + vb < 10)\n continue;\n while (va + vb > 9) {\n if (va > vb)\n va = va > 0 ? Math.floor(Math.random() * va) : 0;\n else\n vb = vb > 0 ? Math.floor(Math.random() * vb) : 0;\n }\n bufa[i] = va.toFixed(0);\n bufb[i] = vb.toFixed(0);\n }\n\n o.numA.vf = parseInt(bufa.join('')) / q;\n o.numB.vf = parseInt(bufb.join('')) / q;\n // Corrected 2019/02/11: Factors should be multiplied by 'q'!\n // INCORRECT: o.numR.vf = Math.floor(o.numA.vf + o.numB.vf + 0.5) / q\n o.numR.vf = Math.floor(o.numA.vf * q + o.numB.vf * q + 0.5) / q;\n }\n break;\n\n case 'REST':\n for (i = 0; i < NMAXLOOPS; i++) {\n this.genNum(o.numA, this.opA, rlinf, this.RES);\n ri2 = o.numA.vf > rlsup ? Math.floor(o.numA.vf - rlsup) : this.RES;\n rs2 = Math.floor(o.numA.vf - rlinf);\n switch (this.opCond) {\n case 'AGB':\n if (rs2 === this.RES || rs2 > o.numA.vf)\n rs2 = Math.floor(o.numA.vf);\n break;\n case 'BGA':\n if (ri2 === this.RES || ri2 < o.numA.vf)\n ri2 = Math.floor(o.numA.vf);\n break;\n }\n this.genNum(o.numB, this.opB, ri2, rs2);\n o.numR.vf = o.numA.vf - o.numB.vf;\n if (o.numR.vf >= rlinf && o.numR.vf <= rlsup)\n break;\n }\n o.numR.c = o.numA.c > o.numB.c ? o.numA.c : o.numB.c;\n o.op = 1;\n if (this.resultCarry && o.numA.vf > 0 && o.numB.vf > 0 && o.numA.vf >= o.numB.vf) {\n q = o.numR.c === 2 ? 100 : o.numR.c === 1 ? 10 : 1;\n bufa = Arith.DecFormat(Math.floor(o.numA.vf * q + 0.5), 0, 10).split('');\n bufb = Arith.DecFormat(Math.floor(o.numB.vf * q + 0.5), 0, 10).split('');\n for (i = 0; i < 10; i++)\n if (bufb[i] !== '0')\n break;\n for (; i < 10; i++) {\n va = parseInt(bufa[i]);\n vb = parseInt(bufb[i]);\n if (va >= vb)\n continue;\n vb = va > 0 ? Math.floor(Math.random() * va) : 0;\n bufb[i] = vb.toFixed(0);\n }\n\n o.numA.vf = parseInt(bufa.join('')) / q;\n o.numB.vf = parseInt(bufb.join('')) / q;\n // Corrected 2019/02/11: Factors should be multiplied by 'q'!\n // o.numR.vf = Math.floor(o.numA.vf - o.numB.vf + 0.5) / q\n o.numR.vf = Math.floor(o.numA.vf * q - o.numB.vf * q + 0.5) / q;\n }\n break;\n\n case 'MULT':\n for (i = 0; i < NMAXLOOPS; i++) {\n this.genNum(o.numA, this.opA, this.RES, this.RES);\n ri2 = this.opB.limInf;\n rs2 = this.opB.limSup;\n switch (this.opCond) {\n case 'AGB':\n if (rs2 > o.numA.vf)\n rs2 = Math.floor(o.numA.vf);\n break;\n case 'BGA':\n if (ri2 < o.numA.vf)\n ri2 = Math.floor(o.numA.vf);\n break;\n }\n this.genNum(o.numB, this.opB, ri2, rs2);\n o.numR.vf = o.numA.vf * o.numB.vf;\n if (o.numR.vf >= rlinf && o.numR.vf <= rlsup)\n break;\n }\n o.numR.c = o.numA.c + o.numB.c;\n o.op = 2;\n break;\n\n case 'DIV':\n for (i = 0; i < NMAXLOOPS; i++) {\n this.genNum(o.numA, this.opA, this.RES, this.RES);\n ri2 = this.opB.limInf;\n rs2 = this.opB.limSup;\n switch (this.opCond) {\n case 'AGB':\n if (rs2 > o.numA.vf)\n rs2 = Math.floor(o.numA.vf);\n break;\n case 'BGA':\n if (ri2 < o.numA.vf)\n ri2 = Math.floor(o.numA.vf);\n break;\n }\n this.genNum(o.numB, this.opB, ri2, rs2);\n if (o.numB.vf !== 0 &&\n Math.abs(o.numA.vf) >= Math.abs(o.numB.vf) &&\n (o.numR.vf = o.numA.vf / o.numB.vf) >= rlinf &&\n o.numR.vf <= rlsup)\n break;\n }\n if (o.numB.vf === 0)\n o.numB.vf = 1;\n o.numR.vf = o.numA.vf / o.numB.vf;\n i = o.numA.c - o.numB.c;\n q = Math.pow(10, i);\n o.numA.vf *= q;\n o.numR.vf *= q;\n o.numR.vf = Math.floor(o.numR.vf);\n o.numA.vf = o.numR.vf * o.numB.vf;\n o.numA.vf /= q;\n o.numR.vf /= q;\n o.numR.c = i > 0 ? i : 0;\n o.op = 3;\n break;\n\n default:\n return false;\n }\n return true;\n }\n\n /**\n * Fills the provided ActiveBagContentKit with randomly generated operations\n * @override\n * @param {module:automation/AutoContentProvider.ActiveBagContentKit} kit - The composite object to be filled with data.\n * @returns {boolean} - `true` if all was OK\n */\n process(kit) {\n let nRows = kit.nRows,\n nCols = kit.nCols,\n content = kit.content, //Array of ActiveBagContent\n useIds = kit.useIds,\n i, j, k,\n o, op = [], // Array of Arith.Operation\n tipus = [],\n numTipus, tipX,\n tipInv = this.exp_caxb,\n va = '', vb = '', vc = '', operator = '',\n stra = [], strb = [], strc = [],\n nColsB = nCols, nRowsB = nRows,\n nCells = nRows * nCols,\n ass = null;\n\n if (nRows <= 0 || nCols <= 0 ||\n content === null || content.length < 1 || content[0] === null)\n return false;\n\n if (nCells < 2)\n return false;\n\n numTipus = 0;\n if (this.exp_abx)\n tipus[numTipus++] = 'ABX';\n if (this.exp_axc)\n tipus[numTipus++] = 'AXC';\n if (this.exp_xbc)\n tipus[numTipus++] = 'XBC';\n if (this.exp_axbc)\n tipus[numTipus++] = 'AXBC';\n if (numTipus === 0)\n return false;\n\n for (i = 0; i < nCells; i++) {\n o = new Arith.Operation();\n for (j = 0; j < NMAXLOOPS; j++) {\n this.genOp(o);\n if (this.resultNoDup) {\n for (k = 0; k < i; k++) {\n if (o.numR.vf === op[k].numR.vf)\n break;\n }\n if (k === i)\n break;\n } else\n break;\n }\n op[i] = o;\n }\n\n if (this.resultOrder !== 0) {\n for (i = nCells - 1; i > 0; i--) {\n for (j = 0; j < i; j++) {\n if (this.resultOrder === 'SORTASC' && op[j].numR.vf > op[j + 1].numR.vf ||\n this.resultOrder === 'SORTDESC' && op[j].numR.vf < op[j + 1].numR.vf) {\n // Switch values\n o = op[j];\n op[j] = op[j + 1];\n op[j + 1] = o;\n }\n }\n }\n }\n\n for (i = 0; i < nCells; i++) {\n tipX = tipus[Math.floor(Math.random() * numTipus)];\n va = Arith.DecFormat(op[i].numA.vf, op[0].numA.c);\n vb = Arith.DecFormat(op[i].numB.vf, op[0].numB.c);\n vc = Arith.DecFormat(op[i].numR.vf, op[0].numR.c);\n operator = OPSTR[op[i].op];\n\n // Use the special blank space ASCII 160 (\\xA0) instead of regular blank spaces\n\n if (tipInv)\n strc[i] = `${vc}\\xA0=\\xA0${va}\\xA0${operator}\\xA0${vb}`;\n else\n strc[i] = `${va}\\xA0${operator}\\xA0${vb}\\xA0=\\xA0${vc}`;\n\n switch (tipX) {\n case 'AXC':\n strb[i] = vb;\n stra[i] = tipInv ? `${vc}\\xA0=\\xA0${va}\\xA0${operator}\\xA0?` : `${va}\\xA0${operator}\\xA0?\\xA0=\\xA0${vc}`;\n break;\n\n case 'XBC':\n strb[i] = va;\n stra[i] = tipInv ? `${vc}\\xA0=\\xA0?\\xA0${operator}\\xA0${vb}` : `?\\xA0${operator}\\xA0${vb}\\xA0=\\xA0${vc}`;\n break;\n\n case 'AXBC':\n strb[i] = operator;\n stra[i] = tipInv ? `${vc}\\xA0=\\xA0${va}\\xA0?\\xA0${vb}` : `${va}\\xA0?\\xA0${vb}\\xA0=\\xA0${vc}`;\n break;\n\n default:\n strb[i] = vc;\n stra[i] = tipInv ? `?\\xA0=\\xA0${va}\\xA0${operator}\\xA0${vb}` : `${va}\\xA0${operator}\\xA0${vb}\\xA0=`;\n break;\n }\n }\n\n if (useIds) {\n ass = [];\n let strbx = [];\n k = 0;\n for (i = 0; i < nCells; i++) {\n for (j = 0; j < k; j++)\n if (strb[i] === strbx[j])\n break;\n if (j === k) {\n strbx[k] = strb[i];\n ass[i] = k;\n k++;\n } else\n ass[i] = j;\n }\n\n strb = [];\n for (i = 0; i < k; i++)\n strb[i] = strbx[i];\n\n if (nRowsB * nColsB !== k) {\n let distH = false;\n switch (k) {\n case 6:\n nRowsB = distH ? 2 : 3;\n nColsB = distH ? 3 : 2;\n break;\n\n case 8:\n nRowsB = distH ? 2 : 4;\n nColsB = distH ? 4 : 2;\n break;\n\n case 9:\n nRowsB = 3;\n nColsB = 3;\n break;\n\n case 10:\n nRowsB = distH ? 2 : 5;\n nColsB = distH ? 5 : 2;\n break;\n\n case 12:\n nRowsB = distH ? 3 : 4;\n nColsB = distH ? 4 : 3;\n break;\n\n case 14:\n nRowsB = distH ? 2 : 7;\n nColsB = distH ? 7 : 2;\n break;\n\n case 15:\n nRowsB = distH ? 3 : 5;\n nColsB = distH ? 3 : 5;\n break;\n\n case 16:\n nRowsB = 4;\n nColsB = 4;\n break;\n\n case 18:\n nRowsB = distH ? 6 : 3;\n nColsB = distH ? 3 : 6;\n break;\n\n case 20:\n nRowsB = distH ? 4 : 5;\n nColsB = distH ? 5 : 4;\n break;\n\n default:\n nRowsB = distH ? 1 : k;\n nColsB = distH ? k : 1;\n break;\n }\n }\n }\n\n // Added 2019/02/11\n // Use comma instead of dot for decimal separator, accordingly to current locale\n if (DOTASCOMMA) {\n function replaceDot(s) { return s.replace(/\\./g, ','); }\n stra = stra.map(replaceDot);\n strb = strb.map(replaceDot);\n strc = strc.map(replaceDot);\n }\n\n content[0].setTextContent(stra, nCols, nRows);\n if (ass !== null)\n content[0].setIds(ass);\n if (content.length > 1 && content[1] !== null) {\n content[1].setTextContent(strb, nColsB, nRowsB);\n content[1].getShaper().reset(nColsB, nRowsB);\n }\n if (content.length > 2 && content[2] !== null)\n content[2].setTextContent(strc, nCols, nRows);\n\n return true;\n }\n}\n\nObject.assign(Arith.prototype, {\n //\n // Operations use two operators:\n /**\n * First operator\n * @name module:automation/arith/Arith.Arith#opA\n * @type {module:automation/arith/Arith.Operator} */\n opA: null,\n /**\n * Second operator\n * @name module:automation/arith/Arith.Arith#opB\n * @type {module:automation/arith/Arith.Operator} */\n opB: null,\n /**\n * Allow additions\n * @name module:automation/arith/Arith.Arith#use_add\n * @type {boolean} */\n use_add: true,\n /**\n * Allow subtractions\n * @name module:automation/arith/Arith.Arith#use_subst\n * @type {boolean} */\n use_subst: false,\n /**\n * Allow multiplications\n * @name module:automation/arith/Arith.Arith#use_mult\n * @type {boolean} */\n use_mult: false,\n /**\n * Allow divides\n * @name module:automation/arith/Arith.Arith#use_div\n * @type {boolean} */\n use_div: false,\n /**\n * Allow expressions of type `A op B = X`\n * @name module:automation/arith/Arith.Arith#exp_abx\n * @type {boolean} */\n exp_abx: true,\n /**\n * Allow expressions of type `A op X = C`\n * @name module:automation/arith/Arith.Arith#exp_axc\n * @type {boolean} */\n exp_axc: false,\n /**\n * Allow expressions of type `X op B = C`\n * @name module:automation/arith/Arith.Arith#exp_xbc\n * @type {boolean} */\n exp_xbc: false,\n /**\n * Allow expressions of type `A x B = C`\n * @name module:automation/arith/Arith.Arith#exp_axbc\n * @type {boolean} */\n exp_axbc: false,\n /**\n * Allow inverse expressions, like `C = A op B`\n * @name module:automation/arith/Arith.Arith#exp_caxb\n * @type {boolean} */\n exp_caxb: false,\n /**\n * Lower limit of the result\n * @name module:automation/arith/Arith.Arith#resultLimInf\n * @type {number} */\n resultLimInf: 0,\n /**\n * Upper limit of the result\n * @name module:automation/arith/Arith.Arith#resultLimSup\n * @type {number} */\n resultLimSup: 9999,\n /**\n * Allow carry operations\n * @see {@link https://en.wikipedia.org/wiki/Carry_(arithmetic)}\n * @name module:automation/arith/Arith.Arith#resultCarry\n * @type {boolean} */\n resultCarry: false,\n /**\n * Avoid operations with the same result\n * @name module:automation/arith/Arith.Arith#resultNoDup\n * @type {boolean} */\n resultNoDup: false,\n /**\n * Type of sorting of results. Possible values are: 'NOSORT', 'SORTASC' and 'SORTDESC'\n * @name module:automation/arith/Arith.Arith#resultOrder\n * @type {string} */\n resultOrder: 'NOSORT',\n /**\n * Sorting of the operands in commutative operations. Possible values are: 'AGB' (_A greater than B_),\n * 'BGA' (_B greater tan A_) and 'INDIF' (default)\n * @name module:automation/arith/Arith.Arith#opCond\n * @type {string} */\n opCond: 'INDIF',\n});\n\n/**\n * Operator is an Utility class used by Arith to encapsulate the properties and methods related\n * to the members of the operations.\n */\nArith.Operator = class {\n constructor() {\n }\n\n /**\n * Loads Operator settings from a specific JQuery XML element\n * @param {external:jQuery} $xml - The XML element to parse\n */\n setProperties($xml) {\n // Read attributes\n attrForEach($xml.get(0).attributes, (name, val) => {\n switch (name) {\n case 'decimals':\n this.numDec = Number(val);\n break;\n\n case 'values':\n this.lst = val.split(' ').map(v => Number(v));\n this.fromList = this.lst.length;\n break;\n\n case 'from':\n this.limInf = Number(val === 'x' ? 0 : val);\n break;\n\n case 'to':\n this.limSup = Number(val === 'x' ? 0 : val);\n break;\n }\n\n $xml.children().each((_n, child) => {\n const $node = $(child);\n switch (child.nodeName) {\n case 'include':\n this.wZero = getBoolean($node.attr('zero'));\n this.wOne = getBoolean($node.attr('one'));\n this.wMinusOne = getBoolean($node.attr('minusOne'));\n break;\n }\n });\n });\n return this;\n }\n\n /**\n * Gets a object with the basic attributes needed to rebuild this instance excluding functions,\n * parent references, constants and also attributes retaining the default value.\n * The resulting object is commonly usued to serialize elements in JSON format.\n * @returns {object} - The resulting object, with minimal attrributes\n */\n getAttributes() {\n return getAttr(this, [\n 'limInf', 'limSup',\n 'numDec|0',\n 'wZero|false', 'wOne|false', 'wMinusOne|false',\n 'fromList|0', 'lst',\n ]);\n }\n\n /**\n * Reads the properties of this operator from a dataset\n * @param {object} data - The data object to be parsed\n * @returns {module:automation/arith/Arith.Arith}\n */\n setAttributes(data) {\n return setAttr(this, data, [\n 'limInf', 'limSup',\n 'numDec',\n 'wZero', 'wOne', 'wMinusOne',\n 'fromList', 'lst',\n ]);\n }\n};\n\nObject.assign(Arith.Operator.prototype, {\n /**\n * Lower limit\n * @name module:automation/arith/Arith.Arith.Operator#limInf\n * @type {number} */\n limInf: 0,\n /**\n * Upper limit\n * @name module:automation/arith/Arith.Arith.Operator#limSup\n * @type {number} */\n limSup: 10,\n /**\n * Number of decimal places\n * @name module:automation/arith/Arith.Arith.Operator#numDec\n * @type {number} */\n numDec: 0,\n /**\n * Including 0\n * @name module:automation/arith/Arith.Arith.Operator#wZero\n * @type {boolean} */\n wZero: false,\n /**\n * Including 1\n * @name module:automation/arith/Arith.Arith.Operator#wOne\n * @type {boolean} */\n wOne: false,\n /**\n * Including -1\n * @name module:automation/arith/Arith.Arith.Operator#wMinusOne\n * @type {boolean} */\n wMinusOne: false,\n /**\n * Take values from list. This member stores the list length.\n * @name module:automation/arith/Arith.Arith.Operator#fromList\n * @type {number} */\n fromList: 0,\n /**\n * The list of possible values\n * @name module:automation/arith/Arith.Arith.Operator#lst\n * @type {number[]} */\n lst: [],\n});\n\nArith.Num = class {\n constructor() {\n this.vf = 0.0; // The number value\n this.c = 0; // Number of decimals to be used when representing the number\n }\n\n format() {\n return Arith.DecFormat(this.vf, this.c);\n }\n};\n\nArith.Operation = class {\n constructor() {\n this.numA = new Arith.Num();\n this.numB = new Arith.Num();\n this.numR = new Arith.Num();\n this.op = 0;\n }\n};\n\n// Register class in AutoContentProvider.CLASSES\nexport default AutoContentProvider.registerClass('@arith.Arith', Arith);\n","/**\n * File : report/SessionStorageReporter.js\n * Created : 06/09/2017\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\n/* global window */\n\nimport Reporter from './Reporter.js';\n\n/**\n * This JClic {@link module:Reporter.Reporter Reporter} writes persistent data to the browser local session storage. It uses some of\n * the {@link https://github.com/projectestac/jclic/wiki/JClic-Reports-developers-guide JClic Reports API}.\n * Connection parameters (`key`, `context`...) are passed through the `options` element of {@link module:JClicPlayer.JClicPlayer JClicPlayer} (acting as {@link module:JClicPlayer.JClicPlayer JClicPlayer}).\n * Set `storage=local` in `options` to store reports in [`window.localStorage`]{@link https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage}\n * instead of [`window.sessionStorage`]{@link https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage} (default).\n * @extends module:reports/Reporter.Reporter\n */\nexport class SessionStorageReporter extends Reporter {\n /**\n * SessionStorageReporter constructor\n * @param {module:JClicPlayer.JClicPlayer} ps - The {@link module:JClicPlayer.JClicPlayer JClicPlayer} used to retrieve settings and localized messages\n */\n constructor(ps) {\n super(ps);\n this.key = `jclic_${(new Date()).toISOString()}#${Math.ceil(Math.random() * 1000)}`;\n }\n\n /**\n * Initializes this report system with an optional set of parameters.\n * Returns a Promise, fulfilled when the reporter is fully initialized.\n * @override\n * @param {object} [options] - Initial settings passed to the reporting system\n * @returns {external:Promise}\n */\n init(options) {\n if (typeof options === 'undefined' || options === null)\n options = this.ps.options;\n if (options.storage === 'local') {\n this.storage = window.localStorage;\n this.descriptionKey = 'Reporting to local storage';\n }\n return Reporter.prototype.init.call(this, options);\n }\n\n /**\n *\n * Saves the current report data to sessionStorage\n */\n saveCurrentReport() {\n // Update results out of current thread\n window.setTimeout(() => {\n this.storage.setItem(this.key, JSON.stringify(this.getData()));\n }, 0);\n }\n\n /**\n * Finalizes the current sequence\n * @override\n */\n endSequence() {\n super.endSequence();\n this.saveCurrentReport();\n }\n\n /**\n * This method should be called when the current activity finishes. Data about user's final results\n * on the activity will then be saved.\n * @override\n * @param {number} score - The final score, usually in a 0-100 scale.\n * @param {number} numActions - The total number of actions done by the user to solve the activity\n * @param {boolean} solved - `true` if the activity was finally solved, `false` otherwise.\n */\n endActivity(score, numActions, solved) {\n super.endActivity(score, numActions, solved);\n this.saveCurrentReport();\n }\n}\n\nObject.assign(SessionStorageReporter.prototype, {\n /**\n * Type of storage to be used. Defaults to `window.sessionStorage`\n * @name module:report/SessionStorageReporter.SessionStorageReporter#storage\n * @type {external:Storage} */\n storage: window.sessionStorage,\n /**\n * Description of this reporting system\n * @name module:report/SessionStorageReporter.SessionStorageReporter#descriptionKey\n * @override\n * @type {string} */\n descriptionKey: 'Reporting to session storage',\n /**\n * Additional info to display after the reporter's `description`\n * @name module:report/SessionStorageReporter.SessionStorageReporter#descriptionDetail\n * @override\n * @type {string} */\n descriptionDetail: '(browser session)',\n /**\n * Key used to save the report into sessionStorage\n * @name module:report/SessionStorageReporter.SessionStorageReporter#key\n * @type {string} */\n key: null,\n});\n\n// Register class in Reporter.CLASSES\nexport default Reporter.registerClass('SessionStorageReporter', SessionStorageReporter);\n","/**\n * File : report/TCPReporter.js\n * Created : 08/06/2016\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Catalan Educational Telematic Network (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\n/* global Promise, document, window, XMLSerializer */\n\nimport $ from 'jquery';\nimport Reporter from './Reporter.js';\nimport { log, startsWith, getMsg } from '../Utils.js';\n\n/**\n * This special case of {@link module:Reporter.Reporter Reporter} connects with an external service reporter providing\n * the {@link https://github.com/projectestac/jclic/wiki/JClic-Reports-developers-guide JClic Reports API}.\n * Connection parameters to the reports server (`path`, `service`, `userId`, `key`, `context`...)\n * are passed through the `options` element of {@link module:JClicPlayer.JClicPlayer JClicPlayer} (acting as {@link module:JClicPlayer.JClicPlayer JClicPlayer}).\n * @extends module:reports/Reporter.Reporter\n */\nexport class TCPReporter extends Reporter {\n /**\n * TCPReporter constructor\n * @param {module:JClicPlayer.JClicPlayer} ps - The {@link module:JClicPlayer.JClicPlayer JClicPlayer} used to retrieve settings and localized messages\n */\n constructor(ps) {\n super(ps);\n this.tasks = [];\n }\n\n /**\n * Gets a specific property from this reporting system\n * @override\n * @param {string} key - Requested property\n * @param {string}+ defaultValue - Default return value when requested property does not exist\n * @returns {string}\n */\n getProperty(key, defaultValue) {\n return this.dbProperties !== null && this.dbProperties.hasOwnProperty(key) ?\n this.dbProperties[key] :\n defaultValue;\n }\n\n /**\n * Adds a new element to the list of report beans pending to be transmitted.\n * @param {module:report/TCPReporter.ReportBean} bean\n */\n addTask(bean) {\n if (this.processingTasks) {\n if (this.waitingTasks === null)\n this.waitingTasks = [bean];\n else\n this.waitingTasks.push(bean);\n } else\n this.tasks.push(bean);\n }\n\n /**\n * Transmits all report beans currently stored in `tasks` to the reports server\n * @returns {external:Promise}\n */\n flushTasksPromise() {\n if (this.processingTasks || this.currentSessionId === null ||\n this.tasks.length === 0 || this.serviceUrl === null) {\n // The task list cannot be processed now. Pass and wait until the next timer cycle:\n if (this.processingTasks)\n this.forceFlush = true;\n return Promise.resolve(true);\n }\n else {\n // Set up the `processingTasks` flag to avoid re-entrant processing\n this.processingTasks = true;\n\n const reportBean = new ReportBean('multiple');\n for (let i = 0; i < this.tasks.length; i++)\n reportBean.appendData(this.tasks[i].$bean);\n\n log('debug', 'Reporting:', reportBean.$bean[0]);\n\n return new Promise((resolve, reject) => {\n this.transaction(reportBean.$bean)\n .done((_data, _textStatus, _jqXHR) => {\n // TODO: Check returned message for possible errors on the server side\n this.failCount = 0;\n\n // Clear waiting tasks\n if (this.waitingTasks) {\n this.tasks = this.waitingTasks;\n this.waitingTasks = null;\n }\n else {\n this.forceFlush = false;\n this.tasks = [];\n }\n\n if (this.forceFlush && this.tasks.length > 0) {\n this.forceFlush = false;\n this.processingTasks = false;\n this.flushTasksPromise().then(() => {\n resolve(true);\n });\n }\n else {\n this.forceFlush = false;\n resolve(true);\n this.processingTasks = false;\n }\n })\n .fail((jqXHR, textStatus, errorThrown) => {\n if (++this.failCount > this.maxFails)\n this.stopReporting().then();\n reject(`Error reporting results to ${this.serviceUrl} [${textStatus} ${errorThrown}]`);\n this.processingTasks = false;\n });\n });\n }\n }\n\n /**\n * Initializes this report system with an optional set of parameters.\n * Returns a Promise, fulfilled when the reporter is fully initialized.\n * @override\n * @param {object} [options] - Initial settings passed to the reporting system\n * @returns {external:Promise}\n */\n init(options) {\n if (typeof options === 'undefined' || options === null)\n options = this.ps.options;\n super.init(options);\n this.initiated = false;\n this.stopReporting();\n\n this.serverPath = options.path || this.DEFAULT_SERVER_PATH;\n this.descriptionDetail = this.serverPath;\n let serverService = options.service || this.DEFAULT_SERVER_SERVICE;\n if (!startsWith(serverService, '/'))\n serverService = `/${serverService}`;\n const serverProtocol = options.protocol || this.DEFAULT_SERVER_PROTOCOL;\n this.serviceUrl = `${serverProtocol}://${this.serverPath}${serverService}`;\n\n const bean = new ReportBean('get_properties');\n return new Promise((resolve, reject) => {\n this.transaction(bean.$bean)\n .done((data, _textStatus, _jqXHR) => {\n this.dbProperties = {};\n $(data).find('param').each((_n, param) => {\n const $param = $(param);\n this.dbProperties[$param.attr('name')] = $param.attr('value');\n });\n this.promptUserId(false).then(userId => {\n this.userId = userId;\n const tl = options.lap || this.getProperty('TIME_LAP', this.DEFAULT_TIMER_LAP);\n this.timerLap = Math.min(30, Math.max(1, parseInt(tl)));\n this.timer = window.setInterval(() => this.flushTasksPromise().then(), this.timerLap * 1000);\n // Warn before leaving the current page with unsaved data:\n this.beforeUnloadFunction = event => {\n if (this.serviceUrl !== null &&\n (this.tasks.length > 0 || this.processingTasks)) {\n this.flushTasksPromise().then();\n const result = getMsg('Please wait until the results of your activities are sent to the reports system');\n if (event)\n event.returnValue = result;\n return result;\n }\n };\n window.addEventListener('beforeunload', this.beforeUnloadFunction);\n this.initiated = true;\n resolve(true);\n }).catch(msg => {\n this.stopReporting();\n reject(`Error getting the user ID: ${msg}`);\n });\n })\n .fail((jqXHR, textStatus, errorThrown) => {\n this.stopReporting();\n reject(`Error initializing reports service ${this.serviceUrl} [${textStatus} ${errorThrown}]`);\n });\n });\n }\n\n /**\n * This method should be invoked when a new session starts.\n * @override\n * @param {module:project/JClicProject.JClicProject} jcp - The {@link module:project/JClicProject.JClicProject JClicProject} this session refers to.\n */\n newSession(jcp) {\n super.newSession(jcp);\n if (this.serviceUrl && this.userId !== null) {\n // Session ID will be obtained when reporting first activity\n this.currentSessionId = null;\n }\n }\n\n /**\n * Creates a new session in the remote database and records its ID for future use\n * @param {boolean} forceNewSession - When `true`, a new session will always be created.\n * @returns {external:Promise} - A Promise reporter will be successfully resolved\n * only when `currentSessionId` have a valid value.\n */\n createDBSession(forceNewSession) {\n if (this.currentSessionId !== null && !forceNewSession)\n // A valid session is available, so just return it\n return Promise.resolve(this.currentSessionId);\n else\n // A new session must be created:\n return new Promise((resolve, reject) => {\n if (this.initiated && this.userId !== null && this.currentSession !== null) {\n this.flushTasksPromise().then(() => {\n this.currentSessionId = null;\n const bean = new ReportBean('add session');\n\n bean.setParam('project', this.currentSession.projectName);\n bean.setParam('activities', Number(this.currentSession.reportableActs));\n bean.setParam('time', Number(this.currentSession.started));\n bean.setParam('code', this.currentSession.code);\n bean.setParam('user', this.userId);\n bean.setParam('key', this.sessionKey);\n bean.setParam('context', this.sessionContext);\n\n this.transaction(bean.$bean)\n .done((data, _textStatus, _jqXHR) => {\n this.currentSessionId = $(data).find('param[name=\"session\"]').attr('value');\n resolve(this.currentSessionId);\n })\n .fail((jqXHR, textStatus, errorThrown) => {\n this.stopReporting();\n reject(`Error creating new reports session in ${this.serviceUrl} [${textStatus} ${errorThrown}]`);\n });\n });\n } else\n reject('Unable to start session in remote server!');\n });\n }\n\n /**\n * Closes this reporting system\n * @override\n * @returns {external:Promise} - A promise to be fullfilled when all pending tasks are finished, or _null_ if not active.\n */\n end() {\n this.reportActivity(true);\n return this.stopReporting().then(super.end());\n }\n\n /**\n * Performs a transaction on the remote server\n * @param {external:jQuery} $xml - The XML element to be transmited, wrapped into a jQuery object\n * @returns {external:jqXHR} - The {@link external:jqXHR} obtained as a result of a call to `$.ajax`.\n * This object should be treated as a Promise or\n * as a JQuery {@link https://api.jquery.com/category/deferred-object|Deferred} object.\n */\n transaction($xml) {\n return this.serviceUrl === null ?\n null :\n $.ajax({\n method: 'POST',\n url: this.serviceUrl,\n data: '<?xml version=\"1.0\" encoding=\"UTF-8\"?>' +\n (new XMLSerializer()).serializeToString($xml.get(0)).replace('minactions', 'minActions').replace('reportactions', 'reportActions'),\n contentType: 'text/xml',\n dataType: 'xml'\n });\n }\n\n /**\n * Gets the list of current groups or organizations registered on this reporting system.\n * @override\n * @returns {external:Promise} - When fulfilled, an array of group data is returned as a result\n */\n getGroups() {\n return new Promise((resolve, reject) => {\n if (!this.userBased())\n reject('This system does not manage users!');\n else {\n const bean = new ReportBean('get groups');\n this.transaction(bean.$bean)\n .done((data, _textStatus, _jqXHR) => {\n const currentGroups = [];\n $(data).find('group').each((_n, gr) => {\n const $group = $(gr);\n currentGroups.push({ id: $group.attr('id'), name: $group.attr('name') });\n });\n resolve(currentGroups);\n })\n .fail((jqXHR, textStatus, errorThrown) => {\n reject(`Error retrieving groups list from ${this.serviceUrl} [${textStatus} ${errorThrown}]`);\n });\n }\n });\n }\n\n /**\n * Gets the list of users currently registered in the system, optionally filtered by\n * a specific group ID.\n * @override\n * @param {string}+ groupId - Optional group ID to be used as a filter criteria\n * @returns {external:Promise} - When fulfilled, an object with a collection of user data records\n * is returned\n */\n getUsers(groupId) {\n return new Promise((resolve, reject) => {\n if (!this.userBased())\n reject('This system does not manage users!');\n else {\n const bean = new ReportBean('get users');\n if (typeof groupId !== 'undefined' && groupId !== null)\n bean.setParam('group', groupId);\n this.transaction(bean.$bean)\n .done((data, _textStatus, _jqXHR) => {\n const currentUsers = [];\n $(data).find('user').each((_n, usr) => {\n const $user = $(usr);\n const user = { id: $user.attr('id'), name: $user.attr('name') };\n if ($user.attr('pwd'))\n user.pwd = $user.attr('pwd');\n currentUsers.push(user);\n });\n resolve(currentUsers);\n })\n .fail((jqXHR, textStatus, errorThrown) => {\n reject(`Error retrieving users list from ${this.serviceUrl} [${textStatus} ${errorThrown}]`);\n });\n }\n });\n }\n\n /**\n * Gets extended data associated with a specific user.\n * @param {string} userId - The requested user ID\n * @returns {external:Promise} - When fulfilled, an object with user data is returned.\n */\n getUserData(userId) {\n return new Promise((resolve, reject) => {\n if (!this.userBased())\n reject('This system does not manage users!');\n else {\n const bean = new ReportBean('get user data');\n\n if (typeof userId !== 'undefined' && userId !== null)\n bean.setParam('user', userId);\n else\n reject('Invalid user ID');\n\n this.transaction(bean.$bean)\n .done((data, _textStatus, _jqXHR) => {\n const $user = $(data).find('user');\n if ($user.length !== 1) {\n window.alert(getMsg('Invalid user'));\n resolve('Invalid user ID');\n } else {\n const user = { id: $user.attr('id'), name: $user.attr('name') };\n if ($user.attr('pwd'))\n user.pwd = $user.attr('pwd');\n resolve(user);\n }\n })\n .fail((jqXHR, textStatus, errorThrown) => {\n reject(`Error retrieving user data from ${this.serviceUrl} [${textStatus} ${errorThrown}]`);\n });\n }\n });\n }\n\n /**\n * Stops the reporting system, usually as a result of repeated errors or because the player\n * shuts down.\n * @returns {external:Promise} - A promise to be fullfilled when all pending tasks are finished.\n */\n stopReporting() {\n let result = null;\n if (this.timer >= 0) {\n window.clearInterval(this.timer);\n this.timer = -1;\n }\n if (this.beforeUnloadFunction) {\n window.removeEventListener('beforeunload', this.beforeUnloadFunction);\n this.beforeUnloadFunction = null;\n }\n if (this.initiated) {\n result = this.flushTasksPromise().then(() => {\n this.serviceUrl = null;\n this.descriptionDetail = `${this.serverPath} (${getMsg('not connected')})`;\n this.initiated = false;\n });\n }\n return result || Promise.resolve(true);\n }\n\n /**\n * Prepares a {@link module:report/TCPReporter.ReportBean ReportBean} object with information related to the current\n * activity, and pushes it into the list of pending `tasks`, to be processed by the main `timer`.\n * @param {boolean} flushNow - When `true`, the activity data will be sent to server as soon as possible\n */\n reportActivity(flushNow) {\n if (this.lastActivity) {\n if (!this.lastActivity.closed)\n this.lastActivity.closeActivity();\n const\n actCount = this.actCount++,\n act = this.lastActivity;\n this.createDBSession(false).then(() => {\n const bean = new ReportBean('add activity');\n bean.setParam('session', this.currentSessionId);\n bean.setParam('num', actCount);\n bean.appendData(act.$getXML());\n this.addTask(bean);\n if (flushNow)\n this.flushTasksPromise().then();\n });\n }\n if (this.currentSession !== null &&\n this.currentSession.currentSequence !== null &&\n this.currentSession.currentSequence.currentActivity !== this.lastActivity) {\n this.lastActivity = this.currentSession.currentSequence.currentActivity;\n } else\n this.lastActivity = null;\n }\n\n /**\n * This method should be invoked when the user starts a new activity\n * @override\n * @param {module:Activity.Activity} act - The {@link module:Activity.Activity Activity} reporter has just started\n */\n newActivity(act) {\n super.newActivity(act);\n this.reportActivity(false);\n }\n\n /**\n * This method should be called when the current activity finishes. Data about user's final results\n * on the activity will then be saved.\n * @override\n * @param {number} score - The final score, usually in a 0-100 scale.\n * @param {number} numActions - The total number of actions done by the user to solve the activity\n * @param {boolean} solved - `true` if the activity was finally solved, `false` otherwise.\n */\n endActivity(score, numActions, solved) {\n super.endActivity(score, numActions, solved);\n this.reportActivity(true);\n }\n}\n\nObject.assign(TCPReporter.prototype, {\n /**\n * Description of this reporting system\n * @name module:report/TCPReporter.TCPReporter#descriptionKey\n * @override\n * @type {string} */\n descriptionKey: 'Reporting to remote server',\n /**\n * Additional info to display after the reporter's `description`\n * @name module:report/TCPReporter.TCPReporter#descriptionDetail\n * @override\n * @type {string} */\n descriptionDetail: '(not connected)',\n /**\n * Main path of the reports server (without protocol nor service)\n * @name module:report/TCPReporter.TCPReporter#serverPath\n * @type {string} */\n serverPath: '',\n /**\n * Function to be called by the browser before leaving the current page\n * @name module:report/TCPReporter.TCPReporter#beforeUnloadFunction\n * @type {function} */\n beforeUnloadFunction: null,\n /**\n * Identifier of the current session, provided by the server\n * @name module:report/TCPReporter.TCPReporter#currentSessionId\n * @type {string} */\n currentSessionId: '',\n /**\n * Last activity reported\n * @name module:report/TCPReporter.TCPReporter#lastActivity\n * @type {module:report/ActivityReg.ActivityReg} */\n lastActivity: null,\n /**\n * Number of activities processed\n * @name module:report/TCPReporter.TCPReporter#actCount\n * @type {number} */\n actCount: 0,\n /**\n * Service URL of the JClic Reports server\n * @name module:report/TCPReporter.TCPReporter#serviceUrl\n * @type {string} */\n serviceUrl: null,\n /**\n * Object used to store specific properties of the connected reports system\n * @name module:report/TCPReporter.TCPReporter#dbProperties\n * @type {object} */\n dbProperties: null,\n /**\n * List of {@link module:report/TCPReporter.ReportBean ReportBean} objects pending to be processed\n * @name module:report/TCPReporter.TCPReporter#tasks\n * @type {module:report/TCPReporter.ReportBean[]} */\n tasks: null,\n /**\n * Waiting list of tasks, to be used while `tasks` is being processed\n * @name module:report/TCPReporter.TCPReporter#waitingTasks\n * @type {module:report/TCPReporter.ReportBean[]} */\n waitingTasks: null,\n /**\n * Flag used to indicate if `transaction` is currently running\n * @name module:report/TCPReporter.TCPReporter#processingTasks\n * @type {boolean} */\n processingTasks: false,\n /**\n * Force processing of pending tasks as soon as possible\n * @name module:report/TCPReporter.TCPReporter#forceFlush\n * @type {boolean} */\n forceFlush: false,\n /**\n * Identifier of the background function obtained with a call to `window.setInterval`\n * @name module:report/TCPReporter.TCPReporter#timer\n * @type {number} */\n timer: -1,\n /**\n * Time between calls to the background function, in seconds\n * @name module:report/TCPReporter.TCPReporter#timerLap\n * @type {number} */\n timerLap: 5,\n /**\n * Counter of unsuccessful connection attempts with the report server\n * @name module:report/TCPReporter.TCPReporter#failCount\n * @type {number} */\n failCount: 0,\n /**\n * Maximum number of failed attempts allowed before disconnecting\n * @name module:report/TCPReporter.TCPReporter#maxFails\n * @type {number} */\n maxFails: 5,\n /**\n * Default path of JClic Reports Server\n * @name module:report/TCPReporter.TCPReporter#DEFAULT_SERVER_PATH\n * @type {string} */\n DEFAULT_SERVER_PATH: 'localhost:9000',\n /**\n * Default name for the reports service\n * @name module:report/TCPReporter.TCPReporter#DEFAULT_SERVER_SERVICE\n * @type {string} */\n DEFAULT_SERVER_SERVICE: '/JClicReportService',\n /**\n * Default server protocol\n * Use always 'https' except when in 'http' and protocol not set in options\n * @name module:report/TCPReporter.TCPReporter#DEFAULT_SERVER_PROTOCOL\n * @type {string} */\n DEFAULT_SERVER_PROTOCOL: (document && document.location && document.location.protocol === 'http:') ? 'http' : 'https',\n /**\n * Default lap between calls to `flushTasks`, in seconds\n * @name module:report/TCPReporter.TCPReporter#DEFAULT_TIMER_LAP\n * @type {number} */\n DEFAULT_TIMER_LAP: 20,\n});\n\n/**\n * This inner class encapsulates a chunk of information in XML format, ready to be\n * transmitted to the remote reports server.\n */\nexport class ReportBean {\n /**\n * ReportBean constructor\n * @param id {string} - The main identifier of this ReportBean. Current valid values are:\n * `get property`, `get_properties`, `add session`, `add activity`, `get groups`, `get users`,\n * `get user data`, `get group data`, `new group`, `new user` and `multiple`.\n * @param $data {external:jQuery}+ - Optional XML data to be added to this bean\n */\n constructor(id, $data) {\n this.$bean = $('<bean/>').attr({ id: id });\n if ($data)\n this.appendData($data);\n }\n\n /**\n * Adds an XML element to the bean\n * @param {external:jQuery} $data - The XML element to be added to this bean\n */\n appendData($data) {\n if ($data) {\n this.$bean.append($data);\n }\n }\n\n /**\n * Adds an XML element of type `param` to this ReportBean\n * @param {string} name - The key name of the parameter\n * @param {string|number|boolean} value - The value of the parameter\n */\n setParam(name, value) {\n if (typeof value !== 'undefined' && value !== null)\n this.appendData($('<param/>').attr({ name: name, value: value }));\n }\n}\n\nObject.assign(ReportBean.prototype, {\n /**\n * The main jQuery XML object managed by this ReportBean\n * @name module:report/TCPReporter.ReportBean#$bean\n * @type {external:jQuery} */\n $bean: null,\n});\n\nTCPReporter.ReportBean = ReportBean;\n\n// Register class in Reporter.CLASSES\nexport default Reporter.registerClass('TCPReporter', TCPReporter);\n","/**\n * File : shapers/JigSaw.js\n * Created : 01/04/2015\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\nimport Shaper from './Shaper.js';\nimport { Path, PathStroke } from '../AWT.js';\n\n/**\n *\n * This {@link module:shapers/Shaper.Shaper Shaper} returns a set of rectangular shapes with teeth and slots that fit between them.\n * @extends module:shapers/Shaper.Shaper\n */\nexport class JigSaw extends Shaper {\n /**\n * JigSaw constructor\n * @param {number} nx - Number of columns\n * @param {number} ny - Number of rows\n */\n constructor(nx, ny) {\n super(nx, ny);\n }\n\n /**\n * Builds the jigsaw shapes based on the number of rows and columns\n * @override\n */\n buildShapes() {\n // Create two two-dimension arrays for storing the type of horizontal and vertical lines\n let hLineType = [], vLineType = [];\n for (let i = 0; i <= this.nRows; i++) {\n hLineType[i] = [];\n vLineType[i] = [];\n }\n\n for (let row = 0; row < this.nRows; row++) {\n for (let col = 0; col < this.nCols; col++) {\n hLineType[row][col] = row === 0 ? 0 : 1 + (this.randomLines ? Math.round(Math.random() * 9) : row + col) % 2;\n vLineType[row][col] = col === 0 ? 0 : 1 + (this.randomLines ? Math.round(Math.random() * 9) : col + row + 1) % 2;\n if (col === this.nCols - 1)\n vLineType[row][col + 1] = 0;\n if (row === this.nRows - 1)\n hLineType[row + 1][col] = 0;\n }\n }\n\n const w = 1 / this.nCols, h = 1 / this.nRows;\n for (let r = 0; r < this.nRows; r++) {\n for (let c = 0; c < this.nCols; c++) {\n const x = w * c;\n const y = h * r;\n const sd = new Path([new PathStroke('M', [x, y])]);\n this.hLine(sd, hLineType[r][c], x + 0, y + 0, w, h, false);\n this.vLine(sd, vLineType[r][c + 1], x + w, y + 0, w, h, false);\n this.hLine(sd, hLineType[r + 1][c], x + w, y + h, w, h, true);\n this.vLine(sd, vLineType[r][c], x + 0, y + h, w, h, true);\n sd.addStroke(new PathStroke('X'));\n sd.calcEnclosingRect();\n // Save the Path in `shapeData`\n this.shapeData[r * this.nCols + c] = sd;\n }\n }\n this.initiated = true;\n }\n\n /**\n * Adds an horizontal line to the provided path\n * @param {module:AWT.Path} sd - The Path to which the line will be added\n * @param {number} type - Type of tooth: 0 is flat (no tooth), 1 means tooth up, and 2 means tooth down\n * @param {number} x - X coordinate of the starting point\n * @param {number} y - Y coordinate of the starting point\n * @param {number} w - Width of the piece\n * @param {number} h - Height of the piece\n * @param {boolean} inv - The line must be drawn right to left\n */\n hLine(sd, type, x, y, w, h, inv) {\n const\n kx = inv ? -1 : 1,\n ky = type === 1 ? 1 : -1;\n\n if (type === 0)\n // Flat line\n sd.addStroke(new PathStroke('L', [x + w * kx, y]));\n else {\n const x0 = x + (w - w * this.baseWidthFactor) / 2 * kx;\n const wb = w * this.baseWidthFactor * kx;\n // Approximation to the tooth:\n sd.addStroke(new PathStroke('L', [x0, y]));\n // The tooth:\n const hb = h * this.toothHeightFactor * ky;\n sd.addStroke(new PathStroke('L', [x0, y + hb]));\n sd.addStroke(new PathStroke('L', [x0 + wb, y + hb]));\n sd.addStroke(new PathStroke('L', [x0 + wb, y]));\n // Draw the remaining of the line\n sd.addStroke(new PathStroke('L', [x + w * kx, y]));\n }\n }\n\n /**\n *\n * Adds a vertical line to the provided path\n * @param {module:AWT.Path} sd - The Path to which the line will be added\n * @param {number} type - Type of tooth: 0 is flat (no tooth), 1 means tooth right, and 2 means tooth left\n * @param {number} x - X coordinate of the starting point\n * @param {number} y - Y coordinate of the starting point\n * @param {number} w - Width of the piece\n * @param {number} h - Height of the piece\n * @param {boolean} inv - The line must be drawn bottom to top\n */\n vLine(sd, type, x, y, w, h, inv) {\n const\n ky = inv ? -1 : 1,\n kx = type === 1 ? 1 : -1;\n\n if (type === 0) {\n // Flat line\n sd.addStroke(new PathStroke('L', [x, y + h * ky]));\n } else {\n const y0 = y + (h - h * this.baseWidthFactor) / 2 * ky;\n const hb = h * this.baseWidthFactor * ky;\n // Approximation to the tooth:\n sd.addStroke(new PathStroke('L', [x, y0]));\n // The tooth:\n const wb = w * this.toothHeightFactor * kx;\n sd.addStroke(new PathStroke('L', [x + wb, y0]));\n sd.addStroke(new PathStroke('L', [x + wb, y0 + hb]));\n sd.addStroke(new PathStroke('L', [x, y0 + hb]));\n // Draw the remaining line\n sd.addStroke(new PathStroke('L', [x, y + h * ky]));\n }\n }\n}\n\n// Register this class in the list of known shapers\nexport default Shaper.registerClass('@JigSaw', JigSaw);\n","/**\n * File : shapers/ClassicJigSaw.js\n * Created : 25/05/2015\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\nimport Shaper from './Shaper.js';\nimport JigSaw from './JigSaw.js';\nimport { PathStroke } from '../AWT.js';\n\n/**\n * This is the classic {@link module:shapers/JigSaw.JigSaw JigSaw} {@link module:shapers/Shaper.Shaper Shaper} used in puzzle toys, where teeth and slots\n * are shaped by Bézier curves.\n * @extends module:shapers/JigSaw.JigSaw\n */\nexport class ClassicJigSaw extends JigSaw {\n /**\n * ClassicJigSaw constructor\n * @param {number} nx - Number of columns\n * @param {number} ny - Number of rows\n */\n constructor(nx, ny) {\n super(nx, ny);\n }\n\n /**\n * Overrides {@link module:shapers/JigSaw.JigSaw#hLine}\n * @override\n * @param {module:AWT.Path} sd - The Path to which the line will be added\n * @param {number} type - Type of tooth: 0 is flat (no tooth), 1 means tooth up, and 2 means tooth down\n * @param {number} x - X coordinate of the starting point\n * @param {number} y - Y coordinate of the starting point\n * @param {number} w - Width of the piece\n * @param {number} h - Height of the piece\n * @param {boolean} inv - The line must be drawn right to left\n */\n hLine(sd, type, x, y, w, h, inv) {\n const\n kx = inv ? -1 : 1,\n ky = type === 1 ? 1 : -1;\n\n if (type === 0)\n // Flat line\n sd.addStroke(new PathStroke('L', [x + w * kx, y]));\n else {\n const\n x0 = x + (w - w * this.baseWidthFactor) / 2 * kx,\n wb = w * (this.baseWidthFactor / 12) * kx;\n\n // Approximation to the tooth:\n sd.addStroke(new PathStroke('L', [x0, y]));\n // This is the tooth:\n const hb = h * this.toothHeightFactor * ky / 8;\n sd.addStroke(new PathStroke('B', [x0 + 4 * wb, y, x0 + 6 * wb, y - hb, x0 + 4 * wb, y - 3 * hb]));\n sd.addStroke(new PathStroke('B', [x0 + 2 * wb, y - 5 * hb, x0 + 10 * wb, y - 5 * hb, x0 + 8 * wb, y - 3 * hb]));\n sd.addStroke(new PathStroke('B', [x0 + 6 * wb, y - 1 * hb, x0 + 8 * wb, y, x0 + 12 * wb, y]));\n // Draw the remaining line\n sd.addStroke(new PathStroke('L', [x + w * kx, y]));\n }\n }\n\n /**\n * Overrides {@link module:shapers/JigSaw.JigSaw#vLine}\n * @override\n * @param {module:AWT.Path} sd - The Path to which the line will be added\n * @param {number} type - Type of tooth: 0 is flat (no tooth), 1 means tooth right, and 2 means tooth left\n * @param {number} x - X coordinate of the starting point\n * @param {number} y - Y coordinate of the starting point\n * @param {number} w - Width of the piece\n * @param {number} h - Height of the piece\n * @param {boolean} inv - The line must be drawn bottom to top\n */\n vLine(sd, type, x, y, w, h, inv) {\n const\n ky = inv ? -1 : 1,\n kx = type === 1 ? 1 : -1;\n\n if (type === 0)\n // Flat line\n sd.addStroke(new PathStroke('L', [x, y + h * ky]));\n else {\n const\n y0 = y + (h - h * this.baseWidthFactor) / 2 * ky,\n hb = h * this.baseWidthFactor / 12 * ky;\n\n // Approximation to the tooth:\n sd.addStroke(new PathStroke('L', [x, y0]));\n // This is the tooth:\n const wb = w * this.toothHeightFactor * kx / 8;\n sd.addStroke(new PathStroke('B', [x, y0 + 4 * hb, x - wb, y0 + 6 * hb, x - 3 * wb, y0 + 4 * hb]));\n sd.addStroke(new PathStroke('B', [x - 5 * wb, y0 + 2 * hb, x - 5 * wb, y0 + 10 * hb, x - 3 * wb, y0 + 8 * hb]));\n sd.addStroke(new PathStroke('B', [x - 1 * wb, y0 + 6 * hb, x, y0 + 8 * hb, x, y0 + 12 * hb]));\n // Draw the remaining line\n sd.addStroke(new PathStroke('L', [x, y + h * ky]));\n }\n }\n}\n\nObject.assign(ClassicJigSaw.prototype, {\n /**\n * ClassicJigSaw needs a biggest base width\n * @name module:shapers/ClassicJigSaw.ClassicJigSaw#baseWidthFactor\n * @type {number} */\n baseWidthFactor: 3.0 / 4,\n /**\n * ClassicJigSaw needs a biggest base height factor\n * @name module:shapers/ClassicJigSaw.ClassicJigSaw#toothHeightFactor\n * @type {number} */\n toothHeightFactor: 3.0 / 5,\n});\n\n// Register this class in the list of known shapers\nexport default Shaper.registerClass('@ClassicJigSaw', ClassicJigSaw);\n","/**\n * File : shapers/Holes.js\n * Created : 20/05/2015\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\nimport Shaper from './Shaper.js';\n\n/**\n * This {@link module:shapers/Shaper.Shaper Shaper} consists of a set of arbitrary shapes placed over a main rectangle that\n * acts as a enclosure.\n * The components can be of type {@link module:AWT.Rectangle}, {@link module:AWT.Ellipse} or {@link module:AWT.Path}.\n * This components have internal dimension values relative to the horizontal and vertical\n * sizes of the enclosure. Its values (always between 0 and 1) must be scaled to real sizes\n * of graphic objects.\n * @extends module:shapers/Shaper.Shaper\n */\nexport class Holes extends Shaper {\n /**\n * Holes constructor\n * @param {number} nx - Not used\n * @param {number} ny - Not used\n */\n constructor(nx, ny) {\n super(1, 1);\n this.customShapes = true;\n this.nCols = nx;\n this.nRows = ny;\n this.showEnclosure = true;\n }\n\n /**\n * Shapes are already loaded by {@link module:shapers/Shaper.Shaper Shaper}, so this function just sets `initiated` to `true`\n * @override\n */\n buildShapes() {\n if (this.nCells > 0)\n this.initiated = true;\n }\n\n /**\n * Gets the rectangle that contains all shapes\n * @override\n * @returns {module:AWT.Rectangle}\n */\n getEnclosingShapeData() {\n return this.showEnclosure ? (this.enclosing || super.getEnclosingShapeData()) : null;\n }\n}\n\n// Register this class in the list of known shapers\nexport default Shaper.registerClass('@Holes', Holes);\n","/**\n * File : shapers/TriangularJigSaw.js\n * Created : 25/05/2015\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\nimport Shaper from './Shaper.js';\nimport JigSaw from './JigSaw.js';\nimport { PathStroke } from '../AWT.js';\n\n/**\n * This {@link module:shapers/Shaper.Shaper Shaper} returns a set of rectangular shapes with triangular teeth and slots that\n * fit between them.\n * @extends module:shapers/JigSaw.JigSaw\n */\nexport class TriangularJigSaw extends JigSaw {\n /**\n * TriangularJigSaw constructor\n * @param {number} nx - Number of columns\n * @param {number} ny - Number of rows\n */\n constructor(nx, ny) {\n super(nx, ny);\n }\n\n /**\n * Overrides {@link module:shapers/JigSaw.JigSaw#hLine}\n * @override\n * @param {module:AWT.Path} sd - The Path to which the line will be added\n * @param {number} type - Type of tooth: 0 is flat (no tooth), 1 means tooth up, and 2 means tooth down\n * @param {number} x - X coordinate of the starting point\n * @param {number} y - Y coordinate of the starting point\n * @param {number} w - Width of the piece\n * @param {number} h - Height of the piece\n * @param {boolean} inv - The line must be drawn right to left\n */\n hLine(sd, type, x, y, w, h, inv) {\n const\n kx = inv ? -1 : 1,\n ky = type === 1 ? 1 : -1;\n\n if (type === 0)\n // Flat line\n sd.addStroke(new PathStroke('L', [x + w * kx, y]));\n else {\n const x0 = x + (w - w * this.baseWidthFactor) / 2 * kx;\n const wb = w * this.baseWidthFactor * kx;\n // Approximation to the tooth:\n sd.addStroke(new PathStroke('L', [x0, y]));\n // This is the tooth:\n const hb = h * this.toothHeightFactor * ky;\n sd.addStroke(new PathStroke('L', [x0 + wb / 2, y + hb]));\n sd.addStroke(new PathStroke('L', [x0 + wb, y]));\n // Draw the remaining line\n sd.addStroke(new PathStroke('L', [x + w * kx, y]));\n }\n }\n\n /**\n * Overrides {@link module:shapers/JigSaw.JigSaw#vLine}\n * @override\n * @param {module:AWT.Path} sd - The Path to which the line will be added\n * @param {number} type - Type of tooth: 0 is flat (no tooth), 1 means tooth right, and 2 means tooth left\n * @param {number} x - X coordinate of the starting point\n * @param {number} y - Y coordinate of the starting point\n * @param {number} w - Width of the piece\n * @param {number} h - Height of the piece\n * @param {boolean} inv - The line must be drawn bottom to top\n */\n vLine(sd, type, x, y, w, h, inv) {\n const\n ky = inv ? -1 : 1,\n kx = type === 1 ? 1 : -1;\n\n if (type === 0)\n // Flat line\n sd.addStroke(new PathStroke('L', [x, y + h * ky]));\n else {\n const\n y0 = y + (h - h * this.baseWidthFactor) / 2 * ky,\n hb = h * this.baseWidthFactor * ky;\n\n // Approximation to the tooth:\n sd.addStroke(new PathStroke('L', [x, y0]));\n // This is the tooth:\n const wb = w * this.toothHeightFactor * kx;\n sd.addStroke(new PathStroke('L', [x + wb, y0 + hb / 2]));\n sd.addStroke(new PathStroke('L', [x, y0 + hb]));\n // Draw the remaining line\n sd.addStroke(new PathStroke('L', [x, y + h * ky]));\n }\n }\n}\n\n// Register this class in the list of known shapers\nexport default Shaper.registerClass('@TriangularJigSaw', TriangularJigSaw);\n","/**\n * File : skins/Counter.js\n * Created : 07/05/2015\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\n/**\n * This class encapsulates the operation of a numeric counter, used to display the current\n * values of score, actions and time.\n */\nexport class Counter {\n /**\n * Counter constructor\n * @param {string} id - The type of information stored on this counter\n * @param {external:jQuery} [$div] - The HTML element where this counter will show values (can be _null_)\n */\n constructor(id, $div) {\n if (id)\n this.id = id;\n if ($div)\n this.$div = $div;\n }\n\n /**\n * Gets the current display value of this counter\n * @returns {number}\n */\n getDisplayValue() {\n let result = this.countDown > 0 ? this.countDown - this.value : this.value;\n if (this.displayDiffFrom)\n result = result - this.displayDiffFrom.value;\n return Math.max(0, Math.min(this.MAX_DISPLAY_VALUE, result));\n }\n\n /**\n * Paints the value of this counter on screen\n * (method to be overridden by subclasses)\n */\n refreshDisplay() {\n if (this.$div)\n this.$div.html(this.enabled ? (this.getDisplayValue() + 1000).toString().substring(1) : '000');\n }\n\n /**\n * Enables or disables this counter\n * @param {boolean} enabled - State been assigned to this counter\n */\n setEnabled(enabled) {\n if (this.enabled !== enabled) {\n this.enabled = enabled;\n if (this.$div) {\n this.refreshDisplay();\n this.$div.css('opacity', this.enabled ? 1.0 : 0.3);\n }\n }\n }\n\n /**\n * Sets the initial value of the counter\n * @param {number} maxValue - Value from which the countdown will start\n */\n setCountDown(maxValue) {\n if (this.countDown !== (this.countDown = maxValue))\n this.refreshDisplay();\n }\n\n /**\n * Increments by one the value of this counter\n */\n incValue() {\n this.value++;\n if (this.enabled)\n this.refreshDisplay();\n }\n\n /**\n * Sets a specific value to this counter\n * @param {number} value - The value to set\n */\n setValue(value) {\n if (this.enabled && this.value !== (this.value = value))\n this.refreshDisplay();\n }\n}\n\nObject.assign(Counter.prototype, {\n /**\n * Type of counter (usually: `score`, `actions` or `time`)\n * @name module:skins/Counter.Counter#id\n * @type {string} */\n id: '',\n /**\n * The HTML element where this counter shows its value\n * @name module:skins/Counter.Counter#$div\n * @type {external:jQuery}\n */\n $div: null,\n /**\n * Current value of this counter\n * @name module:skins/Counter.Counter#value\n * @type {number} */\n value: 0,\n /**\n * When set, the counter displays a countdown from this value to zero\n * @name module:skins/Counter.Counter#countDown\n * @type {number} */\n countDown: 0,\n /**\n * Flag indicating if this counter is currently enabled\n * @name module:skins/Counter.Counter#enabled\n * @type {boolean} */\n enabled: true,\n /**\n * Maximum value to be displayed by this counter\n * @name module:skins/Counter.Counter#MAX_DISPLAY_VALUE\n * @type {number} */\n MAX_DISPLAY_VALUE: 999,\n /**\n * An optional Counter used as a subtractor to display the current value.\n * Useful to display `errors` subtracting `score` from `actions`.\n * @name module:skins/Counter.Counter#displayDiffFrom\n * @type {module:skins/Counter.Counter}\n */\n displayDiffFrom: null,\n});\n\nexport default Counter;\n","/**\n * File : skins/DefaultSkin.js\n * Created : 12/05/2015\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\n/* global document */\n\nimport $ from 'jquery';\nimport { Font } from '../AWT.js';\nimport Skin from './Skin.js';\nimport ActiveBox from '../boxes/ActiveBox.js';\nimport Counter from './Counter.js';\nimport { log, getMsg, getSvg, svgToURI } from '../Utils.js';\n\n// Use Webpack to import CSS and SVG files\nimport mainCSS from './assets/main.css';\nimport mainCSSHalf from './assets/mainHalf.css';\nimport mainCSSTwoThirds from './assets/mainTwoThirds.css';\nimport prevIcon from './assets/prevIcon.svg';\nimport nextIcon from './assets/nextIcon.svg';\nimport fullScreenIcon from './assets/fullScreenIcon.svg';\nimport fullScreenExitIcon from './assets/fullScreenExitIcon.svg';\nimport closeIcon from './assets/closeIcon.svg';\nimport infoIcon from './assets/infoIcon.svg';\nimport reportsIcon from './assets/reportsIcon.svg';\nimport timeIcon from './assets/timeIcon.svg';\nimport scoreIcon from './assets/scoreIcon.svg';\nimport actionsIcon from './assets/actionsIcon.svg';\n\n/**\n * This is the default {@link module:skins/Skin.Skin Skin} used by JClic.js\n * @extends module:skins/Skin.Skin\n */\nexport class DefaultSkin extends Skin {\n /**\n * DefaultSkin constructor\n * @param {module:JClicPlayer.JClicPlayer} ps - The PlayStation (currently a {@link module:JClicPlayer.JClicPlayer JClicPlayer}) used to load and\n * realize the media objects needed tot build the Skin.\n * @param {string} [name] - The skin class name\n * @param {object} [options] - Optional parameter with additional options, used by subclasses\n * this skin. When `null` or `undefined`, a new one will be created.\n */\n constructor(ps, name = null, options = {}) {\n // DefaultSkin extends [Skin](Skin.html)\n super(ps, name, options);\n let msg = '';\n\n Font.loadGoogleFonts(this.cssFonts);\n\n // Create the main container for buttons, counters and message box\n this.$ctrlCnt = $('<div/>', { class: 'JClicCtrlCnt unselectableText', role: 'navigation' });\n this.$div.append(this.$ctrlCnt);\n\n // Add `prev` button\n msg = getMsg('Previous activity');\n this.buttons.prev = $('<button/>', { class: 'JClicBtn', title: msg, 'aria-label': msg })\n .append($(getSvg(this.prevIcon, this.iconWidth, this.iconHeight, this.iconFill)))\n .on('click', evt => {\n if (this.ps)\n this.ps.actions.prev.processEvent(evt);\n });\n this.$ctrlCnt.append(this.buttons.prev);\n\n // Add message box\n this.msgBox = new ActiveBox();\n this.msgBox.role = 'message';\n this.$msgBoxDiv = $('<div/>', { class: 'JClicMsgBox' })\n .on('click', () => {\n this.msgBox.playMedia(ps);\n return false;\n });\n this.$ctrlCnt.append(this.$msgBoxDiv);\n\n // Add `next` button\n msg = getMsg('Next activity');\n this.buttons.next = $('<button/>', { class: 'JClicBtn', title: msg, 'aria-label': msg })\n .append($(getSvg(this.nextIcon, this.iconWidth, this.iconHeight, this.iconFill)))\n .on('click', evt => {\n if (this.ps)\n this.ps.actions.next.processEvent(evt);\n });\n this.$ctrlCnt.append(this.buttons.next);\n\n // Add counters\n if (false !== this.ps.options.counters && false !== options.counters) {\n // Create counters\n msg = getMsg('Reports');\n const $countCnt = $('<button/>', { class: 'JClicCountCnt', 'aria-label': msg })\n .on('click', evt => {\n if (this.ps)\n this.ps.actions.reports.processEvent(evt);\n });\n $.each(Skin.prototype.counters, (name, _val) => {\n msg = getMsg(name);\n this.counters[name] = new Counter(name, $('<div/>', { class: 'JClicCounter', title: msg, 'aria-label': msg })\n .css({\n 'background-image': `url(${svgToURI(this[name + 'Icon'], this.counterIconWidth, this.counterIconHeight, this.counterIconFill)})`,\n color: this.counterIconFill\n })\n .html('000')\n .appendTo($countCnt));\n });\n this.$ctrlCnt.append($countCnt);\n }\n\n // Add info button\n if (true === this.ps.options.info || true === options.info) {\n msg = getMsg('Information');\n this.buttons.info = $('<button/>', { class: 'JClicBtn', title: msg, 'aria-label': msg })\n .append($(getSvg(this.infoIcon, this.iconWidth, this.iconHeight, this.iconFill)))\n .on('click', evt => {\n if (this.ps)\n this.ps.actions.info.processEvent(evt);\n });\n this.$ctrlCnt.append(this.buttons.info);\n }\n\n // Add reports button\n if (true === this.ps.options.reportsBtn || true === options.reportsBtn) {\n msg = getMsg('Reports');\n this.buttons.about = $('<button/>', { class: 'JClicBtn', title: msg, 'aria-label': msg })\n .append($(getSvg(this.reportsIcon, this.iconWidth, this.iconHeight, this.iconFill)))\n .on('click', evt => {\n if (this.ps)\n this.ps.actions.reports.processEvent(evt);\n });\n this.$ctrlCnt.append(this.buttons.about);\n }\n\n // Add `full screen` button\n if (document && document.fullscreenEnabled) {\n msg = getMsg('Toggle full screen');\n this.buttons.fullscreen = $('<button/>', { class: 'JClicBtn', title: msg, 'aria-label': msg })\n .append($('<img/>', { src: svgToURI(this.fullScreenIcon, this.iconWidth, this.iconHeight, this.iconFill) }))\n .on('click', () => {\n this.setScreenFull(null);\n });\n this.$ctrlCnt.append(this.buttons.fullscreen);\n }\n\n // Add `close` button\n if (typeof this.ps.options.closeFn === 'function') {\n msg = getMsg('Close');\n const closeFn = this.ps.options.closeFn;\n this.buttons.close = $('<button/>', { class: 'JClicBtn', title: msg, 'aria-label': msg })\n .append($(getSvg(this.closeIcon, this.iconWidth, this.iconHeight, this.iconFill)))\n .on('click', () => {\n log('info', 'Closing the player');\n closeFn();\n });\n this.$ctrlCnt.append(this.buttons.close);\n }\n\n // Workaround for a bug in Edge and Explorer: SVG objects not implementing `blur` and `focus` methods\n // See: [https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/8479637/]\n // This affects Polymer `iron-overlay-behavior`. See: [https://github.com/PolymerElements/iron-overlay-behavior/pull/211]\n let nilFunc = null;\n $.each(this.buttons, (_key, value) => {\n if (value && (typeof value[0].focus !== 'function' || typeof value[0].blur !== 'function')) {\n if (nilFunc === null)\n nilFunc = () => log('error', '\"blur\" and \"focus\" not defined for SVG objects in Explorer/Edge');\n value[0].focus = value[0].blur = nilFunc;\n }\n });\n }\n\n /**\n * Returns the CSS styles used by this skin. This method should be called only from\n * the `Skin` constructor, and overridded by subclasses if needed.\n * @param {string} media - A specific media size. Possible values are: 'default', 'half' and 'twoThirds'\n * @returns {string}\n */\n _getStyleSheets(media = 'default') {\n return `${super._getStyleSheets(media)}${media === 'default' ? this.mainCSS : media === 'half' ? this.mainCSSHalf : media === 'twoThirds' ? this.mainCSSTwoThirds : ''}`;\n }\n\n /**\n * Main method used to build the content of the skin. Resizes and places internal objects.\n * @override\n */\n doLayout() {\n // Call method on ancestor\n super.doLayout();\n\n // Set the fullScreen icon\n if (this.buttons.fullscreen)\n this.buttons.fullscreen.find('img').get(-1).src = svgToURI(\n this[(document && document.fullscreenElement) ? 'fullScreenExitIcon' : 'fullScreenIcon'],\n this.iconWidth, this.iconHeight, this.iconFill);\n }\n\n /**\n * Enables or disables the `tabindex` attribute of the main buttons. Useful when a modal dialog\n * overlay is active, to avoid direct access to controls not related with the dialog.\n * @param {boolean} status - `true` to make main controls navigable, `false` otherwise\n */\n enableMainButtons(status) {\n this.$ctrlCnt.find('.JClicBtn,.JClicCountCnt').attr('tabindex', status ? '0' : '-1');\n }\n}\n\nObject.assign(DefaultSkin.prototype, {\n /**\n * Class name of this skin. It will be used as a base selector in the definition of all CSS styles.\n * @name module:skins/DefaultSkin.DefaultSkin#skinId\n * @override\n * @type {string}\n */\n skinId: 'JClicDefaultSkin',\n /**\n * The HTML div where buttons, counters and message box are placed\n * @name module:skins/DefaultSkin.DefaultSkin#$ctrlCnt\n * @type {external:jQuery} */\n $ctrlCnt: null,\n /**\n * Space (pixels) between the components of this {@link module:skins/Skin.Skin Skin}\n * @name module:skins/DefaultSkin.DefaultSkin#margin\n * @type {number} */\n margin: 18,\n /**\n * Height of {@link module:skins/DefaultSkin.DefaultSkin#msgBox msgBox}\n * @name module:skins/DefaultSkin.DefaultSkin#msgBoxHeight\n * @type {number} */\n msgBoxHeight: 60,\n /**\n * Width of counters, in pixels\n * @name module:skins/DefaultSkin.DefaultSkin#countersWidth\n * @type {number} */\n countersWidth: 60,\n /**\n * Height of counters, in pixels\n * @name module:skins/DefaultSkin.DefaultSkin#countersHeight\n * @type {number} */\n countersHeight: 20,\n //\n //Buttons and other graphical resources used by this skin.\n //\n /**\n * Styles used in this skin\n * @name module:skins/DefaultSkin.DefaultSkin#mainCSS\n * @type {string} */\n mainCSS,\n /**\n * Styles used in this skin, sized to half its regular size\n * @name module:skins/DefaultSkin.DefaultSkin#mainCSSHalf\n * @type {string} */\n mainCSSHalf,\n /**\n * Styles used in this skin, sized to two thirds of its regular size\n * @name module:skins/DefaultSkin.DefaultSkin#mainCSSTwoThirds\n * @type {string} */\n mainCSSTwoThirds,\n /**\n * Fonts used in this skin\n * @name module:skins/DefaultSkin.DefaultSkin#cssFonts\n * @type {string[]} */\n cssFonts: ['Roboto'],\n //\n // Default settings for icons (can be overridden in subclasses):\n /**\n * Icon width\n * @name module:skins/DefaultSkin.DefaultSkin#iconWidth\n * @type {number} */\n iconWidth: 36,\n /**\n * Icon height\n * @name module:skins/DefaultSkin.DefaultSkin#iconHeight\n * @type {number} */\n iconHeight: 36,\n /**\n * Fill color for icons\n * @name module:skins/DefaultSkin.DefaultSkin#iconFill\n * @type {string} */\n iconFill: '#FFFFFF',\n //\n // SVG images for action buttons\n // Based on [Google Material design Icons](https://google.github.io/material-design-icons/)\n //\n /**\n * Icon for 'previous activity' button\n * @name module:skins/DefaultSkin.DefaultSkin#prevIcon\n * @type {string} */\n prevIcon,\n /**\n * Icon for 'next activity' button\n * @name module:skins/DefaultSkin.DefaultSkin#nextIcon\n * @type {string} */\n nextIcon,\n /**\n * Full screen on icon\n * @name module:skins/DefaultSkin.DefaultSkin#fullScreenIcon\n * @type {string} */\n fullScreenIcon,\n /**\n * Full screen off icon\n * @name module:skins/DefaultSkin.DefaultSkin#fullScreenExitIcon\n * @type {string} */\n fullScreenExitIcon,\n /**\n * Close button\n * @name module:skins/DefaultSkin.DefaultSkin#closeIcon\n * @type {string} */\n closeIcon,\n /**\n * Info button\n * @name module:skins/DefaultSkin.DefaultSkin#infoIcon\n * @type {string} */\n infoIcon,\n /**\n * Reports button\n * @name module:skins/DefaultSkin.DefaultSkin#reportsIcon\n * @type {string} */\n reportsIcon,\n //\n // Settings for counters:\n /**\n * Counter icon width\n * @name module:skins/DefaultSkin.DefaultSkin#counterIconWidth\n * @type {number} */\n counterIconWidth: 18,\n /**\n * Counter icon height\n * @name module:skins/DefaultSkin.DefaultSkin#counterIconHeight\n * @type {number} */\n counterIconHeight: 18,\n /**\n * Counter icon fill color\n * @name module:skins/DefaultSkin.DefaultSkin#counterIconFill\n * @type {string} */\n counterIconFill: '#FFFFFF',\n // Counters:\n /**\n * Time icon\n * @name module:skins/DefaultSkin.DefaultSkin#timeIcon\n * @type {string} */\n timeIcon,\n /**\n * Score icon\n * @name module:skins/DefaultSkin.DefaultSkin#scoreIcon\n * @type {string} */\n scoreIcon,\n /**\n * Actions icon\n * @name module:skins/DefaultSkin.DefaultSkin#actionsIcon\n * @type {string} */\n actionsIcon,\n});\n\n// Register this class in the list of available skins\nexport default Skin.registerClass('default', DefaultSkin);\n","/**\n * File : skins/BlueSkin.js\n * Created : 04/07/2016\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\nimport Skin from './Skin.js';\nimport DefaultSkin from './DefaultSkin.js';\n\n\n/**\n * This is a variant of the default {@link module:skins/Skin.Skin Skin} used by JClic.js\n * It differs from {@link module:skins/DefaultSkin.DefaultSkin DefaultSkin} only in some colors\n * @extends module:skins/DefaultSkin.DefaultSkin\n */\nexport class BlueSkin extends DefaultSkin {\n /**\n * BlueSkin constructor\n * @param {module:JClicPlayer.JClicPlayer} ps - The PlayStation (currently a {@link module:JClicPlayer.JClicPlayer JClicPlayer}) used to load and\n * realize the media objects needed to build the Skin.\n * @param {string} [name] - The skin class name\n * @param {object} [options] - Optional parameter with additional options\n */\n constructor(ps, name = null, options = {}) {\n // BlueSkin extends [DefaultSkin](DefaultSkin.html)\n super(ps, name, options);\n }\n\n /**\n * Returns the CSS styles used by this skin. This method should be called only from\n * the `Skin` constructor, and overridded by subclasses if needed.\n * @param {string} media - A specific media size. Possible values are: 'default', 'half' and 'twoThirds'\n * @returns {string}\n */\n _getStyleSheets(media = 'default') {\n return super._getStyleSheets(media) + (media === 'default' ? this.skinCSS : '');\n }\n}\n\nObject.assign(BlueSkin.prototype, {\n /**\n * Class name of this skin. It will be used as a base selector in the definition of all CSS styles.\n * @name module:skins/BlueSkin.BlueSkin#skinId\n * @override\n * @type {string} */\n skinId: 'JClicBlueSkin',\n /**\n * Styles used in this skin\n * @name module:skins/BlueSkin.BlueSkin#skinCSS\n * @type {string} */\n skinCSS: '.ID {background-color:#1990FF;}',\n});\n\n// Register this class in the list of available skins\nexport default Skin.registerClass('blue', BlueSkin);\n","/**\n * File : skins/CustomSkin.js\n * Created : 12/02/2018\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\nimport $ from 'jquery';\nimport Skin from './Skin.js';\nimport Counter from './Counter.js';\nimport { getMsg, checkColor, getImgClipUrl } from '../Utils.js';\nimport { Rectangle } from '../AWT.js';\nimport ActiveBox from '../boxes/ActiveBox.js';\n\n/**\n * Custom {@link module:skins/Skin.Skin Skin} for JClic.js, built assembling specific cuts of a canvas (usually a PNG file) defined in an XML file\n * @extends module:skins/Skin.Skin\n */\nexport class CustomSkin extends Skin {\n\n /**\n * CustomSkin constructor\n *\n * @param {module:JClicPlayer.JClicPlayer} ps - The PlayStation (currently a {@link module:JClicPlayer.JClicPlayer JClicPlayer}) used to load and\n * realize the media objects needed tot build the Skin.\n * @param {string} [name] - The skin class name\n * @param {object} [options] - Optional parameter with additional options\n */\n constructor(ps, name = null, options = null) {\n // CustomSkin extends [Skin](Skin.html)\n super(ps, name, options);\n //console.log(this.options)\n\n this.$mainPanel = $('<div/>', { class: 'JClicCustomMainPanel' });\n this.$gridPanel = $('<div/>', { class: 'JClicGridPanel' });\n for (let i = 0; i < 9; i++)\n this.$gridPanel.append($('<div/>', { class: `JClicCell JClicCell${i + 1}` }));\n this.$mainPanel.append(this.$gridPanel);\n this.$playerCnt.detach().addClass('JClicPlayerCell').appendTo(this.$mainPanel);\n this.$div.prepend(this.$mainPanel);\n\n // Add buttons\n if (options.buttons) {\n Object.keys(options.buttons.button).forEach(k => {\n const k2 = k === 'about' ? 'reports' : k;\n const msg = getMsg(this.msgKeys[k2] || k2);\n this.buttons[k2] = $('<button/>', { class: `JClicBtn JClicTransform Btn-${k2}`, title: msg, 'aria-label': msg, disabled: typeof this.msgKeys[k2] === 'undefined' })\n .on('click', evt => { if (ps.actions[k2]) ps.actions[k2].processEvent(evt); });\n this.$mainPanel.append(this.buttons[k2]);\n });\n }\n\n // Add message box\n if (options.rectangle.messages) {\n this.msgBox = new ActiveBox();\n this.msgBox.role = 'message';\n this.$msgBoxDiv = $('<div/>', { class: 'JClicMsgBox' })\n .on('click', () => {\n this.msgBox.playMedia(ps);\n return false;\n });\n this.$mainPanel.append(this.$msgBoxDiv);\n }\n\n // Add counters\n if (false !== this.ps.options.counters && options.counters && options.counters.counter) {\n $.each(Skin.prototype.counters, (name, _val) => {\n if (options.counters.counter[name]) {\n const msg = getMsg(name);\n this.counters[name] = new Counter(name, $('<div/>', { class: `JClicCounter JClicTransform Counter-${name}`, title: msg, 'aria-label': msg })\n .html('000')\n .appendTo(this.$mainPanel));\n }\n });\n }\n\n // Add progress animation\n if (options.progressAnimation) {\n this.$progressAnimation = $('<div/>', { class: 'JClicProgressAnimation JClicTransform' });\n this.$mainPanel.append(this.$progressAnimation);\n }\n\n }\n\n /**\n * Enables or disables the `tabindex` attribute of the main buttons. Useful when a modal dialog\n * overlay is active, to avoid direct access to controls not related with the dialog.\n * @param {boolean} status - `true` to make main controls navigable, `false` otherwise\n */\n enableMainButtons(status) {\n this.$mainPanel.find('.JClicBtn').attr('tabindex', status ? '0' : '-1');\n }\n\n /**\n * Computes the CSS styles used by this skin in thre moodes: main, half ant twoThirds.\n * The resulting strings will be stored in `cssVariants`\n * @returns {string}\n */\n _computeStyleSheets() {\n const\n maxw = this.options.dimension.preferredSize.width,\n maxh = this.options.dimension.preferredSize.height;\n\n this.twoThirdsMedia = { width: maxw, height: maxh };\n this.halfMedia = {\n width: Math.round(2 * maxw / 3),\n height: Math.round(2 * maxh / 3)\n };\n\n // Panels:\n const\n ph0 = this.options.rectangle.frame.left,\n ph1 = ph0 + this.options.rectangle.player.left,\n ph2 = ph0 + this.options.slicer.left,\n ph3 = ph0 + this.options.slicer.right,\n ph4 = ph1 + this.options.rectangle.player.width,\n ph5 = ph0 + this.options.rectangle.frame.width,\n pv0 = this.options.rectangle.frame.top,\n pv1 = pv0 + this.options.rectangle.player.top,\n pv2 = pv0 + this.options.slicer.top,\n pv3 = pv0 + this.options.slicer.bottom,\n pv4 = pv1 + this.options.rectangle.player.height,\n pv5 = pv0 + this.options.rectangle.frame.height,\n imgElement = this.ps.project.mediaBag.getElement(this.options.image, true),\n imgUrl = imgElement.data && imgElement.data.src ? imgElement.data.src : '',\n box1 = imgElement.data ? getImgClipUrl(imgElement.data, new Rectangle(ph0, pv0, ph2 - ph0, pv2 - pv0)) : '',\n box2 = imgElement.data ? getImgClipUrl(imgElement.data, new Rectangle(ph2 - ph0, pv0, ph3 - ph2, pv2 - pv0)) : '',\n box3 = imgElement.data ? getImgClipUrl(imgElement.data, new Rectangle(ph3, pv0, ph5 - ph3, pv2 - pv0)) : '',\n box4 = imgElement.data ? getImgClipUrl(imgElement.data, new Rectangle(ph0, pv2 - pv0, ph2 - ph0, pv3 - pv2)) : '',\n box6 = imgElement.data ? getImgClipUrl(imgElement.data, new Rectangle(ph3 - ph0, pv2 - pv0, ph5 - ph3, pv3 - pv2)) : '',\n box7 = imgElement.data ? getImgClipUrl(imgElement.data, new Rectangle(ph0, pv3 - pv0, ph2 - ph0, pv5 - pv3)) : '',\n box8 = imgElement.data ? getImgClipUrl(imgElement.data, new Rectangle(ph2 - ph0, pv3 - pv0, ph3 - ph2, pv5 - pv3)) : '',\n box9 = imgElement.data ? getImgClipUrl(imgElement.data, new Rectangle(ph3, pv3 - pv0, ph5 - ph3, pv5 - pv3)) : '';\n\n let css = `\n.ID .JClicCustomMainPanel {flex-grow:1;position:relative;background-color: ${checkColor(this.options.color.fill.value)};}\n.ID .JClicGridPanel {position:absolute;width:100%;height:100%;display:grid;grid-template-columns:${ph2 - ph0}px 1fr ${ph5 - ph3}px;grid-template-rows:${pv2 - pv0}px 1fr ${pv5 - pv3}px;}\n.ID .JClicCell {background-repeat:no-repeat;background-size:contain;}\n.ID .JClicPlayerCell {position:absolute;top:${pv1 - pv0}px;right:${ph5 - ph4}px;bottom:${pv5 - pv4}px;left:${ph1 - ph0}px;}\n.ID .JClicCell1 {background-image:url(${box1});}\n.ID .JClicCell2 {background-image:url(${box2});background-repeat:repeat-x;}\n.ID .JClicCell3 {background-image:url(${box3});}\n.ID .JClicCell4 {background-image:url(${box4});background-repeat:repeat-y;}\n.ID .JClicCell5 {}\n.ID .JClicCell6 {background-image:url(${box6});background-repeat:repeat-y;}\n.ID .JClicCell7 {background-image:url(${box7});}\n.ID .JClicCell8 {background-image:url(${box8});background-repeat:repeat-x;}\n.ID .JClicCell9 {background-image:url(${box9});}`;\n\n let cssHalf = `\n.ID .JClicGridPanel {grid-template-columns:${Math.round((ph2 - ph0) / 2)}px 1fr ${Math.round((ph5 - ph3) / 2)}px;grid-template-rows:${Math.round((pv2 - pv0) / 2)}px 1fr ${Math.round((pv5 - pv3) / 2)}px;}\n.ID .JClicPlayerCell {top:${Math.round((pv1 - pv0) / 2)}px;right:${Math.round((ph5 - ph4) / 2)}px;bottom:${Math.round((pv5 - pv4) / 2)}px;left:${Math.round((ph1 - ph0) / 2)}px;}\n.ID .JClicTransform {transform: scale(0.5);}`;\n\n let cssTwoThirds = `\n.ID .JClicGridPanel {grid-template-columns:${Math.round(2 * (ph2 - ph0) / 3)}px 1fr ${Math.round(2 * (ph5 - ph3) / 3)}px;grid-template-rows:${Math.round(2 * (pv2 - pv0) / 3)}px 1fr ${Math.round(2 * (pv5 - pv3) / 3)}px;}\n.ID .JClicPlayerCell {top:${Math.round(2 * (pv1 - pv0) / 3)}px;right:${Math.round(2 * (ph5 - ph4) / 3)}px;bottom:${Math.round(2 * (pv5 - pv4) / 3)}px;left:${Math.round(2 * (ph1 - ph0) / 3)}px;}\n.ID .JClicTransform {transform: scale(0.666);}`;\n\n // Buttons:\n if (this.options.buttons) {\n const bt = this.options.buttons;\n let wBase = 30, hBase = 30, offsetBase = {};\n if (bt.settings) {\n if (bt.settings.dimension) {\n wBase = bt.settings.dimension.width || wBase;\n hBase = bt.settings.dimension.height || hBase;\n }\n if (bt.settings.offset)\n Object.assign(offsetBase, bt.settings.offset);\n }\n Object.keys(this.options.buttons.button).forEach(k => {\n const\n btn = bt.button[k],\n k2 = k === 'about' ? 'reports' : k;\n let w = wBase, h = hBase, offset = offsetBase;\n if (btn.settings) {\n if (btn.settings.dimension) {\n w = btn.settings.dimension.width || w;\n h = btn.settings.dimension.height || h;\n }\n if (btn.settings.offset)\n offset = Object.assign({}, offsetBase, btn.settings.offset);\n }\n const\n x = btn.point.pos.left,\n xp = x < ph2 ? `left:${x}` : `right:${ph5 - x - w}`,\n xpHalf = x < ph2 ? `left:${Math.round(x / 2 - w / 4)}` : `right:${Math.round((ph5 - x - w) / 2 - w / 4)}`,\n xpTwoThirds = x < ph2 ? `left:${Math.round(2 * x / 3 - w / 6)}` : `right:${Math.round(2 * (ph5 - x - w) / 3 - w / 6)}`,\n y = btn.point.pos.top,\n yp = y < pv2 ? `top:${y}` : `bottom:${pv5 - y - h}`,\n ypHalf = y < pv2 ? `top:${Math.round(y / 2 - h / 4)}` : `bottom:${Math.round((pv5 - y - h) / 2 - h / 4)}`,\n ypTwoThirds = y < pv2 ? `top:${Math.round(2 * y / 3 - h / 6)}` : `bottom:${Math.round(2 * (pv5 - y - h) / 3 - h / 6)}`,\n xs = btn.point.source.left,\n ys = btn.point.source.top;\n css += `.ID .Btn-${k2} {position:absolute;${xp}px;${yp}px;width:${w}px;height:${h}px;background:url(${imgUrl}) !important;background-position:-${xs}px -${ys}px !important;}\\n`;\n cssHalf += `.ID .Btn-${k2} {${xpHalf}px;${ypHalf}px;}\\n`;\n cssTwoThirds += `.ID .Btn-${k2} {${xpTwoThirds}px;${ypTwoThirds}px;}\\n`;\n if (offset.active)\n css += `.ID .Btn-${k2}:active {background-position:-${xs + offset.active.right}px -${ys + offset.active.down}px !important;}\\n`;\n if (offset.over)\n css += `.ID .Btn-${k2}:hover {background-position:-${xs + offset.over.right}px -${ys + offset.over.down}px !important;}\\n`;\n if (offset.disabled)\n css += `.ID .Btn-${k2}:disabled {background-position:-${xs + offset.disabled.right}px -${ys + offset.disabled.down}px !important;}\\n`;\n });\n }\n\n // Counters:\n if (this.options.counters && this.options.counters.settings) {\n const cnt = this.options.counters;\n let wBase = 35, hBase = 20;\n if (cnt.settings.dimension && cnt.settings.dimension.counter) {\n wBase = (cnt.settings.dimension.counter.width || wBase);\n hBase = cnt.settings.dimension.counter.height || hBase;\n }\n let wLb = 37, hLb = 14;\n if (cnt.settings.dimension && cnt.settings.dimension.label) {\n wLb = (cnt.settings.dimension.label.width || wLb);\n hLb = cnt.settings.dimension.label.height || hLb;\n }\n let bColor = 'black';\n if (cnt.style && cnt.style.color && cnt.style.color.foreground)\n bColor = checkColor(cnt.style.color.foreground.value || bColor);\n let lbFntSize = hLb - 4;\n let lbFntFamily = 'Roboto';\n if (cnt.style && cnt.style.font && cnt.style.font.label) {\n lbFntSize = Math.max(8, cnt.style.font.label.size || lbFntSize);\n lbFntFamily = `${cnt.style.font.label.family || 'Roboto'},Roboto,sans-serif`;\n }\n\n css += `.ID .JClicCounter {font-size:${hBase - 2}px;color:${bColor}}\\n`;\n Object.keys(this.options.counters.counter).forEach(k => {\n const\n counter = cnt.counter[k];\n let w = wBase, h = hBase;\n const\n x = counter.point.counter.left,\n xl = counter.point.label.left || (x - Math.round((wLb - wBase) / 2)),\n xp = x < ph2 ? `left:${x}` : `right:${ph5 - x - w}`,\n xpHalf = x < ph2 ? `left:${Math.round(x / 2 - w / 4)}` : `right:${Math.round((ph5 - x - w) / 2 - w / 4)}`,\n xpTwoThirds = x < ph2 ? `left:${Math.round(2 * x / 3 - w / 6)}` : `right:${Math.round(2 * (ph5 - x - w) / 3 - w / 6)}`,\n y = counter.point.counter.top,\n yl = counter.point.label.top || (y - hLb),\n yp = y < pv2 ? `top:${y}` : `bottom:${pv5 - y - h}`,\n ypHalf = y < pv2 ? `top:${Math.round(y / 2 - h / 4)}` : `bottom:${Math.round((pv5 - y - h) / 2 - h / 4)}`,\n ypTwoThirds = y < pv2 ? `top:${Math.round(2 * y / 3 - h / 6)}` : `bottom:${Math.round(2 * (pv5 - y - h) / 3 - h / 6)}`;\n // counter:\n css += `.ID .Counter-${k} {position:absolute;${xp}px;${yp}px;width:${w}px;height:${h}px;line-height:${h}px;}\\n`;\n // label:\n css += `.ID .Counter-${k}:before {content:\"${getMsg(k)}\";font-size:${lbFntSize}px;font-family:${lbFntFamily};width:${wLb}px;height:${hLb}px;line-height:${hLb}px;position:absolute;top:${yl - y}px;left:${xl - x}px;}`;\n // reduced sizes:\n cssHalf += `.ID .Counter-${k} {${xpHalf}px;${ypHalf}px;}\\n`;\n cssTwoThirds += `.ID .Counter-${k} {${xpTwoThirds}px;${ypTwoThirds}px;}\\n`;\n });\n }\n\n // Progress animation:\n if (this.options.progressAnimation) {\n const pa = this.options.progressAnimation;\n let w = 30, h = 30;\n if (pa.dimension) {\n w = pa.dimension.width || w;\n h = pa.dimension.height || h;\n }\n const\n x = pa.point.pos.left,\n xp = x < ph2 ? `left:${x}` : `right:${ph5 - x - w}`,\n xpHalf = x < ph2 ? `left:${Math.round(x / 2 - w / 4)}` : `right:${Math.round((ph5 - x - w) / 2 - w / 4)}`,\n xpTwoThirds = x < ph2 ? `left:${Math.round(2 * x / 3 - w / 6)}` : `right:${Math.round(2 * (ph5 - x - w) / 3 - w / 6)}`,\n y = pa.point.pos.top,\n yp = y < pv2 ? `top:${y}` : `bottom:${pv5 - y - h}`,\n ypHalf = y < pv2 ? `top:${Math.round(y / 2 - h / 4)}` : `bottom:${Math.round((pv5 - y - h) / 2 - h / 4)}`,\n ypTwoThirds = y < pv2 ? `top:${Math.round(2 * y / 3 - h / 6)}` : `bottom:${Math.round(2 * (pv5 - y - h) / 3 - h / 6)}`,\n xs = pa.point.source.left,\n ys = pa.point.source.top;\n css += `.ID .JClicProgressAnimation {position:absolute;${xp}px;${yp}px;width:${w}px;height:${h}px;background:url(${imgUrl});background-position:-${xs}px -${ys}px;}\\n`;\n cssHalf += `.ID .JClicProgressAnimation {${xpHalf}px;${ypHalf}px;}\\n`;\n cssTwoThirds += `.ID .JClicProgressAnimation {${xpTwoThirds}px;${ypTwoThirds}px;}\\n`;\n\n if (pa.frames && pa.direction) {\n const\n dx = (pa.step || w) * (pa.direction === 'right' ? 1 : pa.direction === 'left' ? -1 : 0),\n dy = (pa.step || h) * (pa.direction === 'down' ? 1 : pa.direction === 'up' ? -1 : 0);\n css += `\\n@keyframes anim {100% {background-position:${(xs + dx * pa.frames) * -1}px ${(ys + dy * pa.frames) * -1}px;}}\\n.ID .JClicProgressAnimation {animation: anim ${pa.frames * pa.delay}ms steps(${pa.frames}) infinite;}`;\n }\n }\n\n // Messages box:\n if (this.options.rectangle.messages) {\n const\n bx = this.options.rectangle.messages,\n left = ph0 + bx.left,\n right = ph5 - bx.width - bx.left - ph0,\n tb = bx.top < pv2 ? `top:${bx.top}` : `bottom:${pv5 - bx.height - bx.top}`,\n tbHalf = bx.top < pv2 ? `top:${Math.round(bx.top / 2)}` : `bottom:${Math.round((pv5 - bx.height - bx.top) / 2)}`,\n tbTwoThirds = bx.top < pv2 ? `top:${Math.round(2 * bx.top / 3)}` : `bottom:${Math.round(2 * (pv5 - bx.height - bx.top) / 3)}`;\n\n css += `.ID .JClicMsgBox {position:absolute;left:${left}px;right:${right}px;height:${bx.height}px;${tb}px;}`;\n cssHalf += `.ID .JClicMsgBox {left:${Math.round(left / 2)}px;right:${Math.round(right / 2)}px;height:${Math.round(bx.height / 2)}px;${tbHalf}px;}`;\n cssTwoThirds += `.ID .JClicMsgBox {left:${Math.round(2 * left / 3)}px;right:${Math.round(2 * right / 3)}px;height:${Math.round(2 * bx.height / 3)}px;${tbTwoThirds}px;}`;\n }\n\n // TODO: Implement status messages?\n\n // Store results in `cssVariants`\n this.cssVariants = {\n default: this.mainCSS + css,\n half: cssHalf,\n twoThirds: cssTwoThirds\n };\n }\n\n /**\n * Returns the CSS styles used by this skin. This method should be called only from\n * the `Skin` constructor, and overridded by subclasses if needed.\n * @param {string} media - A specific media size. Possible values are: 'default', 'half' and 'twoThirds'\n * @override\n * @returns {string}\n */\n _getStyleSheets(media = 'default') {\n if (!this.cssVariants)\n this._computeStyleSheets();\n return `${super._getStyleSheets(media)}${this.cssVariants[media] || ''}`;\n }\n\n /**\n * Sets/unsets the 'wait' state\n * @override\n * @param {boolean} status - Whether to set or unset the wait status. When `undefined`, the\n * `waitCursorCount` member is evaluated to decide if the wait state should be activated or deactivated.\n */\n setWaitCursor(status) {\n super.setWaitCursor(status);\n if (this.$progressAnimation)\n this.$progressAnimation.css('animation-play-state', this.waitCursorCount > 0 ? 'running' : 'paused');\n }\n}\n\nObject.assign(CustomSkin.prototype, {\n /**\n * Class name of this skin. It will be used as a base selector in the definition of all CSS styles.\n * @name module:skins/CustomSkin.CustomSkin#skinId\n * @override\n * @type {string} */\n skinId: 'JClicCustomSkin',\n /**\n * The name of the image file to be used as a base of this skin.\n * @name module:skins/CustomSkin.CustomSkin#image\n * @type {string} */\n image: null,\n /**\n * Styles used in this skin\n * @name module:skins/CustomSkin.CustomSkin#skinCSS\n * @override\n * @type {string} */\n mainCSS: '\\\n.ID .JClicPlayerCnt {margin:0;}\\\n.ID .JClicBtn:focus {outline:0;}\\\n.ID .JClicCounter {font-family:Roboto,sans-serif;text-align:center;}',\n /**\n * Specifc styles (`default`, `half` and `twoThirds`) computed at run-time,\n * based on the provided XML file\n * @name module:skins/CustomSkin.CustomSkin#cssVariants\n * @type {object} */\n cssVariants: null,\n /**\n * Key ids of currently supported buttons, associated with its helper literal\n * @name module:skins/CustomSkin.CustomSkin#msgKeys\n * @type {object} */\n msgKeys: {\n next: 'Next activity',\n prev: 'Previous activity',\n info: 'Information',\n help: 'Help',\n reports: 'Reports',\n // TODO: Implement audio on/off!\n audio: 'Audio on/off',\n reset: 'Reset activity',\n },\n /**\n * Graphic indicator of loading progress\n * @name module:skins/CustomSkin.Skin#$progressAnimation\n * @type {external:jQuery} */\n $progressAnimation: null,\n});\n\n// Register this class in the list of available skins\nexport default Skin.registerClass('custom', CustomSkin);\n","/**\n * File : skins/EmptySkin.js\n * Created : 14/03/2017\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\nimport Skin from './Skin.js';\nimport ActiveBox from '../boxes/ActiveBox.js';\n\n/**\n * A minimalist {@link module:skins/Skin.Skin Skin} for JClic.js with just the player, without messages, counters nor any button.\n * @extends module:skins/Skin.Skin\n */\nexport class EmptySkin extends Skin {\n\n /**\n * EmptySkin constructor\n *\n * @param {module:JClicPlayer.JClicPlayer} ps - The PlayStation (currently a {@link module:JClicPlayer.JClicPlayer JClicPlayer}) used to load and\n * realize the media objects needed tot build the Skin.\n * @param {string} [name] - The skin class name\n * @param {object} [options] - Optional parameter with additional options\n */\n constructor(ps, name = null, options = {}) {\n // EmptySkin extends [Skin](Skin.html)\n super(ps, name, options);\n this.msgBox = new ActiveBox();\n this.msgBox.role = 'message';\n }\n /**\n * Returns the CSS styles used by this skin. This method should be called only from\n * the `Skin` constructor, and overridded by subclasses if needed.\n * @param {string} media - A specific media size. Possible values are: 'default', 'half' and 'twoThirds'\n * @returns {string}\n */\n _getStyleSheets(media = 'default') {\n return super._getStyleSheets(media) + (media === 'default' ? this.mainCSS : '');\n }\n}\n\nObject.assign(EmptySkin.prototype, {\n /**\n * Class name of this skin. It will be used as a base selector in the definition of all CSS styles.\n * @name module:skins/EmptySkin.EmptySkin#skinId\n * @override\n * @type {string} */\n skinId: 'JClicEmptySkin',\n /**\n * Styles used in this skin\n * @name module:skins/EmptySkin.EmptySkin#skinCSS\n * @override\n * @type {string} */\n mainCSS: '.ID .JClicPlayerCnt {margin:0;}'\n});\n\n// Register this class in the list of available skins\nexport default Skin.registerClass('empty', EmptySkin);\n","/**\n * File : skins/GreenSkin.js\n * Created : 04/07/2016\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\nimport Skin from './Skin.js';\nimport DefaultSkin from './DefaultSkin.js';\n\n/**\n * This is a variant of the default {@link module:skins/Skin.Skin Skin} used by JClic.js\n * It differs from {@link module:skins/DefaultSkin.DefaultSkin DefaultSkin} only in some colors\n * @extends module:skins/DefaultSkin.DefaultSkin\n */\nexport class GreenSkin extends DefaultSkin {\n /**\n * GreenSkin constructor\n *\n * @param {module:JClicPlayer.JClicPlayer} ps - The PlayStation (currently a {@link module:JClicPlayer.JClicPlayer JClicPlayer}) used to load and\n * realize the media objects needed to build this Skin.\n * @param {string} [name] - The skin class name\n * @param {object} [options] - Optional parameter with additional options\n */\n constructor(ps, name = null, options = {}) {\n // GreenSkin extends [DefaultSkin](DefaultSkin.html)\n super(ps, name, options);\n }\n\n /**\n * Returns the CSS styles used by this skin. This method should be called only from\n * the `Skin` constructor, and overridded by subclasses if needed.\n * @param {string} media - A specific media size. Possible values are: 'default', 'half' and 'twoThirds'\n * @returns {string}\n */\n _getStyleSheets(media = 'default') {\n return super._getStyleSheets(media) + (media === 'default' ? this.skinCSS : '');\n }\n}\n\nObject.assign(GreenSkin.prototype, {\n /**\n * Class name of this skin. It will be used as a base selector in the definition of all CSS styles.\n * @name module:skins/GreenSkin.GreenSkin#skinId\n * @override\n * @type {string} */\n skinId: 'JClicGreenSkin',\n //\n // Buttons and other graphical resources used by this skin:\n /**\n * Fill color for icons\n * @name module:skins/GreenSkin.GreenSkin#iconFill\n * @override\n * @type {string} */\n iconFill: '#20640E',\n /**\n * Fill-in color for counters\n * @name module:skins/GreenSkin.GreenSkin#counterIconFill\n * @override\n * @type {string} */\n counterIconFill: '#20640E',\n /**\n * Styles used in this skin\n * @name module:skins/GreenSkin.GreenSkin#skinCSS\n * @type {string} */\n skinCSS: '.ID {background-color:#4AFF19;}'\n});\n\n// Register this class in the list of available skins\nexport default Skin.registerClass('green', GreenSkin);\n","/**\n * File : skins/MiniSkin.js\n * Created : 05/07/2016\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\nimport Skin from './Skin.js';\nimport DefaultSkin from './DefaultSkin.js';\n\n// Use Webpack to import CSS and SVG files\nimport skinCSS from './assets/mini.css';\n\n/**\n * This is a variant of the default {@link module:skins/Skin.Skin Skin} used by JClic.js\n * It differs from {@link module:skins/DefaultSkin.DefaultSkin DefaultSkin} in colors and sizes\n * @extends module:skins/DefaultSkin.DefaultSkin\n */\nexport class MiniSkin extends DefaultSkin {\n /**\n * MiniSkin constructor\n *\n * @param {module:JClicPlayer.JClicPlayer} ps - The PlayStation (currently a {@link module:JClicPlayer.JClicPlayer JClicPlayer}) used to load and\n * realize the media objects meeded tot build the Skin.\n * @param {string} [name] - The skin class name\n * @param {object} [options] - Optional parameter with additional options\n */\n constructor(ps, name = null, options = {}) {\n // MiniSkin extends [DefaultSkin](DefaultSkin.html)\n super(ps, name, Object.assign({}, options, { counters: false, reportsBtn: true }));\n }\n\n /**\n * Returns the CSS styles used by this skin. This method should be called only from\n * the `Skin` constructor, and overridded by subclasses if needed.\n * @param {string} media - A specific media size. Possible values are: 'default', 'half' and 'twoThirds'\n * @returns {string}\n */\n _getStyleSheets(media = 'default') {\n return super._getStyleSheets(media) + (media === 'default' ? this.skinCSS : '');\n }\n}\n\nObject.assign(MiniSkin.prototype, {\n /**\n * Class name of this skin. It will be used as a base selector in the definition of all CSS styles.\n * @name MiniSkin#skinId\n * @override\n * @type {string}\n */\n skinId: 'JClicMiniSkin',\n // Buttons and other graphical resources used by this skin.\n //\n /**\n * Icon width\n * @name MiniSkin#iconWidth\n * @override\n * @type {number} */\n iconWidth: 18,\n /**\n * Icon height\n * @name MiniSkin#iconHeight\n * @override\n * @type {number} */\n iconHeight: 18,\n /**\n * Fill color for icons\n * @name MiniSkin#iconFill\n * @override\n * @type {string} */\n iconFill: '#080808',\n /**\n * Fill-in color for counters\n * @name MiniSkin#counterIconFill\n * @override\n * @type {string} */\n counterIconFill: '#080808',\n /**\n * Default margin between elements\n * @name MiniSkin#margin\n * @override\n * @type {number} */\n margin: 8,\n /**\n * Styles used in this skin\n * @name MiniSkin#skinCSS\n * @type {string} */\n skinCSS,\n /**\n * Styles used in this skin, sized to half its regular size.\n * (_null_ here because MiniSkin it's already very small)\n * @name MiniSkin#mainCSSHalf\n * @override\n * @type {string} */\n mainCSSHalf: '',\n /**\n * Styles used in this skin, sized to two thirds of its regular size\n * (_null_ here because MiniSkin it's already very small)\n * @name MiniSkin#mainCSSTwoThirds\n * @override\n * @type {string} */\n mainCSSTwoThirds: '',\n});\n\n// Register this class in the list of available skins\nexport default Skin.registerClass('mini', MiniSkin);\n","/**\n * File : skins/OrangeSkin.js\n * Created : 04/07/2016\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\nimport Skin from './Skin.js';\nimport DefaultSkin from './DefaultSkin.js';\n\n/**\n * This is a variant of the default {@link module:skins/Skin.Skin Skin} used by JClic.js\n * It differs from {@link module:skins/DefaultSkin.DefaultSkin DefaultSkin} only in some colors\n * @extends module:skins/DefaultSkin.DefaultSkin\n */\nexport class OrangeSkin extends DefaultSkin {\n /**\n * OrangeSkin constructor\n * @param {module:JClicPlayer.JClicPlayer} ps - The PlayStation (currently a {@link module:JClicPlayer.JClicPlayer JClicPlayer}) used to load and\n * realize the media objects meeded tot build the Skin.\n * @param {string} [name] - The skin class name\n * @param {object} [options] - Optional parameter with additional options\n */\n constructor(ps, name = null, options = {}) {\n // OrangeSkin extends [DefaultSkin](DefaultSkin.html)\n super(ps, name, options);\n }\n\n /**\n * Returns the CSS styles used by this skin. This method should be called only from\n * the `Skin` constructor, and overridded by subclasses if needed.\n * @param {string} media - A specific media size. Possible values are: 'default', 'half' and 'twoThirds'\n * @returns {string}\n */\n _getStyleSheets(media = 'default') {\n return super._getStyleSheets(media) + (media === 'default' ? this.skinCSS : '');\n }\n}\n\nObject.assign(OrangeSkin.prototype, {\n /**\n * Class name of this skin. It will be used as a base selector in the definition of all CSS styles.\n * @name module:skins/OrangeSkin.OrangeSkin#skinId\n * @override\n * @type {string} */\n skinId: 'JClicOrangeSkin',\n /**\n * Styles used in this skin\n * @name module:skins/OrangeSkin.OrangeSkin#skinCSS\n * @type {string} */\n skinCSS: '.ID {background-color:#FF8B19;}'\n});\n\nexport default Skin.registerClass('orange', OrangeSkin);\n","/**\n * File : skins/SimpleSkin.js\n * Created : 04/07/2016\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2020 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\nimport $ from 'jquery';\nimport Skin from './Skin.js';\nimport DefaultSkin from './DefaultSkin.js';\n\n// Use Webpack to import CSS and SVG files\nimport skinCSS from './assets/simple.css';\nimport skinCSSHalf from './assets/simpleHalf.css';\nimport skinCSSTwoThirds from './assets/simpleTwoThirds.css';\n\n/**\n * This is a variant of the default {@link module:skins/Skin.Skin Skin} used by JClic.js\n * It has the buttons at top, and don't has counters.\n * @extends module:skins/DefaultSkin.DefaultSkin\n */\nexport class SimpleSkin extends DefaultSkin {\n /**\n * SimpleSkin constructor\n * @param {module:JClicPlayer.JClicPlayer} ps - The PlayStation (currently a {@link module:JClicPlayer.JClicPlayer JClicPlayer}) used to load and\n * realize the media objects meeded tot build the Skin.\n * @param {string} [name] - The skin class name\n * @param {object} [options] - Optional parameter with additional options\n */\n constructor(ps, name = null, options = {}) {\n // OrangeSkin extends [DefaultSkin](DefaultSkin.html)\n super(ps, name, Object.assign({}, options, { counters: false, reportsBtn: true }));\n\n this.$ctrlCnt.detach().prependTo(this.$div);\n this.$msgBoxDiv.detach().appendTo(this.$div);\n // Add a spacing div in substitution of msgBox\n $('<div/>').css({ 'flex-grow': 1 }).insertAfter(this.$ctrlCnt.children(':nth-child(2)'));\n }\n\n /**\n * Returns the CSS styles used by this skin. This method should be called only from\n * the `Skin` constructor, and overridded by subclasses if needed.\n * @param {string} media - A specific media size. Possible values are: 'default', 'half' and 'twoThirds'\n * @returns {string}\n */\n _getStyleSheets(media = 'default') {\n return `${super._getStyleSheets(media)}${media === 'default' ? this.skinCSS : media === 'half' ? this.skinCSSHalf : media === 'twoThirds' ? this.skinCSSTwoThirds : ''}`;\n }\n}\n\nObject.assign(SimpleSkin.prototype, {\n /**\n * Class name of this skin. It will be used as a base selector in the definition of all CSS styles.\n * @name module:skins/SimpleSkin.SimpleSkin#skinId\n * @override\n * @type {string} */\n skinId: 'JClicSimpleSkin',\n /**\n * Styles used in this skin\n * @name module:skins/SimpleSkin.SimpleSkin#skinCSS\n * @type {string} */\n skinCSS,\n skinCSSHalf,\n skinCSSTwoThirds,\n});\n\n// Register this class in the list of available skins\nexport default Skin.registerClass('simple', SimpleSkin);\n","/*!\n * File : jclic-node.js\n * Created : 12/11/2024\n * By : Francesc Busquets <francesc@gmail.com>\n *\n * JClic.js\n * An HTML5 player of JClic activities\n * https://projectestac.github.io/jclic.js\n *\n * @source https://github.com/projectestac/jclic.js\n *\n * @license EUPL-1.2\n * @licstart\n * (c) 2000-2024 Educational Telematic Network of Catalonia (XTEC)\n *\n * Licensed under the EUPL, Version 1.1 or -as soon they will be approved by\n * the European Commission- subsequent versions of the EUPL (the \"Licence\");\n * You may not use this work except in compliance with the Licence.\n *\n * You may obtain a copy of the Licence at:\n * https://joinup.ec.europa.eu/software/page/eupl\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the Licence is distributed on an \"AS IS\" basis, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n * Licence for the specific language governing permissions and limitations\n * under the Licence.\n * @licend\n * @module\n */\n\n// Initialize fake DOM global variables like 'window' or 'document'.\nimport './init-jsdom.js';\n\nimport $ from 'jquery';\nimport AWT from './AWT.js';\nimport Activity from './Activity.js';\nimport GlobalData from './GlobalData.js';\nimport JClicPlayer from './JClicPlayer.js';\nimport Utils from './Utils.js';\nimport PlayerHistory from './PlayerHistory.js';\nimport ComplexAssociation from './activities/associations/ComplexAssociation.js';\nimport SimpleAssociation from './activities/associations/SimpleAssociation.js';\nimport MemoryGame from './activities/memory/MemoryGame.js';\nimport Explore from './activities/panels/Explore.js';\nimport Identify from './activities/panels/Identify.js';\nimport InformationScreen from './activities/panels/InformationScreen.js';\nimport Menu from './activities/panels/Menu.js';\nimport DoublePuzzle from './activities/puzzles/DoublePuzzle.js';\nimport ExchangePuzzle from './activities/puzzles/ExchangePuzzle.js';\nimport HolePuzzle from './activities/puzzles/HolePuzzle.js';\nimport Complete from './activities/text/Complete.js';\nimport Evaluator from './activities/text/Evaluator.js';\nimport FillInBlanks from './activities/text/FillInBlanks.js';\nimport CrossWord from './activities/textGrid/CrossWord.js';\nimport WordSearch from './activities/textGrid/WordSearch.js';\nimport IdentifyText from './activities/text/IdentifyText.js';\nimport OrderText from './activities/text/OrderText.js';\nimport TextActivityBase from './activities/text/TextActivityBase.js';\nimport TextActivityDocument from './activities/text/TextActivityDocument.js';\nimport WrittenAnswer from './activities/text/WrittenAnswer.js';\nimport Arith from './automation/arith/Arith.js';\nimport AutoContentProvider from './automation/AutoContentProvider.js';\nimport ActivitySequenceElement from './bags/ActivitySequenceElement.js';\nimport ActivitySequence from './bags/ActivitySequence.js';\nimport ActivitySequenceJump from './bags/ActivitySequenceJump.js';\nimport ConditionalJumpInfo from './bags/ConditionalJumpInfo.js';\nimport JumpInfo from './bags/JumpInfo.js';\nimport MediaBagElement from './bags/MediaBagElement.js';\nimport MediaBag from './bags/MediaBag.js';\nimport AbstractBox from './boxes/AbstractBox.js';\nimport ActiveBagContent from './boxes/ActiveBagContent.js';\nimport ActiveBoxBag from './boxes/ActiveBoxBag.js';\nimport ActiveBoxContent from './boxes/ActiveBoxContent.js';\nimport ActiveBoxGrid from './boxes/ActiveBoxGrid.js';\nimport ActiveBox from './boxes/ActiveBox.js';\nimport BoxBag from './boxes/BoxBag.js';\nimport BoxBase from './boxes/BoxBase.js';\nimport BoxConnector from './boxes/BoxConnector.js';\nimport TextGridContent from './boxes/TextGridContent.js';\nimport TextGrid from './boxes/TextGrid.js';\nimport ActiveMediaBag from './media/ActiveMediaBag.js';\nimport ActiveMediaPlayer from './media/ActiveMediaPlayer.js';\nimport AudioBuffer from './media/AudioBuffer.js';\nimport EventSoundsElement from './media/EventSoundsElement.js';\nimport EventSounds from './media/EventSounds.js';\nimport MediaContent from './media/MediaContent.js';\nimport MidiAudioPlayer from './media/MidiAudioPlayer.js';\nimport JClicProject from './project/JClicProject.js';\nimport ProjectSettings from './project/ProjectSettings.js';\nimport ActionReg from './report/ActionReg.js';\nimport ActivityReg from './report/ActivityReg.js';\nimport EncryptMin from './report/EncryptMin.js';\nimport Reporter from './report/Reporter.js';\nimport SCORM from './report/SCORM.js';\nimport SequenceReg from './report/SequenceReg.js';\nimport SessionReg from './report/SessionReg.js';\nimport SessionStorageReporter from './report/SessionStorageReporter.js';\nimport TCPReporter from './report/TCPReporter.js';\nimport ClassicJigSaw from './shapers/ClassicJigSaw.js';\nimport Holes from './shapers/Holes.js';\nimport JigSaw from './shapers/JigSaw.js';\nimport Rectangular from './shapers/Rectangular.js';\nimport Shaper from './shapers/Shaper.js';\nimport TriangularJigSaw from './shapers/TriangularJigSaw.js';\nimport BlueSkin from './skins/BlueSkin.js';\nimport Counter from './skins/Counter.js';\nimport CustomSkin from './skins/CustomSkin.js';\nimport DefaultSkin from './skins/DefaultSkin.js';\nimport EmptySkin from './skins/EmptySkin.js';\nimport GreenSkin from './skins/GreenSkin.js';\nimport MiniSkin from './skins/MiniSkin.js';\nimport OrangeSkin from './skins/OrangeSkin.js';\nimport SimpleSkin from './skins/SimpleSkin.js';\nimport Skin from './skins/Skin.js';\n\n// Export all JClic core classes plus jQuery, so they can be used in NodeJS\nexport default ({\n $,\n AWT,\n Activity,\n GlobalData,\n JClicPlayer,\n Utils,\n PlayerHistory,\n JClicProject,\n activities: {\n ComplexAssociation,\n SimpleAssociation,\n MemoryGame,\n Explore,\n Identify,\n InformationScreen,\n Menu,\n DoublePuzzle,\n ExchangePuzzle,\n HolePuzzle,\n Complete,\n Evaluator,\n FillInBlanks,\n CrossWord,\n WordSearch,\n IdentifyText,\n OrderText,\n TextActivityBase,\n TextActivityDocument,\n WrittenAnswer,\n },\n automation: {\n Arith,\n AutoContentProvider,\n },\n bags: {\n ActivitySequenceElement,\n ActivitySequence,\n ActivitySequenceJump,\n ConditionalJumpInfo,\n JumpInfo,\n MediaBagElement,\n MediaBag,\n },\n boxes: {\n AbstractBox,\n ActiveBagContent,\n ActiveBoxBag,\n ActiveBoxContent,\n ActiveBoxGrid,\n ActiveBox,\n BoxBag,\n BoxBase,\n BoxConnector,\n TextGridContent,\n TextGrid,\n },\n media: {\n ActiveMediaBag,\n ActiveMediaPlayer,\n AudioBuffer,\n EventSoundsElement,\n EventSounds,\n MediaContent,\n MidiAudioPlayer,\n },\n project: {\n JClicProject,\n ProjectSettings,\n },\n report: {\n ActionReg,\n ActivityReg,\n EncryptMin,\n Reporter,\n SCORM,\n SequenceReg,\n SessionReg,\n SessionStorageReporter,\n TCPReporter,\n },\n shapers: {\n ClassicJigSaw,\n Holes,\n JigSaw,\n Rectangular,\n Shaper,\n TriangularJigSaw,\n },\n skins: {\n BlueSkin,\n Counter,\n CustomSkin,\n DefaultSkin,\n EmptySkin,\n GreenSkin,\n MiniSkin,\n OrangeSkin,\n SimpleSkin,\n Skin,\n },\n});\n"],"names":[],"sourceRoot":""}
|