legacy/outils/scratch/ScratchBase.js

/*
 * Ce fichier contient la classe Scratch, qui reprend tout le code de l’ancien
 * tomblok.js pour le mettre dans un objet avec des méthodes.
 * Attention, l’objet Blockly de départ n’est pas exactement le même, on utilise ici celui du paquet scratch-blocks
 * alors que l’ancien tomblok utilisait un Blockly figé mis en dur dans nos outils externes (cf src/lib/outils/scratch/legacy.js avant 2023-01-09)
 */

import Algebrite from 'algebrite'
import $ from 'jquery'

import { j3pAddContent, j3pAddElt, j3pAjouteBouton, j3pBarre, j3pClone, j3pDetruit, j3pEmpty, j3pFocus, j3pGetRandomInt, j3pModale, j3pShowError, j3pShuffle } from 'src/legacy/core/functions'
import { j3pSvgAppend } from 'src/legacy/core/functionsSvg'
import ZoneStyleMathquill1 from 'src/legacy/outils/zoneStyleMathquill/ZoneStyleMathquill1'
import { addDefaultTable } from 'src/legacy/themes/table'
import { j3pBaseUrl } from 'src/lib/core/constantes'
import { notify } from 'sesajs/error'
import { j3pAffiche } from 'src/lib/mathquill/functions'

import ScratchProg from './ScratchProg'

import './scratch.scss'

// les images du dossier courant
// lignes suivantes générées avec cette commande (lancée dans ce dossier)
// ls -1 images/*.svg images/*.gif images/*.png images/*.jpg|while read f; do n=${f%.*}; echo "import ${n}Img from './images/$f'"; done
// import arc3pImg from './images/arc3p.png'
// import arcmilImg from './images/arcmil.png'
import barreboutonImg from './images/barrebouton.png'
import blackholeImg from './images/blackhole.svg'
import cosmoImg from './images/cosmo.svg'
import planetrougeImg from './images/planetrouge.svg'
import terreImg from './images/terre.svg'
import tuxImg from './images/tux.png'
import valgetusImg from './images/valgetus.png'
import imProgConst from './images/clipart818338.png'
/**
 * Les méthodes internes communes à toutes les classes Scratch qui nous étendent (elles ne devraient pas être appelées en dehors de ces classes filles)
 */
class ScratchBase {
  constructor (Blockly) {
    this._lanceProgLinstener = this.lanceProg.bind(this)
    this._scratchDePauseListener = this.scratchDePause.bind(this)
    this.Blockly = Blockly
    this.isMtg = false
  }

  remplaceMake (ki) {
    const tabremp = []
    if (Array.isArray(this.params.scratchProgDonnees.tabcodeX)) {
      for (let i = 0; i < this.params.scratchProgDonnees.tabcodeX.length; i++) {
        if (this.params.scratchProgDonnees.tabcodeX[i][0].type === 'make') {
          tabremp.push({ ki: this.params.scratchProgDonnees.tabcodeX[i][0].nom, define: [] })
          for (let j = 1; j < this.params.scratchProgDonnees.tabcodeX[i].length - 1; j++) {
            tabremp[tabremp.length - 1].define.push(j3pClone(this.params.scratchProgDonnees.tabcodeX[i][j]))
          }
        }
      }
    }

    for (const property in this.params.listeDef) {
      tabremp.push({ ki: this.params.listeDef[property].nom + 'b', define: [] })
      for (let j = 0; j < this.params.listeDef[property].def.length - 1; j++) {
        tabremp[tabremp.length - 1].define.push(j3pClone(this.params.listeDef[property].def[j]))
      }
    }

    for (let i = ki.length - 1; i > -1; i--) {
      if (ki[i].type === 'Mb') {
        const SouAPush = { num: i, nom: ki[i].nom, agarde: [ki[i].valx, ki[i].valy, ki[i].valz], tabRemp: this.retrouveTab(ki[i].nom, tabremp) || tabremp[0] }
        const agarde = [ki[i].valx, ki[i].valy, ki[i].valz]
        const tatabremp = this.retrouveTab(ki[i].nom, tabremp) || tabremp[0]
        ki.splice(i, 1)
        for (let j = tatabremp.define.length - 1; j > -1; j--) {
          ki.splice(i, 0, tatabremp.define[j])
        }
        ki.splice(i, 0, { type: 'setValPerso', valX: agarde[0], valY: agarde[1], valZ: agarde[2] })
        this.params.toSouvSuite.push(SouAPush)
      }
      if (ki[i].boucle) {
        this.remplaceMake(ki[i].boucle)
      }
    }
  }

  retrouveTab (n, tabremp) {
    for (let i = 0; i < tabremp.length; i++) {
      if (tabremp[i].ki === n) return tabremp[i]
    }
  }

  decodeCo () {
    this.params.scratchProgDonnees.runable = false
    this.scratchRunBlockly(this.params.workspaceco) // ça crée le prog
    this.params.scratchProgDonnees.runable = true
  }

  defineUtil (fg) {
    if (!Array.isArray(fg)) return false
    for (let i = 0; i < fg.length; i++) {
      if (fg[i].type === 'ordre') {
        if (fg[i].nom === 'Getus') return true
      }
      if (fg[i].type === 'boucle') {
        if (this.defineUtil(fg[i].boucle)) { return true }
      }
      if (fg[i].type === 'boucleU') {
        if (this.defineUtil(fg[i].boucle)) { return true }
      }
      if (fg[i].type === 'boucleF') {
        if (this.defineUtil(fg[i].boucle)) { return true }
      }
      if (fg[i].type === 'si') {
        if (this.defineUtil(fg[i].sioui)) { return true }
        if (this.defineUtil(fg[i].sinon)) { return true }
      }
    }
    return false
  }

  defineRandom () {
    const mmm = this.params.workspaceEl.getAllBlocks()
    for (let i = 0; i < mmm.length; i++) {
      if (mmm[i].type === 'operator_random') return true
    }
    return false
  }

  retrouveBorne () {
    const mmm = this.params.workspaceEl.getAllBlocks()
    const bornes = []
    for (let i = 0; i < mmm.length; i++) {
      if (mmm[i].type === 'operator_random') {
        const b1 = Number(this.vireGuillemets(this.Blockly.JavaScript.valueToCode(mmm[i], 'NUM1', this.Blockly.JavaScript.ORDER_ATOMIC)))
        const b2 = Number(this.vireGuillemets(this.Blockly.JavaScript.valueToCode(mmm[i], 'NUM2', this.Blockly.JavaScript.ORDER_ATOMIC)))
        bornes.push({ borneInf: Math.min(b1, b2), borneSup: Math.max(b1, b2), idBlok: mmm[i].id })
      }
    }
    return bornes
  }

  lanceProg (prog, numProgDeTabcodex) {
    if (!this.params.isEditing) {
      if (this.params.me.etat !== 'correction') {
        if (!this.params.scratchProgDonnees.repEleve) {
          this.lesdivs.drap1.classList.add('WorkInProg')
          this.lesdivs.drap2.classList.add('WorkInProg')
        } else {
          this.lesdivs.sortie1.classList.add('WorkInProg')
        }
      } else {
        this.lesdivs.sortie1.classList.add('WorkInProg')
      }
    }
    if (this.lesdivs.stop) {
      this.lesdivs.stop.style.display = (prog.paramDeScratchprog.cacheTest) ? 'none' : ''
    }
    this.params.scratchProgDonnees.fostop = false
    this.params.scratchProgDonnees.fostopErreur = false
    this.params.grosStop = false
    this.params.scratchProgDonnees.run = true
    this.params.scratchProgDonnees.progencours = new ScratchProg(this.Blockly, { scratch: this, options: prog.paramDeScratchprog, numProgDeTabcodex })
  }

  loadSample (monUrl, elem) {
    return $.ajax({
      type: 'GET',
      url: monUrl, // "outils/algo/exemple_blockly.xml" par exemple
      dataType: 'xml',
      success: function (xml) {
        let x = xml.firstChild
        while (x.nodeType !== 1) {
          x = x.nextSibling
        }
        this.Blockly.getMainWorkspace().clear()

        this.Blockly.Xml.domToWorkspace(x, this.Blockly.getMainWorkspace())
        if (elem) {
          for (let i = 0; i < elem.length; i++) {
            let el = this.params.scratchProgDonnees.workspace
            for (let j = 0; j < elem[i].emplacement.length; j++) {
              switch (elem[i].emplacement[j].type) {
                case 'block':
                  el = el.getBlockById(elem[i].emplacement[j].id)
                  break
                case 'input':
                  el = el.getInputTargetBlock(elem[i].emplacement[j].name)
              }
            }
            switch (elem[i].modif.type) {
              case 'field' :
                el.setFieldValue(elem[i].modif.valeur, elem[i].modif.name)
            }
          }
        }
      }
    })
  }

  loadSampletotal (elem) {
    let xml
    if (Array.isArray(this.params.scratchProgDonnees.progdeb[0])) {
      xml = this.scratchCreeProgCo(this.params.scratchProgDonnees.progdeb[0], { kedeb: true })
      xml += this.scratchCreeProgCo(this.params.scratchProgDonnees.progdeb[1], { kefin: true })
    } else {
      xml = this.scratchCreeProgCo(this.params.scratchProgDonnees.progdeb, elem)
    }
    const xmlDoc = $.parseXML(xml)
    let x = xmlDoc.firstChild
    while (x.nodeType !== 1) {
      x = x.nextSibling
    }
    this.Blockly.getMainWorkspace().clear()

    this.Blockly.Xml.domToWorkspace(x, this.Blockly.getMainWorkspace())
    if (this.dansBlokMoha) {
      this.ref()
    }
  }

  newIdCo () {
    this.maxIdCo++
    return this.maxIdCo
  }

  scratchCacheCo (div, bool, bool2) {
    // on détruit rien si bool est undefined
    if ((bool === 'rien') && (this.lesdivs.avire !== undefined)) return
    let lacoul = bool ? 'rgba(113, 240, 65,.3)' : 'rgba(214, 71, 0,.3)'
    let petitLeft = '-10px'
    let petitTop = 10
    let petitWidth = 0
    if (bool === 'rien') {
      lacoul = 'rgba(255, 255, 255, 0.1)'
      div = this.lesdivs.contBlockly
      petitLeft = '0px'
      petitTop = 0
      petitWidth = 10
    }
    if (bool2) {
      petitLeft = '0px'
      petitTop = 0
    }
    const { width, height } = div.getBoundingClientRect()

    const len = j3pAddElt(div, 'div', '', {
      style: {
        position: 'relative',
        left: petitLeft,
        top: '-' + (height - petitTop) + 'px',
        height: height + 'px',
        width: (width - petitWidth) + 'px',
        background: lacoul,
        zIndex: 50
      }
    })
    // div.style.maxHeight = height + 'px'
    div.style.display = 'inline-block'

    if (bool !== 'rien') len.style.pointerEvents = 'none'
    if (!bool) {
      const svg = j3pBarre(len)
      // pour que l’élève puisse déplacer les élément derrière
      svg.style.pointerEvents = 'none' // svg
      svg.parentNode.style.pointerEvents = 'none' // le div parent créé par j3pBarre
    }
    if ((bool !== true) && (bool !== false)) {
      this.lesdivs.avire = len
    } else {
      this.lesdivs.avire = undefined
    }
  }

  scratchFusee () {
    this.params.imageLutin[0].width.baseVal.value = this.params.scratchProgDonnees.Lutins[0].larg
    this.params.imageLutin[0].height.baseVal.value = this.params.scratchProgDonnees.Lutins[0].haut
    this.params.imageLutin[0].y.baseVal.value = this.params.scratchProgDonnees.Lutins[0].coy * this.params.scratchProgDonnees.Lutins[0].larg
    this.params.imageLutin[0].x.baseVal.value = this.params.scratchProgDonnees.Lutins[0].cox * this.params.scratchProgDonnees.Lutins[0].larg
    const ghj = this.params.scratchProgDonnees.Lutins[0].larg
    this.params.imageLutin[0].setAttributeNS(null, 'transform', 'rotate(' + (this.params.scratchProgDonnees.Lutins[0].angle) + ',' + (this.params.scratchProgDonnees.Lutins[0].cox * ghj + (ghj / 2)) + ',' + (this.params.scratchProgDonnees.Lutins[0].coy * ghj + (ghj / 2)) + ')')
    if (!this.params.scratchProgDonnees.Lutins[0].hauteur) {
      this.params.imageLutin[0].width.baseVal.value = this.params.scratchProgDonnees.Lutins[0].larg / 2
      this.params.imageLutin[0].height.baseVal.value = this.params.scratchProgDonnees.Lutins[0].haut / 2
    }
  } // scratchFusee

  scratchBras () {
    const ly = 203 - this.params.scratchProgDonnees.Lutins[0].coy * 100
    this.params.imageLutin[0].y.baseVal.value = ly
    let dec2 = 0
    let dec3 = 0
    if (this.params.scratchProgDonnees.Lutins[0].angle === 0) {
      if (this.params.scratchProgDonnees.Lutins[0].cox === 1) dec2 = 32
      else dec2 = 26
    }
    const lx = this.params.scratchProgDonnees.Lutins[0].cox * 150 + 50
    this.params.imageLutin[0].x.baseVal.value = lx + dec2
    let decs
    if (this.params.scratchProgDonnees.Lutins[0].cox === 1) {
      decs = -37
      dec3 = -8
      if (this.params.scratchProgDonnees.Lutins[0].angle === 1) { dec3 = 56 }
      this.params.imageLutin[0].setAttributeNS(null, 'transform', 'rotate(180,' + (lx + (this.params.scratchProgDonnees.Lutins[0].larg / 2)) + ',' + (ly + (this.params.scratchProgDonnees.Lutins[0].haut / 2)) + ')')
    } else {
      decs = 40
      this.params.imageLutin[0].setAttributeNS(null, 'transform', '')
    }
    this.params.figIm[21].y.baseVal.value = ly - 2
    this.params.figIm[19].y.baseVal.value = ly + 11

    this.params.figIm[19].x.baseVal.value = lx + decs
    this.params.figIm[20].y.baseVal.value = ly + 30

    this.params.figIm[17].x.baseVal.value = lx - 6 + dec2 + dec3
    this.params.figIm[17].y.baseVal.value = ly + 2

    this.params.figIm[18].x.baseVal.value = lx - 6 + dec2 + dec3
    this.params.figIm[18].y.baseVal.value = ly + 2

    if (this.params.scratchProgDonnees.donneesbras.tapis1 === 0) {
      this.params.figIm[9].style.display = 'none'
      this.params.figIm[13].style.display = 'none'
    }
    if (this.params.scratchProgDonnees.donneesbras.tapis1 === 1) {
      this.params.figIm[9].style.display = ''
      this.params.figIm[13].style.display = 'none'
    }
    if (this.params.scratchProgDonnees.donneesbras.tapis1 === 2) {
      this.params.figIm[9].style.display = 'none'
      this.params.figIm[13].style.display = ''
    }
    if (this.params.scratchProgDonnees.donneesbras.tapis2 === 0) {
      this.params.figIm[10].style.display = 'none'
      this.params.figIm[14].style.display = 'none'
    }
    if (this.params.scratchProgDonnees.donneesbras.tapis2 === 1) {
      this.params.figIm[10].style.display = ''
      this.params.figIm[14].style.display = 'none'
    }
    if (this.params.scratchProgDonnees.donneesbras.tapis2 === 2) {
      this.params.figIm[10].style.display = 'none'
      this.params.figIm[14].style.display = ''
    }
    if (this.params.scratchProgDonnees.donneesbras.tapis3 === 0) {
      this.params.figIm[11].style.display = 'none'
      this.params.figIm[15].style.display = 'none'
    }
    if (this.params.scratchProgDonnees.donneesbras.tapis3 === 1) {
      this.params.figIm[11].style.display = ''
      this.params.figIm[15].style.display = 'none'
    }
    if (this.params.scratchProgDonnees.donneesbras.tapis3 === 2) {
      this.params.figIm[11].style.display = 'none'
      this.params.figIm[15].style.display = ''
    }
    if (this.params.scratchProgDonnees.donneesbras.tapis4 === 0) {
      this.params.figIm[12].style.display = 'none'
      this.params.figIm[16].style.display = 'none'
    }
    if (this.params.scratchProgDonnees.donneesbras.tapis4 === 1) {
      this.params.figIm[12].style.display = ''
      this.params.figIm[16].style.display = 'none'
    }
    if (this.params.scratchProgDonnees.donneesbras.tapis4 === 2) {
      this.params.figIm[12].style.display = 'none'
      this.params.figIm[16].style.display = ''
    }
    if (this.params.scratchProgDonnees.donneesbras.bras === 0) {
      this.params.figIm[17].style.display = 'none'
      this.params.figIm[18].style.display = 'none'
    }
    if (this.params.scratchProgDonnees.donneesbras.bras === 1) {
      this.params.figIm[17].style.display = ''
      this.params.figIm[18].style.display = 'none'
    }
    if (this.params.scratchProgDonnees.donneesbras.bras === 2) {
      this.params.figIm[17].style.display = 'none'
      this.params.figIm[18].style.display = ''
    }
  } // scratchBras

  scratchRunBlockly (wkspace) {
    // Generate JavaScript code and run it.
    window.LoopTrap = 10000
    this.Blockly.JavaScript.INFINITE_LOOP_TRAP =
      'if (--window.LoopTrap == 0) throw "Infinite loop.";\n'
    //
    this.params.leWork = wkspace
    return this.Blockly.JavaScript.workspaceToCode(wkspace)
  }

  scratchVerifEvent (koi) {
    this.params.isSpeed = koi === 'drapeauVite'
    this.params.scratchProgDonnees.YaUtilisateur = false
    if (!this.params.scratchProgDonnees.runable) return
    this.params.scratchProgDonnees.runable = false
    this.params.scratchProgDonnees.utilisateur = false
    this.params.scratchProgDonnees.AleaResult = undefined

    this.evenInterss = []

    const eventAt = koi.replace('Demo', '').replace('OK', '').replace('Vite', '')

    let isDef = false
    let isCo = false
    let isDemo = false
    let isCompleteTest = false
    this.params.progAtest = [
      {
        paramDeScratchprog: {
          vite: !this.params.dirigeProg.sequence,
          PasAPas: this.params.dirigeProg.PasAPas,
          cacheTest: this.params.dirigeProg.cacheTest,
          workspace: this.params.workspaceEl,
          tabcodeX: this.scratchRunBlockly(this.params.workspaceEl),
          event: eventAt,
          sortie: this.lesdivs.sortieEl,
          valAlea: [],
          valGetUs: [],
          valRadar: undefined,
          cKi: 'eleve'
        },
        modaleText: null,
        eventAt
      }
    ]
    this.params.pourLaCo = {
      isDef: false,
      TypeCorrection: this.params.modeCorrection.type,
      aVerif: this.params.modeCorrection.aVerif,
      suiteAverif: []
    }

    if (koi.indexOf('Demo') !== -1) { isDemo = true }
    if (koi === 'drapeau' && !this.params.NbEssaiIllimite && !this.params.yaFauxClavier) {
      isCompleteTest = true
    }
    if (koi === 'drapeau' && !this.params.NbEssaiIllimite && !this.params.yaFauxClavier && this.params.nbEssais === 1) {
      isDef = true
    }
    if (koi.indexOf('OK') !== -1) { isDef = true }
    if (this.params.me.etat !== 'correction') {
      isDef = false
      isCompleteTest = false
      if (this.corActif === 'Co') {
        isCo = true
      }
    }
    if (isDemo) {
      this.params.progAtest[0].paramDeScratchprog.PasAPas = false
      this.params.progAtest[0].paramDeScratchprog.workspace = this.params.workspaceDemo
      this.params.progAtest[0].paramDeScratchprog.tabcodeX = this.scratchRunBlockly(this.params.workspaceDemo)
      this.params.progAtest[0].paramDeScratchprog.sortie = this.params.scratchProgDonnees.mypreDemo
      this.params.pourLaCo.isDemo = true
      this.params.pourLaCo.afficheUneCo = false
    }
    if (isCo) {
      this.params.progAtest[0].paramDeScratchprog.PasAPas = false
      this.params.progAtest[0].paramDeScratchprog.workspace = this.params.workspaceco
      this.params.progAtest[0].paramDeScratchprog.tabcodeX = this.scratchRunBlockly(this.params.workspaceco)
      this.params.pourLaCo.isDemo = true
      this.params.pourLaCo.afficheUneCo = false
    }
    this.params.progAtest[0].paramDeScratchprog.variables = this.chopeVariables(this.params.progAtest[0].paramDeScratchprog.workspace)
    isCompleteTest = isCompleteTest || isDef
    if (isCompleteTest) {
      this.params.progAtest[0].PasAPas = false
      this.params.pourLaCo.isDef = true
      // si yaFauxXlav
      if (this.params.yaFauxClavier) this.params.progAtest = this.metsLesEvents()
      // test si ya utilisateur
      // pas dans lui ? this.params.progAtest[0].paramDeScratchprog.tabcodeX
      if (this.params.scratchProgDonnees.listValPos) {
        if (this.params.scratchProgDonnees.listValPos.length > 0) this.params.progAtest = this.metsLesValUtilatest()
      }
      // test si ya aleatoire
      if (this.params.valideAlea) this.params.progAtest = this.completeLesCasAvecAlea()
      //
      if (this.params.radarPos) this.params.progAtest = this.completeLesRadarPos()
      //
      if (this.params.yaCaseAlea) this.params.progAtest = this.completeLesCasAvecAleaCases()
    }
    if (!isDemo && !isCo) {
      if (this.params.pourLaCo.aVerif) {
        this.params.pourLaCo.suiteAverif = this.veriflesaverif(this.params.pourLaCo.aVerif, this.params.progAtest[0].paramDeScratchprog.workspace, this.params.progAtest[0].paramDeScratchprog.variables, this.params.progAtest[0].paramDeScratchprog.tabcodeX)
      }
      if (this.params.progAtest.length > 1) {
        this.params.progAtest = this.metToutVite()
        this.params.progAtest = this.metToutCache()
      }
    }
    if (koi.indexOf('Vite') !== -1) {
      this.params.progAtest = this.metToutVite()
    }

    this.params.onARelance = false
    this.params.modeCompare = false
    this.params.messageRelance = undefined
    this.params.scratchProgDonnees.isDemo = isDemo
    this.params.scratchProgDonnees.isCo = isCo
    this.params.scratchProgDonnees.isDef = isDef
    this.params.scratchProgDonnees.valAleaVerif = undefined
    // on lance le 1er prog
    if (this.params.me.etat === 'correction') {
      if (this.params.scratchProgDonnees.fautChekAllAlea) {
        // faut que je chope les bornes
        // si ya un pb je met fin
        this.params.scratchProgDonnees.valeursaleatoiressorties = []
        if (!Array.isArray(this.params.progAtest[0].paramDeScratchprog.tabcodeX)) {
          this.params.pourLaCo.suiteAverif.fautAnnule = true
          this.params.pourLaCo.suiteAverif.avertissements = ['Il y a un problème avec le début du programme !']
        } else {
          if (!Array.isArray(this.params.progAtest[0].paramDeScratchprog.tabcodeX[0])) {
            this.params.pourLaCo.suiteAverif.fautAnnule = true
            this.params.pourLaCo.suiteAverif.avertissements = ['Il y a un problème avec le début du programme !']
          } else {
            if (!(this.params.progAtest[0].paramDeScratchprog.tabcodeX[0][1])) {
              this.params.pourLaCo.suiteAverif.fautAnnule = true
              this.params.pourLaCo.suiteAverif.avertissements = ['Il y a un problème avec le début du programme !']
            } else {
              try {
                this.params.osef = true
                this.params.progAtest[0].paramDeScratchprog.tabcodeX[0][1].javascript()
                this.params.osef = false
              } catch (e) {
                // eslint-disable-next-line no-console
                console.log('Normal')
              }
              this.params.osef = false
              if (!Array.isArray(this.params.scratchProgDonnees.valeursaleatoiressorties)) {
                this.params.pourLaCo.suiteAverif.fautAnnule = true
                this.params.pourLaCo.suiteAverif.avertissements = ['Il y a un problème avec le début du programme !']
              } else {
                if (this.params.scratchProgDonnees.valeursaleatoiressorties.length < 1) {
                  this.params.pourLaCo.suiteAverif.fautAnnule = true
                  this.params.pourLaCo.suiteAverif.avertissements = ['Il y a un problème avec le début du programme !']
                } else {
                  const pourTrav = this.params.scratchProgDonnees.valeursaleatoiressorties[0]
                  if (Math.abs(pourTrav.borne1 - pourTrav.borne2) > 10000) {
                    this.params.pourLaCo.suiteAverif.fautAnnule = true
                    this.params.pourLaCo.suiteAverif.avertissements = ['Le nombre de cas à tester est trop important pour moi !<br>Tu peux résoudre cet exercice en réduisant le nombre de cas possibles.']
                  } else {
                    this.params.progAtest = this.completeLesCasAvecAleaVerif(pourTrav)
                  }
                }
              }
            }
          }
        }
      }
    }

    this.params.progAtest.splice(100, this.params.progAtest.length)
    this.params.numProgEncours = 0

    if (this.params.pourLaCo.suiteAverif.fautAnnule) {
      if (this.params.scratchProgDonnees.isDef) {
        this.faisFinVerifRun(false, this.metChaine(this.params.pourLaCo.suiteAverif.avertissements))
        return
      } else {
        if (!this.params.NbEssaiIllimite) {
          if (this.params.me.etat === 'correction') {
            this.params.nbEssais--
            if (this.params.nbEssais === 0) {
              this.faisFinVerifRun(false, this.metChaine(this.params.pourLaCo.suiteAverif.avertissements))
              return
            }
          }
        }
        const lim = this.metLim()
        this.afficheModaleSimple(this.params.pourLaCo.suiteAverif.avertissements[this.params.pourLaCo.suiteAverif.avertissements.length - 1], 'Erreur', null, lim)
        this.retireWork()
        this.remetBienLesBoutons()
        return
      }
    }

    this.lanceUnProg(this.params.progAtest[this.params.numProgEncours])
  }

  lanceUnProg (nprog) {
    this.params.scratchProgDonnees.mem = [j3pGetRandomInt(2, 12)]
    this.params.scratchProgDonnees.mem.push(this.params.scratchProgDonnees.mem[0] + j3pGetRandomInt(2, 12))
    this.params.scratchProgDonnees.mem.push(this.params.scratchProgDonnees.mem[1] + j3pGetRandomInt(2, 12))
    this.params.scratchProgDonnees.regMem = j3pClone(this.params.scratchProgDonnees.mem)
    this.params.scratchProgDonnees.valeursaleatoiressorties = []
    this.params.scratchProgDonnees.avertissements = []
    this.params.scratchProgDonnees.said = []
    this.params.scratchProgDonnees.lignetracees = []
    this.params.scratchProgDonnees.reponseDonnesAGetUS = []
    this.params.scratchProgDonnees.aleaCasesSortie = []
    this.params.scratchProgDonnees.lesCases = {}
    this.params.scratchProgDonnees.Valeursutilisees = []
    this.params.scratchProgDonnees.Valeursautorisees = j3pClone(this.params.scratchProgDonnees.Valeursdebaseautorisees)
    this.params.scratchProgDonnees.variables = j3pClone(nprog.paramDeScratchprog.variables)
    // faut que jenregistre les dessins
    // les trucs dit
    // les reponses donnees
    // les nb aléa ( pas sur, cest peut etre predefini , mais quand même )
    // les positions de fin
    // les couleurs de cases
    // les variables
    this.params.valAleoOblige = j3pClone(nprog.paramDeScratchprog.valAlea)
    this.params.valRadarOblige = nprog.paramDeScratchprog.valRadar
    if (this.params.yaCaseAlea) {
      if (nprog.paramDeScratchprog.randomCase) {
        this.params.scratchProgDonnees.randomCases = j3pClone(nprog.paramDeScratchprog.randomCase)
      } else {
        this.params.scratchProgDonnees.randomCases = j3pShuffle(this.params.scratchProgDonnees.cases).pop()
      }
    }
    nprog.paramDeScratchprog.randomCase = j3pClone(this.params.scratchProgDonnees.randomCases)
    if (this.isMtg) this.params.MtgSortieD.show2()
    this.scratchReinitPartiel(nprog.sortie)
    if (nprog.modaleText && !nprog.paramDeScratchprog.cacheTest && !nprog.paramDeScratchprog.vite) {
      this.afficheModaleSimple(nprog.modaleText, 'Message', () => {
        this.finlanceProg(nprog)
      }, tuxImg)
      return
    }

    this.finlanceProg(nprog)
  }

  finlanceProg (nprog) {
    let arte = false
    for (let i = 0; i < nprog.paramDeScratchprog.tabcodeX.length; i++) {
      if ((nprog.paramDeScratchprog.tabcodeX[i][0].type === 'event') && (nprog.paramDeScratchprog.tabcodeX[i][0].eventtype === nprog.eventAt)) {
        arte = true
        this.params.indexProgEncours = i
        this.yaeuLanceProg = true
        if (this.params.me.etat === 'correction') {
          this.scratchCacheCo(this.lesdivs.contBlockly, 'rien')
        }
        this._lanceProgLinstener(nprog, i)
        return
      }
    }
    if (!arte) {
      this.yaeuLanceProg = false
      this.scratchVerifRun()
    }
  }

  metToutVite () {
    const aret = []
    for (let i = 0; i < this.params.progAtest.length; i++) {
      aret.push({
        paramDeScratchprog: {
          PasAPas: false,
          cacheTest: this.params.progAtest[i].paramDeScratchprog.cacheTest,
          workspace: this.params.progAtest[i].paramDeScratchprog.workspace,
          tabcodeX: this.params.progAtest[i].paramDeScratchprog.tabcodeX,
          event: this.params.progAtest[i].paramDeScratchprog.event,
          sortie: this.params.progAtest[i].paramDeScratchprog.sortie,
          variables: j3pClone(this.params.progAtest[i].paramDeScratchprog.variables),
          valAlea: j3pClone(this.params.progAtest[i].paramDeScratchprog.valAlea),
          valRadar: this.params.progAtest[i].paramDeScratchprog.valRadar,
          valGetUs: j3pClone(this.params.progAtest[i].paramDeScratchprog.valGetUs),
          cKi: this.params.progAtest[i].paramDeScratchprog.cKi,
          vite: true
        },
        modaleText: this.params.progAtest[i].modaleText,
        eventAt: this.params.progAtest[i].eventAt
      })
    }
    return aret
  }

  metToutCache () {
    const aret = []
    for (let i = 0; i < this.params.progAtest.length; i++) {
      aret.push({
        paramDeScratchprog: {
          PasAPas: false,
          cacheTest: true,
          workspace: this.params.progAtest[i].paramDeScratchprog.workspace,
          tabcodeX: this.params.progAtest[i].paramDeScratchprog.tabcodeX,
          event: this.params.progAtest[i].paramDeScratchprog.event,
          sortie: this.params.progAtest[i].paramDeScratchprog.sortie,
          variables: j3pClone(this.params.progAtest[i].paramDeScratchprog.variables),
          valAlea: j3pClone(this.params.progAtest[i].paramDeScratchprog.valAlea),
          valRadar: this.params.progAtest[i].paramDeScratchprog.valRadar,
          valGetUs: j3pClone(this.params.progAtest[i].paramDeScratchprog.valGetUs),
          cKi: this.params.progAtest[i].paramDeScratchprog.cKi,
          vite: this.params.progAtest[i].paramDeScratchprog.vite
        },
        modaleText: this.params.progAtest[i].modaleText,
        eventAt: this.params.progAtest[i].eventAt
      })
    }
    return aret
  }

  tradEvt (ki) {
    switch (ki) {
      case 'drapeau': return '"clic sur le drapeau"'
      case '◄': return '"appuis sur la touche ◄ du clavier"'
      case '►': return '"appuis sur la touche ► du clavier"'
      case '▲': return '"appuis sur la touche ▲ du clavier"'
      case '▼': return '"appuis sur la touche ▼ du clavier"'
      case 'ª': return '"appuis sur la touche <b>a</b> du clavier"'
      case '▂': return '"appuis sur la touche ▂ du clavier"'
      case 'sous': return '"clic gauche de la souris sur le lutin"'
    }
    return '?'
  }

  metsLesEvents () {
    const aret = []
    const listEvent = ['drapeau', '◄', '►', '▲', '▼', 'ª', '▂', 'sous']
    for (let i = 0; i < this.params.progAtest.length; i++) {
      for (let j = 0; j < listEvent.length; j++) {
        aret.push({
          paramDeScratchprog: {
            vite: this.params.progAtest[i].paramDeScratchprog.vite,
            PasAPas: this.params.progAtest[i].paramDeScratchprog.PasAPas,
            cacheTest: this.params.progAtest[i].paramDeScratchprog.cacheTest,
            workspace: this.params.progAtest[i].paramDeScratchprog.workspace,
            tabcodeX: this.params.progAtest[i].paramDeScratchprog.tabcodeX,
            event: this.params.progAtest[i].paramDeScratchprog.event,
            sortie: this.params.progAtest[i].paramDeScratchprog.sortie,
            variables: j3pClone(this.params.progAtest[i].paramDeScratchprog.variables),
            valAlea: j3pClone(this.params.progAtest[i].paramDeScratchprog.valAlea),
            valRadar: this.params.progAtest[i].paramDeScratchprog.valRadar,
            valGetUs: j3pClone(this.params.progAtest[i].paramDeScratchprog.valGetUs),
            cKi: this.params.progAtest[i].paramDeScratchprog.cKi
          },
          modaleText: 'Bonjour,<br> Je suis l\'utilisateur qui va tester ton programme.<br><br>Je vais déclencher l\'événement <br><b>' + this.tradEvt(listEvent[j]) + '</b><br> pour ce test.',
          eventAt: listEvent[j]
        })
      }
    }
    return j3pShuffle(aret)
  }

  veriflesaverif = function (averif, workspace, variables, tabCodex) {
    if (!averif) return { avertissements: [], listeFlag: [], fautAnnule: false }
    let yaeubesoinbloc = false
    const avertissements = []
    const listeFlag = []
    let fautAnnule = false
    let quandAvertir = 'après'
    const listePlace = ['']
    const nb = this.scratchCompteBloc(workspace)
    for (let i = 0; i < averif.length; i++) {
      if (averif[i].quoi === 'NombreDeBlocs') {
        if (nb.cmpt < averif[i].combien) {
          avertissements.push('Il n’y a pas assez de blocs !')
        }
        if (nb.cmpt > averif[i].combien) {
          avertissements.push('Il y a trop de blocs !')
        }
      }
      if (averif[i].quoi === 'NombreMaxBlocs' || averif[i].quoi === 'NombreMaxBloc') {
        if (averif[i].combien === undefined) averif[i].combien = averif[i].nombre
        if (nb.cmpt > averif[i].combien) {
          avertissements.push('Il y a trop de blocs !')
        }
      }
      if (averif[i].quoi === 'ExisteVar') {
        for (let j = 0; j < averif[i].nom.length; j++) {
          if (!this.ExisteVar(averif[i].nom[j], variables)) {
            avertissements.push('Tu n’as pas créé la variable <i>' + averif[i].nom[j] + '</i>')
          }
        }
      }

      if (averif[i].quoi === 'BesoinBloc') {
        if (!this.presenceBloc(averif[i].nom, tabCodex, listePlace)) {
          let ghj = this.scratchTraduireOrdre(averif[i].nom)
          if (ghj === 'Getus') ghj = 'demander'
          avertissements.push('Tu n’as pas utilisé le bloc <i>' + ghj + '</i>')
          yaeubesoinbloc = true
        }
      }
      if (averif[i].quoi === 'Flag') {
        listeFlag.push(averif[i].nombre)
      }

      if ((averif[i].quoi === 'BesoinniemeBloc') && (!yaeubesoinbloc)) {
        if (listePlace[averif[i].place] !== averif[i].nom) {
          avertissements.push('Le bloc <i>' + averif[i].nom + '</i> n’est pas à la bonne place !')
        }
      }
      if (averif[i].quoi === 'QuandAvertir') {
        quandAvertir = averif[i].quand
      }
      if (averif[i].quoi === 'AnnuleSiAvert') {
        fautAnnule = averif[i].annule
      }
    }
    return { avertissements, listeFlag, fautAnnule, quandAvertir }
  }

  presenceBloc (qui, tabCodex, listePlace) {
    let prz = false
    if (!tabCodex) return false
    if (tabCodex.length === 0) return false
    for (let i = 0; i < tabCodex[0].length; i++) {
      if (!tabCodex[0][i]) continue
      if (tabCodex[0][i].nom === qui) {
        listePlace.push(qui)
        prz = true
      }
      if (tabCodex[0][i].type === 'boucle') { prz = prz || this.presenceBloc(qui, tabCodex[0][i].boucle) }
      if (tabCodex[0][i].type === 'boucleU') { prz = prz || this.presenceBloc(qui, tabCodex[0][i].boucle) }
      if (tabCodex[0][i].type === 'boucleF') { prz = prz || this.presenceBloc(qui, tabCodex[0][i].boucle) }
      if (tabCodex[0][i].type === 'si') {
        prz = prz || this.presenceBloc(qui, tabCodex[0][i].sioui)
        prz = prz || this.presenceBloc(qui, tabCodex[0][i].sinon)
      }
    }
    return prz
  }

  ExisteVar (qui, variables) {
    for (let i = 0; i < variables.length; i++) {
      if (variables[i].name === qui) return true
    }
    return false
  }

  completeLesCasAvecAlea () {
    const valideAleaTempToT = []
    for (let i = 0; i < this.params.valideAlea.length; i++) {
      valideAleaTempToT.push(j3pShuffle(j3pClone(this.params.valideAlea[i])))
    }
    const valideAleaTempTot2 = this.tousLesCas(valideAleaTempToT)
    const aret = []
    for (let i = 0; i < this.params.progAtest.length; i++) {
      for (let j = 0; j < valideAleaTempTot2.length; j++) {
        aret.push({
          paramDeScratchprog: {
            vite: this.params.progAtest[i].paramDeScratchprog.vite,
            PasAPas: this.params.progAtest[i].paramDeScratchprog.PasAPas,
            cacheTest: this.params.progAtest[i].paramDeScratchprog.cacheTest,
            workspace: this.params.progAtest[i].paramDeScratchprog.workspace,
            tabcodeX: this.params.progAtest[i].paramDeScratchprog.tabcodeX,
            event: this.params.progAtest[i].paramDeScratchprog.event,
            sortie: this.params.progAtest[i].paramDeScratchprog.sortie,
            variables: j3pClone(this.params.progAtest[i].paramDeScratchprog.variables),
            valAlea: j3pClone(valideAleaTempTot2[j]),
            valGetUs: j3pClone(this.params.progAtest[i].paramDeScratchprog.valGetUs),
            valRadar: this.params.progAtest[i].paramDeScratchprog.valRadar,
            cKi: this.params.progAtest[i].paramDeScratchprog.cKi
          },
          modaleText: this.params.progAtest[i].modaleText,
          eventAt: this.params.progAtest[i].eventAt
        })
      }
    }
    return j3pShuffle(aret)
  }

  completeLesCasAvecAleaCases () {
    const aret = []
    for (let i = 0; i < this.params.progAtest.length; i++) {
      for (let j = 0; j < this.params.scratchProgDonnees.cases.length; j++) {
        aret.push({
          paramDeScratchprog: {
            vite: true,
            PasAPas: false,
            cacheTest: true,
            workspace: this.params.progAtest[i].paramDeScratchprog.workspace,
            tabcodeX: this.params.progAtest[i].paramDeScratchprog.tabcodeX,
            event: this.params.progAtest[i].paramDeScratchprog.event,
            sortie: this.params.progAtest[i].paramDeScratchprog.sortie,
            variables: j3pClone(this.params.progAtest[i].paramDeScratchprog.variables),
            valAlea: j3pClone(this.params.progAtest[i].paramDeScratchprog.valAlea),
            valGetUs: j3pClone(this.params.progAtest[i].paramDeScratchprog.valGetUs),
            valRadar: this.params.progAtest[i].paramDeScratchprog.valRadar,
            cKi: this.params.progAtest[i].paramDeScratchprog.cKi,
            randomCase: this.params.scratchProgDonnees.cases[j]
          },
          modaleText: this.params.progAtest[i].modaleText,
          eventAt: this.params.progAtest[i].eventAt
        })
      }
    }
    return j3pShuffle(aret)
  }

  makeAleaCases (tab) {
    const listDesAlea = []
    for (let i = 0; i < tab.length; i++) {
      let cCaseAle = tab[i].cox.length > 1
      cCaseAle = cCaseAle || tab[i].coy.length > 1
      cCaseAle = cCaseAle || tab[i].coul.length > 1
      if (cCaseAle) {
        listDesAlea.push(this.tousLesPetitsCas(tab[i]))
      }
    }
    // liste listDesAlea = [ [ tous les alea1] [tous les alea2]  .... [tousles alean] ]
    // je dois faire pour chaque de alea1 je colle un de chaque alea, puis pour chaque
    return j3pShuffle(this.combineLesAleaCase(listDesAlea))
  }

  combineLesAleaCase (tab) {
    let arte = []
    for (let i = 0; i < tab[0].length; i++) {
      arte.push([tab[0][i]])
    }
    for (let i = 1; i < tab.length; i++) {
      const acop = j3pClone(arte)
      const newC = []
      const tact = arte.length
      for (let j = 0; j < tact; j++) {
        for (let k = 0; k < tab[i].length; k++) {
          newC.push(acop[j].concat(tab[i][k]))
        }
      }
      arte = j3pClone(newC)
    }
    return arte
  }

  tousLesPetitsCas (caseAlea) {
    const arte = []
    for (let i = 0; i < caseAlea.cox.length; i++) {
      for (let j = 0; j < caseAlea.coy.length; j++) {
        for (let k = 0; k < caseAlea.coul.length; k++) {
          arte.push({ cox: caseAlea.cox[i], coy: caseAlea.coy[j], coul: this.fileCouleur(caseAlea.coul[k]) })
        }
      }
    }
    return arte
  }

  completeLesCasAvecAleaVerif (obj) {
    const valideAleaTempToT = []
    const bornesup = Math.max(Number(obj.borne1), Number(obj.borne2))
    const borneinf = Math.min(Number(obj.borne1), Number(obj.borne2))
    this.params.scratchProgDonnees.AleaResult = { att: bornesup - borneinf + 1, rez: [] }
    for (let i = borneinf; i < bornesup + 1; i++) {
      valideAleaTempToT.push(i)
    }
    const aret = []
    for (let i = 0; i < this.params.progAtest.length; i++) {
      for (let j = 0; j < valideAleaTempToT.length; j++) {
        aret.push({
          paramDeScratchprog: {
            vite: true,
            PasAPas: false,
            cacheTest: true,
            workspace: this.params.progAtest[i].paramDeScratchprog.workspace,
            tabcodeX: this.params.progAtest[i].paramDeScratchprog.tabcodeX,
            event: this.params.progAtest[i].paramDeScratchprog.event,
            sortie: this.params.progAtest[i].paramDeScratchprog.sortie,
            variables: j3pClone(this.params.progAtest[i].paramDeScratchprog.variables),
            valAleaVerif: valideAleaTempToT[j],
            valAlea: [],
            valGetUs: j3pClone(this.params.progAtest[i].paramDeScratchprog.valGetUs),
            valRadar: this.params.progAtest[i].paramDeScratchprog.valRadar,
            cKi: this.params.progAtest[i].paramDeScratchprog.cKi
          },
          modaleText: this.params.progAtest[i].modaleText,
          eventAt: this.params.progAtest[i].eventAt
        })
      }
    }
    return j3pShuffle(aret)
  }

  completeLesRadarPos () {
    // pour chaque element de tab (des situations de prog a tester )
    // le duplique avec des valeursAleatoireAtester
    // { ce qu il y avait avant, ... , x: v1, y: v1}, { ce qu il y avait avant, ... , x: v1, y: v2 }
    // les val aléatoires viennent de
    // une liste dans ?
    // des val aleatoires dansle progdeb
    // des places de cases alatoires
    // un radar fuseee
    // precise si il veut voir plusieurs cas dans les progs ( pour radar il veut )
    const valideAleaTempToT = j3pShuffle(this.params.radarPos)
    const aret = []
    for (let i = 0; i < this.params.progAtest.length; i++) {
      for (let j = 0; j < valideAleaTempToT.length; j++) {
        aret.push({
          paramDeScratchprog: {
            vite: this.params.progAtest[i].paramDeScratchprog.vite,
            PasAPas: this.params.progAtest[i].paramDeScratchprog.PasAPas,
            cacheTest: this.params.progAtest[i].paramDeScratchprog.cacheTest,
            workspace: this.params.progAtest[i].paramDeScratchprog.workspace,
            tabcodeX: this.params.progAtest[i].paramDeScratchprog.tabcodeX,
            event: this.params.progAtest[i].paramDeScratchprog.event,
            sortie: this.params.progAtest[i].paramDeScratchprog.sortie,
            variables: j3pClone(this.params.progAtest[i].paramDeScratchprog.variables),
            valAlea: j3pClone(this.params.progAtest[i].paramDeScratchprog.valAlea),
            valRadar: valideAleaTempToT[j],
            valGetUs: j3pClone(this.params.progAtest[i].paramDeScratchprog.valGetUs),
            cKi: this.params.progAtest[i].paramDeScratchprog.cKi
          },
          modaleText: this.params.progAtest[i].modaleText,
          eventAt: this.params.progAtest[i].eventAt
        })
      }
    }
    return j3pShuffle(aret)
  }

  tousLesCas (tab) {
    const aret = []
    if (tab.length === 1) {
      for (let i = 0; i < tab[0].length; i++) {
        aret.push([tab[0][i]])
      }
      return aret
    } else {
      const aaj = []
      for (let i = 1; i < tab.length; i++) {
        aaj.push(j3pClone(tab[i]))
      }
      const aajou = this.tousLesCas(aaj)
      for (let i = 0; i < tab[0].length; i++) {
        const amettre = [tab[0][i]]
        for (let j = 0; j < aajou.length; j++) {
          const amettre2 = amettre.concat(aajou[j])
          aret.push(amettre2)
        }
      }
    }
    return aret
  }

  metsLesValUtilatest () {
    this.params.scratchProgDonnees.YaUtilisateur = true
    const valideAleaTempTot2 = this.params.scratchProgDonnees.listValPos
    const aret = []
    for (let i = 0; i < this.params.progAtest.length; i++) {
      for (let j = 0; j < valideAleaTempTot2.length; j++) {
        aret.push({
          paramDeScratchprog: {
            vite: this.params.progAtest[i].paramDeScratchprog.vite,
            PasAPas: this.params.progAtest[i].paramDeScratchprog.PasAPas,
            cacheTest: this.params.progAtest[i].paramDeScratchprog.cacheTest,
            workspace: this.params.progAtest[i].paramDeScratchprog.workspace,
            tabcodeX: this.params.progAtest[i].paramDeScratchprog.tabcodeX,
            event: this.params.progAtest[i].paramDeScratchprog.event,
            sortie: this.params.progAtest[i].paramDeScratchprog.sortie,
            variables: j3pClone(this.params.progAtest[i].paramDeScratchprog.variables),
            valGetUs: j3pClone(valideAleaTempTot2[j]),
            valAlea: j3pClone(this.params.progAtest[i].paramDeScratchprog.valAlea),
            valRadar: this.params.progAtest[i].paramDeScratchprog.valRadar,
            cKi: this.params.progAtest[i].paramDeScratchprog.cKi
          },
          modaleText: 'Bonjour, <br> je suis l\'utilisateur qui va tester ton programme.',
          eventAt: this.params.progAtest[i].eventAt
        })
      }
    }
    return j3pShuffle(aret)
  }

  scratchVireRadar () {
    const cox = this.params.scratchProgDonnees.Lutins[0].cox
    const coy = this.params.scratchProgDonnees.Lutins[0].coy
    if (cox === this.params.MonRadarX && coy === this.params.MonRadarY) {
      let lalea = this.params.valRadarOblige
      if (!lalea && this.params.radarPos) {
        do {
          lalea = this.params.radarPos[j3pGetRandomInt(0, this.params.radarPos.length - 1)]
        } while (lalea === this.params.oldAleaRadar)
      }
      this.params.oldAleaRadar = lalea
      const elt = this.params.MonRadar
      const urls = [
        '',
        terreImg,
        blackholeImg,
        planetrougeImg,
        cosmoImg
      ]
      const listequoi = ['', 'terre', 'trou', 'mars', 'cosmo']
      const indice = listequoi.indexOf(lalea)
      const url = urls[indice]
      if (indice !== 0) {
        elt.setAttributeNS('http://www.w3.org/1999/xlink', 'xlink:href', url)
      } else {
        j3pDetruit(this.params.MonRadar)
      }
      this.params.scratchProgDonnees.cartefusee[this.params.MonRadarX][this.params.MonRadarY] = indice
    }
  }

  scratchIdDispo () {
    for (let i = 0; i < 10000; i++) {
      if (this.params.scratchProgDonnees.lesidprog.indexOf(i) === -1) {
        this.params.scratchProgDonnees.lesidprog.push(i)
        return i
      }
    }
    j3pShowError(Error('Trop de programmes en cours'))
  }

  scratchReinit () {
    this.fautRinit = false
    this.montreDrapeaux()
    this.cacheBoutonReinit()
    this.params.scratchProgDonnees.runable = true
    this.params.foraz = true
    j3pDetruit('inputdivtot') // pas de pb si ça existe pas
    // this.lesdivs.stop.style.display = 'none'
    // if (this.params.me.etat === 'correction') { this.lesdivs.PASAPAS.style.display = '' }
    // this.lesdivs.PASAPASBOOT.style.display = 'none'
    if (this.pasapas) {
      this.pasapas.disabled = false
    }
    if (this.params.getUp) this.params.getUp.style.display = ''
    // mettre un display vide les rends visible (block ou inline suivant ce que c’est)
    if (this.params.me.etat === 'enonce') {
      this.params.me.buttonsElts.suite.style.display = ''
    }
    if (this.params.me.etat === 'navigation') {
      this.params.me.buttonsElts.sectionSuivante.style.display = ''
    }

    if (this.lesdivs.RetourIm) this.lesdivs.RetourIm.style.display = ''

    this.params.scratchProgDonnees.Lutins[0].cox = this.params.scratchProgDonnees.Lutins[0].coxbase
    this.params.scratchProgDonnees.Lutins[0].coy = this.params.scratchProgDonnees.Lutins[0].coybase
    this.params.scratchProgDonnees.Lutins[0].angle = this.params.scratchProgDonnees.Lutins[0].anglebase
    this.params.scratchProgDonnees.Lutins[0].hauteur = this.params.scratchProgDonnees.Lutins[0].hauteurbase
    this.params.scratchProgDonnees.Lutins[0].StyloPose = false
    if (this.params.yabras) {
      this.params.scratchProgDonnees.donneesbras.tapis1 = this.params.scratchProgDonnees.donneesbrasbase.tapis1
      this.params.scratchProgDonnees.donneesbras.tapis2 = this.params.scratchProgDonnees.donneesbrasbase.tapis2
      this.params.scratchProgDonnees.donneesbras.tapis3 = this.params.scratchProgDonnees.donneesbrasbase.tapis3
      this.params.scratchProgDonnees.donneesbras.tapis4 = this.params.scratchProgDonnees.donneesbrasbase.tapis4
      this.params.scratchProgDonnees.donneesbras.bras = this.params.scratchProgDonnees.donneesbrasbase.bras
    }
    this.scratchResetFlag()
    this.traceSortieBase({ sortie: this.lesdivs.sortieEl })
  }

  scratchReinitPartiel (sortie) {
    this.params.scratchProgDonnees.carteCases = [
      ['vide', 'vide', 'vide', 'vide', 'vide', 'vide'],
      ['vide', 'vide', 'vide', 'vide', 'vide', 'vide'],
      ['vide', 'vide', 'vide', 'vide', 'vide', 'vide'],
      ['vide', 'vide', 'vide', 'vide', 'vide', 'vide'],
      ['vide', 'vide', 'vide', 'vide', 'vide', 'vide'],
      ['vide', 'vide', 'vide', 'vide', 'vide', 'vide']
    ]
    for (const figure of this.params.figureAfaire) {
      switch (figure.type) {
        case 'Cases' : {
          const lx = j3pShuffle(figure.x).pop()
          const ly = j3pShuffle(figure.y).pop()
          const coul = j3pShuffle(figure.coul).pop()
          this.params.scratchProgDonnees.carteCases[lx - 1][ly - 1] = this.recupeCoul(coul)
          break
        }
      }
    }
    if (this.params.scratchProgDonnees.randomCases) {
      for (let i = 0; i < this.params.scratchProgDonnees.randomCases.length; i++) {
        const figure = this.params.scratchProgDonnees.randomCases[i]
        const lx = figure.cox - 1
        const ly = figure.coy - 1
        const coul = figure.coul
        this.params.scratchProgDonnees.carteCases[lx][ly] = this.recupeCoul(coul)
      }
    }
    this.params.scratchProgDonnees.Lutins[0].cox = this.params.scratchProgDonnees.Lutins[0].coxbase
    this.params.scratchProgDonnees.Lutins[0].coy = this.params.scratchProgDonnees.Lutins[0].coybase
    this.params.scratchProgDonnees.Lutins[0].angle = this.params.scratchProgDonnees.Lutins[0].anglebase
    this.params.scratchProgDonnees.Lutins[0].hauteur = this.params.scratchProgDonnees.Lutins[0].hauteurbase
    this.params.scratchProgDonnees.Lutins[0].StyloPose = false
    if (this.params.yabras) {
      this.params.scratchProgDonnees.donneesbras.tapis1 = this.params.scratchProgDonnees.donneesbrasbase.tapis1
      this.params.scratchProgDonnees.donneesbras.tapis2 = this.params.scratchProgDonnees.donneesbrasbase.tapis2
      this.params.scratchProgDonnees.donneesbras.tapis3 = this.params.scratchProgDonnees.donneesbrasbase.tapis3
      this.params.scratchProgDonnees.donneesbras.tapis4 = this.params.scratchProgDonnees.donneesbrasbase.tapis4
      this.params.scratchProgDonnees.donneesbras.bras = this.params.scratchProgDonnees.donneesbrasbase.bras
    }
    this.scratchResetFlag()
    if (!this.params.modeCompare && sortie) this.traceSortieBase({ sortie })
  }

  scratchMohaReinitPartiel () {
    this.params.scratchProgDonnees.Lutins[0].cox = this.params.scratchProgDonnees.Lutins[0].coxbase
    this.params.scratchProgDonnees.Lutins[0].coy = this.params.scratchProgDonnees.Lutins[0].coybase
    this.params.scratchProgDonnees.Lutins[0].angle = this.params.scratchProgDonnees.Lutins[0].anglebase
    this.params.scratchProgDonnees.Lutins[0].hauteur = this.params.scratchProgDonnees.Lutins[0].hauteurbase
    this.params.scratchProgDonnees.Lutins[0].StyloPose = false
    this.scratchResetFlag()
  }

  scratchDePause () {
    this.params.scratchProgDonnees.pause = false
  }

  afficheModaleSimple (texte, titre, fonc, image) {
    if (this.params.isEditing) {
      j3pEmpty(this.params.mtgEditoText)
      j3pAffiche(this.params.mtgEditoText, null, texte)
      return
    }
    const imaaMettre = image || tuxImg
    const uu = j3pModale({ titre, contenu: '' })
    uu.style.left = '20px'
    uu.style.top = '20px'
    const tab = addDefaultTable(uu, 2, 1)
    const tabu = addDefaultTable(tab[0][0], 1, 3)
    const tab2 = addDefaultTable(tab[1][0], 1, 3)
    const lim = j3pAddElt(tabu[0][0], 'img', '', { src: imaaMettre, alt: 'Charlie', height: '20px', width: '20px' })
    lim.style.width = '150px'
    lim.style.height = '150px'
    lim.style.background = '#fff'
    lim.style.borderWidth = '10px'
    lim.style.borderStyle = 'ridge'
    lim.style.borderColor = '#eac43b'
    lim.style.borderRadius = '5px'
    tabu[0][2].classList.add('ScratchFeedback')
    j3pAffiche(tabu[0][2], null, texte)
    j3pAddContent(tabu[0][1], '&nbsp;&nbsp;')
    if (titre === 'Erreur') tabu[0][1].classList.add('errormes')
    const boubout = j3pAjouteBouton(tab2[0][0], this.scratchFerme1.bind(this), { className: 'MepBoutons2', value: 'Fermer' })
    if (typeof fonc === 'function') {
      boubout.value = 'OK'
      boubout.addEventListener('click', fonc)
    }
    const elem = $('.croix')[0]
    j3pDetruit(elem)
    return uu
  }

  scratchVerifRun () {
    if (this.params.isEditing) {
      if (this.params.scratchProgDonnees.sortieAvecProb) {
        j3pEmpty(this.params.mtgEditoText)
        this.params.mtgEditoText.style.color = '#F00'
        j3pAddContent(this.params.mtgEditoText, '<b><u>Le programme s\'est terminé avec une erreur</u>:</b><br>')
        j3pAddContent(this.params.mtgEditoText, this.params.scratchProgDonnees.avertissements[this.params.scratchProgDonnees.avertissements.length - 1])
        this.scratchEditorMetPasOk()
      } else {
        j3pEmpty(this.params.mtgEditoText)
        this.params.mtgEditoText.style.color = '#166216'
        j3pAddContent(this.params.mtgEditoText, 'Programme terminé<br><br>')
      }
      this.params.scratchProgDonnees.run = false
      return
    }
    if (this.params.scratchProgDonnees.isDemo) {
      this.remetBienLesBoutons()
      return
    }
    if (this.params.me.etat !== 'correction') {
      this.remetBienLesBoutons()
      return
    }
    // SORTIE DE SCRATCHPROG AVEC PLANTAGE
    if (this.params.scratchProgDonnees.sortieAvecProb) {
      if (this.params.isMtgLibre) {
        this.afficheModaleSimple(this.params.scratchProgDonnees.avertissements[this.params.scratchProgDonnees.avertissements.length - 1], 'Erreur', null, imProgConst)
        this.remetBienLesBoutons()
        return
      }
      if (this.params.scratchProgDonnees.isDef) {
        if (this.params.progAtest[this.params.numProgEncours].paramDeScratchprog.cacheTest) {
          this.relanceLeMeme({ mess: '<b><u>Ton programme a déclenché une erreur:</u></b><br>' + this.params.scratchProgDonnees.avertissements[this.params.scratchProgDonnees.avertissements.length - 1], isGood: false, cacheTest: false, vite: !this.params.dirigeProg.sequence })
          return
        } else {
          this.faisFinVerifRun(false, ['<b><u>Ton programme a déclenché une erreur:</u></b>', this.params.scratchProgDonnees.avertissements[this.params.scratchProgDonnees.avertissements.length - 1]])
          return
        }
      } else {
        if (this.params.progAtest[this.params.numProgEncours].paramDeScratchprog.cacheTest) {
          this.relanceLeMeme({ mess: '<b><u>Ton programme a déclenché une erreur:</u></b><br>' + this.params.scratchProgDonnees.avertissements[this.params.scratchProgDonnees.avertissements.length - 1], isGood: false, cacheTest: false, vite: !this.params.dirigeProg.sequence })
          return
        } else {
          if (!this.params.NbEssaiIllimite) {
            if (this.params.me.etat === 'correction') {
              this.params.nbEssais--
              if (this.params.nbEssais === 0) {
                this.faisFinVerifRun(false, [this.params.scratchProgDonnees.avertissements[this.params.scratchProgDonnees.avertissements.length - 1], 'Objectif non atteint'])
                return
              }
            }
          }
          this.afficheModaleSimple(this.params.scratchProgDonnees.avertissements[this.params.scratchProgDonnees.avertissements.length - 1], 'Erreur', null, (this.isMtg) ? imProgConst : this.params.scratchProgDonnees.Lutins[0].img)
          this.retireWork()
          this.remetBienLesBoutons()
          return
        }
      }
    }
    // SORTIE DE SCRATCHPROG APRES une relance pour revoir
    if (this.params.onARelance) {
      if (this.params.scratchProgDonnees.isDef) {
        this.faisFinVerifRun(this.params.onARelanceGood, [this.params.messageRelance])
        return
      } else {
        const atex = (this.params.onARelanceGood) ? 'Objectif atteint' : 'Objectif non atteint'
        if (!this.params.NbEssaiIllimite) {
          if (this.params.me.etat === 'correction') {
            if (!this.params.onARelanceGood) {
              this.params.nbEssais--
              if (this.params.nbEssais === 0) {
                this.faisFinVerifRun(false, [this.params.messageRelance, 'Objectif non atteint'])
                return
              }
              this.afficheModaleSimple(this.params.messageRelance, atex, null, tuxImg)
            } else {
              this.faisFinVerifRun(true, ['Objectif atteint'])
              return
            }
          }
        } else {
          this.afficheModaleSimple(this.params.messageRelance, atex, null, tuxImg)
        }
        this.remetBienLesBoutons()
        return
      }
    }
    if (this.params.isMtgLibre) {
      this.afficheModaleSimple('Programme terminé', 'Fin du programme', null, imProgConst)
      this.remetBienLesBoutons()
      return
    }
    // SI on est en mode Comparaison, il faut lancer le programme pour comparer
    // en enregistrant tout avant
    let retFlagFin
    if (this.params.modeCorrection.type === 'Comparaison') {
      // si c un prog eleve, on enregistre tout
      // et on lance le prog suivant
      if (!this.params.modeCompare) {
        this.params.modeCompare = true
        this.params.Aconserve = {
          el: {
            lutin: j3pClone(this.params.scratchProgDonnees.Lutins),
            said: j3pClone(this.params.scratchProgDonnees.said),
            lignes: j3pClone(this.params.scratchProgDonnees.lignetracees),
            variables: j3pClone(this.params.scratchProgDonnees.variables),
            tabCase: j3pClone(this.params.scratchProgDonnees.carteCases)
          }
        }
        this.scratchReinitPartiel(this.lesdivs.sortieEl)
        const progCompare = this.faitProgCompare(this.params.progAtest[this.params.numProgEncours])
        this.lanceUnProg(progCompare)
        return
      } else {
        this.params.modeCompare = false
        this.params.Aconserve.moha = {
          lutin: j3pClone(this.params.scratchProgDonnees.Lutins),
          said: j3pClone(this.params.scratchProgDonnees.said),
          lignes: j3pClone(this.params.scratchProgDonnees.lignetracees),
          variables: j3pClone(this.params.scratchProgDonnees.variables),
          tabCase: j3pClone(this.params.scratchProgDonnees.carteCases)
        }
        this.params.Aconserve.ok = true
        retFlagFin = this.testFlagFin()
      }
      // si cest le progsuivant, on enregistre encore et on evoir tout a testflagfin
    } else {
      retFlagFin = this.testFlagFin()
    }
    if (this.yaeuLanceProg) {
      this.evenInterss.push({ num: this.params.numProgEncours, mess: retFlagFin.mess })
    }
    if (retFlagFin.ok && this.params.pourLaCo.suiteAverif.avertissements.length > 0) {
      retFlagFin.ok = false
      retFlagFin.mess = this.metChaine(this.params.pourLaCo.suiteAverif.avertissements)
    }
    // si retFlagFin pas ok
    if (retFlagFin.ok === false) {
      if (this.params.scratchProgDonnees.isDef) {
        if (this.params.progAtest[this.params.numProgEncours].paramDeScratchprog.cacheTest) {
          this.relanceLeMeme({ isGood: false, mess: retFlagFin.mess, cacheTest: false, vite: !this.params.dirigeProg.sequence })
          return
        } else {
          this.faisFinVerifRun(false, [retFlagFin.mess])
          return
        }
      } else {
        if (this.params.progAtest[this.params.numProgEncours].paramDeScratchprog.cacheTest) {
          this.relanceLeMeme({ isGood: false, mess: retFlagFin.mess, cacheTest: false, vite: !this.params.dirigeProg.sequence })
          return
        } else {
          if (!this.params.NbEssaiIllimite) {
            if (this.params.me.etat === 'correction') {
              this.params.nbEssais--
              if (this.params.nbEssais === 0) {
                this.faisFinVerifRun(false, [retFlagFin.mess, 'Objectif non atteint'])
                return
              }
            }
          }
          this.afficheModaleSimple(retFlagFin.mess, 'Objectif non atteint', null, (this.isMtg) ? imProgConst : tuxImg)
        }
      }
    } else {
      if (this.params.progAtest.length === this.params.numProgEncours + 1) {
        if (this.params.modeCorrection.type === 'Comparaison') {
          if (this.params.scratchProgDonnees.isDef) {
            if (this.params.progAtest[this.params.numProgEncours].paramDeScratchprog.cacheTest) {
              let mess = ''
              if (this.yaeuLanceProg) {
                this.params.numProgEncours = this.evenInterss[this.evenInterss.length - 1].num
                mess = this.evenInterss[this.evenInterss.length - 1].mess
              }
              this.relanceLeMeme({ isGood: true, mess, cacheTest: false, vite: !this.params.dirigeProg.sequence })
              return
            } else {
              this.faisFinVerifRun(true, ['Objectif atteint'])
              return
            }
          } else {
            if (this.params.progAtest[this.params.numProgEncours].paramDeScratchprog.cacheTest) {
              this.params.numProgEncours = this.evenInterss[this.evenInterss.length - 1].num
              const mess = this.evenInterss[this.evenInterss.length - 1].mess
              this.relanceLeMeme({ isGood: true, mess, cacheTest: false, vite: !this.params.dirigeProg.sequence })
              return
            } else {
              if (!this.params.NbEssaiIllimite) {
                this.faisFinVerifRun(true, ['Objectif atteint'])
                return
              }
              this.afficheModaleSimple('Objectif atteint', 'Fin du programme', null, (this.isMtg) ? imProgConst : tuxImg)
            }
          }
        } else {
          if (this.params.scratchProgDonnees.isDef) {
            if (this.params.progAtest[this.params.numProgEncours].paramDeScratchprog.cacheTest) {
              this.params.numProgEncours = this.evenInterss[this.evenInterss.length - 1].num
              const mess = this.evenInterss[this.evenInterss.length - 1].mess
              this.relanceLeMeme({ isGood: true, mess, cacheTest: false, vite: !this.params.dirigeProg.sequence })
              return
            } else {
              this.faisFinVerifRun(true, ['Objectif atteint'])
              return
            }
          } else {
            if (this.params.progAtest[this.params.numProgEncours].paramDeScratchprog.cacheTest) {
              if (this.evenInterss.length === 0) {
                this.faisFinVerifRun(false, ['Ce programme ne démarre pas'])
                return
              } else {
                this.params.numProgEncours = this.evenInterss[this.evenInterss.length - 1].num
                const mess = this.evenInterss[this.evenInterss.length - 1].mess
                this.relanceLeMeme({ isGood: true, mess, cacheTest: false, vite: !this.params.dirigeProg.sequence })
                return
              }
            } else {
              if (!this.params.NbEssaiIllimite) {
                this.faisFinVerifRun(true, ['Objectif atteint'])
                return
              }
              this.afficheModaleSimple('Objectif atteint', 'Fin du programme', null, (this.isMtg) ? imProgConst : tuxImg)
            }
          }
        }
      } else {
        if (this.params.modeCorrection.type === 'Comparaison') {
          this.params.numProgEncours++
          this.params.modeCompare = false
          this.scratchReinitPartiel()
          this.params.progAtest[this.params.numProgEncours].paramDeScratchprog.cacheTest = true
          this.params.progAtest[this.params.numProgEncours].paramDeScratchprog.vite = true
          this.lanceUnProg(this.params.progAtest[this.params.numProgEncours])
        } else {
          this.params.numProgEncours++
          this.scratchReinitPartiel()
          this.lanceUnProg(this.params.progAtest[this.params.numProgEncours])
        }
        return
      }
    }
    // apparemment tout remettre cetait ca
    //
    //
    this.remetBienLesBoutons()
    //
    //
    // oui oui ca
  }

  metLim () {
    let lim = (this.isMtg) ? imProgConst : this.params.scratchProgDonnees.Lutins[0].img
    if (this.params.scratchProgDonnees.YaUtilisateur) lim = tuxImg
    return lim
  }

  faisFinVerifRun (repEl, avert) {
    this.params.scratchProgDonnees.repEleve = repEl
    this.retireWork()
    this.params.scratchProgDonnees.avertissements = avert
    this.params.me.sectionCourante()
  }

  faitProgCompare (progEl) {
    const progaret = {
      paramDeScratchprog: {
        vite: true,
        PasAPas: false,
        cacheTest: true,
        workspace: this.params.workspaceDemo,
        tabcodeX: this.params.ProgCompare,
        event: progEl.paramDeScratchprog.event,
        sortie: progEl.paramDeScratchprog.sortie,
        valAlea: this.extraitVal(this.params.scratchProgDonnees.valeursaleatoiressorties),
        valGetUs: j3pClone(this.params.scratchProgDonnees.reponseDonnesAGetUS),
        cKi: 'compare',
        randomCase: j3pClone(progEl.paramDeScratchprog.randomCase)
      },
      modaleText: progEl.modaleText,
      eventAt: progEl.eventAt
    }
    progaret.paramDeScratchprog.variables = this.chopeVariables(this.params.workspaceDemo)
    return progaret
  }

  extraitVal (tab) {
    const aret = []
    for (let i = 0; i < tab.length; i++) {
      aret.push(tab[i].valeur)
    }
    return aret
  }

  chopeVariables (wkspace) {
    const variables = []
    const mmm = wkspace.getAllVariables()
    for (let i = 0; i < mmm.length; i++) {
      variables.push({ name: mmm[i].name, val: 'Vide', visible: true })
    }
    return variables
  }

  relanceLeMeme (options = {}) {
    this.params.onARelanceGood = options.isGood
    this.params.onARelance = true
    this.params.messageRelance = options.mess
    if (options.cacheTest !== undefined) this.params.progAtest[this.params.numProgEncours].paramDeScratchprog.cacheTest = options.cacheTest
    if (options.vite !== undefined) this.params.progAtest[this.params.numProgEncours].paramDeScratchprog.vite = options.vite
    this.scratchReinitPartiel(this.lesdivs.sortieEl)
    this.lanceUnProg(this.params.progAtest[this.params.numProgEncours])
  }

  metChaine (tab) {
    let arte = ''
    for (let i = 0; i < tab.length; i++) {
      arte += tab[i] + '<br>'
    }
    return arte
  }

  retireWork () {
    this.params.scratchProgDonnees.fostop = false
    this.params.scratchProgDonnees.fostopErreur = false
    this.params.grosStop = false
    this.params.scratchProgDonnees.runable = true
    let buf = this.lesdivs.sortie1
    if (this.lesdivs.drap1) this.lesdivs.drap1.classList.remove('WorkInProg')
    if (this.lesdivs.drap2) this.lesdivs.drap2.classList.remove('WorkInProg')
    if (this.params.isMtgLibre) this.lesdivs.sortie1.classList.remove('WorkInProg')
    if (this.params.squizzEssai) buf = this.params.pourBuf
    if (this.params.squizzEssai) {
      j3pEmpty(this.params.tabMtg[0][0])
      const getUp = j3pAddElt(this.params.tabMtg[0][0], 'a', { href: '#' + this.idTop })
      j3pAddContent(getUp, '^')
    }
    buf.style.backgroundImage = barreboutonImg
    buf.classList.remove('WorkInProg')
  }

  remetBienLesBoutons () {
    this.lesdivs.stop.style.display = 'none'
    if (this.params.DemoText) this.params.DemoText.style.display = ''
    this.params.scratchProgDonnees.run = false
    this.params.scratchProgDonnees.runable = false
    if (this.isMtg && !this.params.squizzEssai) {
      this.params.MtgBoutonFerm.style.display = ''
    }
    this.retireWork()
    if (this.pasapas) {
      this.pasapas.disabled = false
    }
    this.lesdivs.PASAPASBOOT.style.display = 'none'
    if (!this.params.scratchProgDonnees.isDemo) {
      if (this.fautRinitDemo) {
        this.cacheDrapeauxDemo()
        this.montreBoutonReinitDemo()
      } else {
        this.montreDrapeauxDemo()
        this.cahceBoutonReinitDemo()
      }
      this.fautRinit = true
      this.cacheDrapeaux()
      this.montreBoutonReinit()
    } else {
      if (this.fautRinit) {
        this.cacheDrapeaux()
        this.montreBoutonReinit()
      } else {
        this.montreDrapeaux()
        this.cahceBoutonReinit()
      }
      this.fautRinitDemo = true
      this.cacheDrapeauxDemo()
      this.montreBoutonReinitDemo()
    }
    if (this.params.me.etat === 'enonce') { this.params.me.buttonsElts.suite.style.display = '' }
    if (this.params.me.etat === 'navigation') { this.params.me.buttonsElts.sectionSuivante.style.display = '' }
    this._decodeListener()
    j3pDetruit(this.lesdivs.avire)
    this.lesdivs.avire = undefined
  }

  scratchFermeModale () {
    j3pDetruit('j3pmasque')
    j3pDetruit('modale')
  }

  scratchFerme1 () {
    this._scratchDePauseListener()
    this.scratchFermeModale()
  }

  scratchFerme2 () {
    this._scratchDePauseListener()
    this.scratchFermeModale()
    this.scratchReinit()
  }

  scratchFerme3 () {
    this.scratchReinit()
    this.scratchDePause()
    this.scratchFermeModale()
    this.lanceDrapeauOk()
  }

  scratchFerme5 () {
    this.scratchReinit()
    this.scratchDePause()
    this.scratchFermeModale()
    this.params.me.sectionCourante()
  }

  scratchAfficheModaleUtil (nb) {
    const hh = j3pModale({ titre: 'Nouvel Utilisateur' })
    hh.style.left = '20px'
    hh.style.top = '20px'
    const tab = addDefaultTable(hh, 2, 1)

    let hjk
    if (this.params.yayayayeu) {
      hjk = '&nbsp;Je vais à nouveau tester ton programme ' + nb + ' fois . '
      if (nb === 1) hjk = '&nbsp;Je vais à nouveau tester ton programme. '
    } else {
      this.params.yayayayeu = true
      hjk = '&nbsp;Bonjour, <br> &nbsp; pour valider ton programme je dois le tester <br>&nbsp; dans ' + nb + ' situations différentes. '
      if (nb === 1) hjk = '&nbsp;Bonjour, <br> &nbsp; pour valider ton programme je dois le tester '
    }
    const uu = addDefaultTable(tab[0][0], 1, 2)
    j3pAddElt(uu[0][0], 'img', '', { src: tuxImg, alt: 'Charlie', height: '20px', width: '20px' })
    uu[0][1].innerHTML = hjk
    const elem = $('.croix')[0]
    j3pDetruit(elem)
    j3pAjouteBouton(tab[1][0], this.scratchFerme1.bind(this), { className: 'MepBoutons2', value: 'OK' })
  }

  scratchAfficheModaleUtilSuite (id, nb) {
    const hh = j3pModale({ titre: 'Nouvel Utilisateur' })
    hh.style.left = '20px'
    hh.style.top = '20px'
    const tt = addDefaultTable(hh, 2, 1)
    const buffois = (nb === 1) ? '1 dernière fois' : nb + ' fois'
    j3pAddElt(tt[0][0], 'img', '', { src: tuxImg, alt: 'Charlie', height: '20px', width: '20px' })
    j3pAddContent(tt[0][0], `"Test réussi , je vais encore essayer ton programme ${buffois}."`)
    /// /PB ICI
    const elem = $('.croix')[0]
    j3pDetruit(elem)
    j3pAjouteBouton(tt[1][0], () => {
      this.scratchFerme1()
      this.scratchRelance(id)
    }, { className: 'MepBoutons2', value: 'OK' })
  }

  scratchRelance (id) {
    for (let i = 0; i < this.params.scratchProgDonnees.progencours.length; i++) {
      if (this.params.scratchProgDonnees.progencours[i].id === id) {
        this.params.scratchProgDonnees.progencours[i].prog.exeaction()
        return
      }
    }
  }

  scratchAfficheModaleAlea () {
    const hh = j3pModale({ titre: 'Nouvel Utilisateur' })
    hh.style.left = '20px'
    hh.style.top = '20px'
    const tt = addDefaultTable(hh, 2, 1)
    j3pAddElt(tt[0][0], 'img', '', { src: tuxImg, alt: 'Charlie', height: '20px', width: '20px' })/// /PB ICI

    const elem = $('.croix')[0]
    j3pDetruit(elem)
    j3pAjouteBouton(tt[1][0], this.scratchFerme1.bind(this), { className: 'MepBoutons2', value: 'OK' })
  }

  scratchAfficheModaleUtilDonneValeur (ki) {
    this.params.scratchProgDonnees.blokinput = true
    this.params.scratchProgDonnees.valdonnee = undefined

    if (this.params.scratchProgDonnees.valPourGetUs) {
      if (Array.isArray(this.params.scratchProgDonnees.valPourGetUs)) {
        if (this.params.scratchProgDonnees.valPourGetUs.length > 0) {
          this.params.scratchProgDonnees.valdonnee = this.params.scratchProgDonnees.valPourGetUs.shift()
        }
      }
    }

    if (this.params.scratchProgDonnees.valdonnee === undefined) {
      notify('pour tom pas de valPourGetUs en YaUtilisateur', { scratchProgDonnees: this.params.scratchProgDonnees })
      this.params.scratchProgDonnees.valdonnee = String(j3pGetRandomInt(10, 100))
    }

    this.params.scratchProgDonnees.reponseDonnesAGetUS.push(this.params.scratchProgDonnees.reponse)
    const hh = j3pModale({ titre: 'Demande de l’utilisateur' })
    hh.style.left = '20px'
    hh.style.top = '20px'
    const tt = addDefaultTable(hh, 2, 1)
    const tt2 = addDefaultTable(tt[0][0], 1, 2)
    j3pAddElt(tt2[0][0], 'img', '', { src: tuxImg, alt: 'Charlie', height: '20px', width: '20px' })
    tt2[0][0].style.padding = '5px'
    const ttph = addDefaultTable(tt2[0][1], 3, 1)
    j3pAddContent(ttph[0][0], ` "Je voudrais que tu écrives ceci&nbsp;: ${this.params.scratchProgDonnees.valdonnee}. "`)
    j3pAddContent(ttph[1][0], '<i>( pense à valider ce nombre ensuite</i>')
    const ttph3 = addDefaultTable(ttph[2][0], 1, 3)
    j3pAddContent(ttph3[0][0], '<i>en cliquant sur&nbsp;</i>')
    j3pAddElt(ttph3[0][1], 'img', '', { src: valgetusImg, alt: 'Charlie', height: '10px', width: '10px' })
    ttph3[0][1].style.minWidth = '10px'
    j3pAddContent(ttph3[0][2], '<i>&nbsp;)</i>')

    // PB ICI

    const elem = $('.croix')[0]
    j3pDetruit(elem)
    const bb = j3pAjouteBouton(tt[1][0], () => {
      this.scratchFermeModale()
      this.scratchGetUsColle()
    }, { className: 'MepBoutons2', value: 'OK' })
    j3pFocus(bb)
  }

  scratchGetUsColle (ki) {
    if (!this.params.scratchProgDonnees.run) return
    this.params.scratchProgDonnees.blokinput = false
    this.params.GetZOne.reset(this.params.scratchProgDonnees.valdonnee + '')
    if (this.params.correctionCachee) {
      this.params.scratchProgDonnees.pause = false
      this.scratchValGetUs(ki)
    }
  }

  scratchAfficheModaleUtilMauvaisevaleur () {
    const hh = j3pModale({ titre: 'Demande de l’utilisateur' })
    hh.style.left = '20px'
    hh.style.top = '20px'

    const tt = addDefaultTable(hh, 2, 1)
    const tt2 = addDefaultTable(tt[0][0], 1, 2)
    j3pAddElt(tt2[0][0], 'img', '', { src: tuxImg, alt: 'Charlie', height: '20px', width: '20px' })

    tt2[0][0].style.padding = '5px'
    const ttph = addDefaultTable(tt2[0][1], 3, 1)
    j3pAddContent(ttph[0][0], ` "Tu dois écrire ceci&nbsp;: ${this.params.scratchProgDonnees.valdonnee}. "`)
    j3pAddContent(ttph[1][0], '<i>( pense à valider ce nombre ensuite</i>')
    const ttph3 = addDefaultTable(ttph[2][0], 1, 3)
    j3pAddContent(ttph3[0][0], '<i>en cliquant sur&nbsp;</i>')
    j3pAddElt(ttph3[0][1], 'img', '', { src: valgetusImg, alt: 'Charlie', height: '10px', width: '10px' })
    ttph3[0][1].style.minWidth = '10px'
    j3pAddContent(ttph3[0][2], '<i>&nbsp;)</i>')

    const elem = $('.croix')[0]
    j3pDetruit(elem)
    j3pAjouteBouton(tt[1][0], () => {
      this.scratchFermeModale()
      this.scratchGetUsColle()
    }, { className: 'MepBoutons2', value: 'OK' })
  }

  scratchReplaceVar () {
    if (this.params.osef) return
    let el = this.params.zerozero // or other selector like querySelector()
    if (!el) return
    const zero = el.getBoundingClientRect()
    if (zero.x === undefined) zero.x = zero.left
    if (zero.y === undefined) zero.y = zero.top
    for (let i = 0; i < this.params.scratchProgDonnees.variables.length; i++) {
      let caplanteou = 0
      try {
        if ((this.params.scratchProgDonnees.variables[i].val + '').indexOf('x@ù') === -1) {
          caplanteou = 1
          this.params.AffVarText2[i].innerHTML = this.params.scratchProgDonnees.variables[i].val
        } else {
          caplanteou = 2
          this.params.AffVarText2[i].innerHTML = Algebrite.run((this.params.scratchProgDonnees.variables[i].val + '').replace(/x@ù/g, this.params.scratchProgDonnees.reponse))
        }
        el = this.params.AffVarText1[i] // or other selector like querySelector()
        caplanteou = 3
        const text1 = el.getBoundingClientRect()
        el = this.params.AffVarText2[i] // or other selector like querySelector()
        caplanteou = 4
        const text2 = el.getBoundingClientRect()
        if (text1.x === undefined) text1.x = text1.left
        if (text1.y === undefined) text1.y = text1.top
        if (text2.x === undefined) text2.x = text2.left
        if (text2.y === undefined) text2.y = text2.top
        caplanteou = 5
        this.params.AffVarRect1[i].width.baseVal.value = text1.width * 2 + text2.width + 40
        this.params.AffVarRect2[i].width.baseVal.value = text2.width + 30
        this.params.AffVarRect1[i].height.baseVal.value = text1.height + 2
        this.params.AffVarRect2[i].height.baseVal.value = text1.height - 2
        this.params.AffVarRect1[i].y.baseVal.value = text1.y - zero.y
        this.params.AffVarRect2[i].y.baseVal.value = text1.y + 2 - zero.y
        this.params.AffVarRect2[i].x.baseVal.value = text1.x + text1.width * 2 - zero.x
        this.params.AffVarText2[i].x.baseVal.getItem(0).value = 15 + text1.x + text1.width * 2 - zero.x
        caplanteou = 5
        let mes = 'hidden'
        if (this.params.scratchProgDonnees.variables[i].visible) { mes = 'visible' }
        this.params.AffVarRect1[i].style.visibility = mes
        this.params.AffVarRect2[i].style.visibility = mes
        this.params.AffVarText1[i].style.visibility = mes
        this.params.AffVarText2[i].style.visibility = mes
      } catch (e) {
        notify('pour tom: ' + e, { i, caplanteou, variables: this.params.scratchProgDonnees.variables, AffVarText2: this.params.AffVarText2, AffVarText1: this.params.AffVarText1, AffVarRect1: this.params.AffVarRect1, AffVarRect2: this.params.AffVarRect2 })
        continue
      }
    }
  }

  scratchMajMem () {
    this.params.toCharlie.innerHTML = this.params.scratchProgDonnees.mem[2]
    this.params.toLlyn.innerHTML = this.params.scratchProgDonnees.mem[0]
    this.params.toFelix.innerHTML = this.params.scratchProgDonnees.mem[1]
  }

  scratchAfficheDansBloklyCo (xml) {
    const xmlDoc = $.parseXML(xml)
    let x = xmlDoc.firstChild
    while (x.nodeType !== 1) {
      x = x.nextSibling
    }
    this.params.workspaceEl.clear()
    this.Blockly.Xml.domToWorkspace(x, this.params.workspaceEl)
  }

  scratchAfficheDansBloklyCoco (xml) {
    const xmlDoc = $.parseXML(xml)
    let x = xmlDoc.firstChild
    while (x.nodeType !== 1) {
      x = x.nextSibling
    }
    this.params.workspaceco.clear()
    this.Blockly.Xml.domToWorkspace(x, this.params.workspaceco)
    for (let i = 0; i < this.params.scratchProgDonnees.lesvarbonnes.length; i++) { this.params.workspaceco.createVariable(this.params.scratchProgDonnees.lesvarbonnes[i].nom) }
  }

  scratchTraduireOrdre (el) {
    switch (el) {
      case 'avance_fusee':
        return 'avancer'
      case 'droite_fusee':
        return 'tourner à droite'
      case 'gauche_fusee':
        return 'tourner à gauche'
      case 'decolle_fusee':
        return 'décoller'
      case 'atteri_fusee':
        return 'atterrir'

      case 'monter_bras':
        return 'monter'
      case 'descendre_bras':
        return 'descendre'
      case 'tourner_bras':
        return 'tourner'
      case 'reduire_bras':
        return 'réduire'
      case 'agrandir_bras':
        return 'agrandir'
      case 'prendre_bras':
        return 'prendre'
      case 'deposer_bras':
        return 'déposer'
      case 'control_if': return 'si'
      case 'Get_us':return 'demander'
      default : return el
    }
  }

  scratchSetLocale (locale) {
    this.params.workspaceEl.getFlyout().setRecyclingEnabled(false)
    const xml = this.Blockly.Xml.workspaceToDom(this.params.workspaceEl)
    this.Blockly.ScratchMsgs.setLocale(locale)
    this.Blockly.Xml.clearWorkspaceAndLoadFromXml(xml, this.params.workspaceEl)
    this.params.workspaceEl.getFlyout().setRecyclingEnabled(true)
  }

  scratchBloklyCo (xml2) {
    this.lesdivs.divBlockly.innerHTML = ''
    // création de l’espace de travail (en particulier du menu)

    const side = 'start'
    try {
      this.params.workspaceEl = this.Blockly.inject(this.lesdivs.divBlockly, {
        comments: true,
        disable: false,
        collapse: false,
        media: j3pBaseUrl + 'externals/blockly/media/',
        readOnly: true,
        rtl: null,
        scrollbars: true,
        toolbox: $(xml2).find('#toolbox')[0],
        toolboxPosition: side === 'top' || side === 'start' ? 'start' : 'end',
        horizontalLayout: side === 'top' || side === 'bottom',
        sounds: false,
        zoom: {
          controls: true,
          wheel: true,
          startScale: 0.6,
          maxScale: 2,
          minScale: 0.25,
          scaleSpeed: 1.1
        },
        colours: {
          fieldShadow: 'rgba(100, 100, 100, 0.3)',
          dragShadowOpacity: 0.6
        }
      })
    } catch (error) {
      console.error(error)
    }
    // parametrages divers des fenêtres de SofusPy
    this.lesdivs.divBlockly.style.height = '400px'
    this.lesdivs.divBlockly.style.width = '300px'
    this.Blockly.svgResize(this.params.workspaceEl)
  }

  scratchBloklyCoCo (xml2) {
    this.lesdivs.divBlocklyCo.innerHTML = ''
    // création de l’espace de travail (en particulier du menu)
    const side = 'start'
    this.params.workspaceco = this.Blockly.inject(this.lesdivs.divBlocklyCo, {
      comments: true,
      disable: false,
      collapse: false,
      media: j3pBaseUrl + 'externals/blockly/media/',
      readOnly: true,
      rtl: null,
      scrollbars: true,
      toolbox: $(xml2).find('#toolbox')[0],
      toolboxPosition: side === 'top' || side === 'start' ? 'start' : 'end',
      horizontalLayout: side === 'top' || side === 'bottom',
      sounds: false,
      zoom: {
        controls: true,
        wheel: true,
        startScale: 0.6,
        maxScale: 2,
        minScale: 0.25,
        scaleSpeed: 1.1
      },
      colours: {
        fieldShadow: 'rgba(100, 100, 100, 0.3)',
        dragShadowOpacity: 0.6
      }
    })
    // parametrages divers des fenêtres de SofusPy
    this.lesdivs.divBlocklyCo.style.height = '400px'
    this.lesdivs.divBlocklyCo.style.width = '300px'
    this.Blockly.svgResize(this.params.workspaceco)
  }

  scratchRetrouveIdVar (qui) {
    for (let j = 0; j < this.params.scratchProgDonnees.LesVariablesCo.length; j++) {
      if (qui === this.params.scratchProgDonnees.LesVariablesCo[j].name) { return this.params.scratchProgDonnees.LesVariablesCo[j].id }
    }
  }

  // return un tableau avec les items de l’objet
  // pour {type:'ordre',quoi:'ff',message:{text:'ii'}}
  // ca retourne
  // [['type','ordre'],['quoi','ff'],['message',['text','ii']]]
  // mais est ce que ca vaut le coup ?

  scratchBufEd (ob) {
    let ret = ''
    if (ob.movable !== undefined) ret += ' movable="' + ob.movable + '" '
    if (ob.deletable !== undefined) ret += ' deletable="' + ob.deletable + '" '
    if (ob.editable !== undefined) ret += ' editable="' + ob.editable + '" '
    if (ob.id !== undefined) ret += ' id="' + ob.id + '" '
    return ret
  }

  scratchFaisBlokXml (ob) {
    let bufid
    let bufid2
    let arte
    let aaj2 = '>'
    let contbuf
    if (ob.type !== undefined) { arte = { aaj: '<block ', aajmil: '', aajfin: '</block>' } } else { arte = { aaj: '', aajmil: '', aajfin: '' }; aaj2 = '' }
    for (const p in ob) {
      switch (p) {
        case 'value':
          for (let i = 0; i < ob[p].length; i++) {
            if (ob[p][i].contenu.type === undefined) { contbuf = this.scratchCreeProgVal(ob[p][i].contenu) } else {
              contbuf = this.scratchFaisBlokXml(ob[p][i].contenu)
              contbuf = contbuf.aaj + contbuf.aajmil + contbuf.aajfin
            }
            arte.aajmil += '<value name="' + ob[p][i].nom + '" ' + this.scratchBufEd(ob[p][i]) + '>' + contbuf + '</value>'
          }
          break
        case 'statement':
          for (let i = 0; i < ob[p].length; i++) {
            contbuf = this.scratchCreeProgCo(ob[p][i].contenu, { n: 1, ajoutedebut: false })
            arte.aajmil += '<statement name="' + ob[p][i].nom + '" ' + this.scratchBufEd(ob[p][i]) + '>' + contbuf + '</statement>'
          }
          break
        case 'field':
          for (let i = 0; i < ob[p].length; i++) {
            if (ob[p][i].type === undefined) { contbuf = this.scratchCreeProgVal(ob[p][i].contenu) } else {
              contbuf = this.scratchFaisBlokXml(ob[p][i].contenu)
              contbuf = contbuf.aaj + contbuf.aajmil + contbuf.aajfin
            }
            arte.aajmil += '<field name="' + ob[p][i].nom + '" ' + this.scratchBufEd(ob[p]) + '>' + contbuf + '</field>'
          }
          break
        case 'variable':
          for (let i = 0; i < ob[p].length; i++) {
            bufid = this.scratchRetrouveIdVar(ob[p][i].nomvar)
            if (bufid !== undefined) { bufid = ' id="' + bufid + '" ' } else { bufid = '' }
            bufid2 = this.scratchBufEd(ob[p][i])
            if (bufid2.indexOf('id') !== -1) bufid = ''
            arte.aajmil += '<field name="' + ob[p][i].nom + '" ' + bufid + '  ' + bufid2 + ' variabletype="">' + ob[p][i].nomvar + '</field>'
          }
          break
        default: arte.aaj += ' ' + p + '="' + ob[p] + '" '
      }
    }
    arte.aaj += aaj2
    return arte
  }

  scratchCreeProgCo (tab, parametres) {
    if (tab === undefined) return ''
    let booldeb, n, squizzvar, kedeb, kefin, dedec
    if (parametres) {
      booldeb = Boolean(parametres.ajoutedebut)
      kedeb = Boolean(parametres.kedeb)
      kefin = Boolean(parametres.kefin)
      dedec = Boolean(parametres.dedec)
      n = parametres.n
      if (!n) n = 0
      squizzvar = (parametres.squizzVar === true)
    } else {
      booldeb = false
      n = 0
      squizzvar = false
      kedeb = kefin = false
      dedec = false
    }

    let aaj, aajfin, bufaj
    aaj = aajfin = ''
    if (n === 0) {
      if (!kefin) aaj = '<xml xmlns="http://www.w3.org/1999/xhtml"><variables>'
      if (!kedeb) aajfin = '</xml>'
      if (!kefin) this.params.scratchProgDonnees.LesVariablesCo = []
      if (!squizzvar && !kefin) {
        for (let i = 0; i < this.params.scratchProgDonnees.lesvarbonnes.length; i++) {
          this.params.scratchProgDonnees.LesVariablesCo.push({ name: this.params.scratchProgDonnees.lesvarbonnes[i].nom, id: this.params.scratchProgDonnees.lesvarbonnes[i].id, val: 'vide' })
          aaj += '<variable type="" id="' + this.params.scratchProgDonnees.lesvarbonnes[i].id + '" islocal="false" iscloud="false">' + this.params.scratchProgDonnees.lesvarbonnes[i].nom + '</variable>'
        }
      }
      if (!kefin) aaj += '</variables>'
    }

    if (booldeb) {
      const XX = dedec ? 200 : 15
      aaj += '<block type="Drapo" id="?q:ukn@XHs+*k)#oIIl+"  x="' + XX + '" y="25"><next>'
      aajfin = '</next></block>' + aajfin
    }

    for (let i = 0; i < tab.length; i++) {
      bufaj = this.scratchFaisBlokXml(tab[i])
      aaj += bufaj.aaj + bufaj.aajmil + '<next>'
      aajfin = '</next>' + bufaj.aajfin + aajfin
    }
    aaj += aajfin
    return aaj
  }

  scratchCreeProgVal (objectval, n) {
    if (objectval === undefined) { return '' }
    let bufimes = ''
    if (objectval.movable !== undefined) bufimes += ' movable="' + objectval.movable + '" '
    if (objectval.deletable !== undefined) bufimes += ' deletable="' + objectval.deletable + '" '
    if (objectval.editable !== undefined) bufimes += ' editable="' + objectval.editable + '" '
    if (objectval.valeur) {
      if (bufimes !== '') {
        return '<block ' + bufimes + ' type="text" id="' + this.newIdCo() + '"><field name="TEXT">' + objectval.valeur + '</field></block>'
      }
      return '<shadow type="text" id="' + this.newIdCo() + '"><field name="TEXT">' + objectval.valeur + '</field></shadow>'
    }
    if (objectval.shadow) {
      if (bufimes !== '') {
        return '<block ' + bufimes + ' type="math_number" id="' + this.newIdCo() + '"><field name="NUM">2</field></block><block ' + bufimes + ' type="data_variable" ' + bufimes + ' id="' + this.newIdCo() + '"><field name="VARIABLE" id="' + this.scratchRetrouveIdVar(objectval.variable) + '" variabletype="">' + objectval.variable + '</field></block>'
      }
      return '<shadow type="' + objectval.shadow + '" id="' + this.newIdCo() + '"><field name="NUM">' + objectval.val + '</field></shadow>'
    }
    if (objectval.variable) {
      if (bufimes !== '') {
        return '<block ' + bufimes + ' type="math_number" id="' + this.newIdCo() + '"><field name="NUM">2</field></block><block ' + bufimes + ' type="data_variable" ' + bufimes + ' id="' + this.newIdCo() + '"><field name="VARIABLE" id="' + this.scratchRetrouveIdVar(objectval.variable) + '" variabletype="">' + objectval.variable + '</field></block>'
      }
      return '<shadow type="math_number" id="' + this.newIdCo() + '"><field name="NUM">2</field></shadow><block type="data_variable" id="' + this.newIdCo() + '"><field name="VARIABLE" id="' + this.scratchRetrouveIdVar(objectval.variable) + '" variabletype="">' + objectval.variable + '</field></block>'
    }
    if (objectval.operateur) {
      const b1 = this.scratchFaisBlokXml({ value: objectval.value })
      return '<block ' + bufimes + 'type="' + this.scratchConvertOp(objectval.operateur) + '" id="' + this.newIdCo() + '">' + b1.aaj + b1.aajmil + b1.aajfin + '</block>'
    }
    if (objectval.pi) {
      return '<block type="pi" id="' + this.newIdCo() + '"></block>'
    }
    if (objectval.condition) {
      return '<block type="' + objectval.condition + '" id="' + this.newIdCo() + '"><value name="OPERAND1">' + this.scratchCreeProgVal(objectval.operand1, (n + 1)) + '</value><value name="OPERAND2">' + this.scratchCreeProgVal(objectval.operand2, (n + 1)) + '</value></block>'
    }
    if (objectval.conditionsimple) {
      return '<block type="' + objectval.conditionsimple + '" id="' + this.newIdCo() + '"></block>'
    }
    if ((objectval.reponse === '') || (objectval.reponse === true)) {
      return '<block ' + bufimes + ' type="reponse" id="' + this.newIdCo() + '"></block>'
    }
  }

  scratchConvertOp (j) {
    switch (j) {
      case '+':
      case 'add':
      case 'plus' :
        return 'operator_add'
      case '-':
      case 'sou':
      case 'moins' :
        return 'operator_subtract'
      case '*':
      case 'fois':
      case 'mult' :
        return 'operator_multiply'
      case '/':
      case 'divise':
      case 'div' :
        return 'operator_divide'
      case 'rand':
      case 'alea':
      case 'hasard' :
        return 'operator_random'
      default :
        return j
    }
  }

  scratchDire (msg, temps) {
    if (!msg) msg = '...'
    this.params.scratchProgDonnees.said.push(msg)
    if (this.params.cacheTest) return
    if (this.params.modeCompare) return
    if (this.params.scratchProgDonnees.yaEuVerif) return
    this.params.scratchProgDonnees.pause = true
    if (msg.indexOf('x@ù') !== -1) {
      msg = Algebrite.run(msg.replace(/x@ù/g, this.params.scratchProgDonnees.reponse))
    }

    // chope une place
    // 4 max haut droite , haut gauche , bas droite , bas gauche
    // on verra plus tard quand y’a pusieurs lutins
    if (this.params.scratchProgDonnees.Lutins[0].larg === 50) {
      const ns = 'http://www.w3.org/2000/svg'
      const svg = this.params.svg
      const rect = document.createElementNS(ns, 'rect')
      rect.setAttribute('x', 10)
      rect.setAttribute('y', 70)
      rect.setAttribute('width', 280)
      rect.setAttribute('height', 220)
      rect.setAttribute('rx', 10)
      rect.setAttribute('ry', 10)
      svg.appendChild(rect)
      rect.style.fill = '#fff'
      rect.style.stroke = 'rgb(74,173,222)'
      rect.style.strokeWidth = '4px'
      this.params.rect = rect

      // un trait bleu
      const traitbl1 = document.createElementNS(ns, 'line')
      traitbl1.setAttribute('x1', 115)
      traitbl1.setAttribute('y1', 70)
      traitbl1.setAttribute('x2', 115)
      traitbl1.setAttribute('y2', 290)
      svg.appendChild(traitbl1)
      traitbl1.style.stroke = 'rgb(74,173,222)'
      traitbl1.style.strokeWidth = '4px'
      this.params.traitbl1 = traitbl1

      // cree le texte
      const text = document.createElementNS(ns, 'text')
      text.setAttribute('x', 140)
      text.setAttribute('y', 100)
      svg.appendChild(text)
      text.style.fill = '#000'
      text.style.stroke = '#000'
      text.style.fontSize = '15px'
      this.params.text = text
      const nbligne = Math.ceil(this.textWidth(msg, 'Comic sans MS', '20') / 60)
      const ligne = []
      let anc = 0
      for (let i = 0; i < nbligne; i++) {
        ligne[i] = msg.substring(anc, Math.round((i + 1) * (msg.length / nbligne) + 1))
        anc = Math.round((i + 1) * (msg.length / nbligne) + 1)
      }
      text.innerHTML = 'Scratch dit:'
      for (let i = 0; i < nbligne; i++) {
        text.innerHTML += '<tspan x="145" y="' + (110 + 20 * (i + 1)) + '">' + ligne[i] + '</tspan>'
      }

      const linebl = document.createElementNS(ns, 'line')
      linebl.setAttribute('x1', 140)
      linebl.setAttribute('y1', 105)
      linebl.setAttribute('x2', 210)
      linebl.setAttribute('y2', 105)
      svg.appendChild(linebl)
      linebl.style.stroke = '#000'
      linebl.style.strokeWidth = '1px'
      this.params.linebl = linebl

      this.params.traitbl2 = j3pSvgAppend(this.params.svg, 'image', {
        x: 15,
        y: 130,
        width: 100,
        height: 100,
        xlink: this.params.scratchProgDonnees.Lutins[0].img
      })
    } else {
      // cree le rectangle
      const ns = 'http://www.w3.org/2000/svg'
      const svg = this.params.svg
      const rect = document.createElementNS(ns, 'rect')
      rect.setAttribute('x', 100)
      rect.setAttribute('y', 10)
      rect.setAttribute('width', 50)
      rect.setAttribute('height', 60)
      rect.setAttribute('rx', 10)
      rect.setAttribute('ry', 10)
      svg.appendChild(rect)
      rect.style.fill = '#fff'
      rect.style.stroke = 'rgb(74,173,222)'
      rect.style.strokeWidth = '4px'
      this.params.rect = rect

      // cree un rect pour pas se faire ch a compter
      const rect2 = document.createElementNS(ns, 'rect')
      rect2.setAttribute('x', 0)
      rect2.setAttribute('y', 0)
      rect2.setAttribute('width', 0)
      rect2.setAttribute('height', 0)
      svg.appendChild(rect2)
      this.params.rect2 = rect2

      // cree le trait blanc
      const linebl = document.createElementNS(ns, 'line')
      linebl.setAttribute('x1', 0)
      linebl.setAttribute('y1', 0)
      linebl.setAttribute('x2', 0)
      linebl.setAttribute('y2', 0)
      svg.appendChild(linebl)
      linebl.style.stroke = '#fff'
      linebl.style.strokeWidth = '4px'
      this.params.linebl = linebl

      // un trait bleu
      const traitbl1 = document.createElementNS(ns, 'line')
      traitbl1.setAttribute('x1', 0)
      traitbl1.setAttribute('y1', 0)
      traitbl1.setAttribute('x2', 0)
      traitbl1.setAttribute('y2', 0)
      svg.appendChild(traitbl1)
      traitbl1.style.stroke = 'rgb(74,173,222)'
      traitbl1.style.strokeWidth = '4px'
      this.params.traitbl1 = traitbl1

      // autre trait bleu
      const traitbl2 = document.createElementNS(ns, 'line')
      traitbl2.setAttribute('x1', 0)
      traitbl2.setAttribute('y1', 0)
      traitbl2.setAttribute('x2', 0)
      traitbl2.setAttribute('y2', 0)
      svg.appendChild(traitbl2)
      traitbl2.style.stroke = 'rgb(74,173,222)'
      traitbl2.style.strokeWidth = '4px'
      this.params.traitbl2 = traitbl2

      // cree le texte
      const text = document.createElementNS(ns, 'text')
      text.setAttribute('x', this.params.scratchProgDonnees.Lutins[0].cox + 100)
      text.setAttribute('y', this.params.scratchProgDonnees.Lutins[0].coy)
      svg.appendChild(text)
      text.style.fill = '#000'
      text.style.stroke = '#000'
      text.style.fontSize = '15px'
      this.params.text = text
      const nbligne = Math.ceil(this.textWidth(msg, 'Comic sans MS', '15') / 60)
      const ligne = []
      let anc = 0
      for (let i = 0; i < nbligne; i++) {
        ligne[i] = msg.substring(anc, Math.round((i + 1) * (msg.length / nbligne) + 1))
        anc = Math.round((i + 1) * (msg.length / nbligne) + 1)
      }
      text.innerHTML = ligne[0]
      for (let i = 1; i < nbligne; i++) {
        text.innerHTML += '<tspan x="' + (this.params.scratchProgDonnees.Lutins[0].cox + 100) + '" y="' + (this.params.scratchProgDonnees.Lutins[0].coy + 15 * i) + '">' + ligne[i] + '</tspan>'
      }

      // cree les deux ligne jusque chat

      // prend la dimension du texte
      const { x, y, width, height } = text.getBoundingClientRect()
      const { x: x2, y: y2 } = rect2.getBoundingClientRect()

      // replace bien tout
      // le rect
      rect.y.baseVal.value = y - y2 - 10
      rect.x.baseVal.value = x - x2 - 10
      rect.width.baseVal.value = width + 20
      rect.height.baseVal.value = height + 20
      // la ligne blanche
      linebl.y1.baseVal.value = y - y2 + 10 + height
      linebl.x1.baseVal.value = x - x2 + width / 6
      linebl.y2.baseVal.value = y - y2 + 10 + height
      linebl.x2.baseVal.value = x - x2 + width / 2
      // un trait bleu
      traitbl1.y1.baseVal.value = y - y2 + 10 + height + 20
      traitbl1.x1.baseVal.value = x - x2
      traitbl1.y2.baseVal.value = y - y2 + 10 + height
      traitbl1.x2.baseVal.value = x - x2 + width / 2
      // autre trait bleu
      traitbl2.y1.baseVal.value = y - y2 + 10 + height
      traitbl2.x1.baseVal.value = x - x2 + width / 6
      traitbl2.y2.baseVal.value = y - y2 + 10 + height + 20
      traitbl2.x2.baseVal.value = x - x2
    }

    setTimeout(this.scratchVireDire.bind(this), temps * 1000)
  } // scratchDire

  scratchVireDire () {
    j3pDetruit(this.params.rect, this.params.text, this.params.traitbl2, this.params.traitbl1, this.params.linebl)
    this.params.scratchProgDonnees.pause = false
  }

  scratchGetUs (msg) {
    // cree le rectangle
    if (this.params.cacheTest) {
      if (this.params.scratchProgDonnees.valPourGetUs) {
        if (Array.isArray(this.params.scratchProgDonnees.valPourGetUs)) {
          if (this.params.scratchProgDonnees.valPourGetUs.length > 0) {
            this.params.scratchProgDonnees.reponse = this.params.scratchProgDonnees.valPourGetUs.shift()
            this.params.scratchProgDonnees.reponseDonnesAGetUS.push(this.params.scratchProgDonnees.reponse)
            return
          }
        }
      }
      notify('pour tom pas de valPourGetUs en cacheTest', { scratchProgDonnees: this.params.scratchProgDonnees })
      this.params.scratchProgDonnees.reponse = String(j3pGetRandomInt(10, 100))
      this.params.scratchProgDonnees.reponseDonnesAGetUS.push(this.params.scratchProgDonnees.reponse)
      return
    }
    const ns = 'http://www.w3.org/2000/svg'
    const svg = this.params.svg
    const rect = document.createElementNS(ns, 'rect')
    rect.setAttribute('x', 100)
    rect.setAttribute('y', 10)
    rect.setAttribute('width', 50)
    rect.setAttribute('height', 60)
    rect.setAttribute('rx', 10)
    rect.setAttribute('ry', 10)
    svg.appendChild(rect)
    rect.style.fill = '#fff'
    rect.style.stroke = 'rgb(74,173,222)'
    rect.style.strokeWidth = '4px'
    this.params.rect = rect

    // cree un rect pour pas se faire ch a compter
    const rect2 = document.createElementNS(ns, 'rect')
    rect2.setAttribute('x', 0)
    rect2.setAttribute('y', 0)
    rect2.setAttribute('width', 0)
    rect2.setAttribute('height', 0)
    svg.appendChild(rect2)
    this.params.rect2 = rect2

    // cree le trait blanc
    const linebl = document.createElementNS(ns, 'line')
    linebl.setAttribute('x1', 0)
    linebl.setAttribute('y1', 0)
    linebl.setAttribute('x2', 0)
    linebl.setAttribute('y2', 0)
    svg.appendChild(linebl)
    linebl.style.stroke = '#fff'
    linebl.style.strokeWidth = '4px'
    this.params.linebl = linebl

    // un trait bleu
    const traitbl1 = document.createElementNS(ns, 'line')
    traitbl1.setAttribute('x1', 0)
    traitbl1.setAttribute('y1', 0)
    traitbl1.setAttribute('x2', 0)
    traitbl1.setAttribute('y2', 0)
    svg.appendChild(traitbl1)
    traitbl1.style.stroke = 'rgb(74,173,222)'
    traitbl1.style.strokeWidth = '4px'
    this.params.traitbl1 = traitbl1

    // autre trait bleu
    const traitbl2 = document.createElementNS(ns, 'line')
    traitbl2.setAttribute('x1', 0)
    traitbl2.setAttribute('y1', 0)
    traitbl2.setAttribute('x2', 0)
    traitbl2.setAttribute('y2', 0)
    svg.appendChild(traitbl2)
    traitbl2.style.stroke = 'rgb(74,173,222)'
    traitbl2.style.strokeWidth = '4px'
    this.params.traitbl2 = traitbl2

    // cree le texte
    const textElem = document.createElementNS(ns, 'text')
    textElem.setAttribute('x', this.params.scratchProgDonnees.Lutins[0].cox + 100)
    textElem.setAttribute('y', this.params.scratchProgDonnees.Lutins[0].coy)
    svg.appendChild(textElem)
    this.params.textElem = textElem
    textElem.style.fill = '#000'
    textElem.style.stroke = '#000'
    textElem.style.fontSize = '15px'
    const nbligne = Math.ceil(this.textWidth(msg, 'Comic sans MS', '15') / 250)
    const ligne = []
    let anc = 0
    for (let i = 0; i < nbligne; i++) {
      ligne[i] = msg.substring(anc, Math.round((i + 1) * (msg.length / nbligne) + 1))
      anc = Math.round((i + 1) * (msg.length / nbligne) + 1)
    }
    textElem.innerHTML = ligne[0]
    for (let i = 1; i < nbligne; i++) {
      textElem.innerHTML += '<tspan x="' + (this.params.scratchProgDonnees.Lutins[0].cox + 100) + '" y="' + (this.params.scratchProgDonnees.Lutins[0].coy + 15 * i) + '">' + ligne[i] + '</tspan>'
    }

    // cree les deux ligne jusque chat

    // prend la dimension du texte
    const { x, y, width, height } = textElem.getBoundingClientRect()
    const { x: x2, y: y2 } = rect2.getBoundingClientRect()

    // replace bien tout
    // le rect
    rect.y.baseVal.value = y - y2 - 10
    rect.x.baseVal.value = x - x2 - 10
    rect.width.baseVal.value = width + 20
    rect.height.baseVal.value = height + 20
    // la ligne blanche
    linebl.y1.baseVal.value = y - y2 + 10 + height
    linebl.x1.baseVal.value = x - x2 + width / 6
    linebl.y2.baseVal.value = y - y2 + 10 + height
    linebl.x2.baseVal.value = x - x2 + width / 2
    // un trait bleu
    traitbl1.y1.baseVal.value = y - y2 + 10 + height + 20
    traitbl1.x1.baseVal.value = x - x2
    traitbl1.y2.baseVal.value = y - y2 + 10 + height
    traitbl1.x2.baseVal.value = x - x2 + width / 2
    // autre trait bleu
    traitbl2.y1.baseVal.value = y - y2 + 10 + height
    traitbl2.x1.baseVal.value = x - x2 + width / 6
    traitbl2.y2.baseVal.value = y - y2 + 10 + height + 20
    traitbl2.x2.baseVal.value = x - x2

    const hjk = addDefaultTable(this.lesdivs.sortie3, 1, 2)
    this.params.GetZOne = new ZoneStyleMathquill1(hjk[0][0], { restric: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-*/ ', limite: 15, enter: this.scratchValGetUs.bind(this) })
    hjk[0][0].style.border = 0
    hjk[0][0].style.width = '92%'
    hjk[0][1].style.width = '20%'
    hjk[0][0].style.padding = 0
    hjk[0][0].parentNode.style.border = '4px rgb(74,173,222) solid'
    j3pAddElt(hjk[0][1], 'img', { src: valgetusImg })
    hjk[0][1].classList.add('boutValget')
    hjk[0][1].style.backgroundRepeat = 'no-repeat'

    hjk[0][1].addEventListener('click', this.scratchValGetUs2.bind(this), false)
    hjk[0][1].style.cursor = 'pointer'
    this.params.GetZOne.focus()

    if (!this.params.isEditing) this.lesdivs.stop.style.display = 'none'
    this.params.scratchProgDonnees.pause = true
    if (this.params.scratchProgDonnees.YaUtilisateur) this.scratchAfficheModaleUtilDonneValeur()
  }

  scratchValGetUs2 () {
    this.scratchValGetUs()
  }

  scratchValGetUs () {
    if (!this.params.scratchProgDonnees.run) return
    if (this.params.scratchProgDonnees.fostop) return
    if (this.params.scratchProgDonnees.blokinput === true) return
    if (this.params.scratchProgDonnees.YaUtilisateur) {
      const valrep = this.params.GetZOne.reponse().replace(/ /g, '')
      // FIXME apparemment il faut du != et pas !==
      if (valrep != this.params.scratchProgDonnees.valdonnee) { // eslint-disable-line eqeqeq
        this.scratchAfficheModaleUtilMauvaisevaleur()
        return
      }
    }
    this.params.scratchProgDonnees.reponse = this.params.GetZOne.reponse()
    if (this.params.scratchProgDonnees.reponse === '') { this.params.scratchProgDonnees.reponse = ' ' }
    this.params.GetZOne.disable()
    j3pDetruit(this.params.rect)
    j3pDetruit(this.params.textElem)
    j3pDetruit(this.params.traitbl2)
    j3pDetruit(this.params.traitbl1)
    j3pDetruit(this.params.linebl)

    if (!this.params.isEditing) this.lesdivs.stop.style.display = ''
    this.params.scratchProgDonnees.pause = false
    this.params.scratchProgDonnees.reponseDonnesAGetUS.push(this.params.scratchProgDonnees.reponse)
    j3pEmpty(this.lesdivs.sortie3)
  }

  setDisabledDansMenu (qui, disabled, tab) {
    qui = this.scratchTraduireOrdre(qui)
    if (qui === 'demander') { qui = 'Get_us' }
    if (tab === undefined) { tab = this.params.scratchProgDonnees.menu }
    for (let i = 0; i < tab.length; i++) {
      if (tab[i].type === 'catégorie' && this.setDisabledDansMenu(qui, disabled, tab[i].contenu)) return true
      if (tab[i].type === qui) {
        if (tab[i].disabled !== disabled) {
          tab[i].disabled = disabled
          return true
        }
      }
    }
  }

  desactiveDuMenu (qui) {
    if (this.params.me.etat !== 'correction') return

    if (this.setDisabledDansMenu(qui, true)) {
      const x = this.scratchCreeMenu(this.params.scratchProgDonnees.menu, true)
      const xmlDoc = $.parseXML(x)
      let xml = xmlDoc.firstChild
      while (xml.nodeType !== 1) {
        xml = xml.nextSibling
      }
      this.params.scratchProgDonnees.workspace.updateToolbox(xml)
    }
  }

  activeDuMenu (qui) {
    if (this.params.me.etat !== 'correction') return
    if (this.setDisabledDansMenu(qui, false)) {
      const x = this.scratchCreeMenu(this.params.scratchProgDonnees.menu, true)
      const xmlDoc = $.parseXML(x)
      let xml = xmlDoc.firstChild
      while (xml.nodeType !== 1) {
        xml = xml.nextSibling
      }
      this.params.workspaceEl.updateToolbox(xml)
    }
  }

  textWidth (content, police, taille) {
    const container = j3pAddElt(document.body, 'div', content, {
      style: {
        visibility: 'hidden',
        width: '1px',
        fontFamily: police,
        fontSize: taille + 'px',
        overflow: 'auto'
      }
    })
    const longueur = container.scrollWidth
    container.parentNode.removeChild(container)
    return longueur
  } // scratchTextWidth
}

export default ScratchBase