IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Cloud Computing Discussion :

AWS crée un fork du projet Headless recorder et le lance comme son propre service


Sujet :

Cloud Computing

  1. #1
    Chroniqueur Actualités
    Avatar de Patrick Ruiz
    Homme Profil pro
    Redacteur web
    Inscrit en
    février 2017
    Messages
    1 256
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Cameroun

    Informations professionnelles :
    Activité : Redacteur web
    Secteur : Communication - Médias

    Informations forums :
    Inscription : février 2017
    Messages : 1 256
    Points : 38 255
    Points
    38 255
    Par défaut AWS crée un fork du projet Headless recorder et le lance comme son propre service
    « AWS créé un fork de mon projet et le lance comme son propre service », dit le créateur de l’application headless recorder
    Auquel Amazon répond : « nous promettons de mieux faire. »

    Headless recorder est une extension Chrome qui enregistre les interactions des internautes avec leur navigateur web et génère un script Puppeteer ou Playwright. Son créateur accuse Amazon Web Services d’avoir créé un fork de son projet et de l’avoir lancé comme son propre service. La situation divise les observateurs : un pan est d’avis que les créateurs de projets qui finissent par être forkés par des géants technologiques méritent compensation pour leurs efforts ; un autre lui oppose la nécessité pour les développeurs de choisir des licences logicielles qui cadrent avec leurs prétentions.

    Le code source de l’application web headless recorder est disponible. Ci-dessous celui des sections enregistreur d’événements et contrôleur d’interfaces utilisateur :

    Code JavaScript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    import eventsToRecord from '../code-generator/dom-events-to-record'
    import UIController from './UIController'
    import actions from '../models/extension-ui-actions'
    import ctrl from '../models/extension-control-messages'
    import finder from '@medv/finder'
     
    const DEFAULT_MOUSE_CURSOR = 'default'
     
    export default class EventRecorder {
      constructor () {
        this._boundedMessageListener = null
        this._eventLog = []
        this._previousEvent = null
        this._dataAttribute = null
        this._uiController = null
        this._screenShotMode = false
        this._isTopFrame = (window.location === window.parent.location)
        this._isRecordingClicks = true
      }
     
      boot () {
        // We need to check the existence of chrome for testing purposes
        if (chrome.storage && chrome.storage.local) {
          chrome.storage.local.get(['options'], ({options}) => {
            const { dataAttribute } = options ? options.code : {}
            if (dataAttribute) {
              this._dataAttribute = dataAttribute
            }
            this._initializeRecorder()
          })
        } else {
          this._initializeRecorder()
        }
      }
     
      _initializeRecorder () {
        const events = Object.values(eventsToRecord)
        if (!window.pptRecorderAddedControlListeners) {
          this._addAllListeners(events)
          this._boundedMessageListener = this._boundedMessageListener || this._handleBackgroundMessage.bind(this)
          chrome.runtime.onMessage.addListener(this._boundedMessageListener)
          window.pptRecorderAddedControlListeners = true
        }
     
        if (!window.document.pptRecorderAddedControlListeners && chrome.runtime && chrome.runtime.onMessage) {
          window.document.pptRecorderAddedControlListeners = true
        }
     
        if (this._isTopFrame) {
          this._sendMessage({ control: ctrl.EVENT_RECORDER_STARTED })
          this._sendMessage({ control: ctrl.GET_CURRENT_URL, href: window.location.href })
          this._sendMessage({ control: ctrl.GET_VIEWPORT_SIZE, coordinates: { width: window.innerWidth, height: window.innerHeight } })
          console.debug('Puppeteer Recorder in-page EventRecorder started')
        }
      }
     
      _handleBackgroundMessage (msg, sender, sendResponse) {
        console.debug('content-script: message from background', msg)
        if (msg && msg.action) {
          switch (msg.action) {
            case actions.TOGGLE_SCREENSHOT_MODE:
              this._handleScreenshotMode(false)
              break
            case actions.TOGGLE_SCREENSHOT_CLIPPED_MODE:
              this._handleScreenshotMode(true)
              break
            default:
          }
        }
      }
     
      _addAllListeners (events) {
        const boundedRecordEvent = this._recordEvent.bind(this)
        events.forEach(type => {
          window.addEventListener(type, boundedRecordEvent, true)
        })
      }
     
      _sendMessage (msg) {
        // filter messages based on enabled / disabled features
        if (msg.action === 'click' && !this._isRecordingClicks) return
     
        try {
          // poor man's way of detecting whether this script was injected by an actual extension, or is loaded for
          // testing purposes
          if (chrome.runtime && chrome.runtime.onMessage) {
            chrome.runtime.sendMessage(msg)
          } else {
            this._eventLog.push(msg)
          }
        } catch (err) {
          console.debug('caught error', err)
        }
      }
     
      _recordEvent (e) {
        if (this._previousEvent && this._previousEvent.timeStamp === e.timeStamp) return
        this._previousEvent = e
     
        // we explicitly catch any errors and swallow them, as none node-type events are also ingested.
        // for these events we cannot generate selectors, which is OK
        try {
          const optimizedMinLength = (e.target.id) ? 2 : 10 // if the target has an id, use that instead of multiple other selectors
          const selector = this._dataAttribute
            ? finder(e.target, {seedMinLength: 5, optimizedMinLength: optimizedMinLength, attr: (name, _value) => name === this._dataAttribute})
            : finder(e.target, {seedMinLength: 5, optimizedMinLength: optimizedMinLength})
     
          const msg = {
            selector: selector,
            value: e.target.value,
            tagName: e.target.tagName,
            action: e.type,
            keyCode: e.keyCode ? e.keyCode : null,
            href: e.target.href ? e.target.href : null,
            coordinates: EventRecorder._getCoordinates(e)
          }
          this._sendMessage(msg)
        } catch (e) {}
      }
     
      _getEventLog () {
        return this._eventLog
      }
     
      _clearEventLog () {
        this._eventLog = []
      }
     
      _handleScreenshotMode (isClipped) {
        this._disableClickRecording()
        this._uiController = new UIController({ showSelector: isClipped })
        this._screenShotMode = !this._screenShotMode
        document.body.style.cursor = 'crosshair'
     
        console.debug('screenshot mode:', this._screenShotMode)
     
        if (this._screenShotMode) {
          this._uiController.showSelector()
        } else {
          this._uiController.hideSelector()
        }
     
        this._uiController.on('click', event => {
          this._screenShotMode = false
          document.body.style.cursor = DEFAULT_MOUSE_CURSOR
          this._sendMessage({ control: ctrl.GET_SCREENSHOT, value: event.clip })
          this._enableClickRecording()
        })
      }
     
      _disableClickRecording () {
        this._isRecordingClicks = false
      }
     
      _enableClickRecording () {
        this._isRecordingClicks = true
      }
     
      static _getCoordinates (evt) {
        const eventsWithCoordinates = {
          mouseup: true,
          mousedown: true,
          mousemove: true,
          mouseover: true
        }
        return eventsWithCoordinates[evt.type] ? { x: evt.clientX, y: evt.clientY } : null
      }
     
      static _formatDataSelector (element, attribute) {
        return `[${attribute}="${element.getAttribute(attribute)}"]`
      }
    }

    Code JavaScript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    import EventEmitter from 'events'
     
    const BORDER_THICKNESS = 3
     
    const defaults = {
      showSelector: false
    }
     
    class UIController extends EventEmitter {
      constructor (options) {
        options = Object.assign({}, defaults, options)
     
        super()
        this._overlay = null
        this._selector = null
        this._element = null
        this._dimensions = {}
        this._showSelector = options.showSelector
     
        this._boundeMouseMove = this._mousemove.bind(this)
        this._boundeMouseUp = this._mouseup.bind(this)
      }
     
      showSelector () {
        console.debug('UIController:show')
        if (!this._overlay) {
          this._overlay = document.createElement('div')
          this._overlay.className = 'headlessRecorderOverlay'
          this._overlay.style.position = 'fixed'
          this._overlay.style.top = '0px'
          this._overlay.style.left = '0px'
          this._overlay.style.width = '100%'
          this._overlay.style.height = '100%'
          this._overlay.style.pointerEvents = 'none'
     
          if (this._showSelector) {
            this._selector = document.createElement('div')
            this._selector.className = 'headlessRecorderOutline'
            this._selector.style.position = 'fixed'
            this._selector.style.border = BORDER_THICKNESS + 'px solid rgba(69,200,241,0.8)'
            this._selector.style.borderRadius = '3px'
            this._overlay.appendChild(this._selector)
          }
        }
        if (!this._overlay.parentNode) {
          document.body.appendChild(this._overlay)
          document.body.addEventListener('mousemove', this._boundeMouseMove, false)
          document.body.addEventListener('click', this._boundeMouseUp, false)
        }
      }
     
      hideSelector () {
        console.debug('UIController:hide')
        if (this._overlay) {
          document.body.removeChild(this._overlay)
        }
        this._overlay = this._selector = this._element = null
        this._dimensions = {}
      }
     
      _mousemove (e) {
        if (this._element !== e.target) {
          this._element = e.target
     
          this._dimensions.top = -window.scrollY
          this._dimensions.left = -window.scrollX
     
          let elem = e.target
     
          while (elem && elem !== document.body) {
            this._dimensions.top += elem.offsetTop
            this._dimensions.left += elem.offsetLeft
            elem = elem.offsetParent
          }
          this._dimensions.width = this._element.offsetWidth
          this._dimensions.height = this._element.offsetHeight
     
          if (this._selector) {
            this._selector.style.top = (this._dimensions.top - BORDER_THICKNESS) + 'px'
            this._selector.style.left = (this._dimensions.left - BORDER_THICKNESS) + 'px'
            this._selector.style.width = this._dimensions.width + 'px'
            this._selector.style.height = this._dimensions.height + 'px'
            console.debug(`top: ${this._selector.style.top}, left: ${this._selector.style.left}, width: ${this._selector.style.width}, height: ${this._selector.style.height}`)
          }
        }
      }
      _mouseup (e) {
        this._overlay.style.backgroundColor = 'white'
        setTimeout(() => {
          this._overlay.style.backgroundColor = 'none'
          this._cleanup()
     
          let clip = null
     
          if (this._selector) {
            clip = {
              x: this._selector.style.left,
              y: this._selector.style.top,
              width: this._selector.style.width,
              height: this._selector.style.height
            }
          }
     
          this.emit('click', { clip, raw: e })
        }, 100)
      }
     
      _cleanup () {
        document.body.removeEventListener('mousemove', this._boundeMouseMove, false)
        document.body.removeEventListener('mouseup', this._boundeMouseUp, false)
        document.body.removeChild(this._overlay)
      }
    }
     
    module.exports = UIController

    En matière d’open source, l’un des principes de base est d’ouvrir l’accès d’une base de code à des tiers pour qu’ils puissent en faire une copie et introduire des modifications en fonction de la nouvelle orientation recherchée. Les contraintes additionnelles sont spécifiques à chaque type de licence. C’est grosso modo ce sur quoi Amazon s’est appuyé pour créer un fork du projet Headless recorder sachant que ce dernier est publié sous une licence permissive : Apache version 2.0. L’entreprise l’a ensuite lancé comme son propre service, ce que rappelle l’auteur de l’application Headless recorder tout en rappelant quelles sont les obligations d’Amazon…

    Nom : 7.png
Affichages : 67724
Taille : 192,9 Ko

    La situation n’est pas sans faire penser à celle du système de gestion de base de données clé-valeur scalable – Redis. Le cœur du projet est publié sous licence permissive BSD. Au troisième trimestre de l’année 2018, l’équipe Redis a procédé à une reformulation des licences de certains de ses modules complémentaires, bloquant de fait leur utilisation par des tiers offrant des services commerciaux basés sur Redis. L’entreprise visait les gros fournisseurs de cloud computing : Google, Amazon, Microsoft, IBM.

    « Les fournisseurs de services cloud ont à plusieurs reprises tiré profit de projets open source réussis et les ont reconditionnés en offres de services propriétaires compétitives. Les fournisseurs de cloud computing contribuent très peu (voire pas du tout) à ces projets open source. Au lieu de cela, ils utilisent leur nature monopolistique pour en tirer des centaines de millions de dollars de revenus. Ce comportement porte préjudice aux communautés open source et a mis en faillite certaines des entreprises à pied d’œuvre dans la sphère », avait lancé l’équipe Redis.

    Le responsable de ces questions chez Amazon a fait une sortie pour indiquer qu’il n’avait pas été mis au courant et est en train d’étudier la question. « Je vous suis reconnaissant de votre aide dans ce domaine. AWS utilise beaucoup de logiciels libres et nous y contribuons beaucoup. Mais l'open source est en fin de compte une communauté d'utilisateurs et je pense personnellement que nous aurions pu faire mieux ici. Je vais voir avec vous comment nous pouvons mieux soutenir l'excellent travail que vous faites avec headless recorder », a-t-il ajouté.

    Nom : 8.png
Affichages : 5585
Taille : 41,6 Ko

    Source : Twitter, annonce du lancement du service par Amazon

    Et vous ?

    Qui d'Amazon ou des responsables du projet Headless recorder est le plus à blâmer dans cette situation ?
    Le projet Headless recorder ne bénéficie-t-il pas quelque part d'une meilleure visibilité au travers d'Amazon ?

    voir aussi :

    la rubrique Cloud computing
    Contribuez au club : Corrections, suggestions, critiques, ... : Contactez le service news et Rédigez des actualités

  2. #2
    Membre extrêmement actif
    Profil pro
    Inscrit en
    juin 2010
    Messages
    756
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : juin 2010
    Messages : 756
    Points : 901
    Points
    901
    Par défaut
    Ouais enfin le type propose son soft dans une licence en mode yolo, et vient se plaindre après

    Concernant Redis sur Azure Microsoft propose Azure Cache For Redis, et RedisLab propose des images Enterprise ce qui est plutôt cool. Sur AWS je ne sais pas du tout ce qui est proposé.

    Je dirai que la différence entre ces différents fournisseurs tiens à leur politique une grosse partie des briques utilisés par Microsoft sur le health data hub est dispo sur leur repo Github, notamment toute la partie gestion des différents formats d'entrées sorties, DICOM server, FHIR server, pour les stats ils utilisent uniquement le format SARIF, pour le deep learning sur les données médical ils utilisent InnerEye-DeepLearning. Tout ça est dispo sous licence MIT.

    Par contre j'ai genre 100 fois moins confiance en AWS ils ne publient pas du tout le code de brique aussi importantes en plus de ne pas avoir du tout le même politique en terme de datacenter.

  3. #3
    Membre du Club
    Profil pro
    Inscrit en
    août 2007
    Messages
    45
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : août 2007
    Messages : 45
    Points : 63
    Points
    63
    Par défaut
    Que seraient Amazon, Google,. ... sans Linux ?
    C'est assez paradoxale, les défenseurs du libre sont souvent anti gafam hors ils n'existeraient peut être pas sans l'Open Source et le "gratuit".

  4. #4
    Membre extrêmement actif Avatar de darklinux
    Profil pro
    Consultant en technologies
    Inscrit en
    novembre 2005
    Messages
    538
    Détails du profil
    Informations personnelles :
    Localisation : France, Seine et Marne (Île de France)

    Informations professionnelles :
    Activité : Consultant en technologies
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : novembre 2005
    Messages : 538
    Points : 870
    Points
    870
    Par défaut
    D ' ou la nécessité de savoir ce que l ' on veut dès le départ

  5. #5
    Membre éprouvé
    Homme Profil pro
    Développeur Java
    Inscrit en
    mai 2019
    Messages
    373
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur Java

    Informations forums :
    Inscription : mai 2019
    Messages : 373
    Points : 1 068
    Points
    1 068
    Par défaut
    Citation Envoyé par rthomas Voir le message
    Que seraient Amazon, Google,. ... sans Linux ?
    C'est assez paradoxale, les défenseurs du libre sont souvent anti gafam hors ils n'existeraient peut être pas sans l'Open Source et le "gratuit".
    En quoi c'est paradoxale ? C'est comme dire qu'il y aurait pas de meurtre sans victime...Ca fait que souligner son propos au contraire.

  6. #6
    Membre régulier
    Homme Profil pro
    retraité depuis juin 2019
    Inscrit en
    février 2018
    Messages
    40
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 59
    Localisation : Belgique

    Informations professionnelles :
    Activité : retraité depuis juin 2019
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : février 2018
    Messages : 40
    Points : 123
    Points
    123
    Par défaut Mais de quelle licence s'agit-il donc ?
    Dans cet article, il est écrit

    La situation divise les observateurs : un pan est d’avis que les créateurs de projets qui finissent par être forkés par des géants technologiques méritent compensation pour leurs efforts ; un autre lui oppose la nécessité pour les développeurs de choisir des licences logicielles qui cadrent avec leurs prétentions.
    Autrement dit, si vous voulez être rétribué en postant votre code source, veuillez choisir une licence qui indique que votre code ne peut pas être utilisé par des entreprises hors rétribution.

    Mais quelle est donc cette licence à choisir qui permettrait à un développeur d'être rétribué par les entreprises qui cloneraient son code tout en permettant aux autres développeurs de cloner gratuitement ce même code ?

    Si cette licence existe, quel est donc le prix d'une rétribution juste ?

Discussions similaires

  1. OnePlus s’éloigne de Cyanogen et crée son propre fork d’Android
    Par Stéphane le calme dans le forum Mobiles
    Réponses: 1
    Dernier message: 31/01/2015, 00h57
  2. Script? Crée les fichiers de projets à la main à partir d'un simple fichier
    Par LittleWhite dans le forum Langages de programmation
    Réponses: 3
    Dernier message: 18/09/2009, 23h12
  3. Créer un projet avec son propre makefile
    Par Mika2008 dans le forum Eclipse C & C++
    Réponses: 3
    Dernier message: 30/04/2009, 11h29
  4. projet avec une boite de dialogue comme fenêtre principale
    Par patsolaar dans le forum Windows Mobile
    Réponses: 1
    Dernier message: 01/02/2008, 00h46

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo