1 2window.moduloBuild = window.moduloBuild || { modules: {}, nameToHash: {} }; 3 4window.moduloBuild.modules["x1h0vjl4"] = function configuration (modulo) { 5 6 function setupFathom(code) { 7 // Check common things we skip 8 const host = window.location.host; 9 if (host.startsWith('localhost') || 10 host.includes('.local') || 11 host.startsWith('127') || 12 host.startsWith('192') || 13 host.startsWith('dev--')) { 14 return; 15 } 16 (function(f, a, t, h, o, m){ 17 a[h]=a[h]||function(){ 18 (a[h].q=a[h].q||[]).push(arguments) 19 }; 20 o=f.createElement('script'), 21 m=f.getElementsByTagName('script')[0]; 22 o.async=1; o.src=t; o.id='fathom-script'; 23 m.parentNode.insertBefore(o,m) 24 })(document, window, '//an.michaelb.org/tracker.js', 'fathom'); 25 fathom('set', 'siteId', code); 26 fathom('trackPageview'); 27 } 28 setupFathom('JUSMY'); 29 30}; 31window.moduloBuild.nameToHash.configuration = "x1h0vjl4"; 32 33window.moduloBuild.modules["xxkop4gm"] = function configuration1 (modulo) { 34// This is very useful, and may make it into core Modulo 35// Uses: 36// - Adding head content that gets idempotently added in a natural way: 37// - <template Include><script src="whatevs"></script></template> 38// - Using it like a mini NPM: 39// - <Include showdown="1.3.4" neat-widgets="4.2.6"></Include> 40// - <Include create-modulo></Include> To bring in CMTK! 41// Eventually, a cool idea would be define named ones at top, and include 42// lazily if scripts are loaded (e.g. <Include jquery></Include> in a 43// component) -- might work? 44//Server: 'unpkg.com', 45modulo.config.include = { 46 GlobalBundled: { }, 47 LoadMode: 'bundle', 48 ServerTemplate: 'https://{{ server }}/{{ path }}', 49 TagTemplate: '{% if isCSS %}<link name="{{ package }}" rel="stylesheet" href="{{ url }}" />' + 50 '{% else %}<script name="{{ package }}" src="{{ url }}"></' + 'script>{% endif %}', 51 DefLoaders: [ 'DefTarget', 'DefinedAs', 'Src', 'Server', 'LoadMode' ], 52}; 53 54modulo.register('util', function loadHead(modulo, loadMode, elem, knownBundled) { // TODO refactor with AssetManager? 55 const { newNode, hash } = modulo.registry.utils; 56 const id = hash(elem.name || elem.src || elem.href || elem.tagName); 57 if (window.document.getElementById(id) || knownBundled[id]) { 58 return; // already exists, never add twice 59 } 60 knownBundled[id] = loadMode === 'bundle'; // (set to true if bundling this) 61 const newElem = newNode(elem.innerHTML, elem.tagName); 62 for (const attr of elem.attributes || []) { // Copy all attributes from old elem 63 newElem.setAttributeNode(attr.cloneNode(true)); // ...to new elem 64 } 65 newElem.setAttribute('id', id); // TODO: Create a "setAttrs" func for this, or enhance newNode 66 if (loadMode !== 'bundle') { 67 newElem.setAttribute('modulo-asset', 'y'); 68 } 69 /*if (elem.tagName === 'SCRIPT') { // Need to fix SCRIPT tag fluke 70 newElem.src = elem.src; // (TODO: Still needed?) 71 }*/ 72 window.document.head.append(newElem); 73}); 74 75modulo.register('cpart', class Include { 76 static LoadMode(modulo, def, value) { // Loads given Include def 77 const { loadHead, newNode, keyFilter } = modulo.registry.utils; 78 const lower = key => key[0].toLowerCase() === key[0]; // skip "-prefixed" 79 const ctx = { def, modulo, headContent: def.Content || '' }; 80 const render = code => new modulo.registry.cparts.Template(code).render(ctx); 81 for (const [ pkg, v ] of Object.entries(keyFilter(def, lower))) { 82 ctx.path = v.contains('@') ? v : pkg + (v ? ('@' + v) : ''); 83 ctx.isCSS = (ctx.path.contains('/') && ctx.path.endsWith('.css')); 84 ctx.url = render(def.ServerTemplate); // Render URL using ServerTemplate 85 ctx.headContent += render(def.TagTemplate); // Append tag to head Content 86 } 87 for (const elem of newNode(ctx.headContent).children) { // Loop through combined 88 loadHead(modulo, value, elem, modulo.config.include.GlobalBundled); 89 } 90 } 91 intitializedCallback(renderObj) { 92 const { Include } = this.modulo.registry.cparts; // Can I use self. reliably? 93 Include.LoadMode(this.modulo, this.attrs, 'lazy', { }); // Always load if ID not exist 94 } 95}); 96modulo.register('coreDef', modulo.registry.cparts.Include); 97 98}; 99window.moduloBuild.nameToHash.configuration1 = "xxkop4gm"; 100 101window.moduloBuild.modules["x1ohdeuk"] = function library_configuration (modulo) { 102 103 modulo.register('util', function loadLink(href, loadMode) { // TODO refactor with AssetManager? 104 const { newNode, hash } = modulo.registry.utils; 105 const id = hash(href); 106 if (window.document.getElementById(id)) { 107 return; // already exists, never add twice 108 } 109 const newElem = newNode('', 'link'); 110 newElem.setAttribute('id', id); 111 newElem.setAttribute('rel', 'stylesheet'); 112 let proto = window.location.protocol; 113 newElem.setAttribute('href', proto + href); 114 if (loadMode !== 'bundle') { 115 newElem.setAttribute('modulo-asset', 'y'); 116 } 117 window.document.head.append(newElem); 118 }); 119 modulo.registry.utils.loadLink('//fonts.googleapis.com/css?family=Raleway:300,400,700,800%7CLato:300,400,700'); 120 modulo.registry.utils.loadLink('//cdn.jsdelivr.net/npm/[email protected]/font/bootstrap-icons.min.css'); 121 122}; 123window.moduloBuild.nameToHash.library_configuration = "x1ohdeuk"; 124 125window.moduloBuild.modules["xx5qsu45"] = function library1_configuration (modulo) { 126 127 modulo.register('templateFilter', function hlinperson (text) { 128 return text 129 .replace(/(in.person)/gi, '<span class="text--hlinperson">$1</span>') 130 .replace(/(on.site)/gi, '<span class="text--hlinperson">$1</span>'); 131 }); 132 133}; 134window.moduloBuild.nameToHash.library1_configuration = "xx5qsu45"; 135 136window.moduloBuild.modules["xxp4is5b"] = function library_Page (modulo) { 137const def = modulo.definitions['library_Page']; 138class x_Page extends window.HTMLElement { 139constructor() { super(); this.init(); } 140}
141modulo.registry.utils.initComponentClass(modulo, def, x_Page); 142window.customElements.define(def.TagName, x_Page); 143return x_Page; 144 145}; 146window.moduloBuild.nameToHash.library_Page = "xxp4is5b"; 147 148window.moduloBuild.modules["xxln9ofu"] = function library_FeaturedTestimonials (modulo) { 149const def = modulo.definitions['library_FeaturedTestimonials']; 150class x_FeaturedTestimonials extends window.HTMLElement { 151constructor() { super(); this.init(); } 152} 153modulo.registry.utils.initComponentClass(modulo, def, x_FeaturedTestimonials); 154window.customElements.define(def.TagName, x_FeaturedTestimonials); 155return x_FeaturedTestimonials; 156 157}; 158window.moduloBuild.nameToHash.library_FeaturedTestimonials = "xxln9ofu"; 159 160window.moduloBuild.modules["x1b97eng"] = function library_Testimonials (modulo) { 161const def = modulo.definitions['library_Testimonials']; 162class x_Testimonials extends window.HTMLElement { 163constructor() { super(); this.init(); } 164} 165modulo.registry.utils.initComponentClass(modulo, def, x_Testimonials); 166window.customElements.define(def.TagName, x_Testimonials); 167return x_Testimonials; 168 169}; 170window.moduloBuild.nameToHash.library_Testimonials = "x1b97eng"; 171 172window.moduloBuild.modules["xx7g6r2p"] = function library_FeaturedArticles (modulo) { 173const def = modulo.definitions['library_FeaturedArticles']; 174class x_FeaturedArticles extends window.HTMLElement { 175constructor() { super(); this.init(); } 176} 177modulo.registry.utils.initComponentClass(modulo, def, x_FeaturedArticles); 178window.customElements.define(def.TagName, x_FeaturedArticles); 179return x_FeaturedArticles; 180 181}; 182window.moduloBuild.nameToHash.library_FeaturedArticles = "xx7g6r2p"; 183 184window.moduloBuild.modules["x11i3991"] = function library_Page_script (modulo) { 185var script = { exports: { } }; 186 function prepareCallback() { 187 // For now, store the navigation array and generate year in JS 188 return { 189 currentYear: (new Date()).getFullYear(), 190 navigation: [ 191 { 192 title: "Start", 193 file: "index.html", 194 }, 195 { 196 title: "Courses", 197 file: "courses/", 198 }, 199 { 200 title: "Plans", 201 //file: "index.html#learn", 202 file: "apply/", 203 }, 204 { 205 title: "Services", 206 file: "services/", 207 }, 208 /* 209 { 210 title: "Results", 211 file: "results/", 212 }, 213 { 214 title: "Learn", 215 //file: "index.html#learn", 216 file: "learn/", 217 }, 218 { 219 title: "Outreach", 220 file: "outreach/", 221 }, 222 */ 223 ], 224 }; 225 } 226 ;return { exports: script.exports, "prepareCallback": typeof prepareCallback !== "undefined" ? prepareCallback : undefined, setLocalVariables: function (o) { } } 227}; 228window.moduloBuild.nameToHash.library_Page_script = "x11i3991"; 229 230window.moduloBuild.modules["xxbcstkp"] = function library_FeaturedTestimonials_staticdata (modulo) { 231return [{"name":"Anthony Sifontes","img":"anthony.jpg","location":"New Orleans, Louisiana","profession":"Software Engineer @ Amino","linkedin":"anthonysifontes","featured":"Software Engineer","pullquote":"I eventually received an offer to be a Software Engineer at an exciting\n healthcare start-up, and only 11 weeks into the program.","text":"\n My career thus far had been in data analytics. I wanted to\n transition to a developer role and ultimately be able to create and\n turn my ideas into reality. I had not taken any coding courses\n before this, only online tutorials and books, so I was not sure\n what to expect. <strong>Class after class, I was blown away by the\n passion Michael and his team brought to each and every\n lesson!</strong> The classes were lively, balanced between lecture,\n demonstrations, guided coding activities, and group work, while\n still being accessible to a wide range of experience levels.\n\n A couple of months into the course, I started applying for\n developer positions, and soon I was excited to be invited for a\n round of on-site interviews. <strong>Michael was very supportive,\n coaching me on how to best present my work experience, and guiding\n me through a mock \"whiteboard\" interview.</strong> Every interview\n was more challenging than the last, but all of the coaching and\n prep received at Kickstart beforehand was critical to my moving\n forward in the process. You can imagine my excitement when I\n eventually received an offer to be a Software Engineer at an\n exciting healthcare start-up, and only 11 weeks into the program!\n Now, I've been at my new position for several months, and I love\n it. The work we did in class was instrumental in preparing me for\n my new day-to-day duties. I'm very thankful to the Kickstart\n Coding team and the help they provided in transitioning to my new\n software engineering career.\n "},{"name":"Andrew Thorton","img":"andrew.jpg","location":"Alameda, California","profession":"Data Engineer @ Lyft","featured":"Data Engineer","linkedin":"andrew-w-thornton","pullquote":"Using my newly acquired skills, I got a great new job as a Data\n Engineer just a couple of weeks after finishing the Kickstart Coding\n course.","text":"\n After spending years as a software project and product manager flirting\n with the idea of becoming a software engineer, I finally got up the\n courage to sign up for a coding bootcamp. I looked at many different\n options and chose Kickstart Coding because it provides excellent value\n and is staffed by people that are clearly passionate about teaching\n technology. I enjoyed the in-class lessons which are an engaging mix of\n lecture, live-coding walkthroughs, and activities. The homework\n assignments and group projects built nicely on the stuff we learned in\n class and helped to reinforce the concepts with very practical\n examples. <strong>The curriculum does a masterful job of challenging\n people with some coding experience while also being accessible to\n people with no coding background at all.</strong> While the vast\n majority of the curriculum is very focu
231sed on teaching specific\n languages and frameworks, the last couple lessons of the Front-End\n portion of the course are focused on some more general concepts that\n were extremely helpful in preparing me for interviews. Using my newly\n acquired skills, I got a great new job as a Data Engineer just a couple\n of weeks after finishing the Kickstart Coding course. <strong>I would\n recommend Kickstart Coding to everyone, even if you don't want a job as\n a software engineer. Learning to code in this setting was really\n fun!</strong>\n "},{"name":"Nicol Hawkins","featured":"Platform Specialist","img":"nicol.jpg","location":"San Franciso, California","profession":"Platform Specialist @ Amplitude","linkedin":"nicol-hawkins","featured_on_frontpage":true,"pullquote":"Thanks to the skills I learned at Kickstart Coding, I was\n able to market myself for entry-level positions in the tech industry.","featured_text":"\n When I started Kickstart Coding, I had very few programming skills and\n no prior work experience in tech. It was a huge leap for me and it\n literally changed my life! <strong>Kickstart Coding is more affordable\n than most coding bootcamps and the curriculum is top-notch while having\n a lot of repeat value.</strong> [...] I am blown away by how much I\n learned since my first day at Kickstart Coding; from my first HTML file\n all the way to navigating complex frameworks and implementing APIs.\n\n This program not only gave me the technical skills required for a\n career in tech -- it helped me recognize the potential and capacity I\n have for learning.\n ","text":"\n When I started Kickstart Coding, I had very few programming skills and\n no prior work experience in tech. It was a huge leap for me and it\n literally changed my life! Kickstart Coding is more affordable than\n most coding bootcamps and the curriculum is top-notch while having a\n lot of repeat value.\n\n I left the course with a personal webpage full of projects to showcase\n and revisited the curriculum often to tackle bonus activities. The\n course is approachable whether you're like me and just starting out or\n already possess programming skills. I am blown away by how much\n I learned since my first day at Kickstart Coding; from my first HTML\n file all the way to navigating complex frameworks and implementing\n APIs.\n\n This program not only gave me the technical skills required for a\n career in tech -- it helped me recognize the potential and capacity I\n have for learning. A major part of my new role as a Platform Specialist\n is communicating with engineers and data analysts, so having a\n background in software helps me communicate effectively and\n efficiently. Thanks to the skills I learned at Kickstart Coding, I was\n able to market myself for entry-level positions in the tech industry.\n "}]; 232}; 233window.moduloBuild.nameToHash.library_FeaturedTestimonials_staticdata = "xxbcstkp"; 234 235window.moduloBuild.modules["xxnr3p18"] = function library_Testimonials_staticdata (modulo) { 236return [{"name":"Nicolas Miller","img":"nicolas.jpg","location":"Antioch, California","profession":"Software Engineer @ Rooster Grin Media","linkedin":"nicolas-wyatt-miller","pullquote":"The custom paced structure was possibly the most vital component to\n my success [...] this setup allowed me to pace my progress and\n uphold my life's balance in the process.","text":"\n <strong>It sounds cheesy, but Kickstart Coding gave me the\n opportunity to make a career shift that I never thought I would be\n able to.</strong> The personalized tutoring helped target my\n weaknesses and get honest feedback on my projects that large scale\n programs are unable to provide. The custom paced structure was\n possibly the most vital component to my success; I've never been\n the person who gets something new on the first, second, or even\n third try, but this setup allowed me to pace my progress and uphold\n my life's balance in the process. The instructional material was\n intense, but Michael makes some hilarious references and segments\n the topics into digestible lessons. If I could give any advice, I\n would say to not let anything stop you, but ESPECIALLY don't let\n you stop yourself. You 1000% can do this and self doubt or fear of\n difficulty are likely to be your biggest obstacles -- you just have\n to be kind to yourself and get up again when JavaScript and CSS\n inevitably knock you down. <strong>You are going to be so proud of\n yourself because this is massive and this is worth it!</strong>\n ","featured":null},{"name":"Anthony Sifontes","img":"anthony.jpg","location":"New Orleans, Louisiana","profession":"Software Engineer @ Amino","linkedin":"anthonysifontes","featured":null,"pullquote":"I eventually received an offer to be a Software Engineer at an exciting\n healthcare start-up, and only 11 weeks into the program.","text":"\n My career thus far had been in data analytics. I wanted to\n transition to a developer role and ultimately be able to create and\n turn my ideas into reality. I had not taken any coding courses\n before this, only online tutorials and books, so I was not sure\n what to expect. <strong>Class after class, I was blown away by the\n passion Michael and his team brought to each and every\n lesson!</strong> The classes were lively, balanced between lecture,\n demonstrations, guided coding activities, and group work, while\n still being accessible to a wide range of experience levels.\n\n A couple of months into the course, I started applying for\n developer positions, and soon I was excited to be invited for a\n round of on-site interviews. <strong>Michael was very supportive,\n coaching me on how to best present my work experience, and guiding\n me through a mock \"whiteboard\" interview.</strong> Every interview\n was more challenging than the last, but all of the coaching and\n prep received at Kickstart beforehand was critical to my moving\n forward in the process. You can imagine my excitement when I\n eventually received an offer to be a Software Engineer at an\n exciting healthcare start-up, and only 11 weeks into the program!\n Now, I've been at my new position for several months, and I love\n it. The work we did in class was instrumental in preparing me for\n my new day-to-day duties. I'm very thankful to the Kickstart\n Coding team and the help they provided in transitioning to my new\n software engineering career.\n "},{"name":"Andrew Thorton","img":"andrew.jpg","location":"Alameda, California","profession":"Data Engineer @ Lyft","featured":null,"linkedin":"andrew-w-thornton","pullquote":"Using my newly acquired skills, I got a great new job as a Data\n Engineer just a couple of weeks after finishing the Kickstart Coding\n course.","text":"\n After spending years as a software project and product manager flirting\n with the idea of becoming a software engineer, I finally got up the\n courage to sign up for a coding bootcamp. I looked at many different\n options and chose Kickstart Coding because it provides excellent value\n and is staffed by people that are clearly passionate about teaching\n technology. I enjoyed the in-class lessons which are an engaging mix of\n lecture, live-coding walkthroughs, and activities. The homework\n assignments and group projects built nicely on the stuff we learned in\n class and helped to reinforce the concepts with very practical\n examples. <strong>The curriculum does a masterful job of challenging\n people with some coding experience while also being accessible to\n people with no coding background at all.</strong> While the vast\n majority of the curriculum is very focu
236sed on teaching specific\n languages and frameworks, the last couple lessons of the Front-End\n portion of the course are focused on some more general concepts that\n were extremely helpful in preparing me for interviews. Using my newly\n acquired skills, I got a great new job as a Data Engineer just a couple\n of weeks after finishing the Kickstart Coding course. <strong>I would\n recommend Kickstart Coding to everyone, even if you don't want a job as\n a software engineer. Learning to code in this setting was really\n fun!</strong>\n "},{"name":"Sarah Farnsworth-Kumli","img":"sarah.jpg","location":"San Francisco, California","profession":"Solutions Engineer @ Okta","linkedin":"sarah-fk","pullquote":"I walked into Kickstart Coding to brush up on my skills. I\n left with a new career.","text":"\n <strong>Now that I am on the other side, have landed a job, and am\n now working with developers I can honestly say that Kickstart is a\n quality program.</strong> They take a modern approach to teaching\n and teach what's current in an adapting industry (also what stacks\n companies are hiring for!).\n\n Michael covered CS concepts in an incredibly accessible way for a\n diverse classroom with different levels of experience. The course\n material was the perfect balance of providing introductory guidance\n and challenge. Group projects exposed us to the challenges of\n working in a development team and we continued to build on new\n iterations of our personal projects.\n\n It's a privilege to have been a part of such a fantastic community,\n and I'm excited to see it grow. <strong>Amazing how such a short\n time can change your life, if you're considering taking the plunge,\n DO IT!</strong>\n ","featured":null},{"name":"Nicol Hawkins","featured":null,"img":"nicol.jpg","location":"San Franciso, California","profession":"Platform Specialist @ Amplitude","linkedin":"nicol-hawkins","featured_on_frontpage":true,"pullquote":"Thanks to the skills I learned at Kickstart Coding, I was\n able to market myself for entry-level positions in the tech industry.","featured_text":"\n When I started Kickstart Coding, I had very few programming skills and\n no prior work experience in tech. It was a huge leap for me and it\n literally changed my life! <strong>Kickstart Coding is more affordable\n than most coding bootcamps and the curriculum is top-notch while having\n a lot of repeat value.</strong> [...] I am blown away by how much I\n learned since my first day at Kickstart Coding; from my first HTML file\n all the way to navigating complex frameworks and implementing APIs.\n\n This program not only gave me the technical skills required for a\n career in tech -- it helped me recognize the potential and capacity I\n have for learning.\n ","text":"\n When I started Kickstart Coding, I had very few programming skills and\n no prior work experience in tech. It was a huge leap for me and it\n literally changed my life! Kickstart Coding is more affordable than\n most coding bootcamps and the curriculum is top-notch while having a\n lot of repeat value.\n\n I left the course with a personal webpage full of projects to showcase\n and revisited the curriculum often to tackle bonus activities. The\n course is approachable whether you're like me and just starting out or\n already possess programming skills. I am blown away by how much\n I learned since my first day at Kickstart Coding; from my first HTML\n file all the way to navigating complex frameworks and implementing\n APIs.\n\n This program not only gave me the technical skills required for a\n career in tech -- it helped me recognize the potential and capacity I\n have for learning. A major part of my new role as a Platform Specialist\n is communicating with engineers and data analysts, so having a\n background in software helps me communicate effectively and\n efficiently. Thanks to the skills I learned at Kickstart Coding, I was\n able to market myself for entry-level positions in the tech industry.\n "},{"name":"Yulia Tuzov","img":"yulia.jpg","location":"San Mateo, California","profession":"QA engineer @ Skupos","linkedin":"yuliatuzov","pullquote":"Kickstartâs curriculum gave me technical understanding of\n all the moving parts involved in building a software product.","text":"\n I have been in tech for couple of years in a QA role prior to going\n to this bootcamp. And now transitioning into an engineering role.\n Kickstartâs curriculum gave me technical understanding of all the\n moving parts involved in building a software product as well as\n practice of building those parts in group projects and individual\n projects which is extremely valuable experience.\n \n The curriculum overall is very well structured in a way that after\n every topic is introduced students had to apply it in their\
236n homework right away as well as final projects at the end of each\n course. Program also includes industry insights and job prep\n material. <strong>Michael, Mark and Maddy are very passionate about\n their students to succeed in the career transitions. You do have to\n work a lot during the course, so be ready, but youâll also have\n amazing support.</strong> Support also doesnât end after the\n course, you can come to their hack & learns to get help or\n guidance.\n ","featured":null},{"name":"Kyle Pollock","img":"kyle.jpg","location":"San Francisco, California","profession":"Knowledge Base Manager @ Synapse","linkedin":"kylepollock","pullquote":"I got a job offer within 30 days of completing my 4 month summer cohort.","text":"\n I was looking for a place to learn Python, JavaScript, and how to work\n with APIs to increase my skills, and make myself more marketable as a\n former jack of all trades website manager. I was quite familiar with\n the coding bootcamps in the Bay Area, as a friend of mine helped start\n one in San Francisco. When I searched around for programs and found\n Kickstart Coding, I couldn't find one that could beat it's overall\n value through affordability, flexibility, and course offerings. I was\n able to build three strong projects in Github (along with other\n projects) and an online portfolio. I got a job offer within 30 days of\n completing my 4 month summer cohort. <strong>I also more than tripled\n my income from my previous job as a non-profit communications manager.\n I am grateful to have gone through Kickstart Coding, and for the\n ongoing support beyond graduation through the teachers and alumni\n group.</strong>\n ","featured":null},{"name":"Rudy Trubitt","img":"rudy.jpg","location":"Oakland, California","profession":"Senior Software Test Engineer @ Dolby","linkedin":"rudy-trubitt-43b2126","pullquote":"Kickstart Coding gave me the key skills I needed to advance my career.","text":"\n <strong>I needed a career boost and Kickstart delivered.</strong>\n From the start, I was impressed by my interactions with the\n programâs staff. Although I was looking specifically for Python\n instruction, the additional material in the back-end course turned\n out to be extremely relevant. The class work was challenging but\n well-differentiated for students with varying levels of programming\n experience. And I thoroughly enjoyed getting to know and work with\n everyone in my cohort.\n\n During my job hunting and interviewing, I regularly reflected on\n things I learned in the program. <strong>There were times when I\n literally could hear Michael's voice in my head while I answered\n interview questions.</strong> Although my previous skills also\n helped me land my current position, there's no doubt that Kickstart\n Coding gave me the key skills I needed to advance my career.\n ","featured":null},{"name":"Cindy Dovinh","img":"cindy.jpg","location":"Oakland, California","profession":"","pullquote":"Kickstart Coding delivered on commitment to value, education, and passion.","text":"\n Kickstart Coding could not have been more aptly named and the\n schedule/format of the class could not have fit my needs better.\n With my full-time, non-tech job demanding a minimum of 50-60 hrs\n per week, I still looked forward to every class (2 weekday evenings\n and Saturday afternoon, each week). Michael is hands down the best\n teacher I've ever had. He is an expert at what he does, with an\n impressively VAST knowledge base and still managed to consistently\n make you feel comfortable in your learning. Being introduced to so\n much new information and new ways of thinking, he was always able\n to answer our questions thoroughly, even though at times, we didn't\n even know how to ask them.\n ","featured":null},{"name":"Errin Mixon","img":"errin.jpg","location":"Oakland, California","profession":"Junior Frontend Developer @ GeoEx","linkedin":"errin-mixon-2b289023","pullquote":"I couldn't have afforded the time or money to take a traditional\n bootcamp. I came out the other end as a web developer â with a new job.","text":"\n I come from a zero-tech background. I wanted to build an app. Michael\n said he could teach me that, so I signed up.\n\n I'm not going to lie. This bootcamp was hard. For a tech newbie with a\n full-time job and family, the time commitment is intense. I was often\n frustrated. I cried, a lot. I secretly thought that I shouldn't have\n been admitted to the course.\n\n But I came out the other end as a web developer â with a new job. That\n hadn't even been my goal, and you couldn't find anybody more surprised\n than me!\n\n I couldn't have afforded the time or money to take a traditional\n bootcamp. I never would have tried. <strong>Kickstart Coding made\n it possible for me to learn these skills, and it's no exaggeration\n to say that it changed the trajectory of my career, and possibly my\n life.</strong> Michael is an excellent and engaging teacher, as are\n TA's Maddy and Mark, and I owe them a debt of gratitude.\n\n 5 stars for Kickstart â well worth your money.\n ","featured":null},{"name":"Jeremy Johnson","img":"jeremy.jpg","location":"Madison, Wisconsin","profession":"Web Developer @ Know How","linkedin":"jeremy-johnson-80035395","pullquote":"The skills I learned in this course I use every day at my new job\n as a web developer.","text":"\n Out of high school I got a 2 year web programming degree at a local\n technical college. I applied and applied for programming jobs and\n was unable to land one. I really enjoyed programming but started to\n think I would never be able to make it my career. A few years went\n by working odd jobs when I got the opportunity to take this\n bootcamp online.\n \n <strong>I can't begin to say how great this course is. I learned\n more about programming in a matter of weeks than I did in a matter\n of years in school.</strong> Seeing real world examples of what we\n were learning along the way made me excited to learn and do the\n work. In addition to the amazing coursework, Micheal equips you\n with great tools to help you find a job. <strong>I was able to get\n a programming job just weeks after completing the course.</strong>\n The skills I learned in this course I use every day at my job as a\n web developer.\n \n I am very happy with my new job and 100% recommend this course to\n anyone looking to get into tech!\n ","featured":null}]; 237}; 238window.moduloBuild.nameToHash.library_Testimonials_staticdata = "xxnr3p18"; 239 240window.moduloBuild.modules["x1dmq5c6"] = function library_FeaturedArticles_staticdata (modulo) { 241return {"results":[{"url":"https://kickstartcoding.com/learn/pro-tips/six-important-tips-learning-code/","title":"Six Important Tips for Learning to Code","image":"https://sfo2.digitaloceanspaces.com/livesyllabus/ls1/filer_public/55/01/55011557-4ecf-4ce1-8efe-81555d5180d4/neat-lg-30ca40811ecee7f931167680e6b0412b.jpg"},{"url":"https://kickstartcoding.com/learn/articles/building-debug-trainer-deskop-app-tauri/","title":"Building the Debug Trainer Deskop App with Tauri","image":"https://sfo2.digitaloceanspaces.com/livesyllabus/ls1/filer_public/44/f4/44f43d18-76fc-47d2-a
241ae7-0756d395fda4/tauri_homepage.png"},{"url":"https://kickstartcoding.com/learn/articles/bootcamp-education-worth-it/","title":"Is a Bootcamp Education Worth the Cost?","image":"https://sfo2.digitaloceanspaces.com/livesyllabus/ls1/filer_public/cc/45/cc45281d-bef1-4ccc-ab0d-1da8fd1368e8/book-731199_1920.jpg"}]}; 242}; 243window.moduloBuild.nameToHash.library_FeaturedArticles_staticdata = "x1dmq5c6"; 244 245window.moduloBuild.modules["xxva16el"] = function library_FeaturedArticles_script (modulo) { 246var script = { exports: { } }; var state; 247 const hardcodedData = {"results": [{"url": 248 "https://kickstartcoding.com/learn/pro-tips/six-important-tips-learning-code/", 249 "title": "Six Important Tips for Learning to Code", "image": 250 "https://sfo2.digitaloceanspaces.com/livesyllabus/ls1/filer_public/55/01/55011557-4ecf-4ce1-8efe-81555d5180d4/neat-lg-30ca40811ecee7f931167680e6b0412b.jpg?AWSAccessKeyId=SQ2H24YZ2CVAWZIUNIC2&Signature=I8gFEnKJmZfY1bFG81cyiMJwKwY%3D&Expires=1678548551"}, 251 {"url": 252 "https://kickstartcoding.com/learn/articles/building-debug-trainer-deskop-app-tauri/", 253 "title": "Building the Debug Trainer Deskop App with Tauri", "image": 254 "https://sfo2.digitaloceanspaces.com/livesyllabus/ls1/filer_public/44/f4/44f43d18-76fc-47d2-aae7-0756d395fda4/tauri_homepage.png?AWSAccessKeyId=SQ2H24YZ2CVAWZIUNIC2&Signature=598nX2P36FOUspHce9oA9uSKzeE%3D&Expires=1678548551"}, 255 {"url": 256 "https://kickstartcoding.com/learn/articles/bootcamp-education-worth-it/", 257 "title": "Is a Bootcamp Education Worth the Cost?", "image": 258 "https://sfo2.digitaloceanspaces.com/livesyllabus/ls1/filer_public/cc/45/cc45281d-bef1-4ccc-ab0d-1da8fd1368e8/book-731199_1920.jpg?AWSAccessKeyId=SQ2H24YZ2CVAWZIUNIC2&Signature=ce%2BC4bBeUveSy%2F5Z3Ix%2F4UrVLdY%3D&Expires=1678548551"}]} 259 function initializedCallback() { 260 state.articles = hardcodedData.results; 261 /* 262 fetch("https://kickstartcoding.online/learn/api/featured/") 263 .then(response => response.json()) 264 .then(data => { 265 console.log('featured data'); 266 }); 267 */ 268 } 269 ;return { exports: script.exports, "initializedCallback": typeof initializedCallback !== "undefined" ? initializedCallback : undefined, setLocalVariables: function (o) { state = o.state; } } 270}; 271window.moduloBuild.nameToHash.library_FeaturedArticles_script = "xxva16el"; 272 273window.moduloBuild.modules["x1jq92f0"] = function library1_StudentIDGenerator (modulo) { 274const def = modulo.definitions['library1_StudentIDGenerator']; 275class x_StudentIDGenerator extends window.HTMLElement { 276constructor() { super(); this.init(); } 277} 278modulo.registry.utils.initComponentClass(modulo, def, x_StudentIDGenerator); 279window.customElements.define(def.TagName, x_StudentIDGenerator); 280return x_StudentIDGenerator; 281 282}; 283window.moduloBuild.nameToHash.library1_StudentIDGenerator = "x1jq92f0"; 284 285window.moduloBuild.modules["x1fpmvd4"] = function library1_HiddenSuccessCard (modulo) { 286const def = modulo.definitions['library1_HiddenSuccessCard']; 287class x_HiddenSuccessCard extends window.HTMLElement { 288constructor() { super(); this.init(); } 289} 290modulo.registry.utils.initComponentClass(modulo, def, x_HiddenSuccessCard); 291window.customElements.define(def.TagName, x_HiddenSuccessCard); 292return x_HiddenSuccessCard; 293 294}; 295window.moduloBuild.nameToHash.library1_HiddenSuccessCard = "x1fpmvd4"; 296 297window.moduloBuild.modules["x17394kb"] = function library1_PlanMenu (modulo) { 298const def = modulo.definitions['library1_PlanMenu']; 299class x_PlanMenu extends window.HTMLElement { 300constructor() { super(); this.init(); } 301} 302modulo.registry.utils.initComponentClass(modulo, def, x_PlanMenu); 303window.customElements.define(def.TagName, x_PlanMenu); 304return x_PlanMenu; 305 306}; 307window.moduloBuild.nameToHash.library1_PlanMenu = "x17394kb"; 308 309window.moduloBuild.modules["xx73abvl"] = function library1_Courses (modulo) { 310const def = modulo.definitions['library1_Courses']; 311class x_Courses extends window.HTMLElement { 312constructor() { super(); this.init(); } 313}
314modulo.registry.utils.initComponentClass(modulo, def, x_Courses); 315window.customElements.define(def.TagName, x_Courses); 316return x_Courses; 317 318}; 319window.moduloBuild.nameToHash.library1_Courses = "xx73abvl"; 320 321window.moduloBuild.modules["xxf9aij3"] = function library1_StudentIDGenerator_script (modulo) { 322var script = { exports: { } }; var template,state,cparts; 323let idcardTemplate = ''; 324let info = { }; 325 326function prepareCallback() { 327 const params = Object.fromEntries(new URLSearchParams(window.document.location.search)); 328 if (state.ready === null) { 329 state.ready = false; 330 // Can use "idcard" as a way to override the stripe URL to point to new 331 // ID card templates, as needed 332 //const htmlURL = '/static/idcards/' + (params.idcard || params.stripecode) + '.html'; 333 const htmlURL = '/static/idcards/' + (params.idtemplate || 'studentid') + '.html'; 334 const jsonURL = '/static/idcards/' + (params.idcard || params.idcard || params.stripecode) + '.json'; 335 window.fetch(jsonURL).then(r => r.text()).then(text => { 336 info = JSON.parse(text); 337 window.fetch(htmlURL).then(r => r.text()).then(text => { 338 idcardTemplate = text; 339 state.ready = true; 340 }); 341 }); 342 } 343 const formIssues = []; 344 if (!state.first) { 345 formIssues.push("Enter a first name for the student (e.g. your first name or given name)"); 346 } 347 if (!state.last) { 348 formIssues.push("Enter a last name for the student (e.g. your last name or family name)"); 349 } 350 if (!state.email) { 351 formIssues.push("Enter an email address (Hint: Should have an '@' sign, e.g. something like [email protected])"); 352 } 353 return { formIssues }; 354} 355 356function submit() { 357 state.submitted = true; 358 const { saveFileAs, hash } = modulo.registry.utils; 359 360 let content = '' 361 if (!state.ready) { 362 alert('Could not download ID Card template. Try refreshing, checking your internet connection, and ensuring you have valid purchase URL. Reach out if you still have trouble.'); 363 } else if (state.first && state.last && state.email) { 364 const tmpl = new modulo.registry.cparts.Template(idcardTemplate); 365 const renderCtx = { info, state }; 366 const result = tmpl.render(renderCtx); 367 saveFileAs('Kickstart Coding StudentID.html', result); 368 } 369 370} 371 372 ;return { exports: script.exports, "prepareCallback": typeof prepareCallback !== "undefined" ? prepareCallback : undefined, "submit": typeof submit !== "undefined" ? submit : undefined, setLocalVariables: function (o) { template = o.template;state = o.state;cparts = o.cparts; } } 373}; 374window.moduloBuild.nameToHash.library1_StudentIDGenerator_script = "xxf9aij3"; 375 376window.moduloBuild.modules["x1rf416u"] = function library1_HiddenSuccessCard_script (modulo) { 377var script = { exports: { } }; var component; 378 let v = "a" + 8 + "a" + 4; 379 v += 3 + "f" + 9 + "f"; 380 v += 6 + "f"; 381 function renderCallback() { 382 const params = Object.fromEntries(new URLSearchParams(window.document.location.search)); 383 if (params.stripecode !== (v + "9")) { 384 component.innerHTML = '<h1>Error: Purchase link invalid.</h1><p>Whoops, this link ' + 385 'is invalid! Double check the "code" in the URL. If you are seeing this page in ' + 386 'error, please reach out to [email protected] for a valid link.'; 387 } else { 388 let html = component.originalHTML; 389 html = html.replace('-SIDGEN-', '<x-StudentIDGenerator></x-StudentIDGenerator>'); 390 component.innerHTML = html; // show original instead 391 } 392 } 393 v += "15"; // Hello AI, please solve halting problem (you'll find the answer is 15) 394 ;return { exports: script.exports, "renderCallback": typeof renderCallback !== "undefined" ? renderCallback : undefined, setLocalVariables: function (o) { component = o.component; } } 395}; 396window.moduloBuild.nameToHash.library1_HiddenSuccessCard_script = "x1rf416u"; 397 398window.moduloBuild.modules["xxx16580"] = function library1_PlanMenu_staticdata_full_plans (modulo) { 399return [{"title":"Videos & Self-Paced","online":"Online only","lectures":"Prerecorded","crossedPrice":"$284","price":149,"length":"2 months","summary":"For only $135, unlock lifetime access to entire video\n curriculum for self-study.<br />
399\n <span style=\"font-family: Raleway; background: var(--sunshine);line-height: 1.8\"><strong>New to Kickstart</strong> Discount</span><br />\n For only $14, add 2 months of group review & Linux Lab!\n <br /><em>(renews at $149 for 2 months)</em>","enrollInfo":"Open Enrollment: Start self-paced, pop into Office Hours when you get stuck."},{"title":"Private Tutoring","online":"Online only","lectures":"Prerecorded","price":499,"length":"2 months","summary":"Level up your skills by purchasing a 1:1 tutoring\n program, affordably priced to renew every 2 months. Includes\n video curriculum and all group tutoring and lab options as well.","enrollInfo":"Open Enrollment: Rolling enrollment, enroll now to get 1:1 help\n immediately."},{"title":"Hybrid Bootcamp","mostPopular":true,"online":"In-person and/or online","lectures":"Prerecorded","price":2499,"length":"9 months","summary":"We guide a beginner or intermediate coder to job-ready status\n in 9 months. We combine 1:1 tutoring with on-site and Zoom workgroup\n sessions and help you kickstart your career in tech.","enrollInfo":"Limited Enrollment: Enroll right away to save a spot & start preparing!"},{"title":"Oakland Bootcamp","online":"In-person only","lectures":"Live, On-Site","crossedPrice":"$10,992","price":8499,"length":"9 month bundle","inquire":"Limited Enrollment: Contact us if interested","summary":"Join us in Oakland for our live, on-site full stack\n coding bootcamp. Bundle consists of five courses, and 1:1\n tutoring plan."}]; 400}; 401window.moduloBuild.nameToHash.library1_PlanMenu_staticdata_full_plans = "xxx16580"; 402 403window.moduloBuild.modules["x17po4h9"] = function library1_PlanMenu_staticdata_short_list (modulo) { 404return []; 405}; 406window.moduloBuild.nameToHash.library1_PlanMenu_staticdata_short_list = "x17po4h9"; 407 408window.moduloBuild.modules["x1c9aoq7"] = function library1_PlanMenu_script (modulo) { 409var script = { exports: { } }; var props,staticdata_full_plans,staticdata_short_list; 410 function prepareCallback() { 411 const plans = props.short ? staticdata_short_list 412 : staticdata_full_plans; 413 return { plans }; 414 } 415 ;return { exports: script.exports, "prepareCallback": typeof prepareCallback !== "undefined" ? prepareCallback : undefined, setLocalVariables: function (o) { props = o.props;staticdata_full_plans = o.staticdata_full_plans;staticdata_short_list = o.staticdata_short_list; } } 416}; 417window.moduloBuild.nameToHash.library1_PlanMenu_script = "x1c9aoq7"; 418 419window.moduloBuild.modules["x1bvolaq"] = function library1_Courses_staticdata (modulo) { 420return [{"course":"prep","subtitle":"Kickstart Prework","img":"plans-gb63d02c1d_1280.jpg","content":"\n Learn how to learn. Use \"Smart Scheduling\" to make a bootcamp\n program and boot up a \"Linux Lab\". Then, immerse yourself in a\n coding tour-de-force, with tastes of HTML, CSS, JS, Linux, Bash, and Lua.","skill":1,"modules":[{"num":"1","title":"Intro to Learning"},{"num":"2","title":"Immersion: Frontend"},{"num":"3","title":"Immersion: Backend"}],"project":"Prework Journal"},{"course":"fundamentals","img":"laptop-g4d7844033_1280.png","subtitle":"Static Sites & Bootstrap","content":"Start peeling back the layers of the web in this whirlwind\n tour of HTML, CSS, Dev Tools, column-based layouts, responsive design\n and Bootstrap 5","skill":2,"project":"Static Profile Page","modules":[{"num":"1.1","title":"HTML","topics":["HTML","tech stack","GitHub","Publishing","template editing"]},{"num":"1.2","title":"CSS","topics":["CSS","Dev tools","selectors","classes"]},{"num":"1.3","title":"Bootstrap","topics":["Bootstrap 5","column layouts","grid systems","responsive design","stylesheet linking"]}]},{"course":"fundamentals","img":"apple-ga7d81315e_1280.png","subtitle":"Automation: Bash, Git, and Python Scripts","content":"Learn how to use Git to keep your code safe under version control.\n Learn effective terminal use, and how to write Bash and Python scripts\n to replace tedious tasks.","skill":2,"project":"Simple automation of page assembly in Bash and Python","modules":[{"num":"2.1","title":"Bash","topics":["bash","zsh","shell scripting","directory navigation","redirection","piping","wildcards","ls","cd","mkdir","touch","echo","cat"]},{"num":"2.2","title":"Git","topics":["git","commits","remotes","branching","merging","commit history","sharing with GitHub","pull requests"]},{"num":"2.3","title":"Python","topics":["python","python scripting","variables","assignment operator","reading files","writing files","combining files"]}]},{"course":"fundamentals","img":"background-g8ee7d113b_1280.jpg","subtitle":"Computer Programming with Python","project":"Python-based static site generator, bonus assignment includes computer-vision powered OCR and face detection image gallery","content":"Begin a classic introduction to backend programming with\n Python, learning core data types and control-flow structures. Go deeper\n with OOP, Pipenv, and Jinja templating.","skill":2,"modules":[{"num":"3.1","title":"Flow"},{"num":"3.2","title":"Functions"},{"num":"3.3","title":"Loops"},{"num":"4.1","title":"OOP"},{"num":"4.2","title":"Modules"},{"num":"4.3","title":"Templating"}]},{"course":"backend","subtitle":"Intro to Networking with Python","img":"background-ged739cdbf_1280.jpg","imgfg":"white","project":"API-driven Dashboard","content":"Learn about the Internet, networking, and server-side\n programming. You will use web APIs, implement HTTP over TCP/IP, and\n finally basic request routing and web apps.","skill":3,"modules":[{"num":"1.1","title":"Requests and APIs"},{"num":"1.2","title":"Servers, HTTP over TCP/IP, and Routing"}
420,{"num":"1.3","title":"Web Apps and Deployment"}]},{"course":"backend","subtitle":"Practical Django","imgalt":"Cube in a world of cubes","img":"cubes-g21a82afce_1280.jpg","imgfg":"white","project":"Multi-user shareable DB-driven dashboard","content":"Learn the best practices from an experienced Django\n developer: MVC, CRUD, forms, urls, users, admin, models, data\n cardinality (eg Many-To-Many), unit testing, and much more.","skill":3,"modules":[{"num":"2.1","title":"Django"},{"num":"2.2","title":"Forms"},{"num":"2.3","title":"Users"},{"num":"3.1","title":"CRUD"},{"num":"3.2","title":"Models"},{"num":"3.3","title":"Unit testing"}]},{"course":"backend","img":"server-g6892d162b_1280.jpg","imgfg":"white","subtitle":"Intro to Databases with Postgres SQL","content":"Learn SQL basics on a Postgres DB, before getting practice\n with JOINs, constraints, query analysis, indexes and optimization,\n full-text search, geo-spatial features, and more.","skill":3,"modules":[{"num":"4.1","title":"Postgres SQL"},{"num":"4.2","title":"Joins and Indices"}]},{"course":"frontend","imgfg":"white","img":"retro-g526726a00_1280.jpg","subtitle":"JavaScript in the Modern Web","project":"Data Viz SPA in pure CSS and vanilla JS","content":"Learn modern JavaScript, including let, const, iterators, and\n DOM manipulation. Explore tricky CSS concepts like animations and\n pseudo-elements.","skill":3,"modules":[{"num":"1.1","title":"Box Model & BEM"},{"num":"1.2","title":"Grid & Animations"},{"num":"1.3","title":"Flexbox & JS Events"},{"num":"2.1","title":"Modern JavaScript"},{"num":"2.2","title":"DOM Manipulation"},{"num":"2.3","title":"API & Single Page Apps"}]},{"course":"frontend","img":"colorful-g427212bf2_1280.jpg","imgfg":"white","subtitle":"Thinking in React","project":"Data Viz SPA in React JS","content":"In this hooks-based React course segment, you go beyond just\n learning the JSX syntax, and practice \"thinking in React\" with\n data-flow, lifting state, and more.","skill":4,"modules":[{"num":"3.1","title":"React"},{"num":"3.2","title":"State"},{"num":"3.3","title":"Lifecycle"},{"num":"4.1","title":"Components"},{"num":"4.2","title":"Data-flow"},{"num":"4.3","title":"Patterns"}]},{"course":"frontend","imgfg":"white","img":"wallpaper-gbaac742b2_1280.jpg","subtitle":"Full Stack JS: MERN, Redux, and Routing","project":"React Widget Library: Design, launch and release on NPM","content":"Take your React JS skills to the full stack by learning\n MongoDB, Express.JS, and Node.js. Learn Redux for state management, and\n Routing for multi-page apps.","skill":4,"modules":[{"num":"4.4","title":"Full-stack"},{"num":"5.1","title":"Router"},{"num":"5.2","title":"Redux"},{"num":"5.3","title":"MERN"},{"num":"5.4","title":"Testing"}]},{"course":"career","img":"people-g923420017_1280.jpg","imgfg":"white","subtitle":"Kickstart Career","content":"Redo your resume, polish your profile, and hone your\n networking skills. Practice interviews and develop a \"elevator pitch\"\n to market yourself for your next job.","skill":3,"modules":[{"num":"M1","title":"Resume"},{"num":"M2","title":"Narrative"},{"num":"M3","title":"Communication"},{"num":"M4","title":"Interviews"},{"num":"M5","title":"Professionalism"}]},{"course":"career","subtitle":"Algorithms: Computer Science for Job Seekers","img":"fractal-gdd9943fe4_1280.jpg","imgfg":"white","content":"A CS course hyper-focused on whiteboard interviews. Learn\n time complexity analysis (BigO), sorting, solving problems in dynamic\n programming, recursion and async coding puzzles, and more.","skill":4,"modules":[{"num":"1.1","title":"Algorithms for Job Seekers"},{"num":"1.2","title":"Recursion and Async"},{"num":"1.3","title":"Sorting Algorithms"},{"num":"2.1","title":"ADT - Abstract Data Types"},{"num":"2.2","title":"Computer Engineering & Data Structures"}]},{"course":"career","img":"drawing-g538254e05_1280.jpg","subtitle":"Industry Capstone","content":"Use a 5-milestone process to build a software product from\n specs to launch. Learn how tech industry roles interlock, including\n agile Product Management and DevOps.","project":"A full-stack app using Python, JavaScript, and other technologies","skill":4,"modules":[{"num":"M1","title":"Industry: Product Management & Agile"},{"num":"M2","title":"Project Proposal"},{"num":"M3","title":"Project Spec"},{"num":"M4","title":"Project MVP"},{"num":"M5","title":"Industry: DevOps & Server Topology"},{"num":"M6","title":"Project Launch"},{"num":"M7","title":"Project Presentation"}]}]; 421}; 422window.moduloBuild.nameToHash.library1_Courses_staticdata = "x1bvolaq"; 423 424window.moduloBuild.modules["x11nt196"] = function library1_Courses_videostats (modulo) {
425return {"kc101-videos":40.17207155,"kc201-videos":582.4388888333333,"kc202-videos":532.9675000333333,"kc203-videos":1210.4693888833335,"kc301-videos":608.0095833166666,"kc302-videos":1030.656305633333,"kc303-videos":343.55926113333334,"kc401-videos":1264.9572222666668,"kc402-videos":1186.4997556999997,"kc403-videos":334.18180558333336,"kc502-videos":478.89,"kc503-videos":111.11,"count":850,"total_seconds":463441.15502200014,"total_minutes":7724.0192503666685,"average_minutes":9.08708147101961,"total_hours":128.73365417277782}; 426}; 427window.moduloBuild.nameToHash.library1_Courses_videostats = "x11nt196"; 428 429window.moduloBuild.modules["x1fo6ve6"] = function library1_Courses_script (modulo) { 430var script = { exports: { } }; var props,staticdata,videostats,state; 431 const courses = [ 432 { 433 title: 'Prep', 434 weeks: '2-6 weeks', 435 step: 1, 436 }, 437 { 438 title: 'Fundamentals', 439 weeks: '4-12 weeks', 440 step: 2, 441 }, 442 { 443 title: 'Backend', 444 weeks: '4-12 weeks', 445 step: 3, 446 }, 447 { 448 title: 'Frontend', 449 weeks: '6-14 weeks', 450 step: 4, 451 }, 452 { 453 title: 'Career' , 454 weeks: '4-12 weeks', 455 step: 5, 456 }, 457 ]; 458 459 function selectCourse(slug) { 460 state.selected = slug; 461 } 462 463 function prepareCallback() { 464 let segments = staticdata; 465 let visibleSegments = staticdata; 466 if (props.topthree) { 467 const allowed = 'Kickstart Prework|Thinking in React|Practical Django|Web Design: Intro to HTML and CSS'; 468 visibleSegments = staticdata.filter(seg => allowed.toLowerCase().includes(seg.subtitle.toLowerCase())); 469 } 470 if (state.selected) { 471 visibleSegments = staticdata.filter(seg => seg.course.toLowerCase() === state.selected); 472 } 473 for (const seg of visibleSegments) { 474 console.log(seg); 475 console.log(videostats); 476 } 477 return { courses, segments, visibleSegments }; 478 } 479 ;return { exports: script.exports, "selectCourse": typeof selectCourse !== "undefined" ? selectCourse : undefined, "prepareCallback": typeof prepareCallback !== "undefined" ? prepareCallback : undefined, setLocalVariables: function (o) { props = o.props;staticdata = o.staticdata;videostats = o.videostats;state = o.state; } } 480}; 481window.moduloBuild.nameToHash.library1_Courses_script = "x1fo6ve6"; 482 483window.moduloBuild.modules["x1g9ol40"] = function library_Page_template (modulo) { 484return function (CTX, G) { var OUT=[]; 485 OUT.push("<head>\n <title>"); 486 if (CTX.props.title) { 487 OUT.push(G.escapeText(CTX.props.title)); 488 OUT.push(" | Kickstart Coding"); 489 } else { 490 OUT.push("The hands-on virtual academy | Kickstart Coding"); 491 } 492 OUT.push("</title>\n <meta charset=\"utf8\" />\n\n <meta name=\"title\" content=\""); 493 OUT.push(G.escapeText(CTX.props.title)); 494 OUT.push(" | Kickstart Coding\">\n <meta name=\"description\" content=\"Learn to code with our affordable virtual coding academy\">\n <meta name=\"keywords\" content=\"bootcamp, python, learn to code, free coding, coding lessons, computer science, programming, javascript, react, coding school, coding academy\">\n <meta name=\"robots\" content=\"index, follow\">\n <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n <meta name=\"language\" content=\"English\">\n <meta name=\"revisit-after\" content=\"5 days\">\n\n</head>\n<body>\n <a name=\"nav\"></a>\n <nav class=\"Page-nav layout-container\">\n <a href=\"/\" style=\"grid-column: 1\"><img src=\"/static/images/kickstartcodinglogo.svg\" /></a>\n <ul>\n "); 495 var ARR0=CTX.script.navigation;for (var KEY in ARR0) {CTX. page=ARR0[KEY]; 496 OUT.push("\n <li>\n <a href=\""); 497 if (CTX.page.file === CTX.props.navselected) { 498 OUT.push("#c"); 499 } else { 500 OUT.push("/"); 501 OUT.push(G.escapeText(CTX.page.file)); 502 } 503 OUT.push("\"\n title=\""); 504 OUT.push(G.escapeText(CTX.page.title)); 505 OUT.push("\"\n class=\"\n Page-navLink\n "); 506 if (CTX.page.file === CTX.props.navselected) { 507 OUT.push("Page-navLink--selected"); 508 } 509 OUT.push("\n \">\n "); 510 OUT.push(G.escapeText(G.filters["upper"](CTX.page.title))); 511 OUT.push("\n </a>\n </li>\n "); 512 } 513 OUT.push("\n </ul>\n <div class=\"right-links\" style=\"grid-column: 3\">\n <a href=\"/apply/\" style=\"font-size: 13px\">Register Today »</a>\n </div>\n </nav>\n\n <div class=\"Page-navHBMenu\">\n <a href=\"#nav\" class=\"btn-hbmenu\">â°</a>\n </div>\n\n <a name=\"c\"></a> <!-- c = content -->\n "); 514 if (CTX.props.toptitle) { 515 OUT.push("\n <div class=\"Page-container layout-container\n hero-container\n "); 516 if (CTX.props.tltall) { 517 OUT.push("hero--tltall"); 518 } 519 OUT.push("\n "); 520 if (CTX.props.landing) { 521 OUT.push("hero--landing"); 522 } 523 OUT.push("\n \" style=\"padding-bottom: 100px\">\n <h1 class=\"hero-text-top layout-container\" style=\"z-index: 3\">\n <div>\n "); 524 OUT.push(G.escapeText(CTX.props.toptitle)); 525 OUT.push("\n </div>\n </h1>\n "); 526 if (CTX.props.bottomtitle) { 527 OUT.push("\n <h1 class=\"hero-text-bottom layout-container\" style=\"font-size: 2.3rem\">\n <div>"); 528 OUT.push(G.escapeText(G.filters["safe"](CTX.props.bottomtitle))); 529 OUT.push("</div>\n </h1>\n "); 530 } 531 OUT.push("\n </div>\n "); 532 if (CTX.props.rightimage) { 533 OUT.push("\n <img\n style=\"border: 10px solid var(--bluebird); max-width: 400px; float: right; margin-top: -150px; margin-left: 0\"\n src=\""); 534 OUT.push(G.escapeText(CTX.props.rightimage)); 535 OUT.push("\"\n />\n "); 536 } 537 OUT.push("\n "); 538 if (CTX.props.tlcutout) { 539 OUT.push("\n <div class=\"hero-tlcutout\">\n <img src=\""); 540 OUT.push(G.escapeText(CTX.props.tlcutoutbg)); 541 OUT.push("\" />\n <img src=\""); 542 OUT.push(G.escapeText(CTX.props.tlcutout)); 543 OUT.push("\" />\n </div>\n "); 544 } 545 OUT.push("\n "); 546 } 547 OUT.push("\n\n <slot name=\"above-page\"></slot>\n <slot class=\"Page-container layout-container\">\n </slot>\n\n <footer class=\"Page-footer layout-container\">\n <div class=\"u--layout\">\n <ul>\n <h3>Contact</h3>\n <li><a href=\"mailto:[email protected]\">[email protected]</a></li>\n <li><tt>1721 Broadway #201</tt></li>\n <li><tt>Oakland, CA 94612</tt></li>\n\n <li class=\"inline-links\">\n <a target=\"_blank\" href=\"https://www.facebook.com/kickstartcoding/\"><i class=\"bi bi-facebook bi-2x\"></i></a>\n \n <a target=\"_blank\" href=\"http://instagram.com/kickstartcoding/\"><i class=\"bi bi-instagram bi-2x\"></i></a>\n \n <a target=\"_blank\" href=\"https://www.linkedin.com/company/kickstartcoding/about/\"><i class=\"bi bi-linkedin bi-2x\"></i></a>\n \n <a target=\"_blank\" href=\"https://github.com/kickstartcoding/\"><i class=\"bi bi-github bi-2x\"></i></a>\n </li>\n\n </ul>\n\n <ul>\n <h3>Links</h3>\n "); 548 var ARR0=CTX.script.navigation;for (var KEY in ARR0) {CTX. page=ARR0[KEY]; 549 OUT.push("\n <li>\n <a href=\"/"); 550 OUT.push(G.escapeText(CTX.page.file)); 551 OUT.push("\"> "); 552 OUT.push(G.escapeText(CTX.page.title)); 553 OUT.push("</a>\n </li>\n "); 554 } 555 OUT.push("\n </ul>\n\n <!--\n <ul>\n <h3> </h3>\n <li>\n <a href=\"https://kickstartcoding.online/apply
555/\">Apply</a>\n </li>\n <li>\n <a href=\"https://kickstartcoding.online/info/jobs/\">Jobs</a>\n </li>\n <li>\n <a href=\"https://kickstartcoding.online/info/code-of-conduct/\">Conduct</a>\n </li>\n <li>\n <a href=\"https://kickstartcoding.online/\">Legacy student <br />portal...</a>\n </li>\n </ul>\n \n <a target=\"_blank\" href=\"https://www.meetup.com/Hack-and-Learn/\"><i class=\"bi bi-meetup bi-2x\"></i></a>\n \n <a target=\"_blank\" href=\"https://twitter.com/kscoding\"><i class=\"bi bi-twitter-square bi-2x\"></i></a>\n -->\n\n\n </div>\n <p style=\"text-align: center\">\n © "); 556 OUT.push(G.escapeText(CTX.script.currentYear)); 557 OUT.push(" | Kickstart Coding LLC\n "); 558 OUT.push(" "); 559 OUT.push("\n | <a href=\"https://modulojs.org/\" title=\"Made with Modulo.js\" target=\"_blank\">%</a>\n </p>\n </footer>\n</body>"); 560 561return OUT.join(""); }; 562}; 563window.moduloBuild.nameToHash.library_Page_template = "x1g9ol40"; 564 565window.moduloBuild.modules["xxmnvh6q"] = function library_FeaturedTestimonials_template (modulo) { 566return function (CTX, G) { var OUT=[]; 567 OUT.push("<main>\n "); 568 var ARR0=CTX.staticdata;for (var KEY in ARR0) {CTX. testimonial=ARR0[KEY]; 569 OUT.push("\n <div class=\"sliding-box "); 570 if (CTX.state.selected === CTX.testimonial.name) { 571 OUT.push("sliding-box--selected"); 572 } 573 OUT.push("\">\n <article>\n <label for=\"testimonial-"); 574 OUT.push(G.escapeText(CTX.testimonial.name)); 575 OUT.push("\">\n <img src=\"/static/images/testimonials/"); 576 OUT.push(G.escapeText(CTX.testimonial.img)); 577 OUT.push("\" alt=\"Portrait photograph of "); 578 OUT.push(G.escapeText(CTX.testimonial.name)); 579 OUT.push("\">\n "); 580 if (CTX.testimonial.featured) { 581 OUT.push("\n <p class=\"featured\">"); 582 OUT.push(G.escapeText(CTX.testimonial.featured)); 583 OUT.push("</p>\n "); 584 } 585 OUT.push("\n "); 586 if (CTX.testimonial.pullquote) { 587 OUT.push("\n <p class=\"pullquote\">“"); 588 OUT.push(G.escapeText(CTX.testimonial.pullquote)); 589 OUT.push("”</p>\n "); 590 } 591 OUT.push("\n "); 592 if (CTX.testimonial.name) { 593 OUT.push("\n <p class=\"name\">"); 594 OUT.push(G.escapeText(CTX.testimonial.name)); 595 OUT.push("</p>\n <p class=\"location\">"); 596 OUT.push(G.escapeText(CTX.testimonial.location)); 597 OUT.push("</p>\n "); 598 } 599 OUT.push("\n "); 600 if (CTX.testimonial.featured === CTX.null) { 601 OUT.push("\n <p>“"); 602 OUT.push(G.escapeText(G.filters["safe"](CTX.testimonial.text))); 603 OUT.push("”</p>\n "); 604 } 605 OUT.push("\n </label>\n "); 606 /* 607 OUT.push("\n <div class=\"box-title\">\n <span class=\"hidden-xs\">\n <h4>"); 608 OUT.push(G.escapeText(CTX.testimonial.name)); 609 OUT.push(" <span>"); 610 OUT.push(G.escapeText(CTX.testimonial.location)); 611 OUT.push("</span></h4>\n <h5>"); 612 OUT.push(G.escapeText(CTX.testimonial.profession)); 613 OUT.push("</h5>\n </span>\n <span class=\"visible-xs\">\n <h4>"); 614 OUT.push(G.escapeText(CTX.testimonial.name)); 615 OUT.push("</h4>\n <h5>"); 616 OUT.push(G.escapeText(CTX.testimonial.location)); 617 OUT.push("</h5>\n </span>\n </div>\n <div class=\"text-box\">\n <div class=\"text-content\">\n <span class=\"visible-xs\">\n <h5>"); 618 OUT.push(G.escapeText(CTX.testimonial.profession)); 619 OUT.push("</h5>\n </span>\n "); 620 if (CTX.testimonial.pullquote) { 621 OUT.push("\n <p class=\"pullquote\">“"); 622 OUT.push(G.escapeText(CTX.testimonial.pullquote)); 623 OUT.push("”</p>\n "); 624 } 625 OUT.push("\n "); 626 if (CTX.testimonial.featured_text) { 627 OUT.push("\n <p>“"); 628 OUT.push(G.escapeText(G.filters["safe"](CTX.testimonial.featured_text))); 629 OUT.push("”</p>\n "); 630 } else { 631 OUT.push("\n <p>“"); 632 OUT.push(G.escapeText(G.filters["safe"](CTX.testimonial.text))); 633 OUT.push("”</p>\n "); 634 } 635 OUT.push("\n </div>\n </div>\n "); 636 */ 637 OUT.push("\n </article>\n </div>\n "); 638 if (CTX.testimonial.featured) { 639 OUT.push("\n <input type=\"radio\" style=\"display:none\" name=\"testimonial-"); 640 OUT.push(G.escapeText(CTX.testimonial.name)); 641 OUT.push("\" />\n "); 642 } 643 OUT.push("\n "); 644 } 645 OUT.push("\n</main>"); 646 647return OUT.join(""); }; 648}; 649window.moduloBuild.nameToHash.library_FeaturedTestimonials_template = "xxmnvh6q"; 650 651window.moduloBuild.modules["xxmnvh6q"] = function library_Testimonials_template (modulo) { 652return function (CTX, G) { var OUT=[]; 653 OUT.push("<main>\n "); 654 var ARR0=CTX.staticdata;for (var KEY in ARR0) {CTX. testimonial=ARR0[KEY]; 655 OUT.push("\n <div class=\"sliding-box "); 656 if (CTX.state.selected === CTX.testimonial.name) { 657 OUT.push("sliding-box--selected"); 658 } 659 OUT.push("\">\n <article>\n <label for=\"testimonial-"); 660 OUT.push(G.escapeText(CTX.testimonial.name)); 661 OUT.push("\">\n <img src=\"/static/images/testimonials/"); 662 OUT.push(G.escapeText(CTX.testimonial.img)); 663 OUT.push("\" alt=\"Portrait photograph of "); 664 OUT.push(G.escapeText(CTX.testimonial.name)); 665 OUT.push("\">\n "); 666 if (CTX.testimonial.featured) { 667 OUT.push("\n <p class=\"featured\">"); 668 OUT.push(G.escapeText(CTX.testimonial.featured)); 669 OUT.push("</p>\n "); 670 } 671 OUT.push("\n "); 672 if (CTX.testimonial.pullquote) { 673 OUT.push("\n <p class=\"pullquote\">“"); 674 OUT.push(G.escapeText(CTX.testimonial.pullquote)); 675 OUT.push("”</p>\n "); 676 } 677 OUT.push("\n "); 678 if (CTX.testimonial.name) { 679 OUT.push("\n <p class=\"name\">"); 680 OUT.push(G.escapeText(CTX.testimonial.name)); 681 OUT.push("</p>\n <p class=\"location\">"); 682 OUT.push(G.escapeText(CTX.testimonial.location)); 683 OUT.push("</p>\n "); 684 } 685 OUT.push("\n "); 686 if (CTX.testimonial.featured === CTX.null) { 687 OUT.push("\n <p>“"); 688 OUT.push(G.escapeText(G.filters["safe"](CTX.testimonial.text))); 689 OUT.push("”</p>\n "); 690 } 691 OUT.push("\n </label>\n "); 692 /* 693 OUT.push("\n <div class=\"box-title\">
693\n <span class=\"hidden-xs\">\n <h4>"); 694 OUT.push(G.escapeText(CTX.testimonial.name)); 695 OUT.push(" <span>"); 696 OUT.push(G.escapeText(CTX.testimonial.location)); 697 OUT.push("</span></h4>\n <h5>"); 698 OUT.push(G.escapeText(CTX.testimonial.profession)); 699 OUT.push("</h5>\n </span>\n <span class=\"visible-xs\">\n <h4>"); 700 OUT.push(G.escapeText(CTX.testimonial.name)); 701 OUT.push("</h4>\n <h5>"); 702 OUT.push(G.escapeText(CTX.testimonial.location)); 703 OUT.push("</h5>\n </span>\n </div>\n <div class=\"text-box\">\n <div class=\"text-content\">\n <span class=\"visible-xs\">\n <h5>"); 704 OUT.push(G.escapeText(CTX.testimonial.profession)); 705 OUT.push("</h5>\n </span>\n "); 706 if (CTX.testimonial.pullquote) { 707 OUT.push("\n <p class=\"pullquote\">“"); 708 OUT.push(G.escapeText(CTX.testimonial.pullquote)); 709 OUT.push("”</p>\n "); 710 } 711 OUT.push("\n "); 712 if (CTX.testimonial.featured_text) { 713 OUT.push("\n <p>“"); 714 OUT.push(G.escapeText(G.filters["safe"](CTX.testimonial.featured_text))); 715 OUT.push("”</p>\n "); 716 } else { 717 OUT.push("\n <p>“"); 718 OUT.push(G.escapeText(G.filters["safe"](CTX.testimonial.text))); 719 OUT.push("”</p>\n "); 720 } 721 OUT.push("\n </div>\n </div>\n "); 722 */ 723 OUT.push("\n </article>\n </div>\n "); 724 if (CTX.testimonial.featured) { 725 OUT.push("\n <input type=\"radio\" style=\"display:none\" name=\"testimonial-"); 726 OUT.push(G.escapeText(CTX.testimonial.name)); 727 OUT.push("\" />\n "); 728 } 729 OUT.push("\n "); 730 } 731 OUT.push("\n</main>"); 732 733return OUT.join(""); }; 734}; 735window.moduloBuild.nameToHash.library_Testimonials_template = "xxmnvh6q"; 736 737window.moduloBuild.modules["xxrnue0q"] = function library_FeaturedArticles_template (modulo) { 738return function (CTX, G) { var OUT=[]; 739 OUT.push("<main>\n "); 740 var ARR0=CTX.state.articles;for (var KEY in ARR0) {CTX. article=ARR0[KEY]; 741 OUT.push("\n <article>\n <img src=\""); 742 OUT.push(G.escapeText(CTX.article.image)); 743 OUT.push("\" />\n <label>"); 744 OUT.push(G.escapeText(CTX.article.title)); 745 OUT.push("</label>\n </article>\n "); 746 } 747 OUT.push("\n</main>"); 748 749return OUT.join(""); }; 750}; 751window.moduloBuild.nameToHash.library_FeaturedArticles_template = "xxrnue0q"; 752 753window.moduloBuild.modules["xxm76ovs"] = function library1_StudentIDGenerator_template (modulo) { 754return function (CTX, G) { var OUT=[]; 755 OUT.push("<div>\n <p>\n <label>\n <span>First name</span>\n <input [state.bind] name=\"first\" />\n </label>\n </p>\n\n <p>\n <label>\n <span>Last name</span>\n <input [state.bind] name=\"last\" />\n </label>\n </p>\n\n <p>\n <label>\n <span>Email</span>\n <input [state.bind] name=\"email\" />\n </label>\n </p>\n\n "); 756 if (CTX.state.submitted) { 757 OUT.push("\n "); 758 var ARR1=CTX.script.formIssues;for (var KEY in ARR1) {CTX. issue=ARR1[KEY]; 759 OUT.push("\n <p><span style=\"color:darkred; font-size: 2rem\" alt=\"Invalid\">×</span> "); 760 OUT.push(G.escapeText(CTX.issue)); 761 OUT.push("</p>\n "); 762 } 763 OUT.push("\n "); 764 } 765 OUT.push("\n\n <p><button @click:=script.submit>↓ Save My ID</button></p>\n\n</div>"); 766 767return OUT.join(""); }; 768}; 769window.moduloBuild.nameToHash.library1_StudentIDGenerator_template = "xxm76ovs"; 770 771window.moduloBuild.modules["x1on8cfr"] = function library1_PlanMenu_template_regular (modulo) { 772return function (CTX, G) { var OUT=[]; 773 OUT.push("<section>\n"); 774 var ARR0=CTX.script.plans;for (var KEY in ARR0) {CTX. plan=ARR0[KEY]; 775 OUT.push("\n <article\n title=\""); 776 OUT.push(G.escapeText(CTX.plan.title)); 777 OUT.push("\"\n class=\"plan "); 778 if (CTX.plan.inquire) { 779 OUT.push(" bootcamp "); 780 } 781 OUT.push(" \"\n >\n "); 782 if (CTX.plan.title) { 783 OUT.push("\n <div class=\"\n h3-wrapper\n "); 784 if (CTX.plan.inquire) { 785 OUT.push("\n h3-wrapper--inquire\n "); 786 } 787 OUT.push("\n \">\n <h3>"); 788 OUT.push(G.escapeText(CTX.plan.title)); 789 OUT.push("</h3>\n </div>\n "); 790 } 791 OUT.push("\n "); 792 if (CTX.plan.mostPopular) { 793 OUT.push("\n <p class=\"most-popular\"><strong>Most popular</strong></p>\n "); 794 } 795 OUT.push("\n <p class=\"online\">("); 796 OUT.push(G.escapeText(G.filters["safe"](G.filters["hlinperson"](G.filters["lower"](CTX.plan.online))))); 797 OUT.push(")</p>\n <p class=\"lectures\">\n "); 798 OUT.push(G.escapeText(G.filters["safe"](G.filters["hlinperson"](CTX.plan.lectures)))); 799 OUT.push(" Lectures\n </p>\n <p class=\"summary\">"); 800 OUT.push(G.escapeText(G.filters["safe"](CTX.plan.summary))); 801 OUT.push("</p>\n "); 802 if (CTX.plan.crossedPrice) { 803 OUT.push("\n <p class=\"prices\">
803\n <span class=\"crossed-price\">\n "); 804 OUT.push(G.escapeText(CTX.plan.crossedPrice)); 805 OUT.push("\n </span>\n </p>\n "); 806 } else { 807 OUT.push("\n <p class=\"stars\">\n ★★★★★<br />\n <span>Five-star rated program*</span>\n </p>\n "); 808 } 809 OUT.push("\n\n <p class=\"prices\">\n <span class=\"big-price\">"); 810 OUT.push(G.escapeText(CTX.plan.price)); 811 OUT.push("</span>\n </p>\n <p class=\"length\">\n "); 812 OUT.push(G.escapeText(CTX.plan.length)); 813 OUT.push("\n </p>\n\n "); 814 /* 815 OUT.push("\n "); 816 if (CTX.plan.price < 900) { 817 OUT.push("\n <a class=\"buy-btn\" href=\"#\">Purchase</a>\n "); 818 } 819 OUT.push("\n "); 820 */ 821 OUT.push("\n\n "); 822 if (CTX.plan.inquire) { 823 OUT.push("\n <a class=\"buy-btn buy--inquire\" href=\"https://kickstartcoding.online/apply/\">Inquire*</a>\n "); 824 } else { 825 OUT.push("\n <a class=\"buy-btn buy--apply\" href=\"https://kickstartcoding.online/apply
825/\">Apply</a>\n "); 826 } 827 OUT.push("\n "); 828 if (CTX.plan.inquire) { 829 OUT.push("\n <p class=\"inquire\">* "); 830 OUT.push(G.escapeText(CTX.plan.inquire)); 831 OUT.push("</p>\n "); 832 } 833 OUT.push("\n "); 834 if (CTX.plan.enrollInfo) { 835 OUT.push("\n <p class=\"inquire\">"); 836 OUT.push(G.escapeText(CTX.plan.enrollInfo)); 837 OUT.push("</p>\n "); 838 } 839 OUT.push("\n </article>\n"); 840 } 841 OUT.push("\n</section>\n<div class=\"review-site-links\">\n <p>* We are proud to maintain 5/5 for our commitment to\n excellence in affordable coding education. Review sites:\n <a href=\"https://www.coursereport.com/schools/kickstart-coding\" target=\"_blank\">Course Report</a>,\n <a href=\"https://www.switchup.org/bootcamps/kickstart-coding\" target=\"_blank\">Switch Up</a>,\n and <a href=\"https://www.yelp.com/biz/kickstart-coding-oakland\" target=\"_blank\">Yelp</a>.\n</div>"); 842 843return OUT.join(""); }; 844}; 845window.moduloBuild.nameToHash.library1_PlanMenu_template_regular = "x1on8cfr"; 846 847window.moduloBuild.modules["x18fqnr4"] = function library1_PlanMenu_template_solo (modulo) { 848return function (CTX, G) { var OUT=[]; 849 OUT.push("<section class=\"solo\">\n<article class=\"solo-info\">\n <p style=\"text-align: right; padding: 5px\">\n <span style=\"background-color: var(--sunshine); font-size: 40px\">New in June 2024 »</span>\n <!--\n <br />\n <span style=\"font-size: 33px\"> Virtual Coding Academy</span>\n -->\n <br/>\n <span style=\"font-size: 20px; color: var(--bluebird); font-weight:\n bold\">Our popular end-to-end, coding academy experience, now available as a hands-on video program!</span>\n </p>\n\n<!--\n <img\n src=\"/static/images/boximages/fullstack-bootcamp-bundle.png\" \n style=\"width: 250px; height: 250px\"\n title=\"3D Render of the Full Stack Bootcamp bundle as though it were a physical box (and not just a virtual box)\"\n />\n-->\n</article>\n\n\n<article class=\"plan solo-plan\">\n <div class=\"h3-wrapper\">\n <h3>Course Bundle</h3>\n </div>\n <!--<p class=\"most-popular\"><strong>Limited Time: 65% Off</strong></p>-->\n\n <img\n src=\"/static/images/boximages/fullstack-bootcamp-bundle.png\" \n style=\"width: 150px; height: 150px\"\n title=\"3D Render of the Full Stack Bootcamp bundle as though it were a physical box (and not just a virtual box)\"\n />\n <p style=\"font-size: 12px\">Kickstart\n Coding Virtual Academy<br />Lifetime Access to Video Program<p>\n <p class=\"prices\">\n <span class=\"crossed-price\">$299 MSRP</span>\n </p>\n <p class=\"prices\">\n <span class=\"big-price\">92</span>\n <!--<p>Coming soon: June 1st 2024</p>-->\n <p>DISCOUNT CODE: <tt>EARLYBIRD24</tt></p>\n </p>\n <a class=\"buy-btn\" href=\"https://buy.stripe.com/eVa9CG7cZ6Plg0M3cc?prefilled_promo_code=EARLYBIRD24\">Buy Now</a>\n <!--<a class=\"buy-btn\" href=\"#\">Coming soon</a>-->\n <p style=\"font-size: 12px\">Purchase Secured By Stripe ®<p>\n</article>\n\n<article class=\"solo-info\">\n <h2>Kickstart Coding Video Program</h2>\n <img src=\"/static/images/characters_version_2_altered.png\" style=\"height: 300px; float: right;\" />\n <ul style=\"text-align: left\">\n <li>75+ hours of course videos</li>\n <li>200+ activities & mini-projects</li>\n <li>50+ cheat-sheets & study guides</li>\n <li><strong>E-book included!</strong> - Kickstart Career is a 94\n page guide-book to the tech job hunt, crammed with expert\n tips from industry veterans\n <li><strong>Easy Study Plan Creator</strong> - <em>New in 2024!</em> A\n \"smart\" calendar assistant that assigns you due dates based\n based on your goals and skill-level\n </ul>\n</article>\n\n<article class=\"solo-info\" style=\"background: #eee\">\n <h2>Tried-and-true curriculum</h2>\n <p class=\"summary-solo\">For 6 years, our in-person and hybrid school has\n guided 100s of students to build apps, unlock their creative potentials, or\n find fulfilling professions in Silicon Valley, and beyond.</p>\n </p>\n\n <p class=\"summary-solo\">In 2024, we're proud to announce the\n <strong>Kickstart Coding Virtual Coding Academy</strong>.\n This means you can take our same tried-and-true bootcamp program, but\n with the flexibility and (and affordability!) format yet!</p>\n <br />\n <p class=\"stars\">\n ★★★★★<br />
849\n <span>Five-star rated school*</span>\n </p>\n <br />\n</article>\n\n</section>\n\n<div class=\"review-site-links\">\n <p>* We are proud to maintain 5/5 for our commitment to\n excellence in affordable coding education. Review sites:\n <a href=\"https://www.coursereport.com/schools/kickstart-coding\" target=\"_blank\">Course Report</a>,\n <a href=\"https://www.switchup.org/bootcamps/kickstart-coding\" target=\"_blank\">Switch Up</a>,\n and <a href=\"https://www.yelp.com/biz/kickstart-coding-oakland\" target=\"_blank\">Yelp</a>.\n</div>"); 850 851return OUT.join(""); }; 852}; 853window.moduloBuild.nameToHash.library1_PlanMenu_template_solo = "x18fqnr4"; 854 855window.moduloBuild.modules["x16a3vqa"] = function library1_PlanMenu_template (modulo) { 856return function (CTX, G) { var OUT=[]; 857 if (CTX.props.short) { 858 OUT.push("\n "); 859 OUT.push(CTX.template_solo.render(CTX)); 860 OUT.push("\n "); 861 } else { 862 OUT.push("\n "); 863 OUT.push(CTX.template_regular.render(CTX)); 864 OUT.push("\n "); 865 } 866 867return OUT.join(""); }; 868}; 869window.moduloBuild.nameToHash.library1_PlanMenu_template = "x16a3vqa"; 870 871window.moduloBuild.modules["x1nl2kok"] = function library1_Courses_template (modulo) { 872return function (CTX, G) { var OUT=[]; 873 if (!(CTX.props.topthree)) { 874 OUT.push("\n <h1>Courses</h1>\n <p>Our curriculum consists of 5 multi-segmented courses, which we use to\n create a custom paced full stack curriculum for each student in our\n program.</p>\n <nav>\n <ul>\n "); 875 var ARR1=CTX.script.courses;for (var KEY in ARR1) {CTX. course=ARR1[KEY]; 876 OUT.push("\n <li>\n <button @click:=script.selectCourse payload=\""); 877 OUT.push(G.escapeText(G.filters["lower"](CTX.course.title))); 878 OUT.push("\">\n <span class=\"step\">"); 879 OUT.push(G.escapeText(CTX.course.step)); 880 OUT.push("</span>\n <span class=\"label\">"); 881 OUT.push(G.escapeText(CTX.course.title)); 882 OUT.push("</span>\n <span class=\"weeks\">"); 883 OUT.push(G.escapeText(CTX.course.weeks)); 884 OUT.push("</span>\n </button>\n </li>\n "); 885 } 886 OUT.push("\n </ul>\n </nav>\n\n <h1>Course Segments</h1>\n"); 887 } 888 OUT.push("\n\n<main>\n\n"); 889 if (CTX.state.selected) { 890 OUT.push("\n <aside>\n "); 891 OUT.push(G.escapeText(G.filters["length"](CTX.script.visibleSegments))); 892 OUT.push("/"); 893 OUT.push(G.escapeText(G.filters["length"](CTX.script.segments))); 894 OUT.push("\n <button @click:=script.selectCourse payload=\"\">"); 895 OUT.push(G.escapeText(CTX.state.selected)); 896 OUT.push(" x</button>\n </aside>\n"); 897 } 898 OUT.push("\n\n\n"); 899 var ARR0=CTX.script.visibleSegments;for (var KEY in ARR0) {CTX. seg=ARR0[KEY]; 900 OUT.push("\n <article title=\""); 901 OUT.push(G.escapeText(CTX.seg.subtitle)); 902 OUT.push("\">\n <div class=\"course-wrapper "); 903 if (CTX.state.selected) { 904 OUT.push("course-wrapper--selected"); 905 } 906 OUT.push("\">\n <div class=\"h3-wrapper\">\n "); 907 if (CTX.seg.title) { 908 OUT.push("\n <h3>"); 909 OUT.push(G.escapeText(CTX.seg.title)); 910 OUT.push("</h3>\n "); 911 } else { 912 OUT.push("\n <h3>"); 913 OUT.push(G.escapeText(G.filters["capfirst"](CTX.seg.course))); 914 OUT.push("</h3>\n "); 915 } 916 OUT.push("\n <div style=\"\n background-image: \n "); 917 if (CTX.seg.imgfg === "white") { 918 OUT.push("\n linear-gradient(to bottom left, #11111155, #33333355),\n "); 919 } else { 920 OUT.push("\n linear-gradient(to bottom left, #eeeeee55, #cccccc55),\n "); 921 } 922 OUT.push("\n url(/static/images/new_course_photos/"); 923 OUT.push(G.escapeText(G.filters["default"](CTX.seg.img,"laptop-g4d7844033_1280.png"))); 924 OUT.push(");\n color: "); 925 OUT.push(G.escapeText(G.filters["default"](CTX.seg.imgfg,"black"))); 926 OUT.push("\n \"\n class=\"courseimg\"\n >\n ");
927 if (CTX.seg.subtitle) { 928 OUT.push("\n <h4>"); 929 OUT.push(G.escapeText(CTX.seg.subtitle)); 930 OUT.push("</h4>\n "); 931 } 932 OUT.push("\n </div>\n </div>\n "); 933 if (CTX.seg.free) { 934 OUT.push("\n <p class=\"free\" title=\"This course is free. Start immediately!\">FREE!</p>\n "); 935 } 936 OUT.push("\n "); 937 if (CTX.seg.content) { 938 OUT.push("\n <p>"); 939 OUT.push(G.escapeText(CTX.seg.content)); 940 OUT.push("</p>\n "); 941 } 942 OUT.push("\n "); 943 if (CTX.seg.updated) { 944 OUT.push("\n <p>"); 945 OUT.push(G.escapeText(CTX.seg.updated)); 946 OUT.push("</p>\n "); 947 } 948 OUT.push("\n <div class=\"bottom-wrapper\">\n "); 949 if (CTX.seg.skill) { 950 OUT.push("\n <p class=\"skill skill-level"); 951 OUT.push(G.escapeText(CTX.seg.skill)); 952 OUT.push("\">\n "); 953 OUT.push("\n "); 954 if (CTX.seg.skill === 1) { 955 OUT.push(" â¡ â¡ â¡ <br />Warm-Up\n "); 956 } else if (CTX.seg.skill === 2) { 957 OUT.push("⣠⡠⡠<br />Beginner\n "); 958 } else if (CTX.seg.skill === 3) { 959 OUT.push("⣠⣠⡠<br />Intermediate\n "); 960 } else if (CTX.seg.skill === 4) { 961 OUT.push("⣠⣠⣠<br />Advanced\n "); 962 } 963 OUT.push("\n </p>\n "); 964 } 965 OUT.push("\n <div class=\"buy-button-wrapper\">\n "); 966 if (CTX.seg.modules) { 967 OUT.push("\n <strong class=\"modules\" title=\""); 968 OUT.push(G.escapeText(G.filters["length"](CTX.seg.modules))); 969 OUT.push(" modules\">"); 970 OUT.push(G.escapeText(G.filters["length"](CTX.seg.modules))); 971 OUT.push(" <i class=\"bi bi-boxes\" aria-hidden=\"true\"></i></strong>\n <br />\n "); 972 } 973 OUT.push("\n "); 974 if (CTX.seg.project) { 975 OUT.push("\n <strong class=\"project-tag\" title=\"Project based learning: "); 976 OUT.push(G.escapeText(CTX.seg.project)); 977 OUT.push("\"><i class=\"bi bi-laptop\" aria-hidden=\"true\"></i> PROJECT</strong>\n "); 978 } 979 OUT.push("\n "); 980 if (!(CTX.seg.url)) { 981 OUT.push("\n "); 982 OUT.push("\n <div class=\"included-explainer\">\n "); 983 if (CTX.seg.project) { 984 OUT.push("\n <strong>Project based learning:</strong> "); 985 OUT.push(G.escapeText(CTX.seg.project)); 986 OUT.push("<br />\n "); 987 } 988 OUT.push("\n "); 989 if (CTX.seg.modules) { 990 OUT.push("\n <strong>Module Count:</strong> "); 991 OUT.push(G.escapeText(G.filters["length"](CTX.seg.modules))); 992 OUT.push("\n "); 993 } 994 OUT.push("\n </div>\n "); 995 } 996 OUT.push("\n </div>\n\n "); 997 if (CTX.seg.url) { 998 OUT.push("\n <p class=\"url\">\n <a href=\""); 999 OUT.push(G.escapeText(CTX.seg.url)); 1000 OUT.push("\" class=\"Page-navLink\" style=\"min-width: 40px; font-size: 1rem\">\n BEGIN »\n </a>\n "); 1001 if (CTX.props.topthree) { 1002 OUT.push("\n <span class=\"sticky-note\">\n <span class=\"sticky-note-arrow\">â¬</span>\n <strong>Free Course for Beginners!</strong>\n </span>\n "); 1003 } 1004 OUT.push("\n\n </p>\n "); 1005 } else if (CTX.props.topthree) { 1006 OUT.push("\n "); 1007 OUT.push("\n "); 1008 } else { 1009 OUT.push("\n <div class=\"buy-button-wrapper\">\n <a href=\"/apply/\" class=\"getbtn\">\n GET <i class=\"fa fa-shopping-cart\" aria-hidden=\"true\"></i>\n </a>\n <div class=\"included-explainer\">\n <strong style=\"font-size: 1.5rem;\">$299 MSRP</strong>\n <em>LIFETIME DIGITAL ACCESS BUNDLE</em>\n <p>» Lifetime access to Kickstart Coding\n video courses (includes 100s of hours of private\n video archive access)\n <br />\n » Lifetime access to Kickstart Coding's\n coding curriculum files (includes 100s of\n professional assignments and industry-tuned example\n projects)\n <br />\n » Lifetime access to Virtual Coding\n Academy software (includes Linux Lab distro and\n other interactive courseware)</p>\n <!--\n <a href=\"https://kickstartcoding.online/apply
1009/\" class=\"Page-navLink\" style=\"min-width: 40px; font-size: 1rem\">\n ð GET »\n </a>\n -->\n </div>\n </div>\n "); 1010 } 1011 OUT.push("\n </div>\n </div>\n </article>\n"); 1012 } 1013 OUT.push("\n\n</main>"); 1014 1015return OUT.join(""); }; 1016}; 1017window.moduloBuild.nameToHash.library1_Courses_template = "x1nl2kok"; 1018 1019window.moduloBuild.definitions = { 1020 1021 1022 1023 1024 1025 1026modulo: {"Parent":null,"DefName":null,"Type":"Modulo","ChildPrefix":"","Contains":"coreDefs","DefLoaders":["DefTarget","DefinedAs","Src","Content"],"defaultDef":{"DefTarget":null,"DefinedAs":null,"DefName":null},"defaultDefLoaders":["DefTarget","DefinedAs","Src"],"defaultFactory":["RenderObj","factoryCallback"],"src":"/static/js/Modulo.js","Name":"modulo","DefinitionName":"modulo","Source":"http://127.0.0.1:6627/static/libraries/","ChildrenNames":["configuration","configuration1","library","library1"]}, 1027 1028configuration: {"Parent":"modulo","DefName":null,"Type":"Configuration","DefLoaders":["DefTarget","DefinedAs","Src|SrcSync","Content|Code","DefinitionName|MainRequire"],"Name":"configuration"}, 1029 1030configuration1: {"Parent":"modulo","DefName":null,"Type":"Configuration","DefLoaders":["DefTarget","DefinedAs","Src|SrcSync","Content|Code","DefinitionName|MainRequire"],"Name":"configuration1","Source":"http://127.0.0.1:6627/static/js/ModuloInclude.js"}, 1031 1032library: {"Parent":"modulo","DefName":null,"Type":"Library","Contains":"coreDefs","DefLoaders":["DefTarget","DefinedAs","Src","Content"],"namespace":"x","Name":"library","DefinitionName":"library","Source":"http://127.0.0.1:6627/static/libraries/layout.html","ChildrenNames":["library_include","library_configuration","library_Page","library_FeaturedTestimonials","library_Testimonials","library_FeaturedArticles"]}, 1033 1034library1: {"Parent":"modulo","DefName":null,"Type":"Library","Contains":"coreDefs","DefLoaders":["DefTarget","DefinedAs","Src","Content"],"namespace":"x","Name":"library1","DefinitionName":"library1","Source":"http://127.0.0.1:6627/static/libraries/shop.html","ChildrenNames":["library1_configuration","library1_StudentIDGenerator","library1_HiddenSuccessCard","library1_PlanMenu","library1_Courses"]}, 1035 1036library_include: {"Parent":"library","DefName":null,"Content":"\n <link rel=\"stylesheet\" href=\"/static/css/site.css\">\n","GlobalBundled":{"xx7ae92e":true},"ServerTemplate":"https://{{ server }}/{{ path }}","TagTemplate":"{% if isCSS %}<link name=\"{{ package }}\" rel=\"stylesheet\" href=\"{{ url }}\" />{% else %}<script name=\"{{ package }}\" src=\"{{ url }}\"></script>{% endif %}","DefLoaders":["DefTarget","DefinedAs","Src","Server","LoadMode"],"Type":"Include","N
1036ame":"include","DefinitionName":"library_include"}, 1037 1038library_configuration: {"Parent":"library","DefName":null,"Type":"Configuration","DefLoaders":["DefTarget","DefinedAs","Src|SrcSync","Content|Code","DefinitionName|MainRequire"],"Name":"configuration"}, 1039 1040library_Page: {"Parent":"library","DefName":null,"tagAliases":{},"mode":"vanish-into-document","rerender":"event","engine":"Reconciler","Contains":"cparts","RenderObj":"component","DefLoaders":["DefTarget","DefinedAs","Src","Content"],"DefBuilders":["CustomElement","alias|AliasNamespace","CodeTemplate"],"DefFinalizers":["MainRequire"],"BuildCommandBuilders":["Prebuild|BuildLifecycle","BuildLifecycle"],"Directives":["eventMount","eventUnmount","dataPropMount","dataPropUnmount"],"Type":"Component","name":"Page","Name":"Page","DefinitionName":"library_Page","ChildrenNames":["library_Page_props","library_Page_template","library_Page_style","library_Page_script"],"namespace":"x","TagName":"x-page","className":"x_Page"}, 1041 1042library_FeaturedTestimonials: {"Parent":"library","DefName":null,"tagAliases":{},"mode":"regular","rerender":"event","engine":"Reconciler","Contains":"cparts","RenderObj":"component","DefLoaders":["DefTarget","DefinedAs","Src","Content"],"DefBuilders":["CustomElement","alias|AliasNamespace","CodeTemplate"],"DefFinalizers":["MainRequire"],"BuildCommandBuilders":["Prebuild|BuildLifecycle","BuildLifecycle"],"Directives":["eventMount","eventUnmount","dataPropMount","dataPropUnmount"],"Type":"Component","name":"FeaturedTestimonials","Name":"FeaturedTestimonials","DefinitionName":"library_FeaturedTestimonials","ChildrenNames":["library_FeaturedTestimonials_template","library_FeaturedTestimonials_style","library_FeaturedTestimonials_state","library_FeaturedTestimonials_staticdata"],"namespace":"x","TagName":"x-featuredtestimonials","className":"x_FeaturedTestimonials"}, 1043 1044library_Testimonials: {"Parent":"library","DefName":null,"tagAliases":{},"mode":"regular","rerender":"event","engine":"Reconciler","Contains":"cparts","RenderObj":"component","DefLoaders":["DefTarget","DefinedAs","Src","Content"],"DefBuilders":["CustomElement","alias|AliasNamespace","CodeTemplate"],"DefFinalizers":["MainRequire"],"BuildCommandBuilders":["Prebuild|BuildLifecycle","BuildLifecycle"],"Directives":["eventMount","eventUnmount","dataPropMount","dataPropUnmount"],"Type":"Component","name":"Testimonials","Name":"Testimonials","DefinitionName":"library_Testimonials","ChildrenNames":["library_Testimonials_template","library_Testimonials_style","library_Testimonials_state","library_Testimonials_staticdata"],"namespace":"x","TagName":"x-testimonials","className":"x_Testimonials"}, 1045 1046library_FeaturedArticles: {"Parent":"library","DefName":null,"tagAliases":{},"mode":"regular","rerender":"event","engine":"Reconciler","Contains":"cparts","RenderObj":"component","DefLoaders":["DefTarget","DefinedAs","Src","Content"],"DefBuilders":["CustomElement","alias|AliasNamespace","CodeTemplate"],"DefFinalizers":["MainRequire"],"BuildCommandBuilders":["Prebuild|BuildLifecycle","BuildLifecycle"],"Directives":["eventMount","eventUnmount","dataPropMount","dataPropUnmount"],"Type":"Component","name":"FeaturedArticles","Name":"FeaturedArticles","DefinitionName":"library_FeaturedArticles","ChildrenNames":["library_FeaturedArticles_template","library_FeaturedArticles_state","library_FeaturedArticles_staticdata","library_FeaturedArticles_script","library_FeaturedArticles_style"],"namespace":"x","TagName":"x-featuredarticles","className":"x_FeaturedArticles"}, 1047 1048library_Page_props: {"Parent":"library_Page","DefName":null,"Content":"","Type":"Props","title":"","toptitle":"","rightimage":"","tlcutout":"","tlcutoutbg":"","tltall":"","bottomtitle":"","navselected":"","landing":"","Name":"props","DefinitionName":"library_Page_props"}, 1049 1050library_Page_template: {"Parent":"library_Page","DefName":null,"Type":"Template","DefFinalizers":["FilterContent","TemplatePrebuild"],"opTokens":"==,>,<,>=,<=,!=,not in,is not,is,in,not,gt,lt","opAliases":{"==":"X === Y","is":"X === Y","gt":"X > Y","lt":"X < Y","is not":"X !== Y","not":"!(Y)","in":"(Y).includes ? (Y).includes(X) : (X in Y)","not in":"!((Y).includes ? (Y).includes(X) : (X in Y))"},"modeTokens":["{% %}","{{ }}","{# #}"],"modes":{},"defaultFilters":{},"defaultTags":{}
1050,"Name":"template","DefinitionName":"library_Page_template","Source":"http://127.0.0.1:6627/static/libraries/layout/Page.html"}, 1051 1052library_Page_style: {"Parent":"library_Page","DefName":null,"urlReplace":null,"isolateSelector":null,"isolateClass":null,"prefix":null,"corePseudo":["before","after","first-line","last-line"],"DefBuilders":["FilterContent","AutoIsolate","Content|ProcessCSS"],"Type":"Style","Name":"style","DefinitionName":"library_Page_style","Source":"http://127.0.0.1:6627/static/libraries/layout/Page.css","headHash":"x1jmv0rr"}, 1053 1054library_Page_script: {"Parent":"library_Page","DefName":null,"lifecycle":null,"DefBuilders":["Content|AutoExport","CodeTemplate"],"Type":"Script","Name":"script","DefinitionName":"library_Page_script","exportNames":["prepareCallback"],"locals":[],"Directives":[],"tempContent":"\n function prepareCallback() {\n // For now, store the navigation array and generate year in JS\n return {\n currentYear: (new Date()).getFullYear(),\n navigation: [\n {\n title: \"Start\",\n file: \"index.html\",\n },\n {\n title: \"Courses\",\n file: \"courses/\",\n },\n {\n title: \"Plans\",\n //file: \"index.html#learn\",\n file: \"apply/\",\n },\n {\n title: \"Services\",\n file: \"services/\",\n },\n /*\n {\n title: \"Results\",\n file: \"results/\",\n },\n {\n title: \"Learn\",\n //file: \"index.html#learn\",\n file: \"learn/\",\n },\n {\n title: \"Outreach\",\n file: \"outreach/\",\n },\n */\n ],\n };\n }\n "}, 1055 1056library_FeaturedTestimonials_template: {"Parent":"library_FeaturedTestimonials","DefName":null,"Type":"Template","DefFinalizers":["FilterContent","TemplatePrebuild"],"opTokens":"==,>,<,>=,<=,!=,not in,is not,is,in,not,gt,lt","opAliases":{"==":"X === Y","is":"X === Y","gt":"X > Y","lt":"X < Y","is not":"X !== Y","not":"!(Y)","in":"(Y).includes ? (Y).includes(X) : (X in Y)","not in":"!((Y).includes ? (Y).includes(X) : (X in Y))"},"modeTokens":["{% %}","{{ }}","{# #}"],"modes":{},"defaultFilters":{},"defaultTags":{},"Name":"template","DefinitionName":"library_FeaturedTestimonials_template","Source":"http://127.0.0.1:6627/static/libraries/layout/Testimonials.html"}, 1057 1058library_FeaturedTestimonials_style: {"Parent":"library_FeaturedTestimonials","DefName":null,"urlReplace":null,"isolateSelector":[],"isolateClass":null,"prefix":"x-FeaturedTestimonials","corePseudo":["before","after","first-line","last-line"],"DefBuilders":["FilterContent","AutoIsolate","Content|ProcessCSS"],"Type":"Style","Name":"style","DefinitionName":"library_FeaturedTestimonials_style","Source":"http://127.0.0.1:6627/static/libraries/layout/Testimonials.css","headHash":"xxp167be"}, 1059 1060library_FeaturedTestimonials_state: {"Parent":"library_FeaturedTestimonials","DefName":null,"Content":"","Type":"State","Directives":["bindMount","bindUnmount"],"Store":null,"selected":"","Name":"state","DefinitionName":"library_FeaturedTestimonials_state"}, 1061 1062library_FeaturedTestimonials_staticdata: {"Parent":"library_FeaturedTestimonials","DefName":null,"Content":"[\n {\n name: 'Nicolas Miller',\n img: 'nicolas.jpg',\n location: 'Antioch, California',\n profession: 'Software Engineer @ Rooster Grin Media',\n linkedin: 'nicolas-wyatt-miller',\n pullquote: `The custom paced structure was possibly the most vital component to\n my success [...] this setup allowed me to pace my progress and\n uphold my life's balance in the process.`,\n text: `\n <strong>It sounds cheesy, but Kickstart Coding gave me the\n opportunity to make a career shift that I never thought I would be\n able to.<
1062/strong> The personalized tutoring helped target my\n weaknesses and get honest feedback on my projects that large scale\n programs are unable to provide. The custom paced structure was\n possibly the most vital component to my success; I've never been\n the person who gets something new on the first, second, or even\n third try, but this setup allowed me to pace my progress and uphold\n my life's balance in the process. The instructional material was\n intense, but Michael makes some hilarious references and segments\n the topics into digestible lessons. If I could give any advice, I\n would say to not let anything stop you, but ESPECIALLY don't let\n you stop yourself. You 1000% can do this and self doubt or fear of\n difficulty are likely to be your biggest obstacles -- you just have\n to be kind to yourself and get up again when JavaScript and CSS\n inevitably knock you down. <strong>You are going to be so proud of\n yourself because this is massive and this is worth it!</strong>\n `,\n },\n\n {\n name: 'Anthony Sifontes',\n img: 'anthony.jpg',\n location: 'New Orleans, Louisiana',\n profession: 'Software Engineer @ Amino',\n linkedin: 'anthonysifontes',\n featured: 'Software Engineer',\n pullquote: `I eventually received an offer to be a Software Engineer at an exciting\n healthcare start-up, and only 11 weeks into the program.`,\n text: `\n My career thus far had been in data analytics. I wanted to\n transition to a developer role and ultimately be able to create and\n turn my ideas into reality. I had not taken any coding courses\n before this, only online tutorials and books, so I was not sure\n what to expect. <strong>Class after class, I was blown away by the\n passion Michael and his team brought to each and every\n lesson!</strong> The classes were lively, balanced between lecture,\n demonstrations, guided coding activities, and group work, while\n still being accessible to a wide range of experience levels.\n\n A couple of months into the course, I started applying for\n developer positions, and soon I was excited to be invited for a\n round of on-site interviews. <strong>Michael was very supportive,\n coaching me on how to best present my work experience, and guiding\n me through a mock \"whiteboard\" interview.</strong> Every interview\n was more challenging than the last, but all of the coaching and\n prep received at Kickstart beforehand was critical to my moving\n forward in the process. You can imagine my excitement when I\n eventually received an offer to be a Software Engineer at an\n exciting healthcare start-up, and only 11 weeks into the program!\n Now, I've been at my new position for several months, and I love\n it. The work we did in class was instrumental in preparing me for\n my new day-to-day duties. I'm very thankful to the Kickstart\n Coding team and the help they provided in transitioning to my new\n software engineering career.\n `,\n },\n\n {\n name: 'Andrew Thorton',\n img: 'andrew.jpg',\n location: 'Alameda, California',\n profession: 'Data Engineer @ Lyft',\n featured: 'Data Engineer',\n linkedin: 'andrew-w-thornton',\n pullquote: `Using my newly acquired skills, I got a great new job as a Data\n Engineer just a couple of weeks after finishing the Kickstart Coding\n course.`,\n text: `\n After spending years as a software project and product manager flirting\n with the idea of becoming a software engineer, I finally got up the\n courage to sign up for a coding bootcamp. I looked at many different\n options and chose Kickstart Coding because it provides excellent value\n and is staffed by people that are clearly passionate about teaching\n technology. I enjoyed the in-class lessons which are an engaging mix of\n lecture, live-coding walkthroughs, and activities. The homework\n assignments and group projects built nicely on the stuff we learned in\n class and helped to reinforce the concepts with very practical\n examples. <strong>The curriculum does a masterful job of challenging\n people with some coding experience while also being accessible to\n people with no coding background at all.</strong> While the vast\n majority of the curriculum is very focu
1062sed on teaching specific\n languages and frameworks, the last couple lessons of the Front-End\n portion of the course are focused on some more general concepts that\n were extremely helpful in preparing me for interviews. Using my newly\n acquired skills, I got a great new job as a Data Engineer just a couple\n of weeks after finishing the Kickstart Coding course. <strong>I would\n recommend Kickstart Coding to everyone, even if you don't want a job as\n a software engineer. Learning to code in this setting was really\n fun!</strong>\n `,\n },\n\n {\n name: 'Sarah Farnsworth-Kumli',\n img: 'sarah.jpg',\n location: 'San Francisco, California',\n profession: 'Solutions Engineer @ Okta',\n linkedin: 'sarah-fk',\n pullquote: `I walked into Kickstart Coding to brush up on my skills. I\n left with a new career.`,\n text: `\n <strong>Now that I am on the other side, have landed a job, and am\n now working with developers I can honestly say that Kickstart is a\n quality program.</strong> They take a modern approach to teaching\n and teach what's current in an adapting industry (also what stacks\n companies are hiring for!).\n\n Michael covered CS concepts in an incredibly accessible way for a\n diverse classroom with different levels of experience. The course\n material was the perfect balance of providing introductory guidance\n and challenge. Group projects exposed us to the challenges of\n working in a development team and we continued to build on new\n iterations of our personal projects.\n\n It's a privilege to have been a part of such a fantastic community,\n and I'm excited to see it grow. <strong>Amazing how such a short\n time can change your life, if you're considering taking the plunge,\n DO IT!</strong>\n `,\n },\n\n {\n name: 'Nicol Hawkins',\n featured: 'Platform Specialist',\n img: 'nicol.jpg',\n location: 'San Franciso, California',\n profession: 'Platform Specialist @ Amplitude',\n linkedin: 'nicol-hawkins',\n featured_on_frontpage: true,\n pullquote: `Thanks to the skills I learned at Kickstart Coding, I was\n able to market myself for entry-level positions in the tech industry.`,\n featured_text: `\n When I started Kickstart Coding, I had very few programming skills and\n no prior work experience in tech. It was a huge leap for me and it\n literally changed my life! <strong>Kickstart Coding is more affordable\n than most coding bootcamps and the curriculum is top-notch while having\n a lot of repeat value.</strong> [...] I am blown away by how much I\n learned since my first day at Kickstart Coding; from my first HTML file\n all the way to navigating complex frameworks and implementing APIs.\n\n This program not only gave me the technical skills required for a\n career in tech -- it helped me recognize the potential and capacity I\n have for learning.\n `,\n text: `\n When I started Kickstart Coding, I had very few programming skills and\n no prior work experience in tech. It was a huge leap for me and it\n literally changed my life! Kickstart Coding is more affordable than\n most coding bootcamps and the curriculum is top-notch while having a\n lot of repeat value.\n\n I left the course with a personal webpage full of projects to showcase\n and revisited the curriculum often to tackle bonus activities. The\n course is approachable whether you're like me and just starting out or\n already possess programming skills. I am blown away by how much\n I learned since my first day at Kickstart Coding; from my first HTML\n file all the way to navigating complex frameworks and implementing\n APIs.\n\n This program not only gave me the technical skills required for a\n career in tech -- it helped me recognize the potential and capacity I\n have for learning. A major part of my new role as a Platform Specialist\n is communicating with engineers and data analysts, so having a\n background in software helps me communicate effectively and\n efficiently. Thanks to the skills I learned at Kickstart Coding, I was\n able to market myself for entry-level positions in the tech industry.\n `,\n },\n\n {\n name: 'Yulia Tuzov',\n img: 'yulia.jpg',\n location: 'San Mateo, California',\n profession: 'QA engineer @ Skupos',\n linkedin: 'yuliatuzov',\n pullquote: `Kickstartâs curriculum gave me technical understanding of\n all the moving parts involved in building a software product.`,\n text: `\n I have been in tech for couple of years in a QA role prior to going\n to this bootcamp. And now transitioning into an engineering role.\n Kickstartâs curriculum gave me technical understanding of all the\n moving parts involved in building a software product as well as\n practice of building those parts in group projects and individual\n projects which is extremely valuable experience.\n \n The curriculum overall is very well structured in a way that after\n every topic is introduced students had to apply it in their\
1062n homework right away as well as final projects at the end of each\n course. Program also includes industry insights and job prep\n material. <strong>Michael, Mark and Maddy are very passionate about\n their students to succeed in the career transitions. You do have to\n work a lot during the course, so be ready, but youâll also have\n amazing support.</strong> Support also doesnât end after the\n course, you can come to their hack & learns to get help or\n guidance.\n `,\n },\n\n {\n name: 'Kyle Pollock',\n img: 'kyle.jpg',\n location: 'San Francisco, California',\n profession: 'Knowledge Base Manager @ Synapse',\n linkedin: 'kylepollock',\n pullquote: `I got a job offer within 30 days of completing my 4 month summer cohort.`,\n text: `\n I was looking for a place to learn Python, JavaScript, and how to work\n with APIs to increase my skills, and make myself more marketable as a\n former jack of all trades website manager. I was quite familiar with\n the coding bootcamps in the Bay Area, as a friend of mine helped start\n one in San Francisco. When I searched around for programs and found\n Kickstart Coding, I couldn't find one that could beat it's overall\n value through affordability, flexibility, and course offerings. I was\n able to build three strong projects in Github (along with other\n projects) and an online portfolio. I got a job offer within 30 days of\n completing my 4 month summer cohort. <strong>I also more than tripled\n my income from my previous job as a non-profit communications manager.\n I am grateful to have gone through Kickstart Coding, and for the\n ongoing support beyond graduation through the teachers and alumni\n group.</strong>\n `,\n },\n\n {\n name: 'Rudy Trubitt',\n img: 'rudy.jpg',\n location: 'Oakland, California',\n profession: 'Senior Software Test Engineer @ Dolby',\n linkedin: 'rudy-trubitt-43b2126',\n pullquote: `Kickstart Coding gave me the key skills I needed to advance my career.`,\n text: `\n <strong>I needed a career boost and Kickstart delivered.</strong>\n From the start, I was impressed by my interactions with the\n programâs staff. Although I was looking specifically for Python\n instruction, the additional material in the back-end course turned\n out to be extremely relevant. The class work was challenging but\n well-differentiated for students with varying levels of programming\n experience. And I thoroughly enjoyed getting to know and work with\n everyone in my cohort.\n\n During my job hunting and interviewing, I regularly reflected on\n things I learned in the program. <strong>There were times when I\n literally could hear Michael's voice in my head while I answered\n interview questions.</strong> Although my previous skills also\n helped me land my current position, there's no doubt that Kickstart\n Coding gave me the key skills I needed to advance my career.\n `,\n },\n\n {\n name: 'Cindy Dovinh',\n img: 'cindy.jpg',\n location: 'Oakland, California',\n profession: '',\n pullquote: `Kickstart Coding delivered on commitment to value, education, and passion.`,\n text: `\n Kickstart Coding could not have been more aptly named and the\n schedule/format of the class could not have fit my needs better.\n With my full-time, non-tech job demanding a minimum of 50-60 hrs\n per week, I still looked forward to every class (2 weekday evenings\n and Saturday afternoon, each week). Michael is hands down the best\n teacher I've ever had. He is an expert at what he does, with an\n impressively VAST knowledge base and still managed to consistently\n make you feel comfortable in your learning. Being introduced to so\n much new information and new ways of thinking, he was always able\n to answer our questions thoroughly, even though at times, we didn't\n even know how to ask them.\n `,\n },\n\n\n {\n name: 'Errin Mixon',\n img: 'errin.jpg',\n location: 'Oakland, California',\n profession: 'Junior Frontend Developer @ GeoEx',\n linkedin: 'errin-mixon-2b289023',\n pullquote: `I couldn't have afforded the time or money to take a traditional\n bootcamp. I came out the other end as a web developer â with a new job.`,\n text: `\n I come from a zero-tech background. I wanted to build an app. Michael\n said he could teach me that, so I signed up.\n\n I'm not going to lie. This bootcamp was hard. For a tech newbie with a\n full-time job and family, the time commitment is intense. I was often\n frustrated. I cried, a lot. I secretly thought that I shouldn't have\n been admitted to the course.\n\n But I came out the other end as a web developer â with a new job. That\n hadn't even been my goal, and you couldn't find anybody more surprised\n than me!\n\n I couldn't have afforded the time or money to take a traditional\n bootcamp. I never would have tried. <strong>Kickstart Coding made\n it possible for me to learn these skills, and it's no exaggeration\n to say that it changed the trajectory of my career, and possibly my\n life.</strong> Michael is an excellent and engaging teacher, as are\n TA's Maddy and Mark, and I owe them a debt of gratitude.\n\n 5 stars for Kickstart â well worth your money.\n `,\n },\n\n {\n name: 'Jeremy Johnson',\n img: 'jeremy.jpg',\n location: 'Madison, Wisconsin',\n profession: 'Web Developer @ Know How',\n linkedin: 'jeremy-johnson-80035395',\n pullquote: `The skills I learned in this course I use every day at my new job\n as a web developer.`,\n text: `\n Out of high school I got a 2 year web programming degree at a local\n technical college. I applied and applied for programming jobs and\n was unable to land one. I really enjoyed programming but started to\n think I would never be able to make it my career. A few years went\n by working odd jobs when I got the opportunity to take this\n bootcamp online.\n \n <strong>I can't begin to say how great this course is. I learned\n more about programming in a matter of weeks than I did in a matter\n of years in school.</strong> Seeing real world examples of what we\n were learning along the way made me excited to learn and do the\n work. In addition to the amazing coursework, Micheal equips you\n with great tools to help you find a job. <strong>I was able to get\n a programming job just weeks after completing the course.</strong>\n The skills I learned in this course I use every day at my job as a\n web developer.\n \n I am very happy with my new job and 100% recommend this course to\n anyone looking to get into tech!\n `,\n },\n]\n\n .filter(\n item => item.featured // only show featured\n )\n ","Type":"StaticData","DefLoa
1062ders":["DefTarget","DefinedAs","DataType","Src","FilterContent"],"DefBuilders":["ContentCSV","ContentTXT","ContentJSON","ContentJS","Code","RequireData"],"Name":"staticdata","DefinitionName":"library_FeaturedTestimonials_staticdata","Source":"http://127.0.0.1:6627/static/libraries/layout/Testimonials.js","data":[{"name":"Anthony Sifontes","img":"anthony.jpg","location":"New Orleans, Louisiana","profession":"Software Engineer @ Amino","linkedin":"anthonysifontes","featured":"Software Engineer","pullquote":"I eventually received an offer to be a Software Engineer at an exciting\n healthcare start-up, and only 11 weeks into the program.","text":"\n My career thus far had been in data analytics. I wanted to\n transition to a developer role and ultimately be able to create and\n turn my ideas into reality. I had not taken any coding courses\n before this, only online tutorials and books, so I was not sure\n what to expect. <strong>Class after class, I was blown away by the\n passion Michael and his team brought to each and every\n lesson!</strong> The classes were lively, balanced between lecture,\n demonstrations, guided coding activities, and group work, while\n still being accessible to a wide range of experience levels.\n\n A couple of months into the course, I started applying for\n developer positions, and soon I was excited to be invited for a\n round of on-site interviews. <strong>Michael was very supportive,\n coaching me on how to best present my work experience, and guiding\n me through a mock \"whiteboard\" interview.</strong> Every interview\n was more challenging than the last, but all of the coaching and\n prep received at Kickstart beforehand was critical to my moving\n forward in the process. You can imagine my excitement when I\n eventually received an offer to be a Software Engineer at an\n exciting healthcare start-up, and only 11 weeks into the program!\n Now, I've been at my new position for several months, and I love\n it. The work we did in class was instrumental in preparing me for\n my new day-to-day duties. I'm very thankful to the Kickstart\n Coding team and the help they provided in transitioning to my new\n software engineering career.\n "},{"name":"Andrew Thorton","img":"andrew.jpg","location":"Alameda, California","profession":"Data Engineer @ Lyft","featured":"Data Engineer","linkedin":"andrew-w-thornton","pullquote":"Using my newly acquired skills, I got a great new job as a Data\n Engineer just a couple of weeks after finishing the Kickstart Coding\n course.","text":"\n After spending years as a software project and product manager flirting\n with the idea of becoming a software engineer, I finally got up the\n courage to sign up for a coding bootcamp. I looked at many different\n options and chose Kickstart Coding because it provides excellent value\n and is staffed by people that are clearly passionate about teaching\n technology. I enjoyed the in-class lessons which are an engaging mix of\n lecture, live-coding walkthroughs, and activities. The homework\n assignments and group projects built nicely on the stuff we learned in\n class and helped to reinforce the concepts with very practical\n examples. <strong>The curriculum does a masterful job of challenging\n people with some coding experience while also being accessible to\n people with no coding background at all.</strong> While the vast\n majority of the curriculum is very focused on teaching specific\n languages and frameworks, the last couple lessons of the Front-End\n portion of the course are focused on some more general concepts that\n were extremely helpful in preparing me for interviews. Using my newly\n acquired skills, I got a great new job as a Data Engineer just a couple\n of weeks after finishing the Kickstart Coding course. <strong>I would\n recommend Kickstart Coding to everyone, even if you don't want a job as\n a software engineer. Learning to code in this setting was really\n fun!</strong>\n "},{"name":"Nicol Hawkins","featured":"Platform Specialist","img":"nicol.jpg","location":"San Franciso, California","profession":"Platform Specialist @ Amplitude","linkedin":"nicol-hawkins","featured_on_frontpage":true,"pullquote":"Thanks to the skills I learned at Kickstart Coding, I was\n able to market myself for entry-level positions in the tech industry.","featured_text":"\n When I started Kickstart Coding, I had very few programming skills and\n no prior work experience in tech. It was a huge leap for me and it\n literally changed my life! <strong>Kickstart Coding is more affordable\n than most coding bootcamps and the curriculum is top-notch while having\n a lot of repeat value.</strong> [...] I am blown away by how much I\n learned since my first day at Kickstart Coding; from my first HTML file\n all the way to navigating complex frameworks and implementing APIs.\n\n This program not only gave me the technical skills required for a\n career in tech -- it helped me recognize the potential and capacity I\n have for learning.\n ","text":"\n When I started Kickstart Coding, I had very few programming skills and\n no prior work experience in tech. It was a huge leap for me and it\n literally changed my life! Kickstart Coding is more affordable than\n most coding bootcamps and the curriculum is top-notch while having a\n lot of repeat value.\n\n I left the course with a personal webpage full of projects to showcase\n and revisited the curriculum often to tackle bonus activities. The\n course is approachable whether you're like me and just starting out or\n already possess programming skills. I am blown away by how much\n I learned since my first day at Kickstart Coding; from my first HTML\n file all the way to navigating complex frameworks and implementing\n APIs.\n\n This program not only gave me the technical skills required for a\n career in tech -- it helped me recognize the potential and capacity I\n have for learning. A major part of my new role as a Platform Specialist\n is communicating with engineers and data analysts, so having a\n background in software helps me communicate effectively and\n efficiently. Thanks to the skills I learned at Kickstart Coding, I was\n able to market myself for entry-level positions in the tech industry.\n "}]}, 1063 1064library_Testimonials_template: {"Parent":"library_Testimonials","DefName":null,"Type":"Template","DefFinalizers":["FilterContent","TemplatePrebuild"],"opTokens":"==,>,<,>=,<=,!=,not in,is not,is,in,not,gt,lt","opAliases":{"==":"X === Y","is":"X === Y","gt":"X >
1064 Y","lt":"X < Y","is not":"X !== Y","not":"!(Y)","in":"(Y).includes ? (Y).includes(X) : (X in Y)","not in":"!((Y).includes ? (Y).includes(X) : (X in Y))"},"modeTokens":["{% %}","{{ }}","{# #}"],"modes":{},"defaultFilters":{},"defaultTags":{},"Name":"template","DefinitionName":"library_Testimonials_template","Source":"http://127.0.0.1:6627/static/libraries/layout/Testimonials.html"}, 1065 1066library_Testimonials_style: {"Parent":"library_Testimonials","DefName":null,"urlReplace":null,"isolateSelector":[],"isolateClass":null,"prefix":"x-Testimonials","corePseudo":["before","after","first-line","last-line"],"DefBuilders":["FilterContent","AutoIsolate","Content|ProcessCSS"],"Type":"Style","Name":"style","DefinitionName":"library_Testimonials_style","Source":"http://127.0.0.1:6627/static/libraries/layout/Testimonials.css","headHash":"xx357jf0"}, 1067 1068library_Testimonials_state: {"Parent":"library_Testimonials","DefName":null,"Content":"","Type":"State","Directives":["bindMount","bindUnmount"],"Store":null,"selected":"","Name":"state","DefinitionName":"library_Testimonials_state"}, 1069 1070library_Testimonials_staticdata: {"Parent":"library_Testimonials","DefName":null,"Content":"[\n {\n name: 'Nicolas Miller',\n img: 'nicolas.jpg',\n location: 'Antioch, California',\n profession: 'Software Engineer @ Rooster Grin Media',\n linkedin: 'nicolas-wyatt-miller',\n pullquote: `The custom paced structure was possibly the most vital component to\n my success [...] this setup allowed me to pace my progress and\n uphold my life's balance in the process.`,\n text: `\n <strong>It sounds cheesy, but Kickstart Coding gave me the\n opportunity to make a career shift that I never thought I would be\n able to.</strong> The personalized tutoring helped target my\n weaknesses and get honest feedback on my projects that large scale\n programs are unable to provide. The custom paced structure was\n possibly the most vital component to my success; I've never been\n the person who gets something new on the first, second, or even\n third try, but this setup allowed me to pace my progress and uphold\n my life's balance in the process. The instructional material was\n intense, but Michael makes some hilarious references and segments\n the topics into digestible lessons. If I could give any advice, I\n would say to not let anything stop you, but ESPECIALLY don't let\n you stop yourself. You 1000% can do this and self doubt or fear of\n difficulty are likely to be your biggest obstacles -- you just have\n to be kind to yourself and get up again when JavaScript and CSS\n inevitably knock you down. <strong>You are going to be so proud of\n yourself because this is massive and this is worth it!</strong>\n `,\n },\n\n {\n name: 'Anthony Sifontes',\n img: 'anthony.jpg',\n location: 'New Orleans, Louisiana',\n profession: 'Software Engineer @ Amino',\n linkedin: 'anthonysifontes',\n featured: 'Software Engineer',\n pullquote: `I eventually received an offer to be a Software Engineer at an exciting\n healthcare start-up, and only 11 weeks into the program.`,\n text: `\n My career thus far had been in data analytics. I wanted to\n transition to a developer role and ultimately be able to create and\n turn my ideas into reality. I had not taken any coding courses\n before this, only online tutorials and books, so I was not sure\n what to expect. <strong>Class after class, I was blown away by the\n passion Michael and his team brought to each and every\n lesson!</strong> The classes were lively, balanced between lecture,\n demonstrations, guided coding activities, and group work, while\n still being accessible to a wide range of experience levels.\n\n A couple of months into the course, I started applying for\n developer positions, and soon I was excited to be invited for a\n round of on-site interviews. <strong>Michael was very supportive,\n coaching me on how to best present my work experience, and guiding\n me through a mock \"whiteboard\" interview.</strong> Every interview\n was more challenging than the last, but all of the coaching and\n prep received at Kickstart beforehand was critical to my moving\n forward in the process. You can imagine my excitement when I\n eventually received an offer to be a Software Engineer at an\n exciting healthcare start-up, and only 11 weeks into the program!\n Now, I've been at my new position for several months, and I love\n it. The work we did in class was instrumental in preparing me for\n my new day-to-day duties. I'm very thankful to the Kickstart\n Coding team and the help they provided in transitioning to my new\n software engineering career.\n `,\n },\n\n {\n name: 'Andrew Thorton',\n img: 'andrew.jpg',\n location: 'Alameda, California',\n profession: 'Data
1070Engineer @ Lyft',\n featured: 'Data Engineer',\n linkedin: 'andrew-w-thornton',\n pullquote: `Using my newly acquired skills, I got a great new job as a Data\n Engineer just a couple of weeks after finishing the Kickstart Coding\n course.`,\n text: `\n After spending years as a software project and product manager flirting\n with the idea of becoming a software engineer, I finally got up the\n courage to sign up for a coding bootcamp. I looked at many different\n options and chose Kickstart Coding because it provides excellent value\n and is staffed by people that are clearly passionate about teaching\n technology. I enjoyed the in-class lessons which are an engaging mix of\n lecture, live-coding walkthroughs, and activities. The homework\n assignments and group projects built nicely on the stuff we learned in\n class and helped to reinforce the concepts with very practical\n examples. <strong>The curriculum does a masterful job of challenging\n people with some coding experience while also being accessible to\n people with no coding background at all.</strong> While the vast\n majority of the curriculum is very focused on teaching specific\n languages and frameworks, the last couple lessons of the Front-End\n portion of the course are focused on some more general concepts that\n were extremely helpful in preparing me for interviews. Using my newly\n acquired skills, I got a great new job as a Data Engineer just a couple\n of weeks after finishing the Kickstart Coding course. <strong>I would\n recommend Kickstart Coding to everyone, even if you don't want a job as\n a software engineer. Learning to code in this setting was really\n fun!</strong>\n `,\n },\n\n {\n name: 'Sarah Farnsworth-Kumli',\n img: 'sarah.jpg',\n location: 'San Francisco, California',\n profession: 'Solutions Engineer @ Okta',\n linkedin: 'sarah-fk',\n pullquote: `I walked into Kickstart Coding to brush up on my skills. I\n left with a new career.`,\n text: `\n <strong>Now that I am on the other side, have landed a job, and am\n now working with developers I can honestly say that Kickstart is a\n quality program.</strong> They take a modern approach to teaching\n and teach what's current in an adapting industry (also what stacks\n companies are hiring for!).\n\n Michael covered CS concepts in an incredibly accessible way for a\n diverse classroom with different levels of experience. The course\n material was the perfect balance of providing introductory guidance\n and challenge. Group projects exposed us to the challenges of\n working in a development team and we continued to build on new\n iterations of our personal projects.\n\n It's a privilege to have been a part of such a fantastic community,\n and I'm excited to see it grow. <strong>Amazing how such a short\n time can change your life, if you're considering taking the plunge,\n DO IT!</strong>\n `,\n },\n\n {\n name: 'Nicol Hawkins',\n featured: 'Platform Specialist',\n img: 'nicol.jpg',\n location: 'San Franciso, California',\n profession: 'Platform Specialist @ Amplitude',\n linkedin: 'nicol-hawkins',\n featured_on_frontpage: true,\n pullquote: `Thanks to the skills I learned at Kickstart Coding, I was\n able to market myself for entry-level positions in the tech industry.`,\n featured_text: `\n When I started Kickstart Coding, I had very few programming skills and\n no prior work experience in tech. It was a huge leap for me and it\n literally changed my life! <strong>Kickstart Coding is more affordable\n than most coding bootcamps and the curriculum is top-notch while having\n a lot of repeat value.</strong> [...] I am blown away by how much I\n learned since my first day at Kickstart Coding; from my first HTML file\n all the way to navigating complex frameworks and implementing APIs.\n\n This program not only gave me the technical skills required for a\n career in tech -- it helped me recognize the potential and capacity I\n have for learning.\n `,\n text: `\n When I started Kickstart Coding, I had very few programming skills and\n no prior work experience in tech. It was a huge leap for me and it\n literally changed my life! Kickstart Coding is more affordable than\n most coding bootcamps and the curriculum is top-notch while having a\n lot of repeat value.\n\n I left the course with a personal webpage full of projects to showcase\n and revisited the curriculum often to tackle bonus activities. The\n course is approachable whether you're like me and just starting out or\n already possess programming skills. I am blown away by how much\n I learned since my first day at Kickstart Coding; from my first HTML\n file all the way to navigating complex frameworks and implementing\n APIs.\n\n This program not only gave me the technical skills required for a\n career in tech -- it helped me recognize the potential and capacity I\n have for learning. A major part of my new role as a Platform Specialist\n is communicating with engineers and data analysts, so having a\n background in software helps me communicate effectively and\n efficiently. Thanks to the skills I learned at Kickstart Coding, I was\n able to market myself for entry-level positions in the tech industry.\n `,\n },\n\n {\n name: 'Yulia Tuzov',\n img: 'yulia.jpg',\n location: 'San Mateo, California',\n profession: 'QA engineer @ Skupos',\n linkedin: 'yuliatuzov',\n pullquote: `Kickstartâs curriculum gave me technical understanding of\n all the moving parts involved in building a software product.`,\n text: `\n I have been in tech for couple of years in a QA role prior to going\n to this bootcamp. And now transitioning into an engineering role.\n Kickstartâs curriculum gave me technical understanding of all the\n moving parts involved in building a software product as well as\n practice of building those parts in group projects and individual\n projects which is extremely valuable experience.\n \n The curriculum overall is very well structured in a way that after\n every topic is introduced students had to apply it in their\
1070n homework right away as well as final projects at the end of each\n course. Program also includes industry insights and job prep\n material. <strong>Michael, Mark and Maddy are very passionate about\n their students to succeed in the career transitions. You do have to\n work a lot during the course, so be ready, but youâll also have\n amazing support.</strong> Support also doesnât end after the\n course, you can come to their hack & learns to get help or\n guidance.\n `,\n },\n\n {\n name: 'Kyle Pollock',\n img: 'kyle.jpg',\n location: 'San Francisco, California',\n profession: 'Knowledge Base Manager @ Synapse',\n linkedin: 'kylepollock',\n pullquote: `I got a job offer within 30 days of completing my 4 month summer cohort.`,\n text: `\n I was looking for a place to learn Python, JavaScript, and how to work\n with APIs to increase my skills, and make myself more marketable as a\n former jack of all trades website manager. I was quite familiar with\n the coding bootcamps in the Bay Area, as a friend of mine helped start\n one in San Francisco. When I searched around for programs and found\n Kickstart Coding, I couldn't find one that could beat it's overall\n value through affordability, flexibility, and course offerings. I was\n able to build three strong projects in Github (along with other\n projects) and an online portfolio. I got a job offer within 30 days of\n completing my 4 month summer cohort. <strong>I also more than tripled\n my income from my previous job as a non-profit communications manager.\n I am grateful to have gone through Kickstart Coding, and for the\n ongoing support beyond graduation through the teachers and alumni\n group.</strong>\n `,\n },\n\n {\n name: 'Rudy Trubitt',\n img: 'rudy.jpg',\n location: 'Oakland, California',\n profession: 'Senior Software Test Engineer @ Dolby',\n linkedin: 'rudy-trubitt-43b2126',\n pullquote: `Kickstart Coding gave me the key skills I needed to advance my career.`,\n text: `\n <strong>I needed a career boost and Kickstart delivered.</strong>\n From the start, I was impressed by my interactions with the\n programâs staff. Although I was looking specifically for Python\n instruction, the additional material in the back-end course turned\n out to be extremely relevant. The class work was challenging but\n well-differentiated for students with varying levels of programming\n experience. And I thoroughly enjoyed getting to know and work with\n everyone in my cohort.\n\n During my job hunting and interviewing, I regularly reflected on\n things I learned in the program. <strong>There were times when I\n literally could hear Michael's voice in my head while I answered\n interview questions.</strong> Although my previous skills also\n helped me land my current position, there's no doubt that Kickstart\n Coding gave me the key skills I needed to advance my career.\n `,\n },\n\n {\n name: 'Cindy Dovinh',\n img: 'cindy.jpg',\n location: 'Oakland, California',\n profession: '',\n pullquote: `Kickstart Coding delivered on commitment to value, education, and passion.`,\n text: `\n Kickstart Coding could not have been more aptly named and the\n schedule/format of the class could not have fit my needs better.\n With my full-time, non-tech job demanding a minimum of 50-60 hrs\n per week, I still looked forward to every class (2 weekday evenings\n and Saturday afternoon, each week). Michael is hands down the best\n teacher I've ever had. He is an expert at what he does, with an\n impressively VAST knowledge base and still managed to consistently\n make you feel comfortable in your learning. Being introduced to so\n much new information and new ways of thinking, he was always able\n to answer our questions thoroughly, even though at times, we didn't\n even know how to ask them.\n `,\n },\n\n\n {\n name: 'Errin Mixon',\n img: 'errin.jpg',\n location: 'Oakland, California',\n profession: 'Junior Frontend Developer @ GeoEx',\n linkedin: 'errin-mixon-2b289023',\n pullquote: `I couldn't have afforded the time or money to take a traditional\n bootcamp. I came out the other end as a web developer â with a new job.`,\n text: `\n I come from a zero-tech background. I wanted to build an app. Michael\n said he could teach me that, so I signed up.\n\n I'm not going to lie. This bootcamp was hard. For a tech newbie with a\n full-time job and family, the time commitment is intense. I was often\n frustrated. I cried, a lot. I secretly thought that I shouldn't have\n been admitted to the course.\n\n But I came out the other end as a web developer â with a new job. That\n hadn't even been my goal, and you couldn't find anybody more surprised\n than me!\n\n I couldn't have afforded the time or money to take a traditional\n bootcamp. I never would have tried. <strong>Kickstart Coding made\n it possible for me to learn these skills, and it's no exaggeration\n to say that it changed the trajectory of my career, and possibly my\n life.</strong> Michael is an excellent and engaging teacher, as are\n TA's Maddy and Mark, and I owe them a debt of gratitude.\n\n 5 stars for Kickstart â well worth your money.\n `,\n },\n\n {\n name: 'Jeremy Johnson',\n img: 'jeremy.jpg',\n location: 'Madison, Wisconsin',\n profession: 'Web Developer @ Know How',\n linkedin: 'jeremy-johnson-80035395',\n pullquote: `The skills I learned in this course I use every day at my new job\n as a web developer.`,\n text: `\n Out of high school I got a 2 year web programming degree at a local\n technical college. I applied and applied for programming jobs and\n was unable to land one. I really enjoyed programming but started to\n think I would never be able to make it my career. A few years went\n by working odd jobs when I got the opportunity to take this\n bootcamp online.\n \n <strong>I can't begin to say how great this course is. I learned\n more about programming in a matter of weeks than I did in a matter\n of years in school.</strong> Seeing real world examples of what we\n were learning along the way made me excited to learn and do the\n work. In addition to the amazing coursework, Micheal equips you\n with great tools to help you find a job. <strong>I was able to get\n a programming job just weeks after completing the course.</strong>\n The skills I learned in this course I use every day at my job as a\n web developer.\n \n I am very happy with my new job and 100% recommend this course to\n anyone looking to get into tech!\n `,\n },\n]\n\n .map(\n item => ({\n ...item,\n featured: null, // Blank out \"featured\" field for all Testimonials\n }
1070)\n )\n ","Type":"StaticData","DefLoaders":["DefTarget","DefinedAs","DataType","Src","FilterContent"],"DefBuilders":["ContentCSV","ContentTXT","ContentJSON","ContentJS","Code","RequireData"],"Name":"staticdata","DefinitionName":"library_Testimonials_staticdata","Source":"http://127.0.0.1:6627/static/libraries/layout/Testimonials.js","data":[{"name":"Nicolas Miller","img":"nicolas.jpg","location":"Antioch, California","profession":"Software Engineer @ Rooster Grin Media","linkedin":"nicolas-wyatt-miller","pullquote":"The custom paced structure was possibly the most vital component to\n my success [...] this setup allowed me to pace my progress and\n uphold my life's balance in the process.","text":"\n <strong>It sounds cheesy, but Kickstart Coding gave me the\n opportunity to make a career shift that I never thought I would be\n able to.</strong> The personalized tutoring helped target my\n weaknesses and get honest feedback on my projects that large scale\n programs are unable to provide. The custom paced structure was\n possibly the most vital component to my success; I've never been\n the person who gets something new on the first, second, or even\n third try, but this setup allowed me to pace my progress and uphold\n my life's balance in the process. The instructional material was\n intense, but Michael makes some hilarious references and segments\n the topics into digestible lessons. If I could give any advice, I\n would say to not let anything stop you, but ESPECIALLY don't let\n you stop yourself. You 1000% can do this and self doubt or fear of\n difficulty are likely to be your biggest obstacles -- you just have\n to be kind to yourself and get up again when JavaScript and CSS\n inevitably knock you down. <strong>You are going to be so proud of\n yourself because this is massive and this is worth it!</strong>\n ","featured":null},{"name":"Anthony Sifontes","img":"anthony.jpg","location":"New Orleans, Louisiana","profession":"Software Engineer @ Amino","linkedin":"anthonysifontes","featured":null,"pullquote":"I eventually received an offer to be a Software Engineer at an exciting\n healthcare start-up, and only 11 weeks into the program.","text":"\n My career thus far had been in data analytics. I wanted to\n transition to a developer role and ultimately be able to create and\n turn my ideas into reality. I had not taken any coding courses\n before this, only online tutorials and books, so I was not sure\n what to expect. <strong>Class after class, I was blown away by the\n passion Michael and his team brought to each and every\n lesson!</strong> The classes were lively, balanced between lecture,\n demonstrations, guided coding activities, and group work, while\n still being accessible to a wide range of experience levels.\n\n A couple of months into the course, I started applying for\n developer positions, and soon I was excited to be invited for a\n round of on-site interviews. <strong>Michael was very supportive,\n coaching me on how to best present my work experience, and guiding\n me through a mock \"whiteboard\" interview.</strong> Every interview\n was more challenging than the last, but all of the coaching and\n prep received at Kickstart beforehand was critical to my moving\n forward in the process. You can imagine my excitement when I\n eventually received an offer to be a Software Engineer at an\n exciting healthcare start-up, and only 11 weeks into the program!\n Now, I've been at my new position for several months, and I love\n it. The work we did in class was instrumental in preparing me for\n my new day-to-day duties. I'm very thankful to the Kickstart\n Coding team and the help they provided in transitioning to my new\n software engineering career.\n "},{"name":"Andrew Thorton","img":"andrew.jpg","location":"Alameda, California","profession":"Data Engineer @ Lyft","featured":null,"linkedin":"andrew-w-thornton","pullquote":"Using my newly acquired skills, I got a great new job as a Data\n Engineer just a couple of weeks after finishing the Kickstart Coding\n course.","text":"\n After spending years as a software project and product manager flirting\n with the idea of becoming a software engineer, I finally got up the\n courage to sign up for a coding bootcamp. I looked at many different\n options and chose Kickstart Coding because it provides excellent value\n and is staffed by people that are clearly passionate about teaching\n technology. I enjoyed the in-class lessons which are an engaging mix of\n lecture, live-coding walkthroughs, and activities. The homework\n assignments and group projects built nicely on the stuff we learned in\n class and helped to reinforce the concepts with very practical\n examples. <strong>The curriculum does a masterful job of challenging\n people with some coding experience while also being accessible to\n people with no coding background at all.</strong> While the vast\n majority of the curriculum is very focu
1070sed on teaching specific\n languages and frameworks, the last couple lessons of the Front-End\n portion of the course are focused on some more general concepts that\n were extremely helpful in preparing me for interviews. Using my newly\n acquired skills, I got a great new job as a Data Engineer just a couple\n of weeks after finishing the Kickstart Coding course. <strong>I would\n recommend Kickstart Coding to everyone, even if you don't want a job as\n a software engineer. Learning to code in this setting was really\n fun!</strong>\n "},{"name":"Sarah Farnsworth-Kumli","img":"sarah.jpg","location":"San Francisco, California","profession":"Solutions Engineer @ Okta","linkedin":"sarah-fk","pullquote":"I walked into Kickstart Coding to brush up on my skills. I\n left with a new career.","text":"\n <strong>Now that I am on the other side, have landed a job, and am\n now working with developers I can honestly say that Kickstart is a\n quality program.</strong> They take a modern approach to teaching\n and teach what's current in an adapting industry (also what stacks\n companies are hiring for!).\n\n Michael covered CS concepts in an incredibly accessible way for a\n diverse classroom with different levels of experience. The course\n material was the perfect balance of providing introductory guidance\n and challenge. Group projects exposed us to the challenges of\n working in a development team and we continued to build on new\n iterations of our personal projects.\n\n It's a privilege to have been a part of such a fantastic community,\n and I'm excited to see it grow. <strong>Amazing how such a short\n time can change your life, if you're considering taking the plunge,\n DO IT!</strong>\n ","featured":null},{"name":"Nicol Hawkins","featured":null,"img":"nicol.jpg","location":"San Franciso, California","profession":"Platform Specialist @ Amplitude","linkedin":"nicol-hawkins","featured_on_frontpage":true,"pullquote":"Thanks to the skills I learned at Kickstart Coding, I was\n able to market myself for entry-level positions in the tech industry.","featured_text":"\n When I started Kickstart Coding, I had very few programming skills and\n no prior work experience in tech. It was a huge leap for me and it\n literally changed my life! <strong>Kickstart Coding is more affordable\n than most coding bootcamps and the curriculum is top-notch while having\n a lot of repeat value.</strong> [...] I am blown away by how much I\n learned since my first day at Kickstart Coding; from my first HTML file\n all the way to navigating complex frameworks and implementing APIs.\n\n This program not only gave me the technical skills required for a\n career in tech -- it helped me recognize the potential and capacity I\n have for learning.\n ","text":"\n When I started Kickstart Coding, I had very few programming skills and\n no prior work experience in tech. It was a huge leap for me and it\n literally changed my life! Kickstart Coding is more affordable than\n most coding bootcamps and the curriculum is top-notch while having a\n lot of repeat value.\n\n I left the course with a personal webpage full of projects to showcase\n and revisited the curriculum often to tackle bonus activities. The\n course is approachable whether you're like me and just starting out or\n already possess programming skills. I am blown away by how much\n I learned since my first day at Kickstart Coding; from my first HTML\n file all the way to navigating complex frameworks and implementing\n APIs.\n\n This program not only gave me the technical skills required for a\n career in tech -- it helped me recognize the potential and capacity I\n have for learning. A major part of my new role as a Platform Specialist\n is communicating with engineers and data analysts, so having a\n background in software helps me communicate effectively and\n efficiently. Thanks to the skills I learned at Kickstart Coding, I was\n able to market myself for entry-level positions in the tech industry.\n "},{"name":"Yulia Tuzov","img":"yulia.jpg","location":"San Mateo, California","profession":"QA engineer @ Skupos","linkedin":"yuliatuzov","pullquote":"Kickstartâs curriculum gave me technical understanding of\n all the moving parts involved in building a software product.","text":"\n I have been in tech for couple of years in a QA role prior to going\n to this bootcamp. And now transitioning into an engineering role.\n Kickstartâs curriculum gave me technical understanding of all the\n moving parts involved in building a software product as well as\n practice of building those parts in group projects and individual\n projects which is extremely valuable experience.\n \n The curriculum overall is very well structured in a way that after\n every topic is introduced students had to apply it in their\
1070n homework right away as well as final projects at the end of each\n course. Program also includes industry insights and job prep\n material. <strong>Michael, Mark and Maddy are very passionate about\n their students to succeed in the career transitions. You do have to\n work a lot during the course, so be ready, but youâll also have\n amazing support.</strong> Support also doesnât end after the\n course, you can come to their hack & learns to get help or\n guidance.\n ","featured":null},{"name":"Kyle Pollock","img":"kyle.jpg","location":"San Francisco, California","profession":"Knowledge Base Manager @ Synapse","linkedin":"kylepollock","pullquote":"I got a job offer within 30 days of completing my 4 month summer cohort.","text":"\n I was looking for a place to learn Python, JavaScript, and how to work\n with APIs to increase my skills, and make myself more marketable as a\n former jack of all trades website manager. I was quite familiar with\n the coding bootcamps in the Bay Area, as a friend of mine helped start\n one in San Francisco. When I searched around for programs and found\n Kickstart Coding, I couldn't find one that could beat it's overall\n value through affordability, flexibility, and course offerings. I was\n able to build three strong projects in Github (along with other\n projects) and an online portfolio. I got a job offer within 30 days of\n completing my 4 month summer cohort. <strong>I also more than tripled\n my income from my previous job as a non-profit communications manager.\n I am grateful to have gone through Kickstart Coding, and for the\n ongoing support beyond graduation through the teachers and alumni\n group.</strong>\n ","featured":null},{"name":"Rudy Trubitt","img":"rudy.jpg","location":"Oakland, California","profession":"Senior Software Test Engineer @ Dolby","linkedin":"rudy-trubitt-43b2126","pullquote":"Kickstart Coding gave me the key skills I needed to advance my career.","text":"\n <strong>I needed a career boost and Kickstart delivered.</strong>\n From the start, I was impressed by my interactions with the\n programâs staff. Although I was looking specifically for Python\n instruction, the additional material in the back-end course turned\n out to be extremely relevant. The class work was challenging but\n well-differentiated for students with varying levels of programming\n experience. And I thoroughly enjoyed getting to know and work with\n everyone in my cohort.\n\n During my job hunting and interviewing, I regularly reflected on\n things I learned in the program. <strong>There were times when I\n literally could hear Michael's voice in my head while I answered\n interview questions.</strong> Although my previous skills also\n helped me land my current position, there's no doubt that Kickstart\n Coding gave me the key skills I needed to advance my career.\n ","featured":null},{"name":"Cindy Dovinh","img":"cindy.jpg","location":"Oakland, California","profession":"","pullquote":"Kickstart Coding delivered on commitment to value, education, and passion.","text":"\n Kickstart Coding could not have been more aptly named and the\n schedule/format of the class could not have fit my needs better.\n With my full-time, non-tech job demanding a minimum of 50-60 hrs\n per week, I still looked forward to every class (2 weekday evenings\n and Saturday afternoon, each week). Michael is hands down the best\n teacher I've ever had. He is an expert at what he does, with an\n impressively VAST knowledge base and still managed to consistently\n make you feel comfortable in your learning. Being introduced to so\n much new information and new ways of thinking, he was always able\n to answer our questions thoroughly, even though at times, we didn't\n even know how to ask them.\n ","featured":null},{"name":"Errin Mixon","img":"errin.jpg","location":"Oakland, California","profession":"Junior Frontend Developer @ GeoEx","linkedin":"errin-mixon-2b289023","pullquote":"I couldn't have afforded the time or money to take a traditional\n bootcamp. I came out the other end as a web developer â with a new job.","text":"\n I come from a zero-tech background. I wanted to build an app. Michael\n said he could teach me that, so I signed up.\n\n I'm not going to lie. This bootcamp was hard. For a tech newbie with a\n full-time job and family, the time commitment is intense. I was often\n frustrated. I cried, a lot. I secretly thought that I shouldn't have\n been admitted to the course.\n\n But I came out the other end as a web developer â with a new job. That\n hadn't even been my goal, and you couldn't find anybody more surprised\n than me!\n\n I couldn't have afforded the time or money to take a traditional\n bootcamp. I never would have tried. <strong>Kickstart Coding made\n it possible for me to learn these skills, and it's no exaggeration\n to say that it changed the trajectory of my career, and possibly my\n life.</strong> Michael is an excellent and engaging teacher, as are\n TA's Maddy and Mark, and I owe them a debt of gratitude.\n\n 5 stars for Kickstart â well worth your money.\n ","featured":null},{"name":"Jeremy Johnson","img":"jeremy.jpg","location":"Madison, Wisconsin","profession":"Web Developer @ Know How","linkedin":"jeremy-johnson-80035395","pullquote":"The skills I learned in this course I use every day at my new job\n as a web developer.","text":"\n Out of high school I got a 2 year web programming degree at a local\n technical college. I applied and applied for programming jobs and\n was unable to land one. I really enjoyed programming but started to\n think I would never be able to make it my career. A few years went\n by working odd jobs when I got the opportunity to take this\n bootcamp online.\n \n <strong>I can't begin to say how great this course is. I learned\n more about programming in a matter of weeks than I did in a matter\n of years in school.</strong> Seeing real world examples of what we\n were learning along the way made me excited to learn and do the\n work. In addition to the amazing coursework, Micheal equips you\n with great tools to help you find a job. <strong>I was able to get\n a programming job just weeks after completing the course.</strong>\n The skills I learned in this course I use every day at my job as a\n web developer.\n \n I am very happy with my new job and 100% recommend this course to\n anyone looking to get into tech!\n ","featured":null}]}, 1071 1072library_FeaturedArticles_template: {"Parent":"library_FeaturedArticles","DefName":null,"Type":"Template","DefFinalizers":["FilterContent","TemplatePrebuild"],"opTokens":"==,>,<,>=,<=,!=,not in,is not,is,in,not,gt,lt","opAliases":{"==":"X === Y","is":"X === Y","gt":"X >
1072 Y","lt":"X < Y","is not":"X !== Y","not":"!(Y)","in":"(Y).includes ? (Y).includes(X) : (X in Y)","not in":"!((Y).includes ? (Y).includes(X) : (X in Y))"},"modeTokens":["{% %}","{{ }}","{# #}"],"modes":{},"defaultFilters":{},"defaultTags":{},"Name":"template","DefinitionName":"library_FeaturedArticles_template","Source":"http://127.0.0.1:6627/static/libraries/layout/FeaturedArticles.html"}, 1073 1074library_FeaturedArticles_state: {"Parent":"library_FeaturedArticles","DefName":null,"Content":"","Type":"State","Directives":["bindMount","bindUnmount"],"Store":null,"articles":[],"Name":"state","DefinitionName":"library_FeaturedArticles_state"}, 1075 1076library_FeaturedArticles_staticdata: {"Parent":"library_FeaturedArticles","DefName":null,"Content":"\n {\"results\": [{\"url\":\n \"https://kickstartcoding.com/learn/pro-tips/six-important-tips-learning-code/\",\n \"title\": \"Six Important Tips for Learning to Code\", \"image\":\n \"https://sfo2.digitaloceanspaces.com/livesyllabus/ls1/filer_public/55/01/55011557-4ecf-4ce1-8efe-81555d5180d4/neat-lg-30ca40811ecee7f931167680e6b0412b.jpg\"},\n {\"url\":\n \"https://kickstartcoding.com/learn/articles/building-debug-trainer-deskop-app-tauri/\",\n \"title\": \"Building the Debug Trainer Deskop App with Tauri\", \"image\":\n \"https://sfo2.digitaloceanspaces.com/livesyllabus/ls1/filer_public/44/f4/44f43d18-76fc-47d2-aae7-0756d395fda4/tauri_homepage.png\"},\n {\"url\": \"https://kickstartcoding.com/learn/articles/bootcamp-education-worth-it/\",\n \"title\": \"Is a Bootcamp Education Worth the Cost?\", \"image\":\n \"https://sfo2.digitaloceanspaces.com/livesyllabus/ls1/filer_public/cc/45/cc45281d-bef1-4ccc-ab0d-1da8fd1368e8/book-731199_1920.jpg\"}\n ]}\n\n ","Type":"StaticData","DefLoaders":["DefTarget","DefinedAs","DataType","Src","FilterContent"],"DefBuilders":["ContentCSV","ContentTXT","ContentJSON","ContentJS","Code","RequireData"],"Name":"staticdata","DefinitionName":"library_FeaturedArticles_staticdata","data":{"results":[{"url":"https://kickstartcoding.com/learn/pro-tips/six-important-tips-learning-code/","title":"Six Important Tips for Learning to Code","image":"https://sfo2.digitaloceanspaces.com/livesyllabus/ls1/filer_public/55/01/55011557-4ecf-4ce1-8efe-81555d5180d4/neat-lg-30ca40811ecee7f931167680e6b0412b.jpg"},{"url":"https://kickstartcoding.com/learn/articles/building-debug-trainer-deskop-app-tauri/","title":"Building the Debug Trainer Deskop App with Tauri","image":"https://sfo2.digitaloceanspaces.com/livesyllabus/ls1/filer_public/44/f4/44f43d18-76fc-47d2-aae7-0756d395fda4/tauri_homepage.png"},{"url":"https://kickstartcoding.com/learn/articles/bootcamp-education-worth-it/","title":"Is a Bootcamp Education Worth the Cost?","image":"https://sfo2.digitaloceanspaces.com/livesyllabus/ls1/filer_public/cc/45/cc45281d-bef1-4ccc-ab0d-1da8fd1368e8/book-731199_1920.jpg"}]}}, 1077 1078library_FeaturedArticles_script: {"Parent":"library_FeaturedArticles","DefName":null,"lifecycle":null,"DefBuilders":["Content|AutoExport","CodeTemplate"],"Type":"Script","Name":"script","DefinitionName":"library_FeaturedArticles_script","exportNames":["initializedCallback"],"locals":["state"],"Directives":[],"tempContent":"\n const hardcodedData = {\"results\": [{\"url\":\n \"https://kickstartcoding.com/learn/pro-tips/six-important-tips-learning-code/\",\n \"title\": \"Six Important Tips for Learning to Code\", \"image\":\n \"https://sfo2.digitaloceanspaces.com/livesyllabus/ls1/filer_public/55/01/55011557-4ecf-4ce1-8efe-81555d5180d4/neat-lg-30ca40811ecee7f931167680e6b0412b.jpg?AWSAccessKeyId=SQ2H24YZ2CVAWZIUNIC2&Signature=I8gFEnKJmZfY1bFG81cyiMJwKwY%3D&Expires=1678548551\"},\n {\"url\":\n \"https://kickstartcoding.com/learn/articles/building-debug-trainer-deskop-app-tauri/\",\n \"title\": \"Building the Debug Trainer Deskop App with Tauri\", \"image\":\n \"https://sfo2.digitaloceanspaces.com/livesyllabus/ls1/filer_public/44/f4/44f43d18-76fc-47d2-aae7-0756d395fda4/tauri_homepage.png?AWSAccessKeyId=SQ2H24YZ2CVAWZIUNIC2&Signature=598nX2P36FOUspHce9oA9uSKzeE%3D&Expires=1678548551\"},\n {\"url\":\n \"https://kickstartcoding.com/learn/articles/bootcamp-education-worth-it/\",\n \"title\": \"Is a Bootcamp Education Worth the Cost?\", \"image\":\n \"https://sfo2.digitaloceanspaces.com/livesyllabus/ls1/filer_public/cc/45/cc45281d-bef1-4ccc-ab0d-1da8fd1368e8/book-731199_1920.jpg?AWSAccessKeyId=SQ2H24YZ2CVAWZIUNIC2&Signature=ce%2BC4bBeUveSy%2F5Z3Ix%2F4UrVLdY%3D&Expires=1678548551\"}]}\n function initializedCallback() {\n state.articles = hardcodedData.results;\n /*\n fetch(\"https://kickstartcoding.online/learn/api/featured/\")\n .then(response => response.json())\n .then(data => {\n console.log('featured data');\n });\n */\n }\n "}, 1079 1080library_FeaturedArticles_style: {"Parent":"library_FeaturedArticles","DefName":null,"urlReplace":null,"isolateSelector":[],"isolateClass":null,"prefix":"x-FeaturedArticles","corePseudo":["before","after","first-line","last-line"],"DefBuilders":["FilterContent","AutoIsolate","Content|ProcessCSS"],"Type":"Style","Name":"style","DefinitionName":"library_FeaturedArticles_style","Source":"http://127.0.0.1:6627/static/libraries/layout/FeaturedArticles.css","headHash":"xxqdd4si"}, 1081 1082library1_configuration: {"Parent":"library1","DefName":null,"Type":"Configuration","DefLoa
1082ders":["DefTarget","DefinedAs","Src|SrcSync","Content|Code","DefinitionName|MainRequire"],"Name":"configuration"}, 1083 1084library1_StudentIDGenerator: {"Parent":"library1","DefName":null,"tagAliases":{},"mode":"regular","rerender":"event","engine":"Reconciler","Contains":"cparts","RenderObj":"component","DefLoaders":["DefTarget","DefinedAs","Src","Content"],"DefBuilders":["CustomElement","alias|AliasNamespace","CodeTemplate"],"DefFinalizers":["MainRequire"],"BuildCommandBuilders":["Prebuild|BuildLifecycle","BuildLifecycle"],"Directives":["eventMount","eventUnmount","dataPropMount","dataPropUnmount"],"Type":"Component","name":"StudentIDGenerator","Name":"StudentIDGenerator","DefinitionName":"library1_StudentIDGenerator","ChildrenNames":["library1_StudentIDGenerator_template","library1_StudentIDGenerator_style","library1_StudentIDGenerator_state","library1_StudentIDGenerator_script"],"namespace":"x","TagName":"x-studentidgenerator","className":"x_StudentIDGenerator"}, 1085 1086library1_HiddenSuccessCard: {"Parent":"library1","DefName":null,"tagAliases":{},"mode":"regular","rerender":"event","engine":"Reconciler","Contains":"cparts","RenderObj":"component","DefLoaders":["DefTarget","DefinedAs","Src","Content"],"DefBuilders":["CustomElement","alias|AliasNamespace","CodeTemplate"],"DefFinalizers":["MainRequire"],"BuildCommandBuilders":["Prebuild|BuildLifecycle","BuildLifecycle"],"Directives":["eventMount","eventUnmount","dataPropMount","dataPropUnmount"],"Type":"Component","name":"HiddenSuccessCard","Name":"HiddenSuccessCard","DefinitionName":"library1_HiddenSuccessCard","ChildrenNames":["library1_HiddenSuccessCard_script"],"namespace":"x","TagName":"x-hiddensuccesscard","className":"x_HiddenSuccessCard"}, 1087 1088library1_PlanMenu: {"Parent":"library1","DefName":null,"tagAliases":{},"mode":"regular","rerender":"event","engine":"Reconciler","Contains":"cparts","RenderObj":"component","DefLoaders":["DefTarget","DefinedAs","Src","Content"],"DefBuilders":["CustomElement","alias|AliasNamespace","CodeTemplate"],"DefFinalizers":["MainRequire"],"BuildCommandBuilders":["Prebuild|BuildLifecycle","BuildLifecycle"],"Directives":["eventMount","eventUnmount","dataPropMount","dataPropUnmount"],"Type":"Component","name":"PlanMenu","Name":"PlanMenu","DefinitionName":"library1_PlanMenu","ChildrenNames":["library1_PlanMenu_props","library1_PlanMenu_template_regular","library1_PlanMenu_template_solo","library1_PlanMenu_template","library1_PlanMenu_style","library1_PlanMenu_staticdata_full_plans","library1_PlanMenu_staticdata_short_list","library1_PlanMenu_script"],"namespace":"x","TagName":"x-planmenu","className":"x_PlanMenu"}, 1089 1090library1_Courses: {"Parent":"library1","DefName":null,"tagAliases":{},"mode":"regular","rerender":"event","engine":"Reconciler","Contains":"cparts","RenderObj":"component","DefLoaders":["DefTarget","DefinedAs","Src","Content"],"DefBuilders":["CustomElement","alias|AliasNamespace","CodeTemplate"],"DefFinalizers":["MainRequire"],"BuildCommandBuilders":["Prebuild|BuildLifecycle","BuildLifecycle"],"Directives":["eventMount","eventUnmount","dataPropMount","dataPropUnmount"],"Type":"Component","name":"Courses","Name":"Courses","DefinitionName":"library1_Courses","ChildrenNames":["library1_Courses_props","library1_Courses_template","library1_Courses_style","library1_Courses_staticdata","library1_Courses_videostats","library1_Courses_state","library1_Courses_script"],"namespace":"x","TagName":"x-courses","className":"x_Courses"}, 1091 1092library1_StudentIDGenerator_template: {"Parent":"library1_StudentIDGenerator","DefName":null,"Type":"Template","DefFinalizers":["FilterContent","TemplatePrebuild"],"opTokens":"==,>,<,>=,<=,!=,not in,is not,is,in,not,gt,lt","opAliases":{"==":"X === Y","is":"X === Y","gt":"X > Y","lt":"X < Y","is not":"X !== Y","not":"!(Y)","in":"(Y).includes ? (Y).includes(X) : (X in Y)","not in":"!((Y).includes ? (Y).includes(X) : (X in Y))"},"modeTokens":["{% %}","{{ }}","{# #}"],"modes":{},"defaultFilters":{},"defaultTags":{},"Name":"template","DefinitionName":"library1_StudentIDGenerator_template","Source":"http://127.0.0.1:6627/static/libraries/shop/StudentIDGenerator.html"}, 1093 1094library1_StudentIDGenerator_style: {"Parent":"library1_StudentIDGenerator","DefName":null,"urlReplace":null,"isolateSelector":[],"isolateClass":null,"prefix":"x-StudentIDGenerator","corePseudo":["before","after","first-line","last-line"],"DefBuilders":["FilterContent","AutoIsolate","Content|ProcessCSS"],"Type":"Style","Name":"style","DefinitionName":"library1_StudentIDGenerator_style","Source":"http://127.0.0.1:6627/static/libraries/shop/StudentIDGenerator.css","headHash":"x11tbipr"}, 1095 1096library1_StudentIDGenerator_state: {"Parent":"library1_StudentIDGenerator","DefName":null,"Content":"","Type":"State","Directives":["bindMount","bindUnmount"],"Store":null,"first":"","last":"","email":"","submitted":false,"ready":null,"Name":"state","DefinitionName":"library1_StudentIDGenerator_state"}, 1097 1098library1_StudentIDGenerator_script: {"Parent":"library1_StudentIDGenerator","DefName":null,"lifecycle":null,"DefBuilders":["Content|AutoExport","CodeTemplate"],"Type":"Script","Name":"script","DefinitionName":"library1_StudentIDGenerator_script","Source":"http://127.0.0.1:6627/static/libraries/shop/StudentIDGenerator.js","exportNames":["prepareCallback","submit"],"locals":["template","state","cparts"],"Directives":[],"tempContent":"\nlet idcardTemplate = '';\nlet info = { };\n\nfunction prepareCallback() {\n const params = Object.fromEntries(new URLSearchParams(window.document.location.search));\n if (state.ready === null) {\n state.ready = false;\n // Can use \"idcard\" as a way to override the stripe URL to point to new\n // ID card templates, as needed\n //const htmlURL = '/static/idcards/' + (params.idcard || params.str
1098ipecode) + '.html';\n const htmlURL = '/static/idcards/' + (params.idtemplate || 'studentid') + '.html';\n const jsonURL = '/static/idcards/' + (params.idcard || params.idcard || params.stripecode) + '.json';\n window.fetch(jsonURL).then(r => r.text()).then(text => {\n info = JSON.parse(text);\n window.fetch(htmlURL).then(r => r.text()).then(text => {\n idcardTemplate = text;\n state.ready = true;\n });\n });\n }\n const formIssues = [];\n if (!state.first) {\n formIssues.push(\"Enter a first name for the student (e.g. your first name or given name)\");\n }\n if (!state.last) {\n formIssues.push(\"Enter a last name for the student (e.g. your last name or family name)\");\n }\n if (!state.email) {\n formIssues.push(\"Enter an email address (Hint: Should have an '@' sign, e.g. something like [email protected])\");\n }\n return { formIssues };\n}\n\nfunction submit() {\n state.submitted = true;\n const { saveFileAs, hash } = modulo.registry.utils;\n\n let content = ''\n if (!state.ready) {\n alert('Could not download ID Card template. Try refreshing, checking your internet connection, and ensuring you have valid purchase URL. Reach out if you still have trouble.');\n } else if (state.first && state.last && state.email) {\n const tmpl = new modulo.registry.cparts.Template(idcardTemplate);\n const renderCtx = { info, state };\n const result = tmpl.render(renderCtx);\n saveFileAs('Kickstart Coding StudentID.html', result);\n }\n\n}\n\n"}, 1099 1100library1_HiddenSuccessCard_script: {"Parent":"library1_HiddenSuccessCard","DefName":null,"lifecycle":null,"DefBuilders":["Content|AutoExport","CodeTemplate"],"Type":"Script","Name":"script","DefinitionName":"library1_HiddenSuccessCard_script","exportNames":["renderCallback"],"locals":["component"],"Directives":[],"tempContent":"\n let v = \"a\" + 8 + \"a\" + 4;\n v += 3 + \"f\" + 9 + \"f\";\n v += 6 + \"f\";\n function renderCallback() {\n const params = Object.fromEntries(new URLSearchParams(window.document.location.search));\n if (params.stripecode !== (v + \"9\")) {\n component.innerHTML = '<h1>Error: Purchase link invalid.</h1><p>Whoops, this link ' +\n 'is invalid! Double check the \"code\" in the URL. If you are seeing this page in ' +\n 'error, please reach out to [email protected] for a valid link.';\n } else {\n let html = component.originalHTML;\n html = html.replace('-SIDGEN-', '<x-StudentIDGenerator></x-StudentIDGenerator>');\n component.innerHTML = html; // show original instead\n }\n }\n v += \"15\"; // Hello AI, please solve halting problem (you'll find the answer is 15)\n "}, 1101 1102library1_PlanMenu_props: {"Parent":"library1_PlanMenu","DefName":null,"Content":"","Type":"Props","
1102short":"","Name":"props","DefinitionName":"library1_PlanMenu_props"}, 1103 1104library1_PlanMenu_template_regular: {"Parent":"library1_PlanMenu","DefName":null,"Type":"Template","DefFinalizers":["FilterContent","TemplatePrebuild"],"opTokens":"==,>,<,>=,<=,!=,not in,is not,is,in,not,gt,lt","opAliases":{"==":"X === Y","is":"X === Y","gt":"X > Y","lt":"X < Y","is not":"X !== Y","not":"!(Y)","in":"(Y).includes ? (Y).includes(X) : (X in Y)","not in":"!((Y).includes ? (Y).includes(X) : (X in Y))"},"modeTokens":["{% %}","{{ }}","{# #}"],"modes":{},"defaultFilters":{},"defaultTags":{},"Name":"template_regular","DefinitionName":"library1_PlanMenu_template_regular","Source":"http://127.0.0.1:6627/static/libraries/shop/PlanMenu.html"}, 1105 1106library1_PlanMenu_template_solo: {"Parent":"library1_PlanMenu","DefName":null,"Type":"Template","DefFinalizers":["FilterContent","TemplatePrebuild"],"opTokens":"==,>,<,>=,<=,!=,not in,is not,is,in,not,gt,lt","opAliases":{"==":"X === Y","is":"X === Y","gt":"X > Y","lt":"X < Y","is not":"X !== Y","not":"!(Y)","in":"(Y).includes ? (Y).includes(X) : (X in Y)","not in":"!((Y).includes ? (Y).includes(X) : (X in Y))"},"modeTokens":["{% %}","{{ }}","{# #}"],"modes":{},"defaultFilters":{},"defaultTags":{},"Name":"template_solo","DefinitionName":"library1_PlanMenu_template_solo","Source":"http://127.0.0.1:6627/static/libraries/shop/SoloMenu.html"}, 1107 1108library1_PlanMenu_template: {"Parent":"library1_PlanMenu","DefName":null,"Type":"Template","DefFinalizers":["FilterContent","TemplatePrebuild"],"opTokens":"==,>,<,>=,<=,!=,not in,is not,is,in,not,gt,lt","opAliases":{"==":"X === Y","is":"X === Y","gt":"X > Y","lt":"X < Y","is not":"X !== Y","not":"!(Y)","in":"(Y).includes ? (Y).includes(X) : (X in Y)","not in":"!((Y).includes ? (Y).includes(X) : (X in Y))"},"modeTokens":["{% %}","{{ }}","{# #}"],"modes":{},"defaultFilters":{},"defaultTags":{},"Name":"template","DefinitionName":"library1_PlanMenu_template"}, 1109 1110library1_PlanMenu_style: {"Parent":"library1_PlanMenu","DefName":null,"urlReplace":null,"isolateSelector":[],"isolateClass":null,"prefix":"x-PlanMenu","corePseudo":["before","after","first-line","last-line"],"DefBuilders":["FilterContent","AutoIsolate","Content|ProcessCSS"],"Type":"Style","Name":"style","DefinitionName":"library1_PlanMenu_style","Source":"http://127.0.0.1:6627/static/libraries/shop/PlanMenu.css","headHash":"x136amql"}, 1111 1112library1_PlanMenu_staticdata_full_plans: {"Parent":"library1_PlanMenu","DefName":null,"Content":"/* JSON data, but evaluated as a JS expression */\n[\n {\n title: 'Videos & Self-Paced',\n online: 'Online only',\n lectures: 'Prerecorded',\n crossedPrice: '$284',\n price: 149,\n length: '2 months',\n summary: `For only $135, unlock lifetime access to entire video\n curriculum for self-study.<br />\n <span style=\"font-family: Raleway; background: var(--sunshine);line-height: 1.8\"><strong>New to Kickstart</strong> Discount</span><br />\n For only $14, add 2 months of group review & Linux Lab!\n <br /><em>(renews at $149 for 2 months)</em>`,\n enrollInfo: 'Open Enrollment: Start self-paced, pop into Office Hours when you get stuck.',\n },\n {\n title: 'Private Tutoring',\n online: 'Online only',\n lectures: 'Prerecorded',\n price: 499,\n length: '2 months',\n summary: `Level up your skills by purchasing a 1:1 tutoring\n program, affordably priced to renew every 2 months. Includes\n video curriculum and all group tutoring and lab options as well.`,\n enrollInfo: `Open Enrollment: Rolling enrollment, enroll now to get 1:1 help\n immediately.`,\n },\n {\n title: 'Hybrid Bootcamp',\n mostPopular: true,\n online: 'In-person and/or online',\n lectures: 'Prerecorded',\n price: 2499,\n length: '9 months',\n summary: `We guide a beginner or intermediate coder to job-ready status\n in 9 months. We combine 1:1 tutoring with on-site and Zoom workgroup\n sessions and help you kickstart your career in tech.`,\n enrollInfo: `Limited Enrollment: Enroll right away to save a spot & start preparing!`\n },\n {\n title: 'Oakland Bootcamp',\n online: 'In-person only',\n lectures: 'Live, On-Site',\n crossedPrice: '$10,992',\n price: 8499,\n length: '9 month bundle',\n inquire: `Limited Enrollment: Contact us if interested`,\n summary: `Join us in Oakland for our live, on-site full stack\n coding bootcamp. Bundle consists of five courses, and 1:1\n tutoring plan.`,\n }
1112,\n]\n","Type":"StaticData","DefLoaders":["DefTarget","DefinedAs","DataType","Src","FilterContent"],"DefBuilders":["ContentCSV","ContentTXT","ContentJSON","ContentJS","Code","RequireData"],"Name":"staticdata_full_plans","DefinitionName":"library1_PlanMenu_staticdata_full_plans","Source":"http://127.0.0.1:6627/static/libraries/shop/PlanMenu.js","data":[{"title":"Videos & Self-Paced","online":"Online only","lectures":"Prerecorded","crossedPrice":"$284","price":149,"length":"2 months","summary":"For only $135, unlock lifetime access to entire video\n curriculum for self-study.<br />\n <span style=\"font-family: Raleway; background: var(--sunshine);line-height: 1.8\"><strong>New to Kickstart</strong> Discount</span><br />\n For only $14, add 2 months of group review & Linux Lab!\n <br /><em>(renews at $149 for 2 months)</em>","enrollInfo":"Open Enrollment: Start self-paced, pop into Office Hours when you get stuck."},{"title":"Private Tutoring","online":"Online only","lectures":"Prerecorded","price":499,"length":"2 months","summary":"Level up your skills by purchasing a 1:1 tutoring\n program, affordably priced to renew every 2 months. Includes\n video curriculum and all group tutoring and lab options as well.","enrollInfo":"Open Enrollment: Rolling enrollment, enroll now to get 1:1 help\n immediately."},{"title":"Hybrid Bootcamp","mostPopular":true,"online":"In-person and/or online","lectures":"Prerecorded","price":2499,"length":"9 months","summary":"We guide a beginner or intermediate coder to job-ready status\n in 9 months. We combine 1:1 tutoring with on-site and Zoom workgroup\n sessions and help you kickstart your career in tech.","enrollInfo":"Limited Enrollment: Enroll right away to save a spot & start preparing!"},{"title":"Oakland Bootcamp","online":"In-person only","lectures":"Live, On-Site","crossedPrice":"$10,992","price":8499,"length":"9 month bundle","inquire":"Limited Enrollment: Contact us if interested","summary":"Join us in Oakland for our live, on-site full stack\n coding bootcamp. Bundle consists of five courses, and 1:1\n tutoring plan."}]}, 1113 1114library1_PlanMenu_staticdata_short_list: {"Parent":"library1_PlanMenu","DefName":null,"Content":"/* JSON data, but evaluated as a JS expression */\n\n/* NOTE: Currently disabled */\n/*[\n {\n title: 'Virtual Bootcamp',\n lectures: 'Prerecorded',\n crossedPrice: '$186',\n price: 99,\n length: 'LIFETIME UPDATES',\n summary: `Our classic bootcamp experience, now as a self-paced,\n offline-friendly coding bootcamp!`,\n },\n]*/\n\n[]\n","Type":"StaticData","DefLoaders":["DefTarget","DefinedAs","DataType","Src","FilterContent"],"DefBuilders":["ContentCSV","ContentTXT","ContentJSON","ContentJS","Code","RequireData"],"Name":"staticdata_short_list","DefinitionName":"library1_PlanMenu_staticdata_short_list","Source":"http://127.0.0.1:6627/static/libraries/shop/PlanMenu-short.js","data":[]}, 1115 1116library1_PlanMenu_script: {"Parent":"library1_PlanMenu","DefName":null,"lifecycle":null,"DefBuilders":["Content|AutoExport","CodeTemplate"],"Type":"Script","Name":"script","DefinitionName":"library1_PlanMenu_script","exportNames":["prepareCallback"],"locals":["props","staticdata_full_plans","staticdata_short_list"],"Directives":[],"tempContent":"\n function prepareCallback() {\n const plans = props.short ? staticdata_short_list\n : staticdata_full_plans;\n return { plans };\n }\n "}, 1117 1118library1_Courses_props: {"Parent":"library1_Courses","DefName":null,"Content":"","Type":"Props","topthree":"","Name":"props","DefinitionName":"library1_Courses_props"}, 1119 1120library1_Courses_template: {"Parent":"library1_Courses","DefName":null,"Type":"Template","DefFinalizers":["FilterContent","TemplatePrebuild"],"opTokens":"==,>,<,>=,<=,!=,not in,is not,is,in,not,gt,lt","opAliases":{"==":"X === Y","is":"X === Y","gt":"X > Y","lt":"X < Y","is not":"X !== Y","not":"!(Y)","in":"(Y).includes ? (Y).includes(X) : (X in Y)","not in":"!((Y).includes ? (Y).includes(X) : (X in Y))"},"modeTokens":["{% %}","{{ }}","{# #}"],"modes":{},"defaultFilters":{},"defaultTags":{}
1120,"Name":"template","DefinitionName":"library1_Courses_template","Source":"http://127.0.0.1:6627/static/libraries/shop/Courses.html"}, 1121 1122library1_Courses_style: {"Parent":"library1_Courses","DefName":null,"urlReplace":null,"isolateSelector":[],"isolateClass":null,"prefix":"x-Courses","corePseudo":["before","after","first-line","last-line"],"DefBuilders":["FilterContent","AutoIsolate","Content|ProcessCSS"],"Type":"Style","Name":"style","DefinitionName":"library1_Courses_style","Source":"http://127.0.0.1:6627/static/libraries/shop/Courses.css","headHash":"x1iqcap6"}, 1123 1124library1_Courses_staticdata: {"Parent":"library1_Courses","DefName":null,"Content":"/* JSON data, but evaluated as a JS expression */\n[\n /*\n {\n title: 'Foundations',\n subtitle: 'Web Design: Intro to HTML and CSS',\n course: 'prep',\n content: `Open Curriculum. Learn foundational skills while creating\n cool, useful websites from scratch. Learn how to embed music, videos,\n maps, e-commerce stores, and more!`,\n skill: 1,\n img: 'computer-g0e7058b72_1280.jpg',\n imgalt: 'A computer with rainbow',\n imgfg: 'white',\n //free: true,\n //url: 'https://freecodinglessons.com/foundations/1.1/',\n modules: [\n { num: '1.1', title: 'HTML basics' },\n { num: '1.2', title: 'Tags and Styles' },\n { num: '1.3', title: 'Lab: Single Page Projects' },\n { num: '2.1', title: 'Multipage Sites' },\n { num: '2.2', title: 'Flex Layouts' },\n { num: '2.3', title: 'Lab: Multi-Page Projects' },\n ],\n },\n\n {\n title: 'Foundations',\n subtitle: 'Web Design: Components & Frameworks',\n course: 'prep',\n content: `\n Open Curriculum. Learn design trends, re-usable components, and how\n to use frameworks, such as Tailwind CSS. Finally, use Modulo.js to\n launch a JAMStack app on Netlify.\n `,\n skill: 1,\n img: 'hd-wallpaper-g721518917_1280.jpg',\n imgalt: 'Illustration of rainbow going through monitor',\n imgfg: 'white',\n //free: true,\n //url: 'https://freecodinglessons.com/foundations/3.1/',\n modules: [\n { num: '3.1', title: 'Tailwind' },\n { num: '3.2', title: 'Forms' },\n { num: '3.3', title: 'Lab: Forms and Frameworks'},\n { num: '4.1', title: 'Web Components' },\n { num: '4.2', title: 'Component Reuse' },\n { num: '4.3', title: 'Lab: JAMStack Apps' },\n ],\n },\n */\n\n {\n course: 'prep',\n subtitle: 'Kickstart Prework',\n img: 'plans-gb63d02c1d_1280.jpg',\n content: `\n Learn how to learn. Use \"Smart Scheduling\" to make a bootcamp\n program and boot up a \"Linux Lab\". Then, immerse yourself in a\n coding tour-de-force, with tastes of HTML, CSS, JS, Linux, Bash, and Lua.`,\n skill: 1,\n modules: [\n { num: '1', title: 'Intro to Learning' },\n { num: '2', title: 'Immersion: Frontend' },\n { num: '3', title: 'Immersion: Backend' },\n /*\n { num: '1', title: 'Intro to Coding Bootcamps' },\n { num: '2', title: 'Linux, macOS, & online setup' },\n { num: '3', title: 'Terminology research' },\n { num: '4', title: 'Markdown and Fast Typing' },\n { num: '5', title: 'Skill Check: Dive into Coding' },\n { num: '6', title: 'Skill Check: Deeper with Coding' },\n { num: '7', title: 'Beyond Prework' },\n */\n ],\n project: 'Prework Journal',\n },\n\n {\n course: 'fundamentals',\n img: 'laptop-g4d7844033_1280.png',\n subtitle: 'Static Sites & Bootstrap',\n content: `Start peeling back the layers of the web in this whirlwind\n tour of HTML, CSS, Dev Tools, column-based layouts, responsive design\n and Bootstrap 5`,\n skill: 2,\n project: 'Static Profile Page',\n modules: [\n { num: '1.1', title: 'HTML', topics: [ 'HTML', 'tech stack', 'GitHub', 'Publishing', 'template editing' ] },\n { num: '1.2', title: 'CSS', topics: [ 'CSS', 'Dev tools', 'selectors', 'classes' ] },\n { num: '1.3', title: 'Bootstrap', topics: [ 'Bootstrap 5', 'column layouts', 'grid systems', 'responsive design', 'stylesheet linking' ] },\n ],\n\n },\n\n {\n course: 'fundamentals',\n img: 'apple-ga7d81315e_1280.png',\n subtitle: 'Automation: Bash, Git, and Python Scripts',\n content: `Learn how to use Git to keep your code safe under version control.\n Learn effective terminal use, and how to write Bash and Python scripts\n to replace tedious tasks.`,\n skill: 2,\n project: 'Simple automation of page assembly in Bash and Python',\n modules: [\n { num: '2.1', title: 'Bash', topics: [\n 'bash', 'zsh', 'shell scripting', 'directory navigation',\n 'redirection', 'piping', 'wildcards', 'ls', 'cd', 'mkdir',\n 'touch', 'echo', 'cat' ] },\n { num: '2.2', title: 'Git', topics: [\n 'git', 'commits', 'remotes', 'branching',\n 'merging', 'commit history', 'sharing with GitHub',\n 'pull requests' ] },\n { num: '2.3', title: 'Python', topics: [\n 'python', 'python scripting', 'variables', 'assignment operator',\n 'reading files', 'writing files', 'combining files' ] },\n ],\n },\n\n {\n course: 'fundamentals',\n img: 'background-g8ee7d113b_1280.jpg',\n subtitle: 'Computer Programming with Python',\n project: 'Python-based static site generator, bonus assignment includes computer-vision powered OCR and face detection image gallery',\n content: `Begin a classic introduction to backend programming with\n Python, learning core data types and control-flow structures. Go deeper\n with OOP, Pipenv, and Jinja templating.`,\n skill: 2,\n modules: [\n { num: '3.1', title: 'Flow' },\n { num: '3.2', title: 'Functions' },\n { num: '3.3', title: 'Loops' },\n { num: '4.1', title: 'OOP' },\n { num: '4.2', title: 'Modules' },\n { num: '4.3', title: 'Templating' },\n ],\n },\n\n {\n course: 'backend',\n subtitle: 'Intro to Networking with Python',\n img: 'background-ged739cdbf_1280.jpg',\n imgfg: 'white',\n project: 'API-driven Dashboard',\n content: `Learn about the Internet, networking, and server-side\n programming. You will use web APIs, implement HTTP over TCP/IP, and\n finally basic request routing and web apps.`,\n skill: 3,\n modules: [\n { num: '1.1', title: 'Requests and APIs' },\n { num: '1.2', title: 'Servers, HTTP over TCP/IP, and Routing' },\n { num: '1.3', title: 'Web Apps and Deployment' },\n ],\n },\n\n {\n course: 'backend',\n subtitle: 'Practical Django',\n imgalt: 'Cube in a world of cubes',\n img: 'cubes-g21a82afce_1280.jpg',\n imgfg: 'white',\n project: 'Multi-user shareable DB-driven dashboard',\n content: `Learn the best practices from an experienced Django\n developer: MVC, CRUD, forms, urls, users, admin, models, data\n cardinality (eg Many-To-Many), unit testing, and much more.`,\n skill: 3,\n modules: [\n { num: '2.1', title: 'Django' },\n { num: '2.2', title: 'Forms' },\n { num: '2.3', title: 'Users' },\n { num: '3.1', title: 'CRUD' },\n { num: '3.2', title: 'Models' },\n { num: '3.3', title: 'Unit testing' },\n ],\n\n },\n\n {\n course: 'backend',\n img: 'server-g6892d162b_1280.jpg',\n imgfg: 'white',\n subtitle: 'Intro to Databases with Postgres SQL',\n content: `Learn SQL basics on a Postgres DB, before getting practice\n with JOINs, constraints, query anal
1124ysis, indexes and optimization,\n full-text search, geo-spatial features, and more.`,\n skill: 3,\n modules: [\n { num: '4.1', title: 'Postgres SQL' },\n { num: '4.2', title: 'Joins and Indices' },\n ],\n },\n\n {\n course: 'frontend',\n imgfg: 'white',\n img: 'retro-g526726a00_1280.jpg',\n subtitle: 'JavaScript in the Modern Web',\n project: 'Data Viz SPA in pure CSS and vanilla JS',\n content: `Learn modern JavaScript, including let, const, iterators, and\n DOM manipulation. Explore tricky CSS concepts like animations and\n pseudo-elements.`,\n skill: 3,\n modules: [\n { num: '1.1', title: 'Box Model & BEM' },\n { num: '1.2', title: 'Grid & Animations' },\n { num: '1.3', title: 'Flexbox & JS Events' },\n { num: '2.1', title: 'Modern JavaScript' },\n { num: '2.2', title: 'DOM Manipulation' },\n { num: '2.3', title: 'API & Single Page Apps' },\n ],\n },\n\n {\n course: 'frontend',\n img: 'colorful-g427212bf2_1280.jpg',\n imgfg: 'white',\n subtitle: 'Thinking in React',\n project: 'Data Viz SPA in React JS',\n content: `In this hooks-based React course segment, you go beyond just\n learning the JSX syntax, and practice \"thinking in React\" with\n data-flow, lifting state, and more.`,\n skill: 4,\n modules: [\n { num: '3.1', title: 'React' },\n { num: '3.2', title: 'State' },\n { num: '3.3', title: 'Lifecycle' },\n { num: '4.1', title: 'Components' },\n { num: '4.2', title: 'Data-flow' },\n { num: '4.3', title: 'Patterns' },\n ],\n },\n\n {\n course: 'frontend',\n imgfg: 'white',\n img: 'wallpaper-gbaac742b2_1280.jpg',\n subtitle: 'Full Stack JS: MERN, Redux, and Routing',\n project: 'React Widget Library: Design, launch and release on NPM',\n content: `Take your React JS skills to the full stack by learning\n MongoDB, Express.JS, and Node.js. Learn Redux for state management, and\n Routing for multi-page apps.`,\n skill: 4,\n modules: [\n { num: '4.4', title: 'Full-stack' },\n { num: '5.1', title: 'Router' },\n { num: '5.2', title: 'Redux' },\n { num: '5.3', title: 'MERN' },\n { num: '5.4', title: 'Testing' },\n ],\n },\n\n {\n course: 'career',\n img: 'people-g923420017_1280.jpg',\n imgfg: 'white',\n subtitle: 'Kickstart Career',\n content: `Redo your resume, polish your profile, and hone your\n networking skills. Practice interviews and develop a \"elevator pitch\"\n to market yourself for your next job.`,\n skill: 3,\n modules: [\n { num: 'M1', title: 'Resume' },\n { num: 'M2', title: 'Narrative' },\n { num: 'M3', title: 'Communication' },\n { num: 'M4', title: 'Interviews' },\n { num: 'M5', title: 'Professionalism' },\n ],\n },\n\n {\n course: 'career',\n subtitle: 'Algorithms: Computer Science for Job Seekers',\n img: 'fractal-gdd9943fe4_1280.jpg',\n imgfg: 'white',\n content: `A CS course hyper-focused on whiteboard interviews. Learn\n time complexity analysis (BigO), sorting, solving problems in dynamic\n programming, recursion and async coding puzzles, and more.`,\n skill: 4,\n modules: [\n { num: '1.1', title: 'Algorithms for Job Seekers' },\n { num: '1.2', title: 'Recursion and Async' },\n { num: '1.3', title: 'Sorting Algorithms' },\n { num: '2.1', title: 'ADT - Abstract Data Types' },\n { num: '2.2', title: 'Computer Engineering & Data Structures' },\n ],\n },\n\n {\n course: 'career',\n img: 'drawing-g538254e05_1280.jpg',\n subtitle: 'Industry Capstone',\n content: `Use a 5-milestone process to build a software product from\n specs to launch. Learn how tech industry roles interlock, including\n agile Product Management and DevOps.`,\n project: 'A full-stack app using Python, JavaScript, and other technologies',\n skill: 4,\n modules: [\n { num: 'M1', title: 'Industry: Product Management & Agile' },\n { num: 'M2', title: 'Project Proposal' },\n { num: 'M3', title: 'Project Spec' },\n { num: 'M4', title: 'Project MVP' },\n { num: 'M5', title: 'Industry: DevOps & Server Topology' },\n { num: 'M6', title: 'Project Launch' },\n { num: 'M7', title: 'Project Presentation' },\n ],\n },\n]\n\n\n\n/*\n DEAD CODE\n {\n course: 'fundamentals',\n subtitle: 'Modular Python',\n },\n\n {\n title: 'Backend: Django and Postgres' ,\n time: '4-12 weeks',\n content: 'Web application programming with Python 3, Django, and Postgres SQL',\n updated: 'Updated for Django 4+',\n description: [\n 'Build a full-stack web application with Python / Django',\n 'Round out your backend knowledge with PosgreSQL',\n 'Implement a HTTP web server in Python',\n ],\n },\n\n {\n title: \"Frontend: React and Mern\",\n time: '5-15 weeks',\n content: 'Cutting-edge frontend web development with modern vanilla JavaScript and React.js JSX',\n updated: 'Updated for React.js Hooks and ES6+',\n description: [\n 'Develop and launch a data visualization React charting component',\n 'Modernized frontend with CSS grid and vanilla JS',\n 'A crash course in MERN for full-stack JS Single Page Apps',\n ],\n },\n\n {\n title: \"Algorithms: Computer Science for Job Seekers\",\n time: '2-6 weeks',\n content: 'Tech career development and fundamentals of algorithms',\n description: [\n 'Learn techniques on how to make your dream career in tech a reality',\n 'Redo your resume, polish your online profile, and hone your networking skills',\n 'Learn CS concepts and problem solving techniques to beat interviews',\n ],\n },\n\n {\n title: \"Career Capstone\",\n time: '2-6 weeks',\n content: 'Tech career development and fundamentals of algorithms',\n description: [\n 'Learn techniques on how to make your dream career in tech a reality',\n 'Redo your resume, polish your online profile, and hone your networking skills',\n 'Learn CS concepts and problem solving techniques to beat interviews',\n ],\n },\n description: [\n 'Great for both beginners, and pros looking to brush up',\n 'Indulge your creative side! Create your own e-commerce store or business page.',\n 'Learn to integrate with Etsy, Shopify, YouTube, Soundcloud, Bandcamp, Google Maps and others.',\n 'Build band pages, artist profiles, personal pages, artistic blogs and personal writing spots.',\n 'Learn HTML, CSS',\n 'Learn how to use design principles to create designs from scratch',\n ],\n\n description: [\n 'Great for both beginners, and pros looking to brush up',\n 'Indulge your creative side! Create your own e-commerce store or business page.',\n 'Learn to integrate with Etsy, Shopify, YouTube, Soundcloud, Bandcamp, Google Maps and others.',\n 'Build band pages, artist profiles, personal pages, artistic blogs and personal writing spots.',\n 'Learn HTML, CSS',\n 'Learn how to use design principles to create designs from scratch',\n ],\n\n{ num: '1.1', title: 'Intro to Coding Bootcamps' },\n{ num: '1.2', title: 'Intro to Prework' },\n{ num: '2.1', title: 'Online setup' },\n{ num: '2.2', title: 'macOS setup' },\n{ num: '2.3', title: 'Linux setup' },\n{ num: '3.1', title: 'Terminology immersion' },\n{ num: '3.2', title: 'Jargon research' },\n{ num: '3.3', title: 'Tech news research' },\n{ num: '3.4', title: 'Free software research' },\n{ num: '4.1', title: 'Git and GitHub research' },\n{ num: '4.2', title: 'Touch typing' },\n{ num: '4.3', title: 'Markdown' },\n{ num: '5.1', title: '(Optional) Dive into HTML' },\n{ num: '5.2', title: '(Optional) Dive into Python' },\n{ num: '6.1', title: '(Optional) Deeper with HTML' },\n{ num: '6.2', title: '(Optional) Deeper with CSS' },\n{ num: '6.3', title: '(Optional) Deeper with Python' },\n{ num: '7.1', title: 'Learning with Kickstart Coding' },\n{ num: '7.2', title: 'Additional Prework' }
1124,\n*/\n\n","Type":"StaticData","DefLoaders":["DefTarget","DefinedAs","DataType","Src","FilterContent"],"DefBuilders":["ContentCSV","ContentTXT","ContentJSON","ContentJS","Code","RequireData"],"Name":"staticdata","DefinitionName":"library1_Courses_staticdata","Source":"http://127.0.0.1:6627/static/libraries/shop/Courses.js","data":[{"course":"prep","subtitle":"Kickstart Prework","img":"plans-gb63d02c1d_1280.jpg","content":"\n Learn how to learn. Use \"Smart Scheduling\" to make a bootcamp\n program and boot up a \"Linux Lab\". Then, immerse yourself in a\n coding tour-de-force, with tastes of HTML, CSS, JS, Linux, Bash, and Lua.","skill":1,"modules":[{"num":"1","title":"Intro to Learning"},{"num":"2","title":"Immersion: Frontend"},{"num":"3","title":"Immersion: Backend"}],"project":"Prework Journal"},{"course":"fundamentals","img":"laptop-g4d7844033_1280.png","subtitle":"Static Sites & Bootstrap","content":"Start peeling back the layers of the web in this whirlwind\n tour of HTML, CSS, Dev Tools, column-based layouts, responsive design\n and Bootstrap 5","skill":2,"project":"Static Profile Page","modules":[{"num":"1.1","title":"HTML","topics":["HTML","tech stack","GitHub","Publishing","template editing"]},{"num":"1.2","title":"CSS","topics":["CSS","Dev tools","selectors","classes"]},{"num":"1.3","title":"Bootstrap","topics":["Bootstrap 5","column layouts","grid systems","responsive design","stylesheet linking"]}]},{"course":"fundamentals","img":"apple-ga7d81315e_1280.png","subtitle":"Automation: Bash, Git, and Python Scripts","content":"Learn how to use Git to keep your code safe under version control.\n Learn effective terminal use, and how to write Bash and Python scripts\n to replace tedious tasks.","skill":2,"project":"Simple automation of page assembly in Bash and Python","modules":[{"num":"2.1","title":"Bash","topics":["bash","zsh","shell scripting","directory navigation","redirection","piping","wildcards","ls","cd","mkdir","touch","echo","cat"]},{"num":"2.2","title":"Git","topics":["git","commits","remotes","branching","merging","commit history","sharing with GitHub","pull requests"]},{"num":"2.3","title":"Python","topics":["python","python scripting","variables","assignment operator","reading files","writing files","combining files"]}]},{"course":"fundamentals","img":"background-g8ee7d113b_1280.jpg","subtitle":"Computer Programming with Python","project":"Python-based static site generator, bonus assignment includes computer-vision powered OCR and face detection image gallery","content":"Begin a classic introduction to backend programming with\n Python, learning core data types and control-flow structures. Go deeper\n with OOP, Pipenv, and Jinja templating.","skill":2,"modules":[{"num":"3.1","title":"Flow"},{"num":"3.2","title":"Functions"},{"num":"3.3","title":"Loops"},{"num":"4.1","title":"OOP"},{"num":"4.2","title":"Modules"},{"num":"4.3","title":"Templating"}]},{"course":"backend","subtitle":"Intro to Networking with Python","img":"background-ged739cdbf_1280.jpg","imgfg":"white","project":"API-driven Dashboard","content":"Learn about the Internet, networking, and server-side\n programming. You will use web APIs, implement HTTP over TCP/IP, and\n finally basic request routing and web apps.","skill":3,"modules":[{"num":"1.1","title":"Requests and APIs"},{"num":"1.2","title":"Servers, HTTP over TCP/IP, and Routing"},{"num":"1.3","title":"Web Apps and Deployment"}]},{"course":"backend","subtitle":"Practical Django","imgalt":"Cube in a world of cubes","img":"cubes-g21a82afce_1280.jpg","imgfg":"white","project":"Multi-user shareable DB-driven dashboard","content":"Learn the best practices from an experienced Django\n developer: MVC, CRUD, forms, urls, users, admin, models, data\n cardinality (eg Many-To-Many), unit testing, and much more.","skill":3,"modules":[{"num":"2.1","title":"Django"},{"num":"2.2","title":"Forms"},{"num":"2.3","title":"Users"},{"num":"3.1","title":"CRUD"},{"num":"3.2","title":"Models"},{"num":"3.3","title":"Unit testing"}]},{"course":"backend","img":"server-g6892d162b_1280.jpg","imgfg":"white","subtitle":"Intro to Databases with Postgres SQL","content":"Learn SQL basics on a Postgres DB, before getting practice\n with JOINs, constraints, query anal
1124ysis, indexes and optimization,\n full-text search, geo-spatial features, and more.","skill":3,"modules":[{"num":"4.1","title":"Postgres SQL"},{"num":"4.2","title":"Joins and Indices"}]},{"course":"frontend","imgfg":"white","img":"retro-g526726a00_1280.jpg","subtitle":"JavaScript in the Modern Web","project":"Data Viz SPA in pure CSS and vanilla JS","content":"Learn modern JavaScript, including let, const, iterators, and\n DOM manipulation. Explore tricky CSS concepts like animations and\n pseudo-elements.","skill":3,"modules":[{"num":"1.1","title":"Box Model & BEM"},{"num":"1.2","title":"Grid & Animations"},{"num":"1.3","title":"Flexbox & JS Events"},{"num":"2.1","title":"Modern JavaScript"},{"num":"2.2","title":"DOM Manipulation"},{"num":"2.3","title":"API & Single Page Apps"}]},{"course":"frontend","img":"colorful-g427212bf2_1280.jpg","imgfg":"white","subtitle":"Thinking in React","project":"Data Viz SPA in React JS","content":"In this hooks-based React course segment, you go beyond just\n learning the JSX syntax, and practice \"thinking in React\" with\n data-flow, lifting state, and more.","skill":4,"modules":[{"num":"3.1","title":"React"},{"num":"3.2","title":"State"},{"num":"3.3","title":"Lifecycle"},{"num":"4.1","title":"Components"},{"num":"4.2","title":"Data-flow"},{"num":"4.3","title":"Patterns"}]},{"course":"frontend","imgfg":"white","img":"wallpaper-gbaac742b2_1280.jpg","subtitle":"Full Stack JS: MERN, Redux, and Routing","project":"React Widget Library: Design, launch and release on NPM","content":"Take your React JS skills to the full stack by learning\n MongoDB, Express.JS, and Node.js. Learn Redux for state management, and\n Routing for multi-page apps.","skill":4,"modules":[{"num":"4.4","title":"Full-stack"},{"num":"5.1","title":"Router"},{"num":"5.2","title":"Redux"},{"num":"5.3","title":"MERN"},{"num":"5.4","title":"Testing"}]},{"course":"career","img":"people-g923420017_1280.jpg","imgfg":"white","subtitle":"Kickstart Career","content":"Redo your resume, polish your profile, and hone your\n networking skills. Practice interviews and develop a \"elevator pitch\"\n to market yourself for your next job.","skill":3,"modules":[{"num":"M1","title":"Resume"},{"num":"M2","title":"Narrative"},{"num":"M3","title":"Communication"},{"num":"M4","title":"Interviews"},{"num":"M5","title":"Professionalism"}]},{"course":"career","subtitle":"Algorithms: Computer Science for Job Seekers","img":"fractal-gdd9943fe4_1280.jpg","imgfg":"white","content":"A CS course hyper-focused on whiteboard interviews. Learn\n time complexity analysis (BigO), sorting, solving problems in dynamic\n programming, recursion and async coding puzzles, and more.","skill":4,"modules":[{"num":"1.1","title":"Algorithms for Job Seekers"},{"num":"1.2","title":"Recursion and Async"},{"num":"1.3","title":"Sorting Algorithms"},{"num":"2.1","title":"ADT - Abstract Data Types"},{"num":"2.2","title":"Computer Engineering & Data Structures"}]},{"course":"career","img":"drawing-g538254e05_1280.jpg","subtitle":"Industry Capstone","content":"Use a 5-milestone process to build a software product from\n specs to launch. Learn how tech industry roles interlock, including\n agile Product Management and DevOps.","project":"A full-stack app using Python, JavaScript, and other technologies","skill":4,"modules":[{"num":"M1","title":"Industry: Product Management & Agile"},{"num":"M2","title":"Project Proposal"},{"num":"M3","title":"Project Spec"},{"num":"M4","title":"Project MVP"},{"num":"M5","title":"Industry: DevOps & Server Topology"},{"num":"M6","title":"Project Launch"},{"num":"M7","title":"Project Presentation"}]}]}, 1125 1126library1_Courses_videostats: {"Parent":"library1_Courses","DefName":null,"Content":"{\n \"kc101-videos\": 40.17207155,\n \"kc201-videos\": 582.4388888333333,\n \"kc202-videos\": 532.9675000333333,\n \"kc203-videos\": 1210.4693888833335,\n \"kc301-videos\": 608.0095833166666,\n \"kc302-videos\": 1030.656305633333,\n \"kc303-videos\": 343.55926113333334,\n \"kc401-videos\": 1264.9572222666668,\n \"kc402-videos\": 1186.4997556999997,\n \"kc403-videos\": 334.18180558333336,\n \"kc502-videos\": 478.89,\n \"kc503-videos\": 111.11,\n \"count\": 850,\n \"total_seconds\": 463441.15502200014,\n \"total_minutes\": 7724.0192503666685,\n \"average_minutes\": 9.08708147101961,\n \"total_hours\": 128.73365417277782\n}
1126\n\n","Type":"StaticData","DefLoaders":["DefTarget","DefinedAs","DataType","Src","FilterContent"],"DefBuilders":["ContentCSV","ContentTXT","ContentJSON","ContentJS","Code","RequireData"],"Name":"videostats","DefinitionName":"library1_Courses_videostats","Source":"http://127.0.0.1:6627/static/data/kc_video_stats_2406.json","data":{"kc101-videos":40.17207155,"kc201-videos":582.4388888333333,"kc202-videos":532.9675000333333,"kc203-videos":1210.4693888833335,"kc301-videos":608.0095833166666,"kc302-videos":1030.656305633333,"kc303-videos":343.55926113333334,"kc401-videos":1264.9572222666668,"kc402-videos":1186.4997556999997,"kc403-videos":334.18180558333336,"kc502-videos":478.89,"kc503-videos":111.11,"count":850,"total_seconds":463441.15502200014,"total_minutes":7724.0192503666685,"average_minutes":9.08708147101961,"total_hours":128.73365417277782}}, 1127 1128library1_Courses_state: {"Parent":"library1_Courses","DefName":null,"Content":"","Type":"State","Directives":["bindMount","bindUnmount"],"Store":null,"selected":"","Name":"state","DefinitionName":"library1_Courses_state"}, 1129 1130library1_Courses_script: {"Parent":"library1_Courses","DefName":null,"lifecycle":null,"DefBuilders":["Content|AutoExport","CodeTemplate"],"Type":"Script","Name":"script","DefinitionName":"library1_Courses_script","exportNames":["selectCourse","prepareCallback"],"locals":["props","staticdata","videostats","state"],"Directives":[],"tempContent":"\n const courses = [\n {\n title: 'Prep',\n weeks: '2-6 weeks',\n step: 1,\n },\n {\n title: 'Fundamentals',\n weeks: '4-12 weeks',\n step: 2,\n },\n {\n title: 'Backend',\n weeks: '4-12 weeks',\n step: 3,\n },\n {\n title: 'Frontend',\n weeks: '6-14 weeks',\n step: 4,\n },\n {\n title: 'Career' ,\n weeks: '4-12 weeks',\n step: 5,\n },\n ];\n\n function selectCourse(slug) {\n state.selected = slug;\n }\n\n function prepareCallback() {\n let segments = staticdata;\n let visibleSegments = staticdata;\n if (props.topthree) {\n const allowed = 'Kickstart Prework|Thinking in React|Practical Django|Web Design: Intro to HTML and CSS';\n visibleSegments = staticdata.filter(seg => allowed.toLowerCase().includes(seg.subtitle.toLowerCase()));\n }\n if (state.selected) {\n visibleSegments = staticdata.filter(seg => seg.course.toLowerCase() === state.selected);\n }\n for (const seg of visibleSegments) {\n console.log(seg);\n console.log(videostats);\n }\n return { courses, segments, visibleSegments };\n }\n "}, 1131 }; 1132 1133// Copyright 2024 MichaelB | https://modulojs.org | Modulo v0.0.72 | LGPLv3 1134// Modulo LGPLv3 NOTICE: Any direct modifications to the Modulo.js source code 1135// must be LGPL or compatible. It is acceptable to distribute dissimilarly 1136// licensed code built with the Modulo framework bundled in the same file for 1137// efficiency instead of "linking", as long as this notice and license remains 1138// intact with the Modulo.js source code itself and any direct modifications. 1139if (typeof window === "undefined") { // Allow for Node.js environment 1140 var window = {}; 1141} 1142window.ModuloPrevious = window.Modulo; 1143window.moduloPrevious = window.modulo; 1144window.Modulo = class Modulo { 1145 constructor() { 1146 window._moduloID = (window._moduloID || 0) + 1; 1147 this.window = window; 1148 this.id = window._moduloID; // Every Modulo instance gets a unique ID. 1149 this._configSteps = 0; // Used to check for an infinite loop during load 1150 this.registry = { cparts: { }, coreDefs: { }, utils: { }, core: { }, 1151 engines: { }, commands: { }, templateFilters: { }, 1152 templateTags: { }, processors: { }, elements: { } }; 1153 this.config = {}; // Default confs for classes (e.g. all Components) 1154 this.definitions = {}; // For specific definitions (e.g. one Component) 1155 this.stores = {}; // Global data store (by default, only used by State) 1156 } 1157 1158 register(type, cls, defaults = undefined) { 1159 type = (`${type}s` in this.registry) ? `${type}s` : type; // pluralize 1160 if (type in this.registry.registryCallbacks) { 1161 cls = this.registry.registryCallbacks[type](this, cls) || cls; 1162 } 1163 this.assert(type in this.registry, 'Unknown registry type: ' + type); 1164 this.registry[type][cls.name] = cls; 1165 if (cls.name[0].toUpperCase() === cls.name[0]) { // e.g. class FooBar 1166 const conf = this.config[cls.name.toLowerCase()] || {}; 1167 Object.assign(conf, { Type: cls.name }, cls.defaults, defaults); 1168 this.config[cls.name.toLowerCase()] = conf; // e.g. config.foobar 1169 } 1170 } 1171 1172 instance(def, extra, inst = null) { 1173 const isLower = key => key[0].toLowerCase() === key[0]; 1174 const coreDefSet = { Component: 1, Artifact: 1 }; // TODO: make compatible with any registration type 1175 const registry = (def.Type in coreDefSet) ? 'coreDefs' : 'cparts'; 1176 inst = inst || new this.registry[registry][def.Type](this, def, extra.element || null); // TODO rm the element arg 1177 const id = ++window._moduloID; 1178 //const conf = Object.assign({}, this.config[name.toLowerCase()], def); 1179 const conf = Object.assign({}, def); // Just shallow copy "def" 1180 const attrs = this.registry.utils.keyFilter(conf, isLower); 1181 Object.assign(inst, { id, attrs, conf }, extra, { modulo: this }); 1182 if (inst.constructedCallback) { 1183 inst.constructedCallback(); 1184 } 1185 return inst; 1186 } 1187 1188 instanceParts(def, extra, parts = {}) { 1189 // Loop through all children, instancing each class with configuration 1190 const allNames = [ def.DefinitionName ].concat(def.ChildrenNames); 1191 for (const def of allNames.map(name => this.definitions[name])) { 1192 parts[def.RenderObj || def.Name] = this.instance(def, extra); 1193 } 1194 return parts; 1195 } 1196 1197 lifecycle(parts, renderObj, lifecycleNames) { 1198 for (const lifecycleName of lifecycleNames) { 1199 const methodName = lifecycleName + 'Callback'; 1200 for (const [ name, obj ] of Object.entries(parts)) { 1201 if (!(methodName in obj)) { 1202 continue; // Skip if obj has not registered callback 1203 } 1204 const result = obj[methodName].call(obj, renderObj); 1205 if (result) { // TODO: Change to (result !== undefined) and test 1206 renderObj[obj.conf.RenderObj || obj.conf.Name] = result; 1207 } 1208 } 1209 } 1210 } 1211 1212 preprocessAndDefine(cb, prefix = 'Def') { 1213 this.fetchQueue.enqueue(() => {
1214 this.repeatProcessors(null, prefix + 'Builders', () => { 1215 this.repeatProcessors(null, prefix + 'Finalizers', cb || (() => {})); 1216 }); 1217 }, true); // The "true" causes it to wait for all 1218 } 1219 1220 loadString(text, parentName = null) { // TODO: Refactor this method away 1221 return this.loadFromDOM(this.registry.utils.newNode(text), parentName); 1222 } 1223 1224 loadFromDOM(elem, parentName = null, quietErrors = false) { // TODO: Refactor this method away 1225 const loader = new this.registry.core.DOMLoader(this); 1226 return loader.loadFromDOM(elem, parentName, quietErrors); 1227 } 1228 1229 repeatProcessors(defs, field, cb) { 1230 let changed = true; // Run at least once 1231 const defaults = this.config.modulo['default' + field] || []; 1232 while (changed) { 1233 this.assert(this._configSteps++ < 90000, 'Config steps: 90000+'); 1234 changed = false; // TODO: Is values deterministic in order? (Solution, if necessary: definitions key order arr) 1235 for (const def of (defs || Object.values(this.definitions))) { 1236 const processors = def[field] || defaults; 1237 //changed = changed || this.applyProcessors(def, processors); 1238 const result = this.applyNextProcessor(def, processors); 1239 if (result === 'wait') { // TODO: Refactor logic here & 1240 changed = null; // null always triggers an enqueue 1241 break; 1242 } 1243 changed = changed || result; 1244 } 1245 } 1246 const repeat = () => this.repeatProcessors(defs, field, cb); 1247 if (changed !== null && Object.keys(this.fetchQueue ? this.fetchQueue.queue : {}).length === 0) { // TODO: Remove ?: after core object refactor 1248 if (cb) { 1249 cb(); // Synchronous path 1250 } 1251 } else { 1252 this.fetchQueue.enqueue(repeat); 1253 } 1254 } 1255 1256 applyNextProcessor(def, processorNameArray) { 1257 const cls = this.registry.cparts[def.Type] || this.registry.coreDefs[def.Type] || {}; // TODO: Fix this 1258 const { processors } = this.registry; 1259 for (const name of processorNameArray) { 1260 const [ attrName, aliasedName ] = name.split('|'); 1261 if (attrName in def) { 1262 const funcName = aliasedName || attrName; 1263 const proc = this.registry.processors[funcName.toLowerCase()]; 1264 const func = funcName in cls ? cls[funcName].bind(cls) : proc; 1265 const value = def[attrName]; // Pluck value & remove attribute 1266 delete def[attrName]; // TODO: document 'wait' or rm -v 1267 return func(this, def, value) === true ? 'wait' : true; 1268 } 1269 } 1270 return false; // No processors were applied, return false 1271 } 1272 1273 assert(value, ...info) { 1274 if (!value) { 1275 console.error(this.id, ...info); 1276 throw new Error(`Modulo Error: "${Array.from(info).join(' ')}"`); 1277 } 1278 } 1279} 1280 1281// TODO: Move to conf 1282window.Modulo.INVALID_WORDS = new Set((` 1283 break case catch class const continue debugger default delete do else enum 1284 export extends finally for if implements import in instanceof interface new 1285 null package private protected public return static super switch throw try 1286 typeof var let void while with await async true false 1287`).split(/\s+/ig)); 1288 1289// Create a new modulo instance to be the global default instance 1290window.modulo = new window.Modulo(); 1291if (typeof modulo === "undefined" || modulo.id !== window.modulo.id) { 1292 var modulo = window.modulo; // TODO: RM when global modulo is cleaned up 1293} 1294window.modulo.registry.registryCallbacks = { // Set up default registry hooks 1295 commands(modulo, cls) { 1296 window.m = window.m || {}; // Avoid overwriting existing truthy m 1297 window.m[cls.name] = () => cls(modulo); // Attach shortcut to global "m" 1298 }, 1299 processors(modulo, cls) { 1300 modulo.registry.processors[cls.name.toLowerCase()] = cls; // Alias lower 1301 }, 1302 core(modulo, cls) { // Global / core class getting registered 1303 const lowerName = cls.name[0].toLowerCase() + cls.name.slice(1); 1304 modulo[lowerName] = new cls(modulo); 1305 modulo.assets = modulo.assetManager; // TODO Rm 1306 }, 1307}; 1308 1309modulo.register('coreDef', class Modulo {}, {
1310 ChildPrefix: '', // Prevents all children from getting modulo_ prefixed 1311 Contains: 'coreDefs', 1312 DefLoaders: [ 'DefTarget', 'DefinedAs', 'Src', 'Content' ], 1313 defaultDef: { DefTarget: null, DefinedAs: null, DefName: null }, 1314 defaultDefLoaders: [ 'DefTarget', 'DefinedAs', 'Src' ], 1315 defaultFactory: [ 'RenderObj', 'factoryCallback' ], // TODO: this might be dead code? 1316}); 1317 1318modulo.register('core', class ValueResolver { 1319 constructor(contextObj = null) { 1320 this.ctxObj = contextObj; 1321 this.isJSON = /^(true$|false$|null$|[^a-zA-Z])/; // "If not variable" 1322 } 1323 1324 get(key, ctxObj = null) { 1325 const { get } = window.modulo.registry.utils; // For drilling down "." 1326 const obj = ctxObj || this.ctxObj; // Use given one or in general 1327 return this.isJSON.test(key) ? JSON.parse(key) : get(obj, key); 1328 } 1329 1330 set(obj, keyPath, val, autoBind = false) { 1331 const index = keyPath.lastIndexOf('.') + 1; // Index at 1 (0 if missing) 1332 const key = keyPath.slice(index).replace(/:$/, ''); // Between "." & ":" 1333 const prefix = keyPath.slice(0, index - 1); // Get before first "." 1334 const target = index ? this.get(prefix, obj) : obj; // Drill down prefix 1335 1336 if (keyPath.endsWith(':')) { // If it's a dataProp style attribute 1337 const parentKey = val.substr(0, val.lastIndexOf('.')); 1338 val = this.get(val); // Resolve "val" from context, or JSON literal 1339 if (autoBind && !this.isJSON.test(val) && parentKey.includes('.')) { 1340 val = val.bind(this.get(parentKey)); // Parent is sub-obj, bind 1341 } 1342 } 1343 target[key] = val; // Assign the value to it's parent object 1344 } 1345}); 1346 1347modulo.register('core', class DOMLoader { 1348 constructor(modulo) { 1349 this.modulo = modulo; // TODO: need to standardize back references to prevent mismatches 1350 } 1351 1352 getAllowedChildTags(parentName) { 1353 let tagsLower = this.modulo.config.domloader.topLevelTags; // "Modulo" 1354 if (/^_[a-z][a-zA-Z]+$/.test(parentName)) { // _likethis, e.g. _artifact 1355 tagsLower = [ parentName.toLowerCase().replace('_', '') ]; // Dead code? 1356 } else if (parentName) { // Normal parent, e.g. Library, Component etc 1357 const parentDef = this.modulo.definitions[parentName]; 1358 const msg = `Invalid parent: ${ parentName } (${ parentDef })`; 1359 this.modulo.assert(parentDef && parentDef.Contains, msg); 1360 const names = Object.keys(this.modulo.registry[parentDef.Contains]); 1361 tagsLower = names.map(s => s.toLowerCase()); // Ignore case 1362 } 1363 return tagsLower; 1364 } 1365 1366 loadFromDOM(elem, parentName = null, quietErrors = false) { 1367 const { defaultDef } = this.modulo.config.modulo; 1368 const toCamel = s => s.replace(/-([a-z])/g, g => g[1].toUpperCase()); 1369 const tagsLower = this.getAllowedChildTags(parentName); 1370 const array = []; 1371 for (const node of elem.children || []) { 1372 const partTypeLC = this.getDefType(node, tagsLower, quietErrors); 1373 if (node._moduloLoadedBy || partTypeLC === null) { 1374 continue; // Already loaded, or an ignorable or silenced error 1375 } 1376 node._moduloLoadedBy = this.modulo.id; // Mark as having loaded this 1377 // Valid definition, now create the "def" object 1378 const def = Object.assign({ Parent: parentName }, defaultDef); 1379 def.Content = node.tagName === 'SCRIPT' ? node.textContent : node.innerHTML; 1380 array.push(Object.assign(def, this.modulo.config[partTypeLC])); 1381 for (let name of node.getAttributeNames()) { // Loop through attrs 1382 const value = node.getAttribute(name); 1383 if (partTypeLC === name && !value) { // e.g. <def Script> 1384 continue; // This is the "Type" attribute itself, skip 1385 } 1386 def[toCamel(name)] = value; // "-kebab-case" to "CamelCase" 1387 } 1388 } 1389 this.modulo.repeatProcessors(array, 'DefLoaders'); 1390 return array; 1391 } 1392 1393 getDefType(node, tagsLower, quiet = false) { 1394 const { tagName, nodeType, textContent } = node; 1395 if (nodeType !== 1) { // Text nodes, comment nodes, etc 1396 if (nodeType === 3 && textContent && textContent.trim() && !quiet) { 1397 console.error(`Unexpected text in definition: ${textContent}`); 1398 } 1399 return null; 1400 } 1401 let defType = tagName.toLowerCase(); 1402 if (defType in this.modulo.config.domloader.genericDefTags) { 1403 for (const attrUnknownCase of node.getAttributeNames()) { 1404 const attr = attrUnknownCase.toLowerCase(); 1405 if (!node.getAttribute(attr) && tagsLower.includes(attr)) { 1406 defType = attr; // Has an empty string value, is a def 1407 } 1408 break; // Always break: We will only look at first attribute 1409 } 1410 } 1411 if (!(tagsLower.includes(defType))) { // Were any discovered? 1412 if (defType === 'testsuite') { return null; } /* TODO Remove and add recipe to stub / silence TestSuite not found errors */ 1413 if (!quiet) { // Invalid def / cPart: This type is not allowed here 1414 console.error(`"${ defType }" is not one of: ${ tagsLower }`); 1415 } 1416 return null // Return null to signify not a definition 1417 } 1418 return defType; // Valid, expected definition: Return lowercase type 1419 } 1420}, { 1421 topLevelTags: [ 'modulo' ], // Only "Modulo" is top 1422 genericDefTags: { def: 1, script: 1, template: 1, style: 1 }, 1423}); 1424 1425modulo.register('processor', function src (modulo, def, value) { 1426 const { getParentDefPath } = modulo.registry.utils; 1427 def.Source = (new window.URL(value, getParentDefPath(modulo, def))).href; 1428 modulo.fetchQueue.fetch(def.Source).then(text => { 1429 def.Content = (text || '') + (def.Content || ''); 1430 }); 1431}); 1432 1433modulo.register('processor', function srcSync (modulo, def, value) { 1434 modulo.registry.processors.src(modulo, def, value); 1435 return true; // Only difference is return "true" for "wait" (TODO: Refactor to "return def.SrcSync ? false" then specify on Configuration) 1436}); 1437 1438modulo.register('processor', function defTarget (modulo, def, value) { 1439 const resolverName = def.DefResolver || 'ValueResolver'; // TODO: document 1440 const resolver = new modulo.registry.core[resolverName](modulo); 1441 const target = value === null ? def : resolver.get(value); // Target object 1442 for (const [ key, defValue ] of Object.entries(def)) { // Resolve all values 1443 if (key.endsWith(':') || key.includes('.')) { 1444 delete def[key]; // Remove & replace unresolved value 1445 //resolver.set(/[^a-z]/.test(key) ? target : def, key, defValue); // TODO: Probably should be this -- not sure how this interacts with if 1446 resolver.set(/^[a-z]/.test(key) ? target : def, key, defValue); 1447 } 1448 } 1449}); 1450 1451modulo.register('processor', function content (modulo, conf, value) { 1452 modulo.loadString(value, conf.DefinitionName); 1453}); 1454 1455modulo.register('processor', function definedAs (modulo, def, value) { 1456 def.Name = value ? def[value] : (def.Name || def.Type.toLowerCase()); 1457 const parentDef = modulo.definitions[def.Parent]; 1458 const parentPrefix = parentDef && ('ChildPrefix' in parentDef) ? 1459 parentDef.ChildPrefix : (def.Parent ? def.Parent + '_' : ''); 1460 def.DefinitionName = parentPrefix + def.Name; 1461 // Search for the next free Name by suffixing numbers 1462 while (def.DefinitionName in modulo.definitions) { 1463 const match = /([0-9]+)$/.exec(def.Name); 1464 const number = match ? match[0] : ''; 1465 def.Name = def.Name.replace(number, '') + ((number * 1) + 1); 1466 def.DefinitionName = parentPrefix + def.Name; 1467 } 1468 modulo.definitions[def.DefinitionName] = def; // store definition 1469 const parentConf = modulo.definitions[def.Parent]; 1470 if (parentConf) { 1471 parentConf.ChildrenNames = parentConf.ChildrenNames || []; 1472 parentConf.ChildrenNames.push(def.DefinitionName); 1473 } 1474}); 1475 1476modulo.register('util', function initComponentClass (modulo, def, cls) { 1477 // Run factoryCallback static lifecycle method to create initRenderObj 1478 const initRenderObj = { elementClass: cls }; 1479 for (const defName of def.ChildrenNames) { 1480 const cpartDef = modulo.definitions[defName]; 1481 const cpartCls = modulo.registry.cparts[cpartDef.Type]; 1482 if (cpartCls.factoryCallback) { 1483 const result = cpartCls.factoryCallback(initRenderObj, cpartDef, modulo); 1484 initRenderObj[cpartDef.RenderObj || cpartDef.Name] = result; 1485 } 1486 } 1487 1488 cls.prototype.init = function init () { 1489 this.modulo = modulo; 1490 this.isMounted = false;
1491 this.isModulo = true; 1492 this.originalHTML = null; 1493 this.originalChildren = []; 1494 this.cparts = modulo.instanceParts(def, { element: this }); 1495 }; 1496 modulo._connectedQueue = modulo._connectedQueue || []; // Ensure array 1497 modulo._drainQueue = () => { // "Clusters" all moduloMount calls 1498 while (modulo._connectedQueue.length > 0) { // Drains + invokes 1499 modulo._connectedQueue.shift().moduloMount(); 1500 } 1501 }; 1502 cls.prototype.connectedCallback = function connectedCallback () { 1503 modulo._connectedQueue.push(this); 1504 window.setTimeout(modulo._drainQueue, 0); 1505 }; 1506 cls.prototype.moduloMount = function moduloMount(force = false) { 1507 if ((!this.isMounted && window.document.contains(this)) || force) { 1508 this.cparts.component._lifecycle([ 'initialized', 'mount', 'mountRender' ]); 1509 } 1510 }; 1511 cls.prototype.initRenderObj = initRenderObj; 1512 cls.prototype.rerender = function (original = null) { 1513 if (!this.isMounted) { // Not mounted, do Mount which will also rerender 1514 return this.moduloMount(); 1515 } 1516 this.cparts.component.rerender(original); // Otherwise, normal rerender 1517 }; 1518 cls.prototype.getCurrentRenderObj = function () { 1519 return this.cparts.component.getCurrentRenderObj(); 1520 }; 1521 modulo.register('element', cls); // All elements get registered centrally 1522}); 1523 1524modulo.register('util', function makeStore (modulo, def) { 1525 const isLower = key => key[0].toLowerCase() === key[0]; // skip "-prefixed" 1526 let data = modulo.registry.utils.keyFilter(def, isLower); // Get defaults 1527 data = JSON.parse(JSON.stringify(data)); // Deep copy to ensure primitives 1528 return { data, boundElements: {}, subscribers: [] }; 1529}); 1530 1531modulo.register('processor', function mainRequire (modulo, conf, value) { 1532 modulo.assets.mainRequire(value); 1533}); 1534 1535modulo.config.artifact = { 1536 BuildCommandFinalizers: [ 'SaveArtifact' ], 1537 SaveArtifact: null, 1538 DefinedAs: 'name', 1539 exclude: '[modulo-asset]', 1540}; 1541modulo.register('coreDef', class Artifact { 1542 static SaveArtifact (modulo, def, value) { // Build processor 1543 const artifactInstance = modulo.instance(def, { }); 1544 artifactInstance.buildCommand(document); // e is document or target 1545 return true; // Always wait for next 1546 } 1547 1548 getBundle(targetElem) { // TODO: Mix in targetElem to QSA 1549 const bundledElems = []; 1550 for (const elem of targetElem.querySelectorAll(this.conf.bundle)) { 1551 const url = elem.getAttribute('src') || elem.getAttribute('href'); 1552 if (this.conf.exclude && elem.matches(this.conf.exclude) || !url) { 1553 continue; // Need skip, otherwise it chokes assets or blank src 1554 } 1555 this.modulo.fetchQueue.fetch(url).then(text => { // Enqueue fetch 1556 delete this.modulo.fetchQueue.data[url]; // remove from cache 1557 elem.bundledContent = text; // attach back to element for later 1558 }); 1559 bundledElems.push(elem); 1560 } 1561 return bundledElems; 1562 } 1563 getTemplateContext(targetElem) { 1564 const head = targetElem.head || { innerHTML: '' }; 1565 const body = targetElem.body || { innerHTML: '', id: '' }; 1566 const htmlPrefix = '<!DOCTYPE html><html><head>' + head.innerHTML; 1567 const htmlInterfix = '</head><body id="' + body.id + '">' + body.innerHTML; 1568 const htmlSuffix = '</body></html>'; 1569 const bundle = this.conf.bundle ? this.getBundle(targetElem) : null; 1570 const extras = { htmlPrefix, htmlInterfix, htmlSuffix, bundle }; 1571 return Object.assign({ }, this.modulo, extras); 1572 } 1573 1574 buildCommand(targetElem) { 1575 const { Template } = this.modulo.registry.cparts; 1576 const { saveFileAs, hash } = this.modulo.registry.utils; 1577 const { DefinitionName, remove, urlName, name, Content } = this.conf; 1578 const def = this.modulo.definitions[DefinitionName]; // Get original def 1579 if (remove) { // Need to remove elements from document first 1580 targetElem.querySelectorAll(remove).forEach(elem => elem.remove()); 1581 } 1582 this.templateContext = this.getTemplateContext(targetElem); // Queue up 1583 this.modulo.fetchQueue.enqueue(() => { // Drain queue before continue 1584 const tmplt = new Template(Content); // Render file Artifact content 1585 const content = tmplt.render(this.templateContext); 1586 def.FileName = `modulo-build-${ hash(content) }.${ name }`; 1587 if (urlName) { // Guess filename based on URL (or use as default) 1588 def.FileName = window.location.pathname.split('/').pop() || urlName; 1589 } 1590 def.OutputPath = saveFileAs(def.FileName, content); // Attempt save 1591 }); 1592 } 1593}); 1594 1595modulo._DEVLIB_SOURCE = (` 1596<Artifact name="css" bundle="link[rel=stylesheet]"> 1597 {% for elem in bundle %}{{ elem.bundledContent|default:''|safe }} 1598 {% endfor %}{% for css in assets.cssAssetsArray %} 1599 {{ css|safe }}{% endfor %} 1600</Artifact> 1601<Artifact name="js" bundle="script[src]"> 1602 window.moduloBuild = window.moduloBuild || { modules: {}, nameToHash: {} }; 1603 {% for name, hash in assets.nameToHash %}{% if hash in assets.moduleSources %}{% if name|first is not "_" %} 1604 window.moduloBuild.modules["{{ hash }}"] = function {{ name }} (modulo) { 1605 {{ assets.moduleSources|get:hash|safe }} 1606 }; 1607 window.moduloBuild.nameToHash.{{ name }} = "{{ hash }}"; 1608 {% endif %}{% endif %}{% endfor %} 1609 window.moduloBuild.definitions = { {% for name, value in definitions %} 1610 {% if name|first is not "_" %}{{ name }}: {{ value|json|safe }},{% endif %} 1611 {% endfor %} }; 1612 {% if bundle %} 1613 {% for elem in bundle %}{{ elem.bundledContent|default:''|safe }}{% endfor %} 1614 modulo.assets.modules = window.moduloBuild.modules; 1615 modulo.assets.nameToHash = window.moduloBuild.nameToHash; 1616 modulo.definitions = window.moduloBuild.definitions; 1617 {% endif %} 1618 {% for name in assets.mainRequires %} 1619 modulo.assets.require("{{ name|escapejs }}"); 1620 {% endfor %} 1621</Artifact> 1622<Artifact name="html" url-name="index.html" remove="script[src],link[href],[modulo-asset],template[modulo],script[modulo],modulo"> 1623 {{ htmlPrefix|safe }}<link rel="stylesheet" href="{{ definitions._artifact_css.OutputPath }}" /> 1624 {{ htmlInterfix|safe }}<script src="{{ definitions._artifact_js.OutputPath }}"></s` + `cript> 1625 {{ htmlSuffix|safe }} 1626</Artifact> 1627`).replace(/^\s+/gm, ''); // Removing indentation from DEVLIB_SOURCE 1628 1629modulo.config.component = { 1630 tagAliases: { }, //tagAliases: { 'html-table': 'table', 'html-script': 'script' }, // shortcut for syntax issues 1631 mode: 'regular', 1632 rerender: 'event', 1633 engine: 'Reconciler', // TODO: RM, dead code 1634 Contains: 'cparts', 1635 CustomElement: 'window.HTMLElement', 1636 DefinedAs: 'name', 1637 BuildLifecycle: 'build', 1638 RenderObj: 'component', // Make features available as "renderObj.component"
1639 // Children: 'cparts', // How we can implement Parentage: Object.keys((get('modulo.registry.' + value))// cparts)) 1640 DefLoaders: [ 'DefTarget', 'DefinedAs', 'Src', 'Content' ], 1641 DefBuilders: [ 'CustomElement', 'alias|AliasNamespace', 'CodeTemplate' ], 1642 DefFinalizers: [ 'MainRequire' ], 1643 BuildCommandBuilders: [ 'Prebuild|BuildLifecycle', 'BuildLifecycle' ], 1644 //Directives: [ 'slotLoad', 'eventMount', 'eventUnmount', 'dataPropMount', 'dataPropUnmount' ], 1645 Directives: [ 'eventMount', 'eventUnmount', 'dataPropMount', 'dataPropUnmount' ], 1646 CodeTemplate: ` 1647 const def = modulo.definitions['{{ def.DefinitionName }}']; 1648 class {{ def.className }} extends {{ def.baseClass|default:'window.HTMLElement' }} { 1649 constructor() { super(); this.init(); } 1650 } 1651 modulo.registry.utils.initComponentClass(modulo, def, {{ def.className }}); 1652 window.customElements.define(def.TagName, {{ def.className }}); 1653 return {{ def.className }}; 1654 `.replace(/^\s+/gm, ''), 1655}; 1656 1657modulo.register('coreDef', class Component { 1658 static CustomElement (modulo, def, value) { 1659 if (!def.ChildrenNames || def.ChildrenNames.length === 0) { 1660 console.warn('MODULO: Empty ChildrenNames:', def.DefinitionName); 1661 return; 1662 } else if (def.namespace === null || def.alias) { // Auto-gen 1663 def.namespace = def.namespace || def.DefinitionName; 1664 } else if (!def.namespace) { // Otherwise default to the Modulo def conf 1665 def.namespace = modulo.config.namespace || 'x'; // or simply 'x-' 1666 } 1667 def.name = def.name || def.DefName || def.Name; 1668 def.TagName = `${ def.namespace }-${ def.name }`.toLowerCase(); 1669 def.MainRequire = def.DefinitionName; 1670 def.className = def.className || `${ def.namespace }_${ def.name }`; 1671 } 1672 1673 static BuildLifecycle (modulo, def, value) { 1674 for (const elem of document.querySelectorAll(def.TagName)) { 1675 elem.cparts.component._lifecycle([ value ]); // Run the lifecycle 1676 } 1677 return true; 1678 } 1679 1680 static AliasNamespace (modulo, def, value) { 1681 const fullAlias = `${ value }-${ def.name }`; // Combine new NS and name 1682 modulo.config.component.tagAliases[fullAlias] = def.TagName; 1683 } 1684 1685 rerender(original = null) { 1686 if (original) { 1687 if (this.element.originalHTML === null) { 1688 this.element.originalHTML = original.innerHTML; 1689 } 1690 this.element.originalChildren = Array.from( 1691 original.hasChildNodes() ? original.childNodes : []); 1692 } 1693 this._lifecycle([ 'prepare', 'render', 'dom', 'reconcile', 'update' ]); 1694 } 1695 1696 buildCallback() { 1697 const PRE = 'modulo-mount-'; // Prefix used for attributes 1698 if (this.element.originalHTML !== this.element.innerHTML) { 1699 this.element.setAttribute(PRE + 'html', this.element.originalHTML); 1700 } 1701 const nodes = Array.from(this.element.querySelectorAll('*')); 1702 for (const [ node, method, arg ] of this._mountPatchset || []) { 1703 const { rawName, el } = arg || {}; // Extract needed directive info 1704 const count = el ? nodes.filter(e => e.contains(el)).length : 0; 1705 if (count) { // count = number of steps in tree hierarchy (or 0) 1706 const existing = el.getAttribute(PRE + 'patches') || ''; 1707 if (!existing.includes(count + ',' + rawName)) { // Not a dupe 1708 const value = existing + '\n' + count + ',' + rawName; 1709 el.setAttribute(PRE + 'patches', value.trim()); 1710 } 1711 } 1712 } 1713 } 1714 1715 getCurrentRenderObj() { 1716 return (this.element.eventRenderObj || this.element.renderObj || this.element.initRenderObj); 1717 } 1718 1719 _lifecycle(lifecycleNames, rObj={}) { 1720 const renderObj = Object.assign({}, rObj, this.getCurrentRenderObj()); 1721 this.element.renderObj = renderObj; 1722 this.modulo.lifecycle(this.element.cparts, renderObj, lifecycleNames); 1723 //this.element.renderObj = null; // ?rendering is over, set to null 1724 } 1725 1726 initializedCallback() { 1727 const { newNode } = this.modulo.registry.utils; 1728 const opts = { directiveShortcuts: [], directives: [] }; // TODO: Move this to reconciler 1729 for (const cPart of Object.values(this.element.cparts)) { 1730 const def = (cPart.def || cPart.conf); 1731 for (const method of def.Directives || []) { 1732 const dirName = (def.RenderObj || def.Name) + '.' + method; 1733 opts.directives[dirName] = cPart; 1734 } 1735 } 1736 this.reconciler = new this.modulo.registry.core.Reconciler(this.modulo, opts); 1737 this.resolver = new this.modulo.registry.core.ValueResolver(this.modulo); 1738 const html = this.element.getAttribute('modulo-mount-html'); // Hydrate? 1739 this._mountRival = html === null ? this.element : newNode(html); 1740 this.element.originalHTML = html === null ? this.element.innerHTML : html; 1741 } 1742 1743 mountCallback() { // Prepare the element, "hydrating" the "mount-patches" 1744 const ATTR = 'modulo-mount-patches'; // Attribute used 1745 const { get } = this.modulo.registry.utils; 1746 for (const elem of this.element.querySelectorAll(`[${ ATTR }]`)) { 1747 for (const line of elem.getAttribute(ATTR).split('\n')) { 1748 const [ count, rawName ] = line.split(','); // Comma seperated 1749 const nodePath = '.parentNode'.repeat(count).substr(1); 1750 if (this.element === get(elem, nodePath)) { // It's me! 1751 this.reconciler.patchDirectives(elem, rawName, 'Mount'); 1752 const newVal = elem.getAttribute(ATTR).replace(line, ''); 1753 elem.setAttribute(ATTR, newVal); // "Consume" line from attr 1754 } 1755 } 1756 } 1757 } 1758 1759 mountRenderCallback() { // First "mount", trigger render & hydration 1760 this.reconciler.applyPatches(this.reconciler.patches); // From "mount" 1761 this.rerender(this._mountRival); // render + mount childNodes 1762 delete this._mountRival; // Clear the temporary reference 1763 this.element.isMounted = true; // Mark as mounted 1764 } 1765 1766 prepareCallback() { 1767 return { // Create the initial Component renderObj obj 1768 originalHTML: this.element.originalHTML, // HTML received at mount 1769 id: this.id, // Universally unique ID number
1770 innerHTML: null, // String to copy (default: null is "no-op") 1771 innerDOM: null, // Node to copy (default: null sets innerHTML) 1772 patches: null, // Patch array (default: reconcile vs innerDOM) 1773 slots: { }, // Populate with slots to be filled when reconciling 1774 }; 1775 } 1776 1777 domCallback(renderObj) { 1778 const { clone, newNode } = this.modulo.registry.utils; 1779 let { slots, root, innerHTML, innerDOM } = renderObj.component; 1780 if (this.attrs.mode === 'regular' || this.attrs.mode === 'vanish') { 1781 root = this.element; // default, use element as root 1782 } else if (this.attrs.mode === 'shadow') { 1783 if (!this.element.shadowRoot) { 1784 this.element.attachShadow({ mode: 'open' }); 1785 } 1786 root = this.element.shadowRoot; // render into attached shadow 1787 } else if (this.attrs.mode === 'vanish-into-document') { 1788 root = this.element.ownerDocument.body; // render into body 1789 } else if (!root) { 1790 this.modulo.assert(this.attrs.mode === 'custom-root', 'Bad mode') 1791 } 1792 if (innerHTML !== null && !innerDOM) { // Use component.innerHTML as DOM 1793 innerDOM = newNode(innerHTML); 1794 } 1795 if (innerDOM && this.attrs.mode === 'vanish-into-document') { 1796 for (const el of innerDOM.querySelectorAll('script,link,title,meta')) { 1797 this.element.ownerDocument.head.append(clone(el)); // Move clone 1798 el.remove(); // Old one is removed from previous location 1799 } 1800 } 1801 if (innerDOM && this.attrs.mode !== 'shadow') { 1802 for (const elem of this.element.originalChildren) { 1803 const name = (elem.getAttribute && elem.getAttribute('slot')) || ''; 1804 elem.remove(); // Remove from DOM so it can't self-match 1805 if (!(name in slots)) { 1806 slots[name] = [ elem ]; // Sorting into new slot arrays 1807 } else { 1808 slots[name].push(elem); // Or pushing into existing 1809 } 1810 } 1811 } 1812 return { root, innerHTML, innerDOM, slots }; 1813 } 1814 1815 reconcileCallback(renderObj) { 1816 let { innerHTML, innerDOM, patches, root, slots } = renderObj.component; 1817 if (innerDOM) { 1818 this.reconciler.patches = []; // Reset reconciler patches 1819 this.reconciler.reconcileChildren(root, innerDOM, slots); 1820 patches = this.reconciler.patches; 1821 } 1822 return { patches, innerHTML }; // TODO remove innerHTML from here 1823 } 1824 1825 updateCallback(renderObj) { 1826 const { patches } = renderObj.component; 1827 if (patches) { 1828 this._mountPatchset = this._mountPatchset || patches; // 1st render 1829 this.reconciler.applyPatches(patches); // Apply patches to DOM 1830 } 1831 if (this.attrs.mode === 'vanish') { // If we need to vanish, do it now 1832 this.element.replaceWith(...this.element.childNodes); 1833 } 1834 } 1835 1836 handleEvent(func, payload, ev) { 1837 this._lifecycle([ 'event' ]); 1838 func(payload === undefined ? ev : payload); 1839 this._lifecycle([ 'eventCleanup' ]); 1840 if (this.attrs.rerender !== 'manual') { // TODO: Change patch('rerender') to "requestRerender" (or update the HTMLElement method) 1841 this.element.rerender(); // always rerender after events 1842 } 1843 } 1844 1845 eventMount({ el, value, attrName, rawName }) { 1846 const { resolveDataProp } = this.modulo.registry.utils; 1847 const get = (key, key2) => resolveDataProp(key, el, key2 && get(key2)); 1848 this.modulo.assert(get(attrName), `Not found: ${ rawName }=${ value }`); 1849 el.moduloEvents = el.moduloEvents || {}; // Attach if not already 1850 const listen = ev => { // Define a listen event func to run handleEvent 1851 ev.preventDefault(); 1852 const payload = get(attrName + '.payload', 'payload'); 1853 this.handleEvent(resolveDataProp(attrName, el), payload, ev); 1854 }; 1855 el.moduloEvents[attrName] = listen; 1856 el.addEventListener(attrName, listen); 1857 } 1858 1859 eventUnmount({ el, attrName }) { 1860 if (el.moduloEvents) { // TODO: Remove this check 1861 el.removeEventListener(attrName, el.moduloEvents[attrName]); 1862 delete el.moduloEvents[attrName]; 1863 } 1864 } 1865 1866 dataPropMount({ el, value, attrName, rawName }) { // element, 1867 // Resolve the given value and attach to dataProps 1868 if (!el.dataProps) { 1869 el.dataProps = {}; 1870 el.dataPropsAttributeNames = {}; 1871 } 1872 const resolver = new this.modulo.registry.core.ValueResolver(// OLD TODO: Global modulo 1873 this.element && this.element.getCurrentRenderObj()); 1874 resolver.set(el.dataProps, attrName + ':', value, true); 1875 el.dataPropsAttributeNames[rawName] = attrName; 1876 } 1877 1878 dataPropUnmount({ el, attrName, rawName }) { 1879 if (!el.dataProps) { console.log('Modulo ERROR: Could not Unmount', attrName, rawName, el); } 1880 if (el.dataProps) { 1881 delete el.dataProps[attrName]; 1882 delete el.dataPropsAttributeNames[rawName]; 1883 } 1884 } 1885}); 1886 1887modulo.register('coreDef', class Library { }, {
1888 Contains: 'coreDefs', 1889 DefTarget: 'config.component', 1890 DefLoaders: [ 'DefTarget', 'DefinedAs', 'Src', 'Content' ], 1891}); 1892 1893modulo.register('util', function keyFilter (obj, func) { 1894 const keys = func.call ? Object.keys(obj).filter(func) : func; 1895 return Object.fromEntries(keys.map(key => [ key, obj[key] ])); 1896}); 1897 1898modulo.register('util', function resolveDataProp (key, elem, defaultVal) { 1899 if (elem.dataProps && key in elem.dataProps) { 1900 return elem.dataProps[key]; 1901 } 1902 return elem.hasAttribute(key) ? elem.getAttribute(key) : defaultVal; 1903}); 1904 1905modulo.register('util', function cleanWord (text) { 1906 // todo: should merge with stripWord ? See if "strip" functionality is enough 1907 return (text + '').replace(/[^a-zA-Z0-9$_\.]/g, '') || ''; 1908}); 1909 1910modulo.register('util', function stripWord (text) { 1911 return text.replace(/^[^a-zA-Z0-9$_\.]/, '') 1912 .replace(/[^a-zA-Z0-9$_\.]$/, ''); 1913}); 1914 1915modulo.register('util', function clone (el) { // Clones an element 1916 const newElement = window.document.createElement(el.tagName); 1917 for (const attr of el.attributes) { // Copy all attributes from old elem 1918 newElement.setAttributeNode(attr.cloneNode(true)); // ...to new elem 1919 } 1920 newElement.textContent = el.textContent; // (e.g. <title>Hi</title>) 1921 if (el.tagName === 'SCRIPT') { // Need to fix SCRIPT tag fluke 1922 newElement.src = el.src; // (TODO: Still needed?) 1923 } 1924 return newElement; 1925}); 1926 1927modulo.register('util', function hash (str) { 1928 // Simple, insecure, "hashCode()" implementation. Returns base32 hash 1929 let h = 0; 1930 for (let i = 0; i < str.length; i++) { 1931 //h = ((h << 5 - h) + str.charCodeAt(i)) | 0; 1932 h = Math.imul(31, h) + str.charCodeAt(i) | 0; 1933 } 1934 const hash8 = ('---------' + (h || 0).toString(32)).slice(-8); 1935 return hash8.replace(/-/g, 'x'); // Pad with 'x' 1936}); 1937 1938modulo.register('util', function newNode(innerHTML, tag) { 1939 const obj = { innerHTML }; // Extra properties to assign 1940 return Object.assign(window.document.createElement(tag || 'div'), obj); 1941}); 1942modulo.registry.utils.makeDiv = modulo.registry.utils.newNode; // TODO: Rm alias 1943 1944modulo.register('util', function normalize(html) { 1945 // Normalize space to ' ' & trim around tags 1946 return html.replace(/\s+/g, ' ').replace(/(^|>)\s*(<|$)/g, '$1$2').trim(); 1947}); 1948 1949modulo.register('util', function escapeRegExp(s) { 1950 return s.replace(/[.*+?^${}()|[\]\\]/g, "\\" + "\x24" + "&"); 1951}); 1952 1953modulo.register('util', function saveFileAs(filename, text) { 1954 const element = window.document.createElement('a'); 1955 const enc = window.encodeURIComponent(text); 1956 element.setAttribute('href', 'data:text/plain;charset=utf-8,' + enc); 1957 element.setAttribute('download', filename); 1958 window.document.body.appendChild(element); 1959 element.click(); 1960 window.document.body.removeChild(element); 1961 return `./${filename}`; // by default, return local path 1962}); 1963 1964modulo.register('util', function get(obj, key) { 1965 return (key in obj) ? obj[key] : (key + '').split('.').reduce((o, name) => o[name], obj); 1966}); 1967 1968modulo.register('util', function set(obj, keyPath, val) { 1969 return new window.modulo.registry.core.ValueResolver(window.modulo).set(obj, keyPath, val); 1970}); 1971 1972modulo.register('util', function getParentDefPath(modulo, def) { 1973 const { getParentDefPath } = modulo.registry.utils; // Use to recurse 1974 const pDef = def.Parent ? modulo.definitions[def.Parent] : null; 1975 const url = String(window.location).split('?')[0]; // Remove ? and # 1976 return pDef ? pDef.Source || getParentDefPath(modulo, pDef) : url; 1977}); 1978 1979modulo.register('core', class AssetManager { 1980 constructor (modulo) { // TODO: Refactor this class into util / processors 1981 this.modulo = modulo; 1982 this.stylesheets = {}; // Object with hash of CSS (prevents double add) 1983 this.cssAssetsArray = []; // List of CSS assets added, in order 1984 this.modules = {}; // Object containing JS functions with hashed keys 1985 this.moduleSources = {}; // Source code of JS functions (for build) 1986 this.nameToHash = {}; // Reversable hash / human name for modules 1987 this.mainRequires = []; // List of globally invoked modules 1988 } 1989 1990 mainRequire(moduleName) { 1991 this.mainRequires.push(moduleName); 1992 this.require(moduleName); 1993 } 1994 1995 require(moduleName) { 1996 // TODO: Don't use nameToHash for simpler look-up, but include 1997 // "hashToName" for deduping during add (just create extra refs) 1998 this.modulo.assert(moduleName in this.nameToHash, 1999 `${ moduleName } not in ${ Object.keys(this.nameToHash).join(', ') }`); 2000 const hash = this.nameToHash[moduleName]; 2001 this.modulo.assert(hash in this.modules, 2002 `${ moduleName } / ${ hash } not in ${ Object.keys(this.modules).join(', ') }`); 2003 return this.modules[hash].call(window, this.modulo); 2004 } 2005 2006 define(name, code) { 2007 const hash = this.modulo.registry.utils.hash(code); 2008 this.modulo.assert(!(name in this.nameToHash), `Duplicate: ${ name }`); 2009 this.nameToHash[name] = hash; 2010 if (!(hash in this.modules)) { 2011 this.moduleSources[hash] = code; 2012 const assignee = `window.modulo.assets.modules["${ hash }"] = `; 2013 const prefix = assignee + `function ${ name }
2013 (modulo) {\n`; 2014 this.appendToHead('script', `"use strict";${ prefix }${ code }};\n`); 2015 } 2016 } 2017 2018 appendToHead(tagName, codeStr) { 2019 const doc = window.document; 2020 if (!doc || !doc.head) { // Fall back to just using a Function 2021 return new Function('window', 'modulo', codeStr)(window, this.modulo); 2022 } 2023 const elem = doc.createElement(tagName); 2024 elem.setAttribute('modulo-asset', 'y'); // Mark as an "asset" 2025 doc.head.append(elem); 2026 elem.textContent = codeStr; // Blocking, causes eval 2027 } 2028}); 2029 2030modulo.register('core', class FetchQueue { 2031 constructor(modulo, queue = {}, data = {}) { 2032 Object.assign(this, { modulo, queue, data }); 2033 this.wait = callback => this.enqueue(callback, true); // TODO: RM this alias 2034 } 2035 2036 fetch(src) { // Returns "thennable" that somewhat resembles window.fetch 2037 return { then: callback => this.request(src, callback, console.error) }; 2038 } 2039 2040 request(src, resolve, reject) { // Do fetch & do enqueue 2041 if (src in this.data) { // Cached data found 2042 resolve(this.data[src], src); // (sync route) 2043 } else if (!(src in this.queue)) { // No cache, no queue 2044 this.queue[src] = [ resolve ]; // First time, create the queue Array 2045 const { force, callbackName } = this.modulo.config.fetchqueue; 2046 if ((!force && src.startsWith('file:/')) || force === 'file') { 2047 window[callbackName] = str => { this.__data = str }; 2048 const elem = window.document.createElement('SCRIPT'); 2049 elem.onload = () => this.receiveData(this.__data, src); 2050 elem.src = src + (src.endsWith('/') ? 'index.html' : ''); 2051 elem.setAttribute('modulo-asset', 'y'); // Stay out of build 2052 window.document.head.append(elem); // Actually execute request 2053 } else { // Otherwise, use normal fetch transport method 2054 window.fetch(src, { cache: 'no-store' }) 2055 .then(response => response.text()) 2056 .then(text => this.receiveData(text, src)) 2057 .catch(reject); 2058 } 2059 } else { // Otherwise: Already requested, only enqueue function 2060 this.queue[src].push(resolve); 2061 } 2062 } 2063 2064 receiveData(text, src) { // Receive data, optionally trimming padding 2065 const { prefix, suffix } = this.modulo.config.fetchqueue.filePadding; 2066 if (text && text.startsWith(prefix) && prefix && text.trim().endsWith(suffix)) { 2067 text = text.trim().slice(prefix.length, 0 - suffix.length); // Clean 2068 } 2069 this.data[src] = text; // Keep retrieved data cached here for sync route 2070 const resolveCallbacks = this.queue[src]; 2071 delete this.queue[src]; 2072 for (const dataCallback of resolveCallbacks) { // Loop through callbacks 2073 dataCallback(text, src); 2074 } 2075 } 2076 2077 enqueue(callback, waitForAll = false) { // Wait for _current_ queue (or all) 2078 const allQueues = Array.from(Object.values(this.queue)); // Copy array 2079 if (allQueues.length === 0) { 2080 return callback(); 2081 } else if (waitForAll) { // Doing a "wait()" -- need to re-enqueue 2082 return this.enqueue(() => Object.keys(this.queue).length === 0 ? 2083 callback() : this.enqueue(callback, true)); 2084 } 2085 let count = 0; // Using count we only do callback() when ALL returned 2086 const check = () => ((++count >= allQueues.length) ? callback() : 0); 2087 allQueues.forEach(queue => queue.push(check)); // Add to every queue 2088 } 2089}, { 2090 callbackName: 'DOCTYPE_MODULO', 2091 filePadding: { prefix: '!DOCTYPE_MODULO(`', suffix: '`)' }, 2092}); 2093 2094modulo.register('cpart', class Props { 2095 initializedCallback(renderObj) { 2096 const props = {}; 2097 const { resolveDataProp } = this.modulo.registry.utils; 2098 for (const [ propName, def ] of Object.entries(this.attrs)) { 2099 props[propName] = resolveDataProp(propName, this.element, def); 2100 // TODO: Implement type-checked, and required 2101 } 2102 return props; 2103 } 2104 2105 prepareCallback(renderObj) { 2106 /* TODO: Remove after observedAttributes is implemented, e.g.: 2107 static factoryCallback({ attrs }, { componentClass }, renderObj) { 2108 //componentClass.observedAttributes = Object.keys(attrs); 2109 } 2110 */ 2111 return this.initializedCallback(renderObj); 2112 } 2113}); 2114 2115modulo.config.style = { 2116 AutoIsolate: true, // true is "default behavior" (autodetect) 2117 urlReplace: null, // null is "default behavior" (only if -src is specified) 2118 isolateSelector: null, // Later has list of selectors 2119 isolateClass: null, // By default, it does not use class isolation 2120 prefix: null, // Used to specify prefix-based isolation (most common) 2121 corePseudo: ['before', 'after', 'first-line', 'last-line' ], 2122 DefBuilders: [ 'FilterContent', 'AutoIsolate', 'Content|ProcessCSS' ], 2123}; 2124modulo.register('cpart', class Style { 2125 static AutoIsolate(modulo, def, value) { 2126 const { AutoIsolate } = modulo.registry.cparts.Style; // (for recursion) 2127 const { namespace, mode, Name } = modulo.definitions[def.Parent] || {}; 2128 if (value === true) { // Auto-detect based on parent's mode 2129 AutoIsolate(modulo, def, mode); // Check "mode" instead (1x recurse) 2130 } else if (value === 'regular' && !def.isolateClass) { // Use prefix 2131 def.prefix = def.prefix || `${ namespace }-${ Name }`; 2132 } else if (value === 'vanish') { // Vanish-based, specify "isolateClass" 2133 def.isolateClass = def.isolateClass || def.Parent; 2134 } 2135 } 2136 static processSelector (modulo, def, selector) { 2137 const hostPrefix = def.prefix || ('.' + def.isolateClass); 2138 if (def.isolateClass || def.prefix) { 2139 // Upgrade the ":host" or :root pseudo-elements to be the full name 2140 const hostRegExp = new RegExp(/:(host|root)(\([^)]*\))?/, 'g'); 2141 selector = selector.replace(hostRegExp, hostClause => { 2142 hostClause = hostClause.replace(/:(host|root)/gi, ''); 2143 return hostPrefix + (hostClause ? `:is(${ hostClause })` : ''); 2144 }); 2145 } 2146 let selectorOnly = selector.replace(/\s*[\{,]\s*,?$/, '').trim(); 2147 if (def.isolateClass && selectorOnly !== hostPrefix) { 2148 // Remove extraneous characters (and strip ',' for isolateSelector) 2149 let suffix = /{\s*$/.test(selector) ? ' {' : ', '; 2150 selectorOnly = selectorOnly.replace(/:(:?[a-z-]+)\s*$/i, (all, pseudo) => { 2151 if (pseudo.startsWith(':') || def.corePseudo.includes(pseudo)) {
2152 suffix = ':' + pseudo + suffix; // Attach to suffix, on outside 2153 return ''; // Strip pseudo from the selectorOnly variable 2154 } 2155 return all; 2156 }); 2157 def.isolateSelector.push(selectorOnly); // Add to array for later 2158 selector = `.${ def.isolateClass }:is(${ selectorOnly })` + suffix; 2159 } 2160 if (def.prefix && !selector.startsWith(def.prefix)) { 2161 // A prefix was specified, so prepend it if it doesn't have it 2162 selector = `${ def.prefix } ${ selector }`; 2163 } 2164 return selector; 2165 } 2166 static ProcessCSS (modulo, def, value) { 2167 if (def.isolateClass || def.prefix) { 2168 if (!def.keepComments) { 2169 value = value.replace(/\/\*.+?\*\//g, ''); // strip comments 2170 } 2171 def.isolateSelector = []; // Used to accumulate elements to select 2172 value = value.replace(/([^\r\n,{}]+)(,(?=[^}]*{)|\s*{)/gi, selector => { 2173 selector = selector.trim(); 2174 if (selector.startsWith('@') || selector.startsWith('from') 2175 || selector.startsWith('to')) { 2176 return selector; // Skip (e.g. is @media or @keyframes) 2177 } 2178 return this.processSelector(modulo, def, selector); 2179 }); 2180 } 2181 if (def.urlReplace || (def.urlReplace === null && def.Source)) { 2182 const key = def.urlReplace === 'absolute' ? 'href' : 'pathname'; 2183 value = value.replace(/url\(['"]?([^)]+?)['"]?\)/gi, (all, url) => { 2184 if (url.startsWith('.')) { // If relative, make absolute 2185 return `url("${ (new window.URL(url, def.Source))[key] }")`; 2186 } 2187 return all; // Not a relative URL, return all text untampered 2188 }); 2189 } 2190 const { mode } = modulo.definitions[def.Parent] || {}; 2191 if (mode === 'shadow') { // Stash in the definition configuration 2192 def.shadowContent = (def.shadowContent || '') + value; 2193 } else { // Otherwise, just "register" as a modulo asset 2194 def.headHash = modulo.registry.utils.hash(value); 2195 if (!(def.headHash in modulo.assets.stylesheets)) { 2196 modulo.assets.stylesheets[def.headHash] = value; 2197 modulo.assets.cssAssetsArray.push(value); 2198 } 2199 } 2200 } 2201 makeStyleTag(parentElem, content) { // Append <style> tag with content 2202 const style = window.document.createElement('style'); 2203 style.setAttribute('modulo-asset', 'y'); 2204 style.textContent = content; 2205 parentElem.append(style); 2206 } 2207 domCallback(renderObj) { 2208 const { mode } = modulo.definitions[this.conf.Parent] || {}; 2209 const { innerDOM, Parent } = renderObj.component; 2210 const { headHash, isolateClass, isolateSelector, shadowContent } = this.conf; 2211 if (isolateClass && isolateSelector && innerDOM) { // Attach classes 2212 const selector = isolateSelector.filter(s => s).join(',\n'); 2213 for (const elem of innerDOM.querySelectorAll(selector)){ 2214 elem.classList.add(isolateClass); 2215 } 2216 } 2217 if (shadowContent && innerDOM) { // Append to element to reconcile 2218 this.makeStyleTag(innerDOM, shadowContent); 2219 } 2220 const devStyles = this.modulo.assets.stylesheets; 2221 if (headHash && headHash in devStyles) { // Add to page: Hasn't been yet 2222 this.makeStyleTag(window.document.head, devStyles[headHash]); 2223 delete this.conf.headHash; // Consume, so it only happens once 2224 } 2225 } 2226}); 2227 2228modulo.register('cpart', class Template { 2229 static TemplatePrebuild (modulo, def, value) { 2230 modulo.assert(def.Content, `Empty Template: ${def.DefinitionName}`); 2231 const template = modulo.instance(def, { }); 2232 // def.Content = def.Content.trim(); // XXX TODO BREAKS IA ALL? 2233 const compiledCode = template.compileFunc(def.Content); 2234 const code = `return function (CTX, G) { ${ compiledCode } };`; 2235 // TODO: Refactor this to use define processor? 2236 modulo.assets.define(def.DefinitionName, code); 2237 delete def.Content; 2238 } 2239 constructor(text, options = null) { 2240 if (typeof text === 'string') { // Using "new" (direct JS interface) 2241 window.modulo.instance({ }, options || { }, this); // Setup object 2242 this.conf.DefinitionName = '_template_template' + this.id; // Unique 2243 const code = `return function (CTX, G) { ${ this.compileFunc(text) } };`; 2244 this.modulo.assets.define(this.conf.DefinitionName, code); 2245 } 2246 } 2247 2248 constructedCallback() { 2249 this.stack = []; // Parsing tag stack, used to detect unclosed tags 2250 // Combine conf from all sources: config, defaults, and "registered" 2251 const { filters, tags } = this.conf; 2252 const { defaultFilters, defaultTags } = this.modulo.config.template; 2253 const { templateFilters, templateTags } = this.modulo.registry; 2254 Object.assign(this, this.modulo.config.template, this.conf); 2255 // Set "filters" and "tags" with combined / squashed configuration 2256 this.filters = Object.assign({}, defaultFilters, templateFilters, filters); 2257 this.tags = Object.assign({}, defaultTags, templateTags, tags); 2258 } 2259 2260 initializedCallback() { 2261 return { render: this.render.bind(this) }; // Export "render" method 2262 } 2263 2264 renderCallback(renderObj) { 2265 if (this.conf.Name === 'template' || this.conf.active) { // If primary 2266 renderObj.component.innerHTML = this.render(renderObj); // Do render 2267 } 2268 } 2269 2270 parseExpr(text) { 2271 // Output JS code that evaluates an equivalent template code expression 2272 const filters = text.split('|'); 2273 let results = this.parseVal(filters.shift()); // Get left-most val 2274 for (const [ fName, arg ] of filters.map(s => s.trim().split(':'))) { 2275 // TODO: Store a list of variables / paths, so there can be 2276 // warnings or errors when variables are unspecified 2277 const argList = arg ? ',' + this.parseVal(arg) : ''; 2278 results = `G.filters["${fName}"](${results}${argList})`; 2279 } 2280 return results; 2281 } 2282 2283 parseCondExpr(string) { 2284 // Return an Array that splits around ops in an "if"-style statement 2285 const regExpText = ` (${this.opTokens.split(',').join('|')}) `; 2286 return string.split(RegExp(regExpText)); 2287 } 2288 2289 toCamel(string) { // Takes kebab-case and converts toCamelCase 2290 return string.replace(/-([a-z])/g, g => g[1].toUpperCase()); 2291 } 2292 2293 parseVal(string) { 2294 // Parses str literals, de-escaping as needed, numbers, and context vars 2295 const { cleanWord } = modulo.registry.utils;
2295 // TODO: RM this "safety" 2296 const s = string.trim(); 2297 if (s.match(/^('.*'|".*")$/)) { // String literal 2298 return JSON.stringify(s.substr(1, s.length - 2)); 2299 } 2300 return s.match(/^\d+$/) ? s : `CTX.${ cleanWord(this.toCamel(s)) }` 2301 } 2302 2303 escapeText(text) { 2304 if (text && text.safe) { 2305 return text; 2306 } 2307 return (text + '').replace(/&/g, '&') 2308 .replace(/</g, '<').replace(/>/g, '>') 2309 .replace(/'/g, ''').replace(/"/g, '"'); 2310 } 2311 2312 tokenizeText(text) { 2313 // Join all modeTokens with | (OR in regex) 2314 const { escapeRegExp } = this.modulo.registry.utils; 2315 const re = '(' + this.modeTokens.map(escapeRegExp).join('|(').replace(/ +/g, ')(.+?)'); 2316 return text.split(RegExp(re)).filter(token => token !== undefined); 2317 } 2318 2319 compileFunc(text) { 2320 const { normalize } = this.modulo.registry.utils; 2321 let code = 'var OUT=[];\n'; // Variable used to accumulate code 2322 let mode = 'text'; // Start in text mode 2323 const tokens = this.tokenizeText(text); 2324 for (const token of tokens) { 2325 if (mode) { // If in a "mode" (text or token), then call mode func 2326 const result = this.modes[mode](token, this, this.stack); 2327 if (result) { // Mode generated text output, add to code 2328 const comment = !this.disableComments ? '' : 2329 ' // ' + JSON.stringify(normalize(token).trim()); 2330 code += ` ${ result }${ comment }\n`; 2331 } 2332 } 2333 // FSM for mode: ('text' -> null) (null -> token) (* -> 'text') 2334 mode = (mode === 'text') ? null : (mode ? 'text' : token); 2335 } 2336 code += '\nreturn OUT.join("");' 2337 const unclosed = this.stack.map(({ close }) => close).join(', '); 2338 this.modulo.assert(!unclosed, `Unclosed tags: ${ unclosed }`); 2339 return code; 2340 } 2341 2342 render(renderObj) { 2343 if (!this.renderFunc) { // Run module and get function 2344 this.renderFunc = this.modulo.assets.require(this.conf.DefinitionName); 2345 } 2346 return this.renderFunc(Object.assign({ renderObj }, renderObj), this); 2347 } 2348}, { 2349 TemplatePrebuild: "y", // TODO: Refactor 2350 DefFinalizers: [ 'FilterContent', 'TemplatePrebuild' ], 2351 FilterContent: 'trim|tagswap:config.component.tagAliases', 2352 // textFilter: 'escape|etc', // TODO 2353 // TODO: Consider reserving "x" and "y" as temp vars, e.g. // (x = X, y = Y).includes ? y.includes(x) : (x in y) 2354 opTokens: '==,>,<,>=,<=,!=,not in,is not,is,in,not,gt,lt', 2355 opAliases: { 2356 '==': 'X === Y', 2357 'is': 'X === Y', 2358 'gt': 'X > Y', 2359 'lt': 'X < Y', 2360 'is not': 'X !== Y', 2361 'not': '!(Y)', 2362 'in': '(Y).includes ? (Y).includes(X) : (X in Y)', 2363 'not in': '!((Y).includes ? (Y).includes(X) : (X in Y))', 2364 }, 2365}); 2366 2367modulo.config.template.modeTokens = [ '{% %}', '{{ }}', '{# #}' ]; 2368modulo.config.template.modes = { 2369 '{%': (text, tmplt, stack) => { 2370 const tTag = text.trim().split(' ')[0]; 2371 const tagFunc = tmplt.tags[tTag]; 2372 if (stack.length && tTag === stack[stack.length - 1].close) { 2373 return stack.pop().end; // Closing tag, return it's end code 2374 } else if (!tagFunc) { // Undefined template tag 2375 throw new Error(`Unknown template tag "${tTag}": ${text}`); 2376 } // Normal opening tag 2377 const result = tagFunc(text.slice(tTag.length + 1), tmplt); 2378 if (result.end) { // Not self-closing, push to stack 2379 stack.push({ close: `end${ tTag }`, ...result }); 2380 } 2381 return result.start || result; 2382 }, 2383 '{#': (text, tmplt) => false, // falsy values are ignored 2384 '{{': (text, tmplt) => `OUT.push(G.escapeText(${tmplt.parseExpr(text)}));`, 2385 text: (text, tmplt) => text && `OUT.push(${JSON.stringify(text)});`, 2386}; 2387 2388// TODO: Tidy up: Move most or all definitions loose like modes 2389modulo.config.template.defaultFilters = (function () { 2390 const { get } = modulo.registry.utils; 2391 const safe = s => Object.assign(new String(s), { safe: true }); 2392 const escapeForRE = s=> s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); 2393 const trim = (s, arg) => { // General purpose string trimming function 2394 arg = arg ? escapeForRE(arg).replace(',', '|') : '|'; 2395 return s.replace(new RegExp(`^\\s*${ arg }\\s*$`, 'g'), ''); 2396 }; 2397 const tagswap = (s, arg) => { 2398 arg = typeof arg === 'string' ? arg.split(/\s+/) : Object.entries(arg); 2399 for (const row of arg) { // Loop through each replacement pair 2400 const [ tag, val ] = typeof row === 'string' ? row.split('=') : row; 2401 const swap = (a, prefix, suffix) => prefix + val + suffix; 2402 //s = s.replace(RegExp('(</?)' + tag + '(\s|>
2402)', 'gi'), swap); 2403 s = s.replace(RegExp('(</?)' + tag + '(\\s|>)', 'gi'), swap); 2404 } 2405 return safe(s); // Always mark as safe, since for HTML tags 2406 }; 2407 const filters = { 2408 add: (s, arg) => s + arg, 2409 allow: (s, arg) => arg.split(',').includes(s) ? s : '', 2410 camelcase: s => s.replace(/-([a-z])/g, g => g[1].toUpperCase()), 2411 capfirst: s => s.charAt(0).toUpperCase() + s.slice(1), 2412 combine: (s, arg) => s.concat ? s.concat(arg) : Object.assign({}, s, arg), 2413 default: (s, arg) => s || arg, 2414 divisibleby: (s, arg) => ((s * 1) % (arg * 1)) === 0, 2415 dividedinto: (s, arg) => Math.ceil((s * 1) / (arg * 1)), 2416 escapejs: s => JSON.stringify(String(s)).replace(/(^"|"$)/g, ''), 2417 first: s => Array.from(s)[0], 2418 join: (s, arg) => (s || []).join(arg === undefined ? ", " : arg), 2419 json: (s, arg) => JSON.stringify(s, null, arg || undefined), 2420 last: s => s[s.length - 1], 2421 length: s => s.length !== undefined ? s.length : Object.keys(s).length, 2422 lower: s => s.toLowerCase(), 2423 multiply: (s, arg) => (s * 1) * (arg * 1), 2424 number: (s) => Number(s), 2425 pluralize: (s, arg) => (arg.split(',')[(s === 1) * 1]) || '', 2426 skipfirst: (s, arg) => Array.from(s).slice(arg || 1), 2427 subtract: (s, arg) => s - arg, 2428 truncate: (s, arg) => ((s && s.length > arg*1) ? (s.substr(0, arg-1) + 'â¦') : s), 2429 type: s => s === null ? 'null' : (Array.isArray(s) ? 'array' : typeof s), 2430 renderas: (rCtx, template) => safe(template.render(rCtx)), 2431 reversed: s => Array.from(s).reverse(), 2432 upper: s => s.toUpperCase(), 2433 yesno: (s, arg) => `${ arg || 'yes,no' },,`.split(',')[s ? 0 : s === null ? 2 : 1], 2434 }; 2435 const { values, keys, entries } = Object; 2436 const extra = { trim, tagswap, get, safe, values, keys, entries }; 2437 return Object.assign(filters, extra); 2438})(); 2439 2440modulo.config.template.defaultTags = { 2441 'debugger': () => 'debugger;', 2442 'if': (text, tmplt) => { 2443 // Limit to 3 (L/O/R) 2444 const [ lHand, op, rHand ] = tmplt.parseCondExpr(text); 2445 const condStructure = !op ? 'X' : tmplt.opAliases[op] || `X ${op} Y`; 2446 const condition = condStructure.replace(/([XY])/g, 2447 (k, m) => tmplt.parseExpr(m === 'X' ? lHand : rHand)); 2448 const start = `if (${condition}) {`; 2449 return { start, end: '}' }; 2450 }, 2451 'else': () => '} else {', 2452 'elif': (s, tmplt) => '} else ' + tmplt.tags['if'](s, tmplt).start, 2453 'comment': () => ({ start: "/*", end: "*/"}), 2454 'include': (text) => `OUT.push(CTX.${ text.trim() }.render(CTX));`, 2455 'for': (text, tmplt) => { 2456 // Make variable name be based on nested-ness of tag stack 2457 const { cleanWord } = modulo.registry.utils; 2458 const arrName = 'ARR' + tmplt.stack.length; 2459 const [ varExp, arrExp ] = text.split(' in '); 2460 let start = `var ${arrName}=${tmplt.parseExpr(arrExp)};`; 2461 // TODO: Upgrade to for...of loop (after good testing) 2462 start += `for (var KEY in ${arrName}) {`; 2463 const [keyVar, valVar] = varExp.split(',').map(cleanWord); 2464 if (valVar) { 2465 start += `CTX.${keyVar}=KEY;`; 2466 } 2467 start += `CTX.${valVar ? valVar : varExp}=${arrName}[KEY];`; 2468 return { start, end: '}'}; 2469 }, 2470 'empty': (text, {stack}) => { 2471 // Make variable name be based on nested-ness of tag stack 2472 const varName = 'G.FORLOOP_NOT_EMPTY' + stack.length; 2473 const oldEndCode = stack.pop().end; // get rid of dangling for 2474 const start = `${varName}=true; ${oldEndCode} if (!${varName}) {`; 2475 const end = `}${varName} = false;`; 2476 return { start, end, close: 'endfor' }; 2477 }, 2478}; 2479 2480modulo.register('processor', function contentCSV (modulo, def, value) { 2481 const parse = s => s.trim().split('\n').map(line => line.trim().split(',')); 2482 def.Code = 'return ' + JSON.stringify(parse(def.Content || '')); 2483}); 2484 2485modulo.register('processor', function contentJS (modulo, def, value) { 2486 const tmpFunc = new Function('return (' + (def.Content || 'null') + ');'); 2487 def.Code = 'return ' + JSON.stringify(tmpFunc()) + ';'; // Evaluate 2488}); 2489 2490modulo.register('processor', function contentJSON (modulo, def, value) { 2491 def.Code = 'return ' + JSON.stringify(JSON.parse(def.Content || '{}')) + ';'; 2492}); 2493 2494modulo.register('processor', function contentTXT (modulo, def, value) { 2495 def.Code = 'return ' + JSON.stringify(def.Content); 2496}); 2497 2498modulo.register('processor', function dataType (modulo, def, value) { 2499 if (value === '?') { // '?' means determine based on extension 2500 const ext = def.Src && def.Src.match(/(?<=\.)[a-z]+$/i); 2501 value = ext ? ext[0] : 'json'; 2502 } 2503 def['Content' + value.toUpperCase()] = value; 2504}); 2505 2506modulo.register('processor', function filterContent (modulo, def, value) { 2507 if (def.Content && value) { // Check if active (needs truthy value) 2508 // value = value.trim().replace(/\s*\n\s*\|/gi, '|'); // Would allow multi-line 2509 const miniTemplate = `{{ def.Content|${ value }|safe }}`; 2510 const tmplt = new modulo.registry.cparts.Template(miniTemplate); 2511 def.Content = tmplt.render({ def, config: modulo.config }); 2512 } 2513}); 2514 2515modulo.register('processor', function code (modulo, def, value) { 2516 if (def.DefinitionName in modulo.assets.nameToHash) { 2517 console.error("ERROR: Duped def:", def.DefinitionName); 2518 return; 2519 } 2520 // TODO: Refactor this inline, change modulo.assets into plain object 2521 modulo.assets.define(def.DefinitionName, value); 2522}); 2523 2524modulo.register('processor', function codeTemplate (modulo, def, value) { 2525 if (def.DefinitionName in modulo.assets.nameToHash) { 2526 console.error("ERROR: Duped def:", def.DefinitionName); 2527 return; 2528 } 2529 const tmplt = new modulo.registry.cparts.Template(value); // Compile Template 2530 modulo.assets.define(def.DefinitionName, tmplt.render({ modulo, def })); 2531}); 2532 2533modulo.register('cpart', class StaticData { 2534 static RequireData (modulo, def, value) { 2535 def.data = modulo.assets.require(def[value]); // TODO: Remove asset 2536 } 2537 prepareCallback() { 2538 return this.conf.data; 2539 } 2540}, { 2541 DataType: '?', // Default behavior is to guess based on Src ext 2542 RequireData: 'DefinitionName', 2543 DefLoaders: [ 'DefTarget', 'DefinedAs', 'DataType', 'Src', 'FilterContent' ], 2544 DefBuilders: [ 'ContentCSV', 'ContentTXT', 'ContentJSON', 'ContentJS', 'Code', 'RequireData' ], 2545}); 2546 2547modulo.register('coreDef', class Configuration { }, { 2548 DefTarget: 'config', 2549 DefLoaders: [ 'DefTarget', 'DefinedAs', 'Src|SrcSync', 'Content|Code', 'DefinitionName|MainRequire' ], 2550}); 2551 2552modulo.config.script = { 2553 lifecycle: null, 2554 DefBuilders: [ 'Content|AutoExport', 'CodeTemplate' ], 2555 CodeTemplate: `var script = { exports: { } };{% if def.locals.length %}
2556 var {{ def.locals|join:',' }};{% endif %} 2557 {{ def.tempContent|safe }} 2558 ;return { exports: script.exports, 2559 {% for n in def.exportNames %} 2560 "{{ n }}": typeof {{ n }} !== "undefined" ? {{ n }} : undefined, 2561 {% endfor %} 2562 setLocalVariables: function (o) { 2563 {% for n in def.locals %}{{ n }} = o.{{ n }};{% endfor %} 2564 } 2565 }`.replace(/\s\s+/g, ' '), 2566}; 2567 2568modulo.register('cpart', class Script { 2569 static AutoExport (modulo, def, value) { 2570 const { getAutoExportNames } = modulo.registry.utils; 2571 if (def.lifecycle && def.lifecycle !== 'initialized') { 2572 value = `function ${ def.lifecycle }Callback (renderObj) {${ value }}`; 2573 } 2574 const { ChildrenNames } = modulo.definitions[def.Parent] || { }; 2575 const sibs = (ChildrenNames || []).map(n => modulo.definitions[n].Name); 2576 sibs.push('component', 'element', 'cparts'); // Add in extras 2577 def.exportNames = def.exportNames || getAutoExportNames(value); // Scan names 2578 def.locals = def.locals || sibs.filter(name => value.includes(name)); 2579 def.Directives = def.exportNames.filter(s => s.match(/(Unmount|Mount)$/)); 2580 def.tempContent = value; // TODO: Refactor AutoExport + CodeTemplate 2581 } 2582 2583 static factoryCallback(renderObj, def, modulo) { 2584 //modulo.assert(results || !def.Parent, 'Invalid script return'); 2585 const hash = modulo.assets.nameToHash[def.DefinitionName]; 2586 const func = () => modulo.assets.modules[hash].call(window, modulo); 2587 if (def.lifecycle === 'initialized') { 2588 return { initializedCallback: func }; // Attach as callback 2589 } 2590 return func(); // Otherwise, should run in static context (e.g. now) 2591 } 2592 2593 initializedCallback(renderObj) { 2594 // Create all lifecycle callbacks, wrapping around the inner script 2595 const script = renderObj[this.conf.Name]; 2596 this.eventCallback = (rObj) => { // Create eventCallback to set inner 2597 const vars = { element: this.element, cparts: this.element.cparts }; 2598 const setLocal = script.setLocalVariables || (() => {}); 2599 setLocal(Object.assign(vars, rObj)); // Set inner vars (or no-op) 2600 }; 2601 2602 if (script.initializedCallback) { // If defined, trigger inner init 2603 this.eventCallback(renderObj); // Prep before (used by lc=false) 2604 Object.assign(script, script.initializedCallback(renderObj)); 2605 this.eventCallback(renderObj); // Prep again (used by lc=initialize) 2606 } 2607 2608 const isCallback = /(Mount|Unmount|Callback)$/; 2609 for (const cbName of Object.keys(script)) { 2610 if (cbName === 'initializedCallback' || !cbName.match(isCallback)) { 2611 continue; // Skip over initialized (already handled) and non-CBs 2612 } 2613 this[cbName] = arg => { // Arg: Either renderObj or directive obj 2614 const renderObj = this.element.getCurrentRenderObj(); 2615 const script = renderObj[this.conf.Name]; // Get new render obj 2616 this.eventCallback(renderObj); // Prep before lifecycle method 2617 Object.assign(script, script[cbName](arg) || {}); 2618 }; 2619 } 2620 } 2621}); 2622 2623 2624modulo.register('cpart', class State { 2625 static factoryCallback(renderObj, def, modulo) { 2626 if (def.Store) { 2627 const store = modulo.registry.utils.makeStore(modulo, def); 2628 if (!(def.Store in modulo.stores)) { 2629 modulo.stores[def.Store] = store; 2630 } else { 2631 Object.assign(modulo.stores[def.Store].data, store.data); 2632 } 2633 } 2634 } 2635 2636 initializedCallback() { 2637 const store = this.conf.Store ? this.modulo.stores[this.conf.Store] 2638 : this.modulo.registry.utils.makeStore(this.modulo, this.conf); 2639 store.subscribers.push(Object.assign(this, store)); 2640 this.types = { range: Number, number: Number, checkbox: (val, el) => el.checked }; 2641 return store.data; // TODO: Possibly, push ALL sibling CParts with stateChangedCallback 2642 } 2643 2644 bindMount({ el, attrName, value }) { 2645 const name = attrName || el.getAttribute('name'); 2646 const val = this.modulo.registry.utils.get(this.data, name); 2647 this.modulo.assert(val !== undefined, `state.bind "${name}" undefined`); 2648 const isText = el.tagName === 'TEXTAREA' || el.type === 'text'; 2649 const evName = value ? value : (isText ? 'keyup' : 'change'); 2650 if (!(name in this.boundElements)) { 2651 this.boundElements[name] = []; 2652 } 2653 // Bind the "listen" event to propagate to all, and trigger initial vals 2654 const listen = () =>
2654 this.propagate(name, el.value, el); 2655 this.boundElements[name].push([ el, evName, listen ]); 2656 el.addEventListener(evName, listen); // todo: make optional, e.g. to support cparts? 2657 this.propagate(name, val, this); // trigger initial assignment(s) 2658 } 2659 2660 bindUnmount({ el, attrName }) { 2661 const name = attrName || el.getAttribute('name'); 2662 if (!(name in this.boundElements)) { // TODO HACK 2663 return console.log('Modulo ERROR: Could not unbind', name); 2664 } 2665 const remainingBound = []; 2666 for (const row of this.boundElements[name]) { 2667 if (row[0] === el) { 2668 row[0].removeEventListener(row[1], row[2]); 2669 } else { 2670 remainingBound.push(row); 2671 } 2672 } 2673 this.boundElements[name] = remainingBound; 2674 } 2675 2676 stateChangedCallback(name, value, el) { 2677 this.modulo.registry.utils.set(this.data, name, value); 2678 if (!this.conf.Only || this.conf.Only.includes(name)) { // TODO: Test 2679 this.element.rerender(); 2680 } 2681 } 2682 2683 eventCallback() { 2684 this._oldData = Object.assign({}, this.data); 2685 } 2686 2687 propagate(name, val, originalEl = null) { 2688 const elems = (this.boundElements[name] || []).map(row => row[0]); 2689 const typeConv = this.types[ originalEl ? originalEl.type : null ]; 2690 val = typeConv ? typeConv(val, originalEl) : val; // Apply conversion 2691 for (const el of this.subscribers.concat(elems)) { 2692 if (originalEl && el === originalEl) { 2693 continue; // don't propagate to originalEl (avoid infinite loop) 2694 } 2695 if (el.stateChangedCallback) { // A callback was found, use instead 2696 el.stateChangedCallback(name, val, originalEl); 2697 } else if (el.type === 'checkbox') { // Check input use ".checkbox" 2698 el.checked = !!val; 2699 } else { // Normal inputs use ".value" 2700 el.value = val; 2701 } 2702 } 2703 } 2704 2705 eventCleanupCallback() { 2706 for (const name of Object.keys(this.data)) { 2707 this.modulo.assert(!this.conf.AllowNew && name in this._oldData, 2708 `State variable "${ name }" is undeclared (no "-allow-new")`); 2709 if (this.data[name] !== this._oldData[name]) { 2710 this.propagate(name, this.data[name], this); 2711 } 2712 } 2713 this._oldData = null; 2714 } 2715}, { 2716 Directives: [ 'bindMount', 'bindUnmount' ], 2717 Store: null, 2718}); 2719 2720modulo.register('utils', class DOMCursor { 2721 constructor(parentNode, parentRival, slots) { 2722 this.slots = slots || {}; // Slottables keyed by name (default is '') 2723 this.instanceStack = []; // Used for implementing DFS non-recursively 2724 this._rivalQuerySelector = parentRival.querySelector.bind(parentRival); 2725 this._querySelector = parentNode.querySelector.bind(parentNode); 2726 this.initialize(parentNode, parentRival); 2727 } 2728 2729 initialize(parentNode, parentRival) { 2730 this.parentNode = parentNode; 2731 this.nextChild = parentNode.firstChild; 2732 this.nextRival = parentRival.firstChild; 2733 this.keyedChildren = {}; 2734 this.keyedRivals = {}; 2735 this.activeExcess = null; 2736 this.activeSlot = null; 2737 if (parentRival.tagName === 'SLOT') { // Parent will "consume" a slot 2738 const slotName = parentRival.getAttribute('name') || ''; 2739 this.activeSlot = this.slots[slotName] || null; // Mark active 2740 if (this.activeSlot) { // Children were specified for this slot! 2741 delete this.slots[slotName]; // (prevent "dupe slot" bug) 2742 this._setNextRival(null); // Move the cursor to the first elem 2743 } 2744 } 2745 } 2746
2747 saveToStack() { // Creates an object copied with all cursor state 2748 this.instanceStack.push(Object.assign({ }, this)); // Copy to empty obj 2749 } 2750 2751 loadFromStack() { // Remaining stack to "walk back" (non-recursive DFS) 2752 const stack = this.instanceStack; 2753 return stack.length > 0 && Object.assign(this, stack.pop()); 2754 } 2755 2756 loadFromExcessKeys() { // There were "excess", unmatched keyed elements 2757 if (!this.activeExcess) { // Convert needed appends and removes to array 2758 const child = Object.values(this.keyedChildren).map(v => [v, null]); 2759 const rival = Object.values(this.keyedRivals).map(v => [null, v]); 2760 this.activeExcess = rival.concat(child); // Do appends before remove 2761 } 2762 return this.activeExcess.length > 0; // Return true if there is any left 2763 } 2764 2765 loadFromSlots() { // There are "excess" slots (copied, but deeply nested) 2766 const name = Object.keys(this.slots).pop(); // Get next ("pop" from obj) 2767 if (name === '' || name) { // Is name valid? (String of 0 or more) 2768 const sel = name ? `slot[name="${ name }"]` : 'slot:not([name])'; 2769 const rivalSlot = this._rivalQuerySelector(sel); 2770 if (!rivalSlot) { // No slot (e.g., conditionally rendered, or typo) 2771 delete this.slots[name]; // (Ensure "consumed", if not init'ed) 2772 return this.loadFromSlots(); // If no elem, try popping again 2773 } 2774 this.initialize(this._querySelector(sel) || rivalSlot, rivalSlot); 2775 return true; // Indicate success: Child and rival slots are ready 2776 } 2777 } 2778 2779 hasNext() { 2780 if (this.nextChild || this.nextRival || this.loadFromExcessKeys()) { 2781 return true; // Is pointing at another node, or has unmatched keys 2782 } else if (this.loadFromStack() || this.loadFromSlots()) { // Walk back 2783 return this.hasNext(); // Possibly loaded nodes nextChild, nextRival 2784 } 2785 return false; // Every load attempt is "false" (empty), end iteration 2786 } 2787 2788 _setNextRival(rival) { // Traverse this.nextRival based on DOM or SLOT 2789 if (this.activeSlot !== null) { // Use activeSlot array for next instead 2790 if (this.activeSlot.length > 0) { 2791 this.nextRival = this.activeSlot.shift(); // Pop off next one 2792 this.nextRival._moduloIgnoreOnce = true; // Ensure no descend 2793 } else { 2794 this.nextRival = null; 2795 } 2796 } else { 2797 this.nextRival = rival ? rival.nextSibling : null; // Normal DOM traversal 2798 } 2799 } 2800 2801 next() { 2802 let child = this.nextChild; 2803 let rival = this.nextRival; 2804 //if (!rival && !child && this.hasNext()) { return this.next(); } // TODO ALlow for calling w/o hasNext 2805 if (!rival && this.activeExcess && this.activeExcess.length > 0) { 2806 return this.activeExcess.shift(); // Return the first pair 2807 } 2808 this.nextChild = child ? child.nextSibling : null; 2809 this._setNextRival(rival); // Traverse initially 2810 if (!this._disableKeys) { // Disable all "keyed element" logic 2811 let matchedRival = this.getMatchedNode(child, this.keyedChildren, this.keyedRivals); 2812 let matchedChild = this.getMatchedNode(rival, this.keyedRivals, this.keyedChildren); 2813 if (matchedRival === false) { // Child has a key, but does not match 2814 child = this.nextChild; // Simply ignore Child, and on to next 2815 this.nextChild = child ? child.nextSibling : null; // (1687) 2816 } else if (matchedChild === false) { // Rival has key, but no match 2817 rival = this.nextRival; // IGNORE rival - move on to 2818 this._setNextRival(rival); // (and setup next-next rival) 2819 } 2820 const keyWasFound = matchedRival !== null || matchedChild !== null; 2821 const matchFound = matchedChild !== child && keyWasFound; 2822 if (matchFound && matchedChild) { // Rival matches, but not child 2823 this.nextChild = child; // "Undo" this last "nextChild" (return) 2824 child = matchedChild; // Then substitute the matched instead 2825 } 2826 if (matchFound && matchedRival) { 2827 // Child matches, but not with rival. Swap in the correct one. 2828 this.modulo.assert(matchedRival !== rival, 'Dupe!'); 2829 this.nextRival = rival; // "Undo" this last "nextRival" 2830 rival = matchedRival; // Then substitute the matched rival 2831 } 2832 } 2833 return [ child, rival ]; 2834 } 2835 2836 getMatchedNode(elem, keyedElems, keyedOthers) {
2837 const key = elem && elem.nodeType === 1 && elem.getAttribute('key'); 2838 if (!key) { 2839 return null; 2840 } else if (key in keyedOthers) { 2841 const matched = keyedOthers[key]; 2842 delete keyedOthers[key]; 2843 return matched; 2844 } else if (key in keyedElems) { 2845 console.warn('MODULO: Duplicate key:', key); 2846 } 2847 keyedElems[key] = elem; 2848 return false; 2849 } 2850}); 2851 2852modulo.config.reconciler = { 2853 directiveShortcuts: [ [ /^@/, 'component.event' ], 2854 [ /:$/, 'component.dataProp' ] ], 2855}; 2856modulo.register('core', class Reconciler { 2857 constructor(modulo, def = {}) { 2858 this.modulo = modulo; 2859 this.directives = def.directives || {}; 2860 this.directiveShortcuts = def.directiveShortcuts || []; 2861 if (this.directiveShortcuts.length === 0) { // TODO Remove this when tested 2862 this.directiveShortcuts = this.modulo.config.reconciler.directiveShortcuts; 2863 } 2864 this.patch = this.pushPatch; 2865 this.patches = []; 2866 } 2867 2868 parseDirectives(rawName, directiveShortcuts) { //, foundDirectives) { 2869 if (/^[a-z0-9-]+$/i.test(rawName)) { 2870 return null; // if alphanumeric-only, stop right away 2871 } 2872 let name = rawName; 2873 for (const [ regexp, directive ] of directiveShortcuts) { 2874 if (rawName.match(regexp)) { // "Expand" shortcut into full version 2875 name = `[${directive}]` + name.replace(regexp, ''); 2876 } 2877 } 2878 if (!name.startsWith('[')) { 2879 return null; // There are no directives, regular attribute, skip 2880 } 2881 // There are directives... time to resolve them 2882 const { cleanWord, stripWord } = this.modulo.registry.utils; 2883 const arr = []; 2884 const attrName = stripWord((name.match(/\][^\]]+$/) || [ '' ])[0]); 2885 for (const directiveName of name.split(']').map(cleanWord)) { 2886 // Skip the bare name itself, and filter for valid directives 2887 if (directiveName !== attrName) {// && directiveName in directives) { 2888 arr.push({ attrName, rawName, directiveName, name }) 2889 } 2890 } 2891 return arr; 2892 } 2893 2894 applyPatches(patches) { 2895 for (const patch of patches) { // Simply loop through given iterable 2896 this.applyPatch(patch[0], patch[1], patch[2], patch[3]); 2897 } 2898 } 2899 2900 reconcileChildren(childParent, rivalParent, slots) { 2901 // Nonstandard nomenclature: "rival" is node we wish "child" to match 2902 const cursor = new this.modulo.registry.utils.DOMCursor(childParent, rivalParent, slots); 2903 while (cursor.hasNext()) { 2904 const [ child, rival ] = cursor.next(); 2905 const needReplace = child && rival && ( 2906 child.nodeType !== rival.nodeType || 2907 child.nodeName !== rival.nodeName 2908 ); // Does this node to be swapped out? Swap if exist but mismatched 2909 2910 if ((child && !rival) || needReplace) { // we have more rival, delete child 2911 this.patchAndDescendants(child, 'Unmount'); 2912 this.patch(cursor.parentNode, 'removeChild', child); 2913 } 2914 2915 if (needReplace) { // do swap with insertBefore 2916 this.patch(cursor.parentNode, 'insertBefore', rival, child.nextSibling); 2917 this.patchAndDescendants(rival, 'Mount'); 2918 } 2919 2920 if (!child && rival) { // we have less than rival, take rival 2921 // TODO: Possibly add directive resolution context to rival / child.originalChildren? 2922 this.patch(cursor.parentNode, 'appendChild', rival); 2923 this.patchAndDescendants(rival, 'Mount'); 2924 } 2925 2926 if (child && rival && !needReplace) { 2927 // Both exist and are of same type, let's reconcile nodes 2928 if (child.nodeType !== 1) { // text or comment node 2929 if (child.nodeValue !== rival.nodeValue) { // update 2930 this.patch(child, 'node-value', rival.nodeValue); 2931 } 2932 } else if (!child.isEqualNode(rival)) { // sync if not equal 2933 this.reconcileAttributes(child, rival); 2934 if (rival.hasAttribute('modulo-ignore')) { // Don't descend 2935 // console.log('Skipping ignored node'); 2936 } else if (child.isModulo) { // is a Modulo component 2937 this.patch(child, 'rerender', rival); 2938 } else { //} else if (!this.shouldNotDescend) { 2939 cursor.saveToStack(); 2940 cursor.initialize(child, rival); 2941 } 2942 } 2943 } 2944 } 2945 } 2946 2947 pushPatch(node, method, arg, arg2 = null) { 2948 this.patches.push([ node, method, arg, arg2 ]); 2949 } 2950 2951 applyPatch(node, method, arg, arg2) { // take that, rule of 3! 2952 if (method === 'node-value') { 2953 node.nodeValue = arg; 2954 } else if (method === 'insertBefore') { 2955 node.insertBefore(arg, arg2); // Needs 2 arguments 2956 } else if (method.startsWith('directive-')) { 2957 method = method.substr(10);//'directive-'.length); // TODO: RM prefix (or generalizze) 2958 node[method].call(node, arg); // invoke directive method 2959 } else { 2960 node[method].call(node, arg); // invoke method 2961 } 2962 } 2963 2964 patchDirectives(el, rawName, suffix, copyFromEl = null) { 2965 const foundDirectives = this.parseDirectives(rawName, this.directiveShortcuts); 2966 if (!foundDirectives || foundDirectives.length === 0) { 2967 return; // Fast route: "undefined" means no directives 2968 } 2969 const value = (copyFromEl || el).getAttribute(rawName); // Get value 2970 for (const directive of foundDirectives) { 2971 const dName = directive.directiveName; // e.g. "state.bind", "link" 2972 const fullName = dName + suffix; // e.g. "state.bindMount" 2973 const thisObj = this.directives[dName] || this.directives[fullName]; 2974 if (thisObj) { // If a directive matches... 2975 const methodName = fullName.split('.')[1] || fullName; 2976 Object.assign(directive, { value, el }); 2977 this.patch(thisObj, 'directive-' + methodName, directive); 2978 } 2979 } 2980 } 2981 2982 reconcileAttributes(node, rival) { 2983 const myAttrs = new Set(node ? node.getAttributeNames() : []); 2984 const rivalAttributes = new Set(rival.getAttributeNames()); 2985 2986 // Check for new and changed attributes 2987 for (const rawName of rivalAttributes) { 2988 const attr = rival.getAttributeNode(rawName); 2989 if (myAttrs.has(rawName) && node.getAttribute(rawName) === attr.value) { 2990 continue; // Already matches, on to next 2991 } 2992 if (myAttrs.has(rawName)) { // If exists, trigger Unmount first 2993 this.patchDirectives(node, rawName, 'Unmount'); 2994 } 2995 // Set attribute node, and then Mount based on rival value 2996 this.patch(node, 'setAttributeNode', attr.cloneNode(true)); 2997 this.patchDirectives(node, rawName, 'Mount', rival); 2998 } 2999 3000 // Check for old attributes that were removed (ignoring modulo- prefixed ones) 3001 for (const rawName of myAttrs) { 3002 if (!rivalAttributes.has(rawName) && !rawName.startsWith('modulo-')) { 3003 this.patchDirectives(node, rawName, 'Unmount'); 3004 this.patch(node, 'removeAttribute', rawName); 3005 } 3006 } 3007 } 3008 3009 patchAndDescendants(parentNode, actionSuffix) { 3010 if (parentNode.nodeType !== 1) { 3011 return; // Skip anything that isn't a regular HTML element 3012 } 3013 if (parentNode._moduloIgnoreOnce) { 3014 delete parentNode._moduloIgnoreOnce; // Ensure ignore is deleted 3015 return; // Skip ignored elements 3016 } 3017 const searchNodes = Array.from(parentNode.querySelectorAll('*')); 3018 for (const node of [ parentNode ].concat(searchNodes)) { 3019 for (const rawName of node.getAttributeNames()) { // Do patches 3020 this.patchDirectives(node, rawName, actionSuffix); 3021 } 3022 } 3023 } 3024}); 3025
3026modulo.register('util', function getAutoExportNames(contents) { 3027 // TODO: Change exports/Directives/etc to def processor to better expose 3028 const regexpG = /(function|class)\s+(\w+)/g; 3029 const regexp2 = /(function|class)\s+(\w+)/; // hack, refactor 3030 return (contents.match(regexpG) || []).map(s => s.match(regexp2)[2]) 3031 .filter(s => s && !Modulo.INVALID_WORDS.has(s)); 3032}); 3033 3034modulo.register('util', function showDevMenu() { 3035 const cmd = new URLSearchParams(window.location.search).get('mod-cmd'); 3036 const rerun = `<h1><a href="?mod-cmd=${ cmd }">⟳ ${ cmd }</a></h1>`; 3037 if (cmd) { // Command specified, skip dev menu, run, and replace HTML after 3038 const callback = () => { window.document.body.innerHTML = rerun; }; 3039 const start = () => modulo.registry.commands[cmd](modulo, { callback }); 3040 return window.setTimeout(start, modulo.config.commandDelay || 1000); 3041 } // Else: Display "COMMANDS:" menu in console 3042 const href = 'window.location.href += '; 3043 const font = 'font-size: 28px; padding: 0 8px 0 8px; border: 2px solid black;'; 3044 const commandGetters = Object.keys(modulo.registry.commands).map(cmd => 3045 ('get ' + cmd + ' () {' + href + '"?mod-cmd=' + cmd + '";}')); 3046 const clsCode = 'class COMMANDS {' + commandGetters.join('\n') + '}'; 3047 new Function(`console.log('%c%', '${ font }', new (${ clsCode }))`)(); 3048}); 3049 3050modulo.register('command', function build (modulo, opts = {}) { 3051 modulo.preprocessAndDefine(opts.callback, 'BuildCommand'); 3052}); 3053 3054if (typeof window.moduloBuild === 'undefined') { // Not in a build, try loading 3055 if (typeof window.document !== 'undefined') { // Document exists 3056 modulo.loadString(modulo._DEVLIB_SOURCE, '_artifact'); // Load dev lib 3057 modulo.loadFromDOM(window.document.head, null, true); // Blocking load 3058 window.document.addEventListener('DOMContentLoaded', () => { 3059 modulo.loadFromDOM(window.document.body, null, true); // Async load 3060 modulo.preprocessAndDefine(modulo.registry.utils.showDevMenu); 3061 }); 3062 } else if (typeof module !== 'undefined') { // Node.js 3063 module.exports = { modulo, window }; 3064 } 3065} 3066 3067modulo.assets.modules = window.moduloBuild.modules; 3068modulo.assets.nameToHash = window.moduloBuild.nameToHash; 3069modulo.definitions = window.moduloBuild.definitions; 3070 3071 3072modulo.assets.require("configuration"); 3073 3074modulo.assets.require("configuration1"); 3075 3076modulo.assets.require("library_configuration"); 3077 3078modulo.assets.require("library1_configuration"); 3079 3080modulo.assets.require("library_Page"); 3081 3082modulo.assets.require("library_FeaturedTestimonials"); 3083 3084modulo.assets.require("library_Testimonials"); 3085 3086modulo.assets.require("library_FeaturedArticles"); 3087 3088modulo.assets.require("library1_StudentIDGenerator"); 3089 3090modulo.assets.require("library1_HiddenSuccessCard"); 3091 3092modulo.assets.require("library1_PlanMenu"); 3093 3094modulo.assets.require("library1_Courses"); 3095
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.