version notes for MMIR framework code * using Cordova 5.x.x - 9.x.x library optional * jQuery 2.x - 3.x library (presence is auto-detected, if loaded before mmir-lib) * jQuery Mobile 1.4.x library (note: requires jQuery 2.x) additional, required dependencies when running in node environment * scxml (tested with version 3.1.5) * xmlhttprequest (tested with version 1.8.0) * requirejs (tested with version 2.3.3) * webworker-threads (OPTIONAL, tested with version 0.8.0); recommended to use node's internal worker_threads module instead (included as experimental feature since node v 10.x) which may need to be enabled in earlier versions of node NOTE: for versions older than MMIR 3.x, the change-information refers to the MMIG StarterKit code. Since version 3.x the code is restructured: * mmir-lib: the framework code itself (the contents of its /lib directory would usually be located at /www/mmirf/) * mmir-tooling: the tools for building resources (would usually be located at /build/) * mmir-starter-kit: the code for the StarterKit includes mmir-lib and mmir-tooling as well as a small example application (i.e. basically this is the same as the StarterKit from pre 3.x versions) NOTE: the mmir-lib and mmir-tooling code that is used within this example project may lack behind the most current version of their base repositories of mmir-lib and mmir-tooling. -------------- Change Log -------------- ################## Version 7.0.1 ################## BUGFIX: * ttsWebspeech: HACK for Chrome BUG (https://issues.chromium.org/issues/41294170) that causes SpeechSynthesis utterances to stop after ~ 15 secs WORKAROUND: pause() & immediately resume() in regular intervals seems to circumvent the problem ################## Version 7.0.0 ################## IMPROVE: * languageManager: * update `mmir.conf` with selected language * listen to `mmir.conf` changes for language setting & update language in `mmir.lang` accordingly BUGFIX: * webspeechAudioInput: fixed invalid placeholder function name `failureCallback` -> `failureCallBack` * ttsWebspeech: fixed search/filtering for voice selection * added simple check for exact voice-name match * added RegExp escaping for matching/filtering voice-name via RegExp: i.e. escape special RegExp character when converting voice-name to filter-RegExp, adapapted from MIT License, Copyright (c) Sindre Sorhus (https://sindresorhus.com), https://github.com/sindresorhus/escape-string-regexp ################## Version 7.0.0-beta6 ################## FIX: * webAudioInput: HACK for handling case the `SpeechRecognition.stop()` does not actually stop if called shortly after `SpeechRecognition.start()` was invoked (tested in `Chrome` v94.x): WORKAROUND: detect, if `SpeechRecognition.start()` was called shortly before `stopRecord()` is called (currently 60 ms), and if so, do trigger `SpeechRecognition.stop()` delayed BUGFIX: * state engineConfig: remove superfluous comma/argument for debug output for printing active state events ################## Version 7.0.0-beta5 ################## BUGFIX: * typings: use string typings for log-config field names in LogLevelOptions ################## Version 7.0.0-beta4 ################## MODIFICATION: * languageManager.getLanguageConfig(): use current language code as fallback if field "language" is missing * storageUtils: set file-format version to 5 (due to BUGFIX for views; see below) NOTE: generated views should be recompiled after updating to this library version BUGFIX: * languageManager.getResourceUri("dictionary" | "speechConfig" | "grammar"): do support resource loading of of ES modules with default export * storageUtils & views: FIXED stringify()-methods for views: do use storageUtils.getCodeWrapSuffix() correctly (and removed outdated interanl constant STORAGE_CODE_WRAP_SUFFIX) ################## Version 7.0.0-beta3 ################## REMOVED: * [BREAKING CHANGE] in manager/dialog: moved factory method for cordova-plugin based event queue to plugin itself if cordova-plugin base event queue is used, it may cause errors if mmir is initialized before cordova plugin is available WORKAROUND: wait for initialization of cordova before initializing mmir ADDITION: * env/media/cordovaAudio: added support for `getWAVAsAudio()` for `cordova` environment BUGFIX: * env/media/cordovaAudio: fixed `playWAV()` for `cordova` environment: do not try to create `Media(Blob -> DataUrl, ...)`, but create & temporary file instead (analogous to new `getWAVAsAudio()` implementation) * env/media/webAudio: fixed `getWAVAsAudio()` for `web` environment: do release data-blob handle if audio was prematurely released * mediaManager: added missing placeholder/proxy function for audio output API method `getWAVAsAudio()` ################## Version 7.0.0-beta2 ################## MODIFICATION: * lib/vendor: updated/recompiled vendor libraries * mvc/parser/gen: recompiled view parser libraries * improved API docs for mediaManager and scion queue worker ################## Version 7.0.0-beta1 ################## REMOVED: * [BREAKING CHANGE] in env/media/audiotts: * removed backwards-compatiblity for deprecated hook `plugin.setMediaManager()` (plugins must require `mediaManager` directly instead, e.g. `mmir.require('mmirf/mediaManager')`) * [BREAKING CHANGE] in mediaManager: removed method `mediaManager._get_mmir()` plugins should require mmir instance instead, e.g. ``` define(['core'], function(mmir){ // -> use mmir instance }) ``` MODIFICATION: * [BREAKING CHANGE] mediaManager: * changed initialization interface for media plugins (i.e. signature for exported factory function): `initialize: function(callBack, mediaManager, ctxId, moduleConfig)` -> `initialize: function(callBack, ctxId, moduleConfig)` does not pass in the mediaManager instance as second argument anymore (if needed by the plugin, it should `require` it) * renamed method `mediaManager.loadFile(..)` -> `mediaManager.loadPlugin(..)` * [BREAKING CHANGE] env/media/audiotts: * audiotts plugin implementations now need to return a factory function (not the plugin object itself): `factory(logger)` (the `logger` argument is a logger instance that can be used during its intialization; after initialization it should request a dedicated logger instance via exposing the hook `getLogger()`) * adapted env/media/ttsMary and env/media/ttsWebspeech plugin implementations according to new factory-interface of audiotts * [BREAKING CHANGE] configurationManager: * for configurationManager.get(): the meaning of optional third argument is changed from `useSafeAccess` to `setAsDefaultIfUnset` support for "unsafe access" is dropped (i.e. throwing an exception if configuration path is not available); instead the third argument is interpreted as "set specified default value, if there is not value (i.e. undefined) set yet" * initialization of configurationManager is now asynchronous: in order to avoid using synchronous XHR requests (for loading configuration data) the initialization is now done asynchronously. This change can be ignored, if access to the `configurationManager` is done, after `mmir.ready()` has been fired, or initialization interfaces (e.g. for media plugins) are used. Otherwise, `configurationManager.init()` will return a promise that is revolved upon its initialization ``` require('mmirf/configurationManager').init().then(function(){ //-> now configuration data is loaded }) ``` * for configurationManager.get(path, ...) / get(path, ...) / set(path, ...): in case `path` is an `Array` its entries are not further processed support for processing string-entries that contain dot-seprating notation is dropped, i.e. ``` mmir.conf.get(['dot', 'separated.path'], ...); //-> path evaluates to: ['dot', 'separated.path'] instead of ['dot', 'separated', 'path'] ``` If processing of path-Arrays with string-entries that contain dot-seprating notation is required, use (new) helper method `toPath(stringOrArray)`: ``` mmir.conf.get(mmir.toPath(['dot', 'separated.path']), ...); //-> mmir.toPath(['dot', 'separated.path']) -> ['dot', 'separated', 'path'] ``` * for configurationManager.on() / configurationManager.addListener(): the 3rd argument `path` is now an `Array` of strings, instead of a (dot-seperated) property-path string (where the last entry of the `Array` is the property name itself) ``` // old interface: ConfigurationChangeListener(newValue: any, oldValue: any, propertyName: string) => void // -> new interface: ConfigurationChangeListener(newValue: any, oldValue: any, propertyName: string[]) => void ``` * manager/dialog: changed implementation for WebWorker based event queuing: only use 1 Worker instance for all dialog engines (instead of one Worker per dialog engine) * env/view/viewLoader: changed internal `isUpToDate(...)` to use asynchronous XHR requests ADDITION: * mediaManager: support non-function/disabled result when loading media-plugins * expose field `mediaManager.plugins` of all loaded media plugins * extended plugin interface initialized-callback: function(exportedFunctions) -> function(exportedFunctions, /*optional: */nonFunctionalInfo) * provide conveinance methods for generating stub-functions for non-functional/disabled media plugin interfaces (i.e. functions that invoke a provided error callback or log the error, see docs) * update/set field mediaManager.plugins[i].disabled in case plugin reports that it is non-function/disabled * mediaManager and env/media/: added (optional) interface methods for audio-input-plugins (i.e. speech recogntion plugins) * `destroyRecogntion: (successCallback?: (didDestroy: boolean) => void,failureCallback?: Function) => void`: destroys speech recognition instance * `initializeRecogntion: (successCallback?: (didInitialize: boolean) => void,failureCallback?: Function) => void`: re-initialized speech recognition instance * the success callback for speech recognition (i.e. for `recognize(..)`, `startRecord(..)`, `stopRecord(..)`) now supports an optional fifth argument `custom`: the argument is dependent on the ASR engine / plugin, that is, a specific implementation may return some custom results via this argument * mediaManager and env/media/: added (optional) interface methods for audio-output-plugins (i.e. speech synthesis plugins) * `destroySpeech: (successCallback?: (didDestroy: boolean) => void,failureCallback?: Function) => void`: destroys speech synthesis instance * `initializeSpeech: (successCallback?: (didInitialize: boolean) => void,failureCallback?: Function) => void`: re-initialized speech synthesis instance * eventEmitter: support event handlers / hooks for functions set an the thisArgument with "on", by setting optional constructor argument enableHooks to true * configurationManager: * added optional third argument `emitOnAdding` (`boolean`) for `configurationManager.on()` and `configurationManager.addListener()`: if `true` immediately fires listener with current value after adding it. * added converter method `getNumber()` (works analogous to `getString()` and `getBoolean()`) * configurationManager.set(): now returns the newly set value * mmirf/events: added extension module mmirf/events/propertyHandler that attaches a function to the EventEmitter class for creating event handler properties, e.g. ``` var EventEmitter = mmir.require('mmirf/events/propertyHandler'); var emitter = new EventEmitter(); emitter.createEventHandlerProperty('SoundStart'); context.onsoundstart = function(){ console.log('sound has started') }; ``` BUGFIX: * env/media/micLevelsAnalysis: * fixed compatibility for detecting & invoking getUserMedia(): do handle deprecation of navigator.getUserMedia() * do handle case that that plugin is non-functional (e.g. due to missing getUserMedia()) ################## Version 6.2.0 ################## MODIFICATION: * tools/codeGenUtils: added helper tools/codeGenUtils and extracted closure-wrapper functionality for generated code to it (e.g. for generated grammars and views) * mmirf/parserModule: breaking internal change due to removed constants STORAGE_CODE_WRAP_PREFIX and STORAGE_CODE_WRAP_SUFFIX from mmirf/parserModule, replaced by functions getCodeWrapPrefix() and getCodeWrapSuffix() * views: * mvc/view etc: added optional argument disableStrictMode (boolean) to stringify() interface method * explicitly make generated view-code strict (i.e. JavaScript strict mode) * increment STORAGE_FILE_FORMAT_NUMBER to 4 * grammars: * added optional argument option disableStrict (boolean) for generating grammars * jison-engine: update jison version to 0.4.18 (in order to support JavaScript strict mode) * explicitly make generated grammar-code strict (i.e. JavaScript strict mode) * increment GRAMMAR_FILE_FORMAT_VERSION to 7 * languageManager.setLanguage(): now sets changes "language" setting in/with configurationManager.set("language", ...) which will also trigger a configuration change event * mediaManager.getVoices({details: true}): added property `local?: boolean` in returned `VoiceDetails`, indicating if the voices is locally availabe or only via network connection * added support for `VoiceDetails.local` in built-in TTS engines `ttsWebspeech` and `ttsMary` * typings: * `DialogManager`, `InputManager`: normalized typings by declaring and extending base interfaces `StateManager` * `DialogEngine`, `InputEngine`: normalized typings by declaring and extending base interfaces `StateEngine` ADDITION: * logger: added new optional last argument `reverseCallStack?: number` to all logging/printing function, e.g. ```javascript debug: function(className, funcName, msg, reverseCallStack) ``` the optional _offset_ when printing the callstack position/information: a positive number will go further back/up the callstack. This can be used in logging-helper functions to select the invoking function's position from the callstack instead of printing the information of the logging-helper function itself. * typings: * added typing for `mmirf/checksumUtils` (interface `ChecksumUtils`) * added typing for `mmirf/logger` (interfaces `LoggerModule` and `Logger`) BUGFIX: * mediaManager: do evaluate options when trying to invoke error-handler for not-implemented functions * semantic/positionUtils: in _createPosPreProc(), removed undeclared variable sourcePos and fixed handling pos flag for enabling position calculation * env/media/webMicLevels: do declare local variable db * env/media/ttsWebspeech: when selecting voice by filter, do ensure that language corresponds to currently selected voice * logger: shortcut functions (e.g. `d()` for `debug()`) now print the correct invoking function information * typings: * do declare constructor for GrammarConverter and IAudio * fixed declaration for ConfigurationManager.on/.off/.addListener/.removeListener * fixed typing for NodeMmirModule.init() method * fixed typing for Grammar: make deprecated field stop_word optional * fixed typing for MediaManagerPluginEntry: added missing (optional) property `config` * semantic/grammarConverter: remove undeclared (and unused) variable `replLen` in `removeStopwords()` ################## Version 6.1.0 ################## ADDITION: * tools/events: * extendend method EventEmitter.get() to return list of event types (to which listeners are registered) if no event type argument is given * added EventEmitter.destroy() method * env/media/ttsMary: added support for filter options when querying voice list * env/media: added TTS module "ttsWebspeech" for audiotts that utilizes the HTML5 API SpeechSynthesis for TTS * usage example in "browser" environment (in configuration.json): ... "mediaManager": { "plugins": { "browser": [ ... {"mod": "audiotts", "config": "ttsWebspeech", "type": "tts"} ... * tools/resources: added 2nd optional argument isReset (boolean) for mmir.res.init(envParam, isReset) for resetting the resources path to their default value, before (re-) initializing the resources MODIFICATION: * util_jquery/toArray: switched implementation from jQuery.makeArray to Array.from due to more universal conversion applicability (if needed, shim for Array.from is included in vendor libraries) * tools/parseParamsToDictionary and commonUtils.parseParamsToDictionary(): * refactored params dictionary implementation to handle colliding URL parameter names (e.g. colliding with functions defined on the dictionary object) * only add URL parameter value as multiple, if the same value was not already specified, e.g. for "?key1=1&key1=1", "key1" will not be treated as multiple * changed internal (i.e. private) handling for is-mulitiple marker and keys fieldname by adding prefix "_" to the field names BUGFIX * logger: correctly parse and apply core.logLevel setting if options object with {logLevel: STRING | NUMBER} is used * tools/eventEmitter: use correct module IDs "mmirf/util/isArray" and "mmirf/util/toArray" (instead of "mmirf/util//...") * tools/resources: fix handling for platform/environment specific, detected base-path w.r.t. adjusting the framework base path ################## Version 6.0.0 ################## The resolution for the acronym MMIR has been changed to _Mobile Multimodal Interaction and Relay_ framework, to account for the changed focus of the framework: more precisely, that _Rendering_ is not considered an important part of the framework anymore. This means, that no new features will be added to the built-in template rendering engine and is condidred _deprecated_, i.e. support/integration for the built-in rendering engine may be dropped in one of the future major version updates. GENERAL NOTE: Switched mmir-related GitHub dependencies to npm depedencies for mmir packages, e.g. "mmir-lib": "git+https://github.com/mmig/mmir-lib.git" -> "^6.0.0" "mmir-tooling": "git+https://github.com/mmig/mmir-tooling.git" -> "^6.0.0" ... ADDITION: * semanticInterpreter: * added applyPreProcessing(..): convenience method for function GrammarConverter.preproc(..) * replacement for deprecated function removeStopwords(..) * added function addProcessing(..): convenience method for new function GrammarConverter.addProc(..) addProcessing(langCode, processingStep, indexOrIsPrepend, callback) * added isPreProcessPositionsEnabled() and setPreProcessPositionsEnabled(enabled): for enabling/disabling calculation for position-modifications during pre-processing DEFAULT setting: enabled * semantic/stemmer: added option allowUmlauts to allow preventing "normalizing" umlauts * grammar.json: additional (optional) field "example_phrases" (string | Array) for including example phrases that should be recognized by the grammar * added commonUtils.getCompiledResourcesIds(..): helper for extracting the ID from compiled resources * automated support for async grammar execution (in WebWorker): * fix support for async grammar execution & added support for webpack built * added configuration setting "grammarAsyncExecMode": * true: will initialize all compiled grammars for async execution * Array: list of grammar IDs (for compiled grammars) that will be initialized for async execution, or list with entries that MUST have field id (i.e. the grammar ID) and optionally a phrase that will be executed immediately after initalizing the async-exec grammar * added optional argument grammarCode for asyncGrammar.init(..): support initializing async-exec grammar by specifying (JavaScript) grammar-code that will be evaluated withing the async-exec WebWorker (instead of loading compiled grammar) * added "destroy" functionality to asyncGrammar for terminating its WebWorker (can be restarted by initialing again) * languageManager.setLanguage(): added optional 2nd parameter doNotLoadResources: if omitted or TRUTHY will only change current language code, but will not try to load language resources (e.g. dictionary, speech configuration, and grammar), if false will force (re-) loading the language resources * env/media/audiotts: added support / API function for implementation to supply destroy function via implementing getDestroyFunc(): function(callbackFunc(err|null)) * configurationManager: added on()/addListener() and off()/removeListener() for listening to configuration-value changes * core.logLevel: additionally allow log-level options object for configuring log-levels LogLevelOptions: {level?: LogLevel, levels?: {[logLevel: LogLevel]: Array}, modules?: {[moduleId: string]: LogLevel}} usage example (all fields are optional); mmir.logLevel = { level: 'info', //default: "debug" levels: { // LogLevel -> list of module IDs 3: ['mmirf/notificationManager', 'mmirf/commonUtils'], verbose: ['mmirf/semanticInterpreter'] }, modules: { // moduleId -> LogLevel 'mmirf/controller': 'verbose', 'webspeechAudioInput': 2 } }; REFACTOR: * configurationManager: improved implementation for get(..) and set(..) * env/grammar/*Generator: extracted common parsing-/generator-functionality into new module mmirf/baseGen MODIFICATION: * semanticInterpreter (backwards compatible via module 'mmirf/core4Compatibility'): * removeStopwords(..): removed un-documented/internal third argument for using custom stopword removal function * deprecated function removeStopwords(..): should use (new) function applyPreProcessing(..) instead * use of this function will cause warning message * grammarConverter (backwards compatible via module 'mmirf/core4Compatibility'): * modified Positions object: renamed field "str" -> "text", ie. {text: string, pos: Array} * normalized return values for to return string if computePositions is false, otherwise return Positions object: removeStopwords(), maskString(), unmaskString(), maskAsUnicode() (and internally: recodeJSON()) * grammarConverter.removeStopwords: * changed signature: second (optional) in/out argument from positions (Array) to computePositions (boolean) * changed return value: if computePositions is false, return string, otherwise Position * renamed (internal) field jscc_grammar_definition -> grammar_definition NOTE: getter-method getGrammarDef() is unchanged * removed fields from grammerConverter (moved to env/grammar/baseGenerator): variable_prefix, variable_regexp, entry_token_field, entry_index_field, enc_regexp_str * removed methods from grammerConverter (moved to env/grammar/baseGenerator): getCodeWrapPrefix(..), getCodeWrapSuffix(..) * generalized preproc(..) and postproc(..) for allowing custom pre-/post-processing steps/chains * added addProc(..), removeProc(..), getProcIndex(..) and field procList for handeling default pre-/post-processing steps as well as custom steps * added positionUtils with factory methods for wraping functions, e.g. handeling position-modification in pre-/post-processing steps * preproc(): modified signature preproc(thePhrase, pos, maskFunc, stopwordFunc) -> preproc(thePhrase, pos) * use addProc(..), removeProc(..) instead of additional/optional arguments maskFunc, stopwordFunc, OR use compatibility mode * postproc(): modified signature postproc(procResult, recodeFunc) -> preproc(procResult, pos) * use addProc(..), removeProc(..) instead of additional/optional argument recodeFunc OR use compatibility mode * grammar.json: deprecated field "stop_word" and "example_phrase" * deprecated field "stop_word" in JSON grammar format: use field "stopwords" instead * use of this field will cause warning message * deprecated field "example_phrase" in JSON grammar format: use field "example_phrases" instead * mediaManager._fireEvent: deprecated _fireEvent(eventName, argList), should use new method _emitEvent(eventName, ...args) instead * util_purejs/toArray: using Array.from implementation now instead of custom code (if needed, shim for Array.from is included in vendor libraries) * REMOVED un-used script env/node/nodeLoadScript.js * improved compatibility for node environment: * [BREAKING CHANGE] export extended core module of mmir, instead of a wrapper object * renamed field mmirLib.config -> mmirLib._config * renamed field mmirLib.requirejs -> mmirLib._requirejs * NOTE mmirLib.init() will extend the mmirLib instance itself (which is the extended core instance, see typing of NodeMmirModule) * [BREAKING CHANGE] removed internal & unused module tools/emma: now included in mmir-plugin-speech-io BUGFIX: * mediaManager.stopRecord: FIX default implementation, incorrect parameter-name successCallback -> statusCallback * grammarConverter.maskAsUnicode: * added optional argument computePositions (boolean) * FIX call maskString() with correct signature * commonUtils.loadImpl(librariesPath, ...): FIX case that librariesPath (string) has not entry in directories.json * env/grammar/jsccAsyncGenerator: FIX handling of error message from web-worker * env/grammar/asyncGenerator & workers/*Compiler: FIX relative-path-processing for loading scripts by workers when mmir-lib base URL (core._mmirLibPath) is set to custom path * env/grammar/jisonGenerator and env/grammar/pegjsGenerator: FIX handling for semantics-variables for phrases and tokens -> must handle as list NOT as dictionary * env/grammar/jisonGenerator: must manually reset phrase-/token-variables before running grammar/parse * added missing typings for commonUtils.listDir() and resources.getGeneratedStateModelsPath() * worker/scionQueueWorker: added compatibility for invoking postMessage in node environment * env/grammar/asyncCompiler, asyncGrammar, dialog/engineConfig: do correctly register worker.onmessage for browser & node environment (via added tools/asyncUtils) * [BREAKING CHANGE] do not expect file-names for compiled grammars to have suffix "_grammar.js": * commonUtils.getCompiledGrammarPath and languageManager.doCheckExistsGrammar: do interpret complete file-name (without extension) as grammar ID (i.e. no name-suffix parsing using "_") * fix behavior for setting "ignoreGrammarFiles" (Array in configuration.json) and its handling in commonUtils.loadCompiledGrammars(..., ignoreGrammarIds: Array): removed old-style filtering that would expect suffix "_grammar.js" in generated grammars files when comparing ignore-grammar-IDs with file-names -> now expects file-names (minus file-extension) to exactly match the grammar IDs (as this is the new naming scheme for generated grammar files since mmir v5.x) NOTE: this is not backwards compatible for generated grammars files with mmir v4.x RESOLUTION: recompile grammars with mmir (mmir-tooling) v5.x * [BREAKING CHANGE] languageManager: * loadDictionary() and loadSpeechConfig() will not change the current language anymore, use setLanguage() instead * on setLanguage() only load dictionary and speech configuration if they exists (i.e. if there are corresponding entries in directories.json) * [BREAKING CHANGE] worker/scionQueueWorker: for consistency, renamed file workers/ScionQueueWorker.js -> workers/scionQueueWorker.js * [BREAKING CHANGE] core.logTrace: if options object, do treat missing field trace same as default for logTrace, i.e. TRUE (instead of FALSE as before when options object was used) ################## Version 5.2.0 ################## ADDITION: * commonUtils: loadScript() now parses for (internal) "require://" protocol and loads require:// resources via require() call instead of using getLocalScript() (which uses preinit.js: change paths -> remove leading '../' from requirejs module-ID declarations app.js: mmir.ready(function () {mmir.require(['core3Compatibility'], function(core3Compatibility){ ... }); ----------------- [starter-kit backward compat settting] ----------------- ----------------- < Migration Guide > ----------------- > see also migration resources at (T.B.D.) > https://github.com/mmig/mmir-migration/ update build-resources: * replace build/ directory with new mmir-tooling resources * follow the instructions of the mmir-tooling README, or for short: * install gulp-cli (`npm install -g gulp-cli`) * execute `npm install` in build/ * run `gulp` in build/ update web-resources: * replace /mmirf/ directory with new mmir-lib resources * delete /gen/ directory * if the app uses require(): due to the changed baseUrl configuration, the paths may have changed: instead of require('../appjs/some-script') [OLD] use require('./appjs/some-script') [NEW] or require('appjs/some-script') [NEW] * if the app uses jQuery: jQuery does not ship with mmir-lib anymore, i.e. needs to added separately, if it is required (e.g. insert