[{"data":1,"prerenderedAt":1083},["ShallowReactive",2],{"blog-productive-laziness-toolkit":3},{"id":4,"title":5,"body":6,"date":1071,"description":1072,"extension":1073,"featured":1074,"meta":1075,"navigation":101,"part":84,"path":1076,"seo":1077,"series":20,"stem":1078,"tags":1079,"tldr":1081,"__hash__":1082},"blog\u002Fblog\u002Fproductive-laziness-toolkit.md","The Toolkit: Regex Pipelines, Excel Injection, and the Arsenal",{"type":7,"value":8,"toc":1065},"minimark",[9,22,27,34,37,48,55,62,424,431,435,438,445,457,460,512,977,987,992,996,999,1002,1012,1022,1026,1029,1036,1039,1045,1048,1051,1056,1061],[10,11,12],"p",{},[13,14,15,16,21],"em",{},"This is Part 2 of the ",[17,18,20],"a",{"href":19},"\u002Fblog\u002Fproductive-laziness","THE METHOD"," series. If you haven't read Part 1 on the automation philosophy and the two-device meeting, start there.",[23,24,26],"h2",{"id":25},"the-regex-date-cleaning-incident","The Regex Date Cleaning Incident",[10,28,29,30,33],{},"Here's a specific one. We'd get datasets — messy, real-world data — and the dates were an absolute ",[13,31,32],{},"disaster",".",[10,35,36],{},"I'm talking about Excel files with inconsistent formats like:",[38,39,44],"pre",{"className":40,"code":42,"language":43},[41],"language-text","2023-04-15\n15\u002F04\u002F2023\n04\u002F15\u002F2023\nApr 15 2023\n15-Apr-2023\nApril 15, 2023\n20230415\n15.04.2023\n","text",[45,46,42],"code",{"__ignoreMap":47},"",[10,49,50,51,54],{},"Sometimes ",[13,52,53],{},"all in the same column",". Because of course they were.",[10,56,57,58,61],{},"We wrote a Python script with a list of compiled regex patterns, ranked by confidence. The function tried each pattern, extracted the components, and normalised everything to ISO 8601. If a pattern matched ambiguously (looking at ",[45,59,60],{},"04\u002F05\u002F2023"," — April 5th or May 4th?), it flagged the row for manual review instead of guessing.",[38,63,67],{"className":64,"code":65,"language":66,"meta":47,"style":47},"language-python shiki shiki-themes vesper","import re\nfrom datetime import datetime\n\nDATE_PATTERNS = [\n    (r'^(\\d{4})-(\\d{2})-(\\d{2})$', '%Y-%m-%d'),           # 2023-04-15\n    (r'^(\\d{2})\u002F(\\d{2})\u002F(\\d{4})$', '%d\u002F%m\u002F%Y'),            # 15\u002F04\u002F2023\n    (r'^(\\d{2})\u002F(\\d{2})\u002F(\\d{2})$', '%d\u002F%m\u002F%y'),            # 15\u002F04\u002F23\n    (r'^(\\w{3})\\s+(\\d{1,2})\\s+(\\d{4})$', '%b %d %Y'),     # Apr 15 2023\n    (r'^(\\d{1,2})-(\\w{3})-(\\d{4})$', '%d-%b-%Y'),          # 15-Apr-2023\n    (r'^(\\w{3,9})\\s+(\\d{1,2}),?\\s*(\\d{4})$', '%B %d %Y'), # April 15, 2023\n    (r'^(\\d{8})$', '%Y%m%d'),                               # 20230415\n    (r'^(\\d{2})\\.(\\d{2})\\.(\\d{4})$', '%d.%m.%Y'),          # 15.04.2023\n]\n\ndef normalize_date(value):\n    \"\"\"Try every regex pattern and return the first clean match.\"\"\"\n    for pattern, fmt in DATE_PATTERNS:\n        match = re.match(pattern, value.strip())\n        if match:\n            try:\n                return datetime.strptime(value.strip(), fmt).isoformat()\n            except ValueError:\n                continue\n    return None  # Manual review\n","python",[45,68,69,82,96,103,115,145,168,190,217,245,268,291,313,319,324,336,342,357,368,377,386,395,406,412],{"__ignoreMap":47},[70,71,74,78],"span",{"class":72,"line":73},"line",1,[70,75,77],{"class":76},"sq0yK","import",[70,79,81],{"class":80},"sU-n2"," re\n",[70,83,85,88,91,93],{"class":72,"line":84},2,[70,86,87],{"class":76},"from",[70,89,90],{"class":80}," datetime ",[70,92,77],{"class":76},[70,94,95],{"class":80}," datetime\n",[70,97,99],{"class":72,"line":98},3,[70,100,102],{"emptyLinePlaceholder":101},true,"\n",[70,104,106,109,112],{"class":72,"line":105},4,[70,107,108],{"class":80},"DATE_PATTERNS ",[70,110,111],{"class":76},"=",[70,113,114],{"class":80}," [\n",[70,116,118,121,124,127,131,135,138,141],{"class":72,"line":117},5,[70,119,120],{"class":80},"    (",[70,122,123],{"class":76},"r'^(\\d{4})-(\\d{2})-(\\d{2})$'",[70,125,126],{"class":80},", ",[70,128,130],{"class":129},"sZOz5","'%Y-%m-",[70,132,134],{"class":133},"sNEDb","%d",[70,136,137],{"class":129},"'",[70,139,140],{"class":80},"),           ",[70,142,144],{"class":143},"ss8vJ","# 2023-04-15\n",[70,146,148,150,153,155,157,159,162,165],{"class":72,"line":147},6,[70,149,120],{"class":80},[70,151,152],{"class":76},"r'^(\\d{2})\u002F(\\d{2})\u002F(\\d{4})$'",[70,154,126],{"class":80},[70,156,137],{"class":129},[70,158,134],{"class":133},[70,160,161],{"class":129},"\u002F%m\u002F%Y'",[70,163,164],{"class":80},"),            ",[70,166,167],{"class":143},"# 15\u002F04\u002F2023\n",[70,169,171,173,176,178,180,182,185,187],{"class":72,"line":170},7,[70,172,120],{"class":80},[70,174,175],{"class":76},"r'^(\\d{2})\u002F(\\d{2})\u002F(\\d{2})$'",[70,177,126],{"class":80},[70,179,137],{"class":129},[70,181,134],{"class":133},[70,183,184],{"class":129},"\u002F%m\u002F%y'",[70,186,164],{"class":80},[70,188,189],{"class":143},"# 15\u002F04\u002F23\n",[70,191,193,195,198,200,202,205,208,211,214],{"class":72,"line":192},8,[70,194,120],{"class":80},[70,196,197],{"class":76},"r'^(\\w{3})\\s+(\\d{1,2})\\s+(\\d{4})$'",[70,199,126],{"class":80},[70,201,137],{"class":129},[70,203,204],{"class":133},"%b",[70,206,207],{"class":133}," %d",[70,209,210],{"class":129}," %Y'",[70,212,213],{"class":80},"),     ",[70,215,216],{"class":143},"# Apr 15 2023\n",[70,218,220,222,225,227,229,231,234,236,239,242],{"class":72,"line":219},9,[70,221,120],{"class":80},[70,223,224],{"class":76},"r'^(\\d{1,2})-(\\w{3})-(\\d{4})$'",[70,226,126],{"class":80},[70,228,137],{"class":129},[70,230,134],{"class":133},[70,232,233],{"class":129},"-",[70,235,204],{"class":133},[70,237,238],{"class":129},"-%Y'",[70,240,241],{"class":80},"),          ",[70,243,244],{"class":143},"# 15-Apr-2023\n",[70,246,248,250,253,255,258,260,262,265],{"class":72,"line":247},10,[70,249,120],{"class":80},[70,251,252],{"class":76},"r'^(\\w{3,9})\\s+(\\d{1,2}),?\\s*(\\d{4})$'",[70,254,126],{"class":80},[70,256,257],{"class":129},"'%B ",[70,259,134],{"class":133},[70,261,210],{"class":129},[70,263,264],{"class":80},"), ",[70,266,267],{"class":143},"# April 15, 2023\n",[70,269,271,273,276,278,281,283,285,288],{"class":72,"line":270},11,[70,272,120],{"class":80},[70,274,275],{"class":76},"r'^(\\d{8})$'",[70,277,126],{"class":80},[70,279,280],{"class":129},"'%Y%m",[70,282,134],{"class":133},[70,284,137],{"class":129},[70,286,287],{"class":80},"),                               ",[70,289,290],{"class":143},"# 20230415\n",[70,292,294,296,299,301,303,305,308,310],{"class":72,"line":293},12,[70,295,120],{"class":80},[70,297,298],{"class":76},"r'^(\\d{2})\\.(\\d{2})\\.(\\d{4})$'",[70,300,126],{"class":80},[70,302,137],{"class":129},[70,304,134],{"class":133},[70,306,307],{"class":129},".%m.%Y'",[70,309,241],{"class":80},[70,311,312],{"class":143},"# 15.04.2023\n",[70,314,316],{"class":72,"line":315},13,[70,317,318],{"class":80},"]\n",[70,320,322],{"class":72,"line":321},14,[70,323,102],{"emptyLinePlaceholder":101},[70,325,327,330,333],{"class":72,"line":326},15,[70,328,329],{"class":76},"def",[70,331,332],{"class":133}," normalize_date",[70,334,335],{"class":80},"(value):\n",[70,337,339],{"class":72,"line":338},16,[70,340,341],{"class":129},"    \"\"\"Try every regex pattern and return the first clean match.\"\"\"\n",[70,343,345,348,351,354],{"class":72,"line":344},17,[70,346,347],{"class":76},"    for",[70,349,350],{"class":80}," pattern, fmt ",[70,352,353],{"class":76},"in",[70,355,356],{"class":80}," DATE_PATTERNS:\n",[70,358,360,363,365],{"class":72,"line":359},18,[70,361,362],{"class":80},"        match ",[70,364,111],{"class":76},[70,366,367],{"class":80}," re.match(pattern, value.strip())\n",[70,369,371,374],{"class":72,"line":370},19,[70,372,373],{"class":76},"        if",[70,375,376],{"class":80}," match:\n",[70,378,380,383],{"class":72,"line":379},20,[70,381,382],{"class":76},"            try",[70,384,385],{"class":80},":\n",[70,387,389,392],{"class":72,"line":388},21,[70,390,391],{"class":76},"                return",[70,393,394],{"class":80}," datetime.strptime(value.strip(), fmt).isoformat()\n",[70,396,398,401,404],{"class":72,"line":397},22,[70,399,400],{"class":76},"            except",[70,402,403],{"class":133}," ValueError",[70,405,385],{"class":80},[70,407,409],{"class":72,"line":408},23,[70,410,411],{"class":76},"                continue\n",[70,413,415,418,421],{"class":72,"line":414},24,[70,416,417],{"class":76},"    return",[70,419,420],{"class":80}," None  ",[70,422,423],{"class":143},"# Manual review\n",[10,425,426,427,430],{},"We had a version of this for ",[13,428,429],{},"every"," data cleaning task. Phone numbers, currency strings, inconsistent address formats, messy categorical variables spelled five different ways. Each one got its own script with its own set of patterns. We'd run them in a pipeline, flag the unparsable rows, and finish in minutes what used to take a full day of copy-pasting in Excel.",[23,432,434],{"id":433},"the-excel-formula-injection-trick","The Excel Formula Injection Trick",[10,436,437],{},"This one I'm actually proud of.",[10,439,440,441,444],{},"A lot of the people we were delivering reports to? They lived in Excel. They wanted to open a file and see everything: the numbers, the graphs, the conditional formatting. They didn't want to run a script. They didn't want to connect to a database. They wanted a ",[45,442,443],{},".xlsx"," file they could double-click and immediately start reading graphs.",[10,446,447,448,452,453,456],{},"So we gave them that. But here's the thing — we cleaned the data in Python, ran the manipulation in Python, and then... we used Python to ",[449,450,451],"strong",{},"write Excel formulas into specific cells"," and ",[449,454,455],{},"inject chart definitions"," so everything auto-populated on open.",[10,458,459],{},"The workflow:",[461,462,463,470,476,490,506],"ol",{},[464,465,466,469],"li",{},[449,467,468],{},"Clean"," the raw data in Python (regex pipeline).",[464,471,472,475],{},[449,473,474],{},"Transform"," it into the exact shape our \"cheat sheet\" required — specific column names in specific positions.",[464,477,478,481,482,485,486,489],{},[449,479,480],{},"Write"," it to an Excel file using ",[45,483,484],{},"openpyxl",", but ",[13,487,488],{},"also"," inject formulas into summary cells.",[464,491,492,495,496,126,499,126,502,505],{},[449,493,494],{},"Add"," Excel-native functions into specific cells — things like ",[45,497,498],{},"=SUMIFS()",[45,500,501],{},"=XLOOKUP()",[45,503,504],{},"=UNIQUE()"," — so the Excel power users could trace the numbers themselves.",[464,507,508,511],{},[449,509,510],{},"Embed"," chart definitions with exact data ranges so the graphs auto-populated when the formulas recalculated on file open.",[38,513,515],{"className":64,"code":514,"language":66,"meta":47,"style":47},"from openpyxl import Workbook\nfrom openpyxl.chart import BarChart, Reference\nfrom openpyxl.utils import get_column_letter\n\nwb = Workbook()\nws = wb.active\n\n# Write cleaned data\nfor row in cleaned_data:\n    ws.append(row)\n\n# Inject formulas in summary cells\nws['H1'] = 'Total (Formula)'\nfor i in range(2, len(cleaned_data) + 2):\n    ws[f'H{i}'] = f'=SUM(B{i}:G{i})'\n\n# Add an XLOOKUP lookup table so Excel natives can follow the logic\nws['J1'] = 'Category'\nws['K1'] = 'Lookup Value'\nfor idx, cat in enumerate(categories, start=2):\n    ws[f'J{idx}'] = cat\n    ws[f'K{idx}'] = f'=XLOOKUP(J{idx}, A:A, H:H)'\n\n# Create chart\nchart = BarChart()\nchart.title = \"Auto-Generated Report\"\ndata = Reference(ws, min_col=2, max_col=7, min_row=1, max_row=len(cleaned_data))\ncats = Reference(ws, min_col=1, min_row=2, max_row=len(cleaned_data))\nchart.add_data(data, titles_from_data=True)\nchart.set_categories(cats)\nws.add_chart(chart, \"M1\")\n\nwb.save(\"report.xlsx\")\n",[45,516,517,529,541,553,557,567,577,581,586,599,604,608,613,629,664,714,718,723,737,751,772,797,832,836,841,852,863,904,932,943,949,961,966],{"__ignoreMap":47},[70,518,519,521,524,526],{"class":72,"line":73},[70,520,87],{"class":76},[70,522,523],{"class":80}," openpyxl ",[70,525,77],{"class":76},[70,527,528],{"class":80}," Workbook\n",[70,530,531,533,536,538],{"class":72,"line":84},[70,532,87],{"class":76},[70,534,535],{"class":80}," openpyxl.chart ",[70,537,77],{"class":76},[70,539,540],{"class":80}," BarChart, Reference\n",[70,542,543,545,548,550],{"class":72,"line":98},[70,544,87],{"class":76},[70,546,547],{"class":80}," openpyxl.utils ",[70,549,77],{"class":76},[70,551,552],{"class":80}," get_column_letter\n",[70,554,555],{"class":72,"line":105},[70,556,102],{"emptyLinePlaceholder":101},[70,558,559,562,564],{"class":72,"line":117},[70,560,561],{"class":80},"wb ",[70,563,111],{"class":76},[70,565,566],{"class":80}," Workbook()\n",[70,568,569,572,574],{"class":72,"line":147},[70,570,571],{"class":80},"ws ",[70,573,111],{"class":76},[70,575,576],{"class":80}," wb.active\n",[70,578,579],{"class":72,"line":170},[70,580,102],{"emptyLinePlaceholder":101},[70,582,583],{"class":72,"line":192},[70,584,585],{"class":143},"# Write cleaned data\n",[70,587,588,591,594,596],{"class":72,"line":219},[70,589,590],{"class":76},"for",[70,592,593],{"class":80}," row ",[70,595,353],{"class":76},[70,597,598],{"class":80}," cleaned_data:\n",[70,600,601],{"class":72,"line":247},[70,602,603],{"class":80},"    ws.append(row)\n",[70,605,606],{"class":72,"line":270},[70,607,102],{"emptyLinePlaceholder":101},[70,609,610],{"class":72,"line":293},[70,611,612],{"class":143},"# Inject formulas in summary cells\n",[70,614,615,618,621,624,626],{"class":72,"line":315},[70,616,617],{"class":80},"ws[",[70,619,620],{"class":129},"'H1'",[70,622,623],{"class":80},"] ",[70,625,111],{"class":76},[70,627,628],{"class":129}," 'Total (Formula)'\n",[70,630,631,633,636,638,641,644,647,649,652,655,658,661],{"class":72,"line":321},[70,632,590],{"class":76},[70,634,635],{"class":80}," i ",[70,637,353],{"class":76},[70,639,640],{"class":133}," range",[70,642,643],{"class":80},"(",[70,645,646],{"class":133},"2",[70,648,126],{"class":80},[70,650,651],{"class":133},"len",[70,653,654],{"class":80},"(cleaned_data) ",[70,656,657],{"class":76},"+",[70,659,660],{"class":133}," 2",[70,662,663],{"class":80},"):\n",[70,665,666,669,672,675,678,681,684,686,688,690,693,696,698,700,702,705,707,709,711],{"class":72,"line":326},[70,667,668],{"class":80},"    ws[",[70,670,671],{"class":76},"f",[70,673,674],{"class":129},"'H",[70,676,677],{"class":133},"{",[70,679,680],{"class":80},"i",[70,682,683],{"class":133},"}",[70,685,137],{"class":129},[70,687,623],{"class":80},[70,689,111],{"class":76},[70,691,692],{"class":76}," f",[70,694,695],{"class":129},"'=SUM(B",[70,697,677],{"class":133},[70,699,680],{"class":80},[70,701,683],{"class":133},[70,703,704],{"class":129},":G",[70,706,677],{"class":133},[70,708,680],{"class":80},[70,710,683],{"class":133},[70,712,713],{"class":129},")'\n",[70,715,716],{"class":72,"line":338},[70,717,102],{"emptyLinePlaceholder":101},[70,719,720],{"class":72,"line":344},[70,721,722],{"class":143},"# Add an XLOOKUP lookup table so Excel natives can follow the logic\n",[70,724,725,727,730,732,734],{"class":72,"line":359},[70,726,617],{"class":80},[70,728,729],{"class":129},"'J1'",[70,731,623],{"class":80},[70,733,111],{"class":76},[70,735,736],{"class":129}," 'Category'\n",[70,738,739,741,744,746,748],{"class":72,"line":370},[70,740,617],{"class":80},[70,742,743],{"class":129},"'K1'",[70,745,623],{"class":80},[70,747,111],{"class":76},[70,749,750],{"class":129}," 'Lookup Value'\n",[70,752,753,755,758,760,763,766,768,770],{"class":72,"line":379},[70,754,590],{"class":76},[70,756,757],{"class":80}," idx, cat ",[70,759,353],{"class":76},[70,761,762],{"class":133}," enumerate",[70,764,765],{"class":80},"(categories, start",[70,767,111],{"class":76},[70,769,646],{"class":133},[70,771,663],{"class":80},[70,773,774,776,778,781,783,786,788,790,792,794],{"class":72,"line":388},[70,775,668],{"class":80},[70,777,671],{"class":76},[70,779,780],{"class":129},"'J",[70,782,677],{"class":133},[70,784,785],{"class":80},"idx",[70,787,683],{"class":133},[70,789,137],{"class":129},[70,791,623],{"class":80},[70,793,111],{"class":76},[70,795,796],{"class":80}," cat\n",[70,798,799,801,803,806,808,810,812,814,816,818,820,823,825,827,829],{"class":72,"line":397},[70,800,668],{"class":80},[70,802,671],{"class":76},[70,804,805],{"class":129},"'K",[70,807,677],{"class":133},[70,809,785],{"class":80},[70,811,683],{"class":133},[70,813,137],{"class":129},[70,815,623],{"class":80},[70,817,111],{"class":76},[70,819,692],{"class":76},[70,821,822],{"class":129},"'=XLOOKUP(J",[70,824,677],{"class":133},[70,826,785],{"class":80},[70,828,683],{"class":133},[70,830,831],{"class":129},", A:A, H:H)'\n",[70,833,834],{"class":72,"line":408},[70,835,102],{"emptyLinePlaceholder":101},[70,837,838],{"class":72,"line":414},[70,839,840],{"class":143},"# Create chart\n",[70,842,844,847,849],{"class":72,"line":843},25,[70,845,846],{"class":80},"chart ",[70,848,111],{"class":76},[70,850,851],{"class":80}," BarChart()\n",[70,853,855,858,860],{"class":72,"line":854},26,[70,856,857],{"class":80},"chart.title ",[70,859,111],{"class":76},[70,861,862],{"class":129}," \"Auto-Generated Report\"\n",[70,864,866,869,871,874,876,878,881,883,886,889,891,894,897,899,901],{"class":72,"line":865},27,[70,867,868],{"class":80},"data ",[70,870,111],{"class":76},[70,872,873],{"class":80}," Reference(ws, min_col",[70,875,111],{"class":76},[70,877,646],{"class":133},[70,879,880],{"class":80},", max_col",[70,882,111],{"class":76},[70,884,885],{"class":133},"7",[70,887,888],{"class":80},", min_row",[70,890,111],{"class":76},[70,892,893],{"class":133},"1",[70,895,896],{"class":80},", max_row",[70,898,111],{"class":76},[70,900,651],{"class":133},[70,902,903],{"class":80},"(cleaned_data))\n",[70,905,907,910,912,914,916,918,920,922,924,926,928,930],{"class":72,"line":906},28,[70,908,909],{"class":80},"cats ",[70,911,111],{"class":76},[70,913,873],{"class":80},[70,915,111],{"class":76},[70,917,893],{"class":133},[70,919,888],{"class":80},[70,921,111],{"class":76},[70,923,646],{"class":133},[70,925,896],{"class":80},[70,927,111],{"class":76},[70,929,651],{"class":133},[70,931,903],{"class":80},[70,933,935,938,940],{"class":72,"line":934},29,[70,936,937],{"class":80},"chart.add_data(data, titles_from_data",[70,939,111],{"class":76},[70,941,942],{"class":80},"True)\n",[70,944,946],{"class":72,"line":945},30,[70,947,948],{"class":80},"chart.set_categories(cats)\n",[70,950,952,955,958],{"class":72,"line":951},31,[70,953,954],{"class":80},"ws.add_chart(chart, ",[70,956,957],{"class":129},"\"M1\"",[70,959,960],{"class":80},")\n",[70,962,964],{"class":72,"line":963},32,[70,965,102],{"emptyLinePlaceholder":101},[70,967,969,972,975],{"class":72,"line":968},33,[70,970,971],{"class":80},"wb.save(",[70,973,974],{"class":129},"\"report.xlsx\"",[70,976,960],{"class":80},[10,978,979,980,983,984],{},"The Excel fans opened the file, saw the numbers, saw the graphs, saw the formulas. They nodded approvingly. They understood how the numbers connected because they could click on a cell and trace the formula. We got to automate the grunt work ",[13,981,982],{},"and"," make it transparent. ",[449,985,986],{},"Best of both worlds.",[10,988,989],{},[449,990,991],{},"We were cracked.",[23,993,995],{"id":994},"the-collection","The Collection",[10,997,998],{},"Eventually we built up a whole arsenal. Python scripts for specific data cleaning tasks. R scripts for statistical analysis with pre-written ggplot2 templates. Excel templates with premade pivot tables. PowerShell scripts for file organisation.",[10,1000,1001],{},"Every script had a name. Every script had a README (eventually, after the third time we forgot what something did). Every script was designed to be run with one command and produce a consistent output.",[10,1003,1004,1005,1008,1009,1011],{},"We stopped writing code for specific tasks and started writing code that ",[449,1006,1007],{},"generated"," the deliverable. The difference is subtle but massive: instead of \"clean this CSV\" you write \"clean all CSVs that look like this.\" The first approach solves today's problem. The second approach solves today's ",[13,1010,982],{}," next week's.",[10,1013,1014,1015,1021],{},"No wonder ",[17,1016,1020],{"href":1017,"rel":1018},"https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Fbrian-m-mampane-29672121b",[1019],"nofollow","Brian"," and I keep getting asked to automate things for people.",[23,1023,1025],{"id":1024},"the-real-payoff","The Real Payoff",[10,1027,1028],{},"It's not the time. I mean, it is — saving hours or days per week adds up. But the real payoff is something else.",[10,1030,1031,1032,1035],{},"When you automate something, you ",[13,1033,1034],{},"understand"," it. You've decomposed the task into its actual components. You've figured out which parts are patterns and which parts are exceptions. You've built a model of the work in your head, and then you've encoded that model into code.",[10,1037,1038],{},"The people who say \"it's faster to just do it manually\" are missing the point. The automation isn't just about saving time on this one task. It's about building a reusable understanding. It's about learning to see the patterns. It's about being the person who looks at a messy process and thinks \"there's a better way to do this.\"",[10,1040,1041,1042,33],{},"That skill — the ability to see the pattern, abstract it, and encode it — that's what actually scales. Not the scripts themselves. ",[13,1043,1044],{},"The method",[10,1046,1047],{},"And yeah, also the time. Having time to run errands during work hours because you've already delivered is pretty great too.",[1049,1050],"hr",{},[10,1052,1053],{},[449,1054,1055],{},"It's not being lazy. It's called productivity maxxing.",[10,1057,1058],{},[13,1059,1060],{},"If you've got something repetitive eating your week and you can't figure out how to automate it — hit me up. We're always free. For the right price.",[1062,1063,1064],"style",{},"html pre.shiki code .sq0yK, html code.shiki .sq0yK{--shiki-default:#A0A0A0}html pre.shiki code .sU-n2, html code.shiki .sU-n2{--shiki-default:#FFF}html pre.shiki code .sZOz5, html code.shiki .sZOz5{--shiki-default:#99FFE4}html pre.shiki code .sNEDb, html code.shiki .sNEDb{--shiki-default:#FFC799}html pre.shiki code .ss8vJ, html code.shiki .ss8vJ{--shiki-default:#8B8B8B94}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);}",{"title":47,"searchDepth":84,"depth":84,"links":1066},[1067,1068,1069,1070],{"id":25,"depth":84,"text":26},{"id":433,"depth":84,"text":434},{"id":994,"depth":84,"text":995},{"id":1024,"depth":84,"text":1025},"2026-06-19","The specific scripts behind THE METHOD — regex date cleaning, Excel formula injection, and an arsenal that finished 10-day sprints on day 1.","md",false,{},"\u002Fblog\u002Fproductive-laziness-toolkit",{"title":5,"description":1072},"blog\u002Fproductive-laziness-toolkit",[1080,66],"productivity","Regex pipelines that normalise messy dates, Excel formula injection that makes reports auto-populate, and the complete automation arsenal. The technical playbook behind finishing 10-day sprints on day 1.","HaYrI7nvclpnjNSG6X7S56Z0DzMSjIIm45_4ZK8wkgo",1784129939870]