[{"data":1,"prerenderedAt":2624},["ShallowReactive",2],{"blog-paginated-count":3,"blog-paginated-43":4,"blog-paginated-cats":1977},640,[5,123,279,1020,1188,1389,1552,1681,1788,1881],{"id":6,"title":7,"author":8,"body":11,"category":98,"date":99,"description":100,"extension":101,"featured":102,"image":103,"keywords":104,"meta":110,"navigation":111,"path":112,"readTime":113,"seo":114,"stem":115,"tags":116,"__hash__":122},"blog/blog/scottish-mercenaries-gallowglass.md","Gallowglass: Scottish Mercenaries in Medieval Ireland",{"name":9,"bio":10},"James Ross Jr.","Strategic Systems Architect & Enterprise Software Developer",{"type":12,"value":13,"toc":89},"minimark",[14,19,28,37,40,44,47,50,53,57,60,68,76,80,83,86],[15,16,18],"h2",{"id":17},"warriors-for-hire","Warriors for Hire",[20,21,22,23,27],"p",{},"The Gallowglass -- from the Irish ",[24,25,26],"em",{},"galloglach",", meaning \"foreign warrior\" -- were professional soldiers of Scottish and Norse-Gaelic origin who served as elite mercenaries in Ireland from the mid-thirteenth century through the sixteenth century. They were not raiders or adventurers. They were professional heavy infantry, recruited by Irish kings and chieftains to provide the military backbone that native Irish forces often lacked. Their arrival in Ireland transformed Irish warfare, and their descendants became permanent members of Irish society.",[20,29,30,31,36],{},"The first Gallowglass came to Ireland around 1259, when Aedh O'Conor, King of Connacht, recruited a force of Scottish warriors from the Hebrides to fight in his wars against rival Irish kings and the Anglo-Norman settlers. These early Gallowglass were drawn from the same Norse-Gaelic world that produced the ",[32,33,35],"a",{"href":34},"/blog/lord-of-the-isles-history","Lords of the Isles"," -- the mixed-heritage communities of the Hebrides and the western Scottish Highlands, where Norse military traditions had merged with Gaelic social structures.",[20,38,39],{},"The connection between the Gallowglass and Scotland was direct and personal. The major Gallowglass families -- the MacDonnells, MacSweeneys, MacCabes, and MacSheehys -- were cadet branches of Scottish Highland clans who established themselves in Ireland through military service. The MacDonnells of Antrim, for example, were a branch of Clan Donald, the same family that held the Lordship of the Isles. The MacSweeneys traced their origin to Sween Castle in Argyll. These were not anonymous soldiers of fortune. They were members of specific kinship groups with specific homelands, who transplanted themselves to Ireland while maintaining connections to their Scottish origins.",[15,41,43],{"id":42},"the-gallowglass-in-battle","The Gallowglass in Battle",[20,45,46],{},"The Gallowglass fought as heavy infantry at a time when most Irish warfare was conducted by lighter troops -- javelin-armed kerns, cavalry, and missile troops. The typical Gallowglass warrior wore a mail shirt (later supplemented or replaced by a padded jack or iron helmet), carried a large two-handed axe or a claymore (two-handed sword), and was accompanied by two attendants: a boy who carried spare weapons and a kern who served as a light infantry support.",[20,48,49],{},"The two-handed axe was the signature weapon of the Gallowglass, and it made them devastating in close combat. Sixteenth-century English accounts describe the Gallowglass axe as capable of cleaving through helmet and skull in a single blow. The axe was a Norse inheritance -- the same weapon type that had been used by Viking warriors centuries earlier -- and its effectiveness against armored opponents made the Gallowglass the counter to the Anglo-Norman heavy cavalry that had dominated Irish battlefields since the invasion of 1169.",[20,51,52],{},"Gallowglass fought in tight formations, presenting a wall of axes that was extremely difficult to break. They were disciplined, experienced, and motivated by a combination of professional pride and the economic imperative of maintaining their reputation. A Gallowglass family that earned a reputation for reliability and ferocity could secure permanent employment with an Irish king, receiving land and provisions in exchange for military service. A family that failed in battle lost everything.",[15,54,56],{"id":55},"settlement-and-integration","Settlement and Integration",[20,58,59],{},"The Gallowglass did not remain a foreign element in Irish society. Within a generation or two, the major Gallowglass families were thoroughly integrated into the Irish political and social landscape. They held land, married into Irish families, spoke Irish, and participated in Irish cultural life. The MacSweeneys became one of the most prominent families in Donegal. The MacDonnells became the dominant power in Antrim, eventually establishing a lordship that bridged the narrow channel between Ireland and Scotland.",[20,61,62,63,67],{},"The integration of the Gallowglass into Irish society illustrates the permeability of the medieval Gaelic world. The Irish Sea was not a barrier but a highway, and the cultural distance between Gaelic Scotland and Gaelic Ireland was minimal. The ",[32,64,66],{"href":65},"/blog/scottish-gaelic-language-history","Gaelic language"," was mutually intelligible across the two countries. Social structures -- kinship, fosterage, clientship -- were similar. The Gallowglass were foreigners, but culturally they were close enough to their Irish employers to be absorbed within a generation.",[20,69,70,71,75],{},"This integration also ran in the other direction. Irish Gaelic families recruited Scottish Gallowglass, but Scottish Gaelic families also recruited Irish warriors. The flow of military manpower across the Irish Sea was bidirectional, and it created networks of kinship and obligation that connected the two countries at every social level. The ",[32,72,74],{"href":73},"/blog/scottish-clan-system-explained","clan structures"," of Gaelic Scotland and Gaelic Ireland were not parallel systems. They were interconnected systems, linked by marriage, military service, and cultural exchange.",[15,77,79],{"id":78},"the-end-of-the-gallowglass","The End of the Gallowglass",[20,81,82],{},"The Gallowglass tradition persisted through the sixteenth century, adapting to the introduction of firearms and changing tactical conditions. Gallowglass families adopted firearms alongside their traditional axes and swords, and they continued to serve as the military elite of the Gaelic Irish lords who resisted English conquest. The Nine Years' War (1594-1603) was the last major conflict in which Gallowglass fought as a distinct military force, serving under Hugh O'Neill and Red Hugh O'Donnell against the armies of Elizabeth I.",[20,84,85],{},"The defeat of the Gaelic lords in that war, and the subsequent Flight of the Earls in 1607, ended the political structures that had sustained the Gallowglass. With no Gaelic kings to serve, no land grants to earn, and no independent Irish military establishment to join, the Gallowglass ceased to exist as a coherent institution. Many went into continental European military service, joining the Irish regiments that served in the armies of Spain, France, and Austria.",[20,87,88],{},"The Gallowglass left a permanent mark on Irish history. Their surnames -- MacDonnell, MacSweeney, MacCabe -- are common in Ireland today. Their military tradition influenced Irish martial culture for centuries. And their story illustrates one of the most important dynamics in the medieval Celtic world: the constant movement of people, skills, and cultural practices across the Irish Sea, binding Scotland and Ireland together in a web of kinship and service that the modern border between the two countries obscures but does not erase.",{"title":90,"searchDepth":91,"depth":91,"links":92},"",3,[93,95,96,97],{"id":17,"depth":94,"text":18},2,{"id":42,"depth":94,"text":43},{"id":55,"depth":94,"text":56},{"id":78,"depth":94,"text":79},"Heritage","2025-06-08","The Gallowglass were elite Scottish mercenary warriors who crossed to Ireland beginning in the thirteenth century and became a permanent fixture of Irish warfare, politics, and society. They were the most feared soldiers on the island.","md",false,null,[105,106,107,108,109],"gallowglass warriors","scottish mercenaries ireland","gallowglass history","medieval irish warfare","gaelic mercenaries",{},true,"/blog/scottish-mercenaries-gallowglass",7,{"title":7,"description":100},"blog/scottish-mercenaries-gallowglass",[117,118,119,120,121],"Gallowglass","Scottish Mercenaries","Medieval Ireland","Norse-Gaelic Warriors","Highland Warriors","iwwY2r5d3Q85jRMcVp-_8i1qorBXRi9Mr2B3ENDGvCs",{"id":124,"title":125,"author":126,"body":127,"category":265,"date":99,"description":266,"extension":101,"featured":102,"image":103,"keywords":267,"meta":270,"navigation":111,"path":271,"readTime":113,"seo":272,"stem":273,"tags":274,"__hash__":278},"blog/blog/startup-mvp-strategy.md","MVP Strategy for Startups: Building Just Enough",{"name":9,"bio":10},{"type":12,"value":128,"toc":259},[129,133,136,139,143,146,153,159,165,168,176,180,183,186,189,192,198,202,205,211,217,223,229,233,236,247,250,256],[130,131,125],"h1",{"id":132},"mvp-strategy-for-startups-building-just-enough",[20,134,135],{},"The minimum viable product concept has been distorted beyond recognition. Startup teams either build too little — a landing page with an email signup that validates nothing — or too much — a full-featured product that took eight months and a hundred thousand dollars before a single user saw it. Neither extreme serves the purpose an MVP is designed to fulfill.",[20,137,138],{},"An MVP is a learning instrument. Its purpose is to answer a specific question about your market, your users, or your product with the minimum investment required to get a credible answer. Everything about your MVP strategy should flow from that purpose.",[15,140,142],{"id":141},"choosing-what-to-validate-first","Choosing What to Validate First",[20,144,145],{},"Not all assumptions carry equal risk. Some, if wrong, invalidate the entire business. Others, if wrong, are easily corrected. Your MVP should target the riskiest assumption first.",[20,147,148,152],{},[149,150,151],"strong",{},"Demand risk:"," Will people pay for this? This is the most fundamental question. If nobody will pay for your solution to their problem, nothing else matters. Validate demand before validating anything else. Techniques include pre-selling to prospective customers, running a crowdfunding campaign, or building a concierge MVP where you deliver the service manually before automating it.",[20,154,155,158],{},[149,156,157],{},"Usability risk:"," Can people figure out how to use this? Some products solve a real problem but are too complex for the target user. If your product requires a thirty-minute onboarding tutorial, the adoption friction may be too high for the market. Validate usability with a functional prototype that real users attempt to use without guidance.",[20,160,161,164],{},[149,162,163],{},"Technical risk:"," Can this be built? Some products depend on technical capabilities that are unproven. If your product requires real-time processing of ten thousand events per second with sub-millisecond latency, and you have never built that, the technical feasibility is a risk that should be validated early. Build a technical spike that proves the critical path before building the product around it.",[20,166,167],{},"The common mistake is validating the easiest assumption first because it is less uncomfortable. Talking to users about whether they would pay for something is uncomfortable. Building a technical prototype in isolation is comfortable. But a technically impressive product that nobody wants is a worse outcome than an ugly prototype that validates real demand.",[20,169,170,171,175],{},"For a deeper treatment of the tactical build process, the ",[32,172,174],{"href":173},"/blog/mvp-development-guide","MVP development guide"," covers scoping, technology choices, and execution.",[15,177,179],{"id":178},"scoping-with-discipline","Scoping With Discipline",[20,181,182],{},"The hardest part of MVP strategy is deciding what not to build. Every feature you add increases development time, delays learning, and dilutes focus. The discipline is in subtracting, not adding.",[20,184,185],{},"Start with the user's job to be done. What is the one core task your product must accomplish? Not three tasks, not a platform that does everything — one task. A project management tool for freelancers must let users track tasks and deadlines. Everything else — time tracking, invoicing, client portals, reporting — is not part of the core job.",[20,187,188],{},"Define the minimum feature set that makes that one job achievable. Not delightful, not comprehensive — achievable. The user must be able to complete the core workflow from start to finish. If any step in the workflow is missing, the product does not work and you cannot validate the concept.",[20,190,191],{},"Exclude everything that is not on the critical path. User profiles, settings pages, admin dashboards, analytics, notification preferences, dark mode — none of these are required to validate whether users will adopt your core workflow. Build them after you have validated the core, not before.",[20,193,194,197],{},[149,195,196],{},"Manual processes can replace features."," Instead of building an automated email notification system, send the emails manually for the first fifty users. Instead of building a reporting dashboard, export data to a spreadsheet and email it to users who request it. Instead of building a payment integration, send invoices manually. Each manual process you substitute for an automated feature saves days or weeks of development time.",[15,199,201],{"id":200},"technology-choices-for-mvps","Technology Choices for MVPs",[20,203,204],{},"Technology choices for an MVP should optimize for speed of iteration, not long-term scalability. You are building a product that will either be validated and rebuilt properly or invalidated and discarded. In neither case does the initial technology choice matter as much as you think.",[20,206,207,210],{},[149,208,209],{},"Use frameworks you already know."," An MVP built with a familiar framework in three weeks is more valuable than an MVP built with the \"right\" framework in eight weeks. The three weeks of learning you capture from user feedback outweighs any technical advantage of the unfamiliar framework.",[20,212,213,216],{},[149,214,215],{},"Use managed services."," Do not set up your own database server, email service, or file storage. Use hosted services — Supabase, Firebase, Cloudflare, Resend — that handle infrastructure so you can focus on product logic. The monthly cost of managed services for an MVP is trivial compared to the engineering time required to operate your own infrastructure.",[20,218,219,222],{},[149,220,221],{},"Deploy early and continuously."," Your MVP should be deployed from day one. Not at the end — from the first day of development. Deploy a blank page, then deploy with a login flow, then deploy with the core feature. Every deployment is a checkpoint that proves your infrastructure works and lets you show progress to stakeholders and early testers.",[20,224,225,228],{},[149,226,227],{},"Do not optimize prematurely."," Performance optimization, caching strategies, and infrastructure scaling are problems for products that have users. Your MVP does not have users yet. Build for correctness first. When you have enough users that performance matters, you will have validated the concept, and performance optimization is a good problem to have.",[15,230,232],{"id":231},"from-mvp-to-product","From MVP to Product",[20,234,235],{},"The MVP is not the product. It is the experiment that tells you what the product should be. The transition from MVP to product is where many startups stumble.",[20,237,238,241,242,246],{},[149,239,240],{},"Do not add features to the MVP."," When users provide feedback, the temptation is to bolt new features onto the existing MVP codebase. Resist this. The MVP was built for speed, not maintainability. Adding features to a speed-optimized codebase accumulates ",[32,243,245],{"href":244},"/blog/technical-debt-business-impact","technical debt"," that will slow you down quickly.",[20,248,249],{},"Instead, use the learnings from the MVP to design the product properly. The MVP taught you which features users actually need, which workflows they follow, and what data model supports the real use cases. Design the product architecture based on these learnings, not on your pre-MVP assumptions.",[20,251,252,255],{},[149,253,254],{},"Rebuild selectively."," You do not necessarily need to rewrite everything. Some MVP code — authentication, basic CRUD, database schema — may be sound enough to carry forward. Evaluate each component individually. Keep what works, replace what does not, and design the architecture to support the features you now know you need.",[20,257,258],{},"The companies that succeed with MVP strategy are the ones that treat the MVP as a learning phase, not a building phase. The output of an MVP is not software. It is validated knowledge about your market that informs what you build next. Keep the investment small, the learning cycle short, and the willingness to adapt high. The product that emerges from this process will be better than anything you could have designed in a conference room.",{"title":90,"searchDepth":91,"depth":91,"links":260},[261,262,263,264],{"id":141,"depth":94,"text":142},{"id":178,"depth":94,"text":179},{"id":200,"depth":94,"text":201},{"id":231,"depth":94,"text":232},"Business","An MVP is not about building less. It is about learning faster. Here's a strategic framework for scoping, building, and iterating on your first product version.",[268,269],"MVP strategy startups","minimum viable product strategy",{},"/blog/startup-mvp-strategy",{"title":125,"description":266},"blog/startup-mvp-strategy",[275,276,277],"MVP","Startups","Product Strategy","GuvXK0Dw43VbDaIdz_6J2cAqcn255C6TPISVVm6qeT8",{"id":280,"title":281,"author":282,"body":283,"category":1006,"date":99,"description":1007,"extension":101,"featured":102,"image":103,"keywords":1008,"meta":1011,"navigation":111,"path":1012,"readTime":414,"seo":1013,"stem":1014,"tags":1015,"__hash__":1019},"blog/blog/web-fonts-performance.md","Web Font Loading Strategies for Optimal Performance",{"name":9,"bio":10},{"type":12,"value":284,"toc":999},[285,289,292,295,298,301,304,308,316,418,425,433,447,455,471,473,477,480,486,500,512,669,672,678,680,684,695,701,710,713,781,787,789,793,801,817,950,953,967,970,992,995],[15,286,288],{"id":287},"the-cost-of-custom-fonts","The Cost of Custom Fonts",[20,290,291],{},"Typography defines how a website feels. The right typeface communicates brand personality, establishes hierarchy, and improves readability. But every custom font file is a network request that blocks text rendering until it completes. On a fast connection, the delay is imperceptible. On a slow connection — or the first visit before anything is cached — custom fonts can hide text for 2-3 seconds while the files download.",[20,293,294],{},"This is not a theoretical problem. The default browser behavior for web fonts is called \"Flash of Invisible Text\" (FOIT). When the browser encounters text styled with a font that has not loaded yet, it renders the text as invisible. The layout is correct — the space is reserved — but the user sees blank areas where text should be. Once the font loads, the text appears. This behavior means that the most important content on your page — your heading, your value proposition, your navigation — is invisible during the critical first seconds of the page load.",[20,296,297],{},"The alternative behavior is \"Flash of Unstyled Text\" (FOUT), where the browser renders text in a fallback system font immediately and swaps to the custom font when it loads. FOUT is visible — there is a brief flash as the font changes — but users can read your content from the first paint rather than staring at blank space.",[20,299,300],{},"For most web applications, FOUT is preferable to FOIT. Visible text in a fallback font is always better than invisible text in no font. The engineering goal is to minimize the visual disruption of the swap while ensuring text is always readable.",[302,303],"hr",{},[15,305,307],{"id":306},"the-font-display-property","The font-display Property",[20,309,310,311,315],{},"The ",[312,313,314],"code",{},"font-display"," CSS property controls how the browser handles the gap between requesting a font and receiving it. It is the single most impactful font performance setting:",[317,318,322],"pre",{"className":319,"code":320,"language":321,"meta":90,"style":90},"language-css shiki shiki-themes github-dark","@font-face {\n font-family: 'Inter';\n src: url('/fonts/inter-var.woff2') format('woff2');\n font-weight: 100 900;\n font-display: swap;\n}\n","css",[312,323,324,337,353,383,399,412],{"__ignoreMap":90},[325,326,329,333],"span",{"class":327,"line":328},"line",1,[325,330,332],{"class":331},"snl16","@font-face",[325,334,336],{"class":335},"s95oV"," {\n",[325,338,339,343,346,350],{"class":327,"line":94},[325,340,342],{"class":341},"sDLfK"," font-family",[325,344,345],{"class":335},": ",[325,347,349],{"class":348},"sU2Wk","'Inter'",[325,351,352],{"class":335},";\n",[325,354,355,358,360,363,366,369,372,375,377,380],{"class":327,"line":91},[325,356,357],{"class":341}," src",[325,359,345],{"class":335},[325,361,362],{"class":341},"url",[325,364,365],{"class":335},"(",[325,367,368],{"class":348},"'/fonts/inter-var.woff2'",[325,370,371],{"class":335},") ",[325,373,374],{"class":341},"format",[325,376,365],{"class":335},[325,378,379],{"class":348},"'woff2'",[325,381,382],{"class":335},");\n",[325,384,386,389,391,394,397],{"class":327,"line":385},4,[325,387,388],{"class":341}," font-weight",[325,390,345],{"class":335},[325,392,393],{"class":341},"100",[325,395,396],{"class":341}," 900",[325,398,352],{"class":335},[325,400,402,405,407,410],{"class":327,"line":401},5,[325,403,404],{"class":341}," font-display",[325,406,345],{"class":335},[325,408,409],{"class":341},"swap",[325,411,352],{"class":335},[325,413,415],{"class":327,"line":414},6,[325,416,417],{"class":335},"}\n",[20,419,420,424],{},[149,421,422],{},[312,423,409],{},": Shows fallback text immediately, swaps to the custom font whenever it loads. Text is always visible. The swap may cause a layout shift if the fallback font has different metrics than the custom font. This is the right choice for body text where readability matters more than visual consistency.",[20,426,427,432],{},[149,428,429],{},[312,430,431],{},"optional",": Shows fallback text. If the custom font loads within approximately 100ms, it swaps in. Otherwise, the fallback font stays for the entire page load. The font is cached for subsequent visits. This is the best choice for performance-critical pages — it eliminates both FOIT and late-swap layout shifts, at the cost of sometimes not showing the custom font at all on first visit.",[20,434,435,440,441,443,444,446],{},[149,436,437],{},[312,438,439],{},"fallback",": A middle ground. Shows fallback text, gives the font about 3 seconds to load, then commits to whichever font is active. Less aggressive than ",[312,442,431],{}," but more controlled than ",[312,445,409],{},".",[20,448,449,454],{},[149,450,451],{},[312,452,453],{},"block",": The default behavior in most browsers. Hides text for up to 3 seconds while waiting for the font. If the font loads within that window, it appears. If not, fallback text shows. This is almost never the right choice for body text.",[20,456,457,458,462,463,466,467,470],{},"For ",[32,459,461],{"href":460},"/blog/landing-page-optimization","landing pages"," and performance-critical pages, use ",[312,464,465],{},"font-display: optional"," for body text. The user sees text immediately, and on repeat visits the cached font loads instantly. For display typography (headings, hero text) where the visual design depends on the specific font, ",[312,468,469],{},"font-display: swap"," ensures the correct font eventually appears while keeping text readable during loading.",[302,472],{},[15,474,476],{"id":475},"reducing-font-file-size","Reducing Font File Size",[20,478,479],{},"Font files range from 20KB to 500KB+ depending on the format, character set, and number of weights and styles included. Reducing file size directly reduces load time.",[20,481,482,485],{},[149,483,484],{},"Use WOFF2."," WOFF2 compression produces files 30-50% smaller than WOFF and dramatically smaller than TTF or OTF. Browser support is universal. There is no reason to serve any other format as the primary font file. Include WOFF as a fallback only if you need to support very old browsers.",[20,487,488,491,492,495,496,499],{},[149,489,490],{},"Subset your fonts."," If your site is English-only, you do not need the full Unicode character set. A font that includes Latin, Greek, Cyrillic, Arabic, and CJK characters might be 400KB. Subsetting to Latin characters reduces it to 30KB. Tools like ",[312,493,494],{},"glyphhanger"," and ",[312,497,498],{},"subfont"," automate subsetting based on the characters actually used on your pages.",[20,501,502,503,506,507,511],{},"Google Fonts subsets automatically via the ",[312,504,505],{},"text"," parameter, but self-hosting with manual subsetting gives you more control. For sites that may need to support ",[32,508,510],{"href":509},"/blog/internationalization-web-apps","multiple languages",", use Unicode-range subsetting to split the font into per-script chunks that load on demand:",[317,513,515],{"className":319,"code":514,"language":321,"meta":90,"style":90},"/* Latin characters */\n@font-face {\n font-family: 'Inter';\n src: url('/fonts/inter-latin.woff2') format('woff2');\n unicode-range: U+0000-00FF, U+0131, U+0152-0153;\n}\n\n/* Cyrillic characters */\n@font-face {\n font-family: 'Inter';\n src: url('/fonts/inter-cyrillic.woff2') format('woff2');\n unicode-range: U+0400-045F, U+0490-0491, U+04B0-04B1;\n}\n",[312,516,517,523,529,539,562,585,589,594,600,607,618,642,664],{"__ignoreMap":90},[325,518,519],{"class":327,"line":328},[325,520,522],{"class":521},"sAwPA","/* Latin characters */\n",[325,524,525,527],{"class":327,"line":94},[325,526,332],{"class":331},[325,528,336],{"class":335},[325,530,531,533,535,537],{"class":327,"line":91},[325,532,342],{"class":341},[325,534,345],{"class":335},[325,536,349],{"class":348},[325,538,352],{"class":335},[325,540,541,543,545,547,549,552,554,556,558,560],{"class":327,"line":385},[325,542,357],{"class":341},[325,544,345],{"class":335},[325,546,362],{"class":341},[325,548,365],{"class":335},[325,550,551],{"class":348},"'/fonts/inter-latin.woff2'",[325,553,371],{"class":335},[325,555,374],{"class":341},[325,557,365],{"class":335},[325,559,379],{"class":348},[325,561,382],{"class":335},[325,563,564,567,569,572,575,578,580,583],{"class":327,"line":401},[325,565,566],{"class":341}," unicode-range",[325,568,345],{"class":335},[325,570,571],{"class":341},"U+0000-00FF",[325,573,574],{"class":335},", ",[325,576,577],{"class":341},"U+0131",[325,579,574],{"class":335},[325,581,582],{"class":341},"U+0152-0153",[325,584,352],{"class":335},[325,586,587],{"class":327,"line":414},[325,588,417],{"class":335},[325,590,591],{"class":327,"line":113},[325,592,593],{"emptyLinePlaceholder":111},"\n",[325,595,597],{"class":327,"line":596},8,[325,598,599],{"class":521},"/* Cyrillic characters */\n",[325,601,603,605],{"class":327,"line":602},9,[325,604,332],{"class":331},[325,606,336],{"class":335},[325,608,610,612,614,616],{"class":327,"line":609},10,[325,611,342],{"class":341},[325,613,345],{"class":335},[325,615,349],{"class":348},[325,617,352],{"class":335},[325,619,621,623,625,627,629,632,634,636,638,640],{"class":327,"line":620},11,[325,622,357],{"class":341},[325,624,345],{"class":335},[325,626,362],{"class":341},[325,628,365],{"class":335},[325,630,631],{"class":348},"'/fonts/inter-cyrillic.woff2'",[325,633,371],{"class":335},[325,635,374],{"class":341},[325,637,365],{"class":335},[325,639,379],{"class":348},[325,641,382],{"class":335},[325,643,645,647,649,652,654,657,659,662],{"class":327,"line":644},12,[325,646,566],{"class":341},[325,648,345],{"class":335},[325,650,651],{"class":341},"U+0400-045F",[325,653,574],{"class":335},[325,655,656],{"class":341},"U+0490-0491",[325,658,574],{"class":335},[325,660,661],{"class":341},"U+04B0-04B1",[325,663,352],{"class":335},[325,665,667],{"class":327,"line":666},13,[325,668,417],{"class":335},[20,670,671],{},"The browser only downloads the subset that contains characters actually used on the page.",[20,673,674,677],{},[149,675,676],{},"Use variable fonts"," when you need multiple weights or styles. A variable font contains the entire weight range (100-900) in a single file, typically 80-150KB. Without variable fonts, you would download separate files for regular, medium, semibold, and bold — each 30-50KB, totaling 120-200KB and requiring four network requests. One variable font file replaces all of them.",[302,679],{},[15,681,683],{"id":682},"self-hosting-vs-google-fonts","Self-Hosting vs Google Fonts",[20,685,686,687,690,691,694],{},"Google Fonts is the most popular web font service, but it is not always the best performance choice. When you link to Google Fonts, the browser must establish connections to two additional origins (",[312,688,689],{},"fonts.googleapis.com"," for CSS and ",[312,692,693],{},"fonts.gstatic.com"," for font files), adding 100-300ms of connection overhead.",[20,696,697,698,700],{},"Self-hosting eliminates these third-party connections. Download the font files, place them in your project, and reference them with ",[312,699,332],{}," rules. The fonts load from your own domain — same connection, no additional DNS/TLS overhead.",[20,702,703,704,706,707,709],{},"Self-hosting also gives you full control over caching, subsetting, and ",[312,705,314],{}," values. Google Fonts uses ",[312,708,469],{}," by default, which you may want to override. With self-hosted fonts, you configure everything directly.",[20,711,712],{},"Preloading eliminates the discovery delay for critical fonts. Without preloading, the browser discovers the font file only after downloading and parsing the CSS that references it. Preloading starts the font download immediately:",[317,714,718],{"className":715,"code":716,"language":717,"meta":90,"style":90},"language-html shiki shiki-themes github-dark","\u003Clink\n rel=\"preload\"\n href=\"/fonts/inter-var.woff2\"\n as=\"font\"\n type=\"font/woff2\"\n crossorigin\n/>\n","html",[312,719,720,729,741,751,761,771,776],{"__ignoreMap":90},[325,721,722,725],{"class":327,"line":328},[325,723,724],{"class":335},"\u003C",[325,726,728],{"class":727},"s4JwU","link\n",[325,730,731,735,738],{"class":327,"line":94},[325,732,734],{"class":733},"svObZ"," rel",[325,736,737],{"class":335},"=",[325,739,740],{"class":348},"\"preload\"\n",[325,742,743,746,748],{"class":327,"line":91},[325,744,745],{"class":733}," href",[325,747,737],{"class":335},[325,749,750],{"class":348},"\"/fonts/inter-var.woff2\"\n",[325,752,753,756,758],{"class":327,"line":385},[325,754,755],{"class":733}," as",[325,757,737],{"class":335},[325,759,760],{"class":348},"\"font\"\n",[325,762,763,766,768],{"class":327,"line":401},[325,764,765],{"class":733}," type",[325,767,737],{"class":335},[325,769,770],{"class":348},"\"font/woff2\"\n",[325,772,773],{"class":327,"line":414},[325,774,775],{"class":733}," crossorigin\n",[325,777,778],{"class":327,"line":113},[325,779,780],{"class":335},"/>\n",[20,782,310,783,786],{},[312,784,785],{},"crossorigin"," attribute is required even for same-origin fonts because font requests use CORS by specification. Omitting it causes the font to be fetched twice — once without CORS (which fails for the font pipeline) and once with CORS.",[302,788],{},[15,790,792],{"id":791},"fallback-font-matching","Fallback Font Matching",[20,794,795,796,800],{},"The layout shift that occurs when a custom font replaces a fallback font happens because the two fonts have different metrics — different character widths, line heights, ascenders, and descenders. Text reflowing when the custom font loads causes ",[32,797,799],{"href":798},"/blog/core-web-vitals-optimization","Cumulative Layout Shift",", which hurts both user experience and search rankings.",[20,802,310,803,574,806,574,809,812,813,816],{},[312,804,805],{},"size-adjust",[312,807,808],{},"ascent-override",[312,810,811],{},"descent-override",", and ",[312,814,815],{},"line-gap-override"," descriptors let you tune a fallback font's metrics to match the custom font:",[317,818,820],{"className":319,"code":819,"language":321,"meta":90,"style":90},"@font-face {\n font-family: 'Inter Fallback';\n src: local('Arial');\n size-adjust: 107%;\n ascent-override: 90%;\n descent-override: 22%;\n line-gap-override: 0%;\n}\n\nBody {\n font-family: 'Inter', 'Inter Fallback', sans-serif;\n}\n",[312,821,822,828,839,855,870,884,898,912,916,920,927,946],{"__ignoreMap":90},[325,823,824,826],{"class":327,"line":328},[325,825,332],{"class":331},[325,827,336],{"class":335},[325,829,830,832,834,837],{"class":327,"line":94},[325,831,342],{"class":341},[325,833,345],{"class":335},[325,835,836],{"class":348},"'Inter Fallback'",[325,838,352],{"class":335},[325,840,841,843,845,848,850,853],{"class":327,"line":91},[325,842,357],{"class":341},[325,844,345],{"class":335},[325,846,847],{"class":341},"local",[325,849,365],{"class":335},[325,851,852],{"class":348},"'Arial'",[325,854,382],{"class":335},[325,856,857,860,862,865,868],{"class":327,"line":385},[325,858,859],{"class":341}," size-adjust",[325,861,345],{"class":335},[325,863,864],{"class":341},"107",[325,866,867],{"class":331},"%",[325,869,352],{"class":335},[325,871,872,875,877,880,882],{"class":327,"line":401},[325,873,874],{"class":341}," ascent-override",[325,876,345],{"class":335},[325,878,879],{"class":341},"90",[325,881,867],{"class":331},[325,883,352],{"class":335},[325,885,886,889,891,894,896],{"class":327,"line":414},[325,887,888],{"class":341}," descent-override",[325,890,345],{"class":335},[325,892,893],{"class":341},"22",[325,895,867],{"class":331},[325,897,352],{"class":335},[325,899,900,903,905,908,910],{"class":327,"line":113},[325,901,902],{"class":341}," line-gap-override",[325,904,345],{"class":335},[325,906,907],{"class":341},"0",[325,909,867],{"class":331},[325,911,352],{"class":335},[325,913,914],{"class":327,"line":596},[325,915,417],{"class":335},[325,917,918],{"class":327,"line":602},[325,919,593],{"emptyLinePlaceholder":111},[325,921,922,925],{"class":327,"line":609},[325,923,924],{"class":727},"Body",[325,926,336],{"class":335},[325,928,929,931,933,935,937,939,941,944],{"class":327,"line":620},[325,930,342],{"class":341},[325,932,345],{"class":335},[325,934,349],{"class":348},[325,936,574],{"class":335},[325,938,836],{"class":348},[325,940,574],{"class":335},[325,942,943],{"class":341},"sans-serif",[325,945,352],{"class":335},[325,947,948],{"class":327,"line":644},[325,949,417],{"class":335},[20,951,952],{},"When Arial is shown as the fallback (before Inter loads), these overrides make Arial's metrics closely match Inter's. The text occupies nearly the same space, so the swap from fallback to custom font causes minimal layout shift.",[20,954,955,956,959,960,963,964,966],{},"Tools like Fontaine and Next.js's ",[312,957,958],{},"@next/font"," automate fallback metric calculation. For Nuxt projects, the ",[312,961,962],{},"@nuxtjs/fontaine"," module does the same. These tools analyze your custom font's metrics and generate optimized ",[312,965,332],{}," rules for the fallback automatically.",[20,968,969],{},"The system font stack remains the ultimate performance strategy for projects where custom typography is not essential:",[317,971,973],{"className":319,"code":972,"language":321,"meta":90,"style":90},"font-family: system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;\n",[312,974,975],{"__ignoreMap":90},[325,976,977,980,982,985,988,990],{"class":327,"line":328},[325,978,979],{"class":727},"font-family",[325,981,345],{"class":335},[325,983,984],{"class":727},"system-ui",[325,986,987],{"class":335},", -apple-system, 'Segoe UI', Roboto, ",[325,989,943],{"class":727},[325,991,352],{"class":335},[20,993,994],{},"This loads instantly because the fonts are already on the user's device. No network requests, no FOIT, no FOUT, no layout shift. For applications where content and functionality matter more than typographic branding — dashboards, tools, documentation — system fonts are the pragmatic choice.",[996,997,998],"style",{},"html pre.shiki code .snl16, html code.shiki .snl16{--shiki-default:#F97583}html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#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 pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html pre.shiki code .s4JwU, html code.shiki .s4JwU{--shiki-default:#85E89D}html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}",{"title":90,"searchDepth":91,"depth":91,"links":1000},[1001,1002,1003,1004,1005],{"id":287,"depth":94,"text":288},{"id":306,"depth":94,"text":307},{"id":475,"depth":94,"text":476},{"id":682,"depth":94,"text":683},{"id":791,"depth":94,"text":792},"Frontend","Web fonts enhance design but degrade performance when loaded incorrectly. Here are the loading strategies that deliver beautiful typography without sacrificing speed.",[1009,1010],"web fonts performance","font loading strategies",{},"/blog/web-fonts-performance",{"title":281,"description":1007},"blog/web-fonts-performance",[1016,1017,1018],"Fonts","Performance","CSS","GcEPq4OVLSNB8R9zPPxBbwqeEzFPhFfJ9A1TmKQhYsQ",{"id":1021,"title":1022,"author":1023,"body":1024,"category":98,"date":1169,"description":1170,"extension":101,"featured":102,"image":103,"keywords":1171,"meta":1177,"navigation":111,"path":1178,"readTime":113,"seo":1179,"stem":1180,"tags":1181,"__hash__":1187},"blog/blog/cornish-language-resurrection.md","Cornish: Resurrecting a Language from the Dead",{"name":9,"bio":10},{"type":12,"value":1025,"toc":1161},[1026,1030,1046,1049,1052,1056,1059,1062,1065,1075,1079,1086,1089,1092,1096,1099,1102,1105,1108,1112,1115,1118,1125,1128,1135,1137,1141],[15,1027,1029],{"id":1028},"the-language-that-cornwall-forgot","The Language That Cornwall Forgot",[20,1031,1032,1033,1036,1037,495,1041,1045],{},"Cornish -- ",[24,1034,1035],{},"Kernewek"," in the language itself -- is a Brythonic Celtic language, sister to ",[32,1038,1040],{"href":1039},"/blog/welsh-language-survival","Welsh",[32,1042,1044],{"href":1043},"/blog/breton-language-france","Breton",", and a descendant of the common Brythonic spoken across pre-Saxon Britain. For over a thousand years, it was the everyday language of Cornwall, the far southwestern peninsula of England.",[20,1047,1048],{},"The last known monolingual Cornish speaker is traditionally identified as Dolly Pentreath, a fishwife from Mousehole who died in 1777. The reality is less tidy. Pentreath was the last person widely known to speak Cornish as a first language, but scattered speakers and semi-speakers persisted into the early nineteenth century. John Davey of Zennor, who died in 1891, is sometimes cited as the last person with any traditional knowledge of Cornish, though what he spoke was fragmentary.",[20,1050,1051],{},"By any reasonable standard, Cornish died as a community language in the late eighteenth century. The chain of natural transmission from parent to child, unbroken since the Bronze Age, was severed. Cornwall became English-speaking, and Cornish became a historical curiosity.",[15,1053,1055],{"id":1054},"how-cornish-died","How Cornish Died",[20,1057,1058],{},"Cornish retreated westward across Cornwall over the course of five centuries, pushed by the same forces that threatened all the Celtic languages: English political dominance, English-medium education, economic integration with England, and the association of the local language with poverty and backwardness.",[20,1060,1061],{},"The Reformation was particularly damaging. The Prayer Book Rebellion of 1549 saw Cornish-speaking communities rise up against the imposition of English-language Protestant services -- the rebels petitioned that they \"will not receive the new service, because it is but like a Christmas game... We the Cornish men, whereof certain of us understand no English, utterly refuse this new English.\" The rebellion was crushed. The government responded by accelerating the imposition of English in Cornwall's churches and schools.",[20,1063,1064],{},"By 1600, Cornish was confined to the far west of the peninsula -- roughly west of Truro. By 1700, it was retreating to the fishing villages around Penzance and Land's End. By 1800, it was gone.",[20,1066,1067,1068,574,1071,1074],{},"The loss was not total in terms of material. Cornish left behind a significant body of written literature: miracle plays (",[24,1069,1070],{},"Ordinalia",[24,1072,1073],{},"Beunans Meriasek","), saints' lives, a Cornish-English vocabulary compiled by Edward Lhuyd in 1707, and scattered texts and word-lists. These materials would become the foundation of the resurrection.",[15,1076,1078],{"id":1077},"henry-jenner-and-the-first-revival","Henry Jenner and the First Revival",[20,1080,1081,1082,1085],{},"The resurrection of Cornish began in 1904, when Henry Jenner published ",[24,1083,1084],{},"A Handbook of the Cornish Language",". Jenner, a scholar at the British Museum, argued that Cornish could be revived on the basis of the surviving texts and its relationship to Welsh and Breton. He taught himself Cornish from the available sources and began teaching others.",[20,1087,1088],{},"Jenner's work attracted a small but dedicated following. The revival grew slowly through the early twentieth century, with Cornish classes, publications, and cultural events. Robert Morton Nance systematized the revival in the 1920s and 1930s, creating \"Unified Cornish\" -- a standardized form based primarily on medieval texts.",[20,1090,1091],{},"The movement remained small -- a few hundred enthusiasts at most -- but it kept the language alive as a learned pursuit. What it could not do was recreate Cornish as a living language. Without native speakers to provide a model of natural speech, revived Cornish was inevitably a scholarly reconstruction, shaped by the choices and interpretations of its revivers.",[15,1093,1095],{"id":1094},"the-modern-revival-and-the-orthography-wars","The Modern Revival and the Orthography Wars",[20,1097,1098],{},"The Cornish revival accelerated from the 1960s onward, following the broader pattern of Celtic language activism. Richard Gendall developed \"Modern Cornish\" based on the later, pre-death texts of the seventeenth and eighteenth centuries. Ken George proposed \"Kernewek Standard\" based on phonological reconstruction. Nicholas Williams created \"Unified Cornish Revised.\" Each system had its adherents, and the resulting orthography wars -- bitter disputes about which spelling system should be standard -- consumed energy that might have been better spent actually speaking the language.",[20,1100,1101],{},"In 2008, the competing factions reached a compromise with the creation of the Standard Written Form (SWF), intended to provide a common orthography that all groups could accept. The compromise is imperfect -- some groups still prefer their own systems -- but it has reduced the internecine conflict.",[20,1103,1104],{},"The results, despite the divisions, are tangible. Cornish was recognized by the UK government under the European Charter for Regional or Minority Languages in 2002. Cornwall Council provides some bilingual signage. Several hundred people now speak Cornish with varying degrees of fluency. There are Cornish-medium playgroups, adult education classes, and a small but active online community.",[20,1106,1107],{},"The 2011 Census recorded 557 people claiming Cornish as their main language -- a tiny number, but a number that would have been zero a century earlier.",[15,1109,1111],{"id":1110},"can-a-dead-language-truly-live-again","Can a Dead Language Truly Live Again?",[20,1113,1114],{},"The Cornish case raises a fundamental question: can a language that lost all its native speakers truly be revived, or is the result always a different language -- a reconstruction that resembles the original but lacks its living substance?",[20,1116,1117],{},"The honest answer is: both. Revived Cornish is not the same language that Dolly Pentreath spoke. It cannot be. The nuances of pronunciation, the idiomatic expressions, the rhythms of natural speech -- these were lost with the last speakers and cannot be fully recovered from written texts. What exists today is a language built from historical materials by committed people who chose to speak it.",[20,1119,1120,1121,1124],{},"But the same is true, in a less dramatic way, of every language. Modern English is not the English of Chaucer. Modern Irish is not the Irish of the ",[24,1122,1123],{},"Tain",". Languages change. The question is not whether revived Cornish is identical to historical Cornish but whether it is a living language -- spoken by real people, in real communities, for real purposes.",[20,1126,1127],{},"By that standard, Cornish is alive. Barely. Precariously. But alive. And every child who learns it, every conversation held in it, every song sung in it pushes the language a little further from the death it was supposed to have accepted two centuries ago.",[20,1129,1130,1131,1134],{},"The Cornish word for resurrection is ",[24,1132,1133],{},"dasserghyans",". The language is testing whether the word applies to itself.",[302,1136],{},[15,1138,1140],{"id":1139},"related-articles","Related Articles",[1142,1143,1144,1151,1156],"ul",{},[1145,1146,1147],"li",{},[32,1148,1150],{"href":1149},"/blog/manx-language-revival","Manx: Reviving a Language That Died in 1974",[1145,1152,1153],{},[32,1154,1155],{"href":1039},"Welsh: The Celtic Language That Refused to Die",[1145,1157,1158],{},[32,1159,1160],{"href":1043},"Breton: The Celtic Language of France",{"title":90,"searchDepth":91,"depth":91,"links":1162},[1163,1164,1165,1166,1167,1168],{"id":1028,"depth":94,"text":1029},{"id":1054,"depth":94,"text":1055},{"id":1077,"depth":94,"text":1078},{"id":1094,"depth":94,"text":1095},{"id":1110,"depth":94,"text":1111},{"id":1139,"depth":94,"text":1140},"2025-06-07","Cornish died as a community language in the late eighteenth century. Two hundred years later, people are speaking it again. The resurrection of Cornish is a test case for whether a language with no living speakers can truly be brought back.",[1172,1173,1174,1175,1176],"cornish language revival","kernewek","cornish language history","dead language resurrection","celtic language cornwall",{},"/blog/cornish-language-resurrection",{"title":1022,"description":1170},"blog/cornish-language-resurrection",[1182,1183,1184,1185,1186],"Cornish Language","Language Revival","Celtic Languages","Cornwall History","Endangered Languages","Rm6JyEPqqB7BHNgZKVkJ2r3v01xh1rqc88Yt7hI9-pQ",{"id":1189,"title":1190,"author":1191,"body":1192,"category":265,"date":1169,"description":1377,"extension":101,"featured":102,"image":103,"keywords":1378,"meta":1381,"navigation":111,"path":1382,"readTime":113,"seo":1383,"stem":1384,"tags":1385,"__hash__":1388},"blog/blog/custom-business-application-development.md","When Your Business Needs Custom Software",{"name":9,"bio":10},{"type":12,"value":1193,"toc":1369},[1194,1198,1201,1204,1207,1209,1213,1216,1222,1228,1244,1250,1252,1256,1259,1265,1271,1277,1279,1283,1286,1292,1298,1309,1315,1317,1321,1324,1330,1336,1342,1345,1347,1351],[15,1195,1197],{"id":1196},"the-decision-point","The Decision Point",[20,1199,1200],{},"Every growing business reaches a moment where their tools stop fitting. The spreadsheet that tracked inventory for 50 products breaks at 5,000. The CRM that worked for a sales team of three becomes unwieldy at fifteen. The off-the-shelf ERP that seemed comprehensive during the demo can't accommodate the specific workflow that makes your business different from your competitors.",[20,1202,1203],{},"At this point, someone suggests custom software. And the reaction is usually one of two extremes: either \"that's too expensive\" or \"let's rebuild everything from scratch.\" Both reactions miss the point.",[20,1205,1206],{},"Custom software is an investment that makes sense when the gap between what your business needs and what available tools provide is costing you more than the software would cost to build. That gap shows up as manual workarounds, data re-entry between systems, processes that can't scale, or competitive advantages you can't execute on because your tools won't support them.",[302,1208],{},[15,1210,1212],{"id":1211},"signs-youve-outgrown-off-the-shelf","Signs You've Outgrown Off-the-Shelf",[20,1214,1215],{},"The indicators are usually visible long before anyone names them. Recognizing them early saves months of accumulated friction.",[20,1217,1218,1221],{},[149,1219,1220],{},"Your team has built elaborate workarounds."," When employees maintain shadow spreadsheets alongside the official system, copy data between tools manually, or have developed undocumented processes to compensate for software limitations, you're paying for software that doesn't work and paying again in labor to work around it.",[20,1223,1224,1227],{},[149,1225,1226],{},"You're paying for features you don't use and missing features you need."," Enterprise software is designed for the broadest possible market. The 80% of features you don't need add complexity to your team's daily experience. The 20% of features that are missing are the ones specific to your industry or your business model — the ones that would actually differentiate your operations.",[20,1229,1230,1233,1234,1238,1239,1243],{},[149,1231,1232],{},"Integration between your tools is fragile or manual."," If getting data from your ",[32,1235,1237],{"href":1236},"/blog/custom-crm-development","CRM"," into your ",[32,1240,1242],{"href":1241},"/blog/custom-erp-development-guide","ERP"," requires a CSV export, manual transformation, and careful import, you don't have an integrated system. You have disconnected tools with humans acting as the integration layer. This doesn't scale and it introduces errors at every handoff.",[20,1245,1246,1249],{},[149,1247,1248],{},"Your business processes have evolved beyond what the software supports."," Software encodes assumptions about how work flows. When those assumptions no longer match your reality, you're forced to adapt your processes to the software rather than the other way around. This is exactly backwards — your business processes are your competitive advantage, and your software should support them.",[302,1251],{},[15,1253,1255],{"id":1254},"what-custom-software-actually-costs","What Custom Software Actually Costs",[20,1257,1258],{},"The honest conversation about custom software cost starts with acknowledging that it's not just the development cost. It's the development cost, the maintenance cost, the opportunity cost of building versus buying, and the cost of change management.",[20,1260,1261,1264],{},[149,1262,1263],{},"Development cost"," varies enormously based on scope. A custom dashboard that aggregates data from existing tools might take 4-8 weeks. A full custom ERP replacement might take 6-12 months. The key is to scope ruthlessly. You don't need to replace every off-the-shelf tool at once. Start with the area where the gap between what you have and what you need is costing you the most.",[20,1266,1267,1270],{},[149,1268,1269],{},"Maintenance cost"," is ongoing. Custom software needs updates, bug fixes, and feature additions. Plan for 15-25% of the initial development cost annually for maintenance. This is less than it sounds — off-the-shelf software has ongoing license costs too, often increasing annually, plus the hidden cost of the workarounds your team maintains.",[20,1272,1273,1276],{},[149,1274,1275],{},"The comparison that matters"," isn't custom software versus free. It's custom software versus the total cost of your current solution — licenses, labor for workarounds, lost productivity, errors from manual processes, and opportunities you can't pursue because your tools won't support them. When you calculate the full cost of the status quo, custom development often looks more reasonable than the sticker shock suggests.",[302,1278],{},[15,1280,1282],{"id":1281},"how-to-approach-custom-development","How to Approach Custom Development",[20,1284,1285],{},"If the analysis supports custom development, how you approach it determines whether you get a tool that transforms your operations or an expensive disappointment.",[20,1287,1288,1291],{},[149,1289,1290],{},"Start with the process, not the technology."," Before any code is written, document the business processes the software will support. Not the idealized version — the actual version, including the workarounds and exceptions. This documentation becomes the requirements that guide development and the benchmark against which the finished product is evaluated.",[20,1293,1294,1297],{},[149,1295,1296],{},"Build incrementally."," The biggest risk in custom development is spending months building a system, launching it, and discovering it doesn't fit. Agile development mitigates this by delivering working software in short cycles (2-4 weeks), getting feedback from actual users after each cycle, and adjusting the direction based on what you learn. The first version should be the minimum viable tool that replaces one specific pain point, not a complete system that replaces everything.",[20,1299,1300,1303,1304,1308],{},[149,1301,1302],{},"Integrate, don't replace."," Custom software works best when it fills the gaps between your existing tools rather than replacing them entirely. A custom ",[32,1305,1307],{"href":1306},"/blog/custom-inventory-management-system","inventory management system"," that integrates with your existing accounting software gives you the operational capability you need without rebuilding the accounting functionality that works fine.",[20,1310,1311,1314],{},[149,1312,1313],{},"Plan for the team."," Custom software needs someone who understands it — either an internal developer, a retained development partner, or thorough documentation that allows future developers to maintain it. Software without institutional knowledge becomes technical debt.",[302,1316],{},[15,1318,1320],{"id":1319},"the-build-vs-buy-framework","The Build vs. Buy Framework",[20,1322,1323],{},"Not every software need justifies custom development. A clear framework helps make the decision.",[20,1325,1326,1329],{},[149,1327,1328],{},"Buy"," when the need is generic and well-served by existing products. Email, project management, accounting, basic CRM — these are solved problems with excellent off-the-shelf options. Unless your business has genuinely unique requirements in these areas, buying is the right choice.",[20,1331,1332,1335],{},[149,1333,1334],{},"Build"," when the need is specific to your business, when the competitive advantage depends on the capability, or when the integration requirements are complex enough that connecting off-the-shelf tools would be more expensive than building a unified system.",[20,1337,1338,1341],{},[149,1339,1340],{},"Extend"," when an existing tool does 80% of what you need and has an API or extension mechanism that lets you add the remaining 20%. Custom modules on top of existing platforms combine the reliability of established software with the flexibility of custom development.",[20,1343,1344],{},"The decision isn't permanent. Start with off-the-shelf tools, identify where they fall short as your business grows, and invest in custom development targeted at the specific areas where the gap is costing you the most. This approach minimizes risk while ensuring you're not paying for capability you don't need yet.",[302,1346],{},[15,1348,1350],{"id":1349},"keep-reading","Keep Reading",[1142,1352,1353,1358,1363],{},[1145,1354,1355],{},[32,1356,1357],{"href":1241},"Custom ERP Development: Building Software That Runs Your Business",[1145,1359,1360],{},[32,1361,1362],{"href":1236},"Custom CRM Development: Building a System That Fits Your Sales Process",[1145,1364,1365],{},[32,1366,1368],{"href":1367},"/blog/enterprise-software-development-best-practices","Enterprise Software Development Best Practices",{"title":90,"searchDepth":91,"depth":91,"links":1370},[1371,1372,1373,1374,1375,1376],{"id":1196,"depth":94,"text":1197},{"id":1211,"depth":94,"text":1212},{"id":1254,"depth":94,"text":1255},{"id":1281,"depth":94,"text":1282},{"id":1319,"depth":94,"text":1320},{"id":1349,"depth":94,"text":1350},"Off-the-shelf software works until it doesn't. Here's how to know when custom development is the right investment, and how to approach it without wasting time or money.",[1379,1380],"custom business application development","custom software vs off-the-shelf",{},"/blog/custom-business-application-development",{"title":1190,"description":1377},"blog/custom-business-application-development",[1386,265,1387],"Custom Software","Enterprise","eUYygxbB7pvQMn9Wh1GkDh7mCN5ZkHBQGTA0VLa7Jyg",{"id":1390,"title":1391,"author":1392,"body":1393,"category":1538,"date":1169,"description":1539,"extension":101,"featured":102,"image":103,"keywords":1540,"meta":1543,"navigation":111,"path":1544,"readTime":596,"seo":1545,"stem":1546,"tags":1547,"__hash__":1551},"blog/blog/error-handling-patterns.md","Error Handling Patterns for Production Applications",{"name":9,"bio":10},{"type":12,"value":1394,"toc":1531},[1395,1399,1402,1405,1408,1410,1414,1417,1423,1429,1435,1438,1440,1444,1447,1457,1463,1466,1473,1475,1479,1482,1489,1508,1516,1518,1522,1525,1528],[15,1396,1398],{"id":1397},"why-error-handling-is-an-architecture-problem","Why Error Handling Is an Architecture Problem",[20,1400,1401],{},"Error handling is one of those concerns that every developer acknowledges as important and few approach systematically. The default pattern is reactive: something breaks in production, the team adds a try/catch, maybe some logging, and moves on. Over time, this produces a codebase with inconsistent error handling where some errors are caught and silently swallowed, others crash the process, and most land somewhere in between — logged with insufficient context and surfaced to users with generic messages that help no one.",[20,1403,1404],{},"The problem is that error handling is not a local concern that can be addressed function by function. It's an architectural concern that spans the entire application. How errors are categorized, how they propagate between layers, what information gets logged, what the user sees, and how the system recovers — these are system-level decisions that require system-level design.",[20,1406,1407],{},"Production applications need an error handling strategy: a set of conventions that every developer on the team follows, producing consistent behavior that operators can predict and users can understand.",[302,1409],{},[15,1411,1413],{"id":1412},"categorizing-errors-by-response","Categorizing Errors by Response",[20,1415,1416],{},"Not all errors require the same response, and the biggest mistake in error handling is treating them as if they do. A useful categorization separates errors into three groups based on what should happen when they occur.",[20,1418,1419,1422],{},[149,1420,1421],{},"Operational errors"," are expected failures that occur during normal operation. A database connection timeout, a failed HTTP request to a third-party service, user input that fails validation, a file that doesn't exist — these are not bugs. They're conditions the application should anticipate and handle gracefully. The response is typically to retry, fall back to a default, return a meaningful error message to the user, or some combination.",[20,1424,1425,1428],{},[149,1426,1427],{},"Programmer errors"," are bugs. A null reference, an index out of bounds, a type assertion that fails — these indicate a mistake in the code that needs to be fixed. The response is typically to fail fast, log comprehensive diagnostic information, and alert the development team. Attempting to recover from programmer errors is usually counterproductive because the application is in an unexpected state.",[20,1430,1431,1434],{},[149,1432,1433],{},"Infrastructure errors"," are environmental failures — disk full, out of memory, network partition. These require operational response rather than code-level handling. The application should detect them, report them clearly, and either degrade gracefully or shut down cleanly. Attempting to handle out-of-memory errors in application code is generally futile.",[20,1436,1437],{},"This categorization matters because each category requires different handling. Wrapping everything in a generic try/catch that logs an error and returns a 500 response treats a validation failure the same as a null pointer exception, which helps neither the user nor the developer.",[302,1439],{},[15,1441,1443],{"id":1442},"error-propagation-strategies","Error Propagation Strategies",[20,1445,1446],{},"How errors travel from the point of occurrence to the point of handling determines the quality of your error handling. Two anti-patterns dominate.",[20,1448,1449,1452,1453,1456],{},[149,1450,1451],{},"Swallowing errors"," — catching an exception and doing nothing with it — is the worst anti-pattern. The operation failed, but nothing in the system knows about it. The calling code assumes success and continues with invalid state. The user sees confusing behavior with no error message. The logs show nothing. I've debugged production systems where critical failures were invisible for weeks because someone wrote ",[312,1454,1455],{},"catch (e) {}"," during development and never revisited it.",[20,1458,1459,1462],{},[149,1460,1461],{},"Over-catching"," — wrapping every function call in try/catch — creates noise and obscures the actual error flow. When errors are caught and re-thrown at every layer with different messages, the original error gets buried under a stack of wrapper messages, and the log entry that would actually help diagnose the problem is hidden beneath generic \"something went wrong\" messages.",[20,1464,1465],{},"The effective pattern is to let errors propagate naturally to the boundary where they can be handled appropriately. In a web application, that typically means validation errors are handled in the controller layer (returning 400 responses with specific messages), business logic errors are handled in the service layer (returning domain-specific errors), and unexpected errors are caught by a global error handler that logs the full context and returns a safe response to the user.",[20,1467,1468,1469,446],{},"Define custom error types for your domain. Instead of throwing generic errors with string messages, create error classes that carry structured information: error code, user-facing message, internal diagnostic details, and HTTP status code. This makes error handling in consuming code predictable and type-safe — which matters especially when you're working with ",[32,1470,1472],{"href":1471},"/blog/typescript-strict-mode-patterns","TypeScript in strict mode",[302,1474],{},[15,1476,1478],{"id":1477},"logging-errors-for-debuggability","Logging Errors for Debuggability",[20,1480,1481],{},"The purpose of error logging is to give the person investigating a production issue enough information to understand what happened without needing to reproduce it. This requires more context than most developers provide.",[20,1483,1484,1485,1488],{},"Log the error message and stack trace, obviously. But also log the input that triggered the error, the state of relevant variables, the user or request that was being processed, and the operation that was being attempted. The difference between \"TypeError: Cannot read property 'id' of undefined\" and \"TypeError while processing order creation for user 12345: Cannot read property 'id' of undefined (payload: {items: ",[325,1486,1487],{},"...",", shipping: null})\" is the difference between a mystery and a diagnosis.",[20,1490,1491,1492,574,1495,574,1498,574,1501,812,1504,1507],{},"Use structured logging (JSON) rather than free-text log messages. Structured logs can be searched, filtered, and aggregated by machines. A structured log entry with fields for ",[312,1493,1494],{},"level",[312,1496,1497],{},"error_code",[312,1499,1500],{},"user_id",[312,1502,1503],{},"request_id",[312,1505,1506],{},"stack_trace"," is infinitely more useful for investigation than a string that concatenates those values with spaces.",[20,1509,1510,1511,1515],{},"Correlate logs across the request lifecycle using a request ID. When a single user request touches multiple services or passes through multiple middleware layers, a shared request ID lets you trace the complete journey and see exactly where the error originated. This is essential for ",[32,1512,1514],{"href":1513},"/blog/integration-testing-guide","debugging distributed systems"," and becomes non-negotiable as your architecture grows beyond a single process.",[302,1517],{},[15,1519,1521],{"id":1520},"recovery-and-user-communication","Recovery and User Communication",[20,1523,1524],{},"When an error occurs, the user needs to know three things: that something went wrong, whether their action succeeded or failed, and what they should do next. Most error messages fail on all three counts, showing either a stack trace (too much information) or \"An error occurred\" (too little).",[20,1526,1527],{},"Design error messages for the user's context. A payment processing error should tell the user whether they were charged. A form submission error should preserve the form data so the user doesn't have to re-enter it. A file upload error should explain whether they should retry or contact support.",[20,1529,1530],{},"Implement graceful degradation where possible. If a non-critical feature fails — a recommendation engine, an analytics tracker, a social login provider — the core application should continue functioning. This requires designing your error handling to distinguish between critical and non-critical failures and respond proportionally. A production application that crashes because the analytics service is down is not resilient; it's fragile in ways that compound under real-world conditions.",{"title":90,"searchDepth":91,"depth":91,"links":1532},[1533,1534,1535,1536,1537],{"id":1397,"depth":94,"text":1398},{"id":1412,"depth":94,"text":1413},{"id":1442,"depth":94,"text":1443},{"id":1477,"depth":94,"text":1478},{"id":1520,"depth":94,"text":1521},"Engineering","Practical error handling patterns that keep production applications reliable. Strategies for categorizing, propagating, logging, and recovering from errors gracefully.",[1541,1542],"error handling patterns","production error handling",{},"/blog/error-handling-patterns",{"title":1391,"description":1539},"blog/error-handling-patterns",[1548,1549,1550],"Error Handling","Production Systems","Software Reliability","QIW93fDPmapItKKZOc9JM1YC-0Nu2TvROJLxwSwMa1k",{"id":1553,"title":1554,"author":1555,"body":1556,"category":98,"date":1665,"description":1666,"extension":101,"featured":102,"image":103,"keywords":1667,"meta":1671,"navigation":111,"path":1672,"readTime":414,"seo":1673,"stem":1674,"tags":1675,"__hash__":1680},"blog/blog/dna-ancestry-testing-guide.md","DNA Ancestry Testing: What the Results Actually Mean",{"name":9,"bio":10},{"type":12,"value":1557,"toc":1659},[1558,1562,1565,1568,1586,1590,1593,1596,1604,1608,1611,1632,1638,1642,1645,1653,1656],[15,1559,1561],{"id":1560},"the-promise-and-the-fine-print","The Promise and the Fine Print",[20,1563,1564],{},"DNA ancestry testing has become a mainstream consumer product. Companies like AncestryDNA, 23andMe, and FamilyTreeDNA offer to reveal your ethnic origins, connect you with relatives, and trace your deep ancestral lineages — all from a tube of saliva. Tens of millions of people have tested, and the databases grow daily.",[20,1566,1567],{},"The results are genuinely useful. But they are also widely misunderstood. The colorful pie charts and ethnicity maps suggest a precision that the underlying science does not support. Understanding what DNA ancestry tests actually measure — and what they cannot measure — is essential for anyone serious about using genetic data to explore their heritage.",[20,1569,1570,1571,1575,1576,1580,1581,1585],{},"There are three types of DNA tests available to consumers, and each answers a different question. ",[32,1572,1574],{"href":1573},"/blog/autosomal-dna-ethnicity-estimates","Autosomal DNA"," tests measure your recent mixed ancestry (roughly 5-7 generations). ",[32,1577,1579],{"href":1578},"/blog/y-dna-haplogroups-explained","Y-DNA tests"," trace the direct paternal line — father to father, indefinitely. ",[32,1582,1584],{"href":1583},"/blog/mitochondrial-dna-maternal-ancestry","Mitochondrial DNA tests"," trace the direct maternal line — mother to mother, indefinitely. Each has strengths and limitations, and no single test gives you the complete picture.",[15,1587,1589],{"id":1588},"what-ethnicity-estimates-actually-are","What Ethnicity Estimates Actually Are",[20,1591,1592],{},"The ethnicity estimate — the pie chart showing you are, say, 45% Irish, 30% English, 15% Scandinavian, and 10% Germanic — is the most popular feature and the most misunderstood. These estimates are not based on ancient DNA from those populations. They are based on comparisons with modern reference populations — groups of living people who self-identify with specific regions and whose DNA has been characterized.",[20,1594,1595],{},"This means several things. First, the estimates are probabilistic. When a test says you are 45% Irish, it means that 45% of your DNA most closely resembles the DNA of the modern reference panel labeled \"Irish.\" It does not mean that exactly 45% of your ancestors were Irish. Second, the estimates change as reference panels are updated. People who tested years ago have watched their ethnicity estimates shift, sometimes dramatically, with each database revision.",[20,1597,1598,1599,1603],{},"Third, and most importantly, ethnicity estimates cannot distinguish between populations that are genetically similar. The genetic difference between someone from northern England and someone from the Scottish Lowlands is minimal. The difference between someone from western Norway and someone from Orkney — where ",[32,1600,1602],{"href":1601},"/blog/viking-age-scotland","Viking settlement"," mixed Norse and Celtic populations for centuries — is likewise small. The neat categories on the pie chart impose boundaries on a continuous genetic landscape.",[15,1605,1607],{"id":1606},"y-dna-and-mtdna-the-deep-lines","Y-DNA and mtDNA: The Deep Lines",[20,1609,1610],{},"For those interested in deep ancestry — the kind of story that stretches back thousands of years rather than hundreds — Y-DNA and mitochondrial DNA testing are far more powerful tools.",[20,1612,1613,1616,1617,1621,1622,1626,1627,1631],{},[32,1614,1615],{"href":1578},"Y-DNA"," is passed from father to son with minimal change, making it possible to trace the direct paternal line across dozens of generations. The ",[32,1618,1620],{"href":1619},"/blog/r1b-l21-atlantic-celtic-haplogroup","R1b-L21 haplogroup",", for example, connects modern men of Atlantic Celtic ancestry to the ",[32,1623,1625],{"href":1624},"/blog/bell-beaker-conquest-ireland-britain","Bronze Age Bell Beaker migrations",", the ",[32,1628,1630],{"href":1629},"/blog/yamnaya-horizon-steppe-ancestors","Yamnaya steppe pastoralists",", and ultimately to a common paternal ancestor who lived thousands of years ago.",[20,1633,1634,1637],{},[32,1635,1636],{"href":1583},"Mitochondrial DNA"," performs the same function for the maternal line. Because mtDNA is passed from mother to all children (but only daughters pass it on), it traces a single unbroken female line back through time. The maternal haplogroups tell a different story from the paternal ones — sometimes dramatically so, revealing migration patterns and population mixing that Y-DNA alone cannot capture.",[15,1639,1641],{"id":1640},"making-sense-of-results","Making Sense of Results",[20,1643,1644],{},"The best approach to DNA ancestry testing is to use all three types together and to interpret the results in the context of documentary genealogy, historical knowledge, and an honest acknowledgment of what DNA can and cannot tell you.",[20,1646,1647,1648,1652],{},"DNA can confirm or refute specific genealogical connections. It can identify biological relatives. It can place your paternal and maternal lineages within the framework of human migration history. It can ",[32,1649,1651],{"href":1650},"/blog/genetic-genealogy-brick-walls","break through brick walls"," in your family research that documentary records cannot penetrate.",[20,1654,1655],{},"What DNA cannot do is tell you who you are in any culturally meaningful sense. Being 45% genetically Irish does not make you Irish if you were raised in Texas with no connection to Irish culture. Having an R1b-L21 Y-chromosome does not make you a Celt in any sense that a Bronze Age person would recognize. DNA is evidence, not identity. It is a tool for understanding where your ancestors came from, not a script for who you should be.",[20,1657,1658],{},"The science is powerful, and it is getting better every year. But it is most valuable when combined with the historical and cultural knowledge that gives raw genetic data meaning.",{"title":90,"searchDepth":91,"depth":91,"links":1660},[1661,1662,1663,1664],{"id":1560,"depth":94,"text":1561},{"id":1588,"depth":94,"text":1589},{"id":1606,"depth":94,"text":1607},{"id":1640,"depth":94,"text":1641},"2025-06-01","DNA ancestry tests promise to reveal your origins. But the science behind the percentages is more complex and more limited than the marketing suggests.",[1668,1669,1670],"dna ancestry testing guide","dna ancestry test accuracy","what dna ancestry tests mean",{},"/blog/dna-ancestry-testing-guide",{"title":1554,"description":1666},"blog/dna-ancestry-testing-guide",[1676,1677,1678,1679],"DNA Testing","Genetic Genealogy","Ancestry","Genetics","tw3MchbZdIL_v2RrAwe8oT1UNU-5yV5jnL-KeNZADJM",{"id":1682,"title":1683,"author":1684,"body":1685,"category":98,"date":1665,"description":1770,"extension":101,"featured":102,"image":103,"keywords":1771,"meta":1778,"navigation":111,"path":1779,"readTime":602,"seo":1780,"stem":1781,"tags":1782,"__hash__":1787},"blog/blog/human-migration-out-of-africa.md","Out of Africa: The Original Human Migration",{"name":9,"bio":10},{"type":12,"value":1686,"toc":1764},[1687,1691,1694,1697,1705,1709,1720,1723,1730,1734,1737,1740,1743,1747,1754,1757],[15,1688,1690],{"id":1689},"the-deepest-root","The Deepest Root",[20,1692,1693],{},"Before there were Celts, before there were Indo-Europeans, before there were farmers or herders or city-builders, there was a single population living in eastern Africa. Every non-African person on Earth today descends from a subset of that population -- a group that, sometime between 70,000 and 50,000 years ago, walked out of the continent and never came back.",[20,1695,1696],{},"This is not metaphor. It is measurable. The genetic diversity of the entire non-African world is a subset of the genetic diversity found within Africa. The Hadza of Tanzania carry more genetic variation between neighboring villages than exists between a Norwegian and a Japanese person. That single fact tells you everything about how recently the rest of the world was populated and how small the founding group was.",[20,1698,1699,1700,1704],{},"The out-of-Africa migration is the origin event. Every subsequent chapter in ",[32,1701,1703],{"href":1702},"/blog/what-is-genetic-genealogy","human genetic history"," -- the peopling of Europe, the rise of farming, the steppe expansions, the Celtic world -- is a downstream consequence of that first departure.",[15,1706,1708],{"id":1707},"who-left-and-why","Who Left and Why",[20,1710,1711,1712,1715,1716,1719],{},"The migrants were anatomically modern humans, ",[24,1713,1714],{},"Homo sapiens",", who had been living in Africa for at least 200,000 years before the exit event. They were not the first hominins to leave the continent. ",[24,1717,1718],{},"Homo erectus"," had colonized parts of Asia more than a million years earlier, and Neanderthals had been living in Europe and western Asia for hundreds of thousands of years. But prior waves of modern human expansion into the Levant, documented around 120,000 years ago, appear to have died out or been absorbed.",[20,1721,1722],{},"The successful migration was different. Genetic evidence suggests a bottleneck -- a severe reduction in population size -- around 70,000 years ago that left its fingerprint on the genomes of all non-Africans. Some researchers have linked this to the eruption of the Toba supervolcano in Sumatra, which would have plunged global temperatures and devastated ecosystems. Others argue the bottleneck was simply the demographic constraint of a small migrating group pushing through unfamiliar territory.",[20,1724,1725,1726,1729],{},"What mattered was not the cause but the consequence. A few thousand individuals, perhaps fewer, crossed through the southern Sinai or the Bab el-Mandeb strait at the mouth of the Red Sea. They carried with them a narrow slice of Africa's deep genetic diversity. Every ",[32,1727,1728],{"href":1578},"Y-DNA haplogroup"," found outside Africa today descends from haplogroup CT, a single mutation that marks the exit lineage. Every mitochondrial lineage outside Africa descends from haplogroup L3. The bottleneck was real, and it was tight.",[15,1731,1733],{"id":1732},"the-coastal-highway","The Coastal Highway",[20,1735,1736],{},"The first migrants did not march inland and conquer continents. They hugged the coast. The \"southern route\" hypothesis, supported by archaeological sites and genetic data, proposes that the earliest wave followed the Indian Ocean coastline from the Horn of Africa through the Arabian Peninsula, along the shores of South Asia, through Southeast Asia, and ultimately to Australia -- which was reached at least 65,000 years ago.",[20,1738,1739],{},"These were maritime-adapted people. They ate shellfish, fished in shallow waters, and moved along shorelines where resources were predictable. The speed of the expansion was remarkable. Within 20,000 years of leaving Africa, humans had reached the far side of the planet. Australia's Aboriginal populations carry some of the oldest continuous genetic lineages outside Africa, a direct link to that first coastal migration.",[20,1741,1742],{},"The northern route into Europe came later. The ancestors of modern Europeans split from the groups heading east and moved into the Levant and then into the European continent, where they encountered Neanderthals. The interbreeding that followed left every person of European descent carrying between 1 and 4 percent Neanderthal DNA -- a ghost signature of contact between two species that had been separated for half a million years.",[15,1744,1746],{"id":1745},"what-the-migration-means-for-genealogy","What the Migration Means for Genealogy",[20,1748,1749,1750,1753],{},"If you have tested your DNA through any major ",[32,1751,1752],{"href":1672},"ancestry testing service",", the deepest branches of your results trace back to this event. Your Y-chromosome haplogroup, if you are male, descends through a chain of mutations that ultimately leads back to a man who lived in Africa -- Y-chromosomal Adam, the most recent common patrilineal ancestor of all living men. Your mitochondrial haplogroup traces back to Mitochondrial Eve, the most recent common matrilineal ancestor of all living humans.",[20,1755,1756],{},"These are not the first humans. They are the most recent common ancestors, meaning that all other lineages from their time have either died out or converged. The out-of-Africa migration pruned the human family tree so severely that the non-African branch is, genetically speaking, a single twig compared to the full canopy of African diversity.",[20,1758,1759,1760,1763],{},"Understanding this context matters when you trace your heritage through later events -- the ",[32,1761,1762],{"href":1629},"Yamnaya expansion",", the Celtic migrations, the formation of clans and kingdoms. Each of those chapters is a refinement of the original story: a small group of people moved, mixed with or replaced the people already there, and left a genetic signature that we can still read today. The pattern was established 70,000 years ago on the shores of the Red Sea, and it has repeated itself, at different scales, ever since.",{"title":90,"searchDepth":91,"depth":91,"links":1765},[1766,1767,1768,1769],{"id":1689,"depth":94,"text":1690},{"id":1707,"depth":94,"text":1708},{"id":1732,"depth":94,"text":1733},{"id":1745,"depth":94,"text":1746},"Every person alive today descends from a small population that left Africa roughly 70,000 years ago. The out-of-Africa migration is the founding event of global human diversity, and its genetic signature is still written in our DNA.",[1772,1773,1774,1775,1776,1777],"out of africa migration","human migration history","early human migration routes","mitochondrial eve","human origins africa","genetic diversity migration",{},"/blog/human-migration-out-of-africa",{"title":1683,"description":1770},"blog/human-migration-out-of-africa",[1783,1784,1677,1785,1786],"Human Migration","Out of Africa","Prehistory","Population Genetics","SeEQLd2uHrY_qBaZLKR5dVM0pCw56MS5XwRGzD8zSek",{"id":1789,"title":1790,"author":1791,"body":1792,"category":98,"date":1665,"description":1863,"extension":101,"featured":102,"image":103,"keywords":1864,"meta":1870,"navigation":111,"path":1871,"readTime":113,"seo":1872,"stem":1873,"tags":1874,"__hash__":1880},"blog/blog/scottish-proverbs-wisdom.md","Scottish Proverbs: Wisdom from the Highlands",{"name":9,"bio":10},{"type":12,"value":1793,"toc":1857},[1794,1798,1801,1804,1807,1811,1814,1817,1820,1824,1827,1830,1833,1837,1845,1848,1854],[15,1795,1797],{"id":1796},"wisdom-compressed","Wisdom Compressed",[20,1799,1800],{},"Proverbs are philosophy for people who do not have time for philosophy. They compress observation, experience, and moral judgment into phrases short enough to remember and vivid enough to stick. In Scotland, where the oral tradition was strong and literacy came late to many communities, proverbs served as a portable curriculum of practical wisdom, passed from generation to generation in the ordinary course of conversation.",[20,1802,1803],{},"Scottish proverbs come in three languages: Gaelic, Scots, and English, reflecting the country's complex linguistic history. The Gaelic proverbs tend to be the oldest and often the most poetic, drawn from a pastoral and maritime world where observation of nature was essential for survival. The Scots proverbs are earthier, frequently comic, and marked by the directness that characterizes Scots speech. The English-language proverbs often represent translations or adaptations of older Gaelic or Scots originals, smoothed out for a wider audience but retaining their essential wisdom.",[20,1805,1806],{},"The great collections were assembled in the eighteenth and nineteenth centuries. James Kelly's \"A Complete Collection of Scottish Proverbs\" appeared in 1721. Alexander Hislop's \"The Proverbs of Scotland\" followed in 1862. These compilations preserved thousands of sayings that might otherwise have been lost as the oral culture that generated them gave way to literacy and urbanization.",[15,1808,1810],{"id":1809},"character-and-conduct","Character and Conduct",[20,1812,1813],{},"The largest category of Scottish proverbs concerns human character and how to judge it. The Scots had a sharp eye for pretension, dishonesty, and self-importance, and their proverbs cut through these failings with surgical precision.",[20,1815,1816],{},"\"Mony a mickle maks a muckle,\" many small amounts make a large amount, is perhaps the most widely known Scottish proverb, and it encapsulates the Scottish attitude toward thrift and industry. Small efforts, consistently applied, produce significant results. The proverb works equally well as financial advice and as a philosophy of labor: do the small things well, and the large things will take care of themselves.",[20,1818,1819],{},"\"What's for ye'll no go by ye\" expresses a fatalism that actually reflects practical courage. The proverb counsels patience and trust: do what you can, and accept what comes. \"Be happy while you're living, for you're a long time dead\" is Scottish pragmatism at its most characteristically blunt, a reminder that worry is a poor use of limited time. \"Better a wee fire that warms than a big fire that burns\" captures the theme of moderation: sufficiency is preferable to excess.",[15,1821,1823],{"id":1822},"nature-and-weather","Nature and Weather",[20,1825,1826],{},"Scotland's climate, challenging and changeable, generated a rich vocabulary of weather proverbs that served as practical forecasting tools. \"When the mist comes frae the hill, sunny weather it does spill. When the mist comes frae the sea, good weather it will be\" combines observation with prediction in a way that actually works: mist rising from hills often indicates clearing weather, while sea mist in Scotland frequently precedes fair conditions as warm air moves in.",[20,1828,1829],{},"\"Mony haws, mony snaws\" predicts that a heavy crop of hawthorn berries in autumn means a harsh winter. This observation has some ecological basis: trees under stress sometimes produce more fruit, and the same weather patterns that stress trees can precede severe winters. Whether the correlation is reliable enough for practical forecasting is debatable, but the proverb captures a genuine attempt to read the natural world for information about the future.",[20,1831,1832],{},"\"Cast ne'er a clout till May be out\" advises against removing winter clothing until the end of May, reflecting the reality that Scottish springs are cold and unreliable. The saying may refer to the month of May or to the May tree (hawthorn), whose flowering signals the genuine arrival of warm weather. Either interpretation counsels the same patience: do not trust the first warm day.",[15,1834,1836],{"id":1835},"community-and-kinship","Community and Kinship",[20,1838,1839,1840,1844],{},"Proverbs about community and kinship reflect the values of a society organized around the ",[32,1841,1843],{"href":1842},"/blog/scottish-clans-modern-gatherings","clan system"," and the obligations of mutual support. \"Friends are lost by calling often and calling seldom,\" a nicely balanced paradox, warns that friendship requires calibration: too much contact is as destructive as too little.",[20,1846,1847],{},"\"Better be kind over again than be unkindly once\" places the emphasis on kindness as the default, even at the cost of being taken advantage of. \"They that live longest see most\" counsels patience and the value of experience, a recurring theme in a culture that respected age and accumulated wisdom.",[20,1849,1850,1851,1853],{},"The Gaelic proverb \"Is fhearr Gaidhlig briste na Gaidhlig sa chiste\" translates to \"Broken Gaelic is better than Gaelic in the coffin,\" a saying that has taken on new urgency as the ",[32,1852,66],{"href":65}," struggles for survival. It captures in a single sentence the philosophy that has sustained Gaelic revitalization efforts: imperfect use is infinitely better than no use at all.",[20,1855,1856],{},"Scottish proverbs, taken together, describe a people who valued prudence over extravagance, community over individualism, resilience over complaint, and wit over solemnity. They are the distilled wisdom of generations who lived close to the land, close to each other, and close to the edge of survival, and their advice, sharp, warm, and unsentimental, remains remarkably useful centuries after it was first spoken.",{"title":90,"searchDepth":91,"depth":91,"links":1858},[1859,1860,1861,1862],{"id":1796,"depth":94,"text":1797},{"id":1809,"depth":94,"text":1810},{"id":1822,"depth":94,"text":1823},{"id":1835,"depth":94,"text":1836},"Scottish proverbs distill centuries of hard-won wisdom into memorable phrases. From advice on character to observations about weather, here are the sayings that shaped Scottish thinking.",[1865,1866,1867,1868,1869],"scottish proverbs wisdom","scottish sayings meanings","highland proverbs","gaelic proverbs english","scottish folk wisdom",{},"/blog/scottish-proverbs-wisdom",{"title":1790,"description":1863},"blog/scottish-proverbs-wisdom",[1875,1876,1877,1878,1879],"Scottish Proverbs","Scottish Wisdom","Highland Culture","Gaelic Proverbs","Scottish Sayings","dsp0pOFGxRgsNJi-EJIX-N6sNLDBS4XXRYaSIKxxckU",{"id":1882,"title":1883,"author":1884,"body":1886,"category":98,"date":1665,"description":1959,"extension":101,"featured":102,"image":103,"keywords":1960,"meta":1966,"navigation":111,"path":1967,"readTime":113,"seo":1968,"stem":1969,"tags":1970,"__hash__":1976},"blog/blog/standing-stones-scotland.md","Standing Stones of Scotland: Callanish, Brodgar, and Mystery",{"name":9,"bio":1885},"Author of The Forge of Tongues — 22,000 Years of Migration, Mutation, and Memory",{"type":12,"value":1887,"toc":1953},[1888,1892,1899,1902,1905,1909,1912,1919,1922,1926,1929,1932,1935,1939,1947,1950],[15,1889,1891],{"id":1890},"older-than-memory","Older Than Memory",[20,1893,1894,1895,1898],{},"Long before the Celts, before the Bronze Age, before the ",[32,1896,1897],{"href":1629},"Yamnaya migrations"," that reshaped Europe genetically, the peoples of what is now Scotland were raising stones. The great stone circles and standing stones of Scotland date primarily to the late Neolithic and early Bronze Age — roughly 3000 to 2000 BC — making them among the oldest monumental structures in the British Isles and contemporary with the pyramids of Egypt.",[20,1900,1901],{},"These monuments are scattered across Scotland, from the Borders to the Northern Isles, but the most spectacular concentrations are found in two locations: the Isle of Lewis in the Outer Hebrides, where the Callanish Stones stand in their cruciform arrangement overlooking Loch Roag, and Orkney, where the Ring of Brodgar and the Stones of Stenness form part of a remarkable ceremonial landscape that includes the Neolithic village of Skara Brae and the chambered tomb of Maeshowe.",[20,1903,1904],{},"The builders of these monuments left no written records. We do not know their names, their languages, or the specifics of their beliefs. What we have is the stones themselves — their positions, their alignments, their relationships to the landscape and to the sky — and the archaeological evidence from the sites and settlements associated with them.",[15,1906,1908],{"id":1907},"callanish-the-cross-on-the-moor","Callanish: The Cross on the Moor",[20,1910,1911],{},"The Callanish Stones on Lewis are arranged in a rough cruciform pattern — a central stone circle with avenues of stones extending to the north, south, east, and west. The central circle contains thirteen stones, the tallest standing nearly sixteen feet high. A small chambered cairn sits within the circle, though it appears to have been added after the stones were erected.",[20,1913,1914,1915,1918],{},"The setting is extraordinary. The stones stand on a ridge above Loch Roag, and from certain angles they dominate the skyline like figures in a procession. The Gaelic name for the site — ",[24,1916,1917],{},"Tursachan Chalanais"," — simply means the standing stones of Callanish, but local tradition held that the stones were giants turned to stone for refusing to convert to Christianity. The tradition is late, but it preserves something true: the sense that these stones are presences, not objects.",[20,1920,1921],{},"Astronomical alignments have been proposed for Callanish, and some are persuasive. The avenue that extends to the north aligns with the setting position of the moon at its major standstill — a phenomenon that occurs every 18.6 years, when the moon reaches its most extreme northern declination. Whether this alignment was intentional remains debated, but the care with which the stones were positioned suggests that the builders were observing the sky with precision and purpose.",[15,1923,1925],{"id":1924},"brodgar-and-the-heart-of-neolithic-orkney","Brodgar and the Heart of Neolithic Orkney",[20,1927,1928],{},"The Ring of Brodgar on Orkney is one of the largest stone circles in Britain — originally containing sixty stones, of which twenty-seven still stand, arranged in a circle over 340 feet in diameter. The circle is set on a narrow isthmus between the Loch of Harray and the Loch of Stenness, a position that places it between fresh water and salt water, land and sea. The location was almost certainly chosen for its liminal quality — its position on a boundary.",[20,1930,1931],{},"Brodgar is part of a wider ceremonial landscape that UNESCO has recognized as a World Heritage Site. The Stones of Stenness stand less than a mile to the southeast. Maeshowe, one of the finest chambered tombs in Europe, lies nearby, its passage aligned so the setting sun on the winter solstice illuminates the back wall of the inner chamber.",[20,1933,1934],{},"The Ness of Brodgar, excavated since 2003, has revealed a massive complex of Neolithic buildings between the two stone circles. These were substantial stone buildings with painted walls and evidence of feasting on an enormous scale. Whatever was happening at Brodgar and Stenness, it drew people from across the islands for purposes that combined the ceremonial, the social, and the astronomical.",[15,1936,1938],{"id":1937},"what-the-stones-mean","What the Stones Mean",[20,1940,1941,1942,1946],{},"The honest answer is that we do not know, with certainty, what the standing stones meant to the people who raised them. We can observe alignments and infer astronomical knowledge. We can note the careful selection of stone types and the enormous labor required to transport and erect them. We can see that the circles were places of gathering, that they were maintained over centuries, and that they were associated with ",[32,1943,1945],{"href":1944},"/blog/celtic-burial-practices","burial practices"," and ritual activity.",[20,1948,1949],{},"What we cannot do is reconstruct the belief system that motivated their construction. The Neolithic peoples of Scotland were pre-literate. Their religious and cosmological ideas were transmitted orally, and no oral tradition survives from a culture that disappeared four thousand years ago. The stones are the message, and we have lost the language in which they were written.",[20,1951,1952],{},"This uncertainty is part of their power. The standing stones of Scotland resist explanation. They compel attention without yielding their secrets. They stand in landscapes that have changed around them — forests have grown and been cleared, peat has accumulated and been cut, human populations have risen and fallen — while the stones remain, marking a commitment to something that mattered enough to justify years of communal labor. Whatever that something was, its monuments have outlasted every subsequent culture that has occupied these islands. The stones do not explain themselves. They simply endure.",{"title":90,"searchDepth":91,"depth":91,"links":1954},[1955,1956,1957,1958],{"id":1890,"depth":94,"text":1891},{"id":1907,"depth":94,"text":1908},{"id":1924,"depth":94,"text":1925},{"id":1937,"depth":94,"text":1938},"Across Scotland, stone circles and standing stones mark the landscape — monuments raised by Neolithic peoples whose beliefs and purposes we can only partially reconstruct. From Callanish on Lewis to the Ring of Brodgar on Orkney, these stones are among the oldest human structures in Britain.",[1961,1962,1963,1964,1965],"standing stones scotland","callanish stones","ring of brodgar","neolithic scotland","scottish stone circles",{},"/blog/standing-stones-scotland",{"title":1883,"description":1959},"blog/standing-stones-scotland",[1971,1972,1973,1974,1975],"Standing Stones","Neolithic Scotland","Callanish","Ring of Brodgar","Scottish Prehistory","7J8YahbI41ZOUB8vaG-1uuXjqm7iOrMgXt25yBiK-xc",[1978,1979,1980,1982,1983,1984,1985,1986,1987,1988,1989,1990,1991,1992,1993,1994,1995,1996,1997,1998,1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2012,2013,2014,2015,2016,2017,2018,2020,2021,2022,2023,2024,2025,2026,2027,2028,2029,2030,2032,2033,2034,2035,2036,2037,2038,2039,2040,2041,2042,2043,2044,2045,2046,2047,2048,2049,2050,2051,2052,2053,2054,2055,2056,2057,2058,2059,2060,2061,2062,2063,2065,2066,2067,2068,2069,2070,2071,2072,2073,2074,2075,2076,2077,2078,2079,2080,2081,2082,2083,2084,2085,2086,2087,2088,2089,2090,2091,2092,2093,2094,2095,2096,2097,2098,2099,2100,2101,2102,2103,2104,2105,2106,2107,2108,2109,2110,2111,2112,2113,2114,2115,2116,2117,2118,2119,2120,2121,2122,2123,2124,2125,2126,2127,2128,2129,2130,2131,2132,2133,2134,2135,2136,2137,2138,2139,2140,2141,2142,2143,2144,2145,2146,2147,2148,2149,2150,2151,2152,2153,2154,2155,2156,2157,2158,2159,2160,2161,2162,2163,2164,2165,2166,2167,2168,2169,2170,2171,2172,2173,2174,2175,2176,2177,2178,2179,2180,2181,2182,2183,2184,2185,2186,2187,2188,2189,2190,2191,2192,2193,2194,2195,2196,2197,2198,2199,2200,2201,2202,2203,2204,2205,2206,2207,2208,2209,2210,2211,2212,2213,2214,2215,2216,2217,2218,2219,2220,2221,2222,2223,2224,2225,2226,2227,2228,2229,2230,2231,2232,2233,2234,2235,2236,2237,2238,2239,2240,2241,2242,2243,2244,2245,2246,2247,2248,2249,2250,2251,2252,2253,2254,2255,2256,2257,2258,2259,2260,2261,2262,2263,2264,2265,2266,2267,2268,2269,2270,2271,2272,2273,2274,2275,2276,2277,2278,2279,2280,2281,2282,2283,2284,2285,2286,2287,2288,2289,2290,2291,2292,2293,2294,2295,2296,2297,2298,2299,2300,2301,2302,2303,2304,2305,2306,2307,2308,2309,2310,2311,2312,2313,2314,2315,2316,2317,2318,2319,2320,2321,2322,2323,2324,2325,2326,2327,2328,2329,2330,2331,2332,2333,2334,2335,2336,2337,2338,2339,2340,2341,2342,2343,2344,2345,2346,2347,2348,2349,2350,2351,2352,2353,2354,2355,2356,2357,2358,2359,2360,2361,2362,2363,2364,2365,2366,2367,2368,2369,2370,2371,2372,2373,2374,2375,2376,2377,2378,2379,2380,2381,2382,2383,2384,2385,2386,2387,2388,2389,2390,2391,2392,2393,2394,2395,2396,2397,2398,2399,2400,2401,2402,2403,2404,2405,2406,2407,2408,2409,2410,2411,2412,2413,2414,2415,2416,2417,2418,2419,2420,2421,2422,2423,2424,2425,2426,2427,2428,2429,2430,2431,2432,2433,2434,2435,2436,2437,2438,2439,2440,2441,2442,2443,2444,2445,2446,2447,2448,2449,2450,2451,2452,2453,2455,2456,2457,2458,2459,2460,2461,2462,2463,2464,2465,2466,2467,2468,2469,2470,2471,2472,2473,2474,2475,2476,2477,2478,2479,2480,2481,2482,2483,2484,2485,2486,2487,2488,2489,2490,2491,2492,2493,2494,2495,2496,2497,2498,2499,2500,2501,2502,2503,2504,2505,2506,2507,2508,2509,2510,2511,2512,2513,2514,2515,2516,2517,2518,2519,2520,2521,2522,2523,2524,2525,2526,2527,2528,2529,2530,2531,2532,2533,2534,2535,2536,2537,2538,2539,2540,2541,2542,2543,2544,2545,2546,2547,2548,2549,2550,2551,2552,2553,2554,2555,2556,2557,2558,2559,2560,2561,2562,2563,2564,2565,2566,2567,2568,2569,2570,2571,2572,2573,2574,2575,2576,2577,2578,2579,2580,2581,2582,2583,2584,2585,2586,2587,2588,2589,2590,2591,2592,2593,2594,2595,2596,2597,2598,2599,2600,2601,2602,2603,2604,2605,2606,2607,2608,2609,2610,2611,2612,2613,2614,2615,2616,2617,2618,2619,2620,2621,2622,2623],{"category":1006},{"category":98},{"category":1981},"AI",{"category":1538},{"category":265},{"category":1981},{"category":1981},{"category":1981},{"category":1981},{"category":1981},{"category":1981},{"category":1981},{"category":1981},{"category":1981},{"category":1981},{"category":1981},{"category":1981},{"category":1981},{"category":1981},{"category":1981},{"category":1981},{"category":1981},{"category":1981},{"category":1981},{"category":1981},{"category":98},{"category":98},{"category":98},{"category":98},{"category":98},{"category":98},{"category":2011},"Architecture",{"category":2011},{"category":1538},{"category":1538},{"category":2011},{"category":1538},{"category":1538},{"category":2019},"Security",{"category":2019},{"category":265},{"category":265},{"category":98},{"category":2019},{"category":98},{"category":2011},{"category":2019},{"category":1538},{"category":265},{"category":2031},"DevOps",{"category":1981},{"category":98},{"category":1538},{"category":2011},{"category":1538},{"category":98},{"category":98},{"category":98},{"category":2011},{"category":1538},{"category":2011},{"category":1538},{"category":1538},{"category":2011},{"category":98},{"category":98},{"category":98},{"category":98},{"category":98},{"category":98},{"category":2031},{"category":98},{"category":98},{"category":98},{"category":98},{"category":98},{"category":98},{"category":98},{"category":98},{"category":98},{"category":1538},{"category":2064},"Career",{"category":1981},{"category":1981},{"category":265},{"category":2011},{"category":265},{"category":1538},{"category":1538},{"category":265},{"category":1538},{"category":2011},{"category":1538},{"category":2031},{"category":2031},{"category":98},{"category":98},{"category":98},{"category":98},{"category":98},{"category":98},{"category":98},{"category":98},{"category":98},{"category":98},{"category":98},{"category":98},{"category":98},{"category":98},{"category":98},{"category":98},{"category":98},{"category":98},{"category":98},{"category":98},{"category":98},{"category":2011},{"category":2011},{"category":98},{"category":98},{"category":98},{"category":98},{"category":98},{"category":98},{"category":1981},{"category":2011},{"category":265},{"category":2031},{"category":2031},{"category":2031},{"category":98},{"category":1538},{"category":1538},{"category":98},{"category":1006},{"category":1981},{"category":2031},{"category":2031},{"category":2019},{"category":2031},{"category":265},{"category":1981},{"category":98},{"category":1538},{"category":98},{"category":2011},{"category":98},{"category":2011},{"category":2019},{"category":98},{"category":98},{"category":1538},{"category":265},{"category":1538},{"category":1006},{"category":1538},{"category":1538},{"category":1538},{"category":1538},{"category":265},{"category":265},{"category":98},{"category":1006},{"category":2019},{"category":2011},{"category":2019},{"category":1006},{"category":1538},{"category":1538},{"category":2031},{"category":1538},{"category":1538},{"category":2011},{"category":1538},{"category":2031},{"category":1538},{"category":1538},{"category":98},{"category":98},{"category":2019},{"category":2011},{"category":2011},{"category":2064},{"category":2064},{"category":2064},{"category":265},{"category":1538},{"category":2031},{"category":2011},{"category":98},{"category":98},{"category":2031},{"category":2011},{"category":2011},{"category":1006},{"category":1538},{"category":98},{"category":98},{"category":1538},{"category":98},{"category":2031},{"category":2031},{"category":98},{"category":2019},{"category":98},{"category":2011},{"category":2019},{"category":2011},{"category":1538},{"category":2011},{"category":1538},{"category":1538},{"category":1538},{"category":1538},{"category":1538},{"category":1538},{"category":1538},{"category":1538},{"category":2011},{"category":1538},{"category":1538},{"category":2019},{"category":1538},{"category":2031},{"category":2031},{"category":265},{"category":1538},{"category":1538},{"category":1538},{"category":2011},{"category":1538},{"category":1538},{"category":1538},{"category":1538},{"category":1538},{"category":1538},{"category":2011},{"category":2011},{"category":2011},{"category":1538},{"category":98},{"category":98},{"category":98},{"category":2031},{"category":265},{"category":98},{"category":98},{"category":1538},{"category":98},{"category":1538},{"category":1006},{"category":98},{"category":265},{"category":265},{"category":1538},{"category":1538},{"category":1981},{"category":98},{"category":98},{"category":98},{"category":98},{"category":98},{"category":98},{"category":98},{"category":98},{"category":1538},{"category":2031},{"category":2031},{"category":2031},{"category":2011},{"category":98},{"category":98},{"category":98},{"category":98},{"category":2011},{"category":98},{"category":2011},{"category":98},{"category":98},{"category":98},{"category":98},{"category":98},{"category":98},{"category":265},{"category":265},{"category":98},{"category":1538},{"category":1006},{"category":2011},{"category":2064},{"category":98},{"category":98},{"category":2019},{"category":1538},{"category":98},{"category":98},{"category":2031},{"category":98},{"category":1006},{"category":2031},{"category":2031},{"category":2019},{"category":1538},{"category":1538},{"category":2011},{"category":98},{"category":98},{"category":98},{"category":98},{"category":98},{"category":98},{"category":2064},{"category":98},{"category":2011},{"category":1538},{"category":1538},{"category":98},{"category":2031},{"category":98},{"category":98},{"category":98},{"category":1006},{"category":98},{"category":98},{"category":1538},{"category":98},{"category":1538},{"category":2011},{"category":98},{"category":98},{"category":98},{"category":1981},{"category":1981},{"category":1538},{"category":98},{"category":2031},{"category":2031},{"category":98},{"category":1538},{"category":98},{"category":98},{"category":1981},{"category":98},{"category":98},{"category":98},{"category":2011},{"category":98},{"category":98},{"category":98},{"category":1538},{"category":1538},{"category":1538},{"category":2019},{"category":1538},{"category":1538},{"category":1006},{"category":1538},{"category":1006},{"category":1006},{"category":2019},{"category":2011},{"category":1538},{"category":2011},{"category":98},{"category":98},{"category":1538},{"category":1538},{"category":1538},{"category":265},{"category":1538},{"category":1538},{"category":98},{"category":2011},{"category":1981},{"category":1981},{"category":98},{"category":98},{"category":98},{"category":98},{"category":265},{"category":1538},{"category":98},{"category":98},{"category":1538},{"category":1538},{"category":1006},{"category":1538},{"category":1538},{"category":1538},{"category":1538},{"category":1538},{"category":1538},{"category":1538},{"category":1538},{"category":1538},{"category":1538},{"category":1538},{"category":1538},{"category":2011},{"category":1538},{"category":1538},{"category":1538},{"category":2011},{"category":98},{"category":265},{"category":1981},{"category":98},{"category":265},{"category":2019},{"category":98},{"category":2019},{"category":1538},{"category":2031},{"category":98},{"category":98},{"category":1538},{"category":98},{"category":2011},{"category":98},{"category":98},{"category":1538},{"category":265},{"category":1538},{"category":1538},{"category":1538},{"category":1538},{"category":265},{"category":1538},{"category":1538},{"category":265},{"category":2031},{"category":1538},{"category":1981},{"category":98},{"category":98},{"category":1538},{"category":1538},{"category":98},{"category":98},{"category":98},{"category":1981},{"category":1538},{"category":1538},{"category":2011},{"category":1006},{"category":1538},{"category":98},{"category":1538},{"category":2011},{"category":265},{"category":265},{"category":1006},{"category":1006},{"category":98},{"category":265},{"category":2019},{"category":98},{"category":98},{"category":98},{"category":98},{"category":98},{"category":98},{"category":98},{"category":2011},{"category":1538},{"category":1538},{"category":2011},{"category":1538},{"category":1538},{"category":1538},{"category":2454},"Programming",{"category":1538},{"category":1538},{"category":2011},{"category":2011},{"category":1538},{"category":1538},{"category":265},{"category":2019},{"category":1538},{"category":265},{"category":1538},{"category":1538},{"category":1538},{"category":1538},{"category":2031},{"category":2011},{"category":265},{"category":265},{"category":1538},{"category":1538},{"category":265},{"category":1538},{"category":2019},{"category":265},{"category":1538},{"category":1538},{"category":2011},{"category":2011},{"category":98},{"category":265},{"category":98},{"category":98},{"category":98},{"category":98},{"category":98},{"category":98},{"category":98},{"category":98},{"category":98},{"category":98},{"category":98},{"category":98},{"category":98},{"category":98},{"category":98},{"category":98},{"category":98},{"category":98},{"category":98},{"category":98},{"category":98},{"category":98},{"category":98},{"category":98},{"category":98},{"category":98},{"category":98},{"category":98},{"category":1006},{"category":98},{"category":2031},{"category":2019},{"category":2019},{"category":2019},{"category":2019},{"category":2019},{"category":2019},{"category":98},{"category":1538},{"category":2031},{"category":2011},{"category":2031},{"category":2011},{"category":1538},{"category":1006},{"category":98},{"category":2011},{"category":1006},{"category":98},{"category":98},{"category":98},{"category":2011},{"category":2011},{"category":2011},{"category":265},{"category":265},{"category":265},{"category":2011},{"category":2011},{"category":265},{"category":265},{"category":265},{"category":98},{"category":2019},{"category":1538},{"category":2031},{"category":1538},{"category":98},{"category":265},{"category":265},{"category":98},{"category":98},{"category":2011},{"category":1538},{"category":2011},{"category":2011},{"category":2011},{"category":1006},{"category":1538},{"category":98},{"category":98},{"category":265},{"category":265},{"category":2011},{"category":1538},{"category":2064},{"category":2011},{"category":2064},{"category":265},{"category":98},{"category":2011},{"category":98},{"category":98},{"category":98},{"category":1538},{"category":1538},{"category":98},{"category":1981},{"category":1981},{"category":2031},{"category":98},{"category":98},{"category":98},{"category":98},{"category":1538},{"category":1538},{"category":1006},{"category":1538},{"category":2019},{"category":2011},{"category":1006},{"category":1006},{"category":1538},{"category":1538},{"category":1006},{"category":1006},{"category":1006},{"category":2019},{"category":1538},{"category":1538},{"category":265},{"category":1538},{"category":2011},{"category":98},{"category":98},{"category":2011},{"category":98},{"category":98},{"category":2011},{"category":98},{"category":1538},{"category":98},{"category":2019},{"category":98},{"category":98},{"category":98},{"category":2031},{"category":2031},{"category":2019},1772951196256]