From 7a766e56b3b359285c99e4724fdabd1cf0793fd7 Mon Sep 17 00:00:00 2001
From: Astor Bizard <astor.bizard@grenoble-inp.fr>
Date: Tue, 26 Nov 2019 13:48:34 +0100
Subject: [PATCH] Fixed gutter diff performances

---
 amd/build/vplidefile.min.js               |  2 +-
 amd/src/vplide.js                         |  3 --
 amd/src/vplidefile.js                     | 57 ++++++++++++-----------
 similarity/diff.class.php                 | 11 ++++-
 similarity/diff_check_requested_files.php | 57 +++++++++++------------
 5 files changed, 65 insertions(+), 65 deletions(-)

diff --git a/amd/build/vplidefile.min.js b/amd/build/vplidefile.min.js
index c8133d66..12b14dae 100644
--- a/amd/build/vplidefile.min.js
+++ b/amd/build/vplidefile.min.js
@@ -1 +1 @@
-define(["jquery","jqueryui","mod_vpl/vplutil"],function(a,b,c){if("undefined"!=typeof d)return d;var d=function(b,e,f,g,h,i){var j="#vpl_file"+b,k="#vpl_tab_name"+b,l=e,m=!0,n=!1,o=this,p=i;this.getCurrentIdVpl=function(){return p},this.getId=function(){return b},this.getTabNameId=function(){return k},this.getTId=function(){return j},this.getFileName=function(){return l},this.resetModified=function(){m=!1,this.setFileName(l)},this.getTabPos=function(){return g.getTabPos(this)},this.isOpen=function(){return n},this.isModified=function(){return m},this.change=function(){m||(m=!0,g.generateFileList(),this.setFileName(l)),c.longDelay("setModified",g.setModified)},this.setFileName=function(b){if(!c.validPath(b))return!1;if(b!=l&&(l=b,o.change()),!n)return!0;var d=c.getFileName(b);d.length>20&&(d=d.substring(0,16)+"...");var e=(m?c.iconModified():"")+d;return e+=this.getTabPos()<g.minNumberOfFiles?c.iconRequired():c.iconClose(),a(k+" a").html(e),d!=b&&a(k+" a").attr("title",b),m&&g.adjustTabsTitles(!1),this.langSelection(),!0},this.getContent=function(){return f},this.setContent=function(a){f=a},this.destroy=function(){a(k).remove(),a(j).remove()},this.adjustSize=function(){if(!n)return!1;var b=a(j),c=b.parent();if(0!==b.length){var d=b.height(),e=b.width(),f=c.height();f-=b.position().top;var g=a("#vpl_tabs_scroll").width();return(f!=d||g!=e)&&(a(b).height(f),a(b).width(g),!0)}},this.gotoLine=c.doNothing,this.setReadOnly=c.doNothing,this.focus=c.doNothing,this.blur=c.doNothing,this.undo=c.doNothing,this.redo=c.doNothing,this.selectAll=c.doNothing,this.open=c.doNothing,this.hasUndo=c.returnFalse,this.hasRedo=c.returnFalse,this.hasSelectAll=c.returnFalse,this.hasFind=c.returnFalse,this.hasFindReplace=c.returnFalse,this.hasNext=c.returnFalse,this.find=c.doNothing,this.replace=c.doNothing,this.next=c.doNothing,this.getAnnotations=function(){return[]},this.setAnnotations=c.doNothing,this.setFontSize=c.doNothing,this.setTheme=c.doNothing,this.clearAnnotations=c.doNothing,this.langSelection=c.doNothing,this.isBinary=function(){return!1},this.extendToCodeEditor=function(){var d=null,e=null,h=g.readOnly;this.getContent=function(){return n?d.getValue():f},this.setContent=function(a){f=a,n&&d.setValue(a)},this.oldDestroy=this.destroy,this.destroy=function(){n&&d.destroy(),this.oldDestroy()},this.setFontSize=function(a){n&&d.setFontSize(a)},this.oldAdjustSize=this.adjustSize,this.adjustSize=function(){return!!this.oldAdjustSize()&&(d.resize(),!0)},this.gotoLine=function(a){n&&(d.gotoLine(a,0),d.scrollToLine(a,!0),d.focus())},this.setReadOnly=function(a){h=a,n&&d.setReadOnly(a)},this.focus=function(){n&&(a(j).removeClass("ui-widget-content ui-tabs-panel"),a(j).addClass("ui-corner-bottom"),this.adjustSize(),d.focus())},this.blur=function(){n&&d.blur()},this.undo=function(){n&&(d.undo(),d.focus())},this.redo=function(){n&&(d.redo(),d.focus())},this.selectAll=function(){n&&(d.selectAll(),d.focus())},this.hasUndo=function(){return!!n&&e.getUndoManager().hasUndo()},this.hasRedo=function(){return!!n&&e.getUndoManager().hasRedo()},this.hasSelectAll=c.returnTrue,this.hasFind=c.returnTrue,this.hasFindReplace=c.returnTrue,this.hasNext=c.returnTrue,this.find=function(){n&&d.execCommand("find")},this.replace=function(){n&&d.execCommand("replace")},this.next=function(){n&&d.execCommand("findnext")},this.getAnnotations=function(){return n?e.getAnnotations():[]},this.setAnnotations=function(a){if(n)return e.setAnnotations(a)},this.clearAnnotations=function(){if(n)return e.clearAnnotations()},this.langSelection=function(){if(n){var a=c.fileExtension(l),b="text";""!==a&&(b=c.langType(a)),e.setMode("ace/mode/"+b)}},this.getEditor=function(){return!!n&&d},this.setTheme=function(a){n&&d.setTheme("ace/theme/"+a)},this.$_GET=function(a){var b={};return window.location.href.replace(location.hash,"").replace(/[?&]+([^=&]+)=?([^&]*)?/gi,function(a,c,d){b[c]=void 0!==d?d:""}),a?b[a]?b[a]:null:b},this.check_difference=function(){},this.open=function(){function i(){var b=a(j+" div.ace_search");if(b.length){b.on("drop",g.dropHandler);var c=a("button.ace_searchbtn_close");c.css({marginLeft:"1em",marginRight:"1em"}),c.trigger("click")}else setTimeout(i,50)}if("undefined"==typeof ace){var k,m;return"undefined"!=typeof c.get_absolute_path()?(k=c.get_absolute_path()+"/editor/ace9/ace.js",m=c.get_absolute_path()+"/editor/ace9/ext-language_tools.js"):(k="../editor/ace9/ace.js",m="../editor/ace9/ext-language_tools.js"),void c.loadScript([k,m],function(){o.open()})}if(n)return!1;a(j).removeClass("ui-widget-content ui-tabs-panel"),a(j).addClass("ui-corner-bottom"),ace.require("ext/language_tools"),n=!0,d=ace.edit("vpl_file"+b),e=d.getSession(),d.setOptions({enableBasicAutocompletion:!0,enableSnippets:!0}),d.setFontSize(g.getFontSize()),d.setTheme("ace/theme/"+g.getTheme()),this.setFileName(l),d.setValue(f),d.gotoLine(0,0),d.setReadOnly(h),e.setUseSoftTabs(!0),e.setTabSize(4),e.setUndoManager(new ace.UndoManager),d.execCommand("replace"),this.check_difference(),d.on("change",function(){o.change(),o.check_difference()}),setTimeout(i,5);var p=d.onPaste;return d.onPaste=function(a){g.restrictedEdit?d.insert(g.getClipboard()):p.call(d,a)},d.on("copy",function(a){g.setClipboard(a)}),a(j).on("paste","*",g.restrictedPaste),a(j+" div.ace_content").on("drop",g.dropHandler),a(j+" div.ace_content").on("dragover",g.dragoverHandler),this.adjustSize(),d},this.close=function(){n=!1,null!==d&&(f=d.getValue(),d.destroy(),d=null,e=null)}},this.adaptBlockly=function(){"undefined"==typeof Blockly.PHP.workspaceToCodeOld&&(Blockly.PHP.workspaceToCodeOld=Blockly.PHP.workspaceToCode,Blockly.PHP.workspaceToCode=function(a){return"<?\n"+Blockly.PHP.workspaceToCodeOld(a)}),"undefined"==typeof Blockly.Python.workspaceToCodeOld&&(Blockly.Python.workspaceToCodeOld=Blockly.Python.workspaceToCode,Blockly.Python.workspaceToCode=function(a){return"# -*- coding: utf-8 -*-\n"+Blockly.Python.workspaceToCodeOld(a)})},this.extendToBlockly=function(){this.firstFocus=!0,this.workspacePlayground=!1,this.focus=function(){o.firstFocus&&(o.workspacePlayground?(o.firstFocus=!1,Blockly.Events.disable(),o.setContent(f),c.adjustBlockly(o.workspacePlayground,10,10),o.workspacePlayground.scrollX=0,o.workspacePlayground.scrollY=0,Blockly.svgResize(o.workspacePlayground),Blockly.resizeSvgContents(o.workspacePlayground),o.adjustSize(),Blockly.Events.enable()):c.longDelay("focus",o.focus))},this.adjustSize=function(){if(!n||!this.workspacePlayground)return!1;var b=a(j);if(0===b.length)return!1;var c=b.parent(),d=c.height();return d-=b.position().top,b.height(d),a("#"+this.bdiv).height(d),a("#"+this.bdiv).width(b.width()),Blockly.svgResize(this.workspacePlayground),!1},this.undo=function(){n&&this.workspacePlayground.undo(!1)},this.redo=function(){n&&this.workspacePlayground.undo(!0)},this.interpreter=!1,this.animateRun=!1,this.RUNSTATE=1,this.STEPSTATE=2,this.STOPSTATE=3,this.executionState=this.STOPSTATE,this.goNext=!1,this.initRun=function(a){function b(a,b){var e=function(b){return b=b?b.toString()+"\r\n":b+"\r\n",a.createPrimitive(d.writeLocal(b))};a.setProperty(b,"alert",a.createNativeFunction(e)),e=function(a,b){a=a?a.toString():""+a,d.writeLocal(a),d.setDataCallback(function(a){d.writeLocal("\n"),b(a)})},a.setProperty(b,"prompt",a.createAsyncFunction(e)),e=function(a){a==o.breakpoint&&(o.executionState=o.STEPSTATE,o.updateRunButtons(),h.getTerminal().setMessage(c.str("breakpoint"))),(o.animateRun||o.executionState==o.STEPSTATE)&&o.workspacePlayground.highlightBlock(a),o.goNext=!1},a.setProperty(b,"highlightBlock",a.createNativeFunction(e))}var d=h.getTerminal();d.isConnected()&&d.closeLocal(),this.animateRun=a,Blockly.JavaScript.STATEMENT_PREFIX="highlightBlock(%1);\n",Blockly.JavaScript.addReservedWords("highlightBlock");var e=Blockly.JavaScript.workspaceToCode(o.workspacePlayground);o.interpreter=new Interpreter(e,b),d.connectLocal(o.stop,function(){})},this.reservedWords={Infinity:!0,Array:!0,Boolean:!0,Date:!0,Error:!0,EvalError:!0,Function:!0,JSON:!0,Math:!0,NaN:!0,Number:!0,Object:!0,RangeError:!0,ReferenceError:!0,RegExp:!0,String:!0,SyntaxError:!0,TypeError:!0,URIError:!0,alert:!0,arguments:!0,constructor:!0,eval:!0,highlightBlock:!0,isFinite:!0,isNaN:!0,parseFloat:!0,parseInt:!0,prompt:!0,self:!0,"this":!0,window:!0},this.breakpoint="",this.getVarValue=function(a){var b="";if(null===a)b="<b>null</b>";else if(void 0!=a){var d=typeof a;if("string"==d)b='"'+c.sanitizeText(a)+'"';else if("boolean"==d)b="<b>"+a+"</b>";else if("object"==d&&"Array"===a["class"]){b="[";for(var e=a.properties,f=0;f<e.length;f++)b+=o.getVarValue(e[f]),f!=e.length-1&&(b+=", ");b+="]"}else"object"==d?b="<b>"+a.toString()+"</b>":b+=""+a}return b},this.getVariables=function(a){var b="";for(var c in a)if(this.reservedWords[c]!==!0){var d=a[c];void 0!=d&&"Function"!==d["class"]&&(b+="<b>"+c+"</b>: "+o.getVarValue(d)+"<br>\n")}return b},this.getParameters=function(a){for(var b="(",c=0;c<a.length;c++)b+=""+a[c],c<a.length-1&&(b+=", ");return b+")"},this.showStack=function(a){for(var b=0,c='<table class="generaltable">',d=a.stateStack,e="<tr><td>0</td><td><b>Globals</b></td>",f=0;f<d.length;f++){var g=d[f];e>""&&("CallExpression"==g.node.type||f==d.length-1)&&(c+=e+"<td>"+o.getVariables(g.scope.properties),c+="</td></tr>"),"CallExpression"==g.node.type&&(o.reservedWords[g.node.callee.name]!==!0&&void 0!=g.node.callee.name?(b++,e="<tr><td>"+b+"</td>",e+="<td>"+g.node.callee.name+o.getParameters(g.arguments_)+"</td>"):e="")}c+="</table>",h.setResult({variables:c})},this.runLoop=function(){if(o.interpreter){o.goNext=!0;for(var a=0;a<3e4&&o.goNext&&o.executionState!=o.STOPSTATE;a++)if(!o.interpreter||!o.interpreter.step()){o.executionState=o.STOPSTATE,o.updateRunButtons();break}return o.executionState==o.STOPSTATE?(o.workspacePlayground.highlightBlock(-1),h.getTerminal().closeLocal(),void h.setResult({variables:""})):void(o.executionState==o.RUNSTATE?setTimeout(o.runLoop,0):o.showStack(o.interpreter))}},this.start=function(){o.initRun(!1),o.executionState=o.RUNSTATE,o.updateRunButtons(),h.getTerminal().setMessage(c.str("start")),o.runLoop()},this.startAnimate=function(){o.initRun(!0),o.executionState=o.RUNSTATE,o.updateRunButtons(),h.getTerminal().setMessage(c.str("startanimate")),o.runLoop()},this.stop=function(){o.executionState=o.STOPSTATE,o.updateRunButtons(),h.getTerminal().setMessage(c.str("stop")),h.getTerminal().closeLocal(),o.interpreter=!1,h.setResult({variables:""})},this.pause=function(){o.executionState=o.STEPSTATE,h.getTerminal().setMessage(c.str("pause")),o.updateRunButtons()},this.resume=function(){o.executionState=o.RUNSTATE,h.getTerminal().setMessage(c.str("resume")),o.updateRunButtons(),o.runLoop()},this.step=function(){o.executionState==o.STOPSTATE&&o.initRun(!0),o.executionState=o.STEPSTATE,o.updateRunButtons(),h.getTerminal().setMessage(c.str("step")),o.runLoop()},this.hasUndo=function(){return!0},this.hasRedo=function(){return!0},this.oldSetFileName=this.setFileName,this.generatorMap={py:"Python",dart:"Dart",js:"JavaScript",lua:"Lua",php:"PHP"},this.generator="",this.setFileName=function(a){var b=/\.([^.]+)\.blockly[123]?$/,d=/(.+)\.blockly[123]?$/,e=c.fileExtension(l);o.oldSetFileName(a);var f=b.exec(l),g=d.exec(l);null!==f&&null!==g&&"string"==typeof this.generatorMap[f[1]]?(this.generator=this.generatorMap[f[1]],this.generatedFilename=g[1]):this.generator="",null!==g&&e!=c.fileExtension(l)&&this.setToolbox()},this.changeCode=function(a){if("ui"==a.type&&"selected"==a.element)return void(o.breakpoint=a.newValue);if("ui"==a.type&&"category"==a.element&&a.newValue==c.str("run"))return void o.updateRunButtons();if(a.recordUndo&&(o.change(),""!=this.generator)){var b=Blockly[this.generator].workspaceToCode(o.workspacePlayground),d=g.fileNameExists(this.generatedFilename);if(d==-1&&(g.addFile({name:this.generatedFilename,contents:""},!1,c.doNothing,c.doNothing),d=g.fileNameExists(this.generatedFilename)),d!=-1){var e=g.getFile(d);e.setContent(b),e.change(),e.gotoLine(1),e.setReadOnly(!0)}}},this.updateRunButtons=function(){switch(o.executionState){case o.RUNSTATE:a(".blocklyStartC").hide(),a(".blocklyStartAnimateC").hide(),a(".blocklyStopC").show(),a(".blocklyPauseC").show(),a(".blocklyResumeC").hide(),a(".blocklyStepC").hide();break;case o.STEPSTATE:a(".blocklyStartC").hide(),a(".blocklyStartAnimateC").hide(),a(".blocklyStopC").show(),a(".blocklyPauseC").hide(),a(".blocklyResumeC").show(),a(".blocklyStepC").show();break;case o.STOPSTATE:a(".blocklyStartC").show(),a(".blocklyStartAnimateC").show(),a(".blocklyStopC").hide(),a(".blocklyPauseC").hide(),a(".blocklyResumeC").hide(),a(".blocklyStepC").show()}},this.setToolbox=function(){var b=c.fileExtension(l),e=b+"Toolbox";return d[e]===!1?void a.ajax({url:"../editor/blocklytoolboxes/"+e+".xml",dataType:"text",success:function(a){d[e]=d.blocklyIn18(a),o.setToolbox()}}):(this.workspacePlayground.updateToolbox(d[e]),this.workspacePlayground.registerButtonCallback("blocklyStartButton",this.start),this.workspacePlayground.registerButtonCallback("blocklyStartAnimateButton",this.startAnimate),this.workspacePlayground.registerButtonCallback("blocklyStopButton",this.stop),this.workspacePlayground.registerButtonCallback("blocklyPauseButton",this.pause),this.workspacePlayground.registerButtonCallback("blocklyResumeButton",this.resume),this.workspacePlayground.registerButtonCallback("blocklyStepButton",this.step),void this.adjustSize())},this.open=function(){if(n=!0,this.setFileName(l),n=!1,d.blocklyNotLoaded)return void c.loadScript(["../editor/blockly/blockly_compressed.js","../editor/blockly/msg/js/en.js","../editor/blockly/blocks_compressed.js","../editor/blockly/python_compressed.js","../editor/blockly/javascript_compressed.js","../editor/blockly/php_compressed.js","../editor/blockly/lua_compressed.js","../editor/blockly/dart_compressed.js","../editor/acorn/acorn.js","../editor/acorn/interpreter.js"],function(){o.adaptBlockly(),d.blocklyNotLoaded=!1,o.open()});n=!0;var e=!1;if(/.*[0-9]$/.test(c.fileExtension(l)))var e=!0;a(j).removeClass("ui-widget-content ui-tabs-panel"),a(j).addClass("ui-corner-bottom"),this.bdiv="bkdiv"+b,a(j).html('<div id="'+this.bdiv+'" style="height: 480px; width: 600px;"></div>');var f={toolbox:'<xml><category name=""><block type="math_number"></block></category></xml>',media:"../editor/blockly/media/",horizontalLayout:e,zoom:{controls:!0,wheel:!0,startScale:1,maxScale:3,minScale:.2,scaleSpeed:1.15}};return this.workspacePlayground=Blockly.inject(this.bdiv,f),this.workspacePlayground.addChangeListener(function(a){o.changeCode(a)}),this.setToolbox(),!1},this.getContent=function(){if(!n)return f;var a=Blockly.Xml.workspaceToDom(this.workspacePlayground),b=Blockly.Xml.domToPrettyText(a);return b},this.setContent=function(a){if(f=a,n){this.workspacePlayground.clear();var b=Blockly.Xml.textToDom(a);Blockly.Xml.domToWorkspace(b,this.workspacePlayground)}},this.close=function(){f=this.getContent(),this.workspacePlayground.dispose(),this.workspacePlayground=!1,this.firstFocus=!0,n=!1}},this.extendToBinary=function(){this.isBinary=function(){return!0},this.setContent=function(a){m=!0,f=a,this.setFileName(l),this.updateDataURL()},this.updateDataURL=function(){if(c.isImage(l)){var b="data:"+c.getMIME(l)+";base64,";a(j).find("img").attr("src",b+f)}else a(j).find("img").attr("src","")},this.adjustSize=function(){if(!n)return!1;var b=a(j);if(0!==b.length){var c=b.parent(),d=c.height();return d-=b.position().top,d!=b.height()&&(b.height(d),!0)}},this.open=function(){return n=!0,c.isImage(l)?(a(j).addClass("vpl_ide_img").append("<img />"),this.updateDataURL()):a(j).addClass("vpl_ide_binary").text(c.str("binaryfile")),this.setFileName(l),!1},this.close=function(){n=!1}}};return d.blocklyNotLoaded=!0,d.blocklyToolbox=!1,d.blockly0Toolbox=!1,d.blockly1Toolbox=!1,d.blockly2Toolbox=!1,d.blockly3Toolbox=!1,d.blocklyStrs=["basic","intermediate","advanced","variables","operatorsvalues","control","inputoutput","functions","lists","math","text","run","start","startanimate","stop","pause","resume","step"],d.blocklyIn18=function(a){for(var b=d.blocklyStrs.length,e=0;e<b;e++){var f=d.blocklyStrs[e],g=new RegExp("\\[\\["+f+"\\]\\]","g"),h=c.str(f);a=a.replace(g,h)}return a},window.VPLFile=d,d});
\ No newline at end of file
+define(["jquery","jqueryui","mod_vpl/vplutil"],function(a,b,c){if("undefined"!=typeof d)return d;var d=function(b,e,f,g,h,i){var j="#vpl_file"+b,k="#vpl_tab_name"+b,l=e,m=!0,n=!1,o=this,p=i;this.getCurrentIdVpl=function(){return p},this.getId=function(){return b},this.getTabNameId=function(){return k},this.getTId=function(){return j},this.getFileName=function(){return l},this.resetModified=function(){m=!1,this.setFileName(l)},this.getTabPos=function(){return g.getTabPos(this)},this.isOpen=function(){return n},this.isModified=function(){return m},this.change=function(){m||(m=!0,g.generateFileList(),this.setFileName(l)),c.longDelay("setModified",g.setModified)},this.setFileName=function(b){if(!c.validPath(b))return!1;if(b!=l&&(l=b,o.change()),!n)return!0;var d=c.getFileName(b);d.length>20&&(d=d.substring(0,16)+"...");var e=(m?c.iconModified():"")+d;return this.getTabPos()<g.minNumberOfFiles?e+=c.iconRequired():e+=c.iconClose(),a(k+" a").html(e),d!=b&&a(k+" a").attr("title",b),m&&g.adjustTabsTitles(!1),this.langSelection(),!0},this.getContent=function(){return f},this.setContent=function(a){f=a},this.destroy=function(){a(k).remove(),a(j).remove()},this.adjustSize=function(){if(!n)return!1;var b=a(j),c=b.parent();if(0!==b.length){var d=b.height(),e=b.width(),f=c.height();f-=b.position().top;var g=a("#vpl_tabs_scroll").width();return(f!=d||g!=e)&&(a(b).height(f),a(b).width(g),!0)}},this.gotoLine=c.doNothing,this.setReadOnly=c.doNothing,this.focus=c.doNothing,this.blur=c.doNothing,this.undo=c.doNothing,this.redo=c.doNothing,this.selectAll=c.doNothing,this.open=c.doNothing,this.hasUndo=c.returnFalse,this.hasRedo=c.returnFalse,this.hasSelectAll=c.returnFalse,this.hasFind=c.returnFalse,this.hasFindReplace=c.returnFalse,this.hasNext=c.returnFalse,this.find=c.doNothing,this.replace=c.doNothing,this.next=c.doNothing,this.getAnnotations=function(){return[]},this.setAnnotations=c.doNothing,this.setFontSize=c.doNothing,this.setTheme=c.doNothing,this.clearAnnotations=c.doNothing,this.langSelection=c.doNothing,this.isBinary=function(){return!1},this.extendToCodeEditor=function(){var d=null,e=null,h=g.readOnly;this.getContent=function(){return n?d.getValue():f},this.setContent=function(a){f=a,n&&d.setValue(a)},this.oldDestroy=this.destroy,this.destroy=function(){n&&d.destroy(),this.oldDestroy()},this.setFontSize=function(a){n&&d.setFontSize(a)},this.oldAdjustSize=this.adjustSize,this.adjustSize=function(){return!!this.oldAdjustSize()&&(d.resize(),!0)},this.gotoLine=function(a){n&&(d.gotoLine(a,0),d.scrollToLine(a,!0),d.focus())},this.setReadOnly=function(a){h=a,n&&d.setReadOnly(a)},this.focus=function(){n&&(a(j).removeClass("ui-widget-content ui-tabs-panel"),a(j).addClass("ui-corner-bottom"),this.adjustSize(),d.focus())},this.blur=function(){n&&d.blur()},this.undo=function(){n&&(d.undo(),d.focus())},this.redo=function(){n&&(d.redo(),d.focus())},this.selectAll=function(){n&&(d.selectAll(),d.focus())},this.hasUndo=function(){return!!n&&e.getUndoManager().hasUndo()},this.hasRedo=function(){return!!n&&e.getUndoManager().hasRedo()},this.hasSelectAll=c.returnTrue,this.hasFind=c.returnTrue,this.hasFindReplace=c.returnTrue,this.hasNext=c.returnTrue,this.find=function(){n&&d.execCommand("find")},this.replace=function(){n&&d.execCommand("replace")},this.next=function(){n&&d.execCommand("findnext")},this.getAnnotations=function(){return n?e.getAnnotations():[]},this.setAnnotations=function(a){if(n)return e.setAnnotations(a)},this.clearAnnotations=function(){if(n)return e.clearAnnotations()},this.langSelection=function(){if(n){var a=c.fileExtension(l),b="text";""!==a&&(b=c.langType(a)),e.setMode("ace/mode/"+b)}},this.getEditor=function(){return!!n&&d},this.setTheme=function(a){n&&d.setTheme("ace/theme/"+a)},this.$_GET=function(a){var b={};return window.location.href.replace(location.hash,"").replace(/[?&]+([^=&]+)=?([^&]*)?/gi,function(a,c,d){b[c]=void 0!==d?d:""}),a?b[a]?b[a]:null:b},this.check_difference=function(){var b;b="undefined"!=typeof c.get_absolute_path()?c.get_absolute_path()+"/similarity/diff_check_requested_files.php":"../similarity/diff_check_requested_files.php",a.ajax({method:"POST",url:b,data:{id:p,name:l,val:d.getValue()}}).done(function(a){a.response.diff.forEach(function(a){"="!=a.type?(d.session.removeGutterDecoration(a.ln2-1,"ace-changed"),d.session.addGutterDecoration(a.ln2-1,"ace-changed")):d.session.removeGutterDecoration(a.ln2-1,"ace-changed")})})},this.open=function(){var i,k;if("undefined"==typeof ace)return"undefined"!=typeof c.get_absolute_path()?(i=c.get_absolute_path()+"/editor/ace9/ace.js",k=c.get_absolute_path()+"/editor/ace9/ext-language_tools.js"):(i="../editor/ace9/ace.js",k="../editor/ace9/ext-language_tools.js"),void c.loadScript([i,k],function(){o.open()});if(n)return!1;a(j).removeClass("ui-widget-content ui-tabs-panel"),a(j).addClass("ui-corner-bottom"),ace.require("ext/language_tools"),n=!0,d=ace.edit("vpl_file"+b),e=d.getSession(),d.setOptions({enableBasicAutocompletion:!0,enableSnippets:!0}),d.setFontSize(g.getFontSize()),d.setTheme("ace/theme/"+g.getTheme()),this.setFileName(l),d.setValue(f),d.gotoLine(0,0),d.setReadOnly(h),e.setUseSoftTabs(!0),e.setTabSize(4),e.setUndoManager(new ace.UndoManager),d.execCommand("replace"),this.check_difference();var m=null;d.on("change",function(){o.change(),null!==m&&clearTimeout(m),m=setTimeout(()=>{m=null,o.check_difference()},500)}),setTimeout(function b(){var c=a(j+" div.ace_search");if(c.length){c.on("drop",g.dropHandler);var d=a("button.ace_searchbtn_close");d.css({marginLeft:"1em",marginRight:"1em"}),d.trigger("click")}else setTimeout(b,50)},5);var p=d.onPaste;return d.onPaste=function(a){g.restrictedEdit?d.insert(g.getClipboard()):p.call(d,a)},d.on("copy",function(a){g.setClipboard(a)}),a(j).on("paste","*",g.restrictedPaste),a(j+" div.ace_content").on("drop",g.dropHandler),a(j+" div.ace_content").on("dragover",g.dragoverHandler),this.adjustSize(),d},this.close=function(){n=!1,null!==d&&(f=d.getValue(),d.destroy(),d=null,e=null)}},this.adaptBlockly=function(){"undefined"==typeof Blockly.PHP.workspaceToCodeOld&&(Blockly.PHP.workspaceToCodeOld=Blockly.PHP.workspaceToCode,Blockly.PHP.workspaceToCode=function(a){return"<?\n"+Blockly.PHP.workspaceToCodeOld(a)}),"undefined"==typeof Blockly.Python.workspaceToCodeOld&&(Blockly.Python.workspaceToCodeOld=Blockly.Python.workspaceToCode,Blockly.Python.workspaceToCode=function(a){return"# -*- coding: utf-8 -*-\n"+Blockly.Python.workspaceToCodeOld(a)})},this.extendToBlockly=function(){this.firstFocus=!0,this.workspacePlayground=!1,this.focus=function(){o.firstFocus&&(o.workspacePlayground?(o.firstFocus=!1,Blockly.Events.disable(),o.setContent(f),c.adjustBlockly(o.workspacePlayground,10,10),o.workspacePlayground.scrollX=0,o.workspacePlayground.scrollY=0,Blockly.svgResize(o.workspacePlayground),Blockly.resizeSvgContents(o.workspacePlayground),o.adjustSize(),Blockly.Events.enable()):c.longDelay("focus",o.focus))},this.adjustSize=function(){if(!n||!this.workspacePlayground)return!1;var b=a(j);if(0===b.length)return!1;var c=b.parent().height();return c-=b.position().top,b.height(c),a("#"+this.bdiv).height(c),a("#"+this.bdiv).width(b.width()),Blockly.svgResize(this.workspacePlayground),!1},this.undo=function(){n&&this.workspacePlayground.undo(!1)},this.redo=function(){n&&this.workspacePlayground.undo(!0)},this.interpreter=!1,this.animateRun=!1,this.RUNSTATE=1,this.STEPSTATE=2,this.STOPSTATE=3,this.executionState=this.STOPSTATE,this.goNext=!1,this.initRun=function(a){var b=h.getTerminal();b.isConnected()&&b.closeLocal(),this.animateRun=a,Blockly.JavaScript.STATEMENT_PREFIX="highlightBlock(%1);\n",Blockly.JavaScript.addReservedWords("highlightBlock");var d=Blockly.JavaScript.workspaceToCode(o.workspacePlayground);o.interpreter=new Interpreter(d,function(a,d){var e=function(c){return c=c?c.toString()+"\r\n":c+"\r\n",a.createPrimitive(b.writeLocal(c))};a.setProperty(d,"alert",a.createNativeFunction(e)),e=function(a,c){a=a?a.toString():""+a,b.writeLocal(a),b.setDataCallback(function(a){b.writeLocal("\n"),c(a)})},a.setProperty(d,"prompt",a.createAsyncFunction(e)),e=function(a){a==o.breakpoint&&(o.executionState=o.STEPSTATE,o.updateRunButtons(),h.getTerminal().setMessage(c.str("breakpoint"))),(o.animateRun||o.executionState==o.STEPSTATE)&&o.workspacePlayground.highlightBlock(a),o.goNext=!1},a.setProperty(d,"highlightBlock",a.createNativeFunction(e))}),b.connectLocal(o.stop,function(){})},this.reservedWords={Infinity:!0,Array:!0,Boolean:!0,Date:!0,Error:!0,EvalError:!0,Function:!0,JSON:!0,Math:!0,NaN:!0,Number:!0,Object:!0,RangeError:!0,ReferenceError:!0,RegExp:!0,String:!0,SyntaxError:!0,TypeError:!0,URIError:!0,alert:!0,arguments:!0,constructor:!0,eval:!0,highlightBlock:!0,isFinite:!0,isNaN:!0,parseFloat:!0,parseInt:!0,prompt:!0,self:!0,this:!0,window:!0},this.breakpoint="",this.getVarValue=function(a){var b="";if(null===a)b="<b>null</b>";else if(void 0!=a){var d=typeof a;if("string"==d)b='"'+c.sanitizeText(a)+'"';else if("boolean"==d)b="<b>"+a+"</b>";else if("object"==d&&"Array"===a.class){b="[";for(var e=a.properties,f=0;f<e.length;f++)b+=o.getVarValue(e[f]),f!=e.length-1&&(b+=", ");b+="]"}else"object"==d?b="<b>"+a.toString()+"</b>":b+=""+a}return b},this.getVariables=function(a){var b="";for(var c in a)if(!0!==this.reservedWords[c]){var d=a[c];void 0!=d&&"Function"!==d.class&&(b+="<b>"+c+"</b>: "+o.getVarValue(d)+"<br>\n")}return b},this.getParameters=function(a){for(var b="(",c=0;c<a.length;c++)b+=""+a[c],c<a.length-1&&(b+=", ");return b+")"},this.showStack=function(a){for(var b=0,c='<table class="generaltable">',d=a.stateStack,e="<tr><td>0</td><td><b>Globals</b></td>",f=0;f<d.length;f++){var g=d[f];e>""&&("CallExpression"==g.node.type||f==d.length-1)&&(c+=e+"<td>"+o.getVariables(g.scope.properties),c+="</td></tr>"),"CallExpression"==g.node.type&&(!0!==o.reservedWords[g.node.callee.name]&&void 0!=g.node.callee.name?(e="<tr><td>"+ ++b+"</td>",e+="<td>"+g.node.callee.name+o.getParameters(g.arguments_)+"</td>"):e="")}c+="</table>",h.setResult({variables:c})},this.runLoop=function(){if(o.interpreter){o.goNext=!0;for(var a=0;a<3e4&&o.goNext&&o.executionState!=o.STOPSTATE;a++)if(!o.interpreter||!o.interpreter.step()){o.executionState=o.STOPSTATE,o.updateRunButtons();break}if(o.executionState==o.STOPSTATE)return o.workspacePlayground.highlightBlock(-1),h.getTerminal().closeLocal(),void h.setResult({variables:""});o.executionState==o.RUNSTATE?setTimeout(o.runLoop,0):o.showStack(o.interpreter)}},this.start=function(){o.initRun(!1),o.executionState=o.RUNSTATE,o.updateRunButtons(),h.getTerminal().setMessage(c.str("start")),o.runLoop()},this.startAnimate=function(){o.initRun(!0),o.executionState=o.RUNSTATE,o.updateRunButtons(),h.getTerminal().setMessage(c.str("startanimate")),o.runLoop()},this.stop=function(){o.executionState=o.STOPSTATE,o.updateRunButtons(),h.getTerminal().setMessage(c.str("stop")),h.getTerminal().closeLocal(),o.interpreter=!1,h.setResult({variables:""})},this.pause=function(){o.executionState=o.STEPSTATE,h.getTerminal().setMessage(c.str("pause")),o.updateRunButtons()},this.resume=function(){o.executionState=o.RUNSTATE,h.getTerminal().setMessage(c.str("resume")),o.updateRunButtons(),o.runLoop()},this.step=function(){o.executionState==o.STOPSTATE&&o.initRun(!0),o.executionState=o.STEPSTATE,o.updateRunButtons(),h.getTerminal().setMessage(c.str("step")),o.runLoop()},this.hasUndo=function(){return!0},this.hasRedo=function(){return!0},this.oldSetFileName=this.setFileName,this.generatorMap={py:"Python",dart:"Dart",js:"JavaScript",lua:"Lua",php:"PHP"},this.generator="",this.setFileName=function(a){var b=c.fileExtension(l);o.oldSetFileName(a);var d=/\.([^.]+)\.blockly[123]?$/.exec(l),e=/(.+)\.blockly[123]?$/.exec(l);null!==d&&null!==e&&"string"==typeof this.generatorMap[d[1]]?(this.generator=this.generatorMap[d[1]],this.generatedFilename=e[1]):this.generator="",null!==e&&b!=c.fileExtension(l)&&this.setToolbox()},this.changeCode=function(a){if("ui"!=a.type||"selected"!=a.element)if("ui"!=a.type||"category"!=a.element||a.newValue!=c.str("run")){if(a.recordUndo&&(o.change(),""!=this.generator)){var b=Blockly[this.generator].workspaceToCode(o.workspacePlayground),d=g.fileNameExists(this.generatedFilename);if(-1==d&&(g.addFile({name:this.generatedFilename,contents:""},!1,c.doNothing,c.doNothing),d=g.fileNameExists(this.generatedFilename)),-1!=d){var e=g.getFile(d);e.setContent(b),e.change(),e.gotoLine(1),e.setReadOnly(!0)}}}else o.updateRunButtons();else o.breakpoint=a.newValue},this.updateRunButtons=function(){switch(o.executionState){case o.RUNSTATE:a(".blocklyStartC").hide(),a(".blocklyStartAnimateC").hide(),a(".blocklyStopC").show(),a(".blocklyPauseC").show(),a(".blocklyResumeC").hide(),a(".blocklyStepC").hide();break;case o.STEPSTATE:a(".blocklyStartC").hide(),a(".blocklyStartAnimateC").hide(),a(".blocklyStopC").show(),a(".blocklyPauseC").hide(),a(".blocklyResumeC").show(),a(".blocklyStepC").show();break;case o.STOPSTATE:a(".blocklyStartC").show(),a(".blocklyStartAnimateC").show(),a(".blocklyStopC").hide(),a(".blocklyPauseC").hide(),a(".blocklyResumeC").hide(),a(".blocklyStepC").show()}},this.setToolbox=function(){var b=c.fileExtension(l)+"Toolbox";!1!==d[b]?(this.workspacePlayground.updateToolbox(d[b]),this.workspacePlayground.registerButtonCallback("blocklyStartButton",this.start),this.workspacePlayground.registerButtonCallback("blocklyStartAnimateButton",this.startAnimate),this.workspacePlayground.registerButtonCallback("blocklyStopButton",this.stop),this.workspacePlayground.registerButtonCallback("blocklyPauseButton",this.pause),this.workspacePlayground.registerButtonCallback("blocklyResumeButton",this.resume),this.workspacePlayground.registerButtonCallback("blocklyStepButton",this.step),this.adjustSize()):a.ajax({url:"../editor/blocklytoolboxes/"+b+".xml",dataType:"text",success:function(a){d[b]=d.blocklyIn18(a),o.setToolbox()}})},this.open=function(){if(n=!0,this.setFileName(l),n=!1,!d.blocklyNotLoaded){n=!0;var e=!1;if(/.*[0-9]$/.test(c.fileExtension(l)))e=!0;a(j).removeClass("ui-widget-content ui-tabs-panel"),a(j).addClass("ui-corner-bottom"),this.bdiv="bkdiv"+b,a(j).html('<div id="'+this.bdiv+'" style="height: 480px; width: 600px;"></div>');var f={toolbox:'<xml><category name=""><block type="math_number"></block></category></xml>',media:"../editor/blockly/media/",horizontalLayout:e,zoom:{controls:!0,wheel:!0,startScale:1,maxScale:3,minScale:.2,scaleSpeed:1.15}};return this.workspacePlayground=Blockly.inject(this.bdiv,f),this.workspacePlayground.addChangeListener(function(a){o.changeCode(a)}),this.setToolbox(),!1}c.loadScript(["../editor/blockly/blockly_compressed.js","../editor/blockly/msg/js/en.js","../editor/blockly/blocks_compressed.js","../editor/blockly/python_compressed.js","../editor/blockly/javascript_compressed.js","../editor/blockly/php_compressed.js","../editor/blockly/lua_compressed.js","../editor/blockly/dart_compressed.js","../editor/acorn/acorn.js","../editor/acorn/interpreter.js"],function(){o.adaptBlockly(),d.blocklyNotLoaded=!1,o.open()})},this.getContent=function(){if(!n)return f;var a=Blockly.Xml.workspaceToDom(this.workspacePlayground);return Blockly.Xml.domToPrettyText(a)},this.setContent=function(a){if(f=a,n){this.workspacePlayground.clear();var b=Blockly.Xml.textToDom(a);Blockly.Xml.domToWorkspace(b,this.workspacePlayground)}},this.close=function(){f=this.getContent(),this.workspacePlayground.dispose(),this.workspacePlayground=!1,this.firstFocus=!0,n=!1}},this.extendToBinary=function(){this.isBinary=function(){return!0},this.setContent=function(a){m=!0,f=a,this.setFileName(l),this.updateDataURL()},this.updateDataURL=function(){if(c.isImage(l)){var b="data:"+c.getMIME(l)+";base64,";a(j).find("img").attr("src",b+f)}else a(j).find("img").attr("src","")},this.adjustSize=function(){if(!n)return!1;var b=a(j);if(0!==b.length){var c=b.parent().height();return(c-=b.position().top)!=b.height()&&(b.height(c),!0)}},this.open=function(){return n=!0,c.isImage(l)?(a(j).addClass("vpl_ide_img").append("<img />"),this.updateDataURL()):a(j).addClass("vpl_ide_binary").text(c.str("binaryfile")),this.setFileName(l),!1},this.close=function(){n=!1}}};return d.blocklyNotLoaded=!0,d.blocklyToolbox=!1,d.blockly0Toolbox=!1,d.blockly1Toolbox=!1,d.blockly2Toolbox=!1,d.blockly3Toolbox=!1,d.blocklyStrs=["basic","intermediate","advanced","variables","operatorsvalues","control","inputoutput","functions","lists","math","text","run","start","startanimate","stop","pause","resume","step"],d.blocklyIn18=function(a){for(var b=d.blocklyStrs.length,e=0;e<b;e++){var f=d.blocklyStrs[e],g=new RegExp("\\[\\["+f+"\\]\\]","g"),h=c.str(f);a=a.replace(g,h)}return a},window.VPLFile=d,d});
\ No newline at end of file
diff --git a/amd/src/vplide.js b/amd/src/vplide.js
index 24353405..b5316dc8 100644
--- a/amd/src/vplide.js
+++ b/amd/src/vplide.js
@@ -365,9 +365,6 @@ define(['jquery',
                         return false;
                     }
                     var fid = VPLUtil.getUniqueId();
-                    if (file.encoding == 1) {
-			file.contents = base64_ecnore(file.contents);
-		    }
                     var newfile = new VPLFile(fid, file.name, file.contents, this, vplIdeInstance, options.id);
                     if (file.encoding == 1) {
                         newfile.extendToBinary();
diff --git a/amd/src/vplidefile.js b/amd/src/vplidefile.js
index 17a84bfc..b8c5c084 100644
--- a/amd/src/vplidefile.js
+++ b/amd/src/vplidefile.js
@@ -348,34 +348,30 @@ define(['jquery',
             };
 
             this.check_difference = function() {
-                /*
-             var URL;
-
-             
-             if (typeof VPLUtil.get_absolute_path() !== "undefined") {
-                URL = VPLUtil.get_absolute_path() + "/similarity/diff_check_requested_files.php";
-             } else {
-                URL = "../similarity/diff_check_requested_files.php";
-             }
+                var URL;
+                if (typeof VPLUtil.get_absolute_path() !== "undefined") {
+                    URL = VPLUtil.get_absolute_path() + "/similarity/diff_check_requested_files.php";
+                } else {
+                    URL = "../similarity/diff_check_requested_files.php";
+                }
 
-             $.ajax({
-                        method: "POST",
-                        url: URL,
-                        data: { id : current_id_vpl, name: fileName, val : editor.getValue() }
-                      })
-                        .done(function( data ) {
-                            var modified = 'ace-changed'; // css class
-                            var i;
-                            for (i = 0; i < data.length; i++) {
-                              if(data[i].type != "=") {
-                                  editor.session.removeGutterDecoration(data[i].ln2-1, modified);
-                                  editor.session.addGutterDecoration(data[i].ln2-1, modified);
-                              } else {
-                                  editor.session.removeGutterDecoration(data[i].ln2-1, modified);
-                              }
-                            }
-                        });
-                        */
+                $.ajax({
+                    method: "POST",
+                    url: URL,
+                    data: { id : current_id_vpl, name: fileName, val : editor.getValue() }
+                })
+                .done(function( result ) {
+                    var diffData = result.response.diff;
+                    var modified = 'ace-changed'; // CSS class.
+                    diffData.forEach(function(diff){
+                        if(diff.type != "=") {
+                            editor.session.removeGutterDecoration(diff.ln2-1, modified);
+                            editor.session.addGutterDecoration(diff.ln2-1, modified);
+                        } else {
+                            editor.session.removeGutterDecoration(diff.ln2-1, modified);
+                        }
+                    });
+                });
             };
 
             this.open = function() {
@@ -436,9 +432,14 @@ define(['jquery',
 
                 this.check_difference();
 
+                var timeoutID = null;
                 editor.on('change', function() {
                     self.change();
-                    self.check_difference();
+                    // Check for differences with required files once at a time, when the user stops typing.
+                    if(timeoutID !== null){
+                        clearTimeout(timeoutID);
+                    }
+                    timeoutID = setTimeout(() => {timeoutID = null; self.check_difference();}, 500);
                 });
                 // Try to grant dropHandler installation.
                 setTimeout(addEventDrop, 5);
diff --git a/similarity/diff.class.php b/similarity/diff.class.php
index 3f86a284..0b4849c8 100644
--- a/similarity/diff.class.php
+++ b/similarity/diff.class.php
@@ -147,9 +147,11 @@ class vpl_diff {
      *            of string
      * @param $lines2 array
      *            of string
+     * @param $detaileddiff bool
+     *            whether different levels of similarity should be distinguished
      * @return array of objects with info to show the two array of lines
      */
-    static public function calculatediff($lines1, $lines2) {
+    static public function calculatediff($lines1, $lines2, $detaileddiff = true) {
         $ret = array ();
         $nl1 = count( $lines1 );
         $nl2 = count( $lines2 );
@@ -181,7 +183,12 @@ class vpl_diff {
                     $max = $matrix [$i - 1] [$j];
                     $best = - 1;
                 }
-                $prize = self::diffline( $line, $lines2 [$j - 1] );
+                if ($detaileddiff) {
+                    $prize = self::diffline( $line, $lines2 [$j - 1] );
+                }
+                else {
+                    $prize = $line === $lines2 [$j - 1] ? 1 : 0;
+                }
                 if ($matrix [$i - 1] [$j - 1] + $prize >= $max) {
                     $max = $matrix [$i - 1] [$j - 1] + $prize;
                     $best = 0;
diff --git a/similarity/diff_check_requested_files.php b/similarity/diff_check_requested_files.php
index 9455694e..8b1c2f7b 100644
--- a/similarity/diff_check_requested_files.php
+++ b/similarity/diff_check_requested_files.php
@@ -1,43 +1,38 @@
 <?php
 
-/* 
+/*
  * To change this license header, choose License Headers in Project Properties.
  * To change this template file, choose Tools | Templates
  * and open the template in the editor.
  */
 
+define( 'AJAX_SCRIPT', true );
 
 require_once(dirname(__FILE__).'/../../../config.php');
-require_once(dirname(__FILE__).'/../locallib.php');
-require_once(dirname(__FILE__).'/../vpl.class.php');
-require_once(dirname(__FILE__).'/diff.class.php');
 
-require_course_login( $COURSE );
-
-require_login();
-$id = $_POST['id']; // Course Module ID.
-$vpl = new mod_vpl( $id );
-
-$explode_code_in_editor = explode("\n", $_POST['val']);
-
-if(method_exists($vpl, 'get_fgm')) {
-    $fr = $vpl->get_fgm('required');
-} else {
-     $fr = $vpl->get_required_fgm(); 
+$outcome = new stdClass();
+$outcome->success = true;
+$outcome->response = new stdClass();
+$outcome->error = '';
+try {
+    require_once(dirname(__FILE__).'/../locallib.php');
+    require_once(dirname(__FILE__).'/../vpl.class.php');
+    require_once(dirname(__FILE__).'/diff.class.php');
+
+    require_login();
+    $id = required_param('id', PARAM_INT); // VPL ID.
+    $texttocheck = required_param('val', PARAM_RAW);
+    $filename = required_param('name', PARAM_RAW);
+
+    $vpl = new mod_vpl( $id );
+    $reqfiles = $vpl->get_fgm('required')->getAllFiles();
+    $reqfiletext = $reqfiles[$filename];
+
+    $outcome->response->diff = vpl_diff::calculatediff( explode("\n", $reqfiletext) , explode("\n", $texttocheck) , false );
+} catch ( Exception $e ) {
+    $outcome->success = false;
+    $outcome->error = $e->getMessage();
 }
 
-
-        $filenames = $fr->getFileList();
-        foreach ($filenames as $name) {
-            
-            if (file_exists( $fr->get_dir() . $fr::encodeFileName( $name ) ) && $name == $_POST['name']) {
-                    $printer = vpl_sh_factory::get_sh( $name );
-                    $data = $fr->getFileData( $name );
-                    $explode_requested_file = explode("\n", $data);
-            } 
-        }
-        
-        $diff = vpl_diff::calculatediff( $explode_requested_file , $explode_code_in_editor );
-        header('Content-type: application/json');
-        echo json_encode($diff);
-    
\ No newline at end of file
+echo json_encode( $outcome );
+die();
-- 
GitLab