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 = `
+
+ Recipe (click to load) |
+ Data snippet |
+ Most likely language\n(lower scores are better) |
+ File type |
+
`;
- 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 += `
+ ${Utils.generatePrettyRecipe(option.recipe, true)} |
+ ${Utils.escapeHtml(Utils.printable(option.data))} |
+ ${Magic.codeToLanguage(language.lang)}\nScore: ${language.chiSqr.toFixed()} |
+ ${fileType} |
+
`;
+ });
+
+ output += "
";
+ 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];
+ }
+
}
/**