tag:blogger.com,1999:blog-20644619986201587552024-03-17T20:03:20.926-07:00Brian's Programming and Software Architecture BlogAdventures in Brogramming
Born, Raised and Grinding Proudly in Toronto, Ontario, CanadaBrianLimhttp://www.blogger.com/profile/07107383864607795783noreply@blogger.comBlogger42125tag:blogger.com,1999:blog-2064461998620158755.post-77507225078044819462024-02-09T20:48:00.000-08:002024-02-09T20:48:06.464-08:00Advanced React Hacks 4/10 - Prevent Rerenders<h1 style="text-align: left;">Advanced React Hacks 4/10 - Prevent Rerenders</h1><div><br /></div>Very obvious when you see the answer (and actually documented on react.dev, link later) but still worth mentioning for posterity.<div><br /></div><div>You don't want to render too much, because one point of React is that it minimises the amount of rerenders on a screen (or is supposed to)</div><div><br /></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEhGHM9LSdFARRg-3aj5j1oeG3iY8JiLk0KiwBlEpNJ61uPffeMCNr42PJRSJVYOmza1Vl23NAj4KpGsV6JGHwpWuErYcgc3PnRb40Jo_BHhcZVSB4JmzeWDMu4ocULWFESHUan6iXDB4tmsGX0JgE3BM0wZQfr4xTZCWjnpSzOZ1RCykMXCiVyXAswRQKac" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="499" data-original-width="888" height="180" src="https://blogger.googleusercontent.com/img/a/AVvXsEhGHM9LSdFARRg-3aj5j1oeG3iY8JiLk0KiwBlEpNJ61uPffeMCNr42PJRSJVYOmza1Vl23NAj4KpGsV6JGHwpWuErYcgc3PnRb40Jo_BHhcZVSB4JmzeWDMu4ocULWFESHUan6iXDB4tmsGX0JgE3BM0wZQfr4xTZCWjnpSzOZ1RCykMXCiVyXAswRQKac" width="320" /></a></div><br />How do most working React developers see this? With the "highlight updates" tool of course</div><div><br /></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgBdIuXHxQT8-cESVoB0GjghNMnVdxpJQxftY8j5r_yWdHbYBxVUM1782Zl18vP-NhQYa-7OXhExSog7-xHc1ZdpKa0DA6RFm6MsAupl9AnHG6meocn0-LAYU7E6vGRjBRa1wzki_iny6rJmFQJ2uZmReeDLbCWwon2i6xk-5tlfC97PdUmYFM2TIhmyOhE" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="169" data-original-width="709" height="109" src="https://blogger.googleusercontent.com/img/a/AVvXsEgBdIuXHxQT8-cESVoB0GjghNMnVdxpJQxftY8j5r_yWdHbYBxVUM1782Zl18vP-NhQYa-7OXhExSog7-xHc1ZdpKa0DA6RFm6MsAupl9AnHG6meocn0-LAYU7E6vGRjBRa1wzki_iny6rJmFQJ2uZmReeDLbCWwon2i6xk-5tlfC97PdUmYFM2TIhmyOhE=w458-h109" width="458" /></a></div><br />But, it is worth mentioning (in case it happens again, and for a lesson) that in 2019 with React Developer Tools v4, this killer feature was <i><a href="https://github.com/facebook/react/issues/16437#issuecomment-522545667">removed</a></i></div><div><i><br /></i></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEh6Vpiqb_ENM7LDVraMOg1x0QyQvzPmqjau1dzzqsUbkxRJggG1wwrSNHf0yWaeYwXAW3Aj8G4vzaYKmdmrhcidYIcBPoJTlJUUDARa5mb33G5_ByC3PyWdZNGiim-2WgYk-eNqO2Yf4ifCfPomVvPSsFvYMqSWY_eqoWYs4Zm6QupBEPH1MkA34kvEA6F5" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="284" data-original-width="1080" height="180" src="https://blogger.googleusercontent.com/img/a/AVvXsEh6Vpiqb_ENM7LDVraMOg1x0QyQvzPmqjau1dzzqsUbkxRJggG1wwrSNHf0yWaeYwXAW3Aj8G4vzaYKmdmrhcidYIcBPoJTlJUUDARa5mb33G5_ByC3PyWdZNGiim-2WgYk-eNqO2Yf4ifCfPomVvPSsFvYMqSWY_eqoWYs4Zm6QupBEPH1MkA34kvEA6F5=w686-h180" width="686" /></a></div><div><br /></div>To the React Team's credit, they restored "Highlight Updates" quickly</div><div><br /></div><div>Anyway how do you prevent re-rendering? It's actually <a href="https://react.dev/reference/react-dom/components/input#optimizing-re-rendering-on-every-keystroke">easy</a></div><div><br /></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEiDaW5FAFq_QNnpS6wTFG42rFKLlE1eqN6rwOobhhSpmG6XBnOrzXaM7jw7DF4NH7ljsDScrPLvYWdchGrmd5ozx9EgioOiAh8HiWh3CaC6LzrdU2NtzDfVHrp-JOoopZwNbnNyWNuRXqr364b1OgN2QWlDhWTXOFUxBe351fr7XNMpTT0h6HR6mQIm2Fno" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="590" data-original-width="931" height="351" src="https://blogger.googleusercontent.com/img/a/AVvXsEiDaW5FAFq_QNnpS6wTFG42rFKLlE1eqN6rwOobhhSpmG6XBnOrzXaM7jw7DF4NH7ljsDScrPLvYWdchGrmd5ozx9EgioOiAh8HiWh3CaC6LzrdU2NtzDfVHrp-JOoopZwNbnNyWNuRXqr364b1OgN2QWlDhWTXOFUxBe351fr7XNMpTT0h6HR6mQIm2Fno=w552-h351" width="552" /></a></div></div><div><blockquote><i>Once the component has been initially rendered, you can trigger further renders by updating its state with the set function. Updating your component’s state automatically queues a render. (You can imagine these as a restaurant guest ordering tea, dessert, and all sorts of things after putting in their first order, depending on the state of their thirst or hunger.) <a href="https://react.dev/learn/managing-state#sharing-state-between-components">React.Dev "Managing State</a></i><a href="https://react.dev/learn/managing-state#sharing-state-between-components">"</a></blockquote><p>If you see too much of your screen rendering making it slow when taking actions (like clicking) <i>break it down</i></p><p></p><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEj2pMWppM2whKQIvLNDaQhy3XTvMGPV7A0tmw25miqfXwnmsc8qPWgAdMNhIvI_HUKoJROJFShj_29C2SuatKYk6AbMxkl4TmsNNHSslzlE3xpOOfgKM0UDHKZgE3HPJ2pLKehRWVeaDQCSYXI1d2TxFlrVc-6pdc6FqSay7sspOuWp4TEnt_Gi1WIUjAdK" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="412" data-original-width="620" height="213" src="https://blogger.googleusercontent.com/img/a/AVvXsEj2pMWppM2whKQIvLNDaQhy3XTvMGPV7A0tmw25miqfXwnmsc8qPWgAdMNhIvI_HUKoJROJFShj_29C2SuatKYk6AbMxkl4TmsNNHSslzlE3xpOOfgKM0UDHKZgE3HPJ2pLKehRWVeaDQCSYXI1d2TxFlrVc-6pdc6FqSay7sspOuWp4TEnt_Gi1WIUjAdK" width="320" /></a></div><br /><br /></div>Make more components... obvious, but worth mentioning the obvious<p></p><p>Until next time...</p></div><div><i><br /></i></div>BrianLimhttp://www.blogger.com/profile/07107383864607795783noreply@blogger.com0tag:blogger.com,1999:blog-2064461998620158755.post-52171836417556871112024-02-03T01:50:00.000-08:002024-02-03T06:48:52.549-08:00Advanced React Hacks 3/10 - Dynamic GraphQL<h1 style="text-align: left;">Advanced React Hacks 3/10 - Dynamic GraphQL</h1><p>Eventually you will reach a point in your career where you need or want to make dynamic GraphQL queries</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgz78MkRfU96bctnSU5aflmVoa87pTSLMz40u4axBCUlbi70jJjuSLBt1gylN6h05JjbPCerC45lgiJ7YnTmLgJmLlpuEjsuzq4WY4PCbxYr_z60zz86KpLqa3NHVEhAxE1PFsNNeABk302lbqSF8GOrM4oX2MV0j0ELxdjrxoTByVKhKb19b5Py_FU-r48" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="450" data-original-width="604" height="238" src="https://blogger.googleusercontent.com/img/a/AVvXsEgz78MkRfU96bctnSU5aflmVoa87pTSLMz40u4axBCUlbi70jJjuSLBt1gylN6h05JjbPCerC45lgiJ7YnTmLgJmLlpuEjsuzq4WY4PCbxYr_z60zz86KpLqa3NHVEhAxE1PFsNNeABk302lbqSF8GOrM4oX2MV0j0ELxdjrxoTByVKhKb19b5Py_FU-r48" width="320" /></a></div><br />At first it will seem "advanced" especially when looking at Google or Stack Overflow answers<p></p><p>You probably are used to static queries strongly typed from a schema.graphql with autocomplete in VSCode</p><p>How the hell can that change or be data driven?</p><p></p><div class="separator" style="clear: both; text-align: center;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEhU0QWKNehHLVsqtQrIiODi9Mz7ZutuuP4oXpMGxZQZtEDMQyo7soEEVfC8HDVZ7KnCqZ2GimEH7UgXTgy7MmdIxGOfvTaDS3CyAnbr6tZGKaGf6rm3eZBM15-KBoFVqmZqBiXACTstGE09IPqqa4Zns8ow4fbJRR6J-6r8Nay7tS9TzjcCUpRO9xvTI2sg" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="398" data-original-width="628" height="203" src="https://blogger.googleusercontent.com/img/a/AVvXsEhU0QWKNehHLVsqtQrIiODi9Mz7ZutuuP4oXpMGxZQZtEDMQyo7soEEVfC8HDVZ7KnCqZ2GimEH7UgXTgy7MmdIxGOfvTaDS3CyAnbr6tZGKaGf6rm3eZBM15-KBoFVqmZqBiXACTstGE09IPqqa4Zns8ow4fbJRR6J-6r8Nay7tS9TzjcCUpRO9xvTI2sg" width="320" /></a></div><br /><br /></div>Well the answer is in the <a href="https://spec.graphql.org/October2021/#sec-Execution">specification</a><p></p><p data-source="spec/Section%206%20--%20Execution.md#L58-L63" style="color: #333333; font-family: Cambria, "Palatino Linotype", Palatino, "Liberation Serif", serif; font-size: 17px;"></p><blockquote><p data-source="spec/Section%206%20--%20Execution.md#L58-L63" style="color: #333333; font-family: Cambria, "Palatino Linotype", Palatino, "Liberation Serif", serif; font-size: 17px;">Typically validation is performed in the context of a request immediately before execution, however a GraphQL service may execute a request without immediately validating it if that exact same request is known to have been validated before. A GraphQL service should only execute requests which <em>at some point</em> were known to be free of any validation errors, and have since not changed.</p><p data-source="spec/Section%206%20--%20Execution.md#L65-L67" style="color: #333333; font-family: Cambria, "Palatino Linotype", Palatino, "Liberation Serif", serif; font-size: 17px;">For example: the request may be validated during development, provided it does not later change, or a service may validate a request once and memoize the result to avoid validating the same request again in the future.</p></blockquote><p>Request may be validated during development => request may be validated during runtime => request may change!</p><p>For example with <a href="https://www.npmjs.com/package/graphql-tag">graphql-tag</a></p><p></p><blockquote><p>GraphQL strings are the <b>right way to write queries in your code</b>, because they can be statically analyzed using tools like eslint-plugin-graphql. However, strings are inconvenient to manipulate, if you are trying to do things like add extra fields, merge multiple queries together, or other interesting stuff.</p><p>That's where this package comes in - it lets you write your queries with <b>ES2015 template literals</b> and compile them into an AST with the gql tag.</p></blockquote><p>With string interpolation, "dynamic GraphQL" is actually trivial! Just build the string! (And this is JavaScript not Java so you don't need a StringBuilder!)</p><p>So,</p><p>a) RTFM (in this case the specification!)</p><p>b) Never trust the "right way"</p><p>c) Look for an existing solution</p><p>d) Probably more things I haven't thought of...</p><p>Back to basics!</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEinCpQZZ8dLEK3_zYPFFApgtv_VG2XO-jLztH7QZaKuJ9gT4uC3zjbBJX7FqXs4X8nMYptTkGJTITZRFcE2kcIiw3jTmHn_0qQ0c6pGUZL0VRH9A3nuVqr3uqDBe_QIw-ax7JWfprOXZgzBegI6L6gXXomAY_XRPNlkdmtC3BYB0WCcAUWJt07uMYg3ifcE" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="500" data-original-width="500" height="240" src="https://blogger.googleusercontent.com/img/a/AVvXsEinCpQZZ8dLEK3_zYPFFApgtv_VG2XO-jLztH7QZaKuJ9gT4uC3zjbBJX7FqXs4X8nMYptTkGJTITZRFcE2kcIiw3jTmHn_0qQ0c6pGUZL0VRH9A3nuVqr3uqDBe_QIw-ax7JWfprOXZgzBegI6L6gXXomAY_XRPNlkdmtC3BYB0WCcAUWJt07uMYg3ifcE" width="240" /></a></div><br />Hope this helps someone!<p></p><p></p><p data-source="spec/Section%206%20--%20Execution.md#L65-L67" style="color: #333333; font-family: Cambria, "Palatino Linotype", Palatino, "Liberation Serif", serif; font-size: 17px;"></p>BrianLimhttp://www.blogger.com/profile/07107383864607795783noreply@blogger.com0tag:blogger.com,1999:blog-2064461998620158755.post-17174326804838025292024-01-27T02:29:00.000-08:002024-01-27T02:34:49.717-08:00Advanced React Hacks 2/10 - Dynamic JSX<h1 style="text-align: left;"> Advanced React Hacks 2/10 - Dynamic JSX</h1><div>What if you want a data driven application that renders JSON (not HTML obviously, always BBCode!) as JSX?</div><div><br /></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgp8BoIlTlyNgHEYYvmv1foKyuydk3f6e9C5wg3Du21o03FvijdFLtTs2fHEv7p41c1QFK-Rq6pRTFRiLtAbYm5NJYj2TO4Nj6pudwg1hZcIfauheeiyC0NDIuNpGSnIrWILr_HD-vlyOYzd7q8QbhRkr_UaXanyXXR8FVs2FVPO8A2bTMmBoRjGLQEhwoc" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="418" data-original-width="597" height="224" src="https://blogger.googleusercontent.com/img/a/AVvXsEgp8BoIlTlyNgHEYYvmv1foKyuydk3f6e9C5wg3Du21o03FvijdFLtTs2fHEv7p41c1QFK-Rq6pRTFRiLtAbYm5NJYj2TO4Nj6pudwg1hZcIfauheeiyC0NDIuNpGSnIrWILr_HD-vlyOYzd7q8QbhRkr_UaXanyXXR8FVs2FVPO8A2bTMmBoRjGLQEhwoc" width="320" /></a></div><br /></div><div><br /></div>One way is <a href="https://react.dev/reference/react/Children">React.Children</a><div><br /></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEj6nUaaq4aORbL4-zTnY7BZDbACmbsSG_47DAl6W55mhD6cuuKmSVrrAw1V_ab94qDcpmNjjjsLG8dDqhFnrcTyajGKqD9jQ62ObC88RLwEXOjAoIj3fM4LiiPXjy-toTJXvwmJzlkxsi-tWkDVaG94tJC5Om7Xns6JL6xxgkhtHxmuNZ_2GHL93o11K5X2" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="500" data-original-width="733" height="218" src="https://blogger.googleusercontent.com/img/a/AVvXsEj6nUaaq4aORbL4-zTnY7BZDbACmbsSG_47DAl6W55mhD6cuuKmSVrrAw1V_ab94qDcpmNjjjsLG8dDqhFnrcTyajGKqD9jQ62ObC88RLwEXOjAoIj3fM4LiiPXjy-toTJXvwmJzlkxsi-tWkDVaG94tJC5Om7Xns6JL6xxgkhtHxmuNZ_2GHL93o11K5X2" width="320" /></a></div><br />Instead do this,</div><div><br /></div><div><div style="background-color: #1a1a1a; color: #bbbbbb; font-family: "Fira Code", SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace, Consolas, "Courier New", monospace; font-size: 14px; line-height: 23px; white-space: pre;"><div><span style="color: #a390ff;">export</span> <span style="color: #a390ff;">const</span> <span style="color: #cdf861;">Component</span> <span style="color: #b3e8b4;">=</span> <span style="color: #86897a;">(</span>{ <span style="color: #ebebeb;">children</span> }<span style="color: #b3e8b4;">:</span> <span style="color: #86897a;">{</span> <span style="color: #ebebeb;">children</span><span style="color: #b3e8b4;">:</span> <span style="color: #cabeff;">ReactNode</span> <span style="color: #86897a;">})</span> <span style="color: #b3e8b4;">=></span> <span style="color: #86897a;">{</span></div><div> <span style="color: #a390ff;">const</span> <span style="color: #ebebeb;">isArray</span> <span style="color: #b3e8b4;">=</span> <span style="color: #a390ff;">Array</span><span style="color: #86897a;">.</span><span style="color: #cdf861;">isArray</span><span style="color: #86897a;">(</span><span style="color: #ebebeb;">children</span><span style="color: #86897a;">)</span>;</div><div> <span style="color: #a390ff;">return</span> <span style="color: #86897a;">(</span></div><div> <span style="color: #86897a;"><></span></div><div><span style="color: #f0f0f0;"> </span><span style="color: #86897a;">{</span><span style="color: #b3e8b4;">!</span><span style="color: #ebebeb;">isArray</span><span style="color: #f0f0f0;"> </span><span style="color: #b3e8b4;">&&</span><span style="color: #f0f0f0;"> </span><span style="color: #ebebeb;">children</span><span style="color: #86897a;">}</span></div><div><span style="color: #f0f0f0;"> </span><span style="color: #86897a;">{</span><span style="color: #ebebeb;">isArray</span><span style="color: #f0f0f0;"> </span><span style="color: #b3e8b4;">&&</span></div><div><span style="color: #f0f0f0;"> </span><span style="color: #ebebeb;">children</span><span style="color: #86897a;">.</span><span style="color: #cdf861;">map</span><span style="color: #86897a;">((</span><span style="color: #ebebeb;">child</span><span style="color: #86897a;">,</span><span style="color: #f0f0f0;"> </span><span style="color: #ebebeb;">index</span><span style="color: #86897a;">)</span><span style="color: #f0f0f0;"> </span><span style="color: #b3e8b4;">=></span><span style="color: #f0f0f0;"> </span><span style="color: #86897a;">{</span></div><div><span style="color: #f0f0f0;"> </span><span style="color: #a390ff;">return</span><span style="color: #f0f0f0;"> </span><span style="color: #86897a;"><</span><span style="color: #a390ff;">div</span><span style="color: #f0f0f0;"> </span><span style="color: #cabeff;">key</span><span style="color: #b3e8b4;">=</span><span style="color: #86897a;">{</span><span style="color: #ebebeb;">index</span><span style="color: #86897a;">}</span><span style="color: #86897a;">></span><span style="color: #86897a;">{</span><span style="color: #ebebeb;">child</span><span style="color: #86897a;">}</span><span style="color: #86897a;"></</span><span style="color: #a390ff;">div</span><span style="color: #86897a;">></span><span style="color: #f0f0f0;">; </span><span style="color: #6f6f6f;">// do stuff to the child here</span></div><div><span style="color: #f0f0f0;"> </span><span style="color: #86897a;">})</span><span style="color: #86897a;">}</span></div><div><span style="color: #f0f0f0;"> </span><span style="color: #86897a;"></></span></div><div> <span style="color: #86897a;">)</span>;</div><div><span style="color: #86897a;">}</span>;</div></div></div><div><br /></div><div>Now you can use it</div><div><br /></div><div><div style="background-color: #1a1a1a; color: #bbbbbb; font-family: "Fira Code", SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace, Consolas, "Courier New", monospace; font-size: 14px; line-height: 23px; white-space: pre;"><div><span style="color: #a390ff;">import</span> <span style="color: #86897a;">{</span> <span style="color: #ebebeb;">Component</span> <span style="color: #86897a;">}</span> <span style="color: #a390ff;">from</span> <span style="color: #b3e8b4;">"</span><span style="color: #bfd084;">./Component</span><span style="color: #b3e8b4;">"</span>;</div><br /><div><span style="color: #a390ff;">export</span> <span style="color: #a390ff;">default</span> <span style="color: #a390ff;">function</span> <span style="color: #cdf861;">App</span><span style="color: #86897a;">()</span> <span style="color: #86897a;">{</span></div><div> <span style="color: #a390ff;">return</span> <span style="color: #86897a;">(</span></div><div> <span style="color: #86897a;"><</span><span style="color: #a390ff;">div</span><span style="color: #86897a;">></span></div><div><span style="color: #f0f0f0;"> </span><span style="color: #86897a;"><</span><span style="color: #a390ff;">Component</span><span style="color: #86897a;">></span><span style="color: #f0f0f0;">test</span><span style="color: #86897a;"></</span><span style="color: #a390ff;">Component</span><span style="color: #86897a;">></span></div><div><span style="color: #f0f0f0;"> </span><span style="color: #86897a;"><</span><span style="color: #a390ff;">Component</span><span style="color: #86897a;">></span></div><div><span style="color: #f0f0f0;"> </span><span style="color: #86897a;"><</span><span style="color: #a390ff;">div</span><span style="color: #86897a;">></span><span style="color: #f0f0f0;">test2</span><span style="color: #86897a;"></</span><span style="color: #a390ff;">div</span><span style="color: #86897a;">></span></div><div><span style="color: #f0f0f0;"> </span><span style="color: #86897a;"><</span><span style="color: #a390ff;">div</span><span style="color: #86897a;">></span><span style="color: #f0f0f0;">test3</span><span style="color: #86897a;"></</span><span style="color: #a390ff;">div</span><span style="color: #86897a;">></span></div><div><span style="color: #f0f0f0;"> </span><span style="color: #86897a;"></</span><span style="color: #a390ff;">Component</span><span style="color: #86897a;">></span></div><div><span style="color: #f0f0f0;"> </span><span style="color: #86897a;"><</span><span style="color: #a390ff;">Component</span><span style="color: #86897a;">></span></div><div><span style="color: #f0f0f0;"> </span><span style="color: #86897a;"><</span><span style="color: #a390ff;">div</span><span style="color: #86897a;">></span><span style="color: #f0f0f0;">test4</span><span style="color: #86897a;"></</span><span style="color: #a390ff;">div</span><span style="color: #86897a;">></span></div><div><span style="color: #f0f0f0;"> </span><span style="color: #86897a;"><</span><span style="color: #a390ff;">div</span><span style="color: #86897a;">></span><span style="color: #f0f0f0;">test5</span><span style="color: #86897a;"></</span><span style="color: #a390ff;">div</span><span style="color: #86897a;">></span></div><div><span style="color: #f0f0f0;"> </span><span style="color: #86897a;"></</span><span style="color: #a390ff;">Component</span><span style="color: #86897a;">></span></div><div><span style="color: #f0f0f0;"> </span><span style="color: #86897a;"></</span><span style="color: #a390ff;">div</span><span style="color: #86897a;">></span></div><div> <span style="color: #86897a;">)</span>;</div><div><span style="color: #86897a;">}</span></div></div></div><div><br /></div>(Wow pasting from CodeSandbox worked!)<div><br /></div><div>https://codesandbox.io/p/sandbox/cranky-haslett-749y8y</div><div><br /></div><div>Hope this helps someone!</div>BrianLimhttp://www.blogger.com/profile/07107383864607795783noreply@blogger.com0tag:blogger.com,1999:blog-2064461998620158755.post-20161964355570800782024-01-21T11:25:00.000-08:002024-01-27T02:32:03.310-08:00Advanced React Hacks 1/10 - Conditional Hooks<h1 style="text-align: left;">Advanced React Hacks 1/10 - Conditional Hooks</h1><p> According to react.dev "Rules of Hooks" you cannot call hooks inside a condition</p><p><a href="https://react.dev/warnings/invalid-hook-call-warning#breaking-rules-of-hooks">https://react.dev/warnings/invalid-hook-call-warning#breaking-rules-of-hooks</a><br /></p><p><span style="color: #23272f; font-size: 17px;">But what if you want it?</span></p><p><span style="color: #23272f; font-size: 17px;"></span></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEgex-8DMKRK19WKmyH2wKi_65m-og_13SC8o-JtnKyk4exBbfwhlxYOwhA0qr0WJpMRSs69w7lp39csLqMiZY8C5qiXK1rU0Tsif3i_0FZxEumJfIKBrdh5S1LEfY0jV8UiMFYBMTwr8yugk_6iyzzyDg5z7ADZaI8AVdvKYAKF_H0oLE9EYGgQ1XiXsvDI" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="500" data-original-width="660" height="240" src="https://blogger.googleusercontent.com/img/a/AVvXsEgex-8DMKRK19WKmyH2wKi_65m-og_13SC8o-JtnKyk4exBbfwhlxYOwhA0qr0WJpMRSs69w7lp39csLqMiZY8C5qiXK1rU0Tsif3i_0FZxEumJfIKBrdh5S1LEfY0jV8UiMFYBMTwr8yugk_6iyzzyDg5z7ADZaI8AVdvKYAKF_H0oLE9EYGgQ1XiXsvDI" width="317" /></a></div><br /><span style="color: #23272f;"><span style="font-size: 17px;">Use components!</span></span><p></p><pre>export const ParentComponent = ({ component }: ParentComponentProps) => {</pre><pre><br /></pre><pre> /* derive condition here */</pre><pre> // const condition = false;</pre><pre> const condition = true;</pre><pre><br /></pre><pre> /* derive property here */</pre><pre> // cont property = 0;</pre><pre> // ...</pre><pre><br /></pre><pre> return (<></pre><pre> {</pre><pre> condition && <HookComponent hookProperty={property} /></pre><pre> }</pre><pre> </>);</pre><pre>}</pre><pre><br /></pre><pre>export const HookComponent = ({ hookProperty }: ChildComponentProps) => {</pre><pre> useCustomHook(hookProperty); // could be anything!</pre><pre> return <></>; // yes, components can render nothing</pre><pre>}</pre><pre><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/a/AVvXsEjW9hfZJieJH0dF2QPtYAcWpBtxEyBsNuG4h7pPG9sjz-5_7dLA5GQDJ2QATHmNwud4Mz0Aouh0CuIZjSgHZ4UMi6-TD9VjQVXgQmVzldU7xVSq5xGs426CQ3GQxLEa7FkpIGEbuwb_2NpJDvlT_BoszwFw1ZSsR-jHNa6q8sJ9TV-GVYGMjihhZPWDeGrQ" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="500" data-original-width="500" height="240" src="https://blogger.googleusercontent.com/img/a/AVvXsEjW9hfZJieJH0dF2QPtYAcWpBtxEyBsNuG4h7pPG9sjz-5_7dLA5GQDJ2QATHmNwud4Mz0Aouh0CuIZjSgHZ4UMi6-TD9VjQVXgQmVzldU7xVSq5xGs426CQ3GQxLEa7FkpIGEbuwb_2NpJDvlT_BoszwFw1ZSsR-jHNa6q8sJ9TV-GVYGMjihhZPWDeGrQ" width="240" /></a></div><br /></pre>With great power comes great responsibility!<br /><br /><div>Hope this helps! More next time...</div>BrianLimhttp://www.blogger.com/profile/07107383864607795783noreply@blogger.com0tag:blogger.com,1999:blog-2064461998620158755.post-23180027122334332112022-07-03T19:58:00.002-07:002022-07-03T19:58:34.952-07:00Yarn 2 and Yarn 3 Unrecognized or legacy configuration settings found<p>If you get this error</p><p><span style="background-color: #151a1e; color: white; font-family: SFMono-Regular, Menlo, Consolas, "Liberation Mono", Courier, monospace; font-size: 14.4px; white-space: pre-wrap;">Unrecognized or legacy configuration settings found</span></p><p>while running Yarn 2 or Yarn 3 it's possibly because you have a rogue environment variable YARN_XXXX in your environment</p><p>In my case, it was a <b>YARN_WORKSPACES </b>environment variable I accidentally created while using the Netlify BaaS that I was supposed to create with <b>NETLIFY_YARN_WORKSPACES</b></p><p>Delete the rogue environment variable (in this case from Netlify's Build GUI but in other cases could be from your Dockerfile or CI/CD pipeline) and your problem will disappear</p><p>Basically yarn is a busybody and if it sees YARN_XXXXXX in your environment, it will complain if it doesn't recognise the environment variable and fail your build</p><p>I discovered this by modifying the build command to use <b>yarn config -v </b>to see the list of errors and it was an undocumented yarn error code</p><p>See https://yarnpkg.com/advanced/error-codes#yn0050---deprecated_cli_settings for another Netlify configuration error</p><p>Hope this helps someone!</p>BrianLimhttp://www.blogger.com/profile/07107383864607795783noreply@blogger.com3tag:blogger.com,1999:blog-2064461998620158755.post-68987673091444571662020-10-20T05:38:00.001-07:002020-10-20T06:39:03.062-07:00IntelliJ Invalidate Cache Not Working with Gradle<p> Hi,</p><p>If IntellJ Invalidate Cache is not working, try to detach and reimport Gradle project from View > Tool Windows > Gradle (right panel)</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUzScGFxcqcaW7biAHAiYVYR_2yPRmPeygzsPdatxBhLWYPe2EvHXAEMoKuVpSwgm7amvb1V_uSNug_3PJllDAvZX1DI0F6FUDYakSY_jps3OYtlN31T-NXs9ZcpKsp8tNNsTXlDfP2-vE/" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="166" data-original-width="220" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgUzScGFxcqcaW7biAHAiYVYR_2yPRmPeygzsPdatxBhLWYPe2EvHXAEMoKuVpSwgm7amvb1V_uSNug_3PJllDAvZX1DI0F6FUDYakSY_jps3OYtlN31T-NXs9ZcpKsp8tNNsTXlDfP2-vE/" width="318" /></a></div><br /><p></p><p>This may allow you to view the most recent source and eliminate inconsistencies between your intellisense and the actual source code</p><p>Also try unchecking "create separate module per source set" when reimporting the Gradle project</p>BrianLimhttp://www.blogger.com/profile/07107383864607795783noreply@blogger.com6tag:blogger.com,1999:blog-2064461998620158755.post-79838958509222310142018-12-16T15:27:00.001-08:002018-12-16T15:28:40.921-08:00Debugging Multiple Projects in Visual Studio 2017Hi,<br />
<br />
Been a long time so here it goes -- debugging multiple projects<br />
<br />
If you look around a lot you will eventually find this<br />
<br />
<a href="https://docs.microsoft.com/en-us/visualstudio/ide/how-to-set-multiple-startup-projects?view=vs-2017">https://docs.microsoft.com/en-us/visualstudio/ide/how-to-set-multiple-startup-projects?view=vs-2017</a><br />
<br />
But actually, you can't do that well<br />
<br />
<ul>
<li>Most people have custom run configurations</li>
<li>In my case, I was passing parameters to a console program that contacts a service, both in the same solution... doing "multiple project startup" doesn't give me enough control</li>
<li>Microsoft doesn't have good support for this configuration <a href="https://developercommunity.visualstudio.com/content/problem/225855/multiple-startup-project-selection-not-saved.html">https://developercommunity.visualstudio.com/content/problem/225855/multiple-startup-project-selection-not-saved.html</a></li>
<li>It doesn't offer a seamless experience (the service should be persistent, callable from Postman, etc.)</li>
</ul>
<br />
<br />
<img alt="Crunchify.com - RESTful Introduction" height="151" src="https://cdn.crunchify.com/wp-content/uploads/2012/10/Crunchify.com-RESTful-Introduction.png" width="400" /><br />
<i><a href="https://crunchify.com/specifications-methods-in-restful-web-service/">(the most important picture in the world my friends Java but I liked the picture)</a></i><br />
<i><br /></i>
So here is what you do, if you want to debug dotnet core webservices<br />
<br />
* You publish in debug mode to folder<br />
* Startup the project after setting ASPNETCORE_ENVIRONMENT variable<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEzWL7OYTm7Z3NRjdoU3HvHcozItbtSwz3kchkNDShSwK3lxbuOnhMHkhAf4Z6gDiQq7fcTcmfpG-3RMb2tbW06T5mtPV0P7bv5LQ51Fsax4GlsKFtZOHIMGhUjxqooLSi2THSKD-g1VD_/s1600/aspnetcoreservice.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="648" data-original-width="1152" height="225" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEzWL7OYTm7Z3NRjdoU3HvHcozItbtSwz3kchkNDShSwK3lxbuOnhMHkhAf4Z6gDiQq7fcTcmfpG-3RMb2tbW06T5mtPV0P7bv5LQ51Fsax4GlsKFtZOHIMGhUjxqooLSi2THSKD-g1VD_/s400/aspnetcoreservice.png" width="400" /></a></div>
<div style="text-align: center;">
<i>(Do PowerShell for powers)</i></div>
<br />
* Now startup your web project / console program / whatever is going to contact the service in Visual Studio<br />
* Now back to OLD SCHOOL and ATTACH TO PROCESS<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhsj_R6f1le1nxFHk5fiT-Fs51DaPVh2HVYK_aZ69vnFa2I7NawTkbp0YuRT5NqBDYAd8bMbpzddoYrqYBTwDh7bjmV1PoXWlDbwQFjZ3kkTTyXBv9XDCWdMZlT56nx4m4RRYxfpbJojbZO/s1600/attachtoprocess.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="648" data-original-width="1152" height="180" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhsj_R6f1le1nxFHk5fiT-Fs51DaPVh2HVYK_aZ69vnFa2I7NawTkbp0YuRT5NqBDYAd8bMbpzddoYrqYBTwDh7bjmV1PoXWlDbwQFjZ3kkTTyXBv9XDCWdMZlT56nx4m4RRYxfpbJojbZO/s320/attachtoprocess.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<i>(I know, greatest window in the world)</i></div>
<br />
So it's a little pain in the ass to get it to work especially if you debug a lot. Attach to process every single time. But the key is dotnet core comes with its own webserver (Kestrel). You don't need IIS anymore and you don't need IIS Express anymore.<br />
<br />
I am sure there's some crazy way to get it working with IIS / Visual Studio integration, remote debugging, etc., etc., but this way works and doesn't involve downloading a half dozen things and configuring IIS (which is half the point of dotnet core, lol). It also gets you ready for the day everything is on command line and you don't need Visual Studio (yeah, right).<br />
<br />
Happy Coding<br />
<br />BrianLimhttp://www.blogger.com/profile/07107383864607795783noreply@blogger.com14tag:blogger.com,1999:blog-2064461998620158755.post-10663094477124352022018-05-13T04:16:00.003-07:002018-05-13T07:20:10.777-07:00Ungzipping Gzip Compression Without HTTP Headers or With File Size Limit<b><u>Ungzipping in the Browser</u></b><br />
<br />
Sometimes, developers get given tasks outside of their usual area of responsibility. For example, dealing with gzipping.<br />
<br />
<img alt="Gzip-Logo.png" src="https://upload.wikimedia.org/wikipedia/commons/thumb/0/0c/Gzip-Logo.png/220px-Gzip-Logo.png" /><br />
<br />
Gzip is a compression algorithm that's existed for over 25 years. It's a standard on the Internet and almost everything is served gzipped if it is served properly. There's various ways to deal with this, for example just letting the webserver gzip on the fly. However, you may run into a situation where that is impossible. For example, you may have some artificial limit of file size of less than 1 MB.<br />
<br />
<b><a href="https://docs.microsoft.com/en-us/azure/cdn/cdn-troubleshoot-compression">https://docs.microsoft.com/en-us/azure/cdn/cdn-troubleshoot-compression</a></b><br />
<br />
(no code splitting is not always an answer; in particular, if you have an integration between different products, code splitting creates an unstable integration between two different products with different release cycles. a little bit of knowledge is a dangerous thing without the details.)<br />
<br />
And of course even if you managed to gzip, if the infrastructure cannot guarantee the CONTENT-TYPE and CONTENT-ENCODING HTTP Headers and even more HTTP headers like Vary: Accept-Encoding, then the browser may decide to download the gzipped files instead of ungzipping by itself. Or simply crash.<br />
<br />
<b><a href="https://blog.stackpath.com/accept-encoding-vary-important">https://blog.stackpath.com/accept-encoding-vary-important</a></b><br />
<br />
It is also a general ask for JavaScript developers, particularly on full stack JavaScript (for example with Express as the webserver) to deal with gzipping manually. However, who knows where it will be served? It could be served on Apache, on IIS or on a CDN. So chances are, you will be asked during your career to gzip files where<br />
<br />
a) you cannot guarantee the HTTP headers<br />
<br />
or have other restrictions such as<br />
<br />
b) cannot guarantee the file size (as of May 2018, there are 400 issues open in the webpack issue tracker for the <a href="https://github.com/webpack/webpack/tree/master/examples/http2-aggressive-splitting">split by file size</a> . Even if code splitting by file size (actually called chunking) is done, it's experimental and bug ridden. And besides, splitting into many files is <i><b>not </b></i>compression... unless you serve over HTTP2 serving many files introduces an overhead. Gzipping is a standard, it must be done and the gains are too big to ignore. We are looking at gains of 5 to 10 times.<br />
<br />
<b><a href="https://css-tricks.com/the-difference-between-minification-and-gzipping/">https://css-tricks.com/the-difference-between-minification-and-gzipping/</a></b><br />
<br />
(in case you are wondering, no you cannot access the browser's native ungzip facility with JavaScript -- that is only accessible if the HTTP headers are present, and you never have access to the raw script text anyway due to cross origin policy so you will be looking at an AJAX request. If you can't make an AJAX request because of missing Access-Control-Allow-Origin or missing whitelisting tough shit, you got much bigger problems).<br />
<br />
So what is a developer to do? Wash his hands and blame the ops guys? Who cares about gzip right, it's not our problem it's the server's problem. In fact who cares about user experience at all it can take ten seconds to load we will just wash our hands of these stupid server troubles. We are not server guys we are developers who cares about HTTP headers and how it's hosted right?<br />
<br />
<img alt="Image result for troll face" src="http://i0.kym-cdn.com/entries/icons/original/000/000/091/TrollFace.jpg" height="112" width="200" /><br />
<br />
Of course not. Let's put the Dev back in DevOps and ungzip on the fly, <i>with or without HTTP headers, on any infrastructure (well except for the Access-Control-Allow-Origin header that everyone has).</i> Yeah baby! It will be dirty, messy but it will work.<br />
<br />
<b><u>Build Process</u></b><br />
<b><u><br /></u></b>
You can gzip in many ways, for example with this plugin if you are using webpack.<br />
<br />
<a href="https://github.com/webpack-contrib/compression-webpack-plugin">https://github.com/webpack-contrib/compression-webpack-plugin</a><br />
<br />
You can also just use the Linux gzip utility as part of your build process.<br />
<b><u><br /></u></b>
<b><u>The Client Side Code (or, the SECRET SAUCE)</u></b><br />
<b><u><br /></u></b>
We will use the library <b>pako.js</b> to ungzip on the fly, with or without the correct HTTP headers.<br />
<br />
<a href="http://nodeca.github.io/pako/">http://nodeca.github.io/pako/</a><br />
<br />
In order to make sure the JavaScript files load in the correct order, we will use JavaScript Promises (which we will require a shim for IE support) and the JavaScript Fetch API (which also requires a shim for IE support). These are the required libraries.<br />
<br />
https://cdnjs.cloudflare.com/ajax/libs/fetch/2.0.4/fetch.min.js<br />
https://cdnjs.cloudflare.com/ajax/libs/bluebird/3.5.1/bluebird.min.js<br />
https://cdnjs.cloudflare.com/ajax/libs/pako/1.0.6/pako.min.js<br />
<br />
We fetch, paying attention to three things<br />
<br />
<a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch">https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch</a><br />
<br />
1. Load scripts in the correct order<br />
2. Deal with HTTP errors with a CheckXHR method (write this!)<br />
3. Fallback to the JS version, should an error occur<br />
<br />
<pre>fetch('http://www.example.com/test.js.gz')
.then(CheckXHR)
.then(function (response) {
return response.arrayBuffer(); // important to pass to PAKO.JS as array not as string
})</pre>
<pre> .then(function (arr) {</pre>
<pre> return injectScript(arr);</pre>
<pre> })</pre>
<pre> // load more scripts here
.onError(function (response) {
// deal with error... I suggest loading the ungzipped JS files as a fallback here
});
</pre>
<br />
We will dynamically inject the script, again returning a JavaScript promise on completion. Because we are dealing with text in the inner HTML tag, we don't have to use onload or onreadystatechange (IE).<br />
<br />
<pre>function injectScript(arr) {
return new Promise(function (resolve, reject) {
var script = document.createElement('script');
script.text = pako.ungzip(arr, { to: 'string' });
document.head.appendChild(script);
resolve();
});
}</pre>
<pre>
</pre>
<pre></pre>
<pre></pre>
And there we go, complete.<br />
<br />
With great power comes great responsibility; make sure you measure the performance in the browser to see the decrease not only in file size but how long it takes to actually use the web application.<br />
<br />
Hopefully this helps someone<br />
<br />
P.S. Message to server guys : we can code on a 386 or a RaspberryPi or a Commodore 64 or TRS-80 or string and yarn and foodstuffs and but that doesn't mean it's a good idea or a good use of time or money or resources. Upgrade your infrastructure to allow gzipping of any arbitrary file size with the correct HTTP headers and make the infrastructure work with the developers not against them, because the next time the problem might not be so (un)easy to solve.<br />
<br />
<iframe allow="autoplay; encrypted-media" allowfullscreen="" frameborder="0" height="315" src="https://www.youtube.com/embed/yfJXd0rSCqo" width="560"></iframe>
<br />
<br />BrianLimhttp://www.blogger.com/profile/07107383864607795783noreply@blogger.com2tag:blogger.com,1999:blog-2064461998620158755.post-12486980917093753232018-05-04T05:10:00.001-07:002018-05-04T05:12:47.602-07:00Microsoft Surface Can't Connect to WiFiHi, leaving a quick note here for people<br />
<br />
If you cannot connect with your Microsoft Surface or Surface Pro with WiFi to any Internet and have tried everything else, look at the date<br />
<br />
<img alt="Image result for microsoft surface os change date" src="https://www.lovemysurface.net/wp-content/uploads/2015/06/Issues-With-the-Clock-on-Surface-Tablets-Date-Time.png" /><br />
<br />
The WiFi will refuse to connect without a correct date... you don't have to be exact to the millisecond, but you do have to be within the minute range particularly with corporate networks<br />
<br />
Change the date and time manually to match the correct date and WiFi may magically work again<br />
<br />
This is after disabling IPv6 and other various suggestions you may find elsewhere -- do some Googling<br />
<br />
Hope this helps someone<br />
<br />
~ BBrianLimhttp://www.blogger.com/profile/07107383864607795783noreply@blogger.com2tag:blogger.com,1999:blog-2064461998620158755.post-14228844039036883962017-01-08T00:29:00.000-08:002017-01-08T00:29:23.465-08:00Our Responsibility as ProgrammersJust read an <a href="http://blog.cleancoder.com/uncle-bob/2014/11/15/WeRuleTheWorld.html">article </a>by Robert Martin, of "Clean Code" fame (if you haven't heard of Clean Code, read it -- it's probably the seminal text for clean object-oriented programming... some of the advice in it is dated with test-driven development and Java, but it is worth a skim at least)<br />
<br />
"<span style="background-color: #f8fff8; color: #29323c; font-family: FrescoPlusNormal, Georgia, serif; font-size: 17.92px;">Without software: Phones don't ring. Cars don't start. Planes don't fly. Bombs don't explode. Ships don't sail. Ovens don't bake. Garage doors don't open. Money doesn't change hands. Electricity doesn't get generated. And we can't find our way to the store. </span><em style="background-color: #f8fff8; box-sizing: border-box; color: #29323c; font-family: FrescoSansPlusPro-Normal-Italic; font-size: 1.1em;">Nothing</em><span style="background-color: #f8fff8; color: #29323c; font-family: FrescoPlusNormal, Georgia, serif; font-size: 17.92px;"> happens without software. And what is software? </span><em style="background-color: #f8fff8; box-sizing: border-box; color: #29323c; font-family: FrescoSansPlusPro-Normal-Italic; font-size: 1.1em;">Software is a set of rules</em><span style="background-color: #f8fff8; color: #29323c; font-family: FrescoPlusNormal, Georgia, serif; font-size: 17.92px;">."</span><br />
<br />
Also, this<br />
<br />
"<span style="background-color: #f8fff8; color: #29323c; font-family: FrescoPlusNormal, Georgia, serif; font-size: 17.92px;">If the ranks of programmers has doubled every five years, then it stands to reason that most programmers were hired within the last five years, and so about half the programmers would be under 28. Half of those over 28 would be less than 33. Half of those over 33 would be less than 38, and so on. Less than 0.5% of programmers would be 60 or over. So most of us old programmers are still around writing code. It's just that there never were very many of us.</span><br />
<div style="background-color: #f8fff8; box-sizing: border-box; color: #29323c; font-family: FrescoPlusNormal, Georgia, serif; font-size: 17.92px; margin-bottom: 0.8em;">
What does this imply for our industry?</div>
<div style="background-color: #f8fff8; box-sizing: border-box; color: #29323c; font-family: FrescoPlusNormal, Georgia, serif; font-size: 17.92px; margin-bottom: 0.8em;">
Maybe it's not as bad as <em style="box-sizing: border-box; font-family: FrescoSansPlusPro-Normal-Italic; font-size: 1.1em;">Lord of the Flies</em>, but the fact that juniors exponentially outnumbers seniors is concerning. As long as that growth curve continues[4] there will not be enough teachers, role models, and leaders. It means that most software teams will remain relatively unguided, unsupervised, and inexperienced. It means that most software organizations will have to endlessly relearn the lessons they learned the five years before. It means that the industry as a whole will remain dominated by novices, and exist in a state of perpetual immaturity." - <a href="http://blog.cleancoder.com/uncle-bob/2014/06/20/MyLawn.html">Robert Martin</a>, </div>
Basically the problem is this, more in 2017 than ever -- the world has unwittingly ceded control of its financial, healthcare and private personal information for better or worse to computer programmers. We have a duty to create systems which are maintainable, robust and error free, even if it costs us in the short term.<br />
<br />
What are the problems? The problems are in-your-face, serious, and unfortunately have nothing at all to do with coding or computer programming.<br />
<br />
<b>Example #1 (easy):</b> Boss asks for deadline, you can take a shortcut. Either you can take a shortcut, or take 20% more time... piss them off now and make them happy later, or go for the short term gain.<br />
<br />
<b>Example #2 (hard):</b> You are in a responsibility of great authority to pick a framework or a technology and you can either choose what is cool and hot, and therefore good for your career (great, one more line for your resume!), or choose proven but less cool and less interesting technologies. Balance this against whether or not the technology is about to go out of the market (you can write a website in COBOL but it is NOT a good idea!)<br />
<br />
<b>Example #3 (very hard):</b> You have the ear of business people, and you must convince them of the need to create a process or build a framework or library which has no readily apparent business value and no readily apparent use cases, but will increase developer productivity ten-fold down the line, or allow you to enter emerging markets or attack potential competitors.<br />
<br />
<b>Example #4 (extreme):</b> You must either sacrifice personal time and personal emotion and energy to create a process / library / frameworks for your company or down the road you see the end of your company or business (at least tech-wise)... the tech is so bad nobody will want to work there or stay there, you see the train coming a mile away but you are superglued to the tracks at least at work. So you either have to sacrifice, in order to move the company in the right direction, and get 0 credit for it, or hold your tongue and hope that the world works differently than you think.<br />
<br />
What are the answer to these problems? I could give my answers, but they would be my answers.<br />
<br />
The point is, there are no right answers... it depends on the situation, the market, and most of all experience. And, if Robert Martin's numbers are to be believed, experience is severely lacking.<br />
<br />
I don't pretend to know anything about making money or business. Maybe markets are all about point in time and maybe writing spaghetti code and awful code is the way to do it -- forget about "tech" things like build processes, GitHub, Open Source, frameworks, automation, libraries and command line tools. Forget about <a href="http://www.catb.org/esr/writings/taoup/html/">The Art of Unix Programming</a> and give the business people what they want, all the time, because the market wants now and only now and later will be too late because the market won't exist anymore.<br />
<br />
Or, we could draw a line and say this far and no further... the line must be drawn here. Either take the time to do it right, or suffer the consequences.<br />
<br />
How many "senior" developers, and technical leads and architects know this? How many programmers even care about these issues?<br />
<br />
In the end we must all do things we can live with. We all have our own moral codes and standards. The choice is easy. Living with what we choose is the hard part.BrianLimhttp://www.blogger.com/profile/07107383864607795783noreply@blogger.com6tag:blogger.com,1999:blog-2064461998620158755.post-41589651216929562612016-06-11T12:46:00.001-07:002016-06-11T12:49:44.919-07:00Git and GitHub in 5 Minutes for WindowsHi,<br />
<br />
This is Git in Five Minutes for Windows<br />
<br />
After this, you should be able to<br />
<br />
<ul>
<li>Create a git repository on the command line</li>
<li>Add files for staging</li>
<li>Commit files</li>
<li>Push files to a remote, ex. GitHub</li>
</ul>
<div>
<h2>
0. Download Git for Windows Here</h2>
</div>
<div>
<br /></div>
<div>
https://git-scm.com/download/win</div>
<div>
<h2>
<br />1. Configure Git</h2>
</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhaP3eopP6XEKOj5xjZPUf-52iECYY2gXBJNXrGFtp06BZuPS56OofF7-ZuNtd0xX5N3hEcp7CiVo5xIVMG8IyMD1XUJWYWVeft6m9FkXmC2EHNIMilFlxnN_fFjwqoGdR9BYI6rm7DClw5/s1600/git-windows-0.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="161" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhaP3eopP6XEKOj5xjZPUf-52iECYY2gXBJNXrGFtp06BZuPS56OofF7-ZuNtd0xX5N3hEcp7CiVo5xIVMG8IyMD1XUJWYWVeft6m9FkXmC2EHNIMilFlxnN_fFjwqoGdR9BYI6rm7DClw5/s320/git-windows-0.png" width="320" /></a></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
git config --global user.name "Full Name Here"<br />
git config --global user.email "Full Email Here"<br />
<h2>
<br />2. Creating a Git Repository</h2>
</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiLADphJ1r2GQwtbBd4FHqt6AwGULfxhvNZzcDjdWct5ROB6Kkv9G2GJijbOjSuvT2AjsvZ6yb8baW1t71rEqCwodMucZ5PoI3g8V0FxAHtyZVQokOG9RxAokw_5pCAOMyR-pWf23l6EXfv/s1600/git-windows-1.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="202" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiLADphJ1r2GQwtbBd4FHqt6AwGULfxhvNZzcDjdWct5ROB6Kkv9G2GJijbOjSuvT2AjsvZ6yb8baW1t71rEqCwodMucZ5PoI3g8V0FxAHtyZVQokOG9RxAokw_5pCAOMyR-pWf23l6EXfv/s400/git-windows-1.png" width="400" /></a></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
git init<br />
<br />
<h2>
3. Create a File, Stage and Commit It</h2>
</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVyqEKpMReWBdYlVcDm0FN1PkKeiS3t2iT7je-RqVaJfxJwXn3IeHo3hbdol0WNY-PVOpRL4rm3Rb6-S4_y7uPnF7FAv1OrTlejl5QGZynFWj9RtNyrKZrvAGzQS9Oa7AEAEIzTp2CeqaT/s1600/git-windows-2.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="205" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVyqEKpMReWBdYlVcDm0FN1PkKeiS3t2iT7je-RqVaJfxJwXn3IeHo3hbdol0WNY-PVOpRL4rm3Rb6-S4_y7uPnF7FAv1OrTlejl5QGZynFWj9RtNyrKZrvAGzQS9Oa7AEAEIzTp2CeqaT/s400/git-windows-2.png" width="400" /></a></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br />
echo $null >> text.txt<br />
git status<br />
git add .<br />
git commit -m "Initial Commit"<br />
<br />
<h2>
4. Create a Profile and Empty Repository on GitHub</h2>
</div>
<div>
<br /></div>
<div>
<a href="https://help.github.com/articles/create-a-repo/">GitHub - How to Create a Repository</a></div>
<div>
<br /></div>
<div>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWDbTuJe2rvYTwTbpY5qsODi6YPh-ebjpsYoMwHi9ScLTZGNx5F7fSCzF2fLPid3He0shJrel6QtvLqp1AcBIWxYLCoowAMyaU8f8361U8YfPRjKvXqjHkaXZPN4w7ufgM1KVlPeznl0Oj/s1600/git-windows-3.png" imageanchor="1" style="clear: left; display: inline !important; float: left; margin-bottom: 1em; margin-right: 1em; text-align: center;"><img border="0" height="307" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWDbTuJe2rvYTwTbpY5qsODi6YPh-ebjpsYoMwHi9ScLTZGNx5F7fSCzF2fLPid3He0shJrel6QtvLqp1AcBIWxYLCoowAMyaU8f8361U8YfPRjKvXqjHkaXZPN4w7ufgM1KVlPeznl0Oj/s400/git-windows-3.png" width="400" /></a></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br />
<br />
<h2>
5. Get the URL from GitHub and Push Code to GitHub</h2>
</div>
<div>
<br /></div>
<div>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjD1Ub1iYReE5VdqYGeC62Q-5w3oPkkfu09tPIy0DJkOnR_MWPY7y3zaEx6U32QF8BJbpRE3bvYh5Z7EyfrlamyDGxJGFva7RdHyO114cN32ttgzmruQ2GzwS6tr3xTLn4XNkLMmxsLQ0SF/s1600/git-windows-4.png" imageanchor="1" style="clear: left; display: inline !important; margin-bottom: 1em; margin-right: 1em; text-align: center;"><img border="0" height="210" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjD1Ub1iYReE5VdqYGeC62Q-5w3oPkkfu09tPIy0DJkOnR_MWPY7y3zaEx6U32QF8BJbpRE3bvYh5Z7EyfrlamyDGxJGFva7RdHyO114cN32ttgzmruQ2GzwS6tr3xTLn4XNkLMmxsLQ0SF/s320/git-windows-4.png" width="320" /></a></div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhqcYBsCEQJKw00u6KoVc8KY_yfdWaRNswEhtgBLLvp2hme1EcbgMuP6942sFasuzbJh7dov9pBg_8Hc5nSw7yz2GJN2Y0uZLCax1z99yZObw1b98-GNIGDHpgomt60jWDoRKk2Y5DTWpvG/s1600/git-windows-5.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="161" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhqcYBsCEQJKw00u6KoVc8KY_yfdWaRNswEhtgBLLvp2hme1EcbgMuP6942sFasuzbJh7dov9pBg_8Hc5nSw7yz2GJN2Y0uZLCax1z99yZObw1b98-GNIGDHpgomt60jWDoRKk2Y5DTWpvG/s320/git-windows-5.png" width="320" /></a></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
git remote add origin url<br />
git push -u origin master (you may be prompted for GitHub login + username)<br />
<br />
See the file successfully on GitHub!</div>
<div>
<br /></div>
<div>
<h2>
Future Steps</h2>
<br /></div>
<div>
1. Learn what a <a href="https://git-scm.com/book/en/v2/Git-Branching-Basic-Branching-and-Merging">branch</a> is (the whole point of DVCS - distributed version control and Git!)</div>
<div>
2. Learn what a <a href="https://help.github.com/articles/fork-a-repo/">fork</a> is (the whole point of GitHub!)</div>
<div>
3. Fork an existing open source project with an issue you can solve </div>
<div>
<ul>
<li>Pick a language, or learn a language! (JavaScript / C# / Java / C++ / C / whatever!)</li>
<ul>
<li>If you don't know ANY programming, play around with <a href="https://scratch.mit.edu/projects/editor/?tip_bar=home">this</a> then take some "intro to programming" or "learn programming" <a href="https://www.coursera.org/courses?languages=en&query=programming">course</a> (preferably one that's fun)</li>
</ul>
<li>Start small, change one line or handful of lines of code!</li>
</ul>
</div>
<div>
4. Commit and push your change to your own fork, then issue a <a href="https://help.github.com/articles/using-pull-requests/">pull request</a>!</div>
<div>
<br /></div>
<div>
???</div>
<div>
<br /></div>
<div>
profit</div>
<div>
<br /></div>
<div>
Hope this tutorial was helpful</div>
<div>
<br /></div>
<div>
~ B</div>
<div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWDbTuJe2rvYTwTbpY5qsODi6YPh-ebjpsYoMwHi9ScLTZGNx5F7fSCzF2fLPid3He0shJrel6QtvLqp1AcBIWxYLCoowAMyaU8f8361U8YfPRjKvXqjHkaXZPN4w7ufgM1KVlPeznl0Oj/s1600/git-windows-3.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><br /></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWDbTuJe2rvYTwTbpY5qsODi6YPh-ebjpsYoMwHi9ScLTZGNx5F7fSCzF2fLPid3He0shJrel6QtvLqp1AcBIWxYLCoowAMyaU8f8361U8YfPRjKvXqjHkaXZPN4w7ufgM1KVlPeznl0Oj/s1600/git-windows-3.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><br /></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWDbTuJe2rvYTwTbpY5qsODi6YPh-ebjpsYoMwHi9ScLTZGNx5F7fSCzF2fLPid3He0shJrel6QtvLqp1AcBIWxYLCoowAMyaU8f8361U8YfPRjKvXqjHkaXZPN4w7ufgM1KVlPeznl0Oj/s1600/git-windows-3.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><br /></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWDbTuJe2rvYTwTbpY5qsODi6YPh-ebjpsYoMwHi9ScLTZGNx5F7fSCzF2fLPid3He0shJrel6QtvLqp1AcBIWxYLCoowAMyaU8f8361U8YfPRjKvXqjHkaXZPN4w7ufgM1KVlPeznl0Oj/s1600/git-windows-3.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><br /></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWDbTuJe2rvYTwTbpY5qsODi6YPh-ebjpsYoMwHi9ScLTZGNx5F7fSCzF2fLPid3He0shJrel6QtvLqp1AcBIWxYLCoowAMyaU8f8361U8YfPRjKvXqjHkaXZPN4w7ufgM1KVlPeznl0Oj/s1600/git-windows-3.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><br /></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWDbTuJe2rvYTwTbpY5qsODi6YPh-ebjpsYoMwHi9ScLTZGNx5F7fSCzF2fLPid3He0shJrel6QtvLqp1AcBIWxYLCoowAMyaU8f8361U8YfPRjKvXqjHkaXZPN4w7ufgM1KVlPeznl0Oj/s1600/git-windows-3.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><br /></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWDbTuJe2rvYTwTbpY5qsODi6YPh-ebjpsYoMwHi9ScLTZGNx5F7fSCzF2fLPid3He0shJrel6QtvLqp1AcBIWxYLCoowAMyaU8f8361U8YfPRjKvXqjHkaXZPN4w7ufgM1KVlPeznl0Oj/s1600/git-windows-3.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><br /></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWDbTuJe2rvYTwTbpY5qsODi6YPh-ebjpsYoMwHi9ScLTZGNx5F7fSCzF2fLPid3He0shJrel6QtvLqp1AcBIWxYLCoowAMyaU8f8361U8YfPRjKvXqjHkaXZPN4w7ufgM1KVlPeznl0Oj/s1600/git-windows-3.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><br /></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWDbTuJe2rvYTwTbpY5qsODi6YPh-ebjpsYoMwHi9ScLTZGNx5F7fSCzF2fLPid3He0shJrel6QtvLqp1AcBIWxYLCoowAMyaU8f8361U8YfPRjKvXqjHkaXZPN4w7ufgM1KVlPeznl0Oj/s1600/git-windows-3.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><br /></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWDbTuJe2rvYTwTbpY5qsODi6YPh-ebjpsYoMwHi9ScLTZGNx5F7fSCzF2fLPid3He0shJrel6QtvLqp1AcBIWxYLCoowAMyaU8f8361U8YfPRjKvXqjHkaXZPN4w7ufgM1KVlPeznl0Oj/s1600/git-windows-3.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><br /></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWDbTuJe2rvYTwTbpY5qsODi6YPh-ebjpsYoMwHi9ScLTZGNx5F7fSCzF2fLPid3He0shJrel6QtvLqp1AcBIWxYLCoowAMyaU8f8361U8YfPRjKvXqjHkaXZPN4w7ufgM1KVlPeznl0Oj/s1600/git-windows-3.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><br /></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWDbTuJe2rvYTwTbpY5qsODi6YPh-ebjpsYoMwHi9ScLTZGNx5F7fSCzF2fLPid3He0shJrel6QtvLqp1AcBIWxYLCoowAMyaU8f8361U8YfPRjKvXqjHkaXZPN4w7ufgM1KVlPeznl0Oj/s1600/git-windows-3.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><br /></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWDbTuJe2rvYTwTbpY5qsODi6YPh-ebjpsYoMwHi9ScLTZGNx5F7fSCzF2fLPid3He0shJrel6QtvLqp1AcBIWxYLCoowAMyaU8f8361U8YfPRjKvXqjHkaXZPN4w7ufgM1KVlPeznl0Oj/s1600/git-windows-3.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><br /></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWDbTuJe2rvYTwTbpY5qsODi6YPh-ebjpsYoMwHi9ScLTZGNx5F7fSCzF2fLPid3He0shJrel6QtvLqp1AcBIWxYLCoowAMyaU8f8361U8YfPRjKvXqjHkaXZPN4w7ufgM1KVlPeznl0Oj/s1600/git-windows-3.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><br /></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWDbTuJe2rvYTwTbpY5qsODi6YPh-ebjpsYoMwHi9ScLTZGNx5F7fSCzF2fLPid3He0shJrel6QtvLqp1AcBIWxYLCoowAMyaU8f8361U8YfPRjKvXqjHkaXZPN4w7ufgM1KVlPeznl0Oj/s1600/git-windows-3.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><br /></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWDbTuJe2rvYTwTbpY5qsODi6YPh-ebjpsYoMwHi9ScLTZGNx5F7fSCzF2fLPid3He0shJrel6QtvLqp1AcBIWxYLCoowAMyaU8f8361U8YfPRjKvXqjHkaXZPN4w7ufgM1KVlPeznl0Oj/s1600/git-windows-3.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><br /></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWDbTuJe2rvYTwTbpY5qsODi6YPh-ebjpsYoMwHi9ScLTZGNx5F7fSCzF2fLPid3He0shJrel6QtvLqp1AcBIWxYLCoowAMyaU8f8361U8YfPRjKvXqjHkaXZPN4w7ufgM1KVlPeznl0Oj/s1600/git-windows-3.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><br /></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWDbTuJe2rvYTwTbpY5qsODi6YPh-ebjpsYoMwHi9ScLTZGNx5F7fSCzF2fLPid3He0shJrel6QtvLqp1AcBIWxYLCoowAMyaU8f8361U8YfPRjKvXqjHkaXZPN4w7ufgM1KVlPeznl0Oj/s1600/git-windows-3.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><br /></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWDbTuJe2rvYTwTbpY5qsODi6YPh-ebjpsYoMwHi9ScLTZGNx5F7fSCzF2fLPid3He0shJrel6QtvLqp1AcBIWxYLCoowAMyaU8f8361U8YfPRjKvXqjHkaXZPN4w7ufgM1KVlPeznl0Oj/s1600/git-windows-3.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><br /></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWDbTuJe2rvYTwTbpY5qsODi6YPh-ebjpsYoMwHi9ScLTZGNx5F7fSCzF2fLPid3He0shJrel6QtvLqp1AcBIWxYLCoowAMyaU8f8361U8YfPRjKvXqjHkaXZPN4w7ufgM1KVlPeznl0Oj/s1600/git-windows-3.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><br /></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWDbTuJe2rvYTwTbpY5qsODi6YPh-ebjpsYoMwHi9ScLTZGNx5F7fSCzF2fLPid3He0shJrel6QtvLqp1AcBIWxYLCoowAMyaU8f8361U8YfPRjKvXqjHkaXZPN4w7ufgM1KVlPeznl0Oj/s1600/git-windows-3.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><br /></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWDbTuJe2rvYTwTbpY5qsODi6YPh-ebjpsYoMwHi9ScLTZGNx5F7fSCzF2fLPid3He0shJrel6QtvLqp1AcBIWxYLCoowAMyaU8f8361U8YfPRjKvXqjHkaXZPN4w7ufgM1KVlPeznl0Oj/s1600/git-windows-3.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><br /></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWDbTuJe2rvYTwTbpY5qsODi6YPh-ebjpsYoMwHi9ScLTZGNx5F7fSCzF2fLPid3He0shJrel6QtvLqp1AcBIWxYLCoowAMyaU8f8361U8YfPRjKvXqjHkaXZPN4w7ufgM1KVlPeznl0Oj/s1600/git-windows-3.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><br /></a></div>
</div>
BrianLimhttp://www.blogger.com/profile/07107383864607795783noreply@blogger.com5tag:blogger.com,1999:blog-2064461998620158755.post-22293041084384104422016-02-21T12:37:00.002-08:002016-02-21T12:37:28.842-08:00Advanced MVVM Concepts - MVVM Practical Theory and Experience Part 1Hello,<br />
<br />
This is Part 1 of short series of blog posts about practical MVVM and its usage. The goal of these posts will be to give information not readily available through documentation or examples, mainly how to construct a complex data-driven application with non-trivial issues.<br />
<br />
This post will discuss the practical theory about MVVM and it's application in real-world applications. For theory and an introduction, look <a href="http://martinfowler.com/eaaDev/PresentationModel.html">Martin Fowler's</a> article, or look at any introductory textbook to Software Engineering/Software Architecture.<br />
<br />
We will waste no time introducing what MVVM is and simply dive into the details (with a short refresher).<br />
<br />
<b>What is the Problem we are Solving?</b><br />
<b><br /></b>
I am not a fan of learning or increasing complexity of an application just for the sake of software purity or self-edification. Hopefully you are not either. Therefore, the question must be asked, what problems does MVVM actually solve? What is it's use? Is it worth the additional complexity? In corporate/Software Architecture parlance, what is the "use case" that MVVM applies to?<br />
<br />
I am assuming we are solving a business problem. Business problems have a specific purpose, use and scope. In particular, we are not looking to reinvent the wheel and demonstrate technology or do technology for technology's sake (although valid reasons, we aren't talking about the technical merits here). What we are wondering is how we can solve business problems in a fast enough, maintainable enough and quick enough way that the business continues to be viable, extensible and expandable.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgn3xGHeG7qcCpOpYyQX0ONaj5juBoEpvxrvFRfvvLLfW9UqNqCgyoG_wePr8UmIYTETrlJkA9Oq2Sjxu2TPdIgV6eK_dEdD9oaw30B9Uu6Eret7gfeKs6Qq-eUd4QQEQhwmEBj3d2f11dt/s1600/wordcloud.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgn3xGHeG7qcCpOpYyQX0ONaj5juBoEpvxrvFRfvvLLfW9UqNqCgyoG_wePr8UmIYTETrlJkA9Oq2Sjxu2TPdIgV6eK_dEdD9oaw30B9Uu6Eret7gfeKs6Qq-eUd4QQEQhwmEBj3d2f11dt/s640/wordcloud.png" width="640" /></a></div>
<br />
(wordclouds.com of <a href="https://en.wikipedia.org/wiki/Business">Business</a>)<br />
<br />
So, what types of problems are we trying to solve?<br />
<br />
1. Business problems are data problems. Data is the business, moving data from point A to point B. However, the days of simple data-entry are gone. Dumping data from the database onto the screen and saving it is a trivial, simple task. In order to create a product of any value, the <b>relationships between data points</b> must be maintained, because without relationships there's no meaning for the data.<br />
<br />
2. Increasingly, <b>data visualization</b> is just as important as data processing. Without reports, without diagrams, without charts, without Key-Performance-Indicators, data entry is useless. This is beyond the scope of this series of blog posts, but is obviously the next step after mastering data integrity.<br />
<br />
3. More increasingly, the interface has to be attractive enough to provide a <b>superior user experience</b>. Business users are now computer experts, unlike years or decades ago and expect the same experience from top-notch consumer software in their business products. Things like milliseconds of delay, buggy interactions and non-standard interactions are unacceptable. In addition, this is not the heyday of the Internet -- the market is now mature, and mature markets demand superior customer experience as the key (and sometimes only) differentiator. This is again, beyond the scope of this series of blog posts.<br />
<br />
We will focus on problem 1, non-trivial relationships between data points. In particular, we will focus on how to represent data points with multiple relationships between data points and a <b>hierarchical relationship</b> (since most business problems are hierarchical) and how to create and architect software which takes this reality into account.<br />
<br />
<b>What does all that mean for the Developer?</b><br />
<b><br /></b>
In general, what that means for the bog-standard Software Developer in his day-to-day tasks is three things.<br />
<br />
1. The primary task of a backend Software Developer (and increasingly frontend developers as well) is to create tools, or user-interfaces. This immediately directs us to some sort of design pattern (after all, UI problems are a solved problem) and immediately to MV***, *** being the question mark. The model is a given, since we are solving business problems and all business problems are modelled. The view is a given, unless we are creating backend data processing software with no user interface.<br />
<br />
2. Unless you are lucky enough to work somewhere you can do whatever you want, you are under the gun. Particularly for a business, time is money and time is lost market-share or lost revenue. Therefore, you can't take forever reinventing the wheel from the ground up. Luckily, a lot MV*** frameworks already exist.<br />
<br />
<a href="https://nirajrules.wordpress.com/2009/07/18/mvc-vs-mvp-vs-mvvm/">This is a good introduction</a> to the differences between MVC, MVVM and MVP. In particular, we will select MVVM, because the business problems we will try to solve are non-trivial (advanced relationships between data points).<br />
<br />
<b>Technology</b><br />
<b><br /></b>
We will use technology meant to solve a business problem. This immediately leads us to -- you guessed it -- Microsoft. However, the solution we will select is KnockoutJS, the Microsoft-recommended way to accomplish advanced UI binding. However, the concepts and code samples should be clear enough to port to any framework or programming language.<br />
<br />
The next blog post will start with a practical example of MVVM (the trivial/kitchen sink example) then discuss the problems developers immediately face when trying to implement realistic business solutions.<br />
<br />
(Link To Be Released)BrianLimhttp://www.blogger.com/profile/07107383864607795783noreply@blogger.com14tag:blogger.com,1999:blog-2064461998620158755.post-24555494276954451422016-01-03T05:49:00.000-08:002016-01-03T06:00:16.914-08:00JavaScript - Converting JSON to XMLThis post discusses how to convert between a JavaScript object, XML and JSON (not the same as a <a href="http://stackoverflow.com/a/8294127">JavaScript object</a>).<br />
<div>
<br /></div>
<div>
(Un)Surprisingly there is no native function to do this. There's various implementations of conversion like <a href="https://developer.mozilla.org/en-US/docs/JXON">JXON </a>or <a href="http://api.jquery.com/jQuery.parseXML/">jQuery's parseXML</a>, but no official standard. So chances are every developer will have to work with converting between these data interchange formats (and native JavaScript objects) depending on the use case or circumstances.</div>
<div>
<br /></div>
<div>
JavaScript Object to JSON is the most straightforward. Just use the browser's native JSON.stringify (or use a <a href="http://bestiejs.github.io/json3/">shim </a>if you need to support older browsers). Or is it? Consider the following case:</div>
<div>
<br /></div>
<div>
var obj = ["lightsaber", "blaster", "vibroblade"]</div>
<div>
<br /></div>
<div>
All of these are Star Wars weapons. But this data structure has no idea what's inside it. It doesn't know that these are weapons, or star wars weapons.</div>
<div>
<br /></div>
<div>
So the conversion then, is not trivial to XML. So care must be taken when converting between a JavaScript object and JSON, to send the <b>metadata </b>of the JavaScript object along.</div>
<div>
<br /></div>
<div>
The notation I've seen most used is the $metadata attribute. It has the added advantage of $ not being a valid XML tag character, which means you won't accidently create a node with the metadata.</div>
<div>
<br /></div>
<div>
So instead, obj becomes this</div>
<div>
<br /></div>
<div>
var obj = {</div>
<div>
$weapon: [</div>
<div>
"lightsaber",</div>
<div>
"blaster",</div>
<div>
"vibroblade"</div>
<div>
]</div>
<div>
}</div>
<div>
<br /></div>
<div>
The following is a sample implementation of JavaScript object to JSON<br />
<br />
<script src="https://gist.github.com/bhldev/d56799f46c3084e06093.js"></script>
<br />
<br />
And another sample implementation of JSON to XML<br /><br />
<script src="https://gist.github.com/bhldev/d4b4e09370010fbad968.js"></script>
<br />
<br />
Hope this gives someone ideas, or helps someone</div>BrianLimhttp://www.blogger.com/profile/07107383864607795783noreply@blogger.com4tag:blogger.com,1999:blog-2064461998620158755.post-46099555377469926372015-11-11T03:05:00.003-08:002015-11-11T03:05:24.736-08:00Google Hangout Dial ExtensionHi,<br />
<br />
Just wanted to add a quick note to anyone having trouble dialing an extension with Google Hangout / Google Voice<br />
<br />
You need a working microphone plugged in and active<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhOjrifOGCthe-pGyKyEWGz39F4WAEwJo2ulQ_DyHqs2-fwungFk-JrH8rGiOMbh9MtVZ_AQPFRbz2F5jmG59bhQNQ3CrjATbLlm0KRz1TZc0kclHXf-DCSqWThtTJ4J5hXB33HToQnenDL/s1600/microphone.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhOjrifOGCthe-pGyKyEWGz39F4WAEwJo2ulQ_DyHqs2-fwungFk-JrH8rGiOMbh9MtVZ_AQPFRbz2F5jmG59bhQNQ3CrjATbLlm0KRz1TZc0kclHXf-DCSqWThtTJ4J5hXB33HToQnenDL/s320/microphone.png" width="289" /></a></div>
<br />
Without it, you won't be able to dial extension<br />
<br />
Note that the actual dial tone doesn't have to exist. For example, when dialing an extension 3000 after dialing the number 555-555-5555, you don't hear the usual dialtone or extension sounds when dialing 3000. What you will hear is a series of clicks, but the clicks will work if there's a microphone plugged in.<br />
<br />
Hope this helps someone<br />
<br />
~ BBrianLimhttp://www.blogger.com/profile/07107383864607795783noreply@blogger.com5tag:blogger.com,1999:blog-2064461998620158755.post-37614548721161209072015-08-31T15:02:00.003-07:002015-08-31T15:03:21.017-07:00ASP.NET MVC HttpContext.Current.Server.MapPath null for WCF WebserviceHi,<br />
<br />
Just solved a problem at work:<br />
<br />
If <span class="typ" style="background-color: #eeeeee; border: 0px; color: #2b91af; font-family: Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, sans-serif; font-size: 13px; margin: 0px; padding: 0px; white-space: inherit;">HttpContext</span><span class="pun" style="background-color: #eeeeee; border: 0px; font-family: Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, sans-serif; font-size: 13px; margin: 0px; padding: 0px; white-space: inherit;">.</span><span class="typ" style="background-color: #eeeeee; border: 0px; color: #2b91af; font-family: Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, sans-serif; font-size: 13px; margin: 0px; padding: 0px; white-space: inherit;">Current</span><span class="pun" style="background-color: #eeeeee; border: 0px; font-family: Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, sans-serif; font-size: 13px; margin: 0px; padding: 0px; white-space: inherit;">.</span><span class="typ" style="background-color: #eeeeee; border: 0px; color: #2b91af; font-family: Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, sans-serif; font-size: 13px; margin: 0px; padding: 0px; white-space: inherit;">Server</span><span class="pun" style="background-color: #eeeeee; border: 0px; font-family: Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, sans-serif; font-size: 13px; margin: 0px; padding: 0px; white-space: inherit;">.</span><span class="typ" style="background-color: #eeeeee; border: 0px; color: #2b91af; font-family: Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, sans-serif; font-size: 13px; margin: 0px; padding: 0px; white-space: inherit;">MapPath</span> is giving you null or an exception or not working, there are several possibilities. One of them is you didn't enable asp.net compatibility mode.<br />
<br />
<a href="https://msdn.microsoft.com/en-us/library/aa702682(v=vs.110).aspx">https://msdn.microsoft.com/en-us/library/aa702682(v=vs.110).aspx</a><br />
<br />
Better off to migrate to another way of finding the server path than depending on HttpContext though,<br />
<br />
<a href="http://stackoverflow.com/a/6861451">http://stackoverflow.com/a/6861451</a><br />
<br />
HttpContext is bad to depend on, when dealing with WCF or non-MVC applications (there isn't always a context.)<br />
<br />
Hope this helps someone<br />
<br />
~ BBrianLimhttp://www.blogger.com/profile/07107383864607795783noreply@blogger.com5tag:blogger.com,1999:blog-2064461998620158755.post-49242179262199568612015-08-08T14:32:00.000-07:002015-08-08T14:32:50.783-07:00jQuery UI Dialog Create Custom Close ButtonHi,<br />
<br />
Just wanted to share how to create a custom close button with jQuery UI's Dialog Widget<br />
<br />
Create a dialog this way<br />
<br />
<script src="https://gist.github.com/bhldev/e490a926e159b2ae6b84.js"></script><br />
<br />
// TODO store modalDialog somewhere so you can call modalDialog.dialog('open'); and modalDialog.dialog('close'); when required<br />
<br />
I suggest creating a wrapper JavaScript class, to store the dialogs by some id. That way you can retrieve dialogs already created. Some basic functions like wrapper.closeDialog(id), wrapper,createDialog(id) and so on will go a long way.<br />
<br />
The key is, when using the .dialog function, jQuery UI wraps the dialog in its own div (the $(this).parent().find(".ui-dialog-titlebar") line).<br />
<br />
Hope this helps someone.BrianLimhttp://www.blogger.com/profile/07107383864607795783noreply@blogger.com6tag:blogger.com,1999:blog-2064461998620158755.post-75366392364229885932015-07-13T15:27:00.001-07:002015-07-13T15:27:23.008-07:00ASP.NET MVC Call Controller with jQuery $.ajax and Return PartialViewResultHi,<br />
<br />
Didn't find a one-stop answer to this question, so here it is:<br />
<br />
<i>"How do I POST JSON to an ASP.NET MVC controller?"</i><br />
<i><br /></i>
It's actually quite simple. Follow the following steps.<br />
<br />
1. Create a model to represent the data structure you want to POST<br />
<br />
<script src="https://gist.github.com/bhldev/eac727e65feb2a96d000.js"></script>
<br />
<br />
2. Create a controller method to represent the endpoint you want to contact<br />
<br />
<script src="https://gist.github.com/bhldev/8b5fa42129d55a073f5e.js"></script>
<br />
<br />
3. Create the following jQuery call to make an AJAX call from the frontend to the backend<br />
<br />
<script src="https://gist.github.com/bhldev/3677fec5d16765557147.js"></script>
<br />
<br />
You can return a PartialViewResult from the controller, and as long as the jQuery AJAX call expects html it will be done.
<br />
<br />
Hope this helps someone.BrianLimhttp://www.blogger.com/profile/07107383864607795783noreply@blogger.com6tag:blogger.com,1999:blog-2064461998620158755.post-27639361598633804922015-06-30T06:26:00.002-07:002015-06-30T06:56:13.602-07:00How to call a .NET SOAP or JSON WCF Webservice with jQueryHi,<br />
<br />
This is an article about how to call .NET SOAP Webservices from an HTML page. However it should be useful for anyone wanting to call any webservice from a webpage, as it outlines the technical considerations and plumbing you need to keep in mind.<br />
<br />
There are four considerations to bear in mind<br />
<br />
1. <b>The type of data sent to the server and the type of data returned from the server</b>. Consider the following,<br />
<br />
<script src="https://gist.github.com/bhldev/312022ccd42f827fe39f.js"></script><br />
<br />
The type of data sent to the server is XML. The type of data retrieved from the server is JSON. However, you will often want to accept / retrieve the other. Keep this in mind for the next step.<br />
<br />
As well, if you receive XML or JSON, you will often need to deserialize into a string. Either use JavaScript's <a href="https://developer.mozilla.org/en/docs/XMLSerializer">XMLSerializer </a>or use <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse">JSON.parse</a> to get the data you want in string format. The same goes for data you send to the server (it must be JSON.stringify or serialized into XML before sending it, not just a JavaScript string)<br />
<br />
2. <b>The jQuery AJAX call</b> itself. For example consider the following<br />
<script src="https://gist.github.com/anonymous/23ce8f174c071f41330f.js"></script><br />
Match the content type parameter to the required input data, either 'application/xml' or 'application/json'. Note that trying 'application/soap+xml' or other unexpected content types will generate a server error in response.<br />
<br />
3. <b>CORS.</b> If the HTML page is hosted on a different domain than the webservice itself (might be true in Enterprise where the webservice is on a different server than the web server) then CORS applies. Note that when using jQuery with methods other than GET, jQuery will send a preflight OPTIONS request so the server will need to accept OPTIONS and GET and POST, in addition to the appropriate CORS headers on the server side response and the HTML tags. So if you cannot control the server-side headers on your webserver, you will need a different application architecture. Perhaps call the webservice from the backend C# instead of trying to call it from the HTML.<br />
<br />
4. <b>The SOAP envelope.</b> You've got three choices here<br />
<br />
<ul>
<li>Retrieve the SOAP string from some external source, like a database or a text file. Every time the webservices are updated, you will have to update the external source.</li>
<li>Construct the SOAP envelope yourself with a JavaScript client. This is the approach I do not recommend, since parsing a WSDL and associated XSDs is not trivial.</li>
<li>Have a project like <a href="http://cxf.apache.org/docs/javascript.html">Apache CXF</a> generate the SOAP client for you. This defeats the purpose of this article, since Apache CXF is a JavaScript client already. But this is an option, especially for Java backends or Enterprise.</li>
</ul>
<div>
In order to avoid these issues, have the webservice allow JSON if possible. If the architecture of the software is to allow access to the webservices from the client side (HTML pages) then the webservice should speak the lingua franca of the web (JSON) or else there's no point even exposing the webservice to the client side.</div>
<div>
<br /></div>
<div>
Make sure to know what type of binding the server allows, either wsHTTPBinding or basicHTTPBinding. This means a different SOAP Envelope. You may have to strip the envelope from the XML before sending it, if WCF expects only the inner request XML and not the SOAP envelope.</div>
<div>
<br /></div>
<div>
I hope this helps someone build their dream application. Thanks.</div>BrianLimhttp://www.blogger.com/profile/07107383864607795783noreply@blogger.com2tag:blogger.com,1999:blog-2064461998620158755.post-18832376173714490962015-06-14T18:42:00.003-07:002015-06-14T19:22:44.412-07:00Cordova Command Does Nothing on Ubuntu 14.04 LTSHi,<br />
<br />
If you install Apache Cordova and find running the Cordova command does nothing and rule out all the usual suspects (not installing Ant, not installing Java, clearing the npm cache etc.) the problem is that the cordova script references node instead of the nodejs command. Changing it doesn't help unless you change all the scripts.<br />
<br />
Run which nodejs and which node and you will see the problem<br />
<br />
See this post for a description:<br />
<br />
http://stackoverflow.com/questions/22457834/what-is-the-difference-between-node-vs-nodejs-command-in-terminal<br />
<br />
What needs to be done is to symlink the /usr/sbin/node to the /usr/bin/nodejs file . See the following for a description of the problem.<br />
<br />
http://stackoverflow.com/questions/22457834/what-is-the-difference-between-node-vs-nodejs-command-in-terminal<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjkCg_YqWK3197GkjVuiVoj1lGBzNZuG3SIZALEHwWWDXnzOorz95-hRorIAXCZieYI90yhi4XX0UTnInp-7QBY3G2UZIah9qaEBj1A-PXQoaohHLZuFGKFPQFF-9axiqqy1t2PhhnQCRD3/s1600/Cordova+Script.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="265" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjkCg_YqWK3197GkjVuiVoj1lGBzNZuG3SIZALEHwWWDXnzOorz95-hRorIAXCZieYI90yhi4XX0UTnInp-7QBY3G2UZIah9qaEBj1A-PXQoaohHLZuFGKFPQFF-9axiqqy1t2PhhnQCRD3/s400/Cordova+Script.PNG" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
Hope this helps someone</div>
<br />BrianLimhttp://www.blogger.com/profile/07107383864607795783noreply@blogger.com4tag:blogger.com,1999:blog-2064461998620158755.post-14529937158688600732015-05-31T02:53:00.001-07:002015-05-31T02:53:28.408-07:00Love the Stateless Nature of the Web and Be HappyHi,<br />
<i><br /></i>
<i>(This is a technical article about the history of web programming. It may prove interesting to a non-programmer, however.)</i><br />
<br />
The stateless nature of the web is the key to happiness as a developer.<br />
<br />
By stateless, I mean that one web page without effort on the part of the programmer (or effort on the part of the framework the programmer is using), does not remember or recall anything when you go to the next web page.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhyNFbJPH_C3QK31Bm9t9XXtakcvMPvYshBrt2r8K2SYq0MDNOBNERv-BciuRT_uuR97yqvQdeF_cNLwt6376dr9YZBWOuNjOHNe1Tb6zcBYHuhXUi5wipcBXSxGXlBLJXDcWhB9v1ELB94/s1600/HTTP+Pocket+Reference.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhyNFbJPH_C3QK31Bm9t9XXtakcvMPvYshBrt2r8K2SYq0MDNOBNERv-BciuRT_uuR97yqvQdeF_cNLwt6376dr9YZBWOuNjOHNe1Tb6zcBYHuhXUi5wipcBXSxGXlBLJXDcWhB9v1ELB94/s320/HTTP+Pocket+Reference.jpg" width="197" /></a></div>
<br />
<br />
<a href="http://www.amazon.com/HTTP-Pocket-Reference-Hypertext-Transfer/dp/1565928628">(HTTP is the foundation for web programming, not Framework A or Language B or Abstraction C)</a><br />
<br />
Most programmers did not become programmers to do "plumbing" or "wiring". Most programmers have passions like solving deep technical problems or algorithms or just getting things to work. Most problems do not like solving trivial issues. "Hooking things up" for example, moving data from point A to point B is not why most programmers got degrees or experience or spend their hours late hacking away. But it is exactly the thing to embrace, to master and to be happy with for professional success and personal satisfaction.<br />
<br />
And indeed, frameworks and platforms attempted to abstract away the plumbing and mundane tasks and impose a stateful model to increase programmer productivity and still do. For example, the ASP.NET Webforms technology abstracted away the nature of the web. It continued and continued and continued until Microsoft saw the light and created ASP.NET MVC. MVC isn't new pattern. It's been around for decades (or so I've been told). But Microsoft abandoned its page lifecycle model in favor for the loosely coupled MVC model because they finally saw the light.<br />
<br />
Moving data from point A to point B is exactly the key to happiness as a (web) developer in every way. Accept the stateless nature of the web as the fundamental problem, and all the fun and wonderful things happen to your life and career.<br />
<br />
Those who embraced the stateless nature of the web, and did so from top to bottom, faced success in the past fifteen years. Those who ignored the stateless web, suffered, unless they were lucky. One obvious example is MySpace versus Facebook. ASP.NET Webforms is great, and was good for its time. It allowed COBOL or C programmers to transition to web programming with very little effort or investment of time upfront to learn but more importantly accept the nature of the Internet.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiA3UPQPSNtK3NOxV87EO3OhQFYnvqgISBIwVxjjtOvY4OQlbTF14I6YcEhcnKr5CsJmsk6uIj1eH05rhKI5DQO-if5Ql54Xg3C2BPFX4rZFvFmPNnfvwBVLJORJiY94GOoQYIFp1l-U3Un/s1600/Google+Trends.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="167" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiA3UPQPSNtK3NOxV87EO3OhQFYnvqgISBIwVxjjtOvY4OQlbTF14I6YcEhcnKr5CsJmsk6uIj1eH05rhKI5DQO-if5Ql54Xg3C2BPFX4rZFvFmPNnfvwBVLJORJiY94GOoQYIFp1l-U3Un/s400/Google+Trends.PNG" width="400" /></a></div>
<br />
<br />
<a href="http://www.google.com/trends/explore#q=myspace,facebook">(Courtesy of Google Trends)</a><br />
<br />
But we all know what happened to <a href="http://www.forbes.com/sites/quora/2012/09/13/did-myspaces-demise-have-anything-to-do-with-bad-growth-hacking/">MySpace</a>. This is not a knock on Microsoft at all. I happen to like and love Microsoft, and like and love Linux as well. But, eventually Microsoft arrived to the same conclusion that everyone else did; that the stateless nature of the web can only be avoided so long until you pay the price.<br />
<br />
No matter what frameworks come and go, no matter what technology comes and goes, the web will always be stateless. You've got a few choices.<br />
<br />
<ul>
<li>Fight this. Draw a line and refuse to accept this, much less like it. Ignore how the Web works and the Internet works. Use frameworks, use abstractions, use layers, use everything and anything to ignore the fact that you need data to move from point A to point B but more importantly understand how that works. One day, the world will catch up (if it hasn't already). Out of all the options, this is the only one which ultimately leads to failure 100%. Better to get another career.</li>
<li>Fight this, but in an old fashioned way. This means mingling the client-side and server-side together to the point moving data from point A to point B is trivial. For example, avoiding strict <a href="https://theantlrguy.atlassian.net/wiki/display/ST4/Motivation+and+philosophy">Model-View</a> separation and rendering everything all at once so everything is accessible to you all at once. An example of this is using technology which mingles the model and view, for example PHP, or the old ASP.NET Webforms. If you can handle spaghetti code or messy code, this is the way for you.</li>
<li>Fight this, but in a modern way (2015). This means using modern or cutting edge techniques like client-side JavaScript applications (so-called single page JavaScript applications). Bring order to chaos with frameworks like Backbone.js to keep data squarely on the client side except when absolutely necessary. But eventually, you will need to move data to the server. The problem is just being pushed off until later.</li>
<li>Accept this. Work the way the Web was intended. This can take several forms.</li>
<ul>
<li>Create a mini-framework to move data from point A to point B. This does not have to start from scratch. For example, you could make AJAX requests with jQuery instead of raw JavaScript (and should). The key point is to not depend on state when moving between webpages. The disadvantage of this approach is </li>
<li>Use someone else's gargantuan framework to move data from point A to point B. Use only the features you want, when you want them, and keep an eye on performance. However, the risk is one day the framework is obsolete, or the framework's designers or implementers don't have the same vision for you or your best interests at heart. </li>
<li>Work at a very fundamental level right with bare HTTP. Become a master at DOM manipulation, become a master at JavaScript and learn the cross-browser differences (or at the least have caniuse.com handy). Working at this level, you will never become dated or obsolete. The problem with working at this level is speed. Can you create deliverables as fast as the guy who uses Framework of the Day to crap things out faster than you can blink? </li>
</ul>
</ul>
<div>
So, there are many choices available for those who want to develop for the web. Which one will you choose? Which one will make you happy? That is a question only you can decide.</div>
<br /><br />
<br />
<div>
<br /></div>
<br />
<br />BrianLimhttp://www.blogger.com/profile/07107383864607795783noreply@blogger.com6tag:blogger.com,1999:blog-2064461998620158755.post-50546974583546791502015-05-24T14:16:00.001-07:002015-05-24T14:16:44.535-07:00MySQL Stored Procedure Not Using IN variableHi,<br />
<br />
I came across a trivial problem in MySQL today. I hope this helps someone (should apply to Oracle and MS SQL as well).<br />
<br />
When defining a MySQL stored procedure and executing it, instead of the correct result set I got all rows of the table.<br />
<br />
DELIMITER //<br />
CREATE PROCEDURE testproc<br />
(<br />
IN id INT<br />
)<br />
BEGIN<br />
SELECT *<br />
FROM `Test`<br />
WHERE `ID` = id;<br />
END //<br />
DELIMITER ;<br />
<br />
On closer inspection in phpMyAdmin and fooling around with the definition of the stored procedure, I discovered the issue. The column is called id, and of course id is always equal to id. It doesn't resolve to the IN variable id.<br />
<br />
On further thought, this makes sense. Scope should be the smallest possible, and if one defines an IN or OUT or INOUT variable the same as a column name, there be dragons.<br />
<br />
See the following for more information:<br />
https://dev.mysql.com/doc/refman/5.7/en/local-variable-scope.html (local variables)<br />
https://dev.mysql.com/doc/refman/5.1/en/set-statement.html (session variables)<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhhNEvNFnO6dQkB7YtqatYKzqY8oLG1CY5-k2yK_7BzKNt1wOBqmmE32yom-WIzS0_bQftRaA3lF86DQNeFbVS-21-RlLaQwTIqQUDn6fg2aWka2Ep9_9dUGNViPB0VTBOdG-Fk04B-dHNP/s1600/MySQL+Stored+Procedure+Anomaly.PNG" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="372" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhhNEvNFnO6dQkB7YtqatYKzqY8oLG1CY5-k2yK_7BzKNt1wOBqmmE32yom-WIzS0_bQftRaA3lF86DQNeFbVS-21-RlLaQwTIqQUDn6fg2aWka2Ep9_9dUGNViPB0VTBOdG-Fk04B-dHNP/s400/MySQL+Stored+Procedure+Anomaly.PNG" width="400" /></a></div>
<br />BrianLimhttp://www.blogger.com/profile/07107383864607795783noreply@blogger.com2tag:blogger.com,1999:blog-2064461998620158755.post-49348844591855677742015-05-19T04:19:00.001-07:002015-05-19T04:19:31.140-07:00PyCharm Interactive Command Line / DebuggerHi,<br />
<br />
Didn't find this on Google so here it is.<br />
<br />
If you are looking for the Interactive Command Prompt when you are debugging for the PyCharm Python IDE Community Edition (the open source free version) go to Tools -> Open Debug Command Line. Somewhat hidden since you would expect it to be under the Debug menu.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEicEFB8mgPMj02LAIc9-Eo4aDsTHt9eWNBgDyKUwGrvxCbi3zinCRjSJZy1OUeREAMy7JNnT056Uuruehg2jreaFjJkCsOiyAhk_B6uNTy2mYxIjLiky-79__Jqq940CQgEIxpxeG2OioUj/s1600/PyCharm+Debugger.PNG" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="255" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEicEFB8mgPMj02LAIc9-Eo4aDsTHt9eWNBgDyKUwGrvxCbi3zinCRjSJZy1OUeREAMy7JNnT056Uuruehg2jreaFjJkCsOiyAhk_B6uNTy2mYxIjLiky-79__Jqq940CQgEIxpxeG2OioUj/s320/PyCharm+Debugger.PNG" width="320" /></a></div>
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
Other answers I found told me to click on a non-existent icon on the Debug Toolbar, which either doesn't exist in the Community Edition or was moved / removed.<br />
<br />
Hope this helps someone.BrianLimhttp://www.blogger.com/profile/07107383864607795783noreply@blogger.com3tag:blogger.com,1999:blog-2064461998620158755.post-56220227798595830772015-05-16T14:29:00.003-07:002015-05-19T04:13:16.327-07:00jQuery AJAX 500 Error with ASP.NET MVCHi,<br />
<br />
Just wanted to drop a quick note for anyone using jQuery with ASP.NET MVC and experiencing 500 Internal Server errors when debugging with the browser's network monitoring feature.<br />
<br />
In order to send a proper AJAX call with jQuery's $.ajax function, you must use JSON.stringify . Suppose you are sending one field to the MVC backend.<br />
<br />
var data = $('#inputBox').val();<br />
$.ajax({<br />
method: "POST",<br />
url: "@Url.Action("ActionName", "ControllerName")",<br />
data: JSON.stringify({"data" : data }),<br />
success: function (data) {<br />
if (data.valid)<br />
{<br />
alert('Success:' + data.message); <br />
}<br />
}<br />
});<br />
<br />
In the ControllerName controller,<br />
<br />
public JsonResult ActionName(string data) {<br />
// do something with data<br />
return Json(new { valid = true, message = "Success" });<br />
}<br />
<br />
Basically, if you receive a 500 error from the server but are never able to hit a break point in Visual Studio, look at the way the data is sent and the way the data is received. More likely than not there is an error with the data or dataType or mimeType parameters (cross-domain requests are a different beast too).<br />
<br />
The key difference is the difference between a JSON string and a JavaScript object. JSON strings aren't JavaScript objects just because they look like JavaScript objects; they have a stricter syntax. It is not a limitation or error of ASP.NET MVC or the backend if it refuses to parse incorrectly formed JSON.<br />
<br />
Thanks for visiting and comments are welcome.BrianLimhttp://www.blogger.com/profile/07107383864607795783noreply@blogger.com1tag:blogger.com,1999:blog-2064461998620158755.post-42696257027758389402015-04-18T11:53:00.000-07:002015-04-18T11:53:09.445-07:00Missing 64-bit from Oracle Virtualbox in Microsoft WindowsHi,<br />
<br />
Just wanted to make a note for people,<br />
<br />
If you find you can't create a 64-bit Virtual Machine with Oracle Virtualbox, disable Windows Hyper-V through Windows Features.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj46gkT83ASUuPeKVo0iUWIBoQHrInIYV6nD2AvWXo98B95604WmE4Se6Atj2Qb_gQsSfbm8GYb_mMocrOBmdNVankoITey9CUFA7QULKJ1mYq8n-aTeclFn3qe4G2e13F4bvIcJH3vG6s8/s1600/Operating+System.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj46gkT83ASUuPeKVo0iUWIBoQHrInIYV6nD2AvWXo98B95604WmE4Se6Atj2Qb_gQsSfbm8GYb_mMocrOBmdNVankoITey9CUFA7QULKJ1mYq8n-aTeclFn3qe4G2e13F4bvIcJH3vG6s8/s1600/Operating+System.PNG" height="250" width="320" /></a></div>
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgqAEJs0S97QVPpPKctHVArKKRqyTIohSUQGyI_SWGVCGLbEzRv3IepY8m2139yOuMt70S5vYiuKsmhQpXcDLmNFrDn7neqgD0DQwzJjMrzSwl4zyaq4GoolHJQaqPAIVISF9N3jQb16LCd/s1600/Windows+Features.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgqAEJs0S97QVPpPKctHVArKKRqyTIohSUQGyI_SWGVCGLbEzRv3IepY8m2139yOuMt70S5vYiuKsmhQpXcDLmNFrDn7neqgD0DQwzJjMrzSwl4zyaq4GoolHJQaqPAIVISF9N3jQb16LCd/s1600/Windows+Features.PNG" height="275" width="320" /></a></div>
<br />
<br />
Another requirement is to enable VT-x (Intel) or AMD-V (AMD) in the computer's BIOS. You might have to hard reboot after.<br />
<br />
Hope this helps someone.BrianLimhttp://www.blogger.com/profile/07107383864607795783noreply@blogger.com3tag:blogger.com,1999:blog-2064461998620158755.post-52888974883490477732014-06-05T17:17:00.001-07:002014-06-05T17:33:02.274-07:00Getting Started with Cocos2d-JS 3.0 Part 1 - First Sprite<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<h4>
<b>Prerequisites</b></h4>
<ul>
<li>Knowledge of how to download, unzip and install software packages and software on your computer and how to change environment variables for your operating system of choice (Linux / Windows)</li>
<li>Basic knowledge of JavaScript (should know what closures are, what a callback function is, etc.) in other words not a complete beginner. If you need a refresher on JavaScript I suggest <a href="http://javascript.info/">this tutorial</a>.</li>
<li>Some experience using Eclipse-like IDEs would be helpful (although not necessary).<b></b> If you can step through a debugger you will be fine.</li>
</ul>
<h2>
<b><b>Introduction</b></b></h2>
<a href="http://www.cocos2d-x.org/wiki/Cocos2d-JS">Cocos2d-JS 3.0</a> is an html5 framework derived from cocos2d-x. It was recommended to me by a coworker as a JavaScript framework. This will be a tutorial on how to get started with Cocos2d-JS with the most basic type of rendering -- a <a href="https://www.google.com/search?tbm=isch&q=9+slice+sprite">9-slice sprite</a> from the very beginning (downloading, installing, configuration and code sample). Proper scaling is crucial to resolution independent and mobile development. Later tutorials will cover event handling, physics and more advanced topics. <br />
<br />
Because installation, configuration and setup is often the first major hurdle, much of Part 1 will be spent on creating your environment (stick with it, trust me it pays off) or at least pointing you in the right direction.<br />
<br />
As of June 1st, 2014 Cocos2d-JS is still in beta stage so not ready for production. But it is looking very promising and is just a few weeks/months away from production (already been through alpha). Since cocos2d-JS 2.0 was rock solid for years and the team appears dedicated I have no reason to doubt 3.0 will eventually be released production ready.<br />
<br />
This tutorial will assume you have an Ubuntu-like system. If you are familiar with unzipping and changing environment variables on Windows, you should also be able to follow along since the code will be compatible. <b></b><br />
<b></b><br />
<h4>
<b>Advantages of Cocos2d-JS 3.0 (as of June 1st, 2014) or Why Use Cocos2d-JS?</b></h4>
<ul>
<li>HTML5 compatible so mobile friendly with wrappers like <a href="https://crosswalk-project.org/">Intel Crosswalk</a>
(Android) or <a href="http://impactjs.com/ejecta">Ejecta</a> (iOS). Also has JSB (JavaScript bindings) to compile
with cocos2d-x to native, though the JSBs lag behind the main trunk for
now.</li>
<li>JavaScript for fast development (debatable)</li>
<li>MIT License</li>
</ul>
<h4>
<b>Disadvantages (few, but worth mentioning) or Why Not to Use Cocos2d-JS</b></h4>
<ul>
<li>A <a href="http://www.cocos2d-x.org/forums/19/topics/45945?r=46184#message-46184">little more difficult to use</a> compared to other JavaScript frameworks. This is being resolved by the cocos2d-JS team (they acknowledge this).</li>
<li>Cutting edge (as of June 1st, 2014) so not ready for production. Not a big deal since it will be ready eventually.</li>
<li>Not too many tutorials or examples (one of the reasons I'm writing this, plus will get solved eventually when the framework is out of beta).</li>
<li>JavaScript (for people who hate / can't stand JavaScript) </li>
</ul>
The goals of this tutorial will be to setup your environment and create
reusable sample code for a <a href="https://www.google.com/search?tbm=isch&q=9+slice+sprite">9-slice sprite</a>. A 9-slice sprite is a sprite
which scales properly on all devices without distorting the image,
crucial for mobile friendly games and apps.<br />
<br />
<h3>
<b>Step 1 - Downloading Cocos2d-JS</b></h3>
<br />
<a href="http://www.cocos2d-x.org/download">Download the Cocos2d-JS v3.0 beta</a>. By the time you read this, cocos2d-js may be out of beta.<br />
<br />
<br />
<script src="http://pastebin.com/embed_js.php?i=hiQpd7WV"></script>
<br />
The setup will ask you a few questions, mainly about Android NDK and SDK locations and ant locations. You should have ANT properly installed and setup; if not, run sudo apt-get install ant and rerun the cocos setup. We will be building for web only, so we will not bother with Android for now.<br />
<br />
If you are having trouble setting the environment variables or downloading the prerequisites (Python 2.7.6 32-bit, not Python 3, Ant) see the section <a href="http://cocos2d-x.org/docs/manual/framework/html5/v2/cocos-console/en"><b>SETUP</b></a> here. Unfortunately installing Python, Ant and so on is outside the scope of this tutorial; however your distro should have these preinstalled. If this is a problem for some people I can write another article about how to install packages in Ubuntu.<br />
<b></b><br />
<h3>
</h3>
<h3>
<b>Step 2 - Downloading Aptana Studio</b></h3>
<br />
<script src="http://pastebin.com/embed_js.php?i=e4SfxGnX"></script>
<a href="http://www.aptana.com/products/studio3/download">Download the Aptana Studio standalone version.</a> Unfortunately Aptana Studio does not support OpenJDK (the default Java installation that comes with Ubuntu) so you will need to switch to Oracle JDK to use it. Switching from Open JDK to Oracle JDK is outside the scope of this tutorial; see <a href="http://www.wikihow.com/Install-Oracle-Java-on-Ubuntu-Linux">this link</a> for a comprehensive tutorial. If you are using Windows, Aptana Studio comes with a prepackaged JDK.<br />
<br />
If you don't want to bother with the switch, or you hate Eclipse-style IDEs in general you can use <a href="http://www.jetbrains.com/webstorm/">Jetbrains Webstorm</a>. However Jetbrains Webstorm is non-free. However Webstorm has much smarter autocompletion and if you are doing a serious project I would consider buying a license.<br />
<b><br /></b><u>
Note about Aptana Studio Bug #1</u><b>: </b>I encountered a bug when using Aptana Studio with Linux Mint (an Ubuntu variant) and found the <a href="http://www.webupd8.org/2014/05/fix-aptana-studio-3-crashing-in-ubuntu.html">solution here</a>. It involves the default web browser and Firefox.<br />
<br />
<u>Note about Aptana Studio Bug #2</u>: I <a href="http://stackoverflow.com/questions/11532388/socket-connection-error-when-debugging-php-js-on-aptana-3">encountered another bug when using Aptana Studio debugger</a> with Firefox. If you see a window like below when running debug mode, uninstall the Firebug addon in Firefox, uninstall the Aptana Studio addon in Firefox, close all your browser windows and restart debug mode in Aptana Studio. The problem is with Firebug > 1.8.3 not being compatible with Aptana Studio (another reason to shell out the bucks for an IDE like Webstorm if you are doing a serious project, this bug has been around for quite some time).<br />
<b></b><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjbB1WpS4wXn5efc5dxrgiEiO-EhYrFMk_Mv0rSjFizk6qES1Lv6p62K9a6v77HX_yDkZxno4EkbKxk5kZFdXjDFBNlsmgQCJtOD9mFa4AeF9ExaIs0IVoNHhNRxJ6fgjq1x411lkkWZv1e/s1600/image0.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjbB1WpS4wXn5efc5dxrgiEiO-EhYrFMk_Mv0rSjFizk6qES1Lv6p62K9a6v77HX_yDkZxno4EkbKxk5kZFdXjDFBNlsmgQCJtOD9mFa4AeF9ExaIs0IVoNHhNRxJ6fgjq1x411lkkWZv1e/s1600/image0.png" height="161" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<h3>
<b>Step 3 - Creating the Cocos2d-JS Project</b></h3>
<br />
Run the following from wherever you create new projects:<br />
<br />
<script src="http://pastebin.com/embed_js.php?i=PUWqNEUA"></script>
You should see the default Cocos2d-JS hello world screen now.<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhglTRriyfjaW-SRCIq_9VbQ2L1bmj8rwSdFUelhmcox_D50UTvsd-Zit66UL51czjHXde20a1FMGsvo38RnLtYiPx9fELtG9BI0gBz5r2cKLVvJ6jgZGdkFgIUo1Ns0vDoXcUTS4z7Mj20/s1600/image1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhglTRriyfjaW-SRCIq_9VbQ2L1bmj8rwSdFUelhmcox_D50UTvsd-Zit66UL51czjHXde20a1FMGsvo38RnLtYiPx9fELtG9BI0gBz5r2cKLVvJ6jgZGdkFgIUo1Ns0vDoXcUTS4z7Mj20/s1600/image1.png" height="180" width="320" /></a></div>
<br />
<h3>
<b>Step 4 - Importing into Aptana Studio</b></h3>
Start Aptana Studio from the folder you installed Aptana Studio in. It will prompt you for a workspace. Create a new folder and select a workspace for Aptana.<b></b><br />
<b><br /></b>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEilr0cuaSs_WYXdEprxSjf4U5uwopebj8LKKntFLeut9IxxlLd-RnA-sW6aNJM7nO4-5bVj6pJgJMnwqq1zrF_aAyQqOvukm1s-Faaxq0CbF9vnFhbejBGGr6M48IWBfOp5EYYdTSqkvSCg/s1600/image2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEilr0cuaSs_WYXdEprxSjf4U5uwopebj8LKKntFLeut9IxxlLd-RnA-sW6aNJM7nO4-5bVj6pJgJMnwqq1zrF_aAyQqOvukm1s-Faaxq0CbF9vnFhbejBGGr6M48IWBfOp5EYYdTSqkvSCg/s1600/image2.png" height="153" width="320" /></a></div>
<b><br /></b>
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
Click the "Import Project" button and go to "Existing Folder as New Project". Then pick the folder with the web application.<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhtbC4DbVYIJs4Cza3dwVSIyp0-EJFDghbt5NVbTOtVgD4iLgrH5zOJNEqtlyYnAuDQ8ZdEKQSxR1FADaJBwwyWVFKxIEHbr-sYSLMx1rk98EVqqivegkKOpklTPFJpKEOchIJ94PolLDoX/s1600/image3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhtbC4DbVYIJs4Cza3dwVSIyp0-EJFDghbt5NVbTOtVgD4iLgrH5zOJNEqtlyYnAuDQ8ZdEKQSxR1FADaJBwwyWVFKxIEHbr-sYSLMx1rk98EVqqivegkKOpklTPFJpKEOchIJ94PolLDoX/s1600/image3.png" height="320" width="273" /></a></div>
<br />
<h3>
Step 5 - Get a 9-slice Sprite</h3>
This is the easiest part of the tutorial. Get the 9-slice (9patch in Android) image for free courtesy <a href="http://www.dibbus.com/2011/03/9patch-images-in-android/">of dibbus.com</a><br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjzWgw7hfMd7tkGyiLDIr7m6U3ZjufizhgXTF0dEwyB31Fa4leNY4sm5rJZpLjEM63iq6vcADwdQMiEeVH2CnDyl4NLdRQahK6CtRpcN7djnim-L-a9r7VMJ5q45YIlYSFK-16L9ar75bbd/s1600/image4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjzWgw7hfMd7tkGyiLDIr7m6U3ZjufizhgXTF0dEwyB31Fa4leNY4sm5rJZpLjEM63iq6vcADwdQMiEeVH2CnDyl4NLdRQahK6CtRpcN7djnim-L-a9r7VMJ5q45YIlYSFK-16L9ar75bbd/s1600/image4.png" /></a></div>
<br />
<a href="https://www.blogger.com/blogger.g?blogID=2064461998620158755" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"></a><br />
Next, place the image in the res directory of the 01-sprite cocos2d-JS project (assuming btn_red_matte.9.png).<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjzeC3Rvr-RKbLN6aKivATOKQT6xn5ZCIbGbmBixcYPJj6zU6iPrJzcqTUTUu9kzzJ87MXuvOBmC5hZAa5v4AOyu8Lmas7xQTz6Lw8muPN6seLfjUsCfvA2xIAlbiRfGZn17txx_ghWkDB9/s1600/image5.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjzeC3Rvr-RKbLN6aKivATOKQT6xn5ZCIbGbmBixcYPJj6zU6iPrJzcqTUTUu9kzzJ87MXuvOBmC5hZAa5v4AOyu8Lmas7xQTz6Lw8muPN6seLfjUsCfvA2xIAlbiRfGZn17txx_ghWkDB9/s1600/image5.png" height="320" width="173" /></a></div>
<br />
<a href="https://www.blogger.com/blogger.g?blogID=2064461998620158755" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"></a><br />
Now, add btn_red_matte.9.png to resource.js as one of the available resources.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEit9AV2Qmff0kFx4cyVK9Fs1clojH2yahb2YhYzEqxlT8N46ZL-cDgownxpdpZyyVWr8Mbxz9dTki3BtbdOEzi_KgZCfq4XpNoNVm1ltv-_PCS8-LvKqlXbcN_EkpTXHJpOVZYyDJ5lPJ7L/s1600/image6.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEit9AV2Qmff0kFx4cyVK9Fs1clojH2yahb2YhYzEqxlT8N46ZL-cDgownxpdpZyyVWr8Mbxz9dTki3BtbdOEzi_KgZCfq4XpNoNVm1ltv-_PCS8-LvKqlXbcN_EkpTXHJpOVZYyDJ5lPJ7L/s1600/image6.png" height="190" width="320" /></a></div>
<br />
<h3>
<b>Step 6 - Get the required information from the sprite</b></h3>
We require the following information from btn_red_matte.9.png in order to render the 9-slice sprite. Note that in Cocos2d-JS capInsets is a rectangular area, not margins of pixels to avoid scaling as in Cocos2d-x. Don't worry if you don't understand all of it; it makes more sense in Step 7 with the code.<br />
<ul>
<li><u>Bottom left x coordinate</u> - Cocos2d-JS treats the bottom left corner as the origin point. We will pick a portion of the image to render. The image is larger than we need, since it comes from Android and Android uses the <a href="http://developer.android.com/tools/help/draw9patch.html">Draw 9-patch tool</a> to create 9-slice sprites. We do not need the black marks or the margin because Cocos2d-JS will use capInsets to define the scalable area instead (explained below). Therefore, the portion should be the red area of the image and only the red area. You will create a rectangle with the bottom left x, bottom left y, width and height then pass it in as the second parameter to the cc.Scale9Sprite constructor. </li>
<li><u>Bottom left y coordinate</u> - Same as above</li>
<li><u>Width</u> - Width of rectangular area of image to render</li>
<li><u>Height</u> - Height of rectangular area of image to render </li>
<li><u>capInsets</u> - The capInsets are a little different than in Cocos2d-x. In iOS and Cocos2d-x you would define the capInsets as the number of pixels of top, left, bottom and right of the selected area in that order to ignore scaling. In Cocos2d-JS the "capInsets" parameter is actually an instance of cc.rect which is the stretchable area within the sprite. The green area below is the "capInsets" parameter for Cocos2d-JS. You will create this rectangle and pass it in as the third parameter to the cc.Scale9Sprite constructor.</li>
</ul>
<br />
<a href="https://www.blogger.com/blogger.g?blogID=2064461998620158755" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"></a><br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-CFuZtWTyOx68YrUh1Ews4lG9Cukuu7AhgbarWwFLYjW2L7nyE3WaKhLawIFHxyctr8xf8YJSHBmJR1LsdgErvo-QKPJHvahubtdyitVJTIwWr0Q6WOTbArKNsRKvhJm6Qn3hPnU8NuPp/s1600/image7.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-CFuZtWTyOx68YrUh1Ews4lG9Cukuu7AhgbarWwFLYjW2L7nyE3WaKhLawIFHxyctr8xf8YJSHBmJR1LsdgErvo-QKPJHvahubtdyitVJTIwWr0Q6WOTbArKNsRKvhJm6Qn3hPnU8NuPp/s1600/image7.png" /></a></div>
<a href="https://www.blogger.com/blogger.g?blogID=2064461998620158755" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"></a><a href="https://www.blogger.com/blogger.g?blogID=2064461998620158755" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"></a><br />
<a href="https://www.blogger.com/blogger.g?blogID=2064461998620158755" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"></a><br />
Using GIMP, we discover that the bottom left x-coordinate of the sprite we want is 2,2 and it is 44 pixels wide and 47 pixels high. Note that GIMP doesn't treat the bottom left as (0,0) like Cocos2d-JS does so you'll have to do some simple math.<br />
<br />
As well, using GIMP we discover that the inner green rectangle (the area we want to allow to scale) has its origin at (8,7) and is 32 pixels wide and 36 pixels high.<br />
<br />
<h3>
Step 7 - Code</h3>
<br />
At long last, the code.<br />
<br />
First, modify the project.json file to add the "extensions" module to the cocos2d-JS boot loader. cc.Scale9Sprite is an extension.<br />
<br />
<script src="http://pastebin.com/embed_js.php?i=bkFnJP53"></script>
<br />
Open up app.js and delete all the text in the file. We will code from scratch.<br />
<br />
Fill up app.js with the following (explanation below the code):<br />
<script src="http://pastebin.com/embed_js.php?i=pu0uW3kG"></script>
<b>Lines 1 to 7</b> should be self-explanatory. HelloWorldScene is called by main.js by the boot loader. This is unmodified from the default HelloWorld application when you first create a Cocos2d-JS project. The scene is created, which is basically a container for layers. Then the layer is created, defined below.<br />
<br />
<b>Lines 11 to 34</b> are the object properties.<br />
<br />
<b>Line 39 to 42</b> is the constructor. It calls the init() function to initialize the layer.<br />
<br />
<b>Lines 48 and 49</b> set a couple instance variables of the layer (the width and height, which we will use to scale.)<br />
<br />
<b>Line 50</b> schedules a update every frame. The update function (ticker) will be called each frame. Usually the update function will have a delta time parameter (dt) to model physics. However in this tutorial we will simply use the update function once, to draw three sprites scaled without distortion.<br />
<br />
<b>Line 58</b> creates conditions to draw the buttons. We only want to draw the buttons once (since they don't move) and check whether the buttons have been created previously. If they haven't we enter the block.<br />
<br />
<b>Lines 60 to 62</b> create the buttons. Down at lines 90 to 94 you see the create button function. For simplicity sake we have hardcoded the dimensions of the delimitation zone (area of the .png file to render) and the capInsets (area of the sprite to allow to scale). Note that the Cocos2d-JS definition of capInset is different than the Cocos2d-x definition or indeed the iOS definition.<br />
<br />
<b>Lines 65, 68 and 71</b> draw the buttons on the screen. This is done using three functions, drawButton, getWidthPercent and getHeightPercent on <b>lines 79, 97 and 101</b>.<br />
<br />
For the getWidthPercent and getHeightPercent functions, it is a simple calculation of number of pixels for a given percentage. If 20 is passed to the function, it calculates 20 percent of the pixels available on the width/height of the screen and returns it. If 50 is passed to the function, it calculates 50 percent of the pixels available on the width/height of the screen and returns it.<br />
<br />
At <b>line 80</b> the drawButton function first sets the anchor point to (0,0). An anchor point is the<br />
"origin" point in the sprite's internal coordinate system where all the transformations are applied. It is also where the sprite's position (its x and y coordinate) is centered. The anchor point is by default (0.5,0.5). We want it at the bottom left of the sprite, (0,0), so that when the sprite is scaled up it is scaled to the right and upwards, not below and to the left.<br />
<br />
At <b>line 81</b> we use the setContentSize function to scale the image up and down without distortion. Note that using the setScaleX and setScaleY functions will distort the sprite, ruining the whole point of a 9-slice sprite. By using setContentSize we make sure the edges are not scaled upwards and only the center of the button is scaled.<br />
<br />
At <b>line 82 and line 83</b> we set the x and y position. Since we set the anchor point at line 80 to the bottom left of the sprite, the x and y position is fixed regardless of whatever scale we set at line 81 using setContentSize.<br />
<br />
Finally at <b>line 84</b> the button is added as a child to the current layer.<br />
<br />
You should get a screen similar to the following<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://www.blogger.com/blogger.g?blogID=2064461998620158755" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"></a><a href="https://www.blogger.com/blogger.g?blogID=2064461998620158755" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"></a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgGF79LAKJZ0iF2HUV-dkhgsDQ8KSZU2a6qEsWAEP6Z3esXmIDDgxNtmqAxWIThDbLCCytmUvSr5WtMK_lxyFfGJx2crPOrcuZa9QqqWRabcmCJX6TQjOn2-pxMls_tjpNW5xGvn-pCV0EI/s1600/image8.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgGF79LAKJZ0iF2HUV-dkhgsDQ8KSZU2a6qEsWAEP6Z3esXmIDDgxNtmqAxWIThDbLCCytmUvSr5WtMK_lxyFfGJx2crPOrcuZa9QqqWRabcmCJX6TQjOn2-pxMls_tjpNW5xGvn-pCV0EI/s1600/image8.png" height="191" width="400" /></a></div>
<a href="https://www.blogger.com/blogger.g?blogID=2064461998620158755" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"></a><br />
<br />
<a href="https://www.blogger.com/blogger.g?blogID=2064461998620158755" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"></a><br />
Note that the corners and edges are not distorted in any way. You can now create buttons and sprites without distortion of any size with a relative percentage of the screen. Congratulations.<br />
<br />
The entire project is <a href="https://mega.co.nz/#!FlgSCQCC!vF-zcNKH7F1AFSbO64FsVacz1NT8lRAmtz9G-4z3UK8">available here</a>. Note you should do it yourself by reading the above blog post instead of downloading this, since the version of Cocos2d in that zip will be drastically outdated by the time you've read this.<br />
<br />
The next tutorial will deal with basic physics and collision detection.BrianLimhttp://www.blogger.com/profile/07107383864607795783noreply@blogger.com3