131 private links
La passion !!
"Je te prends un exemple simple : tu dois rajouter un champ dans un formulaire. Ça a l’air simple, mais ça ne l’est pas. Car le formulaire il est dans un énorme portail en prod. Déjà il faut mettre à jour la base de données en mettant à jour le script de migration lancé au moment du build sur la CI au moment du docker build. Si tu ne maîtrises pas bash, docker et la CI-CD déjà t’es pas bien et tu transpires. Et t’as rien fait là encore ! Il reste à mettre à jour le model de données backend, la validation coté UI, ajouter des tests unitaires, des tests d’intégration, des tests fonctionnels, passer la code review, passer la QA, déployer sur tous les environnements pour enfin prier de pas te péter la gueule en prod. Ça t’a pris trois jours et t’as fait deux crises d’épilepsie."
« Nous pensons qu’à terme, les personnes précaires seront orientées vers ces annonces, dit Daniel. Ils auront des indemnités ridicules, voire pas d’indemnités du tout et on va pouvoir leur dire : "Ça tombe bien on a des postes difficiles à pourvoir !" Ce sont les fameux emplois à déficit d’image. »
« Dans notre bassin d’emploi, par exemple, on a une cafétéria qui est une vraie lessiveuse à salariés, illustre un conseiller. Tout le monde le sait, tout le monde la connaît. Personne ne veut aller y travailler. Demain la direction va nous demander : "Pourquoi vous ne proposez pas ces offres ?" Et ils vont dire aux demandeurs d’emplois : "Vous avez validé des compétences en vente, la restauration c’est la même chose, allez hop !" »
"Les faits reprochés à Laura Pfeiffer portent sur des e-mails envoyés et reçus en 2013 par la direction de l’usine Tefal à Rumilly (Haute-Savoie). Ils avaient été transmis à l’inspectrice du travail par un salarié de l’entreprise, Christophe M., qui se les était procurés frauduleusement. Ces correspondances pouvaient laisser penser qu’il y avait une collusion entre les patrons du fabricant d’articles de cuisine et Philippe Dumont, le supérieur hiérarchique de Laura Pfeiffer, afin que celle-ci se montre moins rigide lors de contrôles d’entreprises."
@jmblanquer : "La #laïcité française c'est de dire que l'espace public est un espace de raison, où l'on doit échanger de manière rationnelle et argumentée, entre citoyens égaux"
"La CNIL allemande vient de rendre un jugement en Allemagne interdisant l’utilisation de Windows 10 et Office 365 dans les écoles, car ces produits enfreignent le RGPD"
(Règlement Général sur la Protection des Données)
"et si l’accident avait été plus grave pour le conducteur ?"
"un TER heurte un convoi exceptionnel et blesse le conducteur qui, seul et blessé à la jambe, doit aller sécuriser le train en marchant 1,5km, avant de revenir s’occuper des passagers, étant seul dans le train à cause des suppressions de postes dans l’entreprise."
"en effet, d’autres trains arrivant sur la voie auraient pu causer un « sur-accident », si le cheminot n’était pas parvenu à mettre en place la procédure d’urgence assez rapidement."
NB: le poste radio du train a été cassé lors de la collision
PS: oui, je viens de le découvrir
Click on the button, if yuo can !
const { useState, useRef, useEffect, useLayoutEffect, createContext } = React;
/**
* Globals
*/
const CONSTANTS = {
assetPath: "https://s3-us-west-2.amazonaws.com/s.cdpn.io/184729",
}
const ASSETS = {
head: `${CONSTANTS.assetPath}/head.svg`,
waiting: `${CONSTANTS.assetPath}/hand.svg`,
stalking: `${CONSTANTS.assetPath}/hand-waiting.svg`,
grabbing: `${CONSTANTS.assetPath}/hand.svg`,
grabbed: `${CONSTANTS.assetPath}/hand-with-cursor.svg`,
shaka: `${CONSTANTS.assetPath}/hand-surfs-up.svg`
}
// Preload images
Object.keys(ASSETS).forEach(key => {
const img = new Image();
img.src = ASSETS[key];
});
/**
* Shared hooks
*/
// Hover state - https://dev.to/spaciecat/hover-states-with-react-hooks-4023
const useHover = () => {
const ref = useRef();
const [hovered, setHovered] = useState(false);
const enter = () => setHovered(true);
const leave = () => setHovered(false);
useEffect(
() => {
ref.current.addEventListener("mouseenter", enter);
ref.current.addEventListener("mouseleave", leave);
return () => {
ref.current.removeEventListener("mouseenter", enter);
ref.current.removeEventListener("mouseleave", leave);
};
},
[ref]
);
return [ref, hovered];
};
// Mouse position
const useMousePosition = () => {
const [position, setPosition] = useState({ x: 0, y: 0 });
useEffect(() => {
const setFromEvent = e => setPosition({ x: e.clientX, y: e.clientY });
window.addEventListener("mousemove", setFromEvent);
return () => {
window.removeEventListener("mousemove", setFromEvent);
};
}, []);
return position;
};
// Element position
const usePosition = () => {
const ref = useRef();
const [position, setPosition] = useState({});
const handleResize = () => {
setPosition(ref.current.getBoundingClientRect());
};
useLayoutEffect(() => {
handleResize();
window.addEventListener('resize', handleResize);
return () => {
window.removeEventListener('resize', handleResize);
};
}, [ref.current]);
return [ref, position];
};
/**
* React Components
*/
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
debug: false,
cursorGrabbed: false,
gameOver: false,
};
this.handleToggleDebug = this.handleToggleDebug.bind(this);
this.handleButtonClicked = this.handleButtonClicked.bind(this);
this.handleCursorGrabbed = this.handleCursorGrabbed.bind(this);
}
handleToggleDebug() {
this.setState({
debug: !this.state.debug
});
}
handleCursorGrabbed() {
this.setState({
cursorGrabbed: true
});
setTimeout(() => {
this.setState({
cursorGrabbed: false
});
}, 2000)
}
handleButtonClicked() {
this.setState({
gameOver: true
});
setTimeout(() => {
this.setState({
gameOver: false
});
}, 4000)
}
render() {
const { cursorGrabbed, gameOver, debug } = this.state;
const screenStyle = cursorGrabbed ? { cursor: "none" } : {};
const appClass = debug ? "app app--debug" : "app";
return (
<div className={appClass} style={screenStyle}>
<section className="container">
<h1>Hello!</h1>
<h2>Welcome to the internet.</h2>
<p>This is a classic website, no traps or weird stuff!</p>
<p>Feel free to browse, relax and, I don't know, click the button down there? Might as well, right?</p>
<button
className="debug-button"
onClick={this.handleToggleDebug}>
Debug
</button>
</section>
<button
className="trap-button"
onClick={this.handleButtonClicked}>
{ gameOver && "Nice one" }
{ cursorGrabbed && "Gotcha!" }
{ !gameOver && !cursorGrabbed && "Button!"}
</button>
<div className="grab-zone-wrapper">
<GrabZone
onCursorGrabbed={this.handleCursorGrabbed}
cursorGrabbed={cursorGrabbed}
gameOver={gameOver}
/>
</div>
</div>
);
}
}
// GrabZone (The hover trigger zone)
const GrabZone = ({ cursorGrabbed, gameOver, onCursorGrabbed }) => {
const [outerRef, outerHovered] = useHover();
const [innerRef, innerHovered] = useHover();
const [isExtended, setExtendedArm] = useState(false);
let state = "waiting";
if (outerHovered) {
state = "stalking";
}
if (innerHovered) {
state = "grabbing";
}
if (cursorGrabbed) {
state = "grabbed";
}
if (gameOver) {
state = "shaka"
}
// If state is grabbing for a long time, they're being clever!
useEffect(() => {
let timer;
if (state === "grabbing") {
timer = setTimeout(() => {
// Not so clever now, are they?
setExtendedArm(true);
timer = null;
}, 2000);
}
return () => {
setExtendedArm(false);
if (timer) {
clearTimeout(timer);
}
};
},
[state]
);
return (
<div className="grab-zone" ref={outerRef}>
<div className="grab-zone__debug">
<strong>Debug info:</strong>
<p>Current state: {state}</p>
<p>Extended arm: {isExtended ? "Yes" : "No"}</p>
</div>
<div className="grab-zone__danger" ref={innerRef}>
<Grabber
state={state}
gameOver={gameOver}
extended={isExtended}
onCursorGrabbed={onCursorGrabbed}
/>
</div>
</div>
);
};
// Grabber (The graphic)
const Grabber = ({ state, gameOver, extended, onCursorGrabbed }) => {
const mousePos = useMousePosition();
const [ref, position] = usePosition();
const hasCursor = false;
// Calculate rotation of armWrapper
const x = position.left + position.width * 0.5;
const y = position.top + position.height * 0.5;
const angle = gameOver ? 0 : Math.atan2(mousePos.x - x, -(mousePos.y - y)) * (180 / Math.PI);
// Ensure value is within acceptable range (-75 to 75)
const rotation = Math.min(Math.max(parseInt(angle), -79), 79);
const grabberClass = `grabber grabber--${state} ${extended && "grabber--extended"}`;
const wrapperStyle = { transform: `rotate(${rotation}deg)` };
let handImageSrc = ASSETS[state];
return (
<div className={grabberClass}>
<div className="grabber__body"></div>
<img className="grabber__face" src={ASSETS.head} />
<div className="grabber__arm-wrapper" ref={ref} style={wrapperStyle}>
<div className="grabber__arm">
<img
className="grabber__hand"
src={handImageSrc}
onMouseEnter={onCursorGrabbed}
/>
</div>
</div>
</div>
);
};
// Render app
ReactDOM.render(<App />, document.getElementById("app"));
html {
font-size: 18px;
@media (min-width: 900px) {
font-size: 24px;
}
}
body {
font-family: 'Montserrat', sans-serif;
font-weight: 300;
line-height: 1.45;
color: #0F1108;
}
h1 {
font-size: 2.2rem;
margin: 0;
font-weight: 600;
line-height: 1.15;
@media (min-width: 900px) {
font-size: 2.488rem;
}
}
h2 {
font-size: 1.4rem;
margin: 0.5rem 0;
line-height: 1.15;
font-weight: 200;
@media (min-width: 900px) {
margin: 1rem 0;
font-size: 1.44rem;
}
}
p {
margin-top: 0.25rem;
@media (min-width: 900px) {
margin-top: 0.5rem;
}
}
a {
color: #0F1108;
text-decoration: none;
border-bottom: currentcolor 1px solid;
}
// General modules
.container {
max-width: 520px;
margin: 0 auto;
padding: 0 1rem 100px 1rem;
@media (min-width: 900px) {
max-width: 650px;
padding: 0 1rem 90px 1rem;
}
}
// Full-screen wrapper
.app {
position: relative;
background: #F2E9DE;
display: flex;
align-items: center;
justify-content: center;
min-height: calc(100vh - 2rem);
margin: 1rem;
overflow: hidden;
// Modifiers
&--debug {
.grab-zone {
background: rgba(0, 0, 0, 0.15);
}
.grab-zone__debug {
display: block;
}
.grab-zone__danger {
background: rgba(0, 0, 0, 0.15);
}
.grabber__arm-wrapper {
background: rgba(0, 0, 0, 0.15);
}
}
}
.grab-zone-wrapper {
position: absolute;
bottom: 0;
right: 0;
transform: translateX(30%) translateY(50%);
}
.grab-zone {
display: flex;
align-items: center;
justify-content: center;
width: 700px;
height: 700px;
border-radius: 50%;
&__danger {
display: flex;
align-items: center;
justify-content: center;
width: 400px;
height: 400px;
border-radius: 50%;
}
&__debug {
display: none;
position: absolute;
width: 300px;
top: -100px;
font-size: 14px;
text-align: center;
text-transform: uppercase;
}
}
.grabber {
position: relative;
width: 100px;
height: 100px;
&__arm-wrapper {
position: absolute;
top: -80px;
width: 24px;
height: 260px;
}
&__arm {
position: relative;
width: 24px;
height: 200px;
background: #7D9A9E;
border-radius: 20px;
overflow: visible;
transform: translateY(100%);
transition: transform 0.2s ease;
}
&__hand {
display: block;
position: absolute;
top: -12px;
transform: scale(1.4) rotate(-10deg) translateY(100%);
transform-origin: bottom center;
transition: transform 0.3s ease;
}
&__face {
position: absolute;
width: 75px;
height: 84px;
right: 5%;
transition: transform 0.3s ease;
}
&__body {
position: absolute;
top: 50%;
left: 0%;
width: 110px;
height: 95px;
border-radius: 50%;
background: #7D9A9E;
transition: transform 0.3s ease;
}
// Modifiers
&--waiting {
.grabber__hand {
transform: scale(1.4) rotate(-10deg);
}
.grabber__arm {
transform: translateY(80%);
}
.grabber__face {
transform: translateY(60%);
}
}
// Modifiers
&--stalking {
.grabber__hand {
transform: scale(1.4) rotate(-10deg);
}
.grabber__arm {
transform: translateY(70%);
}
.grabber__face {
transform: translateY(10%);
}
}
&--grabbing {
.grabber__face {
transform: translateY(-40%) rotate(10deg);
}
.grabber__arm {
transform: translateY(0%);
}
.grabber__body {
transform: translateY(-20%);
}
.grabber__hand {
transform: scale(1.7) rotate(10deg);
}
}
&--grabbed {
.grabber__arm {
transition: transform 1s ease;
}
.grabber__hand {
transition: transform 2.5s ease;
}
.grabber__face {
transform: translateY(70%);
transition: transform 1s ease;
}
.grabber__body {
transform: translateY(50%);
transition: transform 1s ease;
}
}
&--extended {
.grabber__arm {
transform: translateY(-20%);
}
.grabber__face {
transform: translateY(-60%) rotate(15deg);
}
.grabber__body {
transform: translateY(-40%);
}
}
&--shaka {
.grabber__arm {
transform: translateY(50%);
}
.grabber__hand {
transform: scale(2.5) translateY(10%);
animation: shaka 0.5s infinite alternate forwards;
transform-origin: 55% 60%;
}
.grabber__face {
transform: translateY(70%);
transition: transform 1s ease;
}
.grabber__body {
transform: translateY(50%);
transition: transform 1s ease;
}
}
}
.trap-button {
position: absolute;
bottom: 80px;
right: 70px;
min-width: 125px;
background: #8ECACC;
color: white;
border-radius: 5px;
padding: 0.4rem 0.5rem;
font-weight: 600;
font-size: 18px;
letter-spacing: 1px;
text-transform: uppercase;
}
.debug-button {
position: fixed;
top: 0;
right: 0;
background: transparent;
padding: 1rem;
margin: 1rem;
font-size: 16px;
text-transform: uppercase;
letter-spacing: 1px;
opacity: 0.5;
}
@keyframes shaka {
0% { transform: scale(2.5) translateY(0%) rotate(-20deg); }
100% { transform: scale(2.5) translateY(0%) rotate(20deg); }
}
<div id="app"></div>
Certains élèves de Chine ont un dispositif qui analyse leur activité cérébrale en cours, qui est directement consultable par le prof et les parents. Il y a même une petite lumière bleu quand l'élève est dissipé...
Résultats: ils ont peurs, se surmènent et sont anormalement actif en classe (dixit la prof).
Les données, on ne sait pas qui y a réellement accès...
Pourquoi choisir le JS comme langage d'apprentissage
"#LindaKebbab admet que les #BlackBlocs pourraient être arrétés mais que les ordres ne sont pas donnés en ce sens !