Dans la foulée, on peut supprimer l'encodage base64 vu que le stockage des images utilisera des tags <img src=url/> plutôt que des base64
LX2ZVNAYX2FRCEIJ6XBCBILB3O7YT52AP56QDWCCGLATFCEB7KHQC 632SZPUQC6KX3CDZLYWV22OSFIOG66CJ7PONRNTXYTFLQX3JFFXQC 5FNNIOUNDS5SG75A4ZR6VY7DS6WU2GNNCOSSHX34RFTRB7LJ3D2QC PI6D6Y5EHSXHSILBYHKRKXWXZ6H6JOR5ZTP44CXBW4LUUIREY7OQC RLLNOBJM5LB446HWBUNDLNMG35PTUFRBRRVNHMFTX7CMQC4JSXUQC 7MCTB5G2W6IB7JQXGO2HCMRHBUYIOKXI4MBODKLAJIK66EMLC5ZQC P7KZ25R4CNS4PZITRWPBVXRFSLY5TKCOFO6U3SDKX45ITNVU773QC C56DYYC72SFNR6BSKCOVDY2QW6XNP66EUGGKCBROTCFJVQDB4FUAC QHVOZBISIQ3E3P5F6GGKWVDSXC4OA23HCIH2OMXEVGXKSF5W4APAC 3ZF3ND2IS3EKQ5LPGCAN5P3N7X4W5NFIEM3KLO4RISONNSLILT4QC XTPX4PYLPGJAEK52LYOYHLVRCL7N5FFAEY4E3OL23LOWLYPLCILQC KNH5OGCTL3YCOQQPA32M76SGWHGHAPQRIZ7S2CBC5DGIEV32SOYQC YLOKW6ERT2XEQG4T6GBPSBCQWVIHWAKBESCXJBKMQBSDXV3C2ACQC UR5RFMWCD455OQZMTDQ2MSVJUPBNEUQHOBJ2UJBDWVHRJ4SOA5NAC const base64abc = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M","N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z","a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m","n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z","0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "-", "_"];const base64codes = [255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, 62, 255, 63,52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 0, 255, 255,255, 0, 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, 255, 255, 255, 255, 63,255, 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];function getBase64Code(charCode: number): number {if (charCode >= base64codes.length) {throw new Error("Unable to parse base64 string.");}const code = base64codes[charCode];if (code === 255) {throw new Error("Unable to parse base64 string.");}return code;}export function bytesToBase64(bytes: Uint8Array): string {let result = '', i, l = bytes.length;for (i = 2; i < l; i += 3) {result += base64abc[bytes[i - 2] >> 2];result += base64abc[((bytes[i - 2] & 0x03) << 4) | (bytes[i - 1] >> 4)];result += base64abc[((bytes[i - 1] & 0x0F) << 2) | (bytes[i] >> 6)];result += base64abc[bytes[i] & 0x3F];}if (i === l + 1) { // 1 octet yet to writeresult += base64abc[bytes[i - 2] >> 2];result += base64abc[(bytes[i - 2] & 0x03) << 4];result += "==";}if (i === l) { // 2 octets yet to writeresult += base64abc[bytes[i - 2] >> 2];result += base64abc[((bytes[i - 2] & 0x03) << 4) | (bytes[i - 1] >> 4)];result += base64abc[(bytes[i - 1] & 0x0F) << 2];result += "=";}return result;}export function base64ToBytes(str: string): Uint8Array {if (str.length % 4 !== 0) {throw new Error("Unable to parse base64 string.");}const index = str.indexOf("=");if (index !== -1 && index < str.length - 2) {throw new Error("Unable to parse base64 string.");}let missingOctets = str.endsWith("==") ? 2 : str.endsWith("=") ? 1 : 0,n = str.length,result = new Uint8Array(3 * (n / 4)),buffer;for (let i = 0, j = 0; i < n; i += 4, j += 3) {buffer =getBase64Code(str.charCodeAt(i)) << 18 |getBase64Code(str.charCodeAt(i + 1)) << 12 |getBase64Code(str.charCodeAt(i + 2)) << 6 |getBase64Code(str.charCodeAt(i + 3));result[j] = buffer >> 16;result[j + 1] = (buffer >> 8) & 0xFF;result[j + 2] = buffer & 0xFF;}return result.subarray(0, result.length - missingOctets);}export function base64encode(str: Uint8Array): string {return bytesToBase64(str);}export function base64decode(str: string, decoder = new TextDecoder()): Uint8Array {return base64ToBytes(str)}
let resp = await fetch(`https://${srv}/api/grain`,{ method: "POST",body: f})
const srv = import.meta.env.MODE == 'production' ? 'https://x.coturnix.fr' : 'http://localhost:5173'const resp = await fetch(`${srv}/api/grain/prms`, {method: "POST",body: JSON.stringify(prms)})
}let t = min_t;for(let semaine of r) {let b = new DataView(base64decode(semaine).buffer)let length = b.getUint32(0, true)for(let i = 8; i < 8 + 8 * length; i+= 8) {const ti = b.getUint32(i, true)const vi = b.getUint32(i+4, true)for(let tt = t + 1800; tt < ti; tt += 1800) {d.t.push(tt)d.y.push(0)}t = tid.t.push(ti)d.y.push(vi / 1000)}
<table class="table"><thead><tr><th></th><th>Profil</th><th>Consommation annuelle</th></tr></thead><tbody>{#each pr as pr, i}<tr><td class="px-3">Profil</td><td><select class="form-select" bind:value={pr.type} on:change={(_ev) => updatePlot(puissance)}>{#each Object.entries(profils) as [p, _]}<option value={p}>{p}</option>{/each}</select></td><td><input type="number" class="form-control" placeholder="Consommation Annuelle (kWh)" min="0" step="500" bind:value={pr.conso} on:change={(_ev) => updatePlot(puissance)}/></td><td style="width:1%;white-space:nowrap;text-align:center"><button class="btn btn-link" on:click={(_ev) => delProfil(i)}><i class="bi bi-x-circle text-primary"/></button></td></tr>{/each}</table>
<table class="table"><thead><tr><th></th><th>Profil</th><th>Consommation annuelle</th><th></th></tr></thead><tbody>{#each pr as pr, i}<tr><td class="px-3 align-middle">Profil</td><td><select class="form-select" bind:value={pr.type} on:change={(_ev) => updatePlot(puissance)}>{#each Object.entries(profils) as [p, _]}<option value={p}>{p}</option>{/each}</select></td><td><input type="number" class="form-control" placeholder="Consommation Annuelle (kWh)" min="0" step="500" bind:value={pr.conso} on:change={(_ev) => updatePlot(puissance)}/></td><td style="width:1%;white-space:nowrap;text-align:center"><button class="btn btn-link" on:click={(_ev) => delProfil(i)}><i class="bi bi-x-circle text-primary"/></button></td></tr>{/each}</tbody></table>
<div class="row"><div class="col px-3" style="width: 25%">Liste de PRM, séparés par des virgules<button type="button" class="btn btn-link align-baseline p-0 ms-2" data-bs-toggle="popover" data-bs-trigger="hover focus" data-bs-content="Un PRM, aussi appelé PDL, est l'identifiant d'un compteur électrique. On peut le trouver sur les factures d'électricité, ou en appuyant sur le bouton + du compteur Linky."><i class="bi bi-question-circle"></i></button></div><div class="col-auto my-3"><input class="form-control" form="pdl" id="prms" name="prms" bind:value={prms}/>
<h2 class="my-5">Relevés de compteurs</h2>{#if prms.length}<table class="table"><thead><tr><th>PRM<button type="button" class="btn btn-link align-baseline p-0 ms-2" data-bs-toggle="popover" data-bs-trigger="hover focus" data-bs-content="Un PRM, aussi appelé PDL, est l'identifiant d'un compteur électrique. On peut le trouver sur les factures d'électricité, ou en appuyant sur le bouton + du compteur Linky."><i class="bi bi-question-circle"></i></button></th><th>Prénom</th><th>Nom</th><th></th></tr></thead><tbody>{#each prms as prm, i}<tr><td><input class="form-control" bind:value={prm.prm} type="number" /></td><td><input class="form-control" bind:value={prm.nom}/></td><td><input class="form-control" bind:value={prm.prenom}/></td><td style="width:1%;white-space:nowrap;text-align:center"><button class="btn btn-link" on:click={(ev) => delPrm(ev, i)}><i class="bi bi-x-circle text-primary"/></button></td></tr>{/each}</tbody></table><div class="my-3 form-check"><input class="form-check-input" type="checkbox" id="consentement" bind:checked={consentement}><label class="form-check-label" for="consentement">Ces abonnés consentent à ce que j'accède à leurs données</label>
<div class="col d-flex align-items-center"><button class="btn btn-primary" form="pdl">Ok</button>{#if prm_loading}<div class="spinner-border text-primary ms-3"></div>
{/if}<div class="d-flex justify-content-center"><button class="mx-2 btn btn-primary" on:click={addPrm}><i class="bi bi-plus-circle"/> Ajouter un compteur</button>{#if prms.length}<button disabled={!consentement} class="mx-2 btn btn-primary" form="pdl">Mettre à jour</button><div class="mx-2 spinner-border text-primary" class:d-none={!prm_loading}></div>
<div class="my-5 text-center"><button class="btn btn-primary" on:click={addProfil}><i class="bi bi-plus-circle"/> Ajouter un profil</button></div>
<h2 class="mt-5">Simulation</h2>
import type { Grain } from '../../../helpers'import type { Modal, Offcanvas } from 'bootstrap'import { email } from '../../../stores'
import type { Grain } from '../../../helpers'import * as H from '../../../helpers'import type { Modal, Offcanvas } from 'bootstrap'import { email } from '../../../stores'
export let data: {name: string,porteur: string,adresse: string,tel: string,id: string,img?: string,simulation: Grain.SimulationCommunaute,guest?: boolean,prms: string,email?: string,}
type Prm = { prm: number | null, nom: string, prenom: string }export let data: {nom: string,porteur: string,adresse: string,tel: string,id: string,img?: string,simulation: Grain.SimulationCommunaute,guest?: boolean,prms: Prm[],email?: string,}
$: primeInvestissement =(p.puissance <= 36) ? (0.21 * 1000 * p.puissance) :(p.puissance <= 100) ? (0.11 * 1000 * p.puissance) :0
$: primeInvestissement =(p.puissance <= 36) ? (0.21 * 1000 * p.puissance) :(p.puissance <= 100) ? (0.11 * 1000 * p.puissance) :0
$: tarifLocal = (i: number) => p.prix * Math.pow(1+p.inflation/100, i)$: tarifAllo = (i: number) => p.coutElec * Math.pow(1+p.inflationElec/100, i)
$: tarifLocal = (i: number) => H.tarifLocal(p, i)$: tarifAllo = (i: number) => p.coutElec * Math.pow(1+p.inflationElec/100, i)
<Simulation prmsFeature={prmsFeature} active={simuActive} bind:prms={data.prms} puissance={p.puissance} bind:prodWeekly={prodWeekly} bind:maxProd={maxProd} bind:pvgis_loading={pvgis_loading} />
<Simulation prmsFeature={prmsFeature} bind:prms={data.prms} puissance={p.puissance} bind:prodWeekly={prodWeekly} bind:maxProd={maxProd} bind:pvgis_loading={pvgis_loading} />
import { error, redirect } from '@sveltejs/kit';import type { PageServerLoad, Actions, RouteParams } from './$types';import { userForm, SimulationCommunaute, Grain, save, del } from '../../../helpers';import { base } from '$app/paths'import { base64encode } from '../../../base64';
import { error } from '@sveltejs/kit';import type { PageServerLoad, Actions } from './$types';import { userForm, Grain, save, del } from '../../../helpers';
<div class="pb-3 mb-3 border-bottom border-4 border-primary fs-1 fw-bold bg-cc fs-1 fw-bold">+ {donnees.economies} k€</div>
<div class="pb-3 mb-3 border-bottom border-4 border-primary fs-1 fw-bold bg-cc fs-1 fw-bold">+{Math.round(donnees.economies / 1000)}k€</div>
await userForm(platform.env, id_, {DelProjet: {id: params['id'],}})throw redirect(302, `${base}`)
if(params.id) {await userForm(platform.env, id_, {DelProjet: {id: params['id'],}})throw redirect(302, `${base}`)}}export function coutElec(p: Grain.SimulationCommunaute, N: number) {let cout = 0for (let i = 0; i < N; i++) {cout += p.coutElec * Math.pow(1 + p.inflationElec / 100, i) * consoMoyenneFoyer(p, i)}return cout}export function coutElecAuto(p: Grain.SimulationCommunaute, N: number) {let cout = 0for (let i = 0; i < N; i++) {cout += tarifLocal(p, i) * consoMoyenneFoyer(p, i) * p.autoprod / 100+ p.coutElec * Math.pow(1 + p.inflationElec / 100, i) * consoMoyenneFoyer(p, i) * (100 - p.autoprod) / 100}return cout}export function tarifLocal(p: Grain.SimulationCommunaute, i: number) {return p.prix * Math.pow(1+p.inflation/100, i)}export function productionAnnuelle(p: Grain.SimulationCommunaute, i: number){return p.productible * p.puissance * Math.pow(1-(p.degradation)/100, i)
export function consoMoyenneFoyer(p: Grain.SimulationCommunaute, i: number) {return Math.min(p.consoMoyenneFoyer, productionAnnuelle(p, i)/p.autoprod)}