text: /*
  variables
  */
  var model;
  var canvas;
  var classNames = [];
  var canvas;
  var coords = [];
  var mousePressed = false;
  var mode;
  var bestResult;
  /*
  prepare the drawing canvas 
  */
  $(function () {
      canvas = window._canvas = new fabric.Canvas('canvas');
      canvas.backgroundColor = '#ffffff';
      canvas.isDrawingMode = 0;
      canvas.freeDrawingBrush.color = "black";
      canvas.freeDrawingBrush.width = 8;
      canvas.renderAll();
      //setup listeners 
      canvas.on('mouse:up', function (e) {
          getFrame();
          mousePressed = false
      });
      canvas.on('mouse:down', function (e) {
          mousePressed = true
      });
      canvas.on('mouse:move', function (e) {
          recordCoor(e)
      });
  })
  
  /*
  set the table of the predictions 
  */
  function setTable(top5, probs) {
      //loop over the predictions 
      for (var i = 0; i < top5.length; i++) {
          let sym = document.getElementById('sym' + (i + 1))
          let prob = document.getElementById('prob' + (i + 1))
          sym.innerHTML = top5[i]
          prob.innerHTML = Math.round(probs[i] * 100)
      }
      //create the pie 
      createPie(".pieID.legend", ".pieID.pie");
  
  }
  
  /*
  record the current drawing coordinates
  */
  function recordCoor(event) {
      var pointer = canvas.getPointer(event.e);
      var posX = pointer.x;
      var posY = pointer.y;
  
      if (posX >= 0 && posY >= 0 && mousePressed) {
          coords.push(pointer)
      }
  }
  
  /*
  get the best bounding box by trimming around the drawing
  */
  function getMinBox() {
      //get coordinates 
      var coorX = coords.map(function (p) {
          return p.x
      });
      var coorY = coords.map(function (p) {
          return p.y
      });
  
      //find top left and bottom right corners 
      var min_coords = {
          x: Math.min.apply(null, coorX),
          y: Math.min.apply(null, coorY)
      }
      var max_coords = {
          x: Math.max.apply(null, coorX),
          y: Math.max.apply(null, coorY)
      }
  
      //return as strucut 
      return {
          min: min_coords,
          max: max_coords
      }
  }
  
  /*
  get the current image data 
  */
  function getImageData() {
      //get the minimum bounding box around the drawing 
      const mbb = getMinBox()
  
      //get image data according to dpi 
      const dpi = window.devicePixelRatio
      const imgData = canvas.contextContainer.getImageData(mbb.min.x * dpi, mbb.min.y * dpi,
          (mbb.max.x - mbb.min.x) * dpi, (mbb.max.y - mbb.min.y) * dpi);
      return imgData
  }
  
  /*
  get the prediction 
  */
  function getFrame() {
      //make sure we have at least two recorded coordinates 
      if (coords.length >= 2) {
  
          //get the image data from the canvas 
          const imgData = getImageData()
  
          //get the prediction 
          const pred = model.predict(preprocess(imgData)).dataSync()
  
          //find the top 5 predictions 
          const indices = findIndicesOfMax(pred, 5)
          const probs = findTopValues(pred, 5)
          const names = getClassNames(indices)
  
          if (probs[0] > 0.44) {
              bestResult = names[0];
          } else {
              bestResult = "none"
          }
  
          console.log(probs[0], bestResult)
  
          //set the table 
          setTable(names, probs)
      }
  }
  
  /*
  get the the class names 
  */
  function getClassNames(indices) {
      var outp = []
      for (var i = 0; i < indices.length; i++)
          outp[i] = classNames[indices[i]]
      return outp
  }
  
  /*
  load the class names 
  */
  async function loadDict() {
      if (mode == 'ar')
          loc = 'src/model2/class_names_ar.txt'
      else
          loc = 'src/model2/class_names.txt'
  
      await $.ajax({
          url: loc,
          dataType: 'text',
      }).done(success);
  }
  
  /*
  load the class names
  */
  function success(data) {
      const lst = data.split(/\n/)
      for (var i = 0; i < lst.length - 1; i++) {
          let symbol = lst[i]
          classNames[i] = symbol
      }
  }
  
  /*
  get indices of the top probs
  */
  function findIndicesOfMax(inp, count) {
      var outp = [];
      for (var i = 0; i < inp.length; i++) {
          outp.push(i); // add index to output array
          if (outp.length > count) {
              outp.sort(function (a, b) {
                  return inp[b] - inp[a];
              }); // descending sort the output array
              outp.pop(); // remove the last index (index of smallest element in output array)
          }
      }
      return outp;
  }
  
  /*
  find the top 5 predictions
  */
  function findTopValues(inp, count) {
      var outp = [];
      let indices = findIndicesOfMax(inp, count)
      // show 5 greatest scores
      for (var i = 0; i < indices.length; i++)
          outp[i] = inp[indices[i]]
      return outp
  }
  
  /*
  preprocess the data
  */
  function preprocess(imgData) {
      return tf.tidy(() => {
          //convert to a tensor 
          let tensor = tf.browser.fromPixels(imgData, numChannels = 1)
  
          //resize 
          const resized = tf.image.resizeBilinear(tensor, [28, 28]).toFloat()
  
          //normalize 
          const offset = tf.scalar(255.0);
          const normalized = tf.scalar(1.0).sub(resized.div(offset));
  
          //We add a dimension to get a batch shape 
          const batched = normalized.expandDims(0)
          return batched
      })
  }
  
  /*
  load the model
  */
  async function start(cur_mode) {
      //arabic or english
      mode = cur_mode
  
      //load the model 
      model = await tf.loadLayersModel('src/model2/model.json')
  
      //warm up 
      model.predict(tf.zeros([1, 28, 28, 1]))
  
      //allow drawing on the canvas 
      allowDrawing()
  
      //load the class names
      await loadDict()
  }
  
  /*
  allow drawing on canvas
  */
  function allowDrawing() {
      if (canvas){
          canvas.isDrawingMode = true;
          document.getElementById('status').innerHTML = "<button type=\"button\" class=\"button start_btn is-primary\" onclick=\'toggleSketch()\'>Start drawing</button>";
          $('button').prop('disabled', false);
          var slider = document.getElementById('myRange');
          slider.oninput = function () {
              canvas.freeDrawingBrush.width = this.value;
          };
      }
  }
  
  /*
  clear the canvs 
  */
  function erase() {
      canvas.clear();
      canvas.backgroundColor = '#ffffff';
      coords = [];
  }
  
  function exportLevel() {
      var image = canvas.toDataURL("image/png").replace("image/png", "image/octet-stream");
      console.log("s")
      window.location.href = image;
  }
  
  function dataURLtoBlob(dataurl) {
      var arr = dataurl.split(','),
          mime = arr[0].match(/:(.*?);/)[1],
          bstr = atob(arr[1]),
          n = bstr.length,
          u8arr = new Uint8Array(n);
      while (n--) {
          u8arr[n] = bstr.charCodeAt(n);
      }
      return new Blob([u8arr], {
          type: mime
      });
  }
  
  function sendToServer() {
      var base64Data = canvas.toDataURL()
      var image = dataURLtoBlob(base64Data)
  
      var formData = new FormData()
      formData.append('sketch', image)
      formData.append('result', bestResult)
  
      console.log(formData)
  
      $.ajax({
          type: "POST",
          url: "/uploadSketch",
          data: formData,
          processData: false,
          contentType: false,
          success: function(respMsg){
              document.getElementById("atmsg").innerHTML = respMsg
              toggleSketch()
          },
      });
  }