131 private links
« Il y a quelques jours, l’amie @Harsinoee se rend à la préfecture des Pyrénées-Orientales, à Perpignan, pour plaider sa cause devant la commission DALO (droit au logement opposable). Il y a le feu au lac, et pas qu’un peu.
Cette procédure représente en effet son dernier espoir de retrouver un toit et de reprendre pied après l’invraisemblable série de tuiles qui se sont abattues sur elle ces dernières années : la CAF qui se plante dans ses calculs et lui coupe les allocs, la privation quasi totale de ses moyens de subsistance, les dettes, les insomnies, l’arrêté d’expulsion, la peur au ventre de se retrouver à la rue avec son fils et ses chats – toutes choses dont on vous a déjà parlé, ici ou sur le fil de @Harsinoee .Vous en trouverez également un résumé sur la page de son comité de soutien (où Harsinoee mettra bientôt en ligne son courrier au @Defenseurdroits). https://soutienharsinoee.home.blog/
Au passage : celles et ceux qui ont alimenté sa cagnotte de lutte (6 400 euros, merci !), sachez que cet argent ne servira pas seulement à payer le champagne le jour de la victoire, quand elle aura enfin gagné son combat contre la CAF, l’OPHLM et la préf. Pour l’instant, le fric sert exclusivement à payer les frais d’avocat pour mener la lutte sur le plan judiciaire. Notre courageuse amie s’entête à ne vouloir prendre aucun sou pour elle et continue de se nourrir à la banque alimentaire. Fin de la parenthèse.
Voici donc Harsinoee qui se pointe à la préfecture, confiante dans l’examen de sa demande de relogement. Et là, stupeur : son référent préfectoral – que nous appellerons Igor, comme l’assistant patibulaire du baron Frankenstein – lui annonce que ça ne va pas être possible.
Pourquoi ? Parce que, lui dit Igor, des images de vidéosurveillance enregistrées à Perpignan la montrent en présence d’un homme. Un homme, doux Jésus ! C’est bien la preuve que Madame vit en couple, qu’elle n’est donc pas célibataire et que par conséquent elle a menti sur son statut de mère isolée. Moyennant quoi la commission est au regret de ne pouvoir examiner son dossier. Abasourdie, Harsinoee demande à visionner ces images, mais Igor ne veut rien savoir, circulez, fin de la discussion.
L’histoire est délirante à tous les niveaux.
1/ Harsinoee n’a pas de compagnon. Depuis le viol qu’elle a subi en mai 2018, elle n’est pas spécialement en recherche de compagnie masculine.
2/ Quand bien même elle aurait un chéri, un pote ou un cousin, en quoi ce serait les oignons du @pref66 ?
3/ Quand bien même la préfecture s’arrogerait le droit de veiller aux bonnes mœurs des femmes célibataires, en quoi cela justifierait l’usage de la vidéosurveillance, encadré en principe par un truc ballot qui s’appelle la loi, n’est-ce pas la @CNIL ?
Plein d'autres questions se posent. Ces images existent-elles seulement ? Si oui, qui les a enregistrées, identifiées et fournies à la préfecture, et dans quel but ? Et si elles n’existent que dans l’imagination créative d’Igor, pourquoi avoir inventé une histoire aussi wtf ?
L’ennui, c’est que l’argument invoqué pour virer Harsinoee du DALO n’a laissé aucune trace écrite. Passé un certain délai, elle pourra certes contester le rejet de son dossier devant le tribunal administratif, mais d’ici là la préf aura peut-être élaboré un plan plus présentable.
Son avocate n’étant hélas ni très réactive, ni très disponible, Harsinoee a essayé de recontacter Igor à plusieurs reprises. Son comité de soutien s’y est collé aussi, mais l’agent préfectoral a mis prudemment sa ligne sur répondeur. Nous sommes donc passés par le standard de la préf, qui nous a renvoyé à la responsable de la communication, laquelle a mis vingt-quatre heures pour nous servir par SMS une réponse en deux temps.
Premier temps : « Le dossier de cette personne a bien été examiné en commission. Au cours de cette réunion il n’a jamais été question de sa situation personnelle et encore moins de vidéosurveillance. » Ah, parfait. Donc Igor a tout inventé. Ou alors c’est Harsinoee qui a rêvé ?
Trois heures plus tard, nouveau texto, nouvelle version. « Après renseignements pris auprès des services concernés, le dossier de cette personne n’a pas été rejeté, mais ajourné, compte tenu de l’attente d’une décision connexe la concernant. » Connexe ? Quoi, où, comment ?
Par ailleurs, si l’on considère l’urgence de la situation, et le fait que les travaux de la commission ne durent que quelques jours, un « ajournement » sine die ressemble bigrement à un renvoi à la saint-glinglin, donc à un rejet. Mais la dir’com’ n’en dira pas plus.
Aujourd’hui, on est à deux jours de la trêve hivernale, et bien qu’une expulsion de dernière minute paraisse peu vraisemblable, Harsinoee est en panique. Le sale coup qu’on lui a fait à la préfecture l’incline à penser que celle-ci est capable de tout. Après toutes ces années où la CAF, l’OPHLM et la préf’ se sont acharnées sur elle et sa famille, la voici condamnée encore à passer les heures qui viennent dans l’angoisse de voir débouler l’huissier et le shériff. Elle a beau être d'un courage exceptionnel, c'est lourd.
Quant à la vidéosurveillance comme instrument de refus d’accès aux droits... qui sait si on aura un jour le fin mot de l’histoire. S’agit-il d’une simple bavure d’agent zélé, ou d’une expérimentation préparant une énième extension de leur politique de flicage tous azimuts ? Dans une start-up nation séduite par la reconnaissance faciale et le garrottage des «gens qui ne sont rien», on ne sait jamais. »
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