1 |
efrain |
1 |
{"version":3,"file":"tool_configure_controller.min.js","sources":["../src/tool_configure_controller.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Standard Ajax wrapper for Moodle. It calls the central Ajax script,\n * which can call any existing webservice using the current session.\n * In addition, it can batch multiple requests and return multiple responses.\n *\n * @module mod_lti/tool_configure_controller\n * @copyright 2015 Ryan Wyllie <ryan@moodle.com>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n * @since 3.1\n */\ndefine(['jquery', 'core/ajax', 'core/paged_content_factory', 'core/notification', 'core/templates', 'mod_lti/events',\n 'mod_lti/keys', 'mod_lti/tool_types_and_proxies', 'mod_lti/tool_type', 'mod_lti/tool_proxy', 'core/str', 'core/config'],\n function($, ajax,\n pagedContentFactory, notification, templates, ltiEvents, KEYS,\n toolTypesAndProxies, toolType, toolProxy, str, config) {\n\n var SELECTORS = {\n EXTERNAL_REGISTRATION_CONTAINER: '#external-registration-container',\n EXTERNAL_REGISTRATION_PAGE_CONTAINER: '#external-registration-page-container',\n EXTERNAL_REGISTRATION_TEMPLATE_CONTAINER: '#external-registration-template-container',\n CARTRIDGE_REGISTRATION_CONTAINER: '#cartridge-registration-container',\n CARTRIDGE_REGISTRATION_FORM: '#cartridge-registration-form',\n ADD_TOOL_FORM: '#add-tool-form',\n TOOL_CARD_CONTAINER: '#tool-card-container',\n TOOL_LIST_CONTAINER: '#tool-list-container',\n TOOL_CREATE_BUTTON: '#tool-create-button',\n TOOL_CREATE_LTILEGACY_BUTTON: '#tool-createltilegacy-button',\n REGISTRATION_CHOICE_CONTAINER: '#registration-choice-container',\n TOOL_URL: '#tool-url'\n };\n\n /**\n * Get the tool list container element.\n *\n * @method getToolListContainer\n * @private\n * @return {Object} jQuery object\n */\n var getToolListContainer = function() {\n return $(SELECTORS.TOOL_LIST_CONTAINER);\n };\n\n /**\n * Get the tool card container element.\n *\n * @method getToolCardContainer\n * @private\n * @return {Object} jQuery object\n */\n const getToolCardContainer = function() {\n return $(SELECTORS.TOOL_CARD_CONTAINER);\n };\n\n /**\n * Get the external registration container element.\n *\n * @method getExternalRegistrationContainer\n * @private\n * @return {Object} jQuery object\n */\n var getExternalRegistrationContainer = function() {\n return $(SELECTORS.EXTERNAL_REGISTRATION_CONTAINER);\n };\n\n /**\n * Get the cartridge registration container element.\n *\n * @method getCartridgeRegistrationContainer\n * @private\n * @return {Object} jQuery object\n */\n var getCartridgeRegistrationContainer = function() {\n return $(SELECTORS.CARTRIDGE_REGISTRATION_CONTAINER);\n };\n\n /**\n * Get the registration choice container element.\n *\n * @method getRegistrationChoiceContainer\n * @private\n * @return {Object} jQuery object\n */\n var getRegistrationChoiceContainer = function() {\n return $(SELECTORS.REGISTRATION_CHOICE_CONTAINER);\n };\n\n /**\n * Close the LTI Advantage Registration IFrame.\n *\n * @private\n * @param {Object} e post message event sent from the registration frame.\n */\n var closeLTIAdvRegistration = function(e) {\n if (e.data && 'org.imsglobal.lti.close' === e.data.subject) {\n $(SELECTORS.EXTERNAL_REGISTRATION_TEMPLATE_CONTAINER).empty();\n hideExternalRegistration();\n showRegistrationChoices();\n showToolList();\n showRegistrationChoices();\n reloadToolList();\n }\n };\n\n /**\n * Load the external registration template and render it in the DOM and display it.\n *\n * @method initiateRegistration\n * @private\n * @param {String} url where to send the registration request\n */\n var initiateRegistration = function(url) {\n // Show the external registration page in an iframe.\n $(SELECTORS.EXTERNAL_REGISTRATION_PAGE_CONTAINER).removeClass('hidden');\n var container = $(SELECTORS.EXTERNAL_REGISTRATION_TEMPLATE_CONTAINER);\n container.append($(\"<iframe src='startltiadvregistration.php?url=\"\n + encodeURIComponent(url) + \"&sesskey=\" + config.sesskey + \"'></iframe>\"));\n showExternalRegistration();\n window.addEventListener(\"message\", closeLTIAdvRegistration, false);\n };\n\n /**\n * Get the tool type URL.\n *\n * @method getToolURL\n * @private\n * @return {String} the tool type url\n */\n var getToolURL = function() {\n return $(SELECTORS.TOOL_URL).val();\n };\n\n /**\n * Hide the external registration container.\n *\n * @method hideExternalRegistration\n * @private\n */\n var hideExternalRegistration = function() {\n getExternalRegistrationContainer().addClass('hidden');\n };\n\n /**\n * Hide the cartridge registration container.\n *\n * @method hideCartridgeRegistration\n * @private\n */\n var hideCartridgeRegistration = function() {\n getCartridgeRegistrationContainer().addClass('hidden');\n };\n\n /**\n * Hide the registration choice container.\n *\n * @method hideRegistrationChoices\n * @private\n */\n var hideRegistrationChoices = function() {\n getRegistrationChoiceContainer().addClass('hidden');\n };\n\n /**\n * Display the external registration panel and hides the other\n * panels.\n *\n * @method showExternalRegistration\n * @private\n */\n var showExternalRegistration = function() {\n hideCartridgeRegistration();\n hideRegistrationChoices();\n getExternalRegistrationContainer().removeClass('hidden');\n screenReaderAnnounce(getExternalRegistrationContainer());\n };\n\n /**\n * Display the cartridge registration panel and hides the other\n * panels.\n *\n * @method showCartridgeRegistration\n * @param {String} url\n * @private\n */\n var showCartridgeRegistration = function(url) {\n hideExternalRegistration();\n hideRegistrationChoices();\n // Don't save the key and secret from the last tool.\n var container = getCartridgeRegistrationContainer();\n container.find('input').val('');\n container.removeClass('hidden');\n container.find(SELECTORS.CARTRIDGE_REGISTRATION_FORM).attr('data-cartridge-url', url);\n screenReaderAnnounce(container);\n };\n\n /**\n * Display the registration choices panel and hides the other\n * panels.\n *\n * @method showRegistrationChoices\n * @private\n */\n var showRegistrationChoices = function() {\n hideExternalRegistration();\n hideCartridgeRegistration();\n getRegistrationChoiceContainer().removeClass('hidden');\n screenReaderAnnounce(getRegistrationChoiceContainer());\n };\n\n /**\n * JAWS does not notice visibility changes with aria-live.\n * Remove and add the content back to force it to read it out.\n * This function can be removed once JAWS supports visibility.\n *\n * @method screenReaderAnnounce\n * @param {Object} element\n * @private\n */\n var screenReaderAnnounce = function(element) {\n var children = element.children().detach();\n children.appendTo(element);\n };\n\n /**\n * Hides the list of tool types.\n *\n * @method hideToolList\n * @private\n */\n var hideToolList = function() {\n getToolListContainer().addClass('hidden');\n };\n\n /**\n * Display the list of tool types.\n *\n * @method hideToolList\n * @private\n */\n var showToolList = function() {\n getToolListContainer().removeClass('hidden');\n };\n\n /**\n * Display the registration feedback alert and hide the other panels.\n *\n * @method showRegistrationFeedback\n * @param {Object} data\n * @private\n */\n var showRegistrationFeedback = function(data) {\n var type = data.error ? 'error' : 'success';\n notification.addNotification({\n message: data.message,\n type: type\n });\n };\n\n /**\n * Show the loading animation\n *\n * @method startLoading\n * @private\n * @param {Object} element jQuery object\n */\n var startLoading = function(element) {\n element.addClass(\"loading\");\n };\n\n /**\n * Hide the loading animation\n *\n * @method stopLoading\n * @private\n * @param {Object} element jQuery object\n */\n var stopLoading = function(element) {\n element.removeClass(\"loading\");\n };\n\n /**\n * Refresh the list of tool types and render the new ones.\n *\n * @method reloadToolList\n * @private\n */\n var reloadToolList = function() {\n // Behat tests should wait for the tool list to load.\n M.util.js_pending('reloadToolList');\n\n const cardContainer = getToolCardContainer();\n const listContainer = getToolListContainer();\n const limit = 60;\n // Get initial data with zero limit and offset.\n fetchToolCount().done(function(data) {\n pagedContentFactory.createWithTotalAndLimit(\n data.count,\n limit,\n function(pagesData) {\n return pagesData.map(function(pageData) {\n return fetchToolData(pageData.limit, pageData.offset)\n .then(function(data) {\n return renderToolData(data);\n });\n });\n },\n {\n 'showFirstLast': true\n })\n .done(function(html, js) {\n // Add the paged content into the page.\n templates.replaceNodeContents(cardContainer, html, js);\n })\n .always(function() {\n stopLoading(listContainer);\n M.util.js_complete('reloadToolList');\n });\n });\n startLoading(listContainer);\n };\n\n /**\n * Fetch the count of tool type and proxy datasets.\n *\n * @return {*|void}\n */\n const fetchToolCount = function() {\n return toolTypesAndProxies.count({'orphanedonly': true})\n .done(function(data) {\n return data;\n }).catch(function(error) {\n // Add debug message, then return empty data.\n notification.exception(error);\n return {\n 'count': 0\n };\n });\n };\n\n /**\n * Fetch the data for tool type and proxy cards.\n *\n * @param {number} limit Maximum number of datasets to get.\n * @param {number} offset Offset count for fetching the data.\n * @return {*|void}\n */\n const fetchToolData = function(limit, offset) {\n const args = {'orphanedonly': true};\n // Only add limit and offset to args if they are integers and not null, otherwise defaults will be used.\n if (limit !== null && !Number.isNaN(limit)) {\n args.limit = limit;\n }\n if (offset !== null && !Number.isNaN(offset)) {\n args.offset = offset;\n }\n return toolTypesAndProxies.query(args)\n .done(function(data) {\n return data;\n }).catch(function(error) {\n // Add debug message, then return empty data.\n notification.exception(error);\n return {\n 'types': [],\n 'proxies': [],\n 'limit': limit,\n 'offset': offset\n };\n });\n };\n\n /**\n * Render Tool and Proxy cards from data.\n *\n * @param {Object} data Contains arrays of data objects to populate cards.\n * @return {*}\n */\n const renderToolData = function(data) {\n const context = {\n tools: data.types,\n proxies: data.proxies,\n };\n return templates.render('mod_lti/tool_list', context)\n .done(function(html, js) {\n return {html, js};\n }\n );\n };\n\n /**\n * Start the LTI Advantage registration.\n *\n * @method addLTIAdvTool\n * @private\n */\n var addLTIAdvTool = function() {\n var url = getToolURL().trim();\n\n if (url) {\n $(SELECTORS.TOOL_URL).val('');\n hideToolList();\n initiateRegistration(url);\n }\n\n };\n\n /**\n * Trigger appropriate registration process process for the user input\n * URL. It can either be a cartridge or a registration url.\n *\n * @method addLTILegacyTool\n * @private\n * @return {Promise} jQuery Deferred object\n */\n var addLTILegacyTool = function() {\n var url = getToolURL().trim();\n\n if (url === \"\") {\n return $.Deferred().resolve();\n }\n var toolButton = $(SELECTORS.TOOL_CREATE_LTILEGACY_BUTTON);\n startLoading(toolButton);\n\n var promise = toolType.isCartridge(url);\n\n promise.always(function() {\n stopLoading(toolButton);\n });\n\n promise.done(function(result) {\n if (result.iscartridge) {\n $(SELECTORS.TOOL_URL).val('');\n $(document).trigger(ltiEvents.START_CARTRIDGE_REGISTRATION, url);\n } else {\n $(document).trigger(ltiEvents.START_EXTERNAL_REGISTRATION, {url: url});\n }\n });\n\n promise.fail(function() {\n str.get_string('errorbadurl', 'mod_lti')\n .done(function(s) {\n $(document).trigger(ltiEvents.REGISTRATION_FEEDBACK, {\n message: s,\n error: true\n });\n })\n .fail(notification.exception);\n });\n\n return promise;\n };\n\n /**\n * Sets up the listeners for user interaction on the page.\n *\n * @method registerEventListeners\n * @private\n */\n var registerEventListeners = function() {\n\n // These are events fired by the registration processes. Either\n // the cartridge registration or the external registration url.\n $(document).on(ltiEvents.NEW_TOOL_TYPE, function() {\n reloadToolList();\n });\n\n $(document).on(ltiEvents.START_EXTERNAL_REGISTRATION, function() {\n showExternalRegistration();\n $(SELECTORS.TOOL_URL).val('');\n hideToolList();\n });\n\n $(document).on(ltiEvents.STOP_EXTERNAL_REGISTRATION, function() {\n showToolList();\n showRegistrationChoices();\n });\n\n $(document).on(ltiEvents.START_CARTRIDGE_REGISTRATION, function(event, url) {\n showCartridgeRegistration(url);\n });\n\n $(document).on(ltiEvents.STOP_CARTRIDGE_REGISTRATION, function() {\n getCartridgeRegistrationContainer().find(SELECTORS.CARTRIDGE_REGISTRATION_FORM).removeAttr('data-cartridge-url');\n showRegistrationChoices();\n });\n\n $(document).on(ltiEvents.REGISTRATION_FEEDBACK, function(event, data) {\n showRegistrationFeedback(data);\n });\n\n var addLegacyButton = $(SELECTORS.TOOL_CREATE_LTILEGACY_BUTTON);\n addLegacyButton.click(function(e) {\n e.preventDefault();\n addLTILegacyTool();\n });\n\n var addLTIButton = $(SELECTORS.TOOL_CREATE_BUTTON);\n addLTIButton.click(function(e) {\n e.preventDefault();\n addLTIAdvTool();\n });\n\n };\n\n return /** @alias module:mod_lti/cartridge_registration_form */ {\n\n /**\n * Initialise this module.\n */\n init: function() {\n registerEventListeners();\n reloadToolList();\n }\n };\n});\n"],"names":["define","$","ajax","pagedContentFactory","notification","templates","ltiEvents","KEYS","toolTypesAndProxies","toolType","toolProxy","str","config","SELECTORS","getToolListContainer","getExternalRegistrationContainer","getCartridgeRegistrationContainer","getRegistrationChoiceContainer","closeLTIAdvRegistration","e","data","subject","empty","hideExternalRegistration","showRegistrationChoices","showToolList","reloadToolList","getToolURL","val","addClass","hideCartridgeRegistration","hideRegistrationChoices","showExternalRegistration","removeClass","screenReaderAnnounce","element","children","detach","appendTo","hideToolList","startLoading","stopLoading","M","util","js_pending","cardContainer","listContainer","fetchToolCount","done","createWithTotalAndLimit","count","pagesData","map","pageData","fetchToolData","limit","offset","then","renderToolData","html","js","replaceNodeContents","always","js_complete","catch","error","exception","args","Number","isNaN","query","context","tools","types","proxies","render","addLTIAdvTool","url","trim","append","encodeURIComponent","sesskey","window","addEventListener","initiateRegistration","registerEventListeners","document","on","NEW_TOOL_TYPE","START_EXTERNAL_REGISTRATION","STOP_EXTERNAL_REGISTRATION","START_CARTRIDGE_REGISTRATION","event","container","find","attr","showCartridgeRegistration","STOP_CARTRIDGE_REGISTRATION","removeAttr","REGISTRATION_FEEDBACK","type","addNotification","message","showRegistrationFeedback","click","preventDefault","Deferred","resolve","toolButton","promise","isCartridge","result","iscartridge","trigger","fail","get_string","s","addLTILegacyTool","init"],"mappings":";;;;;;;;;;AAyBAA,2CAAO,CAAC,SAAU,YAAa,6BAA8B,oBAAqB,iBAAkB,iBAC5F,eAAgB,iCAAkC,oBAAqB,qBAAsB,WAAY,gBACzG,SAASC,EAAGC,KACHC,oBAAqBC,aAAcC,UAAWC,UAAWC,KACzDC,oBAAqBC,SAAUC,UAAWC,IAAKC,YAExDC,0CACiC,mCADjCA,+CAEsC,wCAFtCA,mDAG0C,4CAH1CA,2CAIkC,oCAJlCA,sCAK6B,+BAL7BA,8BAOqB,uBAPrBA,8BAQqB,uBARrBA,6BASoB,sBATpBA,uCAU8B,+BAV9BA,wCAW+B,iCAX/BA,mBAYU,YAUVC,qBAAuB,kBAChBb,EAAEY,oCAqBTE,iCAAmC,kBAC5Bd,EAAEY,4CAUTG,kCAAoC,kBAC7Bf,EAAEY,6CAUTI,+BAAiC,kBAC1BhB,EAAEY,0CASTK,wBAA0B,SAASC,GAC/BA,EAAEC,MAAQ,4BAA8BD,EAAEC,KAAKC,UAC/CpB,EAAEY,oDAAoDS,QACtDC,2BACAC,0BACAC,eACAD,0BACAE,mBA4BJC,WAAa,kBACN1B,EAAEY,oBAAoBe,OAS7BL,yBAA2B,WAC3BR,mCAAmCc,SAAS,WAS5CC,0BAA4B,WAC5Bd,oCAAoCa,SAAS,WAS7CE,wBAA0B,WAC1Bd,iCAAiCY,SAAS,WAU1CG,yBAA2B,WAC3BF,4BACAC,0BACAhB,mCAAmCkB,YAAY,UAC/CC,qBAAqBnB,qCA6BrBS,wBAA0B,WAC1BD,2BACAO,4BACAb,iCAAiCgB,YAAY,UAC7CC,qBAAqBjB,mCAYrBiB,qBAAuB,SAASC,SACjBA,QAAQC,WAAWC,SACzBC,SAASH,UASlBI,aAAe,WACfzB,uBAAuBe,SAAS,WAShCJ,aAAe,WACfX,uBAAuBmB,YAAY,WAyBnCO,aAAe,SAASL,SACxBA,QAAQN,SAAS,YAUjBY,YAAc,SAASN,SACvBA,QAAQF,YAAY,YASpBP,eAAiB,WAEjBgB,EAAEC,KAAKC,WAAW,wBAEZC,cA/OC5C,EAAEY,+BAgPHiC,cAAgBhC,uBAGtBiC,iBAAiBC,MAAK,SAAS5B,MAC3BjB,oBAAoB8C,wBAChB7B,KAAK8B,MAJC,IAMN,SAASC,kBACEA,UAAUC,KAAI,SAASC,iBACnBC,cAAcD,SAASE,MAAOF,SAASG,QACzCC,MAAK,SAASrC,aACJsC,eAAetC,cAItC,gBACqB,IAEpB4B,MAAK,SAASW,KAAMC,IAErBvD,UAAUwD,oBAAoBhB,cAAec,KAAMC,OAElDE,QAAO,WACJrB,YAAYK,eACZJ,EAAEC,KAAKoB,YAAY,wBAG/BvB,aAAaM,sBAQXC,eAAiB,kBACZvC,oBAAoB0C,MAAM,eAAiB,IAC7CF,MAAK,SAAS5B,aACJA,QACR4C,OAAM,SAASC,cAEd7D,aAAa8D,UAAUD,OAChB,OACM,OAYnBX,cAAgB,SAASC,MAAOC,cAC5BW,KAAO,eAAiB,UAEhB,OAAVZ,OAAmBa,OAAOC,MAAMd,SAChCY,KAAKZ,MAAQA,OAEF,OAAXC,QAAoBY,OAAOC,MAAMb,UACjCW,KAAKX,OAASA,QAEXhD,oBAAoB8D,MAAMH,MAC5BnB,MAAK,SAAS5B,aACJA,QACR4C,OAAM,SAASC,cAEd7D,aAAa8D,UAAUD,OAChB,OACM,WACE,SACFV,aACCC,YAWpBE,eAAiB,SAAStC,YACtBmD,QAAU,CACZC,MAAOpD,KAAKqD,MACZC,QAAStD,KAAKsD,gBAEXrE,UAAUsE,OAAO,oBAAqBJ,SACxCvB,MAAK,SAASW,KAAMC,UACN,CAACD,KAAAA,KAAMC,GAAAA,YAW1BgB,cAAgB,eACZC,IAAMlD,aAAamD,OAEnBD,MACA5E,EAAEY,oBAAoBe,IAAI,IAC1BW,eAhSmB,SAASsC,KAEhC5E,EAAEY,gDAAgDoB,YAAY,UAC9ChC,EAAEY,oDACRkE,OAAO9E,EAAE,gDACA+E,mBAAmBH,KAAO,YAAcjE,OAAOqE,QAAU,gBAC5EjD,2BACAkD,OAAOC,iBAAiB,UAAWjE,yBAAyB,GA0RxDkE,CAAqBP,OAyDzBQ,uBAAyB,WAIzBpF,EAAEqF,UAAUC,GAAGjF,UAAUkF,eAAe,WACpC9D,oBAGJzB,EAAEqF,UAAUC,GAAGjF,UAAUmF,6BAA6B,WAClDzD,2BACA/B,EAAEY,oBAAoBe,IAAI,IAC1BW,kBAGJtC,EAAEqF,UAAUC,GAAGjF,UAAUoF,4BAA4B,WACjDjE,eACAD,6BAGJvB,EAAEqF,UAAUC,GAAGjF,UAAUqF,8BAA8B,SAASC,MAAOf,MApS3C,SAASA,KACrCtD,2BACAQ,8BAEI8D,UAAY7E,oCAChB6E,UAAUC,KAAK,SAASlE,IAAI,IAC5BiE,UAAU5D,YAAY,UACtB4D,UAAUC,KAAKjF,uCAAuCkF,KAAK,qBAAsBlB,KACjF3C,qBAAqB2D,WA6RjBG,CAA0BnB,QAG9B5E,EAAEqF,UAAUC,GAAGjF,UAAU2F,6BAA6B,WAClDjF,oCAAoC8E,KAAKjF,uCAAuCqF,WAAW,sBAC3F1E,6BAGJvB,EAAEqF,UAAUC,GAAGjF,UAAU6F,uBAAuB,SAASP,MAAOxE,OA3OrC,SAASA,UAChCgF,KAAOhF,KAAK6C,MAAQ,QAAU,UAClC7D,aAAaiG,gBAAgB,CACzBC,QAASlF,KAAKkF,QACdF,KAAMA,OAwONG,CAAyBnF,SAGPnB,EAAEY,wCACR2F,OAAM,SAASrF,GAC3BA,EAAEsF,iBA9Ea,eACf5B,IAAMlD,aAAamD,UAEX,KAARD,WACO5E,EAAEyG,WAAWC,cAEpBC,WAAa3G,EAAEY,wCACnB2B,aAAaoE,gBAETC,QAAUpG,SAASqG,YAAYjC,KAEnCgC,QAAQ/C,QAAO,WACbrB,YAAYmE,eAGdC,QAAQ7D,MAAK,SAAS+D,QACdA,OAAOC,aACP/G,EAAEY,oBAAoBe,IAAI,IAC1B3B,EAAEqF,UAAU2B,QAAQ3G,UAAUqF,6BAA8Bd,MAE5D5E,EAAEqF,UAAU2B,QAAQ3G,UAAUmF,4BAA6B,CAACZ,IAAKA,SAIzEgC,QAAQK,MAAK,WACTvG,IAAIwG,WAAW,cAAe,WACzBnE,MAAK,SAASoE,GACPnH,EAAEqF,UAAU2B,QAAQ3G,UAAU6F,sBAAuB,CAC7CG,QAASc,EACTnD,OAAO,OAGtBiD,KAAK9G,aAAa8D,cA+CvBmD,MAGepH,EAAEY,8BACR2F,OAAM,SAASrF,GACxBA,EAAEsF,iBACF7B,0BAKwD,CAK5D0C,KAAM,WACFjC,yBACA3D"}
|