diff --git a/src/core/ChefWorker.js b/src/core/ChefWorker.js index 9e9f8a30..dc4cfad1 100644 --- a/src/core/ChefWorker.js +++ b/src/core/ChefWorker.js @@ -88,7 +88,7 @@ self.addEventListener("message", function(e) { */ async function bake(data) { // Ensure the relevant modules are loaded - loadRequiredModules(data.recipeConfig); + self.loadRequiredModules(data.recipeConfig); try { const response = await self.chef.bake( @@ -125,24 +125,6 @@ function silentBake(data) { } -/** - * Checks that all required modules are loaded and loads them if not. - * - * @param {Object} recipeConfig - */ -function loadRequiredModules(recipeConfig) { - recipeConfig.forEach(op => { - let module = self.OperationConfig[op.op].module; - - if (!OpModules.hasOwnProperty(module)) { - log.info("Loading module " + module); - self.sendStatusMessage("Loading module " + module); - self.importScripts(self.docURL + "/" + module + ".js"); - } - }); -} - - /** * Calculates highlight offsets if possible. * @@ -162,6 +144,24 @@ function calculateHighlights(recipeConfig, direction, pos) { } +/** + * Checks that all required modules are loaded and loads them if not. + * + * @param {Object} recipeConfig + */ +self.loadRequiredModules = function(recipeConfig) { + recipeConfig.forEach(op => { + let module = self.OperationConfig[op.op].module; + + if (!OpModules.hasOwnProperty(module)) { + log.info("Loading module " + module); + self.sendStatusMessage("Loading module " + module); + self.importScripts(self.docURL + "/" + module + ".js"); + } + }); +}; + + /** * Send status update to the app. * diff --git a/src/core/FlowControl.js b/src/core/FlowControl.js index bcad2377..ee3599c0 100755 --- a/src/core/FlowControl.js +++ b/src/core/FlowControl.js @@ -1,6 +1,7 @@ import Recipe from "./Recipe.js"; import Dish from "./Dish.js"; import Magic from "./lib/Magic.js"; +import Utils from "./Utils.js"; /** @@ -267,12 +268,47 @@ const FlowControl = { const ings = state.opList[state.progress].getIngValues(), depth = ings[0], dish = state.dish, - magic = new Magic(dish.get(Dish.ARRAY_BUFFER)); + currentRecipeConfig = state.opList.map(op => op.getConfig()), + magic = new Magic(dish.get(Dish.ARRAY_BUFFER)), + options = await magic.speculativeExecution(depth); - const specExec = await magic.speculativeExecution(depth+1); - const output = JSON.stringify(specExec, null, 2); + let output = ` + + + + + + `; - dish.set(output, Dish.STRING); + options.forEach(option => { + // Construct recipe URL + // Replace this Magic op with the generated recipe + const recipeConfig = currentRecipeConfig.slice(0, state.progress) + .concat(option.recipe) + .concat(currentRecipeConfig.slice(state.progress + 1)), + recipeURL = "recipe=" + Utils.encodeURIFragment(Utils.generatePrettyRecipe(recipeConfig)); + + const language = option.languageScores[0]; + let fileType = "Unknown"; + + if (option.fileType) { + fileType = `Extension: ${option.fileType.ext}\nMime type: ${option.fileType.mime}`; + if (option.fileType.desc) + fileType += `\nDescription: ${option.fileType.desc}`; + } + + output += ` + + + + + `; + }); + + output += "
Recipe (click to load)Data snippetMost likely language\n(lower scores are better)File type
${Utils.generatePrettyRecipe(option.recipe, true)}${Utils.escapeHtml(Utils.printable(option.data))}${Magic.codeToLanguage(language.lang)}\nScore: ${language.chiSqr.toFixed()}${fileType}
"; + dish.set(output, Dish.HTML); return state; }, diff --git a/src/core/Utils.js b/src/core/Utils.js index 877f1f82..922d426c 100755 --- a/src/core/Utils.js +++ b/src/core/Utils.js @@ -908,10 +908,10 @@ const Utils = { * for users. * * @param {Object[]} recipeConfig - * @param {boolean} newline - whether to add a newline after each operation + * @param {boolean} [newline=false] - whether to add a newline after each operation * @returns {string} */ - generatePrettyRecipe: function(recipeConfig, newline) { + generatePrettyRecipe: function(recipeConfig, newline = false) { let prettyConfig = "", name = "", args = "", diff --git a/src/core/config/OperationConfig.js b/src/core/config/OperationConfig.js index a20ad15e..07b7ac4b 100755 --- a/src/core/config/OperationConfig.js +++ b/src/core/config/OperationConfig.js @@ -85,7 +85,7 @@ const OperationConfig = { module: "Default", description: "Attempts to detect what the input data is and which operations could help to make more sense of it.", inputType: "ArrayBuffer", - outputType: "string", + outputType: "html", flowControl: true, args: [ { diff --git a/src/core/lib/Magic.js b/src/core/lib/Magic.js index 38548777..09025a63 100644 --- a/src/core/lib/Magic.js +++ b/src/core/lib/Magic.js @@ -96,12 +96,12 @@ class Magic { /** * Speculatively executes matching operations, recording metadata of each result. * - * @param {number} [depth=1] - How many levels to try to execute + * @param {number} [depth=0] - How many levels to try to execute * @param {Object[]} [recipeConfig=[]] - The recipe configuration up to this point * @returns {Object[]} A sorted list of the recipes most likely to result in correct decoding */ - async speculativeExecution(depth = 1, recipeConfig = []) { - if (depth === 0) return []; + async speculativeExecution(depth = 0, recipeConfig = []) { + if (depth < 0) return []; let results = []; @@ -123,12 +123,16 @@ class Magic { opConfig = { op: op.op, args: op.args - }, - recipe = new Recipe([opConfig]); + }; + if (ENVIRONMENT_IS_WORKER()) self.loadRequiredModules([opConfig]); + + const recipe = new Recipe([opConfig]); await recipe.execute(dish, 0); + const magic = new Magic(dish.get(Dish.ARRAY_BUFFER)), speculativeResults = await magic.speculativeExecution(depth-1, [...recipeConfig, opConfig]); + results = results.concat(speculativeResults); })); @@ -215,6 +219,201 @@ class Magic { return res; } + /** + * Translates an ISO 639-1 code to a full language name. + * + * @param {string} code - The two letter ISO 639-1 code + * @returns {string} The full name of the languge + */ + static codeToLanguage(code) { + return { + "aa": "Afar", + "ab": "Abkhazian", + "ae": "Avestan", + "af": "Afrikaans", + "ak": "Akan", + "am": "Amharic", + "an": "Aragonese", + "ar": "Arabic", + "as": "Assamese", + "av": "Avaric", + "ay": "Aymara", + "az": "Azerbaijani", + "ba": "Bashkir", + "be": "Belarusian", + "bg": "Bulgarian", + "bh": "Bihari languages", + "bi": "Bislama", + "bm": "Bambara", + "bn": "Bengali", + "bo": "Tibetan", + "br": "Breton", + "bs": "Bosnian", + "ca": "Catalan; Valencian", + "ce": "Chechen", + "ch": "Chamorro", + "co": "Corsican", + "cr": "Cree", + "cs": "Czech", + "cu": "Church Slavic; Old Slavonic; Church Slavonic; Old Bulgarian; Old Church Slavonic", + "cv": "Chuvash", + "cy": "Welsh", + "da": "Danish", + "de": "German", + "dv": "Divehi; Dhivehi; Maldivian", + "dz": "Dzongkha", + "ee": "Ewe", + "el": "Greek, Modern (1453-)", + "en": "English", + "eo": "Esperanto", + "es": "Spanish; Castilian", + "et": "Estonian", + "eu": "Basque", + "fa": "Persian", + "ff": "Fulah", + "fi": "Finnish", + "fj": "Fijian", + "fo": "Faroese", + "fr": "French", + "fy": "Western Frisian", + "ga": "Irish", + "gd": "Gaelic; Scottish Gaelic", + "gl": "Galician", + "gn": "Guarani", + "gu": "Gujarati", + "gv": "Manx", + "ha": "Hausa", + "he": "Hebrew", + "hi": "Hindi", + "ho": "Hiri Motu", + "hr": "Croatian", + "ht": "Haitian; Haitian Creole", + "hu": "Hungarian", + "hy": "Armenian", + "hz": "Herero", + "ia": "Interlingua (International Auxiliary Language Association)", + "id": "Indonesian", + "ie": "Interlingue; Occidental", + "ig": "Igbo", + "ii": "Sichuan Yi; Nuosu", + "ik": "Inupiaq", + "io": "Ido", + "is": "Icelandic", + "it": "Italian", + "iu": "Inuktitut", + "ja": "Japanese", + "jv": "Javanese", + "ka": "Georgian", + "kg": "Kongo", + "ki": "Kikuyu; Gikuyu", + "kj": "Kuanyama; Kwanyama", + "kk": "Kazakh", + "kl": "Kalaallisut; Greenlandic", + "km": "Central Khmer", + "kn": "Kannada", + "ko": "Korean", + "kr": "Kanuri", + "ks": "Kashmiri", + "ku": "Kurdish", + "kv": "Komi", + "kw": "Cornish", + "ky": "Kirghiz; Kyrgyz", + "la": "Latin", + "lb": "Luxembourgish; Letzeburgesch", + "lg": "Ganda", + "li": "Limburgan; Limburger; Limburgish", + "ln": "Lingala", + "lo": "Lao", + "lt": "Lithuanian", + "lu": "Luba-Katanga", + "lv": "Latvian", + "mg": "Malagasy", + "mh": "Marshallese", + "mi": "Maori", + "mk": "Macedonian", + "ml": "Malayalam", + "mn": "Mongolian", + "mr": "Marathi", + "ms": "Malay", + "mt": "Maltese", + "my": "Burmese", + "na": "Nauru", + "nb": "Bokmål, Norwegian; Norwegian Bokmål", + "nd": "Ndebele, North; North Ndebele", + "ne": "Nepali", + "ng": "Ndonga", + "nl": "Dutch; Flemish", + "nn": "Norwegian Nynorsk; Nynorsk, Norwegian", + "no": "Norwegian", + "nr": "Ndebele, South; South Ndebele", + "nv": "Navajo; Navaho", + "ny": "Chichewa; Chewa; Nyanja", + "oc": "Occitan (post 1500)", + "oj": "Ojibwa", + "om": "Oromo", + "or": "Oriya", + "os": "Ossetian; Ossetic", + "pa": "Panjabi; Punjabi", + "pi": "Pali", + "pl": "Polish", + "ps": "Pushto; Pashto", + "pt": "Portuguese", + "qu": "Quechua", + "rm": "Romansh", + "rn": "Rundi", + "ro": "Romanian; Moldavian; Moldovan", + "ru": "Russian", + "rw": "Kinyarwanda", + "sa": "Sanskrit", + "sc": "Sardinian", + "sd": "Sindhi", + "se": "Northern Sami", + "sg": "Sango", + "si": "Sinhala; Sinhalese", + "sk": "Slovak", + "sl": "Slovenian", + "sm": "Samoan", + "sn": "Shona", + "so": "Somali", + "sq": "Albanian", + "sr": "Serbian", + "ss": "Swati", + "st": "Sotho, Southern", + "su": "Sundanese", + "sv": "Swedish", + "sw": "Swahili", + "ta": "Tamil", + "te": "Telugu", + "tg": "Tajik", + "th": "Thai", + "ti": "Tigrinya", + "tk": "Turkmen", + "tl": "Tagalog", + "tn": "Tswana", + "to": "Tonga (Tonga Islands)", + "tr": "Turkish", + "ts": "Tsonga", + "tt": "Tatar", + "tw": "Twi", + "ty": "Tahitian", + "ug": "Uighur; Uyghur", + "uk": "Ukrainian", + "ur": "Urdu", + "uz": "Uzbek", + "ve": "Venda", + "vi": "Vietnamese", + "vo": "Volapük", + "wa": "Walloon", + "wo": "Wolof", + "xh": "Xhosa", + "yi": "Yiddish", + "yo": "Yoruba", + "za": "Zhuang; Chuang", + "zh": "Chinese", + "zu": "Zulu" + }[code]; + } + } /**