\n",[530,2139,2140,2145,2150,2155,2160,2165,2170,2175,2180,2186,2191,2197,2203,2209],{"__ignoreMap":369},[1761,2141,2142],{"class":1763,"line":1764},[1761,2143,2144],{},"\n",[129,2216,2217,2218,2227],{},"The SDK then mounts a ",[84,2219,2220,2221,2226],{},"minimal ",[80,2222,2225],{"href":2223,"rel":2224},"https://vuejs.org",[213],"Vue 3"," app (≈40KB)"," to manage all iframe logic and styling reactively. This approach ensures:",[74,2229,2230,2233,2236],{},[77,2231,2232],{},"Zero CSS/JS conflicts, full isolation via iframe.",[77,2234,2235],{},"Maximum compatibility, z-index and sizing are dynamically computed, keeping the widget always visible and unobtrusive.",[77,2237,2238],{},"No performance penalty, the widget loads only after the host page is fully interactive.",[249,2240,2242,2247],{"id":2241},"postmessage-communication-protocol",[80,2243,2246],{"href":2244,"rel":2245},"https://developer.mozilla.org/fr/docs/Web/API/Window/postMessage",[213],"PostMessage"," communication protocol",[129,2249,2250],{},[84,2251,1752],{},[1197,2253,2255],{"className":1755,"code":2254,"language":1757,"meta":369,"style":369},"// Widget to parent communication\nwindow.parent.postMessage({ \n type: \"widget\", \n action: \"is_left\", \n value: true/false \n}, \"*\");\n\n// Parent response handler\nwindow.addEventListener(\"message\", (event) => {\n if (event.data.type === \"widget\") {\n updateWidgetState(event.data.action, event.data.value);\n }\n});\n",[530,2256,2257,2262,2267,2272,2277,2282,2287,2291,2296,2301,2306,2311,2316],{"__ignoreMap":369},[1761,2258,2259],{"class":1763,"line":1764},[1761,2260,2261],{},"// Widget to parent communication\n",[1761,2263,2264],{"class":1763,"line":370},[1761,2265,2266],{},"window.parent.postMessage({ \n",[1761,2268,2269],{"class":1763,"line":380},[1761,2270,2271],{}," type: \"widget\", \n",[1761,2273,2274],{"class":1763,"line":1780},[1761,2275,2276],{}," action: \"is_left\", \n",[1761,2278,2279],{"class":1763,"line":1589},[1761,2280,2281],{}," value: true/false \n",[1761,2283,2284],{"class":1763,"line":1791},[1761,2285,2286],{},"}, \"*\");\n",[1761,2288,2289],{"class":1763,"line":1797},[1761,2290,1783],{"emptyLinePlaceholder":55},[1761,2292,2293],{"class":1763,"line":941},[1761,2294,2295],{},"// Parent response handler\n",[1761,2297,2298],{"class":1763,"line":2182},[1761,2299,2300],{},"window.addEventListener(\"message\", (event) => {\n",[1761,2302,2303],{"class":1763,"line":394},[1761,2304,2305],{}," if (event.data.type === \"widget\") {\n",[1761,2307,2308],{"class":1763,"line":2193},[1761,2309,2310],{}," updateWidgetState(event.data.action, event.data.value);\n",[1761,2312,2313],{"class":1763,"line":2199},[1761,2314,2315],{}," }\n",[1761,2317,2318],{"class":1763,"line":2205},[1761,2319,2320],{},"});\n",[129,2322,2323],{},"This protocol allows the widget to:",[74,2325,2326,2332,2338,2344],{},[77,2327,2328,2331],{},[84,2329,2330],{},"Receive dynamic state updates"," from the host page",[77,2333,2334,2337],{},[84,2335,2336],{},"Send interaction events"," back to the host",[77,2339,2340,2343],{},[84,2341,2342],{},"Maintain responsive UI"," without blocking the main thread",[77,2345,2346,2349],{},[84,2347,2348],{},"Ensure secure communication"," by validating message origins",[478,2351],{},[69,2353,2355],{"id":2354},"conclusion-performance-driven-client-success","Conclusion: performance-driven client success",[129,2357,2358],{},"Building Vendeo's video popup product meant fighting real-world browser quirks, pushing the boundaries of what’s possible with WebAssembly and JavaScript, and always keeping the client experience front and center.",[129,2360,2361],{},[84,2362,2363],{},"Key Takeaways:",[74,2365,2366,2372,2382,2395],{},[77,2367,2368,2371],{},[84,2369,2370],{},"WebAssembly unlocks real browser power:"," Video transcoding in the client browser isn’t just \"possible\", it’s fast, reliable, and reduces backend costs to zero.",[77,2373,2374,2377,2378,2381],{},[84,2375,2376],{},"Late-loading and isolation are non-negotiable for 3rd-party widgets:"," By injecting the SDK after DOMContentLoaded, then running Vue 3 inside an isolated iframe with the maximum safe ",[530,2379,2380],{},"z-index: 2147483647",", I ensured universal compatibility and zero conflicts, tested on Chrome, Safari, Firefox, and Edge.",[77,2383,2384,2387,2388,221,2391,2394],{},[84,2385,2386],{},"Performance trade-offs are about context:"," For popup video, users want ",[149,2389,2390],{},"speed",[149,2392,2393],{},"reliability"," more than pixel-perfect quality. Bandwidth savings and instant load matter far more than 4K resolution.",[77,2396,2397,2400],{},[84,2398,2399],{},"Obsessive integration simplicity = higher adoption:"," By boiling integration down to a single script, I eliminated barriers for both technical and non-technical users.",[249,2402,2404],{"id":2403},"personal-note","Personal note:",[129,2406,2407,2408,2413,2414,2419],{},"There were moments of frustration, like wrestling with browser memory limits and edge-case CORS bugs, but each challenge made the final product more robust. If you’re facing similar problems, know that the browser platform is far more capable than many engineers think. For example, ",[80,2409,2412],{"href":2410,"rel":2411},"https://supabase.com",[213],"Supabase","'s team has released a ",[80,2415,2418],{"href":2416,"rel":2417},"https://wasm.supabase.com/",[213],"PostgreSQL in the browser"," that runs entirely in WebAssembly, proving that the limits of what’s possible are constantly being pushed.",[478,2421],{},[129,2423,2424],{},[149,2425,2426,2427,2430,2431,2434],{},"Want to discuss similar technical challenges or performance optimization strategies? Connect with me on ",[80,2428,1305],{"href":211,"rel":2429},[213]," or check out the ",[80,2432,1608],{"href":1606,"rel":2433},[213]," implementation.",[2436,2437,2438],"style",{},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}",{"title":369,"searchDepth":370,"depth":370,"links":2440},[2441,2442,2446,2451,2456],{"id":1338,"depth":370,"text":1600},{"id":1653,"depth":370,"text":1654,"children":2443},[2444,2445],{"id":1657,"depth":380,"text":1658},{"id":1687,"depth":380,"text":1688},{"id":1725,"depth":370,"text":1726,"children":2447},[2448,2449,2450],{"id":1729,"depth":380,"text":1730},{"id":1803,"depth":380,"text":1804},{"id":1995,"depth":380,"text":1996},{"id":2063,"depth":370,"text":2064,"children":2452},[2453,2454],{"id":2067,"depth":380,"text":2068},{"id":2241,"depth":380,"text":2455},"PostMessage communication protocol",{"id":2354,"depth":370,"text":2355,"children":2457},[2458],{"id":2403,"depth":380,"text":2404},"2025-06-09","A deep dive into the technical challenges of building an injected video popup SDK, achieving 10:1 compression ratios with WebAssembly and solving cross-domain communication with performance for optimal client satisfaction.","/06-09-2025.png",{},{"title":24,"description":2460},"TB8fguvZzOM0-ND2yzIZe90RxU5fqsYn4bwnrQLuadg",{"id":2466,"title":36,"author":2467,"body":2469,"date":3613,"description":3614,"extension":391,"image":3615,"meta":3616,"minRead":394,"navigation":55,"path":37,"seo":3617,"stem":38,"__hash__":3618},"blog/blog/how-you-can-earn-money-thanks-to-open-source.md",{"name":62,"avatar":2468},{"src":64,"alt":62},{"type":66,"value":2470,"toc":3588},[2471,2475,2481,2491,2493,2497,2501,2510,2514,2528,2532,2535,2539,2542,2565,2568,2570,2574,2577,2586,2589,2605,2607,2615,2624,2645,2649,2672,2676,2688,2701,2714,2718,2721,3116,3122,3146,3149,3173,3190,3199,3208,3211,3215,3221,3224,3255,3258,3261,3292,3296,3345,3349,3366,3370,3444,3446,3450,3453,3491,3496,3498,3502,3505,3519,3522,3524,3528,3551,3553,3557,3564,3567,3571,3574,3576,3585],[69,2472,2474],{"id":2473},"introduction","Introduction",[129,2476,2477,2478,309],{},"I've always loved the world of open source, collaborating with other developers, diving into real-world problems, and contributing to projects that matter. But here's something many people don't realize: ",[84,2479,2480],{},"you can actually earn money by contributing to open source",[129,2482,2483,2484,2490],{},"In this post, I'll walk you through the different ways open source can reward you financially, share my own experience contributing to a few projects, and give you a behind-the-scenes look at my most ",[84,2485,2486],{},[80,2487,2489],{"href":2488},"/blog/how-you-can-earn-money-thanks-to-open-source#case-study-fixing-oramas-exact-true-bug-150-bounty","recent contribution that could help me earned a $150 bounty",". If you've ever thought \"I'd love to contribute, but I need to focus on paid work,\" this might change your mind.",[478,2492],{},[69,2494,2496],{"id":2495},"the-many-ways-open-source-pays","The many ways open source pays",[249,2498,2500],{"id":2499},"bounties-on-issues","Bounties on Issues",[129,2502,2503,2504,2509],{},"Platforms like ",[80,2505,2508],{"href":2506,"rel":2507},"https://algora.io",[213],"Algora"," let open source maintainers post cash rewards for solving specific problems. You can browse issues, filter by tech stack or payout amount, and claim a task to work on. It's freelancing, but with full transparency and community impact.",[249,2511,2513],{"id":2512},"sponsorships","Sponsorships",[129,2515,2516,2517,728,2522,2527],{},"Once you gain traction, you can receive direct support through ",[80,2518,2521],{"href":2519,"rel":2520},"https://github.com/sponsors",[213],"GitHub Sponsors",[80,2523,2526],{"href":2524,"rel":2525},"https://opencollective.com",[213],"OpenCollective",", or even individual backers who appreciate your work. Maintainers with strong reputations often generate recurring income just from keeping their projects alive and improving.",[249,2529,2531],{"id":2530},"freelance-work-job-offers","Freelance work & job offers",[129,2533,2534],{},"Your public contributions act like a living résumé. You can leverage your experience through PRs and reach out for freelance projects that matched the exact tech you used in OSS. It eventually become the best inbound marketing you can do as a developer.",[249,2536,2538],{"id":2537},"monetizing-your-own-oss","Monetizing your own OSS",[129,2540,2541],{},"If you're building something from scratch, you can still keep it open source and monetize via:",[74,2543,2544,2550,2555,2560],{},[77,2545,2546,2549],{},[84,2547,2548],{},"Open core"," (core is free, advanced features are paid)",[77,2551,2552],{},[84,2553,2554],{},"Dual licensing",[77,2556,2557],{},[84,2558,2559],{},"Paid cloud hosting",[77,2561,2562],{},[84,2563,2564],{},"Extensions/add-ons marketplaces",[129,2566,2567],{},"It's been a long time since I started to build a big OSS project, even if I know a startup is a full-time job, I still think that the best way to learn is to build something. And if you can make money while doing it, even better.",[478,2569],{},[69,2571,2573],{"id":2572},"my-oss-track-record","My OSS track record",[129,2575,2576],{},"Over the years, I've contributed to a growing list of open source projects. From documentation improvements to bug fixes and feature additions, I've learned a ton and built track record I'm proud of.",[129,2578,2579],{},[84,2580,2581,2582],{},"You can see a full history of my contributions ",[80,2583,286],{"href":2584,"rel":2585},"https://prs.valentinchmara.com",[213],[129,2587,2588],{},"Projects include:",[74,2590,2591,2599,2602],{},[77,2592,2593,2594],{},"Company like ",[80,2595,2598],{"href":2596,"rel":2597},"https://cal.com",[213],"Cal.com",[77,2600,2601],{},"TypeScript packages",[77,2603,2604],{},"Front-end frameworks",[478,2606],{},[69,2608,2610,2611,2614],{"id":2609},"case-study-fixing-oramas-exact-true-bug-150-bounty","Case Study – Fixing Orama's ",[530,2612,2613],{},"exact: true"," Bug (💵 $150 bounty)",[129,2616,2617,2618,2623],{},"One of my most recent contributions involved a bounty posted on ",[80,2619,2622],{"href":2620,"rel":2621},"https://github.com/oramasearch/orama",[213],"Orama",", a blazing fast full-text search engine in TypeScript.",[129,2625,2626,2627,2629,2630,2635,2637,2638,2629,2640],{},"The issue:",[910,2628],{},"\n👉 ",[80,2631,2634],{"href":2632,"rel":2633},"https://github.com/oramasearch/orama/issues/866",[213],"Exact match not working as expected",[910,2636],{},"\nThe fix:",[910,2639],{},[80,2641,2644],{"href":2642,"rel":2643},"https://github.com/oramasearch/orama/pull/941",[213],"My pull request",[249,2646,2648],{"id":2647},"why-i-picked-this-issue","Why I picked this issue",[74,2650,2651,2656,2659,2662,2665],{},[77,2652,2653,2654,434],{},"The scope was clearly defined and focused on a single behavior (",[530,2655,2613],{},[77,2657,2658],{},"The reward was fair given the expected effort.",[77,2660,2661],{},"The tech stack (TypeScript, radix trees, tokenizer logic) matched my interests and strengths.",[77,2663,2664],{},"I was curious to understand how exact string matching works under the hood in a full-text search engine.",[77,2666,2667,2668,2671],{},"Interestingly, several people had previously dismissed the issue as \"not a bug\", which made it more appealing. I saw it as a chance to approach the problem with a ",[84,2669,2670],{},"business-first mindset"," rather than a strictly technical one.",[249,2673,2675],{"id":2674},"reproducing-the-bug","Reproducing the bug",[129,2677,2678,2679,2684,2685,2687],{},"The issue reporter included a ",[80,2680,2683],{"href":2681,"rel":2682},"https://codesandbox.io/p/sandbox/lvy7mc",[213],"minimal reproduction on CodeSandbox",", which made the debugging process incredibly smooth. I was able to see the unexpected behavior immediately: enabling ",[530,2686,2613],{}," was returning one result when it shouldn't have returned one.",[129,2689,2690,2691,2694,2695,2700],{},"After verifying the issue, I cloned the Orama repository locally. Following the README and contributing guidelines, I set up the monorepo and explored the structure. At the root, I checked the ",[530,2692,2693],{},"package.json"," and noticed the project uses ",[80,2696,2699],{"href":2697,"rel":2698},"https://turborepo.com/",[213],"Turborepo"," for managing multiple packages, very clean and well-structured.",[129,2702,2703,2704,2707,2708,2713],{},"I then focused on understanding how the search engine processes queries in ",[530,2705,2706],{},"exact"," mode. I read the documentation, particularly ",[80,2709,2712],{"href":2710,"rel":2711},"https://docs.orama.com/open-source/usage/search/introduction#exact-match",[213],"this section on exact match",", to make sure my expectations were aligned with intended behavior.",[249,2715,2717],{"id":2716},"understand-whats-going-on","Understand what's going on",[129,2719,2720],{},"Below is the reproduction code that was provided in the issue:",[1197,2722,2726],{"className":2723,"code":2724,"language":2725,"meta":369,"style":369},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","const db = create({\n schema: {\n path: \"string\",\n title: \"string\",\n },\n});\n\ninsert(db, { path: \"First Note.md\", title: \"First Note\" });\ninsert(db, { path: \"Second Note.md\", title: \"Second Note\" });\n\nconst noExact = search(db, {\n term: \"first\",\n properties: [\"path\"],\n}); \nconst withExact = search(db, {\n term: \"first\",\n properties: [\"path\"],\n exact: true,\n}); \n\nconsole.log(\"noExact path\", noExact); // 1 result returned, 1 expected => GOOD\nconsole.log(\"withExact path\", withExact); // 1 result returned, but none was expected => BAD\n","ts",[530,2727,2728,2751,2763,2782,2797,2802,2812,2816,2863,2903,2907,2925,2941,2963,2975,2993,3008,3027,3041,3052,3057,3088],{"__ignoreMap":369},[1761,2729,2730,2734,2737,2741,2745,2748],{"class":1763,"line":1764},[1761,2731,2733],{"class":2732},"spNyl","const",[1761,2735,2736],{"class":1855}," db ",[1761,2738,2740],{"class":2739},"sMK4o","=",[1761,2742,2744],{"class":2743},"s2Zo4"," create",[1761,2746,2747],{"class":1855},"(",[1761,2749,2750],{"class":2739},"{\n",[1761,2752,2753,2757,2760],{"class":1763,"line":370},[1761,2754,2756],{"class":2755},"swJcz"," schema",[1761,2758,2759],{"class":2739},":",[1761,2761,2762],{"class":2739}," {\n",[1761,2764,2765,2768,2770,2773,2776,2779],{"class":1763,"line":380},[1761,2766,2767],{"class":2755}," path",[1761,2769,2759],{"class":2739},[1761,2771,2772],{"class":2739}," \"",[1761,2774,2775],{"class":1823},"string",[1761,2777,2778],{"class":2739},"\"",[1761,2780,2781],{"class":2739},",\n",[1761,2783,2784,2787,2789,2791,2793,2795],{"class":1763,"line":1780},[1761,2785,2786],{"class":2755}," title",[1761,2788,2759],{"class":2739},[1761,2790,2772],{"class":2739},[1761,2792,2775],{"class":1823},[1761,2794,2778],{"class":2739},[1761,2796,2781],{"class":2739},[1761,2798,2799],{"class":1763,"line":1589},[1761,2800,2801],{"class":2739}," },\n",[1761,2803,2804,2807,2809],{"class":1763,"line":1791},[1761,2805,2806],{"class":2739},"}",[1761,2808,287],{"class":1855},[1761,2810,2811],{"class":2739},";\n",[1761,2813,2814],{"class":1763,"line":1797},[1761,2815,1783],{"emptyLinePlaceholder":55},[1761,2817,2818,2821,2824,2827,2830,2833,2835,2837,2840,2842,2844,2847,2849,2851,2854,2856,2859,2861],{"class":1763,"line":941},[1761,2819,2820],{"class":2743},"insert",[1761,2822,2823],{"class":1855},"(db",[1761,2825,2826],{"class":2739},",",[1761,2828,2829],{"class":2739}," {",[1761,2831,2832],{"class":2755}," path",[1761,2834,2759],{"class":2739},[1761,2836,2772],{"class":2739},[1761,2838,2839],{"class":1823},"First Note.md",[1761,2841,2778],{"class":2739},[1761,2843,2826],{"class":2739},[1761,2845,2846],{"class":2755}," title",[1761,2848,2759],{"class":2739},[1761,2850,2772],{"class":2739},[1761,2852,2853],{"class":1823},"First Note",[1761,2855,2778],{"class":2739},[1761,2857,2858],{"class":2739}," }",[1761,2860,287],{"class":1855},[1761,2862,2811],{"class":2739},[1761,2864,2865,2867,2869,2871,2873,2875,2877,2879,2882,2884,2886,2888,2890,2892,2895,2897,2899,2901],{"class":1763,"line":2182},[1761,2866,2820],{"class":2743},[1761,2868,2823],{"class":1855},[1761,2870,2826],{"class":2739},[1761,2872,2829],{"class":2739},[1761,2874,2832],{"class":2755},[1761,2876,2759],{"class":2739},[1761,2878,2772],{"class":2739},[1761,2880,2881],{"class":1823},"Second Note.md",[1761,2883,2778],{"class":2739},[1761,2885,2826],{"class":2739},[1761,2887,2846],{"class":2755},[1761,2889,2759],{"class":2739},[1761,2891,2772],{"class":2739},[1761,2893,2894],{"class":1823},"Second Note",[1761,2896,2778],{"class":2739},[1761,2898,2858],{"class":2739},[1761,2900,287],{"class":1855},[1761,2902,2811],{"class":2739},[1761,2904,2905],{"class":1763,"line":394},[1761,2906,1783],{"emptyLinePlaceholder":55},[1761,2908,2909,2911,2914,2916,2919,2921,2923],{"class":1763,"line":2193},[1761,2910,2733],{"class":2732},[1761,2912,2913],{"class":1855}," noExact ",[1761,2915,2740],{"class":2739},[1761,2917,2918],{"class":2743}," search",[1761,2920,2823],{"class":1855},[1761,2922,2826],{"class":2739},[1761,2924,2762],{"class":2739},[1761,2926,2927,2930,2932,2934,2937,2939],{"class":1763,"line":2199},[1761,2928,2929],{"class":2755}," term",[1761,2931,2759],{"class":2739},[1761,2933,2772],{"class":2739},[1761,2935,2936],{"class":1823},"first",[1761,2938,2778],{"class":2739},[1761,2940,2781],{"class":2739},[1761,2942,2943,2946,2948,2951,2953,2956,2958,2961],{"class":1763,"line":2205},[1761,2944,2945],{"class":2755}," properties",[1761,2947,2759],{"class":2739},[1761,2949,2950],{"class":1855}," [",[1761,2952,2778],{"class":2739},[1761,2954,2955],{"class":1823},"path",[1761,2957,2778],{"class":2739},[1761,2959,2960],{"class":1855},"]",[1761,2962,2781],{"class":2739},[1761,2964,2965,2967,2969,2972],{"class":1763,"line":2211},[1761,2966,2806],{"class":2739},[1761,2968,287],{"class":1855},[1761,2970,2971],{"class":2739},";",[1761,2973,2974],{"class":1855}," \n",[1761,2976,2978,2980,2983,2985,2987,2989,2991],{"class":1763,"line":2977},15,[1761,2979,2733],{"class":2732},[1761,2981,2982],{"class":1855}," withExact ",[1761,2984,2740],{"class":2739},[1761,2986,2918],{"class":2743},[1761,2988,2823],{"class":1855},[1761,2990,2826],{"class":2739},[1761,2992,2762],{"class":2739},[1761,2994,2996,2998,3000,3002,3004,3006],{"class":1763,"line":2995},16,[1761,2997,2929],{"class":2755},[1761,2999,2759],{"class":2739},[1761,3001,2772],{"class":2739},[1761,3003,2936],{"class":1823},[1761,3005,2778],{"class":2739},[1761,3007,2781],{"class":2739},[1761,3009,3011,3013,3015,3017,3019,3021,3023,3025],{"class":1763,"line":3010},17,[1761,3012,2945],{"class":2755},[1761,3014,2759],{"class":2739},[1761,3016,2950],{"class":1855},[1761,3018,2778],{"class":2739},[1761,3020,2955],{"class":1823},[1761,3022,2778],{"class":2739},[1761,3024,2960],{"class":1855},[1761,3026,2781],{"class":2739},[1761,3028,3030,3033,3035,3039],{"class":1763,"line":3029},18,[1761,3031,3032],{"class":2755}," exact",[1761,3034,2759],{"class":2739},[1761,3036,3038],{"class":3037},"sfNiH"," true",[1761,3040,2781],{"class":2739},[1761,3042,3044,3046,3048,3050],{"class":1763,"line":3043},19,[1761,3045,2806],{"class":2739},[1761,3047,287],{"class":1855},[1761,3049,2971],{"class":2739},[1761,3051,2974],{"class":1855},[1761,3053,3055],{"class":1763,"line":3054},20,[1761,3056,1783],{"emptyLinePlaceholder":55},[1761,3058,3060,3063,3065,3068,3070,3072,3075,3077,3079,3082,3084],{"class":1763,"line":3059},21,[1761,3061,3062],{"class":1855},"console",[1761,3064,309],{"class":2739},[1761,3066,3067],{"class":2743},"log",[1761,3069,2747],{"class":1855},[1761,3071,2778],{"class":2739},[1761,3073,3074],{"class":1823},"noExact path",[1761,3076,2778],{"class":2739},[1761,3078,2826],{"class":2739},[1761,3080,3081],{"class":1855}," noExact)",[1761,3083,2971],{"class":2739},[1761,3085,3087],{"class":3086},"sHwdD"," // 1 result returned, 1 expected => GOOD\n",[1761,3089,3091,3093,3095,3097,3099,3101,3104,3106,3108,3111,3113],{"class":1763,"line":3090},22,[1761,3092,3062],{"class":1855},[1761,3094,309],{"class":2739},[1761,3096,3067],{"class":2743},[1761,3098,2747],{"class":1855},[1761,3100,2778],{"class":2739},[1761,3102,3103],{"class":1823},"withExact path",[1761,3105,2778],{"class":2739},[1761,3107,2826],{"class":2739},[1761,3109,3110],{"class":1855}," withExact)",[1761,3112,2971],{"class":2739},[1761,3114,3115],{"class":3086}," // 1 result returned, but none was expected => BAD\n",[129,3117,3118,3119,3121],{},"I tracked the ",[530,3120,2706],{}," parameter through the codebase:",[74,3123,3124,3135],{},[77,3125,3126,3127,3134],{},"The core logic lived in the ",[80,3128,3131],{"href":3129,"rel":3130},"https://github.com/oramasearch/orama/blob/main/packages/orama/src/methods/search-fulltext.ts",[213],[530,3132,3133],{},"search-fulltext.ts"," file.",[77,3136,3137,3138,3145],{},"This file called into the lower-level search function defined in",[80,3139,3142],{"href":3140,"rel":3141},"https://github.com/oramasearch/orama/blob/main/packages/orama/src/components/index.ts",[213],[530,3143,3144],{},"components/index.ts",", which uses a radix tree for fast token lookups.",[129,3147,3148],{},"By analyzing this flow, I learned that:",[74,3150,3151,3160,3163],{},[77,3152,3153,3154,3157,3158,3134],{},"The ",[530,3155,3156],{},"term"," was being tokenized in the ",[530,3159,3144],{},[77,3161,3162],{},"The radix tree was used to look for matching tokens.",[77,3164,3165,3166,3168,3169,3172],{},"However, ",[530,3167,2613],{}," only ensured token exactness, ",[84,3170,3171],{},"not"," property-level exactness.",[129,3174,3175,3176,3179,3180,3183,3184,3187,3188,309],{},"If we take our reproduction example. The ",[530,3177,3178],{},"noExact"," search tokenization is ",[530,3181,3182],{},"[\"first\"]",".\nAnd the ",[530,3185,3186],{},"withExact"," search tokenization is also ",[530,3189,3182],{},[129,3191,3192,3193,3195,3196,3198],{},"So it is correct that the ",[530,3194,2613],{}," search returns the same result as the ",[530,3197,3178],{}," search. The real problem is more on the usage of a text search engine.",[129,3200,3201,3202],{},"We need to ask ourselves: ",[149,3203,3204,3205,3207],{},"What the user expects when they set ",[530,3206,2613],{},"?",[129,3209,3210],{},"In this case, the user expects to get the exact match of the string \"first\" in the property \"path\".",[249,3212,3214],{"id":3213},"crafting-the-fix","Crafting the fix",[129,3216,3217,3218,3220],{},"Now that we understood the problem, we needed to ensure that the search engine would return the exact match of the string \"first\" in the property \"path\".\nA strict string comparison would be needed when ",[530,3219,2613],{}," is set.",[129,3222,3223],{},"I proposed a solution that:",[1405,3225,3226,3229,3239],{},[77,3227,3228],{},"Keep the current token-level matching.",[77,3230,3231,3232,3234,3235,3238],{},"Rename the internal ",[530,3233,2706],{}," flag to something more explicit (e.g. ",[530,3236,3237],{},"exactToken",";).",[77,3240,3241,3242,524,3245,3247,3248,3251,3252,3254],{},"Apply the ",[84,3243,3244],{},"public",[530,3246,2706],{}," option only when comparing the ",[149,3249,3250],{},"entire"," property value to the ",[149,3253,3250],{}," normalised term.",[129,3256,3257],{},"As of right now, this PR is still open, don't hesitate to check and comment on it if you have any suggestions.",[129,3259,3260],{},"Tools I used:",[74,3262,3263,3269,3275,3281,3286],{},[77,3264,3265,3268],{},[84,3266,3267],{},"VS Code"," for dev",[77,3270,3271,3274],{},[84,3272,3273],{},"Tap and C8"," to run the tests",[77,3276,3277,3280],{},[84,3278,3279],{},"Copilot agent mode"," to brainstorm solutions and validate understanding",[77,3282,3283,3285],{},[84,3284,2508],{}," to track bounty progress",[77,3287,3288,3291],{},[84,3289,3290],{},"GitHub"," for PR and issue management",[249,3293,3295],{"id":3294},"time-breakdown","Time breakdown",[1452,3297,3298,3311],{},[1455,3299,3300],{},[1458,3301,3302,3305,3308],{},[1461,3303,3304],{},"Phase",[1461,3306,3307],{},"Time Spent",[1461,3309,3310],{},"Notes",[1471,3312,3313,3324,3335],{},[1458,3314,3315,3318,3321],{},[1476,3316,3317],{},"Triaging & environment setup",[1476,3319,3320],{},"~1h",[1476,3322,3323],{},"Repo setup, running tests",[1458,3325,3326,3329,3332],{},[1476,3327,3328],{},"Debugging & writing the fix",[1476,3330,3331],{},"~3h",[1476,3333,3334],{},"Reading code, implementing solution",[1458,3336,3337,3340,3342],{},[1476,3338,3339],{},"PR polish & communication",[1476,3341,3320],{},[1476,3343,3344],{},"Writing description, test coverage",[249,3346,3348],{"id":3347},"what-i-learned","What I learned",[74,3350,3351,3354,3363],{},[77,3352,3353],{},"Got deeper into how search engines tokenize and compare inputs.",[77,3355,3356,3357,221,3360,287],{},"Improved my test-driven workflow. (Learn new libraries like ",[530,3358,3359],{},"tap",[530,3361,3362],{},"c8",[77,3364,3365],{},"Practiced communicating clearly with maintainers in an async, open environment.",[249,3367,3369],{"id":3368},"next-steps","Next steps",[1452,3371,3372,3385],{},[1455,3373,3374],{},[1458,3375,3376,3379,3382],{},[1461,3377,3378],{},"Task",[1461,3380,3381],{},"Owner",[1461,3383,3384],{},"Status",[1471,3386,3387,3401,3411,3425,3435],{},[1458,3388,3389,3395,3398],{},[1476,3390,3391,3392,3394],{},"Benchmark new ",[530,3393,2706],{}," logic against existing suite",[1476,3396,3397],{},"Me",[1476,3399,3400],{},"Pending after maintainer feedback",[1458,3402,3403,3406,3408],{},[1476,3404,3405],{},"Prototype index-based optimisation (avoid full scan)",[1476,3407,3397],{},[1476,3409,3410],{},"Researching",[1458,3412,3413,3419,3422],{},[1476,3414,3415,3416,3418],{},"Update docs (",[530,3417,2706],{}," flag semantics)",[1476,3420,3421],{},"Me / Maintainer",[1476,3423,3424],{},"-",[1458,3426,3427,3430,3433],{},[1476,3428,3429],{},"Final review & merge",[1476,3431,3432],{},"Maintainer",[1476,3434,3424],{},[1458,3436,3437,3440,3442],{},[1476,3438,3439],{},"Post-merge blog update + Changelog entry",[1476,3441,3397],{},[1476,3443,3424],{},[478,3445],{},[69,3447,3449],{"id":3448},"a-repeatable-bounty-hunting-workflow","A repeatable bounty-hunting workflow",[129,3451,3452],{},"If you're thinking of jumping in, here's a workflow that worked for me:",[1405,3454,3455,3461,3467,3473,3479,3485],{},[77,3456,3457,3460],{},[84,3458,3459],{},"Pick an issue"," that matches your tech skills.",[77,3462,3463,3466],{},[84,3464,3465],{},"Validate scope"," by reading the repo and any linked code/tests/CI/CD etc.",[77,3468,3469,3472],{},[84,3470,3471],{},"Work on it",": clone the repo, set up your environment, and start coding.",[77,3474,3475,3478],{},[84,3476,3477],{},"Stay focused",": write small, test-driven commits.",[77,3480,3481,3484],{},[84,3482,3483],{},"Write a great PR",": explain your thought process, link to the issue, and keep it clean.",[77,3486,3487,3490],{},[84,3488,3489],{},"Celebrate!"," And don't forget to update your portfolio.",[343,3492,3493],{},[129,3494,3495],{},"Sometimes you need to tell on the issue that you are working on it, even if most of the time, it's not needed you can just push your PR that fixes the issue.",[478,3497],{},[69,3499,3501],{"id":3500},"why-oss-makes-you-a-better-developer","Why OSS makes you a better developer",[129,3503,3504],{},"Every OSS contribution I've made helped me:",[74,3506,3507,3510,3513,3516],{},[77,3508,3509],{},"Write better code with fewer assumptions.",[77,3511,3512],{},"Learn how large, well-structured repos are maintained.",[77,3514,3515],{},"Practice real collaboration and async communication.",[77,3517,3518],{},"Build a visible portfolio that could get me hired.",[129,3520,3521],{},"It's the ultimate blend of learning, reputation-building, and side income.",[478,3523],{},[69,3525,3527],{"id":3526},"resources-next-steps","Resources & Next Steps",[74,3529,3530,3536,3544],{},[77,3531,3532,3533],{},"💼 My contributions: ",[80,3534,2584],{"href":2584,"rel":3535},[213],[77,3537,3538,3539],{},"🏹 My Algora profile: ",[80,3540,3543],{"href":3541,"rel":3542},"https://algora.io/vachmara/profile",[213],"https://algora.io/vachmara",[77,3545,3546,3547],{},"🚀 Good first bounty list: ",[80,3548,3549],{"href":3549,"rel":3550},"https://goodfirstissue.dev",[213],[478,3552],{},[69,3554,3556],{"id":3555},"conclusion","Conclusion",[129,3558,3559,3560,3563],{},"Open source isn't just about giving-it's about growing. You can learn, collaborate, and yes, even ",[84,3561,3562],{},"get paid"," for writing great code in public. If you're passionate about development, pick one bounty this week. Fix it. Submit it.",[129,3565,3566],{},"You'll come out a better engineer-and maybe with coffee money (or more) in your pocket.",[69,3568,3570],{"id":3569},"edit-2025-10-15","Edit (2025-10-15):",[129,3572,3573],{},"The maintainer eventually closed every related PR, including mine, and shipped the fix internally.\nIt's not the ending I expected-but that's also what open source teaches you: sometimes your work is merged, sometimes it's just mirrored. Either way, the learning remains yours.",[478,3575],{},[129,3577,3578,3584],{},[149,3579,3580,3581,309],{},"Thanks for reading! Feel free to share your own OSS bounty stories with me on ",[80,3582,1305],{"href":211,"rel":3583},[213]," ✌️",[2436,3586,3587],{},"html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sfNiH, html code.shiki .sfNiH{--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":369,"searchDepth":370,"depth":370,"links":3589},[3590,3591,3597,3598,3608,3609,3610,3611,3612],{"id":2473,"depth":370,"text":2474},{"id":2495,"depth":370,"text":2496,"children":3592},[3593,3594,3595,3596],{"id":2499,"depth":380,"text":2500},{"id":2512,"depth":380,"text":2513},{"id":2530,"depth":380,"text":2531},{"id":2537,"depth":380,"text":2538},{"id":2572,"depth":370,"text":2573},{"id":2609,"depth":370,"text":3599,"children":3600},"Case Study – Fixing Orama's exact: true Bug (💵 $150 bounty)",[3601,3602,3603,3604,3605,3606,3607],{"id":2647,"depth":380,"text":2648},{"id":2674,"depth":380,"text":2675},{"id":2716,"depth":380,"text":2717},{"id":3213,"depth":380,"text":3214},{"id":3294,"depth":380,"text":3295},{"id":3347,"depth":380,"text":3348},{"id":3368,"depth":380,"text":3369},{"id":3448,"depth":370,"text":3449},{"id":3500,"depth":370,"text":3501},{"id":3526,"depth":370,"text":3527},{"id":3555,"depth":370,"text":3556},{"id":3569,"depth":370,"text":3570},"2025-05-20","A personal journey through open-source contributions, bounties and real-world projects, how I improved my skills and got (not) paid along the way.","/05-20-2025-thumbnail.png",{},{"title":36,"description":3614},"D7yoNk7VlGd0fzZ4tFxz_jnPJUWMvZCZeoMMOONGRJY",{"id":3620,"title":20,"author":3621,"body":3623,"date":4353,"description":4354,"extension":391,"image":4355,"meta":4356,"minRead":394,"navigation":55,"path":21,"seo":4357,"stem":22,"__hash__":4358},"blog/blog/comparing-javascript-bundlers-vite-rspack-webpack-for-nuxt.md",{"name":62,"avatar":3622},{"src":64,"alt":62},{"type":66,"value":3624,"toc":4327},[3625,3629,3638,3641,3645,3648,3652,3656,3663,3667,3680,3684,3695,3699,3707,3790,3808,3811,3815,3818,3825,3922,3925,3934,4026,4029,4032,4071,4079,4083,4086,4089,4092,4101,4104,4112,4116,4224,4227,4244,4248,4251,4254,4268,4271,4274,4285,4288,4291,4302,4310,4312,4324],[3626,3627,20],"h1",{"id":3628},"comparing-modern-javascript-bundlers-for-nuxt-3-rspack-vite-and-webpack",[129,3630,3631,3632,3637],{},"JavaScript bundlers are critical for modern web development, transforming code and dependencies into optimized files for browsers. With many bundlers available, choosing the right one can be daunting. This article compares three prominent bundlers, Webpack, Vite, and Rspack, specifically because they are supported by ",[80,3633,3636],{"href":3634,"rel":3635},"https://nuxt.com/",[213],"Nuxt 3",", a popular Vue.js framework that allows developers to switch between these bundlers for development and production builds. By focusing on their performance, ease of use, ecosystem, features, and use cases in the context of Nuxt 3, we aim to help you select the best tool for your project.",[129,3639,3640],{},"Nuxt 3’s flexibility in bundler choice makes Webpack, Vite, and Rspack particularly relevant. Webpack is Nuxt’s traditional bundler, offering robust customization. Vite, the default since Nuxt 3, provides a fast development experience with native ES modules. Rspack, a newer option, delivers high performance and Webpack compatibility, appealing for large-scale Nuxt applications. This comparison will guide Nuxt developers in leveraging these options effectively.",[69,3642,3644],{"id":3643},"what-is-a-javascript-bundler","What is a JavaScript bundler?",[129,3646,3647],{},"A JavaScript bundler takes your code, including JavaScript, CSS, and other assets, and bundles them into optimized files for browser execution. This process involves transpiling modern JavaScript for compatibility, managing dependencies, and applying optimizations like code splitting and minification. Bundlers enhance both development workflows and production performance, making them critical tools in web development.",[69,3649,3651],{"id":3650},"overview-of-each-bundler","Overview of each bundler",[249,3653,3655],{"id":3654},"webpack","Webpack",[129,3657,3658,3662],{},[80,3659,3655],{"href":3660,"rel":3661},"https://webpack.js.org/",[213]," is a cornerstone of JavaScript bundling, introduced in 2012. It’s renowned for its flexibility, allowing developers to handle virtually any asset type through its extensive ecosystem of plugins and loaders. Webpack’s configurability makes it a go-to choice for complex projects, though its performance can lag in large-scale applications.",[249,3664,3666],{"id":3665},"vite","Vite",[129,3668,3669,3673,3674,3679],{},[80,3670,3666],{"href":3671,"rel":3672},"https://vitejs.dev/",[213],", created by Vue.js founder ",[80,3675,3678],{"href":3676,"rel":3677},"https://evanyou.me/",[213],"Evan You",", is Nuxt 3’s default bundler. It leverages native ES modules for instant server startup and fast hot module replacement (HMR) during development, using Rollup for production builds. Vite is ideal for modern Vue projects, offering simplicity and speed.",[249,3681,3683],{"id":3682},"rspack","Rspack",[129,3685,3686,3690,3691,434],{},[80,3687,3683],{"href":3688,"rel":3689},"https://rspack.dev/",[213],", developed by ByteDance in 2023, is a Rust-based bundler designed as a Webpack alternative. Supported experimentally in Nuxt 3, Rspack offers superior build performance and compatibility with Webpack’s ecosystem, making it a compelling choice for performance-critical Nuxt applications (",[80,3692,3694],{"href":3688,"rel":3693},[213],"Rspack Documentation",[69,3696,3698],{"id":3697},"performance-comparison","Performance Comparison",[129,3700,3701,3702,3706],{},"Performance is a key consideration, especially for large projects where build times impact productivity. Benchmarks from a GitHub repository (",[80,3703,3698],{"href":3704,"rel":3705},"https://github.com/farm-fe/performance-compare",[213],") provide insights into how these bundlers compare.",[1452,3708,3709,3724],{},[1455,3710,3711],{},[1458,3712,3713,3716,3718,3721],{},[1461,3714,3715],{},"Metric",[1461,3717,3683],{},[1461,3719,3720],{},"Vite (SWC)",[1461,3722,3723],{},"Webpack (SWC)",[1471,3725,3726,3742,3758,3774],{},[1458,3727,3728,3733,3736,3739],{},[1476,3729,3730],{},[84,3731,3732],{},"Startup Time",[1476,3734,3735],{},"~417ms",[1476,3737,3738],{},"~1716ms",[1476,3740,3741],{},"~1926ms",[1458,3743,3744,3749,3752,3755],{},[1476,3745,3746],{},[84,3747,3748],{},"HMR (Root)",[1476,3750,3751],{},"~82ms",[1476,3753,3754],{},"~114ms",[1476,3756,3757],{},"~138ms",[1458,3759,3760,3765,3768,3771],{},[1476,3761,3762],{},[84,3763,3764],{},"HMR (Leaf)",[1476,3766,3767],{},"~85ms",[1476,3769,3770],{},"~123ms",[1476,3772,3773],{},"~122ms",[1458,3775,3776,3781,3784,3787],{},[1476,3777,3778],{},[84,3779,3780],{},"Build Time",[1476,3782,3783],{},"~320ms",[1476,3785,3786],{},"~1260ms",[1476,3788,3789],{},"~4144ms",[74,3791,3792,3797,3803],{},[77,3793,3794,3796],{},[84,3795,3732],{},": Rspack leads with a startup time of approximately 417ms, followed by Vite at 1716ms and Webpack at 1926ms. Rspack’s Rust-based architecture contributes to its speed.",[77,3798,3799,3802],{},[84,3800,3801],{},"Hot Module Replacement (HMR)",": Rspack excels in HMR, with root updates at ~82ms and leaf updates at ~85ms. Vite and Webpack are slower, with Vite at ~114ms (root) and Webpack at ~138ms (root).",[77,3804,3805,3807],{},[84,3806,3780],{},": Rspack (via Rsbuild) achieves the fastest build time at ~320ms, compared to Vite’s ~1260ms and Webpack’s ~4144ms. This makes Rspack particularly suited for CI/CD pipelines where build speed is critical.",[129,3809,3810],{},"These metrics suggest Rspack offers the best overall performance for startup and build times. However, these are general benchmarks, and actual performance may vary based on project complexity and configuration.",[69,3812,3814],{"id":3813},"ease-of-use-and-configuration-in-nuxt-3","Ease of use and configuration in Nuxt 3",[249,3816,3655],{"id":3817},"webpack-1",[129,3819,3820,3821,3824],{},"Webpack’s flexibility in Nuxt 3 comes with complex configuration, requiring loaders and plugins for tasks like CSS or TypeScript processing. Nuxt simplifies this with its ",[530,3822,3823],{},"nuxt.config"," file, but advanced tweaks demand Webpack expertise. Example:",[1197,3826,3828],{"className":2723,"code":3827,"language":2725,"meta":369,"style":369},"export default defineNuxtConfig({\n builder: 'webpack',\n webpack: {\n loaders: { css: ['style-loader', 'css-loader'] },\n },\n});\n",[530,3829,3830,3846,3863,3872,3910,3914],{"__ignoreMap":369},[1761,3831,3832,3836,3839,3842,3844],{"class":1763,"line":1764},[1761,3833,3835],{"class":3834},"s7zQu","export",[1761,3837,3838],{"class":3834}," default",[1761,3840,3841],{"class":2743}," defineNuxtConfig",[1761,3843,2747],{"class":1855},[1761,3845,2750],{"class":2739},[1761,3847,3848,3851,3853,3856,3858,3861],{"class":1763,"line":370},[1761,3849,3850],{"class":2755}," builder",[1761,3852,2759],{"class":2739},[1761,3854,3855],{"class":2739}," '",[1761,3857,3654],{"class":1823},[1761,3859,3860],{"class":2739},"'",[1761,3862,2781],{"class":2739},[1761,3864,3865,3868,3870],{"class":1763,"line":380},[1761,3866,3867],{"class":2755}," webpack",[1761,3869,2759],{"class":2739},[1761,3871,2762],{"class":2739},[1761,3873,3874,3877,3879,3881,3884,3886,3888,3890,3893,3895,3897,3899,3902,3904,3907],{"class":1763,"line":1780},[1761,3875,3876],{"class":2755}," loaders",[1761,3878,2759],{"class":2739},[1761,3880,2829],{"class":2739},[1761,3882,3883],{"class":2755}," css",[1761,3885,2759],{"class":2739},[1761,3887,2950],{"class":1855},[1761,3889,3860],{"class":2739},[1761,3891,3892],{"class":1823},"style-loader",[1761,3894,3860],{"class":2739},[1761,3896,2826],{"class":2739},[1761,3898,3855],{"class":2739},[1761,3900,3901],{"class":1823},"css-loader",[1761,3903,3860],{"class":2739},[1761,3905,3906],{"class":1855},"] ",[1761,3908,3909],{"class":2739},"},\n",[1761,3911,3912],{"class":1763,"line":1589},[1761,3913,2801],{"class":2739},[1761,3915,3916,3918,3920],{"class":1763,"line":1791},[1761,3917,2806],{"class":2739},[1761,3919,287],{"class":1855},[1761,3921,2811],{"class":2739},[249,3923,3666],{"id":3924},"vite-1",[129,3926,3927,3928,3930,3931,3933],{},"Vite, Nuxt 3’s default, offers minimal configuration with sensible defaults. Its ",[530,3929,3665],{}," property in ",[530,3932,3823],{}," supports plugins and CSS options, making it developer-friendly for Vue projects. Example:",[1197,3935,3937],{"className":2723,"code":3936,"language":2725,"meta":369,"style":369},"export default defineNuxtConfig({\n /* Default bundler is Vite */\n vite: {\n plugins: [/* Vite plugins */],\n css: { modules: { localsConvention: 'camelCase' } },\n },\n});\n",[530,3938,3939,3951,3956,3965,3981,4014,4018],{"__ignoreMap":369},[1761,3940,3941,3943,3945,3947,3949],{"class":1763,"line":1764},[1761,3942,3835],{"class":3834},[1761,3944,3838],{"class":3834},[1761,3946,3841],{"class":2743},[1761,3948,2747],{"class":1855},[1761,3950,2750],{"class":2739},[1761,3952,3953],{"class":1763,"line":370},[1761,3954,3955],{"class":3086}," /* Default bundler is Vite */\n",[1761,3957,3958,3961,3963],{"class":1763,"line":380},[1761,3959,3960],{"class":2755}," vite",[1761,3962,2759],{"class":2739},[1761,3964,2762],{"class":2739},[1761,3966,3967,3970,3972,3974,3977,3979],{"class":1763,"line":1780},[1761,3968,3969],{"class":2755}," plugins",[1761,3971,2759],{"class":2739},[1761,3973,2950],{"class":1855},[1761,3975,3976],{"class":3086},"/* Vite plugins */",[1761,3978,2960],{"class":1855},[1761,3980,2781],{"class":2739},[1761,3982,3983,3986,3988,3990,3993,3995,3997,4000,4002,4004,4007,4009,4011],{"class":1763,"line":1589},[1761,3984,3985],{"class":2755}," css",[1761,3987,2759],{"class":2739},[1761,3989,2829],{"class":2739},[1761,3991,3992],{"class":2755}," modules",[1761,3994,2759],{"class":2739},[1761,3996,2829],{"class":2739},[1761,3998,3999],{"class":2755}," localsConvention",[1761,4001,2759],{"class":2739},[1761,4003,3855],{"class":2739},[1761,4005,4006],{"class":1823},"camelCase",[1761,4008,3860],{"class":2739},[1761,4010,2858],{"class":2739},[1761,4012,4013],{"class":2739}," },\n",[1761,4015,4016],{"class":1763,"line":1791},[1761,4017,2801],{"class":2739},[1761,4019,4020,4022,4024],{"class":1763,"line":1797},[1761,4021,2806],{"class":2739},[1761,4023,287],{"class":1855},[1761,4025,2811],{"class":2739},[249,4027,3683],{"id":4028},"rspack-1",[129,4030,4031],{},"Rspack in Nuxt 3 uses a Webpack-like configuration but benefits from built-in optimizations. Example:",[1197,4033,4035],{"className":2723,"code":4034,"language":2725,"meta":369,"style":369},"export default defineNuxtConfig({\n builder: 'rspack',\n});\n",[530,4036,4037,4049,4063],{"__ignoreMap":369},[1761,4038,4039,4041,4043,4045,4047],{"class":1763,"line":1764},[1761,4040,3835],{"class":3834},[1761,4042,3838],{"class":3834},[1761,4044,3841],{"class":2743},[1761,4046,2747],{"class":1855},[1761,4048,2750],{"class":2739},[1761,4050,4051,4053,4055,4057,4059,4061],{"class":1763,"line":370},[1761,4052,3850],{"class":2755},[1761,4054,2759],{"class":2739},[1761,4056,3855],{"class":2739},[1761,4058,3682],{"class":1823},[1761,4060,3860],{"class":2739},[1761,4062,2781],{"class":2739},[1761,4064,4065,4067,4069],{"class":1763,"line":380},[1761,4066,2806],{"class":2739},[1761,4068,287],{"class":1855},[1761,4070,2811],{"class":2739},[129,4072,4073,4074,434],{},"Vite is the easiest for Nuxt 3 beginners, while Rspack and Webpack cater to developers familiar with Webpack’s ecosystem (",[80,4075,4078],{"href":4076,"rel":4077},"https://nuxt.com/docs/api/nuxt-config#builder",[213],"Nuxt 3 Documentation",[69,4080,4082],{"id":4081},"ecosystem-and-community-support","Ecosystem and community support",[249,4084,3655],{"id":4085},"webpack-2",[129,4087,4088],{},"Webpack’s mature ecosystem, with thousands of plugins and loaders, integrates seamlessly with Nuxt’s historical reliance on it. Its extensive documentation and community support make it a safe choice for Nuxt 3 projects requiring specific customizations.",[249,4090,3666],{"id":4091},"vite-2",[129,4093,4094,4095,4100],{},"Vite’s ecosystem, boosted by Nuxt 3’s adoption, is thriving in the Vue community. It supports Rollup plugins and has ~72,568 GitHub stars (",[80,4096,4099],{"href":4097,"rel":4098},"https://github.com/vitejs/vite",[213],"Vite GitHub","). Nuxt 3’s first-class Vite support ensures robust tooling for Vue developers.",[249,4102,3683],{"id":4103},"rspack-2",[129,4105,4106,4107,434],{},"Rspack’s ecosystem is nascent but leverages Webpack’s plugins due to API compatibility, a boon for Nuxt 3 users transitioning from Webpack. Backed by ByteDance, Rspack is gaining traction for performance-critical Nuxt apps (",[80,4108,4111],{"href":4109,"rel":4110},"https://github.com/web-infra-dev/rspack",[213],"Rspack GitHub",[69,4113,4115],{"id":4114},"feature-set","Feature Set",[1452,4117,4118,4131],{},[1455,4119,4120],{},[1458,4121,4122,4125,4127,4129],{},[1461,4123,4124],{},"Feature",[1461,4126,3655],{},[1461,4128,3666],{},[1461,4130,3683],{},[1471,4132,4133,4149,4162,4178,4193,4209],{},[1458,4134,4135,4140,4143,4146],{},[1476,4136,4137],{},[84,4138,4139],{},"Code splitting",[1476,4141,4142],{},"Yes, via plugins",[1476,4144,4145],{},"Yes, built-in (Rollup)",[1476,4147,4148],{},"Yes, built-in",[1458,4150,4151,4156,4158,4160],{},[1476,4152,4153],{},[84,4154,4155],{},"Tree shaking",[1476,4157,4142],{},[1476,4159,4145],{},[1476,4161,4148],{},[1458,4163,4164,4169,4172,4175],{},[1476,4165,4166],{},[84,4167,4168],{},"HMR",[1476,4170,4171],{},"Yes, slower",[1476,4173,4174],{},"Yes, pretty fast",[1476,4176,4177],{},"Yes, optimized for large projects",[1458,4179,4180,4185,4187,4190],{},[1476,4181,4182],{},[84,4183,4184],{},"Module federation",[1476,4186,4142],{},[1476,4188,4189],{},"Limited support",[1476,4191,4192],{},"Built-in support",[1458,4194,4195,4200,4203,4206],{},[1476,4196,4197],{},[84,4198,4199],{},"CSS handling",[1476,4201,4202],{},"Via loaders (e.g., css-loader)",[1476,4204,4205],{},"Built-in (PostCSS, CSS Modules)",[1476,4207,4208],{},"Built-in (CSS Modules)",[1458,4210,4211,4216,4219,4222],{},[1476,4212,4213],{},[84,4214,4215],{},"TypeScript/JSX",[1476,4217,4218],{},"Via loaders (e.g., ts-loader)",[1476,4220,4221],{},"Built-in",[1476,4223,4221],{},[129,4225,4226],{},"In Nuxt 3:",[74,4228,4229,4234,4239],{},[77,4230,4231,4233],{},[84,4232,3655],{}," supports complex customizations, ideal for legacy Nuxt projects.",[77,4235,4236,4238],{},[84,4237,3666],{}," provides seamless Vue integration and fast HMR, aligning with Nuxt 3’s modern architecture.",[77,4240,4241,4243],{},[84,4242,3683],{}," offers Module Federation for micro frontends, useful for large Nuxt apps, with performance optimizations.",[69,4245,4247],{"id":4246},"use-cases-in-nuxt-3","Use Cases in Nuxt 3",[249,4249,3655],{"id":4250},"webpack-3",[129,4252,4253],{},"Best for:",[74,4255,4256,4259,4262,4265],{},[77,4257,4258],{},"Legacy Nuxt projects already using Webpack.",[77,4260,4261],{},"Migrating existing Webpack-based projects to Nuxt 3.",[77,4263,4264],{},"Nuxt 3 apps requiring extensive plugin-based customizations.",[77,4266,4267],{},"Projects prioritizing ecosystem maturity over build speed.",[249,4269,3666],{"id":4270},"vite-3",[129,4272,4273],{},"Ideal for:",[74,4275,4276,4279,4282],{},[77,4277,4278],{},"New Nuxt 3 projects leveraging Vue 3.",[77,4280,4281],{},"Development-focused workflows needing fast HMR.",[77,4283,4284],{},"Teams valuing simplicity and modern ES module support.",[249,4286,3683],{"id":4287},"rspack-3",[129,4289,4290],{},"Suited for:",[74,4292,4293,4296,4299],{},[77,4294,4295],{},"Large Nuxt 3 projects where build performance is critical.",[77,4297,4298],{},"Webpack-based Nuxt apps seeking faster builds without major refactoring.",[77,4300,4301],{},"Experimental Nuxt deployments exploring micro frontends via Module Federation.",[129,4303,4304,4305,434],{},"ByteDance’s use of Rspack for TikTok’s frontend highlights its potential for Nuxt 3’s performance needs (",[80,4306,4309],{"href":4307,"rel":4308},"https://dev.to/a4arpon/bytedances-rspack-the-future-of-web-bundling-shahin-islam-arpon-a4arpon-op4",[213],"ByteDance’s RsPack",[69,4311,3556],{"id":3555},[129,4313,4314,4315,4317,4318,4320,4321,4323],{},"Nuxt 3’s support for Webpack, Vite, and Rspack offers developers flexibility to choose based on project needs. ",[84,4316,3655],{}," suits legacy or highly customized Nuxt apps, despite slower builds. ",[84,4319,3666],{},", the default, excels in development speed and simplicity, perfect for modern Vue projects. ",[84,4322,3683],{}," delivers unmatched build performance and Webpack compatibility, ideal for large-scale or performance-critical Nuxt applications. Consider your Nuxt 3 project’s size, performance goals, and team familiarity when selecting a bundler, and explore Nuxt’s documentation for the latest on Rspack’s experimental support.",[2436,4325,4326],{},"html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}",{"title":369,"searchDepth":370,"depth":370,"links":4328},[4329,4330,4335,4336,4341,4346,4347,4352],{"id":3643,"depth":370,"text":3644},{"id":3650,"depth":370,"text":3651,"children":4331},[4332,4333,4334],{"id":3654,"depth":380,"text":3655},{"id":3665,"depth":380,"text":3666},{"id":3682,"depth":380,"text":3683},{"id":3697,"depth":370,"text":3698},{"id":3813,"depth":370,"text":3814,"children":4337},[4338,4339,4340],{"id":3817,"depth":380,"text":3655},{"id":3924,"depth":380,"text":3666},{"id":4028,"depth":380,"text":3683},{"id":4081,"depth":370,"text":4082,"children":4342},[4343,4344,4345],{"id":4085,"depth":380,"text":3655},{"id":4091,"depth":380,"text":3666},{"id":4103,"depth":380,"text":3683},{"id":4114,"depth":370,"text":4115},{"id":4246,"depth":370,"text":4247,"children":4348},[4349,4350,4351],{"id":4250,"depth":380,"text":3655},{"id":4270,"depth":380,"text":3666},{"id":4287,"depth":380,"text":3683},{"id":3555,"depth":370,"text":3556},"2025-05-13","An in-depth comparison of Rspack, Vite, and Webpack, exploring their performance, features, and use cases to help you choose the right tool for your project.","/05-13-2025-thumbnail.png",{},{"title":20,"description":4354},"8TNi-fiGD4VWOUMYxdXxHvLQsMiK_QDq8BcchFEdg8E",{"id":4360,"title":32,"author":4361,"body":4363,"date":4854,"description":4855,"extension":391,"image":4856,"meta":4857,"minRead":1589,"navigation":55,"path":33,"seo":4858,"stem":34,"__hash__":4859},"blog/blog/how-supacodeur-got-its-first-users-from-internal-tool-to-niche-saas.md",{"name":62,"avatar":4362},{"src":64,"alt":62},{"type":66,"value":4364,"toc":4840},[4365,4369,4376,4387,4390,4399,4403,4414,4421,4425,4428,4441,4446,4455,4461,4465,4468,4471,4529,4535,4539,4557,4571,4574,4578,4584,4591,4602,4605,4623,4631,4639,4642,4645,4656,4660,4663,4697,4702,4705,4712,4715,4721,4724,4728,4731,4754,4757,4795,4798,4821,4823,4826,4829,4832],[69,4366,4368],{"id":4367},"the-origin-story","The origin story",[129,4370,4371,4372,4375],{},"In ",[84,4373,4374],{},"April 2024",", I was burned out from scrolling through low-quality leads on Codeur.com. Like many freelancers, I found most projects on the platform were either:",[74,4377,4378,4381,4384],{},[77,4379,4380],{},"Underfunded",[77,4382,4383],{},"Vague or unserious",[77,4385,4386],{},"Ghosted you mid-discussion",[129,4388,4389],{},"But I kept using Codeur anyway, because despite the mess, it still brought me clients.",[129,4391,4392,4393,4395,4396,309],{},"So I built myself a tool.",[910,4394],{},"\nNot a startup. Not a product. Just an ",[84,4397,4398],{},"extension that automated my prospecting flow",[249,4400,4402],{"id":4401},"what-it-did","What it did:",[74,4404,4405,4408,4411],{},[77,4406,4407],{},"Scanned new projects on Codeur",[77,4409,4410],{},"Filtered by budget, tags, or project quality",[77,4412,4413],{},"Auto-generated personalized proposals with my tone & style",[129,4415,4416,4417,4420],{},"It worked. I used it for ",[84,4418,4419],{},"a full year",", quietly, every day.",[69,4422,4424],{"id":4423},"breaking-point","Breaking point",[129,4426,4427],{},"Late 2024 was rough professionally.",[129,4429,4430,4431,4434,4435,4437,4438,309],{},"I lost a long-term client in Web3 after ",[84,4432,4433],{},"two security breaches"," (that’s a story for another time).",[910,4436],{},"\nThen in January, another client straight-up ",[84,4439,4440],{},"refused to pay",[343,4442,4443],{},[129,4444,4445],{},"I had worked like crazy all year… for what?",[129,4447,4448,4449,4451,4452,309],{},"Meanwhile, my engineering friends had stable jobs, decent salaries, and no surprise invoices.",[910,4450],{},"\nI realized: I needed to stop relying on ",[84,4453,4454],{},"unpredictable acquisition channels",[129,4456,4457,4458,4460],{},"That internal tool, the one I built for Codeur, deserved better.",[910,4459],{},"\nSo I decided to turn it into a real product.",[69,4462,4464],{"id":4463},"building-supacodeur-as-a-saas","Building SupaCodeur (as a SaaS)",[129,4466,4467],{},"By January 2025, I was in my element: building MVPs.",[129,4469,4470],{},"I used my favorite stack:",[74,4472,4473,4491,4501,4510,4520],{},[77,4474,4475,4482,4483,4490],{},[80,4476,4479],{"href":4477,"rel":4478},"https://nuxt.com",[213],[84,4480,4481],{},"Nuxt"," + ",[80,4484,4487],{"href":4485,"rel":4486},"https://ui.nuxt.com",[213],[84,4488,4489],{},"Nuxt UI Pro"," (seriously underrated templates)",[77,4492,4493,4500],{},[80,4494,4497],{"href":4495,"rel":4496},"https://vuejs.org/",[213],[84,4498,4499],{},"Vue"," for the extension",[77,4502,4503,4509],{},[80,4504,4507],{"href":4505,"rel":4506},"https://supabase.com/",[213],[84,4508,2412],{}," for auth, DB, and storage",[77,4511,4512,4519],{},[80,4513,4516],{"href":4514,"rel":4515},"https://vercel.com",[213],[84,4517,4518],{},"Vercel"," for fast shipping",[77,4521,4522,4528],{},[80,4523,4526],{"href":4524,"rel":4525},"https://github.com",[213],[84,4527,3290],{}," to keep it clean",[129,4530,4371,4531,4534],{},[84,4532,4533],{},"February",", the MVP was ready. Not perfect, but usable.",[249,4536,4538],{"id":4537},"the-first-iteration","The First iteration",[129,4540,4541,4542,4549,4550,309,4554,4556],{},"I hosted it under my previous studio brand, ",[80,4543,4546],{"href":4544,"rel":4545},"https://www.agence-swai.com",[213],[530,4547,4548],{},"supadev.fr",", which has now been merged into ",[80,4551,4553],{"href":4544,"rel":4552},[213],"Agence SWAI",[910,4555],{},"\nAt first it was just:",[74,4558,4559,4562,4565,4568],{},[77,4560,4561],{},"A simple form",[77,4563,4564],{},"Some backend API logic",[77,4566,4567],{},"A waiting list & filters for targeting freelancers' ideal project types",[77,4569,4570],{},"A Chrome extension that was a bit buggy",[129,4572,4573],{},"It felt good. Clean. Lightweight.",[69,4575,4577],{"id":4576},"getting-the-first-user","Getting the first user",[129,4579,4580,4581,309],{},"Then came ",[84,4582,4583],{},"sales",[129,4585,4586,4587,4590],{},"The great thing about SupaCodeur is that the ",[84,4588,4589],{},"target market is super niche",", freelancers on Codeur.com. And the data is public:",[74,4592,4593,4596,4599],{},[77,4594,4595],{},"Phone numbers",[77,4597,4598],{},"Names",[77,4600,4601],{},"Project history",[129,4603,4604],{},"So I went guerrilla-style:",[74,4606,4607,4614,4620],{},[77,4608,4609,4610,4613],{},"Set up a ",[84,4611,4612],{},"WhatsApp Business"," account",[77,4615,4616,4617],{},"Wrote a very ",[84,4618,4619],{},"aggressive sales message",[77,4621,4622],{},"Manually contacted 100 freelancers",[343,4624,4625],{},[129,4626,4627,4628,4630],{},"WhatsApp banned me fast. 😂",[910,4629],{},"\nBut it worked.",[129,4632,4633,4636,4638],{},[84,4634,4635],{},"Multiple people replied. I learned and eventually convert one client.",[910,4637],{},"\nThat’s all I needed.",[129,4640,4641],{},"He became my first user, and a key tester.",[129,4643,4644],{},"Together, we:",[74,4646,4647,4650,4653],{},[77,4648,4649],{},"Debugged the Chrome extension",[77,4651,4652],{},"Improved the user flow",[77,4654,4655],{},"Identified the real pain points (and ignored the fake ones)",[69,4657,4659],{"id":4658},"leveling-up","Leveling up",[129,4661,4662],{},"With momentum building, I invested more:",[74,4664,4665,4672,4678,4684,4687,4690],{},[77,4666,4667,4668,4671],{},"Bought a ",[84,4669,4670],{},"dedicated domain"," with a better name",[77,4673,4674,4675],{},"Added a real ",[84,4676,4677],{},"dashboard",[77,4679,4680,4681],{},"Built a nicer ",[84,4682,4683],{},"stats interface",[77,4685,4686],{},"Refined the extension UI/UX",[77,4688,4689],{},"Identified the different personas (freelancers, agencies, etc.)",[77,4691,4692,4693,4696],{},"Create ",[84,4694,4695],{},"subscriptions"," for each persona",[129,4698,4580,4699,309],{},[84,4700,4701],{},"sales round #2",[129,4703,4704],{},"A new agency showed interest. They tested it in April.",[129,4706,4707,4708],{},"I was excited. MRR was picking up. But not for too long...\n",[616,4709],{"alt":4710,"src":4711},"stripe result","/05-05-2025-supacodeur-billing-overview.png",[129,4713,4714],{},"Unfortunately, the results weren’t great, low conversion on their end, the generated proposals were too generic.",[129,4716,4717,4718,309],{},"But that’s part of the journey. Every new user is a ",[84,4719,4720],{},"lesson",[129,4722,4723],{},"And we are working on it together to improve the product and give them a reason to come back.",[69,4725,4727],{"id":4726},"long-term-play","Long-Term play",[129,4729,4730],{},"To support the project long-term, I also:",[74,4732,4733,4740,4748,4751],{},[77,4734,4735,4736],{},"Launched an SEO-focused ",[80,4737,9],{"href":4738,"rel":4739},"https://www.supacodeur.fr/blog",[213],[77,4741,4742,4743,4747],{},"Launched on ",[80,4744,887],{"href":4745,"rel":4746},"https://www.producthunt.com/products/supacodeur",[213]," for backlinks",[77,4749,4750],{},"Wrote use-case pages to boost organic discovery",[77,4752,4753],{},"Started documenting the product more seriously",[69,4755,4756],{"id":801},"What’s next?",[74,4758,4759,4765,4771,4777,4783,4789],{},[77,4760,4761,4764],{},[84,4762,4763],{},"More users",": I’m still reaching out to freelancers and agencies, I am planning to semi automate the process.",[77,4766,4767,4770],{},[84,4768,4769],{},"More features",": I’m working on a new version of the product, with a better UI and more features.",[77,4772,4773,4776],{},[84,4774,4775],{},"More content",": I’m writing more blog posts, tutorials, and guides to help users get the most out of SupaCodeur.",[77,4778,4779,4782],{},[84,4780,4781],{},"More partnerships",": I’m looking for collaborations with other freelancers and agencies to expand the reach of SupaCodeur.",[77,4784,4785,4788],{},[84,4786,4787],{},"More feedback",": I’m actively seeking feedback from users to improve the product and make it more valuable.",[77,4790,4791,4794],{},[84,4792,4793],{},"More fun",": I’m enjoying the process of building and learning, and I want to keep it that way.",[69,4796,4797],{"id":3347},"What I Learned",[74,4799,4800,4803,4806,4812,4815],{},[77,4801,4802],{},"Build for yourself first. You’ll always be your best user.",[77,4804,4805],{},"Niche SaaS markets can be super powerful if the pain is real.",[77,4807,4808,4809,309],{},"Early users are not clients — they’re ",[84,4810,4811],{},"co-builders",[77,4813,4814],{},"Guerrilla sales works when your prospect is clear and reachable.",[77,4816,4817,4818,309],{},"MVPs don’t need to be polished. They need to be ",[84,4819,4820],{},"used",[478,4822],{},[129,4824,4825],{},"SupaCodeur is still growing. Still niche. Still learning.",[129,4827,4828],{},"But now it’s a real product — with users, feedback, and a future.",[129,4830,4831],{},"And I’m excited to share the next steps, as always, in public.",[129,4833,4834,4835],{},"👉 Want to try it? ",[80,4836,4839],{"href":4837,"rel":4838},"https://www.supacodeur.fr",[213],"Visit SupaCodeur",{"title":369,"searchDepth":370,"depth":370,"links":4841},[4842,4845,4846,4849,4850,4851,4852,4853],{"id":4367,"depth":370,"text":4368,"children":4843},[4844],{"id":4401,"depth":380,"text":4402},{"id":4423,"depth":370,"text":4424},{"id":4463,"depth":370,"text":4464,"children":4847},[4848],{"id":4537,"depth":380,"text":4538},{"id":4576,"depth":370,"text":4577},{"id":4658,"depth":370,"text":4659},{"id":4726,"depth":370,"text":4727},{"id":801,"depth":370,"text":4756},{"id":3347,"depth":370,"text":4797},"2025-05-05","I built SupaCodeur to solve my own frustrations with Codeur.com. Here's how I turned it into a real SaaS, got my first users, and what I learned along the way.","https://images.pexels.com/photos/7679642/pexels-photo-7679642.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1",{},{"title":32,"description":4855},"q5dzviny-48B2E70-N5Puxw7bR1QBPKvEo7xhe0Luvw",{"id":4861,"title":28,"author":4862,"body":4864,"date":8356,"description":8357,"extension":391,"image":8358,"meta":8359,"minRead":1589,"navigation":55,"path":29,"seo":8360,"stem":30,"__hash__":8361},"blog/blog/from-root-me-to-saas-builder-my-journey-into-code-security-and-autonomy.md",{"name":62,"avatar":4863},{"src":64,"alt":62},{"type":66,"value":4865,"toc":8346},[4866,4870,4882,4889,4893,4904,4915,4923,4927,4938,4945,4951,4962,4965,4969,4976,4979,4990,4997,5001,5007,5010,5013,5027,5036,5046,5057,5060,5069,5072,5086,5093,5096,5099,5110,5113,5115,5118,5121,8343],[69,4867,4869],{"id":4868},"it-all-started-with-root-me","It all started with Root-Me",[129,4871,4872,4873,4878,4879,309],{},"Back in December 2014, I completed my first CTF challenge on ",[80,4874,4877],{"href":4875,"rel":4876},"https://www.root-me.org/",[213],"Root-Me.org",". I was 16, curious, and fascinated by the idea of being a “hacker”. I didn’t even know what software engineering really was, just that I wanted to ",[84,4880,4881],{},"understand how systems worked... and how to break them",[129,4883,4884,4885,4888],{},"But it wasn’t just fun. Root-Me lit a fire in me. It taught me logic, security, and how to think like a machine. Even now, ",[84,4886,4887],{},"security is baked into how I design every system",", because I started by trying to break them first.",[69,4890,4892],{"id":4891},"my-first-project-demisn","My first project: DEMISN",[129,4894,4895,4896,4899,4900,4903],{},"During my final year of high school, I chose a specialty called ",[84,4897,4898],{},"ISN (Informatique et Sciences du Numérique)",". That’s where I built my first “real” project: ",[84,4901,4902],{},"Demisn",", a Python & Tkinter version of Minesweeper.",[129,4905,4906,4907,4909,4910,4912,4913],{},"Was it messy? Absolutely.",[910,4908],{},"\nDid it work? Somehow.",[910,4911],{},"\nDid it teach me a ton? For sure.",[910,4914],{},[129,4916,4917,4918,4922],{},"The code is chaotic by today’s standards, but it’s a beautiful snapshot of how every dev starts: by building something that kinda-sorta works and being ridiculously proud of it. (you can found the code in the ",[80,4919,4921],{"href":4920},"#notes","notes"," of this post.)",[69,4924,4926],{"id":4925},"engineering-school-reality-check","Engineering school & reality check",[129,4928,4929,4930,4933,4934,4937],{},"I passed the entry exams and joined ",[84,4931,4932],{},"ISTY",", an engineering school in France. After 2 years of general studies, I picked ",[84,4935,4936],{},"mechatronics"," because I was curious about both software and hardware.",[129,4939,4940,4941,4944],{},"I landed an apprenticeship at ",[84,4942,4943],{},"Stellantis",", a major automotive group. On paper, it sounded like a dream: safety engineering, big teams, real-world impact.",[129,4946,4947,4948],{},"But I quickly learned something else: ",[84,4949,4950],{},"I hated it.",[129,4952,4953,4954,4956,4957,4959,4960],{},"Too many meetings.",[910,4955],{},"\nToo little action.",[910,4958],{},"\nEverything moved at the speed of paperwork.",[910,4961],{},[129,4963,4964],{},"But something good came out of it.",[69,4966,4968],{"id":4967},"my-first-automation-win","My first \"automation win\"",[129,4970,4971,4972,4975],{},"One day, I saw a tedious process being handled by an external company. It took ",[84,4973,4974],{},"weeks",". I asked if I could try automating it.",[129,4977,4978],{},"A few days later, I had a working script.",[129,4980,4981,4982,4985,4986,4989],{},"Suddenly, what took ",[84,4983,4984],{},"weeks and multiple people"," became a ",[84,4987,4988],{},"5-minute internal task",". It saved time, saved money, and gave me a taste of what I really loved:",[343,4991,4992],{},[129,4993,4994],{},[84,4995,4996],{},"Building useful tools that make life easier.",[69,4998,5000],{"id":4999},"from-employee-to-indie","From employee to indie",[129,5002,5003,5004,309],{},"After that, I knew I didn’t want a traditional career. I wanted ",[84,5005,5006],{},"freedom, speed, and ownership",[129,5008,5009],{},"I didn’t leap into freelancing with a masterplan. It was messy. Emotional. Unstructured. But it was the beginning of something real.",[129,5011,5012],{},"Back then, I had two things:",[74,5014,5015,5021],{},[77,5016,5017,5020],{},[84,5018,5019],{},"Some savings"," from my apprenticeship (even if I didn’t enjoy the work, I still believe apprenticeships are the best way to start a career)",[77,5022,5023,5026],{},[84,5024,5025],{},"A lucky investment"," in $MATIC that turned into a x30 profit - unrealized it peaked at x60",[129,5028,5029,5030,5035],{},"At first, I naively thought I could become a trader. I genuinely believed I could make a living predicting the price of Bitcoin. I even open-sourced a project on ",[80,5031,5034],{"href":5032,"rel":5033},"https://gitlab.com/vachmara/Bitcoin-price-RNN",[213],"GitLab"," using an RNN to forecast BTC prices. Spoiler: it didn’t work out.",[129,5037,5038,5039,732,5042,5045],{},"Then came the NFT wave. I started building my first dApps for minting NFTs. But I didn’t know how to price my work, how to write a proper quotation, how to ",[84,5040,5041],{},"sell",[84,5043,5044],{},"convert",". I fell into all the classic traps:",[74,5047,5048,5051,5054],{},[77,5049,5050],{},"Working for free on vague promises",[77,5052,5053],{},"Clients who ghosted after delivery",[77,5055,5056],{},"Over-engineering solutions for people who didn’t need them",[129,5058,5059],{},"At the same time, I tried launching a proptech startup. One of my biggest (and most expensive) mistakes?",[343,5061,5062],{},[129,5063,5064,5065,5068],{},"Buying a domain name worth ",[84,5066,5067],{},"$8,000 in crypto","… for a project that didn’t even exist yet.",[129,5070,5071],{},"Looking back, I’m grateful for all of it. These failures weren’t signs to stop, they were exactly what I needed to grow. They taught me how to:",[74,5073,5074,5077,5080,5083],{},[77,5075,5076],{},"Say no",[77,5078,5079],{},"Qualify clients",[77,5081,5082],{},"Build only what matters",[77,5084,5085],{},"Charge what I’m worth",[129,5087,5088,5089,5092],{},"Today, the contrast is night and day. I can go from ",[84,5090,5091],{},"idea to working MVP in just a few days",". I’ve built a system, refined my processes, and learned how to stay lean and focused. Most importantly, I’m building for the long term with autonomy, speed, and intention.",[69,5094,5095],{"id":801},"What’s Next",[129,5097,5098],{},"Through this blog, I’ll share:",[74,5100,5101,5104,5107],{},[77,5102,5103],{},"My wins and failures",[77,5105,5106],{},"What I build and how I build it",[77,5108,5109],{},"My learnings from freelancing, entrepreneurship, and solo product development",[129,5111,5112],{},"Thanks for reading and if any of this resonates, feel free to reach out or follow the journey.",[249,5114,3310],{"id":4921},[129,5116,5117],{},"You want to see the code of my first project? Here it is:",[129,5119,5120],{},"Please, don't judge me too hard!!",[1197,5122,5126],{"className":5123,"code":5124,"language":5125,"meta":369,"style":369},"language-python shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\"\"\"\nProgramme principal du code du démineur. \n Tous droits réservés Demisn © 2016\n\nmenubar.py, ainsi que score.py sont essentiels au bon fonctionnement du programme.\n\"\"\"\ntry:\n # Python2\n #!/usr/bin/python2.7\n # -*-coding:Latin-1 -*\n from Tkinter import *\n from tkMessageBox import *\nexcept ImportError:\n #!/usr/bin/python3.5\n # -*-coding:Latin-1 -*\n # Python3\n from tkinter import *\n from tkinter.messagebox import *\n\n\nimport random,math,string\nfrom score import *\nfrom time import *\nfrom menubar import *\nfrom os import path\n\n\n\ndef create_image():\n \"\"\"Défini les images nécéssaire\"\"\"\n global picBomb,picFlag\n picBomb=PhotoImage(file=\"img/bomb.gif\")\n picFlag=PhotoImage(file=\"img/flag1.gif\")\n \n\ndef damier():\n \"\"\"Crée un damier lors du lancement du jeu\"\"\"\n a=0\n \n for i in range(c):\n for j in range(h):\n labels.append(Label(can, text=v,bd=1,justify=CENTER,relief=SUNKEN,font=(\"Helvetica\", 9),image=\"\",width=1,height=1,padx=9,pady=5))\n labels[a].grid(column=i,row=j)\n \n b.append(Button(can,text=\"\",image=\"\",padx=8,pady=1)) \n b[a].grid(column=i,row=j)\n b[a].bind(\"\",lambda i,ref=a: afficheFlag(ref))\n b[a].bind(\"\",lambda i,ref=a: click(ref))\n b[a].config(relief=RAISED)\n a+=1\n bombes()\n \n \ndef bombes(charger=False):\n \"\"\"Si c'est une partie chargée cette fonction positionne les bombes à leurs emplacements sinon elle crée de nouvelles bombes\"\"\"\n create_image()\n global presentBomb\n \n if charger:\n for i in presentBomb:\n labels[i].config(text=v,image=picBomb,relief=GROOVE,bd=3,width=0,height=0)\n chiffres(i)\n else: \n presentBomb=[]\n for i in range(nbBombs):\n a=random.randint(0,maxi)\n while a in presentBomb:\n a=random.randint(0,maxi)\n labels[a].config(text=v,image=picBomb,relief=GROOVE,bd=3,width=0,height=0) \n presentBomb.append(a)\n chiffres(a)\n \n \ndef chiffres(ref):\n \"\"\"Positionne les chiffres autour des bombes\"\"\"\n\n if ref in top:\n for i in [ref-h,ref-(h-1),ref+h,ref+(h+1),ref+1]: #On parcours les positions à côter de la bombe pour mettre si possible les bombes à proximités pour le HAUT\n if i>=0 and i<=maxi:\n if labels[i].cget(\"text\")==\" \":\n v=\"1\"\n elif labels[i].cget(\"text\") in maxBomb:\n v=str(int(labels[i].cget(\"text\"))+1)\n labels[i].config(text=v)\n elif ref in down:\n for i in [ref-h,ref-(h+1),ref+h,ref+(h-1),ref-1]: #On parcours les positions à côter de la bombe pour mettre si possible les bombes à proximités pour le BAS\n if i>=0 and i<=maxi:\n if labels[i].cget(\"text\")==\" \":\n v=\"1\"\n elif labels[i].cget(\"text\") in maxBomb:\n v=str(int(labels[i].cget(\"text\"))+1)\n labels[i].config(text=v)\n else:\n for i in [ref-h,ref-(h+1),ref-(h-1),ref+h,ref+(h-1),ref+(h+1),ref-1,ref+1]: #On parcours les positions à côter de la bombe pour mettre si possible les bombes à proximités pour les autres\n if i>=0 and i<=maxi:\n if labels[i].cget(\"text\")==\" \":\n v=\"1\"\n elif labels[i].cget(\"text\") in maxBomb:\n v=str(int(labels[i].cget(\"text\"))+1)\n labels[i].config(text=v)\n\ndef click(ref):\n \"\"\"Vérifie les conditions de jeu, retourne la fonction perdu si c'est la position d'une bombe sinon on appelle la fonction 'Explore'\"\"\"\n global clique,partie_terminée\n if clique==0:\n temps()\n partie_terminée=False\n clique+=1\n b[ref].grid_forget()\n verifGagne()\n if labels[ref].cget(\"image\")!=\"\":\n perdu(ref)\n if labels[ref].cget(\"image\")==\"\" and labels[ref].cget(\"text\")==v:\n explore(ref)\n \n\n \ndef explore(ref):\n \"\"\"Contient toutes les fonctions qui doivent être appellées quand on clique sur un bouton\"\"\"\n enlever_ranger(ref)\n enlever_colonne(ref,True)\n posForget.append(ref)\n verif()\n verifGagne()\n \n\n\ndef verifGagne():\n \"\"\"Vérifie si la partie est gagnée\"\"\"\n global partie_terminée\n posFlag,posBou=[],[]\n nbBou=0\n \n for i in range(c*h):\n if labels[i].cget(\"image\")!=\"\" and b[i].grid_info()!={}:\n posBou.append(i)\n if b[i].cget(\"image\")!=\"\" and b[i].grid_info()!={}:\n posFlag.append(i)\n if labels[i].cget(\"image\")==\"\" and b[i].grid_info()=={}:\n nbBou+=1\n\n \n posFlag.sort()\n posBou.sort()\n presentBomb.sort()\n \n if posFlag==presentBomb and posBou==presentBomb and nbBou==(c*h)-nbBombs:\n\n partie_terminée=True\n time.after_cancel(timafter)\n\n if pseudo!=\"\":\n menubar.delete_save(str(pseudo))\n showwarning('Attention', \"Votre sauvegarde est supprimée, vous avez terminé votre partie !\")\n \n \n showinfo('Bien joué', \"Vous avez réussi à ne pas exploser !\\nBravo\")\n \n for i in range(c*h):\n b[i].unbind(\"\")\n b[i].unbind(\"\")\n b[i].config(state='disabled')\n \n if connecter():\n \n if askokcancel('Score','Voulez-vous enregistrer votre score ?'):\n\n def on_button():\n niveau=0\n pseudo=entree.get()\n chiffre=0\n \n if c==9 and nbBombs==10:\n niveau=1\n elif c==16 and nbBombs==40:\n niveau=2\n elif c==30 and nbBombs==99:\n niveau=3\n else:\n showerror('Erreur', \"C'est une partie personnalisée votre score ne peut être pris en compte\")\n t.destroy()\n \n bool=False\n for i in pseudo:\n if i not in string.printable[0:62]:\n bool=True\n if i in string.printable[0:10]:\n chiffre+=1\n if chiffre==len(pseudo):\n bool=True\n \n if bool:\n showerror('Erreur', 'Veuillez choisir un autre pseudo')\n entree.delete(0,len(pseudo))\n else:\n ajoute_score(pseudo, sec, niveau)\n showinfo('Sauvegarde', 'Votre score a été enregistré '+str(pseudo)+' !')\n t.destroy()\n t=Toplevel()\n t.grab_set()\n t.title('Enregistre ton score')\n t.iconbitmap('img/bomb.ico')\n t.resizable(width=False, height=False)\n l = LabelFrame(t, text=\"Votre pseudo :\", padx=12, pady=12)\n l.pack(fill=\"both\", expand=\"yes\")\n l.pack(side=LEFT)\n \n \n entree = Entry(l)\n entree.pack()\n bou=Button(t,text='Annuler',command=t.destroy)\n bou.pack(side=BOTTOM)\n bou=Button(t,text='Enregistre ton score !',command=on_button)\n bou.pack(side=BOTTOM)\n entree.pack()\n t.mainloop()\n \n else:\n showwarning('Erreur', \"Vous n'êtes pas connecté à internet\")\n \n\n \n \n \n \n\ndef afficheFlag(ref):\n \"\"\"Afiiche ou enleve le drapeau lorsque que l'on fait un clic droit\"\"\"\n if b[ref].cget(\"image\")==\"\":\n b[ref].config(image=picFlag)\n verifGagne()\n compteur_bombe()\n else:\n b[ref].config(image=\"\")\n compteur_bombe(False)\n \ndef verif(bool=False):\n \"\"\"Permet de verifier si toutes les cases ont bien été enlevées\"\"\"\n for ref in range(c*h):\n\n if ref in top and b[ref].grid_info()=={} and labels[ref].cget(\"text\")==v and labels[ref].cget(\"image\")==\"\":\n\n for i in [ref-h,ref-(h-1),ref+h,ref+(h+1),ref+1]:\n \n if i>=0 and i<=maxi and labels[i].cget(\"text\") in maxBomb and labels[i].cget(\"image\")==\"\":\n b[i].grid_forget()\n elif i>=0 and i<=maxi and labels[i].cget(\"text\")==v and labels[i].cget(\"image\")==\"\" and bool and i not in posForget:\n b[i].grid_forget()\n enlever_ranger(ref)\n enlever_colonne(i,True)\n posForget.append(i)\n verif()\n \n \n\n elif ref in down and b[ref].grid_info()=={} and labels[ref].cget(\"text\")==v and labels[ref].cget(\"image\")==\"\":\n\n for i in [ref-h,ref-(h+1),ref+h,ref+(h-1),ref-1]:\n\n if i>=0 and i<=maxi and labels[i].cget(\"text\") in maxBomb and labels[i].cget(\"image\")==\"\" :\n b[i].grid_forget()\n elif i>=0 and i<=maxi and labels[i].cget(\"text\")==v and labels[i].cget(\"image\")==\"\" and bool and i not in posForget:\n b[i].grid_forget()\n enlever_ranger(ref)\n enlever_colonne(i,True)\n posForget.append(i)\n verif()\n \n \n elif b[ref].grid_info()=={} and labels[ref].cget(\"text\")==v and labels[ref].cget(\"image\")==\"\":\n\n for i in [ref-h,ref-(h+1),ref-(h-1),ref+h,ref+(h-1),ref+(h+1),ref-1,ref+1]:\n\n if i>=0 and i<=maxi and labels[i].cget(\"text\") in maxBomb and labels[i].cget(\"image\")==\"\":\n b[i].grid_forget()\n elif i>=0 and i<=maxi and labels[i].cget(\"text\")==v and labels[i].cget(\"image\")==\"\" and bool and i not in posForget:\n b[i].grid_forget()\n enlever_ranger(ref)\n enlever_colonne(i,True)\n posForget.append(i)\n verif()\n \n \n \ndef enlever_ranger(pos):\n \"\"\"Permet d'enlever les boutons d'une rangée de droite et de gauche jusqu'à ce qu'on rencontre un chiffe dans un label\"\"\"\n left=pos-h\n right=pos+h\n \n while left>=0 and labels[left].cget(\"text\")==\" \":\n if b[left].grid_info()!={}:\n b[left].grid_forget()\n \n enlever_colonne(left,True)\n \n \n left-=h\n \n while right<=maxi and labels[right].cget(\"text\")==\" \":\n if b[right].grid_info()!={}:\n b[right].grid_forget()\n enlever_colonne(right,True)\n \n \n \n right+=h\n\ndef enlever_colonne(pos, bool=False):\n \"\"\"Permet d'enlever les boutons d'une colonne du bas et du haut jusqu'à ce qu'on rencontre un chiffre dans un label\"\"\"\n d=pos-1\n up=pos+1\n \n\n while d not in down and labels[d].cget(\"text\")==\" \" and labels[d].cget(\"image\")==\"\" and d>=0 and d=0 and up\")\n b[i].unbind(\"\")\n b[i].config(state='disabled')\n\n \n showinfo('Perdu', 'Vous avez fait exploser la mine')\n\ndef supprimer():\n \"\"\"Supprime les infos de la partie précédente.\"\"\"\n global b,labels\n for i in range(len(b)):\n b[i].grid_remove()\n b[i].destroy()\n labels[i].grid_remove()\n labels[i].destroy()\n b=[]\n labels=[]\n\n\ndef nouveau(charger=False,bombe=[],pos=[],bouton=[],flag=[],name=\"\"):\n \n \"\"\" Permet de creer un nouveau damier avec de nouvelle bombes, de plus si le paramètre charger est True\n alors on charge la sauvegarde grâce à la fonction charge() de menubar.py\"\"\"\n global presentBomb,posForget,sec,compteur_bombes,pseudo,partie_terminée,clique,top,down\n\n partie_terminée=True\n clique = 0\n pseudo=name\n compteur_bombes=nbBombs\n compteur['text']='Bombes restantes : '+str(compteur_bombes)\n \n time.after_cancel(timafter)\n \n \n supprimer()\n posForget=[]\n presentBomb=[]\n \n if charger:\n presentBomb=bombe\n posForget=pos\n else:\n sec=0\n time['text'] = 'Temps : ' + strftime('%M : %S', gmtime(sec))\n \n can.pack_forget()\n \n top=[]\n down=[]\n top.append(0)\n for i in range(h):\n top.append((i+1)*h)\n down.append(((i+1)*h)-1)\n down.append(c*h)\n \n a=0\n for i in range(c):\n for j in range(h):\n labels.append(Label(can, text=v,bd=1,relief=SUNKEN,font=(\"Helvetica\", 9),width=1,height=1,justify=CENTER,padx=9,pady=5))\n labels[a].grid(column=i,row=j)\n b.append(Button(can,text=\"\",image=\"\",padx=8,pady=1))\n b[a].grid(column=i,row=j)\n b[a].bind(\"\",lambda i,ref=a: afficheFlag(ref))\n b[a].bind(\"\",lambda i,ref=a: click(ref))\n b[a].config(text=\"\",image=\"\")\n a+=1\n \n if charger:\n \n for i in bouton:\n b[i].grid_forget()\n bombes(True)\n else:\n bombes()\n\n \n can.pack(side=TOP,expand=True)\n if charger:\n for i in flag:\n \n afficheFlag(i)\n timer()\n partie_terminée=False\n clique=1\n \ndef recup_info_partie():\n \"\"\"Récupère les informations de la partie en cours \"\"\"\n\n b_forget=[]\n flag=[]\n taille_interface=c\n for i in range(c*h):\n if b[i].grid_info()=={}:\n b_forget.append(i)\n if b[i].cget(\"image\")!=\"\":\n flag.append(i)\n return presentBomb,posForget,b_forget,flag,taille_interface,sec\n\ndef option(nbmines, taille_interface,bool=True,s=0):\n \"\"\" Permet de définir les options définis par la commande option du menu. \"\"\"\n\n global c,maxi,nbBombs,top,down,h,sec\n\n sec=s\n c = taille_interface\n maxi=(c*c)-1\n h=c\n if taille_interface==30:\n h=16\n maxi=(c*16)-1\n \n nbBombs = int(nbmines)\n \n\n if bool:\n nouveau()\n\ndef timer(bool=False):\n \"\"\"Arrête ou démarre le timer en fonction de la variable bool\"\"\"\n global timafter\n if bool:\n time.after_cancel(timafter)\n else:\n timafter = time.after(1000, temps)\n\ndef temps():\n \"\"\"Affiche le temps dans la fenètre principale\"\"\"\n global sec,timafter\n sec += 1\n time['text'] = 'Temps : ' + strftime('%M : %S', gmtime(sec))\n \n timafter = time.after(1000, temps)\n\ndef compteur_bombe(bool=True):\n \"\"\"Affiche dans la fenètre principale le nombres de bombes encore à trouver\"\"\"\n global compteur_bombes\n if bool:\n compteur_bombes-=1\n elif bool==False and compteur_bombes+1<=nbBombs:\n compteur_bombes+=1\n compteur['text']='Bombes restantes : '+str(compteur_bombes)\n \n if compteur_bombes<=0:\n compteur['text']='Bombes restantes : 0'\n\ndef pseudo_partie():\n \"\"\"Retourne la valeur pseudo pour menubar.py\"\"\" \n return pseudo\n \n\ndef etat_partie():\n \"\"\"Retourne l'état de la partie, \n terminée = True \n non terminée = False \n fonction créée pour menubar.py\"\"\"\n return partie_terminée\n \n######Programme ######\n\n\n\nc=9 \nnbBombs=10 \nw=200\nh=200 \n\ncompteur_bombes=nbBombs\n\nh=c\nposForget=[]\nmaxBomb=[\"1\",\"2\",\"3\",\"4\",\"5\",\"6\",\"7\",\"8\"]\npresentBomb=[]\nmaxi=(c*h)-1\nlabels=[]\nb = []\nv = \" \"\n\n\n\npseudo=\"\"\npartie_terminée=True\nclique=0\n\ntop=[]\ndown=[]\ntop.append(0)\nfor i in range(h):\n top.append((i+1)*c)\n down.append(((i+1)*c)-1)\ndown.append(c*h)\n\n\nsec=0\n\nfen = Tk()\nmenubar = MenuBar(fen,nouveau,recup_info_partie,option,timer,etat_partie,pseudo_partie)\nfen.title('Démineur')\nfen.resizable(width=False, height=False)\nfen.config(menu=menubar)\n\nframe= LabelFrame(fen,bd=2)\nframe.pack(side=TOP,fill=X)\ncan = Canvas(fen, width=w, height=h, background='white')\n\ntime = Label(frame, fg='Black')\ntime.pack(side=LEFT)\ntime['text'] = 'Temps : ' + strftime('%M : %S', gmtime(sec))\ntimafter = time.after(1000, temps)\ntime.after_cancel(timafter)\ncompteur = Label(frame, fg='Black')\ncompteur.pack(side=RIGHT)\ncompteur['text']='Bombes restantes : '+str(compteur_bombes)\n\ncreate_image()\ndamier()\n\n\nfen.iconbitmap('img/bomb.ico')\n\n \ncan.pack(side=BOTTOM,expand=True)\n\nfen.mainloop()\n","python",[530,5127,5128,5133,5138,5143,5147,5152,5156,5161,5166,5171,5176,5181,5186,5191,5196,5200,5205,5210,5215,5219,5223,5228,5233,5239,5245,5251,5256,5261,5266,5272,5278,5284,5290,5296,5302,5307,5313,5319,5325,5330,5336,5342,5348,5354,5360,5366,5372,5378,5384,5390,5396,5402,5407,5412,5418,5424,5430,5436,5441,5447,5453,5459,5465,5471,5477,5483,5489,5495,5501,5507,5513,5519,5524,5529,5535,5541,5546,5552,5558,5564,5570,5576,5582,5588,5594,5600,5606,5611,5616,5621,5626,5631,5636,5642,5648,5653,5658,5663,5668,5673,5678,5683,5689,5695,5701,5707,5713,5719,5725,5731,5737,5743,5749,5755,5761,5767,5772,5777,5783,5789,5795,5801,5807,5813,5818,5823,5828,5833,5839,5845,5851,5857,5863,5868,5874,5880,5886,5892,5898,5904,5910,5915,5920,5926,5932,5938,5943,5949,5954,5960,5966,5971,5977,5983,5989,5994,5999,6005,6010,6016,6022,6028,6034,6039,6045,6050,6056,6061,6067,6073,6079,6085,6091,6097,6103,6109,6115,6121,6127,6133,6139,6145,6151,6157,6163,6169,6175,6181,6187,6193,6199,6204,6210,6216,6222,6227,6233,6239,6244,6250,6256,6262,6268,6274,6280,6286,6292,6298,6303,6309,6315,6321,6327,6333,6338,6343,6349,6354,6360,6366,6371,6376,6381,6386,6391,6396,6401,6407,6413,6419,6425,6431,6437,6442,6448,6454,6459,6465,6471,6477,6482,6488,6493,6499,6504,6510,6516,6522,6527,6533,6539,6545,6551,6556,6561,6566,6572,6577,6583,6588,6594,6599,6604,6609,6614,6619,6624,6629,6634,6639,6645,6650,6656,6661,6666,6671,6676,6681,6686,6691,6696,6701,6707,6713,6718,6724,6730,6736,6742,6748,6754,6760,6766,6772,6778,6783,6788,6794,6799,6805,6811,6817,6823,6828,6833,6838,6844,6849,6855,6861,6867,6873,6878,6883,6889,6895,6901,6906,6912,6918,6923,6929,6934,6939,6945,6950,6956,6962,6967,6972,6978,6983,6989,6994,6999,7005,7011,7016,7022,7027,7033,7039,7045,7051,7057,7062,7067,7073,7079,7084,7090,7096,7102,7107,7112,7118,7123,7129,7135,7141,7147,7153,7159,7165,7171,7177,7183,7188,7193,7199,7204,7210,7216,7222,7227,7232,7238,7244,7250,7256,7261,7267,7272,7277,7283,7289,7295,7300,7305,7311,7317,7322,7328,7334,7339,7345,7350,7356,7362,7368,7374,7380,7386,7392,7397,7402,7407,7412,7418,7423,7429,7434,7439,7444,7450,7455,7460,7465,7470,7476,7481,7487,7492,7498,7503,7508,7514,7519,7525,7530,7536,7542,7547,7553,7558,7564,7570,7575,7581,7587,7593,7598,7604,7610,7616,7622,7628,7633,7639,7645,7650,7656,7661,7667,7673,7679,7685,7691,7697,7703,7708,7714,7719,7724,7730,7736,7741,7747,7753,7759,7764,7769,7774,7780,7785,7791,7797,7803,7809,7814,7819,7825,7830,7836,7842,7848,7853,7859,7865,7871,7876,7881,7887,7893,7898,7904,7910,7916,7921,7926,7932,7938,7944,7950,7956,7962,7967,7973,7978,7983,7988,7994,8000,8006,8012,8017,8023,8028,8034,8040,8046,8052,8058,8064,8070,8076,8081,8086,8091,8097,8103,8109,8114,8120,8126,8132,8138,8144,8150,8156,8161,8166,8172,8177,8183,8189,8195,8201,8207,8212,8218,8224,8230,8235,8241,8247,8253,8259,8265,8271,8277,8283,8288,8294,8300,8305,8310,8316,8321,8326,8332,8337],{"__ignoreMap":369},[1761,5129,5130],{"class":1763,"line":1764},[1761,5131,5132],{},"\"\"\"\n",[1761,5134,5135],{"class":1763,"line":370},[1761,5136,5137],{},"Programme principal du code du démineur. \n",[1761,5139,5140],{"class":1763,"line":380},[1761,5141,5142],{}," Tous droits réservés Demisn © 2016\n",[1761,5144,5145],{"class":1763,"line":1780},[1761,5146,1783],{"emptyLinePlaceholder":55},[1761,5148,5149],{"class":1763,"line":1589},[1761,5150,5151],{},"menubar.py, ainsi que score.py sont essentiels au bon fonctionnement du programme.\n",[1761,5153,5154],{"class":1763,"line":1791},[1761,5155,5132],{},[1761,5157,5158],{"class":1763,"line":1797},[1761,5159,5160],{},"try:\n",[1761,5162,5163],{"class":1763,"line":941},[1761,5164,5165],{}," # Python2\n",[1761,5167,5168],{"class":1763,"line":2182},[1761,5169,5170],{}," #!/usr/bin/python2.7\n",[1761,5172,5173],{"class":1763,"line":394},[1761,5174,5175],{}," # -*-coding:Latin-1 -*\n",[1761,5177,5178],{"class":1763,"line":2193},[1761,5179,5180],{}," from Tkinter import *\n",[1761,5182,5183],{"class":1763,"line":2199},[1761,5184,5185],{}," from tkMessageBox import *\n",[1761,5187,5188],{"class":1763,"line":2205},[1761,5189,5190],{},"except ImportError:\n",[1761,5192,5193],{"class":1763,"line":2211},[1761,5194,5195],{}," #!/usr/bin/python3.5\n",[1761,5197,5198],{"class":1763,"line":2977},[1761,5199,5175],{},[1761,5201,5202],{"class":1763,"line":2995},[1761,5203,5204],{}," # Python3\n",[1761,5206,5207],{"class":1763,"line":3010},[1761,5208,5209],{}," from tkinter import *\n",[1761,5211,5212],{"class":1763,"line":3029},[1761,5213,5214],{}," from tkinter.messagebox import *\n",[1761,5216,5217],{"class":1763,"line":3043},[1761,5218,1783],{"emptyLinePlaceholder":55},[1761,5220,5221],{"class":1763,"line":3054},[1761,5222,1783],{"emptyLinePlaceholder":55},[1761,5224,5225],{"class":1763,"line":3059},[1761,5226,5227],{},"import random,math,string\n",[1761,5229,5230],{"class":1763,"line":3090},[1761,5231,5232],{},"from score import *\n",[1761,5234,5236],{"class":1763,"line":5235},23,[1761,5237,5238],{},"from time import *\n",[1761,5240,5242],{"class":1763,"line":5241},24,[1761,5243,5244],{},"from menubar import *\n",[1761,5246,5248],{"class":1763,"line":5247},25,[1761,5249,5250],{},"from os import path\n",[1761,5252,5254],{"class":1763,"line":5253},26,[1761,5255,1783],{"emptyLinePlaceholder":55},[1761,5257,5259],{"class":1763,"line":5258},27,[1761,5260,1783],{"emptyLinePlaceholder":55},[1761,5262,5264],{"class":1763,"line":5263},28,[1761,5265,1783],{"emptyLinePlaceholder":55},[1761,5267,5269],{"class":1763,"line":5268},29,[1761,5270,5271],{},"def create_image():\n",[1761,5273,5275],{"class":1763,"line":5274},30,[1761,5276,5277],{}," \"\"\"Défini les images nécéssaire\"\"\"\n",[1761,5279,5281],{"class":1763,"line":5280},31,[1761,5282,5283],{}," global picBomb,picFlag\n",[1761,5285,5287],{"class":1763,"line":5286},32,[1761,5288,5289],{}," picBomb=PhotoImage(file=\"img/bomb.gif\")\n",[1761,5291,5293],{"class":1763,"line":5292},33,[1761,5294,5295],{}," picFlag=PhotoImage(file=\"img/flag1.gif\")\n",[1761,5297,5299],{"class":1763,"line":5298},34,[1761,5300,5301],{}," \n",[1761,5303,5305],{"class":1763,"line":5304},35,[1761,5306,1783],{"emptyLinePlaceholder":55},[1761,5308,5310],{"class":1763,"line":5309},36,[1761,5311,5312],{},"def damier():\n",[1761,5314,5316],{"class":1763,"line":5315},37,[1761,5317,5318],{}," \"\"\"Crée un damier lors du lancement du jeu\"\"\"\n",[1761,5320,5322],{"class":1763,"line":5321},38,[1761,5323,5324],{}," a=0\n",[1761,5326,5328],{"class":1763,"line":5327},39,[1761,5329,5301],{},[1761,5331,5333],{"class":1763,"line":5332},40,[1761,5334,5335],{}," for i in range(c):\n",[1761,5337,5339],{"class":1763,"line":5338},41,[1761,5340,5341],{}," for j in range(h):\n",[1761,5343,5345],{"class":1763,"line":5344},42,[1761,5346,5347],{}," labels.append(Label(can, text=v,bd=1,justify=CENTER,relief=SUNKEN,font=(\"Helvetica\", 9),image=\"\",width=1,height=1,padx=9,pady=5))\n",[1761,5349,5351],{"class":1763,"line":5350},43,[1761,5352,5353],{}," labels[a].grid(column=i,row=j)\n",[1761,5355,5357],{"class":1763,"line":5356},44,[1761,5358,5359],{}," \n",[1761,5361,5363],{"class":1763,"line":5362},45,[1761,5364,5365],{}," b.append(Button(can,text=\"\",image=\"\",padx=8,pady=1)) \n",[1761,5367,5369],{"class":1763,"line":5368},46,[1761,5370,5371],{}," b[a].grid(column=i,row=j)\n",[1761,5373,5375],{"class":1763,"line":5374},47,[1761,5376,5377],{}," b[a].bind(\"\",lambda i,ref=a: afficheFlag(ref))\n",[1761,5379,5381],{"class":1763,"line":5380},48,[1761,5382,5383],{}," b[a].bind(\"\",lambda i,ref=a: click(ref))\n",[1761,5385,5387],{"class":1763,"line":5386},49,[1761,5388,5389],{}," b[a].config(relief=RAISED)\n",[1761,5391,5393],{"class":1763,"line":5392},50,[1761,5394,5395],{}," a+=1\n",[1761,5397,5399],{"class":1763,"line":5398},51,[1761,5400,5401],{}," bombes()\n",[1761,5403,5405],{"class":1763,"line":5404},52,[1761,5406,5301],{},[1761,5408,5410],{"class":1763,"line":5409},53,[1761,5411,5359],{},[1761,5413,5415],{"class":1763,"line":5414},54,[1761,5416,5417],{},"def bombes(charger=False):\n",[1761,5419,5421],{"class":1763,"line":5420},55,[1761,5422,5423],{}," \"\"\"Si c'est une partie chargée cette fonction positionne les bombes à leurs emplacements sinon elle crée de nouvelles bombes\"\"\"\n",[1761,5425,5427],{"class":1763,"line":5426},56,[1761,5428,5429],{}," create_image()\n",[1761,5431,5433],{"class":1763,"line":5432},57,[1761,5434,5435],{}," global presentBomb\n",[1761,5437,5439],{"class":1763,"line":5438},58,[1761,5440,5301],{},[1761,5442,5444],{"class":1763,"line":5443},59,[1761,5445,5446],{}," if charger:\n",[1761,5448,5450],{"class":1763,"line":5449},60,[1761,5451,5452],{}," for i in presentBomb:\n",[1761,5454,5456],{"class":1763,"line":5455},61,[1761,5457,5458],{}," labels[i].config(text=v,image=picBomb,relief=GROOVE,bd=3,width=0,height=0)\n",[1761,5460,5462],{"class":1763,"line":5461},62,[1761,5463,5464],{}," chiffres(i)\n",[1761,5466,5468],{"class":1763,"line":5467},63,[1761,5469,5470],{}," else: \n",[1761,5472,5474],{"class":1763,"line":5473},64,[1761,5475,5476],{}," presentBomb=[]\n",[1761,5478,5480],{"class":1763,"line":5479},65,[1761,5481,5482],{}," for i in range(nbBombs):\n",[1761,5484,5486],{"class":1763,"line":5485},66,[1761,5487,5488],{}," a=random.randint(0,maxi)\n",[1761,5490,5492],{"class":1763,"line":5491},67,[1761,5493,5494],{}," while a in presentBomb:\n",[1761,5496,5498],{"class":1763,"line":5497},68,[1761,5499,5500],{}," a=random.randint(0,maxi)\n",[1761,5502,5504],{"class":1763,"line":5503},69,[1761,5505,5506],{}," labels[a].config(text=v,image=picBomb,relief=GROOVE,bd=3,width=0,height=0) \n",[1761,5508,5510],{"class":1763,"line":5509},70,[1761,5511,5512],{}," presentBomb.append(a)\n",[1761,5514,5516],{"class":1763,"line":5515},71,[1761,5517,5518],{}," chiffres(a)\n",[1761,5520,5522],{"class":1763,"line":5521},72,[1761,5523,5301],{},[1761,5525,5527],{"class":1763,"line":5526},73,[1761,5528,5301],{},[1761,5530,5532],{"class":1763,"line":5531},74,[1761,5533,5534],{},"def chiffres(ref):\n",[1761,5536,5538],{"class":1763,"line":5537},75,[1761,5539,5540],{}," \"\"\"Positionne les chiffres autour des bombes\"\"\"\n",[1761,5542,5544],{"class":1763,"line":5543},76,[1761,5545,1783],{"emptyLinePlaceholder":55},[1761,5547,5549],{"class":1763,"line":5548},77,[1761,5550,5551],{}," if ref in top:\n",[1761,5553,5555],{"class":1763,"line":5554},78,[1761,5556,5557],{}," for i in [ref-h,ref-(h-1),ref+h,ref+(h+1),ref+1]: #On parcours les positions à côter de la bombe pour mettre si possible les bombes à proximités pour le HAUT\n",[1761,5559,5561],{"class":1763,"line":5560},79,[1761,5562,5563],{}," if i>=0 and i<=maxi:\n",[1761,5565,5567],{"class":1763,"line":5566},80,[1761,5568,5569],{}," if labels[i].cget(\"text\")==\" \":\n",[1761,5571,5573],{"class":1763,"line":5572},81,[1761,5574,5575],{}," v=\"1\"\n",[1761,5577,5579],{"class":1763,"line":5578},82,[1761,5580,5581],{}," elif labels[i].cget(\"text\") in maxBomb:\n",[1761,5583,5585],{"class":1763,"line":5584},83,[1761,5586,5587],{}," v=str(int(labels[i].cget(\"text\"))+1)\n",[1761,5589,5591],{"class":1763,"line":5590},84,[1761,5592,5593],{}," labels[i].config(text=v)\n",[1761,5595,5597],{"class":1763,"line":5596},85,[1761,5598,5599],{}," elif ref in down:\n",[1761,5601,5603],{"class":1763,"line":5602},86,[1761,5604,5605],{}," for i in [ref-h,ref-(h+1),ref+h,ref+(h-1),ref-1]: #On parcours les positions à côter de la bombe pour mettre si possible les bombes à proximités pour le BAS\n",[1761,5607,5609],{"class":1763,"line":5608},87,[1761,5610,5563],{},[1761,5612,5614],{"class":1763,"line":5613},88,[1761,5615,5569],{},[1761,5617,5619],{"class":1763,"line":5618},89,[1761,5620,5575],{},[1761,5622,5624],{"class":1763,"line":5623},90,[1761,5625,5581],{},[1761,5627,5629],{"class":1763,"line":5628},91,[1761,5630,5587],{},[1761,5632,5634],{"class":1763,"line":5633},92,[1761,5635,5593],{},[1761,5637,5639],{"class":1763,"line":5638},93,[1761,5640,5641],{}," else:\n",[1761,5643,5645],{"class":1763,"line":5644},94,[1761,5646,5647],{}," for i in [ref-h,ref-(h+1),ref-(h-1),ref+h,ref+(h-1),ref+(h+1),ref-1,ref+1]: #On parcours les positions à côter de la bombe pour mettre si possible les bombes à proximités pour les autres\n",[1761,5649,5651],{"class":1763,"line":5650},95,[1761,5652,5563],{},[1761,5654,5656],{"class":1763,"line":5655},96,[1761,5657,5569],{},[1761,5659,5661],{"class":1763,"line":5660},97,[1761,5662,5575],{},[1761,5664,5666],{"class":1763,"line":5665},98,[1761,5667,5581],{},[1761,5669,5671],{"class":1763,"line":5670},99,[1761,5672,5587],{},[1761,5674,5676],{"class":1763,"line":5675},100,[1761,5677,5593],{},[1761,5679,5681],{"class":1763,"line":5680},101,[1761,5682,1783],{"emptyLinePlaceholder":55},[1761,5684,5686],{"class":1763,"line":5685},102,[1761,5687,5688],{},"def click(ref):\n",[1761,5690,5692],{"class":1763,"line":5691},103,[1761,5693,5694],{}," \"\"\"Vérifie les conditions de jeu, retourne la fonction perdu si c'est la position d'une bombe sinon on appelle la fonction 'Explore'\"\"\"\n",[1761,5696,5698],{"class":1763,"line":5697},104,[1761,5699,5700],{}," global clique,partie_terminée\n",[1761,5702,5704],{"class":1763,"line":5703},105,[1761,5705,5706],{}," if clique==0:\n",[1761,5708,5710],{"class":1763,"line":5709},106,[1761,5711,5712],{}," temps()\n",[1761,5714,5716],{"class":1763,"line":5715},107,[1761,5717,5718],{}," partie_terminée=False\n",[1761,5720,5722],{"class":1763,"line":5721},108,[1761,5723,5724],{}," clique+=1\n",[1761,5726,5728],{"class":1763,"line":5727},109,[1761,5729,5730],{}," b[ref].grid_forget()\n",[1761,5732,5734],{"class":1763,"line":5733},110,[1761,5735,5736],{}," verifGagne()\n",[1761,5738,5740],{"class":1763,"line":5739},111,[1761,5741,5742],{}," if labels[ref].cget(\"image\")!=\"\":\n",[1761,5744,5746],{"class":1763,"line":5745},112,[1761,5747,5748],{}," perdu(ref)\n",[1761,5750,5752],{"class":1763,"line":5751},113,[1761,5753,5754],{}," if labels[ref].cget(\"image\")==\"\" and labels[ref].cget(\"text\")==v:\n",[1761,5756,5758],{"class":1763,"line":5757},114,[1761,5759,5760],{}," explore(ref)\n",[1761,5762,5764],{"class":1763,"line":5763},115,[1761,5765,5766],{}," \n",[1761,5768,5770],{"class":1763,"line":5769},116,[1761,5771,1783],{"emptyLinePlaceholder":55},[1761,5773,5775],{"class":1763,"line":5774},117,[1761,5776,5301],{},[1761,5778,5780],{"class":1763,"line":5779},118,[1761,5781,5782],{},"def explore(ref):\n",[1761,5784,5786],{"class":1763,"line":5785},119,[1761,5787,5788],{}," \"\"\"Contient toutes les fonctions qui doivent être appellées quand on clique sur un bouton\"\"\"\n",[1761,5790,5792],{"class":1763,"line":5791},120,[1761,5793,5794],{}," enlever_ranger(ref)\n",[1761,5796,5798],{"class":1763,"line":5797},121,[1761,5799,5800],{}," enlever_colonne(ref,True)\n",[1761,5802,5804],{"class":1763,"line":5803},122,[1761,5805,5806],{}," posForget.append(ref)\n",[1761,5808,5810],{"class":1763,"line":5809},123,[1761,5811,5812],{}," verif()\n",[1761,5814,5816],{"class":1763,"line":5815},124,[1761,5817,5736],{},[1761,5819,5821],{"class":1763,"line":5820},125,[1761,5822,5301],{},[1761,5824,5826],{"class":1763,"line":5825},126,[1761,5827,1783],{"emptyLinePlaceholder":55},[1761,5829,5831],{"class":1763,"line":5830},127,[1761,5832,1783],{"emptyLinePlaceholder":55},[1761,5834,5836],{"class":1763,"line":5835},128,[1761,5837,5838],{},"def verifGagne():\n",[1761,5840,5842],{"class":1763,"line":5841},129,[1761,5843,5844],{}," \"\"\"Vérifie si la partie est gagnée\"\"\"\n",[1761,5846,5848],{"class":1763,"line":5847},130,[1761,5849,5850],{}," global partie_terminée\n",[1761,5852,5854],{"class":1763,"line":5853},131,[1761,5855,5856],{}," posFlag,posBou=[],[]\n",[1761,5858,5860],{"class":1763,"line":5859},132,[1761,5861,5862],{}," nbBou=0\n",[1761,5864,5866],{"class":1763,"line":5865},133,[1761,5867,5301],{},[1761,5869,5871],{"class":1763,"line":5870},134,[1761,5872,5873],{}," for i in range(c*h):\n",[1761,5875,5877],{"class":1763,"line":5876},135,[1761,5878,5879],{}," if labels[i].cget(\"image\")!=\"\" and b[i].grid_info()!={}:\n",[1761,5881,5883],{"class":1763,"line":5882},136,[1761,5884,5885],{}," posBou.append(i)\n",[1761,5887,5889],{"class":1763,"line":5888},137,[1761,5890,5891],{}," if b[i].cget(\"image\")!=\"\" and b[i].grid_info()!={}:\n",[1761,5893,5895],{"class":1763,"line":5894},138,[1761,5896,5897],{}," posFlag.append(i)\n",[1761,5899,5901],{"class":1763,"line":5900},139,[1761,5902,5903],{}," if labels[i].cget(\"image\")==\"\" and b[i].grid_info()=={}:\n",[1761,5905,5907],{"class":1763,"line":5906},140,[1761,5908,5909],{}," nbBou+=1\n",[1761,5911,5913],{"class":1763,"line":5912},141,[1761,5914,1783],{"emptyLinePlaceholder":55},[1761,5916,5918],{"class":1763,"line":5917},142,[1761,5919,5359],{},[1761,5921,5923],{"class":1763,"line":5922},143,[1761,5924,5925],{}," posFlag.sort()\n",[1761,5927,5929],{"class":1763,"line":5928},144,[1761,5930,5931],{}," posBou.sort()\n",[1761,5933,5935],{"class":1763,"line":5934},145,[1761,5936,5937],{}," presentBomb.sort()\n",[1761,5939,5941],{"class":1763,"line":5940},146,[1761,5942,5301],{},[1761,5944,5946],{"class":1763,"line":5945},147,[1761,5947,5948],{}," if posFlag==presentBomb and posBou==presentBomb and nbBou==(c*h)-nbBombs:\n",[1761,5950,5952],{"class":1763,"line":5951},148,[1761,5953,1783],{"emptyLinePlaceholder":55},[1761,5955,5957],{"class":1763,"line":5956},149,[1761,5958,5959],{}," partie_terminée=True\n",[1761,5961,5963],{"class":1763,"line":5962},150,[1761,5964,5965],{}," time.after_cancel(timafter)\n",[1761,5967,5969],{"class":1763,"line":5968},151,[1761,5970,1783],{"emptyLinePlaceholder":55},[1761,5972,5974],{"class":1763,"line":5973},152,[1761,5975,5976],{}," if pseudo!=\"\":\n",[1761,5978,5980],{"class":1763,"line":5979},153,[1761,5981,5982],{}," menubar.delete_save(str(pseudo))\n",[1761,5984,5986],{"class":1763,"line":5985},154,[1761,5987,5988],{}," showwarning('Attention', \"Votre sauvegarde est supprimée, vous avez terminé votre partie !\")\n",[1761,5990,5992],{"class":1763,"line":5991},155,[1761,5993,5359],{},[1761,5995,5997],{"class":1763,"line":5996},156,[1761,5998,5766],{},[1761,6000,6002],{"class":1763,"line":6001},157,[1761,6003,6004],{}," showinfo('Bien joué', \"Vous avez réussi à ne pas exploser !\\nBravo\")\n",[1761,6006,6008],{"class":1763,"line":6007},158,[1761,6009,5766],{},[1761,6011,6013],{"class":1763,"line":6012},159,[1761,6014,6015],{}," for i in range(c*h):\n",[1761,6017,6019],{"class":1763,"line":6018},160,[1761,6020,6021],{}," b[i].unbind(\"\")\n",[1761,6023,6025],{"class":1763,"line":6024},161,[1761,6026,6027],{}," b[i].unbind(\"\")\n",[1761,6029,6031],{"class":1763,"line":6030},162,[1761,6032,6033],{}," b[i].config(state='disabled')\n",[1761,6035,6037],{"class":1763,"line":6036},163,[1761,6038,5359],{},[1761,6040,6042],{"class":1763,"line":6041},164,[1761,6043,6044],{}," if connecter():\n",[1761,6046,6048],{"class":1763,"line":6047},165,[1761,6049,5359],{},[1761,6051,6053],{"class":1763,"line":6052},166,[1761,6054,6055],{}," if askokcancel('Score','Voulez-vous enregistrer votre score ?'):\n",[1761,6057,6059],{"class":1763,"line":6058},167,[1761,6060,1783],{"emptyLinePlaceholder":55},[1761,6062,6064],{"class":1763,"line":6063},168,[1761,6065,6066],{}," def on_button():\n",[1761,6068,6070],{"class":1763,"line":6069},169,[1761,6071,6072],{}," niveau=0\n",[1761,6074,6076],{"class":1763,"line":6075},170,[1761,6077,6078],{}," pseudo=entree.get()\n",[1761,6080,6082],{"class":1763,"line":6081},171,[1761,6083,6084],{}," chiffre=0\n",[1761,6086,6088],{"class":1763,"line":6087},172,[1761,6089,6090],{}," \n",[1761,6092,6094],{"class":1763,"line":6093},173,[1761,6095,6096],{}," if c==9 and nbBombs==10:\n",[1761,6098,6100],{"class":1763,"line":6099},174,[1761,6101,6102],{}," niveau=1\n",[1761,6104,6106],{"class":1763,"line":6105},175,[1761,6107,6108],{}," elif c==16 and nbBombs==40:\n",[1761,6110,6112],{"class":1763,"line":6111},176,[1761,6113,6114],{}," niveau=2\n",[1761,6116,6118],{"class":1763,"line":6117},177,[1761,6119,6120],{}," elif c==30 and nbBombs==99:\n",[1761,6122,6124],{"class":1763,"line":6123},178,[1761,6125,6126],{}," niveau=3\n",[1761,6128,6130],{"class":1763,"line":6129},179,[1761,6131,6132],{}," else:\n",[1761,6134,6136],{"class":1763,"line":6135},180,[1761,6137,6138],{}," showerror('Erreur', \"C'est une partie personnalisée votre score ne peut être pris en compte\")\n",[1761,6140,6142],{"class":1763,"line":6141},181,[1761,6143,6144],{}," t.destroy()\n",[1761,6146,6148],{"class":1763,"line":6147},182,[1761,6149,6150],{}," \n",[1761,6152,6154],{"class":1763,"line":6153},183,[1761,6155,6156],{}," bool=False\n",[1761,6158,6160],{"class":1763,"line":6159},184,[1761,6161,6162],{}," for i in pseudo:\n",[1761,6164,6166],{"class":1763,"line":6165},185,[1761,6167,6168],{}," if i not in string.printable[0:62]:\n",[1761,6170,6172],{"class":1763,"line":6171},186,[1761,6173,6174],{}," bool=True\n",[1761,6176,6178],{"class":1763,"line":6177},187,[1761,6179,6180],{}," if i in string.printable[0:10]:\n",[1761,6182,6184],{"class":1763,"line":6183},188,[1761,6185,6186],{}," chiffre+=1\n",[1761,6188,6190],{"class":1763,"line":6189},189,[1761,6191,6192],{}," if chiffre==len(pseudo):\n",[1761,6194,6196],{"class":1763,"line":6195},190,[1761,6197,6198],{}," bool=True\n",[1761,6200,6202],{"class":1763,"line":6201},191,[1761,6203,6150],{},[1761,6205,6207],{"class":1763,"line":6206},192,[1761,6208,6209],{}," if bool:\n",[1761,6211,6213],{"class":1763,"line":6212},193,[1761,6214,6215],{}," showerror('Erreur', 'Veuillez choisir un autre pseudo')\n",[1761,6217,6219],{"class":1763,"line":6218},194,[1761,6220,6221],{}," entree.delete(0,len(pseudo))\n",[1761,6223,6225],{"class":1763,"line":6224},195,[1761,6226,6132],{},[1761,6228,6230],{"class":1763,"line":6229},196,[1761,6231,6232],{}," ajoute_score(pseudo, sec, niveau)\n",[1761,6234,6236],{"class":1763,"line":6235},197,[1761,6237,6238],{}," showinfo('Sauvegarde', 'Votre score a été enregistré '+str(pseudo)+' !')\n",[1761,6240,6242],{"class":1763,"line":6241},198,[1761,6243,6144],{},[1761,6245,6247],{"class":1763,"line":6246},199,[1761,6248,6249],{}," t=Toplevel()\n",[1761,6251,6253],{"class":1763,"line":6252},200,[1761,6254,6255],{}," t.grab_set()\n",[1761,6257,6259],{"class":1763,"line":6258},201,[1761,6260,6261],{}," t.title('Enregistre ton score')\n",[1761,6263,6265],{"class":1763,"line":6264},202,[1761,6266,6267],{}," t.iconbitmap('img/bomb.ico')\n",[1761,6269,6271],{"class":1763,"line":6270},203,[1761,6272,6273],{}," t.resizable(width=False, height=False)\n",[1761,6275,6277],{"class":1763,"line":6276},204,[1761,6278,6279],{}," l = LabelFrame(t, text=\"Votre pseudo :\", padx=12, pady=12)\n",[1761,6281,6283],{"class":1763,"line":6282},205,[1761,6284,6285],{}," l.pack(fill=\"both\", expand=\"yes\")\n",[1761,6287,6289],{"class":1763,"line":6288},206,[1761,6290,6291],{}," l.pack(side=LEFT)\n",[1761,6293,6295],{"class":1763,"line":6294},207,[1761,6296,6297],{}," \n",[1761,6299,6301],{"class":1763,"line":6300},208,[1761,6302,6297],{},[1761,6304,6306],{"class":1763,"line":6305},209,[1761,6307,6308],{}," entree = Entry(l)\n",[1761,6310,6312],{"class":1763,"line":6311},210,[1761,6313,6314],{}," entree.pack()\n",[1761,6316,6318],{"class":1763,"line":6317},211,[1761,6319,6320],{}," bou=Button(t,text='Annuler',command=t.destroy)\n",[1761,6322,6324],{"class":1763,"line":6323},212,[1761,6325,6326],{}," bou.pack(side=BOTTOM)\n",[1761,6328,6330],{"class":1763,"line":6329},213,[1761,6331,6332],{}," bou=Button(t,text='Enregistre ton score !',command=on_button)\n",[1761,6334,6336],{"class":1763,"line":6335},214,[1761,6337,6326],{},[1761,6339,6341],{"class":1763,"line":6340},215,[1761,6342,6314],{},[1761,6344,6346],{"class":1763,"line":6345},216,[1761,6347,6348],{}," t.mainloop()\n",[1761,6350,6352],{"class":1763,"line":6351},217,[1761,6353,6297],{},[1761,6355,6357],{"class":1763,"line":6356},218,[1761,6358,6359],{}," else:\n",[1761,6361,6363],{"class":1763,"line":6362},219,[1761,6364,6365],{}," showwarning('Erreur', \"Vous n'êtes pas connecté à internet\")\n",[1761,6367,6369],{"class":1763,"line":6368},220,[1761,6370,5766],{},[1761,6372,6374],{"class":1763,"line":6373},221,[1761,6375,1783],{"emptyLinePlaceholder":55},[1761,6377,6379],{"class":1763,"line":6378},222,[1761,6380,6297],{},[1761,6382,6384],{"class":1763,"line":6383},223,[1761,6385,5359],{},[1761,6387,6389],{"class":1763,"line":6388},224,[1761,6390,5766],{},[1761,6392,6394],{"class":1763,"line":6393},225,[1761,6395,5301],{},[1761,6397,6399],{"class":1763,"line":6398},226,[1761,6400,1783],{"emptyLinePlaceholder":55},[1761,6402,6404],{"class":1763,"line":6403},227,[1761,6405,6406],{},"def afficheFlag(ref):\n",[1761,6408,6410],{"class":1763,"line":6409},228,[1761,6411,6412],{}," \"\"\"Afiiche ou enleve le drapeau lorsque que l'on fait un clic droit\"\"\"\n",[1761,6414,6416],{"class":1763,"line":6415},229,[1761,6417,6418],{}," if b[ref].cget(\"image\")==\"\":\n",[1761,6420,6422],{"class":1763,"line":6421},230,[1761,6423,6424],{}," b[ref].config(image=picFlag)\n",[1761,6426,6428],{"class":1763,"line":6427},231,[1761,6429,6430],{}," verifGagne()\n",[1761,6432,6434],{"class":1763,"line":6433},232,[1761,6435,6436],{}," compteur_bombe()\n",[1761,6438,6440],{"class":1763,"line":6439},233,[1761,6441,5641],{},[1761,6443,6445],{"class":1763,"line":6444},234,[1761,6446,6447],{}," b[ref].config(image=\"\")\n",[1761,6449,6451],{"class":1763,"line":6450},235,[1761,6452,6453],{}," compteur_bombe(False)\n",[1761,6455,6457],{"class":1763,"line":6456},236,[1761,6458,5766],{},[1761,6460,6462],{"class":1763,"line":6461},237,[1761,6463,6464],{},"def verif(bool=False):\n",[1761,6466,6468],{"class":1763,"line":6467},238,[1761,6469,6470],{}," \"\"\"Permet de verifier si toutes les cases ont bien été enlevées\"\"\"\n",[1761,6472,6474],{"class":1763,"line":6473},239,[1761,6475,6476],{}," for ref in range(c*h):\n",[1761,6478,6480],{"class":1763,"line":6479},240,[1761,6481,1783],{"emptyLinePlaceholder":55},[1761,6483,6485],{"class":1763,"line":6484},241,[1761,6486,6487],{}," if ref in top and b[ref].grid_info()=={} and labels[ref].cget(\"text\")==v and labels[ref].cget(\"image\")==\"\":\n",[1761,6489,6491],{"class":1763,"line":6490},242,[1761,6492,1783],{"emptyLinePlaceholder":55},[1761,6494,6496],{"class":1763,"line":6495},243,[1761,6497,6498],{}," for i in [ref-h,ref-(h-1),ref+h,ref+(h+1),ref+1]:\n",[1761,6500,6502],{"class":1763,"line":6501},244,[1761,6503,6297],{},[1761,6505,6507],{"class":1763,"line":6506},245,[1761,6508,6509],{}," if i>=0 and i<=maxi and labels[i].cget(\"text\") in maxBomb and labels[i].cget(\"image\")==\"\":\n",[1761,6511,6513],{"class":1763,"line":6512},246,[1761,6514,6515],{}," b[i].grid_forget()\n",[1761,6517,6519],{"class":1763,"line":6518},247,[1761,6520,6521],{}," elif i>=0 and i<=maxi and labels[i].cget(\"text\")==v and labels[i].cget(\"image\")==\"\" and bool and i not in posForget:\n",[1761,6523,6525],{"class":1763,"line":6524},248,[1761,6526,6515],{},[1761,6528,6530],{"class":1763,"line":6529},249,[1761,6531,6532],{}," enlever_ranger(ref)\n",[1761,6534,6536],{"class":1763,"line":6535},250,[1761,6537,6538],{}," enlever_colonne(i,True)\n",[1761,6540,6542],{"class":1763,"line":6541},251,[1761,6543,6544],{}," posForget.append(i)\n",[1761,6546,6548],{"class":1763,"line":6547},252,[1761,6549,6550],{}," verif()\n",[1761,6552,6554],{"class":1763,"line":6553},253,[1761,6555,6297],{},[1761,6557,6559],{"class":1763,"line":6558},254,[1761,6560,6090],{},[1761,6562,6564],{"class":1763,"line":6563},255,[1761,6565,1783],{"emptyLinePlaceholder":55},[1761,6567,6569],{"class":1763,"line":6568},256,[1761,6570,6571],{}," elif ref in down and b[ref].grid_info()=={} and labels[ref].cget(\"text\")==v and labels[ref].cget(\"image\")==\"\":\n",[1761,6573,6575],{"class":1763,"line":6574},257,[1761,6576,1783],{"emptyLinePlaceholder":55},[1761,6578,6580],{"class":1763,"line":6579},258,[1761,6581,6582],{}," for i in [ref-h,ref-(h+1),ref+h,ref+(h-1),ref-1]:\n",[1761,6584,6586],{"class":1763,"line":6585},259,[1761,6587,1783],{"emptyLinePlaceholder":55},[1761,6589,6591],{"class":1763,"line":6590},260,[1761,6592,6593],{}," if i>=0 and i<=maxi and labels[i].cget(\"text\") in maxBomb and labels[i].cget(\"image\")==\"\" :\n",[1761,6595,6597],{"class":1763,"line":6596},261,[1761,6598,6515],{},[1761,6600,6602],{"class":1763,"line":6601},262,[1761,6603,6521],{},[1761,6605,6607],{"class":1763,"line":6606},263,[1761,6608,6515],{},[1761,6610,6612],{"class":1763,"line":6611},264,[1761,6613,6532],{},[1761,6615,6617],{"class":1763,"line":6616},265,[1761,6618,6538],{},[1761,6620,6622],{"class":1763,"line":6621},266,[1761,6623,6544],{},[1761,6625,6627],{"class":1763,"line":6626},267,[1761,6628,6550],{},[1761,6630,6632],{"class":1763,"line":6631},268,[1761,6633,6297],{},[1761,6635,6637],{"class":1763,"line":6636},269,[1761,6638,6297],{},[1761,6640,6642],{"class":1763,"line":6641},270,[1761,6643,6644],{}," elif b[ref].grid_info()=={} and labels[ref].cget(\"text\")==v and labels[ref].cget(\"image\")==\"\":\n",[1761,6646,6648],{"class":1763,"line":6647},271,[1761,6649,1783],{"emptyLinePlaceholder":55},[1761,6651,6653],{"class":1763,"line":6652},272,[1761,6654,6655],{}," for i in [ref-h,ref-(h+1),ref-(h-1),ref+h,ref+(h-1),ref+(h+1),ref-1,ref+1]:\n",[1761,6657,6659],{"class":1763,"line":6658},273,[1761,6660,1783],{"emptyLinePlaceholder":55},[1761,6662,6664],{"class":1763,"line":6663},274,[1761,6665,6509],{},[1761,6667,6669],{"class":1763,"line":6668},275,[1761,6670,6515],{},[1761,6672,6674],{"class":1763,"line":6673},276,[1761,6675,6521],{},[1761,6677,6679],{"class":1763,"line":6678},277,[1761,6680,6515],{},[1761,6682,6684],{"class":1763,"line":6683},278,[1761,6685,6532],{},[1761,6687,6689],{"class":1763,"line":6688},279,[1761,6690,6538],{},[1761,6692,6694],{"class":1763,"line":6693},280,[1761,6695,6544],{},[1761,6697,6699],{"class":1763,"line":6698},281,[1761,6700,6550],{},[1761,6702,6704],{"class":1763,"line":6703},282,[1761,6705,6706],{}," \n",[1761,6708,6710],{"class":1763,"line":6709},283,[1761,6711,6712],{}," \n",[1761,6714,6716],{"class":1763,"line":6715},284,[1761,6717,5301],{},[1761,6719,6721],{"class":1763,"line":6720},285,[1761,6722,6723],{},"def enlever_ranger(pos):\n",[1761,6725,6727],{"class":1763,"line":6726},286,[1761,6728,6729],{}," \"\"\"Permet d'enlever les boutons d'une rangée de droite et de gauche jusqu'à ce qu'on rencontre un chiffe dans un label\"\"\"\n",[1761,6731,6733],{"class":1763,"line":6732},287,[1761,6734,6735],{}," left=pos-h\n",[1761,6737,6739],{"class":1763,"line":6738},288,[1761,6740,6741],{}," right=pos+h\n",[1761,6743,6745],{"class":1763,"line":6744},289,[1761,6746,6747],{}," \n",[1761,6749,6751],{"class":1763,"line":6750},290,[1761,6752,6753],{}," while left>=0 and labels[left].cget(\"text\")==\" \":\n",[1761,6755,6757],{"class":1763,"line":6756},291,[1761,6758,6759],{}," if b[left].grid_info()!={}:\n",[1761,6761,6763],{"class":1763,"line":6762},292,[1761,6764,6765],{}," b[left].grid_forget()\n",[1761,6767,6769],{"class":1763,"line":6768},293,[1761,6770,6771],{}," \n",[1761,6773,6775],{"class":1763,"line":6774},294,[1761,6776,6777],{}," enlever_colonne(left,True)\n",[1761,6779,6781],{"class":1763,"line":6780},295,[1761,6782,5359],{},[1761,6784,6786],{"class":1763,"line":6785},296,[1761,6787,5766],{},[1761,6789,6791],{"class":1763,"line":6790},297,[1761,6792,6793],{}," left-=h\n",[1761,6795,6797],{"class":1763,"line":6796},298,[1761,6798,5766],{},[1761,6800,6802],{"class":1763,"line":6801},299,[1761,6803,6804],{}," while right<=maxi and labels[right].cget(\"text\")==\" \":\n",[1761,6806,6808],{"class":1763,"line":6807},300,[1761,6809,6810],{}," if b[right].grid_info()!={}:\n",[1761,6812,6814],{"class":1763,"line":6813},301,[1761,6815,6816],{}," b[right].grid_forget()\n",[1761,6818,6820],{"class":1763,"line":6819},302,[1761,6821,6822],{}," enlever_colonne(right,True)\n",[1761,6824,6826],{"class":1763,"line":6825},303,[1761,6827,5359],{},[1761,6829,6831],{"class":1763,"line":6830},304,[1761,6832,5766],{},[1761,6834,6836],{"class":1763,"line":6835},305,[1761,6837,5766],{},[1761,6839,6841],{"class":1763,"line":6840},306,[1761,6842,6843],{}," right+=h\n",[1761,6845,6847],{"class":1763,"line":6846},307,[1761,6848,1783],{"emptyLinePlaceholder":55},[1761,6850,6852],{"class":1763,"line":6851},308,[1761,6853,6854],{},"def enlever_colonne(pos, bool=False):\n",[1761,6856,6858],{"class":1763,"line":6857},309,[1761,6859,6860],{}," \"\"\"Permet d'enlever les boutons d'une colonne du bas et du haut jusqu'à ce qu'on rencontre un chiffre dans un label\"\"\"\n",[1761,6862,6864],{"class":1763,"line":6863},310,[1761,6865,6866],{}," d=pos-1\n",[1761,6868,6870],{"class":1763,"line":6869},311,[1761,6871,6872],{}," up=pos+1\n",[1761,6874,6876],{"class":1763,"line":6875},312,[1761,6877,5301],{},[1761,6879,6881],{"class":1763,"line":6880},313,[1761,6882,1783],{"emptyLinePlaceholder":55},[1761,6884,6886],{"class":1763,"line":6885},314,[1761,6887,6888],{}," while d not in down and labels[d].cget(\"text\")==\" \" and labels[d].cget(\"image\")==\"\" and d>=0 and d=0 and up\")\n",[1761,7091,7093],{"class":1763,"line":7092},351,[1761,7094,7095],{}," b[i].unbind(\"\")\n",[1761,7097,7099],{"class":1763,"line":7098},352,[1761,7100,7101],{}," b[i].config(state='disabled')\n",[1761,7103,7105],{"class":1763,"line":7104},353,[1761,7106,1783],{"emptyLinePlaceholder":55},[1761,7108,7110],{"class":1763,"line":7109},354,[1761,7111,5301],{},[1761,7113,7115],{"class":1763,"line":7114},355,[1761,7116,7117],{}," showinfo('Perdu', 'Vous avez fait exploser la mine')\n",[1761,7119,7121],{"class":1763,"line":7120},356,[1761,7122,1783],{"emptyLinePlaceholder":55},[1761,7124,7126],{"class":1763,"line":7125},357,[1761,7127,7128],{},"def supprimer():\n",[1761,7130,7132],{"class":1763,"line":7131},358,[1761,7133,7134],{}," \"\"\"Supprime les infos de la partie précédente.\"\"\"\n",[1761,7136,7138],{"class":1763,"line":7137},359,[1761,7139,7140],{}," global b,labels\n",[1761,7142,7144],{"class":1763,"line":7143},360,[1761,7145,7146],{}," for i in range(len(b)):\n",[1761,7148,7150],{"class":1763,"line":7149},361,[1761,7151,7152],{}," b[i].grid_remove()\n",[1761,7154,7156],{"class":1763,"line":7155},362,[1761,7157,7158],{}," b[i].destroy()\n",[1761,7160,7162],{"class":1763,"line":7161},363,[1761,7163,7164],{}," labels[i].grid_remove()\n",[1761,7166,7168],{"class":1763,"line":7167},364,[1761,7169,7170],{}," labels[i].destroy()\n",[1761,7172,7174],{"class":1763,"line":7173},365,[1761,7175,7176],{}," b=[]\n",[1761,7178,7180],{"class":1763,"line":7179},366,[1761,7181,7182],{}," labels=[]\n",[1761,7184,7186],{"class":1763,"line":7185},367,[1761,7187,1783],{"emptyLinePlaceholder":55},[1761,7189,7191],{"class":1763,"line":7190},368,[1761,7192,1783],{"emptyLinePlaceholder":55},[1761,7194,7196],{"class":1763,"line":7195},369,[1761,7197,7198],{},"def nouveau(charger=False,bombe=[],pos=[],bouton=[],flag=[],name=\"\"):\n",[1761,7200,7202],{"class":1763,"line":7201},370,[1761,7203,5301],{},[1761,7205,7207],{"class":1763,"line":7206},371,[1761,7208,7209],{}," \"\"\" Permet de creer un nouveau damier avec de nouvelle bombes, de plus si le paramètre charger est True\n",[1761,7211,7213],{"class":1763,"line":7212},372,[1761,7214,7215],{}," alors on charge la sauvegarde grâce à la fonction charge() de menubar.py\"\"\"\n",[1761,7217,7219],{"class":1763,"line":7218},373,[1761,7220,7221],{}," global presentBomb,posForget,sec,compteur_bombes,pseudo,partie_terminée,clique,top,down\n",[1761,7223,7225],{"class":1763,"line":7224},374,[1761,7226,1783],{"emptyLinePlaceholder":55},[1761,7228,7230],{"class":1763,"line":7229},375,[1761,7231,7021],{},[1761,7233,7235],{"class":1763,"line":7234},376,[1761,7236,7237],{}," clique = 0\n",[1761,7239,7241],{"class":1763,"line":7240},377,[1761,7242,7243],{}," pseudo=name\n",[1761,7245,7247],{"class":1763,"line":7246},378,[1761,7248,7249],{}," compteur_bombes=nbBombs\n",[1761,7251,7253],{"class":1763,"line":7252},379,[1761,7254,7255],{}," compteur['text']='Bombes restantes : '+str(compteur_bombes)\n",[1761,7257,7259],{"class":1763,"line":7258},380,[1761,7260,5301],{},[1761,7262,7264],{"class":1763,"line":7263},381,[1761,7265,7266],{}," time.after_cancel(timafter)\n",[1761,7268,7270],{"class":1763,"line":7269},382,[1761,7271,5301],{},[1761,7273,7275],{"class":1763,"line":7274},383,[1761,7276,5301],{},[1761,7278,7280],{"class":1763,"line":7279},384,[1761,7281,7282],{}," supprimer()\n",[1761,7284,7286],{"class":1763,"line":7285},385,[1761,7287,7288],{}," posForget=[]\n",[1761,7290,7292],{"class":1763,"line":7291},386,[1761,7293,7294],{}," presentBomb=[]\n",[1761,7296,7298],{"class":1763,"line":7297},387,[1761,7299,5301],{},[1761,7301,7303],{"class":1763,"line":7302},388,[1761,7304,5446],{},[1761,7306,7308],{"class":1763,"line":7307},389,[1761,7309,7310],{}," presentBomb=bombe\n",[1761,7312,7314],{"class":1763,"line":7313},390,[1761,7315,7316],{}," posForget=pos\n",[1761,7318,7320],{"class":1763,"line":7319},391,[1761,7321,5641],{},[1761,7323,7325],{"class":1763,"line":7324},392,[1761,7326,7327],{}," sec=0\n",[1761,7329,7331],{"class":1763,"line":7330},393,[1761,7332,7333],{}," time['text'] = 'Temps : ' + strftime('%M : %S', gmtime(sec))\n",[1761,7335,7337],{"class":1763,"line":7336},394,[1761,7338,5766],{},[1761,7340,7342],{"class":1763,"line":7341},395,[1761,7343,7344],{}," can.pack_forget()\n",[1761,7346,7348],{"class":1763,"line":7347},396,[1761,7349,5301],{},[1761,7351,7353],{"class":1763,"line":7352},397,[1761,7354,7355],{}," top=[]\n",[1761,7357,7359],{"class":1763,"line":7358},398,[1761,7360,7361],{}," down=[]\n",[1761,7363,7365],{"class":1763,"line":7364},399,[1761,7366,7367],{}," top.append(0)\n",[1761,7369,7371],{"class":1763,"line":7370},400,[1761,7372,7373],{}," for i in range(h):\n",[1761,7375,7377],{"class":1763,"line":7376},401,[1761,7378,7379],{}," top.append((i+1)*h)\n",[1761,7381,7383],{"class":1763,"line":7382},402,[1761,7384,7385],{}," down.append(((i+1)*h)-1)\n",[1761,7387,7389],{"class":1763,"line":7388},403,[1761,7390,7391],{}," down.append(c*h)\n",[1761,7393,7395],{"class":1763,"line":7394},404,[1761,7396,5301],{},[1761,7398,7400],{"class":1763,"line":7399},405,[1761,7401,5324],{},[1761,7403,7405],{"class":1763,"line":7404},406,[1761,7406,5335],{},[1761,7408,7410],{"class":1763,"line":7409},407,[1761,7411,5341],{},[1761,7413,7415],{"class":1763,"line":7414},408,[1761,7416,7417],{}," labels.append(Label(can, text=v,bd=1,relief=SUNKEN,font=(\"Helvetica\", 9),width=1,height=1,justify=CENTER,padx=9,pady=5))\n",[1761,7419,7421],{"class":1763,"line":7420},409,[1761,7422,5353],{},[1761,7424,7426],{"class":1763,"line":7425},410,[1761,7427,7428],{}," b.append(Button(can,text=\"\",image=\"\",padx=8,pady=1))\n",[1761,7430,7432],{"class":1763,"line":7431},411,[1761,7433,5371],{},[1761,7435,7437],{"class":1763,"line":7436},412,[1761,7438,5377],{},[1761,7440,7442],{"class":1763,"line":7441},413,[1761,7443,5383],{},[1761,7445,7447],{"class":1763,"line":7446},414,[1761,7448,7449],{}," b[a].config(text=\"\",image=\"\")\n",[1761,7451,7453],{"class":1763,"line":7452},415,[1761,7454,5395],{},[1761,7456,7458],{"class":1763,"line":7457},416,[1761,7459,5359],{},[1761,7461,7463],{"class":1763,"line":7462},417,[1761,7464,5446],{},[1761,7466,7468],{"class":1763,"line":7467},418,[1761,7469,5766],{},[1761,7471,7473],{"class":1763,"line":7472},419,[1761,7474,7475],{}," for i in bouton:\n",[1761,7477,7479],{"class":1763,"line":7478},420,[1761,7480,7078],{},[1761,7482,7484],{"class":1763,"line":7483},421,[1761,7485,7486],{}," bombes(True)\n",[1761,7488,7490],{"class":1763,"line":7489},422,[1761,7491,5641],{},[1761,7493,7495],{"class":1763,"line":7494},423,[1761,7496,7497],{}," bombes()\n",[1761,7499,7501],{"class":1763,"line":7500},424,[1761,7502,1783],{"emptyLinePlaceholder":55},[1761,7504,7506],{"class":1763,"line":7505},425,[1761,7507,5301],{},[1761,7509,7511],{"class":1763,"line":7510},426,[1761,7512,7513],{}," can.pack(side=TOP,expand=True)\n",[1761,7515,7517],{"class":1763,"line":7516},427,[1761,7518,5446],{},[1761,7520,7522],{"class":1763,"line":7521},428,[1761,7523,7524],{}," for i in flag:\n",[1761,7526,7528],{"class":1763,"line":7527},429,[1761,7529,5359],{},[1761,7531,7533],{"class":1763,"line":7532},430,[1761,7534,7535],{}," afficheFlag(i)\n",[1761,7537,7539],{"class":1763,"line":7538},431,[1761,7540,7541],{}," timer()\n",[1761,7543,7545],{"class":1763,"line":7544},432,[1761,7546,5718],{},[1761,7548,7550],{"class":1763,"line":7549},433,[1761,7551,7552],{}," clique=1\n",[1761,7554,7556],{"class":1763,"line":7555},434,[1761,7557,5301],{},[1761,7559,7561],{"class":1763,"line":7560},435,[1761,7562,7563],{},"def recup_info_partie():\n",[1761,7565,7567],{"class":1763,"line":7566},436,[1761,7568,7569],{}," \"\"\"Récupère les informations de la partie en cours \"\"\"\n",[1761,7571,7573],{"class":1763,"line":7572},437,[1761,7574,1783],{"emptyLinePlaceholder":55},[1761,7576,7578],{"class":1763,"line":7577},438,[1761,7579,7580],{}," b_forget=[]\n",[1761,7582,7584],{"class":1763,"line":7583},439,[1761,7585,7586],{}," flag=[]\n",[1761,7588,7590],{"class":1763,"line":7589},440,[1761,7591,7592],{}," taille_interface=c\n",[1761,7594,7596],{"class":1763,"line":7595},441,[1761,7597,5873],{},[1761,7599,7601],{"class":1763,"line":7600},442,[1761,7602,7603],{}," if b[i].grid_info()=={}:\n",[1761,7605,7607],{"class":1763,"line":7606},443,[1761,7608,7609],{}," b_forget.append(i)\n",[1761,7611,7613],{"class":1763,"line":7612},444,[1761,7614,7615],{}," if b[i].cget(\"image\")!=\"\":\n",[1761,7617,7619],{"class":1763,"line":7618},445,[1761,7620,7621],{}," flag.append(i)\n",[1761,7623,7625],{"class":1763,"line":7624},446,[1761,7626,7627],{}," return presentBomb,posForget,b_forget,flag,taille_interface,sec\n",[1761,7629,7631],{"class":1763,"line":7630},447,[1761,7632,1783],{"emptyLinePlaceholder":55},[1761,7634,7636],{"class":1763,"line":7635},448,[1761,7637,7638],{},"def option(nbmines, taille_interface,bool=True,s=0):\n",[1761,7640,7642],{"class":1763,"line":7641},449,[1761,7643,7644],{}," \"\"\" Permet de définir les options définis par la commande option du menu. \"\"\"\n",[1761,7646,7648],{"class":1763,"line":7647},450,[1761,7649,1783],{"emptyLinePlaceholder":55},[1761,7651,7653],{"class":1763,"line":7652},451,[1761,7654,7655],{}," global c,maxi,nbBombs,top,down,h,sec\n",[1761,7657,7659],{"class":1763,"line":7658},452,[1761,7660,1783],{"emptyLinePlaceholder":55},[1761,7662,7664],{"class":1763,"line":7663},453,[1761,7665,7666],{}," sec=s\n",[1761,7668,7670],{"class":1763,"line":7669},454,[1761,7671,7672],{}," c = taille_interface\n",[1761,7674,7676],{"class":1763,"line":7675},455,[1761,7677,7678],{}," maxi=(c*c)-1\n",[1761,7680,7682],{"class":1763,"line":7681},456,[1761,7683,7684],{}," h=c\n",[1761,7686,7688],{"class":1763,"line":7687},457,[1761,7689,7690],{}," if taille_interface==30:\n",[1761,7692,7694],{"class":1763,"line":7693},458,[1761,7695,7696],{}," h=16\n",[1761,7698,7700],{"class":1763,"line":7699},459,[1761,7701,7702],{}," maxi=(c*16)-1\n",[1761,7704,7706],{"class":1763,"line":7705},460,[1761,7707,5766],{},[1761,7709,7711],{"class":1763,"line":7710},461,[1761,7712,7713],{}," nbBombs = int(nbmines)\n",[1761,7715,7717],{"class":1763,"line":7716},462,[1761,7718,5301],{},[1761,7720,7722],{"class":1763,"line":7721},463,[1761,7723,1783],{"emptyLinePlaceholder":55},[1761,7725,7727],{"class":1763,"line":7726},464,[1761,7728,7729],{}," if bool:\n",[1761,7731,7733],{"class":1763,"line":7732},465,[1761,7734,7735],{}," nouveau()\n",[1761,7737,7739],{"class":1763,"line":7738},466,[1761,7740,1783],{"emptyLinePlaceholder":55},[1761,7742,7744],{"class":1763,"line":7743},467,[1761,7745,7746],{},"def timer(bool=False):\n",[1761,7748,7750],{"class":1763,"line":7749},468,[1761,7751,7752],{}," \"\"\"Arrête ou démarre le timer en fonction de la variable bool\"\"\"\n",[1761,7754,7756],{"class":1763,"line":7755},469,[1761,7757,7758],{}," global timafter\n",[1761,7760,7762],{"class":1763,"line":7761},470,[1761,7763,7729],{},[1761,7765,7767],{"class":1763,"line":7766},471,[1761,7768,5965],{},[1761,7770,7772],{"class":1763,"line":7771},472,[1761,7773,5641],{},[1761,7775,7777],{"class":1763,"line":7776},473,[1761,7778,7779],{}," timafter = time.after(1000, temps)\n",[1761,7781,7783],{"class":1763,"line":7782},474,[1761,7784,1783],{"emptyLinePlaceholder":55},[1761,7786,7788],{"class":1763,"line":7787},475,[1761,7789,7790],{},"def temps():\n",[1761,7792,7794],{"class":1763,"line":7793},476,[1761,7795,7796],{}," \"\"\"Affiche le temps dans la fenètre principale\"\"\"\n",[1761,7798,7800],{"class":1763,"line":7799},477,[1761,7801,7802],{}," global sec,timafter\n",[1761,7804,7806],{"class":1763,"line":7805},478,[1761,7807,7808],{}," sec += 1\n",[1761,7810,7812],{"class":1763,"line":7811},479,[1761,7813,7333],{},[1761,7815,7817],{"class":1763,"line":7816},480,[1761,7818,5301],{},[1761,7820,7822],{"class":1763,"line":7821},481,[1761,7823,7824],{}," timafter = time.after(1000, temps)\n",[1761,7826,7828],{"class":1763,"line":7827},482,[1761,7829,1783],{"emptyLinePlaceholder":55},[1761,7831,7833],{"class":1763,"line":7832},483,[1761,7834,7835],{},"def compteur_bombe(bool=True):\n",[1761,7837,7839],{"class":1763,"line":7838},484,[1761,7840,7841],{}," \"\"\"Affiche dans la fenètre principale le nombres de bombes encore à trouver\"\"\"\n",[1761,7843,7845],{"class":1763,"line":7844},485,[1761,7846,7847],{}," global compteur_bombes\n",[1761,7849,7851],{"class":1763,"line":7850},486,[1761,7852,7729],{},[1761,7854,7856],{"class":1763,"line":7855},487,[1761,7857,7858],{}," compteur_bombes-=1\n",[1761,7860,7862],{"class":1763,"line":7861},488,[1761,7863,7864],{}," elif bool==False and compteur_bombes+1<=nbBombs:\n",[1761,7866,7868],{"class":1763,"line":7867},489,[1761,7869,7870],{}," compteur_bombes+=1\n",[1761,7872,7874],{"class":1763,"line":7873},490,[1761,7875,7255],{},[1761,7877,7879],{"class":1763,"line":7878},491,[1761,7880,5301],{},[1761,7882,7884],{"class":1763,"line":7883},492,[1761,7885,7886],{}," if compteur_bombes<=0:\n",[1761,7888,7890],{"class":1763,"line":7889},493,[1761,7891,7892],{}," compteur['text']='Bombes restantes : 0'\n",[1761,7894,7896],{"class":1763,"line":7895},494,[1761,7897,1783],{"emptyLinePlaceholder":55},[1761,7899,7901],{"class":1763,"line":7900},495,[1761,7902,7903],{},"def pseudo_partie():\n",[1761,7905,7907],{"class":1763,"line":7906},496,[1761,7908,7909],{}," \"\"\"Retourne la valeur pseudo pour menubar.py\"\"\" \n",[1761,7911,7913],{"class":1763,"line":7912},497,[1761,7914,7915],{}," return pseudo\n",[1761,7917,7919],{"class":1763,"line":7918},498,[1761,7920,5301],{},[1761,7922,7924],{"class":1763,"line":7923},499,[1761,7925,1783],{"emptyLinePlaceholder":55},[1761,7927,7929],{"class":1763,"line":7928},500,[1761,7930,7931],{},"def etat_partie():\n",[1761,7933,7935],{"class":1763,"line":7934},501,[1761,7936,7937],{}," \"\"\"Retourne l'état de la partie, \n",[1761,7939,7941],{"class":1763,"line":7940},502,[1761,7942,7943],{}," terminée = True \n",[1761,7945,7947],{"class":1763,"line":7946},503,[1761,7948,7949],{}," non terminée = False \n",[1761,7951,7953],{"class":1763,"line":7952},504,[1761,7954,7955],{}," fonction créée pour menubar.py\"\"\"\n",[1761,7957,7959],{"class":1763,"line":7958},505,[1761,7960,7961],{}," return partie_terminée\n",[1761,7963,7965],{"class":1763,"line":7964},506,[1761,7966,5301],{},[1761,7968,7970],{"class":1763,"line":7969},507,[1761,7971,7972],{},"######Programme ######\n",[1761,7974,7976],{"class":1763,"line":7975},508,[1761,7977,1783],{"emptyLinePlaceholder":55},[1761,7979,7981],{"class":1763,"line":7980},509,[1761,7982,1783],{"emptyLinePlaceholder":55},[1761,7984,7986],{"class":1763,"line":7985},510,[1761,7987,1783],{"emptyLinePlaceholder":55},[1761,7989,7991],{"class":1763,"line":7990},511,[1761,7992,7993],{},"c=9 \n",[1761,7995,7997],{"class":1763,"line":7996},512,[1761,7998,7999],{},"nbBombs=10 \n",[1761,8001,8003],{"class":1763,"line":8002},513,[1761,8004,8005],{},"w=200\n",[1761,8007,8009],{"class":1763,"line":8008},514,[1761,8010,8011],{},"h=200 \n",[1761,8013,8015],{"class":1763,"line":8014},515,[1761,8016,1783],{"emptyLinePlaceholder":55},[1761,8018,8020],{"class":1763,"line":8019},516,[1761,8021,8022],{},"compteur_bombes=nbBombs\n",[1761,8024,8026],{"class":1763,"line":8025},517,[1761,8027,1783],{"emptyLinePlaceholder":55},[1761,8029,8031],{"class":1763,"line":8030},518,[1761,8032,8033],{},"h=c\n",[1761,8035,8037],{"class":1763,"line":8036},519,[1761,8038,8039],{},"posForget=[]\n",[1761,8041,8043],{"class":1763,"line":8042},520,[1761,8044,8045],{},"maxBomb=[\"1\",\"2\",\"3\",\"4\",\"5\",\"6\",\"7\",\"8\"]\n",[1761,8047,8049],{"class":1763,"line":8048},521,[1761,8050,8051],{},"presentBomb=[]\n",[1761,8053,8055],{"class":1763,"line":8054},522,[1761,8056,8057],{},"maxi=(c*h)-1\n",[1761,8059,8061],{"class":1763,"line":8060},523,[1761,8062,8063],{},"labels=[]\n",[1761,8065,8067],{"class":1763,"line":8066},524,[1761,8068,8069],{},"b = []\n",[1761,8071,8073],{"class":1763,"line":8072},525,[1761,8074,8075],{},"v = \" \"\n",[1761,8077,8079],{"class":1763,"line":8078},526,[1761,8080,1783],{"emptyLinePlaceholder":55},[1761,8082,8084],{"class":1763,"line":8083},527,[1761,8085,1783],{"emptyLinePlaceholder":55},[1761,8087,8089],{"class":1763,"line":8088},528,[1761,8090,1783],{"emptyLinePlaceholder":55},[1761,8092,8094],{"class":1763,"line":8093},529,[1761,8095,8096],{},"pseudo=\"\"\n",[1761,8098,8100],{"class":1763,"line":8099},530,[1761,8101,8102],{},"partie_terminée=True\n",[1761,8104,8106],{"class":1763,"line":8105},531,[1761,8107,8108],{},"clique=0\n",[1761,8110,8112],{"class":1763,"line":8111},532,[1761,8113,1783],{"emptyLinePlaceholder":55},[1761,8115,8117],{"class":1763,"line":8116},533,[1761,8118,8119],{},"top=[]\n",[1761,8121,8123],{"class":1763,"line":8122},534,[1761,8124,8125],{},"down=[]\n",[1761,8127,8129],{"class":1763,"line":8128},535,[1761,8130,8131],{},"top.append(0)\n",[1761,8133,8135],{"class":1763,"line":8134},536,[1761,8136,8137],{},"for i in range(h):\n",[1761,8139,8141],{"class":1763,"line":8140},537,[1761,8142,8143],{}," top.append((i+1)*c)\n",[1761,8145,8147],{"class":1763,"line":8146},538,[1761,8148,8149],{}," down.append(((i+1)*c)-1)\n",[1761,8151,8153],{"class":1763,"line":8152},539,[1761,8154,8155],{},"down.append(c*h)\n",[1761,8157,8159],{"class":1763,"line":8158},540,[1761,8160,1783],{"emptyLinePlaceholder":55},[1761,8162,8164],{"class":1763,"line":8163},541,[1761,8165,1783],{"emptyLinePlaceholder":55},[1761,8167,8169],{"class":1763,"line":8168},542,[1761,8170,8171],{},"sec=0\n",[1761,8173,8175],{"class":1763,"line":8174},543,[1761,8176,1783],{"emptyLinePlaceholder":55},[1761,8178,8180],{"class":1763,"line":8179},544,[1761,8181,8182],{},"fen = Tk()\n",[1761,8184,8186],{"class":1763,"line":8185},545,[1761,8187,8188],{},"menubar = MenuBar(fen,nouveau,recup_info_partie,option,timer,etat_partie,pseudo_partie)\n",[1761,8190,8192],{"class":1763,"line":8191},546,[1761,8193,8194],{},"fen.title('Démineur')\n",[1761,8196,8198],{"class":1763,"line":8197},547,[1761,8199,8200],{},"fen.resizable(width=False, height=False)\n",[1761,8202,8204],{"class":1763,"line":8203},548,[1761,8205,8206],{},"fen.config(menu=menubar)\n",[1761,8208,8210],{"class":1763,"line":8209},549,[1761,8211,1783],{"emptyLinePlaceholder":55},[1761,8213,8215],{"class":1763,"line":8214},550,[1761,8216,8217],{},"frame= LabelFrame(fen,bd=2)\n",[1761,8219,8221],{"class":1763,"line":8220},551,[1761,8222,8223],{},"frame.pack(side=TOP,fill=X)\n",[1761,8225,8227],{"class":1763,"line":8226},552,[1761,8228,8229],{},"can = Canvas(fen, width=w, height=h, background='white')\n",[1761,8231,8233],{"class":1763,"line":8232},553,[1761,8234,1783],{"emptyLinePlaceholder":55},[1761,8236,8238],{"class":1763,"line":8237},554,[1761,8239,8240],{},"time = Label(frame, fg='Black')\n",[1761,8242,8244],{"class":1763,"line":8243},555,[1761,8245,8246],{},"time.pack(side=LEFT)\n",[1761,8248,8250],{"class":1763,"line":8249},556,[1761,8251,8252],{},"time['text'] = 'Temps : ' + strftime('%M : %S', gmtime(sec))\n",[1761,8254,8256],{"class":1763,"line":8255},557,[1761,8257,8258],{},"timafter = time.after(1000, temps)\n",[1761,8260,8262],{"class":1763,"line":8261},558,[1761,8263,8264],{},"time.after_cancel(timafter)\n",[1761,8266,8268],{"class":1763,"line":8267},559,[1761,8269,8270],{},"compteur = Label(frame, fg='Black')\n",[1761,8272,8274],{"class":1763,"line":8273},560,[1761,8275,8276],{},"compteur.pack(side=RIGHT)\n",[1761,8278,8280],{"class":1763,"line":8279},561,[1761,8281,8282],{},"compteur['text']='Bombes restantes : '+str(compteur_bombes)\n",[1761,8284,8286],{"class":1763,"line":8285},562,[1761,8287,1783],{"emptyLinePlaceholder":55},[1761,8289,8291],{"class":1763,"line":8290},563,[1761,8292,8293],{},"create_image()\n",[1761,8295,8297],{"class":1763,"line":8296},564,[1761,8298,8299],{},"damier()\n",[1761,8301,8303],{"class":1763,"line":8302},565,[1761,8304,1783],{"emptyLinePlaceholder":55},[1761,8306,8308],{"class":1763,"line":8307},566,[1761,8309,1783],{"emptyLinePlaceholder":55},[1761,8311,8313],{"class":1763,"line":8312},567,[1761,8314,8315],{},"fen.iconbitmap('img/bomb.ico')\n",[1761,8317,8319],{"class":1763,"line":8318},568,[1761,8320,1783],{"emptyLinePlaceholder":55},[1761,8322,8324],{"class":1763,"line":8323},569,[1761,8325,6771],{},[1761,8327,8329],{"class":1763,"line":8328},570,[1761,8330,8331],{},"can.pack(side=BOTTOM,expand=True)\n",[1761,8333,8335],{"class":1763,"line":8334},571,[1761,8336,1783],{"emptyLinePlaceholder":55},[1761,8338,8340],{"class":1763,"line":8339},572,[1761,8341,8342],{},"fen.mainloop()\n",[2436,8344,8345],{},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":369,"searchDepth":370,"depth":370,"links":8347},[8348,8349,8350,8351,8352,8353],{"id":4868,"depth":370,"text":4869},{"id":4891,"depth":370,"text":4892},{"id":4925,"depth":370,"text":4926},{"id":4967,"depth":370,"text":4968},{"id":4999,"depth":370,"text":5000},{"id":801,"depth":370,"text":5095,"children":8354},[8355],{"id":4921,"depth":380,"text":3310},"2025-05-03","At 16, I wanted to break into systems. Today, I build them. This is how a hacker mindset, a frustrating job, and a Python minesweeper led me to be self-employed.","https://images.pexels.com/photos/7988745/pexels-photo-7988745.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1",{},{"title":28,"description":8357},"dMoSDjllelUlJgeEch1ZnFwyE5_8Vo9cQpOzSQMefTw",["Reactive",8363],{"$scolor-mode":8364,"$snuxt-seo-utils:routeRules":8366,"$stoasts":8367,"$ssite-config":8368},{"preference":8365,"value":8365,"unknown":55,"forced":47},"system",{"head":-1,"seoMeta":-1},[],{"_priority":8369,"env":8373,"name":8374,"url":8375},{"env":8370,"url":8371,"name":8372},-15,0,-3,"production","Valentin Chmara - Software Engineer","https://valentinchmara.com",["Set"],["ShallowReactive",8378],{"navigation":-1,"search":-1,"blog-page":-1,"blogs":-1}]