Home
recent posts
{ "kind": "blogger#postList", "nextPageToken": "CgkIChjAsvqZsikQiNn6s5euieIm", "items": [ { "kind": "blogger#post", "id": "7811001374406210291", "blog": { "id": "2793398838126095496" }, "published": "2017-04-10T17:38:00-07:00", "updated": "2017-04-10T17:39:51-07:00", "etag": "\"h3phi6z0oROkI1XWpXsALUFHLuA/dGltZXN0YW1wOiAxNDkxODcxMTkxNzgyCm9mZnNldDogLTI1MjAwMDAwCg\"", "url": "http://currentlyunderdevelopment.blogspot.com/2017/04/upgrading-from-angular-1-to-angular-2.html", "selfLink": "https://www.googleapis.com/blogger/v3/blogs/2793398838126095496/posts/7811001374406210291", "title": "Upgrading from Angular 1 to Angular 2: Getting to the starting line", "content": "We have a large Angular 1.4.7 application to upgrade to Angular 2. It's going to take a while to upgrade all the parts, so I wanted to use the ngUpgrade approach to make a hybrid app. I also wanted to use the Angular CLI to generate the Angular 2 part of our app.\u003cbr /\u003e\n\u003cdiv\u003e\n\u003cbr /\u003e\u003c/div\u003e\n\u003cdiv\u003e\nAfter a very long and frustrating search for a complete example of how to make a hybrid app, I eventually stumbled my way onto a working solution. Here it is, in case this is of use to anyone else.\u003c/div\u003e\n\u003cdiv\u003e\n\u003cbr /\u003e\u003c/div\u003e\n\u003cdiv\u003e\n\u003ca href=\"https://github.com/scottschafer/ng2hybrid\"\u003ehttps://github.com/scottschafer/ng2hybrid\u003c/a\u003e\u003c/div\u003e\n", "author": { "id": "g112717159621076070821", "displayName": "Scott Schafer", "url": "https://www.blogger.com/profile/16894652095365231201", "image": { "url": "//lh3.googleusercontent.com/-jFDZBEADuiE/AAAAAAAAAAI/AAAAAAAAKEE/1_m2xLHmLkI/s35-c/photo.jpg" } }, "replies": { "totalItems": "0", "selfLink": "https://www.googleapis.com/blogger/v3/blogs/2793398838126095496/posts/7811001374406210291/comments" }, "labels": [ "Angular2 AngularJS hybrid ngUpgrade ng-upgrade" ] }, { "kind": "blogger#post", "id": "7557136834597532067", "blog": { "id": "2793398838126095496" }, "published": "2017-03-15T17:26:00-07:00", "updated": "2017-05-02T11:50:25-07:00", "etag": "\"h3phi6z0oROkI1XWpXsALUFHLuA/dGltZXN0YW1wOiAxNDkzNzUxMDI1NDA5Cm9mZnNldDogLTI1MjAwMDAwCg\"", "url": "http://currentlyunderdevelopment.blogspot.com/2017/03/a-distributed-team-approach-for.html", "selfLink": "https://www.googleapis.com/blogger/v3/blogs/2793398838126095496/posts/7557136834597532067", "title": "A distributed team approach for resolving merge conflicts in git", "content": "\u003cspan style=\"font-family: inherit;\"\u003eWhere I work, we frequently have big ugly merge conflicts (probably indicative of a problem in our process, but that's a different blog post).\u003c/span\u003e\u003cbr /\u003e\n\u003cspan style=\"font-family: inherit;\"\u003e\u003cbr /\u003e\u003c/span\u003e\n\u003cspan style=\"font-family: inherit;\"\u003eThe way it goes down is like this. Let's say we need to merge \u003cb\u003erelease/2.0.0 \u003c/b\u003einto \u003cb\u003emaster\u003c/b\u003e. Sally volunteers to do the merge, so she might do something like the following:\u003c/span\u003e\u003cbr /\u003e\n\u003cbr /\u003e\n\u003cspan style=\"font-family: "courier new" , "courier" , monospace;\"\u003e\u003cb\u003egit fetch\u003c/b\u003e\u003c/span\u003e\u003cbr /\u003e\n\u003cspan style=\"font-family: "courier new" , "courier" , monospace;\"\u003e\u003cb\u003egit checkout master\u003c/b\u003e\u003c/span\u003e\u003cbr /\u003e\n\u003cspan style=\"font-family: "courier new" , "courier" , monospace;\"\u003e\u003cb\u003egit pull origin master\u003c/b\u003e\u003c/span\u003e\u003cbr /\u003e\n\u003cspan style=\"font-family: "courier new" , "courier" , monospace;\"\u003e\u003cb\u003egit merge origin/release/2.0.0\u003c/b\u003e\u003c/span\u003e\u003cbr /\u003e\n\u003cspan style=\"font-family: Arial, Helvetica, sans-serif;\"\u003e\u003cbr /\u003e\u003c/span\u003e\n\u003cspan style=\"font-family: inherit;\"\u003eLet's say this results in the following conflicted files:\u003c/span\u003e\u003cbr /\u003e\n\u003cstyle type=\"text/css\"\u003e\np.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #c33720}\nspan.s1 {font-variant-ligatures: no-common-ligatures; color: #000000}\nspan.s2 {font-variant-ligatures: no-common-ligatures}\nspan.Apple-tab-span {white-space:pre}\n\u003c/style\u003e\n\n\n\u003cbr /\u003e\n\u003cdiv class=\"p1\"\u003e\n\u003cspan style=\"font-family: "courier new" , "courier" , monospace; font-size: small;\"\u003e\u003cb\u003e\u003cspan class=\"s1\"\u003e\u003cspan class=\"Apple-tab-span\"\u003e \u003c/span\u003e\u003c/span\u003e\u003cspan class=\"s2\"\u003eboth modified:   database.sql\u003c/span\u003e\u003c/b\u003e\u003c/span\u003e\u003c/div\u003e\n\u003cdiv class=\"p1\"\u003e\n\u003cspan style=\"font-family: "courier new" , "courier" , monospace; font-size: small;\"\u003e\u003cb\u003e\u003cspan class=\"s1\"\u003e\u003cspan class=\"Apple-tab-span\"\u003e \u003c/span\u003e\u003c/span\u003e\u003cspan class=\"s2\"\u003eboth modified:   \u003c/span\u003eapi.java\u003c/b\u003e\u003c/span\u003e\u003c/div\u003e\n\u003cdiv class=\"p1\"\u003e\n\u003cspan style=\"font-family: "courier new" , "courier" , monospace; font-size: small;\"\u003e\u003cb\u003e\u003cspan class=\"s1\"\u003e\u003cspan class=\"Apple-tab-span\"\u003e \u003c/span\u003e\u003c/span\u003e\u003cspan class=\"s2\"\u003eboth modified:   \u003c/span\u003efrontend.js\u003c/b\u003e\u003c/span\u003e\u003c/div\u003e\n\u003cdiv class=\"p1\"\u003e\n\u003cbr /\u003e\u003c/div\u003e\n\u003cspan style=\"font-family: inherit;\"\u003e\u003cspan style=\"font-family: inherit;\"\u003eSally knows how to resolve the merge conflicts in database.sql, but Ahmed is the expert on api.java, and Yasuko is the expert on frontend.js. To make matters worse, let's just say that everyone is in different timezones. \u003c/span\u003e\u003cspan style=\"font-family: inherit;\"\u003eWhat can she do at this point, apart from aborting the merge and giving up or trying to figure out how to resolve the merge conflicts herself? \u003c/span\u003e\u003c/span\u003e\u003cbr /\u003e\n\u003cspan style=\"font-family: inherit;\"\u003e\u003cspan style=\"font-family: inherit;\"\u003e\u003cbr /\u003e\u003c/span\u003e\nHere's one way to do it. The basic strategy is to create a branch that merges two SHA-1 tags (representing specific commits), and push the branch with the conflicted files. Other developers perform the exact same merge using the same tags, resolve their conflicts, and then commit/push their resolved files to the merge branch. By using tags rather than branches, we ensure that all developers are working on the same merge (even if the branches are modified) and the git history will be correct after the merge branch has itself been merged.\u003c/span\u003e\u003cbr /\u003e\n\u003col\u003e\n\u003cli\u003e\u003cspan style=\"font-family: inherit;\"\u003e\u003cspan style=\"font-family: inherit;\"\u003eUse\u003c/span\u003e \u003c/span\u003e\u003cspan style=\"font-family: "courier new" , "courier" , monospace;\"\u003e\u003cb\u003egit merge --abort\u003c/b\u003e\u003c/span\u003e\u003cspan style=\"font-family: inherit;\"\u003e \u003cspan style=\"font-family: inherit;\"\u003eto stop the merge.\u003c/span\u003e\u003c/span\u003e\u003c/li\u003e\n\u003cbr /\u003e\n\u003cli\u003e\u003cspan style=\"font-family: inherit;\"\u003e\u003cspan style=\"font-family: inherit;\"\u003eDetermine the SHA tags of the two branches you will be merging like so:\u003c/span\u003e\u003cbr /\u003e\u003cb style=\"font-family: "courier new", courier, monospace;\"\u003egit fetch origin\u003cbr /\u003egit log origin/master\u003c/b\u003e\u003c/span\u003e\u003cb style=\"font-family: "courier new", courier, monospace;\"\u003e\u003cbr /\u003egit log origin/release/5.1.2\u003cbr\u003e\u003c/b\u003e\u003c/li\u003e\n\u003cli\u003e\u003cspan style=\"font-family: inherit;\"\u003eMake a note of the first seven letters/numbers of the top SHA tag for each branch. For example, if this is the most recent commit, use \"a820826\".\u003c/span\u003e\u003cspan style=\"font-family: "courier new" , "courier" , monospace;\"\u003e\u003cbr /\u003e\n\n\n\n\n\u003cstyle type=\"text/css\"\u003e\np.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #afad24}\np.p2 {margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo}\np.p3 {margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; min-height: 13.0px}\nspan.s1 {font-variant-ligatures: no-common-ligatures}\n\u003c/style\u003e\n\n\n\u003c/span\u003e\u003cdiv class=\"p1\"\u003e\n\u003c/div\u003e\n\u003cblockquote style=\"border: none; margin: 0 0 0 40px; padding: 0px;\"\u003e\n\u003cspan class=\"s1\"\u003e\u003cspan style=\"font-family: "courier new" , "courier" , monospace; font-size: small;\"\u003ecommit a8208268dffbd3ab63ac7466b861a2be33c4f665\u003c/span\u003e\u003c/span\u003e\u003c/blockquote\u003e\n\u003cdiv class=\"p2\"\u003e\n\u003c/div\u003e\n\u003cblockquote style=\"border: none; margin: 0 0 0 40px; padding: 0px;\"\u003e\n\u003cspan class=\"s1\"\u003e\u003cspan style=\"font-family: "courier new" , "courier" , monospace; font-size: small;\"\u003eAuthor: joeshmo <joeshmo@joeshmo.com>\u003c/span\u003e\u003c/span\u003e\u003c/blockquote\u003e\n\u003cdiv class=\"p2\"\u003e\n\u003c/div\u003e\n\u003cblockquote style=\"border: none; margin: 0 0 0 40px; padding: 0px;\"\u003e\n\u003cspan class=\"s1\"\u003e\u003cspan style=\"font-family: "courier new" , "courier" , monospace; font-size: small;\"\u003eDate:   Mon May 1 14:38:41 2017 -0700\u003c/span\u003e\u003c/span\u003e\u003c/blockquote\u003e\n\u003cdiv class=\"p3\"\u003e\n\u003cspan class=\"s1\"\u003e\u003c/span\u003e\u003cbr /\u003e\u003c/div\u003e\nFor the purposes of this tutorial, let's say that the tip of master is 1111111 and the tip of release/2.0.0 is 2222222.\u003c/li\u003e\n\u003cli\u003e\u003cspan style=\"font-family: inherit;\"\u003e\u003cb style=\"font-family: "courier new", courier, monospace;\"\u003e \u003c/b\u003e\u003c/span\u003eCreate a new branch from the master SHA tag like:\u003cbr /\u003e\u003cb style=\"font-family: "courier new", courier, monospace;\"\u003e\u003cspan style=\"font-family: "courier new" , "courier" , monospace;\"\u003egit checkout \u003c/span\u003e\u003cb\u003e\u003cspan style=\"font-family: "courier new" , "courier" , monospace;\"\u003e1111111\u003c/span\u003e\u003c/b\u003e\u003c/b\u003e\u003cspan style=\"font-family: "courier new" , "courier" , monospace;\"\u003e\u003cb\u003e\u003cspan style=\"font-family: "courier new" , "courier" , monospace;\"\u003egit checkout -b \u003c/span\u003e\u003cspan style=\"font-family: "courier new" , "courier" , monospace;\"\u003emerge/\u003cb\u003e1111111\u003c/b\u003e-and-\u003c/span\u003e\u003c/b\u003e\u003c/span\u003e\u003cb\u003e\u003cspan style=\"font-family: "courier new" , "courier" , monospace;\"\u003e2222222\u003c/span\u003e\u003c/b\u003e\u003c/li\u003e\n\u003cbr /\u003e\n\u003cli\u003e\u003cspan style=\"font-family: inherit;\"\u003ePerform the merge:\u003c/span\u003e\u003cbr /\u003e\u003cspan style=\"font-family: "courier new" , "courier" , monospace;\"\u003e\u003cb\u003egit merge \u003c/b\u003e\u003c/span\u003e\u003cb\u003e\u003cspan style=\"font-family: "courier new" , "courier" , monospace;\"\u003e2222222\u003c/span\u003e\u003c/b\u003e\u003c/li\u003e\n\u003cbr /\u003e\n\u003cli\u003e\u003cspan style=\"font-family: inherit;\"\u003eSally would resolve whatever merge conflicts that she could, namely on database.sql. For the other two files, she would commit them in their conflicted state like so:\u003c/span\u003e\u003cbr /\u003e\u003cb\u003e\u003cspan style=\"font-family: "courier new" , "courier" , monospace;\"\u003egit reset HEAD api.java\u003cbr /\u003egit add api.java\u003cbr /\u003egit reset HEAD frontend.js\u003cbr /\u003egit add frontend.js\u003c/span\u003e\u003c/b\u003e\u003c/li\u003e\n\u003cbr /\u003e\n\u003cli\u003e\u003cspan style=\"font-family: inherit;\"\u003eCommit and push like so:\u003c/span\u003e\u003cbr /\u003e\u003cb\u003e\u003cspan style=\"font-family: "courier new" , "courier" , monospace;\"\u003egit commit -m \"contains conflicted files\"\u003cbr /\u003egit push origin merge/\u003cb style=\"font-family: Times;\"\u003e\u003cspan style=\"font-family: "courier new" , "courier" , monospace;\"\u003e1111111\u003c/span\u003e\u003c/b\u003e-and-\u003c/span\u003e\u003c/b\u003e\u003cb\u003e\u003cspan style=\"font-family: "courier new" , "courier" , monospace;\"\u003e2222222\u003c/span\u003e\u003c/b\u003e\u003c/li\u003e\n\u003cbr /\u003e\n\u003c/ol\u003e\n\u003cdiv\u003e\nNext up, she would inform Ahmed and Yasuko that they need to fix conflicts in the files they own. Their instructions would be something like this:\u003c/div\u003e\n\u003cdiv\u003e\n\u003col\u003e\n\u003cli\u003eAssuming they have the repo already cloned in /gitmain, they should clone the repo into a new directory /gitmerge (for example).\u003c/li\u003e\n\u003cbr /\u003e\n\u003cli\u003eWithin /gitmerge, execute the commands:\u003cbr /\u003e\u003cspan style=\"font-family: "courier new" , "courier" , monospace;\"\u003e\u003cb\u003egit checkout \u003cb style=\"font-family: Times;\"\u003e\u003cspan style=\"font-family: "courier new" , "courier" , monospace;\"\u003e1111111\u003c/span\u003e\u003c/b\u003e\u003cbr /\u003egit merge \u003c/b\u003e\u003c/span\u003e\u003cb\u003e\u003cspan style=\"font-family: "courier new" , "courier" , monospace;\"\u003e2222222\u003c/span\u003e\u003c/b\u003e\u003c/li\u003e\n\u003cbr /\u003e\n\u003cli\u003eResolve the conflicts on the files they are concerned about.\u003c/li\u003e\n\u003cbr /\u003e\n\u003cli\u003eIn their main repo, \u003cb\u003e\u003cspan style=\"font-family: "courier new" , "courier" , monospace;\"\u003egit checkout \u003c/span\u003e\u003c/b\u003e\u003cb\u003e\u003cspan style=\"font-family: "courier new" , "courier" , monospace;\"\u003emerge/\u003cb style=\"font-family: Times;\"\u003e\u003cspan style=\"font-family: "courier new" , "courier" , monospace;\"\u003e1111111\u003c/span\u003e\u003c/b\u003e-and-\u003c/span\u003e\u003c/b\u003e\u003cb\u003e\u003cspan style=\"font-family: "courier new" , "courier" , monospace;\"\u003e2222222\u003c/span\u003e\u003c/b\u003e\u003c/li\u003e\n\u003cbr /\u003e\n\u003cli\u003eManually copy the modified file(s) from /gitmerge into /gitmain\u003c/li\u003e\n\u003cbr /\u003e\n\u003cli\u003eAdd, commit and push their resolved files\u003c/li\u003e\n\u003c/ol\u003e\n\u003cdiv\u003e\nEventually, when Yasuko and Ahmed have finished resolving their conflicts, there should be no <<<<< ======= >>>>>> conflict markers in any file, and \u003cspan style=\"font-family: "courier new" , "courier" , monospace;\"\u003e\u003cb style=\"font-family: Times;\"\u003e\u003cspan style=\"font-family: "courier new" , "courier" , monospace;\"\u003emerge/\u003cb style=\"font-family: Times;\"\u003e\u003cspan style=\"font-family: "courier new" , "courier" , monospace;\"\u003e1111111\u003c/span\u003e\u003c/b\u003e-and-\u003c/span\u003e\u003c/b\u003e\u003cb style=\"font-family: Times;\"\u003e\u003cspan style=\"font-family: "courier new" , "courier" , monospace;\"\u003e2222222\u003c/span\u003e\u003c/b\u003e\u003cb\u003e \u003c/b\u003e\u003c/span\u003ecan be merged back into \u003cb style=\"font-family: "Courier New", Courier, monospace;\"\u003emaster.\u003c/b\u003e\u003c/div\u003e\n\u003c/div\u003e\n", "author": { "id": "g112717159621076070821", "displayName": "Scott Schafer", "url": "https://www.blogger.com/profile/16894652095365231201", "image": { "url": "//lh3.googleusercontent.com/-jFDZBEADuiE/AAAAAAAAAAI/AAAAAAAAKEE/1_m2xLHmLkI/s35-c/photo.jpg" } }, "replies": { "totalItems": "0", "selfLink": "https://www.googleapis.com/blogger/v3/blogs/2793398838126095496/posts/7557136834597532067/comments" } }, { "kind": "blogger#post", "id": "419324855562053388", "blog": { "id": "2793398838126095496" }, "published": "2017-01-18T12:44:00-08:00", "updated": "2017-01-18T12:44:06-08:00", "etag": "\"h3phi6z0oROkI1XWpXsALUFHLuA/dGltZXN0YW1wOiAxNDg0NzcyMjQ2NzI0Cm9mZnNldDogLTI4ODAwMDAwCg\"", "url": "http://currentlyunderdevelopment.blogspot.com/2017/01/using-angular2-services-as-singletons.html", "selfLink": "https://www.googleapis.com/blogger/v3/blogs/2793398838126095496/posts/419324855562053388", "title": "Using Angular2 services as singletons for busy people", "content": "\u003cdiv class=\"tr_bq\"\u003e\nPerhaps like you, I can't be bothered to read the documentation or blog posts either, so I'll keep this short and to the point.\u003c/div\u003e\n\u003cbr /\u003e\nIn Angular 1, services are always singletons. I followed what I thought was the correct way to do Dependency Injection in Angular 2, and found out the hard way that multiple instances of my services were being created. This meant that they could not be used to share the state across components.\u003cbr /\u003e\n\u003cbr /\u003e\n\u003cb\u003eTL;DR\u003c/b\u003e:\n\nThe problem was that I had put my service in the providers array of every component that needed access. For example, I had:\n\u003cbr /\u003e\n\u003cblockquote\u003e\n\u003cspan style=\"font-family: Courier New, Courier, monospace;\"\u003e@Component({\u003c/span\u003e\u003cbr /\u003e\n\u003cspan style=\"font-family: Courier New, Courier, monospace;\"\u003e  selector: 'game',\u003c/span\u003e\u003cbr /\u003e\n\u003cspan style=\"font-family: Courier New, Courier, monospace;\"\u003e  templateUrl: './game.component.html',\u003c/span\u003e\u003cbr /\u003e\n\u003cspan style=\"font-family: Courier New, Courier, monospace;\"\u003e  styleUrls: ['./game.component.css'],\u003c/span\u003e\u003cbr /\u003e\n\u003cspan style=\"font-family: Courier New, Courier, monospace;\"\u003e\u003cb\u003e  providers: [ AppStateService ]\u003c/b\u003e\u003c/span\u003e\u003cbr /\u003e\n\u003cspan style=\"font-family: Courier New, Courier, monospace;\"\u003e})\u003c/span\u003e\u003cbr /\u003e\n\u003cdiv\u003e\n\u003cspan style=\"font-family: Courier New, Courier, monospace;\"\u003e\u003cbr /\u003e\u003c/span\u003e\u003c/div\u003e\n\u003c/blockquote\u003e\nand\n\u003cbr /\u003e\n\u003cblockquote\u003e\n\u003cspan style=\"font-family: Courier New, Courier, monospace;\"\u003e@Component({\u003c/span\u003e\u003cbr /\u003e\n\u003cspan style=\"font-family: Courier New, Courier, monospace;\"\u003e  selector: 'game',\u003c/span\u003e\u003cbr /\u003e\n\u003cspan style=\"font-family: Courier New, Courier, monospace;\"\u003e  templateUrl: './game.component.html',\u003c/span\u003e\u003cbr /\u003e\n\u003cspan style=\"font-family: Courier New, Courier, monospace;\"\u003e  styleUrls: ['./game.component.css'],\u003c/span\u003e\u003cbr /\u003e\n\u003cspan style=\"font-family: Courier New, Courier, monospace;\"\u003e\u003cb\u003e  providers: [ AppStateService ]\u003c/b\u003e\u003c/span\u003e\u003cbr /\u003e\n\u003cspan style=\"font-family: Courier New, Courier, monospace;\"\u003e})\u003c/span\u003e\u003cbr /\u003e\n\u003cdiv\u003e\n\u003cbr /\u003e\u003c/div\u003e\n\u003c/blockquote\u003e\nThis seemed to be causing the service to be instantiated multiple times. My fix was this:\u003cbr /\u003e\n\u003cbr /\u003e\n1. Only having the AppStateService appear in \u003cb\u003eone\u003c/b\u003e providers array. I put it in my app.component.ts.\u003cbr /\u003e\n\u003cbr /\u003e2. Use @Injectable on my service, like so:\u003cbr /\u003e\n\u003cblockquote class=\"tr_bq\"\u003e\n\u003cspan style=\"font-family: Courier New, Courier, monospace;\"\u003eimport { Injectable } from '@angular/core';\u003c/span\u003e \u003c/blockquote\u003e\n\u003cblockquote class=\"tr_bq\"\u003e\n\u003cspan style=\"font-family: Courier New, Courier, monospace;\"\u003e@Injectable()\u003cbr /\u003eexport class AppStateService { ...\u003c/span\u003e\u003c/blockquote\u003e\n3. Wherever I need to use the service, use @Inject like so:\u003cbr /\u003e\n\u003cblockquote\u003e\n\u003cspan style=\"font-family: Courier New, Courier, monospace;\"\u003eimport { Component, OnInit, Inject } from '@angular/core'; \u003c/span\u003e\u003c/blockquote\u003e\n\u003cblockquote\u003e\n\u003cspan style=\"font-family: Courier New, Courier, monospace;\"\u003e@Component({\u003cbr /\u003e  selector: 'start-screen',\u003cbr /\u003e  templateUrl: './start-screen.component.html',\u003cbr /\u003e  styleUrls: ['./start-screen.component.scss']\u003cbr /\u003e})\u003cbr /\u003e@Inject(AppStateService)\u003cbr /\u003eexport class StartScreenComponent implements OnInit {\u003cbr /\u003e  constructor(public appState: AppStateService) {  \u003c/span\u003e\u003c/blockquote\u003e\n", "author": { "id": "g112717159621076070821", "displayName": "Scott Schafer", "url": "https://www.blogger.com/profile/16894652095365231201", "image": { "url": "//lh3.googleusercontent.com/-jFDZBEADuiE/AAAAAAAAAAI/AAAAAAAAKEE/1_m2xLHmLkI/s35-c/photo.jpg" } }, "replies": { "totalItems": "0", "selfLink": "https://www.googleapis.com/blogger/v3/blogs/2793398838126095496/posts/419324855562053388/comments" } }, { "kind": "blogger#post", "id": "4272060425785613467", "blog": { "id": "2793398838126095496" }, "published": "2017-01-07T18:14:00-08:00", "updated": "2017-01-07T18:15:34-08:00", "etag": "\"h3phi6z0oROkI1XWpXsALUFHLuA/dGltZXN0YW1wOiAxNDgzODQxNzM0NzI2Cm9mZnNldDogLTI4ODAwMDAwCg\"", "url": "http://currentlyunderdevelopment.blogspot.com/2017/01/presto-evolution.html", "selfLink": "https://www.googleapis.com/blogger/v3/blogs/2793398838126095496/posts/4272060425785613467", "title": "Presto! Evolution", "content": "Because I dig this sort of thing, and as an excuse to teach myself Typescript and Angular 2, I ported an old C++/Windows program of mine to modern web technologies. I now really, really love Angular 2 and Typescript both.\n\u003cbr /\u003e\n\u003ca href=\"https://github.com/scottschafer/presto-evolution\"\u003eSource on github\u003c/a\u003e\n\u003cbr /\u003e\n\n\u003ciframe src=\"https://scottschafer.github.io//presto-evolution//\" width=\"900\" height=\"1200\"\u003e\u003c/iframe\u003e", "author": { "id": "g112717159621076070821", "displayName": "Scott Schafer", "url": "https://www.blogger.com/profile/16894652095365231201", "image": { "url": "//lh3.googleusercontent.com/-jFDZBEADuiE/AAAAAAAAAAI/AAAAAAAAKEE/1_m2xLHmLkI/s35-c/photo.jpg" } }, "replies": { "totalItems": "0", "selfLink": "https://www.googleapis.com/blogger/v3/blogs/2793398838126095496/posts/4272060425785613467/comments" } }, { "kind": "blogger#post", "id": "2108008848738997810", "blog": { "id": "2793398838126095496" }, "published": "2016-03-31T10:40:00-07:00", "updated": "2016-05-09T15:57:05-07:00", "etag": "\"h3phi6z0oROkI1XWpXsALUFHLuA/dGltZXN0YW1wOiAxNDYyODM0NjI1NDEyCm9mZnNldDogLTI1MjAwMDAwCg\"", "url": "http://currentlyunderdevelopment.blogspot.com/2016/03/meet-you-in-middle-perfectly-imperfect.html", "selfLink": "https://www.googleapis.com/blogger/v3/blogs/2793398838126095496/posts/2108008848738997810", "title": "Meet you in the middle: a perfectly imperfect approach to frontend/backend integration", "content": "\u003ca href=\"https://docs.angularjs.org/img/tutorial/catalog_screen.png\" imageanchor=\"1\" style=\"clear: right; float: right; margin-bottom: 1em; margin-left: 1em;\"\u003e\u003cimg border=\"0\" height=\"169\" src=\"https://docs.angularjs.org/img/tutorial/catalog_screen.png\" width=\"200\" /\u003e\u003c/a\u003eIf you're an AngularJS programmer like me,  you probably went through the excellent \u003ca href=\"https://docs.angularjs.org/tutorial\" target=\"_blank\"\u003ePhoneCat tutorial\u003c/a\u003e at some point. You may have done something similar on a different stack. The tutorial I'm referring to leads you through the steps of getting data from a server and presenting it on a webpage using HTML templates and databinding. The result is a web application that lets you search phones and see the results in a nicely formatted list like this:\u003cbr /\u003e\n\u003cbr /\u003e\nIt's a great tutorial, but unfortunately I believe sets an expectation that will get you into trouble on sufficiently complicated projects. Hence this blog post.\u003cbr /\u003e\n\u003cbr /\u003e\nIn this tutorial, the \u003ca href=\"https://github.com/angular/angular-phonecat/blob/master/app/phones/phones.json\" target=\"_blank\"\u003edata returned from the server\u003c/a\u003e looks like this:\u003cbr /\u003e\n\u003cspan style=\"font-family: "courier new" , "courier" , monospace;\"\u003e[{\u003c/span\u003e\u003cbr /\u003e\n\u003cspan style=\"font-family: "courier new" , "courier" , monospace;\"\u003e  \"age\": 0,\u003c/span\u003e\u003cbr /\u003e\n\u003cspan style=\"font-family: "courier new" , "courier" , monospace;\"\u003e  \"id\": \"motorola-xoom-with-wi-fi\",\u003c/span\u003e\u003cbr /\u003e\n\u003cspan style=\"font-family: "courier new" , "courier" , monospace;\"\u003e  \"imageUrl\": \"img/phones/motorola-xoom-with-wi-fi.0.jpg\",\u003c/span\u003e\u003cbr /\u003e\n\u003cspan style=\"font-family: "courier new" , "courier" , monospace;\"\u003e  \"name\": \"Motorola XOOM\\u2122 with Wi-Fi\",\u003c/span\u003e\u003cbr /\u003e\n\u003cspan style=\"font-family: "courier new" , "courier" , monospace;\"\u003e  \"snippet\": \"The Next, Next Generation\\r\\n\\r\\nExperience the future       with Motorola XOOM with Wi-Fi, the world's first tablet powered by Android 3.0 (Honeycomb).\"\u003c/span\u003e\u003cbr /\u003e\n\u003cspan style=\"font-family: "courier new" , "courier" , monospace;\"\u003e  } . . .\u003c/span\u003e\u003cbr /\u003e\n\u003cbr /\u003e\nAnd it's elegantly rendered \u003ca href=\"https://github.com/angular/angular-phonecat/blob/master/app/partials/phone-list.html\" target=\"_blank\"\u003eusing this template\u003c/a\u003e:\u003cbr /\u003e\n\u003cbr /\u003e\n\u003cspan style=\"font-family: "courier new" , "courier" , monospace;\"\u003e<ul class=\"phones\">\u003c/span\u003e\u003cbr /\u003e\n\u003cspan style=\"font-family: "courier new" , "courier" , monospace;\"\u003e  <li ng-repeat=\"phone in phones | filter:query | orderBy:orderProp\"\u003c/span\u003e\u003cbr /\u003e\n\u003cspan style=\"font-family: "courier new" , "courier" , monospace;\"\u003e     class=\"thumbnail phone-listing\">\u003c/span\u003e\u003cbr /\u003e\n\u003cspan style=\"font-family: "courier new" , "courier" , monospace;\"\u003e    <a href=\"#/phones/{{phone.id}}\" class=\"thumb\">\u003c/span\u003e\u003cbr /\u003e\n\u003cspan style=\"font-family: "courier new" , "courier" , monospace;\"\u003e      <img ng-src=\"{{phone.imageUrl}}\" alt=\"{{phone.name}}\"></a>\u003c/span\u003e\u003cbr /\u003e\n\u003cspan style=\"font-family: "courier new" , "courier" , monospace;\"\u003e    <a href=\"#/phones/{{phone.id}}\">{{phone.name}}</a>\u003c/span\u003e\u003cbr /\u003e\n\u003cspan style=\"font-family: "courier new" , "courier" , monospace;\"\u003e    <p>{{phone.snippet}}</p>\u003c/span\u003e\u003cbr /\u003e\n\u003cspan style=\"font-family: "courier new" , "courier" , monospace;\"\u003e  </li>\u003c/span\u003e\u003cbr /\u003e\n\u003cspan style=\"font-family: "courier new" , "courier" , monospace;\"\u003e</ul>\u003c/span\u003e\u003cbr /\u003e\n\u003cdiv\u003e\n\u003cbr /\u003e\u003c/div\u003e\n\u003cdiv\u003e\nThis HTML template repeats through the phones array, applying filtering and sorting, and rendering each item by data-binding to its properties. So elegant! That's how it should be, right? This is the gold standard of front/back end integration, and anything less elegant is a \u003ca href=\"https://en.wikipedia.org/wiki/Code_smell\" target=\"_blank\"\u003eBad Smell\u003c/a\u003e right?\u003c/div\u003e\n\u003cdiv\u003e\n\u003cbr /\u003e\u003c/div\u003e\n\u003cdiv\u003e\nYes exactly. End of post. Thanks for reading.\u003c/div\u003e\n\u003cdiv\u003e\n\u003cbr /\u003e\u003c/div\u003e\n\u003cdiv\u003e\n\u003chr /\u003e\n\u003c/div\u003e\n\u003cdiv\u003e\n\u003cbr /\u003e\u003c/div\u003e\n\u003cdiv\u003e\nHah, you probably guessed that my real answer is \"no\". While this kind of elegance is nice to aim for, you shouldn't expect that it's always acheivable, and doing so is going to lead you into trouble.\u003c/div\u003e\n\u003cdiv\u003e\n\u003cbr /\u003e\u003c/div\u003e\n\u003cdiv\u003e\nMy last big project woke me up to this. I was given an extremely complex UI to implement, with APIs being developed independently by another developer. My first instinct was to try to hammer out the APIs with this other developer - determine exactly how they should be called and what data they would return. Not a bad instinct. I think, and probably still a good first step. But in the meantime, I felt blocked. I had all these custom directives that I knew I had to write, and I didn't know what the data format would be that they would bind to.\u003c/div\u003e\n\u003cdiv\u003e\n\u003cbr /\u003e\nThe one thing I knew was the APIs would be returning fairly complicated and weighty data structures.\u003cbr /\u003e\n\u003cbr /\u003e\u003c/div\u003e\n\u003cdiv\u003e\nI felt blocked becausethe elegance of this tutorial and others like it had convinced me that the\u003cb\u003e \u003c/b\u003e\u003ci\u003e\u003cb\u003eUI should be tightly coupled to the API results\u003c/b\u003e\u003c/i\u003e. Once I put that into words, I knew it was wrong, and I pivoted to create directives that bound to only small bits of relevant data, not big objects returned from the server where only a small percentage of the fields were relevant to the directive.\u003c/div\u003e\n\u003cdiv\u003e\n\u003cbr /\u003e\u003c/div\u003e\n\u003cdiv\u003e\nThis means that in my service layer, I get data from the server and then munge it into a format that's best for the views and directives. \u003c/div\u003e\n\u003cdiv\u003e\n\u003cbr /\u003e\u003c/div\u003e\n\u003cdiv\u003e\nIt does seems a bit silly to have to write our own transformation layer when we own both the back and the front end. But on the other hand, the backend developers have different concerns than the front end engineers. If it's better for the backend to return a list as an associative array (so there are no duplicate keys), it's easier for me to convert it to a sequential array if that's what the UI needs instead of asking for an API modification.\u003c/div\u003e\n\u003cdiv\u003e\n\u003cbr /\u003e\u003c/div\u003e\n\u003cdiv\u003e\nThe APIs on this project have changed numerous times. I'm currently reworking the service to handle a new data format that was required by a change in requirements. A benefit of having the transformation layer in place, the impact of changes has been severely limited.\u003cbr /\u003e\n\u003cbr /\u003e\nIn case you're wondering, this is basically what the transformation layer looks like in my service.\u003cbr /\u003e\n\u003cbr /\u003e\n\u003cspan style=\"font-family: "courier new" , "courier" , monospace;\"\u003e    var url = '/myAPI?param=' + param;\u003c/span\u003e\u003cbr /\u003e\n\u003cspan style=\"font-family: "courier new" , "courier" , monospace;\"\u003e        return $q(function (resolve, reject) {\u003c/span\u003e\u003cbr /\u003e\n\u003cspan style=\"font-family: "courier new" , "courier" , monospace;\"\u003e          $http.get(url).then(\u003c/span\u003e\u003cbr /\u003e\n\u003cspan style=\"font-family: "courier new" , "courier" , monospace;\"\u003e            function (success) {\u003c/span\u003e\u003cbr /\u003e\n\u003cspan style=\"font-family: "courier new" , "courier" , monospace;\"\u003e              \u003cb\u003eresolve(prepareResult(success.data));\u003c/b\u003e\u003c/span\u003e\u003cbr /\u003e\n\u003cspan style=\"font-family: "courier new" , "courier" , monospace;\"\u003e            },\u003c/span\u003e\u003cbr /\u003e\n\u003cspan style=\"font-family: "courier new" , "courier" , monospace;\"\u003e            function (failure) {\u003c/span\u003e\u003cbr /\u003e\n\u003cspan style=\"font-family: "courier new" , "courier" , monospace;\"\u003e              reject(failure)\u003c/span\u003e\u003cbr /\u003e\n\u003cspan style=\"font-family: "courier new" , "courier" , monospace;\"\u003e            }\u003c/span\u003e\u003cbr /\u003e\n\u003cspan style=\"font-family: "courier new" , "courier" , monospace;\"\u003e          );\u003c/span\u003e\u003cbr /\u003e\n\u003cspan style=\"font-family: "courier new" , "courier" , monospace;\"\u003e        });\u003c/span\u003e\u003cbr /\u003e\n\u003cspan style=\"font-family: "courier new" , "courier" , monospace;\"\u003e      }\u003c/span\u003e\u003c/div\u003e\n\u003cdiv\u003e\n\u003cbr /\u003e\u003c/div\u003e\n", "author": { "id": "g112717159621076070821", "displayName": "Scott Schafer", "url": "https://www.blogger.com/profile/16894652095365231201", "image": { "url": "//lh3.googleusercontent.com/-jFDZBEADuiE/AAAAAAAAAAI/AAAAAAAAKEE/1_m2xLHmLkI/s35-c/photo.jpg" } }, "replies": { "totalItems": "0", "selfLink": "https://www.googleapis.com/blogger/v3/blogs/2793398838126095496/posts/2108008848738997810/comments" } }, { "kind": "blogger#post", "id": "8568975944934760082", "blog": { "id": "2793398838126095496" }, "published": "2015-11-19T09:40:00-08:00", "updated": "2015-11-19T21:13:39-08:00", "etag": "\"h3phi6z0oROkI1XWpXsALUFHLuA/dGltZXN0YW1wOiAxNDQ3OTk2NDE5MTM2Cm9mZnNldDogLTI4ODAwMDAwCg\"", "url": "http://currentlyunderdevelopment.blogspot.com/2015/11/so-i-guess-i-reinvented-wordpress-or.html", "selfLink": "https://www.googleapis.com/blogger/v3/blogs/2793398838126095496/posts/8568975944934760082", "title": "So I guess I reinvented WordPress or something", "content": "\u003cspan style=\"font-family: inherit;\"\u003eIt's embarrassing to say I guess, but I took a look at WordPress once or twice and never figured out how to get started. And I suppose I had some resistance to it, because I had an inkling that it was going to restrict what I could do as a web developer. Rightly or wrongly.\u003c/span\u003e\u003cbr /\u003e\n\u003cspan style=\"font-family: inherit;\"\u003e\u003cbr /\u003e\u003c/span\u003e\n\u003cspan style=\"font-family: inherit;\"\u003eAnyway, I made a pretty simple web development framework that extracts content from a blog using \u003ca href=\"https://developers.google.com/blogger/\" target=\"_blank\"\u003eGoogle's API\u003c/a\u003e and presents it in the website of your choice. I built in originally for \u003ca href=\"http://www.rachaelnewmanmft.com/\" target=\"_blank\"\u003emy wife's website\u003c/a\u003e but reused it for my own website just now. So this is \u003ca href=\"http://currentlyunderdevelopment.blogspot.com/\" target=\"_blank\"\u003emy blog\u003c/a\u003e and this is \u003ca href=\"http://www.scottschaferenterprises.com/\" target=\"_blank\"\u003emy website\u003c/a\u003e, and the website automatically gets the content from the blog posts. It should work with SEO as well, since the content is injected server side.\u003c/span\u003e\u003cbr /\u003e\n\u003cspan style=\"font-family: inherit;\"\u003e\u003cbr /\u003e\u003c/span\u003e\n\u003cspan style=\"font-family: inherit;\"\u003eThe way this works is that a PHP script calls the Google blogger API to get the blog posts, injects it into the HTML and then Javascript on the client side parses and presents it. Why not just handle all the formatting in PHP? Because I learned just enough PHP to call an API and inject the results into a template, that's why. It's a bit quick and dirty, but it does the trick.\u003c/span\u003e\u003cbr /\u003e\n\u003cspan style=\"font-family: inherit;\"\u003e\u003cbr /\u003e\u003c/span\u003e\n\u003cspan style=\"font-family: inherit;\"\u003eThe code is on github (\u003ca href=\"https://github.com/scottschafer/blogger2website\"\u003ehttps://github.com/scottschafer/blogger2website\u003c/a\u003e) although I've removed sensitive information (the blog id and access key) from the PHP file.\u003c/span\u003e", "author": { "id": "g112717159621076070821", "displayName": "Scott Schafer", "url": "https://www.blogger.com/profile/16894652095365231201", "image": { "url": "//lh3.googleusercontent.com/-jFDZBEADuiE/AAAAAAAAAAI/AAAAAAAAKEE/1_m2xLHmLkI/s35-c/photo.jpg" } }, "replies": { "totalItems": "0", "selfLink": "https://www.googleapis.com/blogger/v3/blogs/2793398838126095496/posts/8568975944934760082/comments" } }, { "kind": "blogger#post", "id": "4196187916128543477", "blog": { "id": "2793398838126095496" }, "published": "2015-11-18T17:06:00-08:00", "updated": "2015-11-19T22:25:00-08:00", "etag": "\"h3phi6z0oROkI1XWpXsALUFHLuA/dGltZXN0YW1wOiAxNDQ4MDAwNzAwMTA2Cm9mZnNldDogLTI4ODAwMDAwCg\"", "url": "http://currentlyunderdevelopment.blogspot.com/2015/11/the-end-is-near-again.html", "selfLink": "https://www.googleapis.com/blogger/v3/blogs/2793398838126095496/posts/4196187916128543477", "title": "The end is near! (again)", "content": "\u003cspan style=\"font-family: inherit;\"\u003eI do tend towards apocalyptic thinking, so I when I tried to come up with a demonstration of how to build an application with a yeoman generator I thought to make a simple Doomsday clock. \u003ca href=\"http://doomsday-clock.herokuapp.com/#!/\" target=\"_blank\"\u003eHere it is\u003c/a\u003e.\u003c/span\u003e\u003cbr /\u003e\n\u003cspan style=\"font-family: inherit;\"\u003e\u003cbr /\u003e\u003c/span\u003e\n\u003cspan style=\"font-family: inherit;\"\u003eIt's inspired by \u003c/span\u003e\u003ca href=\"https://en.wikipedia.org/wiki/List_of_dates_predicted_for_apocalyptic_events\" style=\"font-family: inherit;\" target=\"_blank\"\u003ethis wikipedia\u003c/a\u003e\u003cspan style=\"font-family: inherit;\"\u003e page but gives you what you really need to know: how much time we have left until the world ends. And in case it doesn't, the time until the next one. If you're signed in you can also add and edit your own apocalypses to keep us all posted. Note that you can sign in using username \"task\" and password \"testtest\", or sign up to create a new account, but the social sign in doesn't actually work.\u003c/span\u003e\u003cbr /\u003e\n\u003cspan style=\"font-family: inherit;\"\u003e\u003cbr /\u003e\u003c/span\u003e\n\u003cspan style=\"font-family: inherit;\"\u003e The application (both front and backend) was generated with this (somewhat old but still useful) yeoman based tool: \u003c/span\u003e\u003cspan style=\"font-family: inherit;\"\u003e\u003ca href=\"https://github.com/meanjs/generator-meanjs\"\u003ehttps://github.com/meanjs/generator-meanjs\u003c/a\u003e.\u003c/span\u003e\u003cbr /\u003e\n\u003cspan style=\"font-family: inherit;\"\u003e\u003cbr /\u003e\u003c/span\u003e\n\u003cspan style=\"font-family: inherit;\"\u003e Here’s the source code at various points. You can click on the links below to see the code at various points (thanks to the power of github). Note that I didn't write a line of code until the last step.\u003c/span\u003e\u003cbr /\u003e\n\u003cspan style=\"font-family: inherit;\"\u003e\u003cbr /\u003e\u003c/span\u003e\n\u003cspan style=\"font-family: inherit;\"\u003e \u003ca href=\"https://github.com/scottschafer/doomsday-clock/commit/ecc73468341a01d208d8acb259822f0024852f1f\" target=\"_blank\"\u003eStep 1 - Initial generation\u003c/a\u003e\u003c/span\u003e\u003cbr /\u003e\n\u003cspan style=\"font-family: inherit;\"\u003eThis is the project that was generated by running \u003cb\u003eyo meanjs\u003c/b\u003e. It includes a backend (running on NodeJS) and front end component, as well as build scripts that are configured to compile LESS files, minimize JS/CSS/HTML, run unit tests and so on.\u003c/span\u003e\u003cbr /\u003e\n\u003cspan style=\"font-family: inherit;\"\u003e\u003cbr /\u003e\u003c/span\u003e\n\u003cspan style=\"font-family: inherit;\"\u003e \u003ca href=\"https://github.com/scottschafer/doomsday-clock/commit/ecc73468341a01d208d8acb259822f0024852f1f\" target=\"_blank\"\u003eStep 2 - Add Create/Read/Update/Delete (CRUD) module\u003c/a\u003e\u003c/span\u003e\u003cbr /\u003e\n\u003cspan style=\"font-family: inherit;\"\u003eTo model and allow creating, viewing, editing and deleting of apocalypse entities, I ran the following: \u003cb\u003eyo meanjs:crud-module apocalypse\u003c/b\u003e\u003c/span\u003e\u003cbr /\u003e\n\u003cspan style=\"font-family: inherit;\"\u003e\u003cbr /\u003e\u003c/span\u003e\n\u003cspan style=\"font-family: inherit;\"\u003e \u003ca href=\"https://github.com/scottschafer/doomsday-clock/commit/ec7012eb294d2ce9c00586e17c3341dbfb1f4577\" target=\"_blank\"\u003eStep 3 - Add clock directive\u003c/a\u003e\u003c/span\u003e\u003cbr /\u003e\n\u003cspan style=\"font-family: inherit;\"\u003eIn order to see how much time we have left, I wanted to create a simple clock directive. To scaffold it, I ran: \u003cb\u003eyo meanjs:angular-directive clock\u003c/b\u003e\u003c/span\u003e\u003cbr /\u003e\n\u003cspan style=\"font-family: inherit;\"\u003e\u003cbr /\u003e\u003c/span\u003e\n\u003cspan style=\"font-family: inherit;\"\u003e \u003ca href=\"https://github.com/scottschafer/doomsday-clock/compare/ec7012eb294d2ce9c00586e17c3341dbfb1f4577...1946228982f6c58d6d20728aa97ec71727e2c5d3?w=1\" target=\"_blank\"\u003eStep 4 - Custom code\u003c/a\u003e\u003c/span\u003e\u003cbr /\u003e\n\u003cspan style=\"font-family: inherit;\"\u003eUp until now, all code has been automatically generated with the meanjs tool. This commit contains all the code to customize the apocalypse schema, the UI for editing and for viewing the next upcoming apocalypse. As you can see, it’s not a lot of code!\u003c/span\u003e", "author": { "id": "g112717159621076070821", "displayName": "Scott Schafer", "url": "https://www.blogger.com/profile/16894652095365231201", "image": { "url": "//lh3.googleusercontent.com/-jFDZBEADuiE/AAAAAAAAAAI/AAAAAAAAKEE/1_m2xLHmLkI/s35-c/photo.jpg" } }, "replies": { "totalItems": "0", "selfLink": "https://www.googleapis.com/blogger/v3/blogs/2793398838126095496/posts/4196187916128543477/comments" } }, { "kind": "blogger#post", "id": "7988958499533896940", "blog": { "id": "2793398838126095496" }, "published": "2015-02-27T22:34:00-08:00", "updated": "2015-02-27T22:44:38-08:00", "etag": "\"h3phi6z0oROkI1XWpXsALUFHLuA/dGltZXN0YW1wOiAxNDI1MTA1ODc4ODM4Cm9mZnNldDogLTI4ODAwMDAwCg\"", "url": "http://currentlyunderdevelopment.blogspot.com/2015/02/more-nonsense-with-mean-stack-for-fun.html", "selfLink": "https://www.googleapis.com/blogger/v3/blogs/2793398838126095496/posts/7988958499533896940", "title": "More nonsense with the MEAN stack, for fun and...um...", "content": "Ok, so I built a simple shell of an ecommerce site in AngularJS. It's really just the front end, and I whipped this out in a day and a half, so don't expect wonders, but I think it could be reasonably turned into production code.\u003cbr /\u003e\n\u003cbr /\u003e\nI would *love* to hear feedback, particularly constructive feedback as to how this could be improved.\u003cbr /\u003e\n\u003cbr /\u003e\n\u003ca href=\"https://github.com/scottschafer/BespokeCarservice\" target=\"_blank\"\u003eOn github\u003c/a\u003e.\u003cbr /\u003e\n\u003cbr /\u003e\n\u003ca href=\"https://bespokecarservice.herokuapp.com\" target=\"_blank\"\u003eLive on heroku\u003c/a\u003e\n", "author": { "id": "g112717159621076070821", "displayName": "Scott Schafer", "url": "https://www.blogger.com/profile/16894652095365231201", "image": { "url": "//lh3.googleusercontent.com/-jFDZBEADuiE/AAAAAAAAAAI/AAAAAAAAKEE/1_m2xLHmLkI/s35-c/photo.jpg" } }, "replies": { "totalItems": "0", "selfLink": "https://www.googleapis.com/blogger/v3/blogs/2793398838126095496/posts/7988958499533896940/comments" } }, { "kind": "blogger#post", "id": "1275285603586515203", "blog": { "id": "2793398838126095496" }, "published": "2015-02-16T21:48:00-08:00", "updated": "2015-02-16T21:58:39-08:00", "etag": "\"h3phi6z0oROkI1XWpXsALUFHLuA/dGltZXN0YW1wOiAxNDI0MTUyNzE5NjU1Cm9mZnNldDogLTI4ODAwMDAwCg\"", "url": "http://currentlyunderdevelopment.blogspot.com/2015/02/adventures-with-mean-stack.html", "selfLink": "https://www.googleapis.com/blogger/v3/blogs/2793398838126095496/posts/1275285603586515203", "title": "Adventures with the MEAN stack", "content": "I've been working across the stack for years now, but I've never written a complete web application from start to end. Until now, that is!\u003cbr /\u003e\n\u003cbr /\u003e\nPresenting \u003ca href=\"https://squirreltv.herokuapp.com/\"\u003eSquirrelTV\u003c/a\u003e!\u003cbr /\u003e\n\u003cbr /\u003e\nIt's an experiment in teaching language skills using segments of YouTube clips. You can associate segments of YouTube videos with sentences (persisted on the server) and then play with different sentence structures.\u003cbr /\u003e\n\u003cbr /\u003e\nIt's also quite unfinished, but might be the start of something interesting. I built it with the amazing \u003ca href=\"http://meanjs.org/\"\u003eMean.js\u003c/a\u003e stack and toolset, which makes building quality web apps almost embarrassingly easy.\u003cbr /\u003e\n\u003cbr /\u003e\nSource code available on my \u003ca href=\"https://github.com/scottschafer\" target=\"_blank\"\u003egithub\u003c/a\u003e. ", "author": { "id": "g112717159621076070821", "displayName": "Scott Schafer", "url": "https://www.blogger.com/profile/16894652095365231201", "image": { "url": "//lh3.googleusercontent.com/-jFDZBEADuiE/AAAAAAAAAAI/AAAAAAAAKEE/1_m2xLHmLkI/s35-c/photo.jpg" } }, "replies": { "totalItems": "0", "selfLink": "https://www.googleapis.com/blogger/v3/blogs/2793398838126095496/posts/1275285603586515203/comments" } }, { "kind": "blogger#post", "id": "627622911650376414", "blog": { "id": "2793398838126095496" }, "published": "2015-01-25T14:38:00-08:00", "updated": "2015-01-25T14:38:24-08:00", "etag": "\"h3phi6z0oROkI1XWpXsALUFHLuA/dGltZXN0YW1wOiAxNDIyMjI1NTA0NTI1Cm9mZnNldDogLTI4ODAwMDAwCg\"", "url": "http://currentlyunderdevelopment.blogspot.com/2015/01/particlefuntime-now-with-angularjs.html", "selfLink": "https://www.googleapis.com/blogger/v3/blogs/2793398838126095496/posts/627622911650376414", "title": "ParticleFunTime, now with AngularJS directive", "content": "\u003cp\u003e\u003ca href=\"https://github.com/scottschafer/ParticleFunTime\"\u003eParticleFunTime\u003c/a\u003e now has an AngularJS wrapper - a live example is below.\u003c/p\u003e\n\n\u003ciframe width=\"750\" height=\"750\" frameBorder=\"0\" src=\"https://dl.dropboxusercontent.com/u/7106189/ParticleFunTime/test-ng/test-ng.html\"\u003e\u003c/iframe\u003e", "author": { "id": "g112717159621076070821", "displayName": "Scott Schafer", "url": "https://www.blogger.com/profile/16894652095365231201", "image": { "url": "//lh3.googleusercontent.com/-jFDZBEADuiE/AAAAAAAAAAI/AAAAAAAAKEE/1_m2xLHmLkI/s35-c/photo.jpg" } }, "replies": { "totalItems": "0", "selfLink": "https://www.googleapis.com/blogger/v3/blogs/2793398838126095496/posts/627622911650376414/comments" } } ], "etag": "\"h3phi6z0oROkI1XWpXsALUFHLuA/MjAxNy0wNS0wMlQxODo1MDoyNS40MDla\"" } { "kind": "blogger#pageList", "items": [ { "kind": "blogger#page", "id": "3397178238739023980", "blog": { "id": "2793398838126095496" }, "published": "2015-11-19T09:24:00-08:00", "updated": "2015-11-19T09:24:51-08:00", "etag": "\"h3phi6z0oROkI1XWpXsALUFHLuA/dGltZXN0YW1wOiAxNDQ3OTUzODkxMDE3Cm9mZnNldDogLTI4ODAwMDAwCg\"", "url": "http://currentlyunderdevelopment.blogspot.com/p/about-me.html", "selfLink": "https://www.googleapis.com/blogger/v3/blogs/2793398838126095496/pages/3397178238739023980", "title": "main", "content": "Welcome to my \u003ca href=\"http://currentlyunderdevelopment.blogspot.com/\" target=\"_blank\"\u003eblog\u003c/a\u003e and \u003ca href=\"http://scottschaferenterprises.com/\" target=\"_blank\"\u003ewebsite\u003c/a\u003e. I'm a software developer by trade, though my real love is the sea. Not sure what to write here. Anyway, come back for updates.\u003cbr /\u003e\n\u003cbr /\u003e\nBTW, if you got here through my old \u003ca href=\"https://www.youtube.com/watch?v=GuWJ1ZiwO2g\" target=\"_blank\"\u003eYouTube video\u003c/a\u003e you are probably looking for \u003ca href=\"https://github.com/scottschafer/Micropond\" target=\"_blank\"\u003ethis\u003c/a\u003e, and you might also be interested to watch a more recent (but stalled) effort \u003ca href=\"https://www.youtube.com/watch?v=d8X-3KMsNQc\" target=\"_blank\"\u003ehere\u003c/a\u003e.", "author": { "id": "g112717159621076070821", "displayName": "Scott Schafer", "url": "https://www.blogger.com/profile/16894652095365231201", "image": { "url": "//lh3.googleusercontent.com/-jFDZBEADuiE/AAAAAAAAAAI/AAAAAAAAKEE/1_m2xLHmLkI/s35-c/photo.jpg" } } } ], "etag": "\"h3phi6z0oROkI1XWpXsALUFHLuA/MjAxNy0wNS0wMlQxODo1MDoyNS40MDla\"" }