{"id":4753,"date":"2016-02-16T10:00:00","date_gmt":"2016-02-16T18:00:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/visualstudio\/?p=4753"},"modified":"2019-10-24T17:39:09","modified_gmt":"2019-10-25T00:39:09","slug":"node-js-zero-to-bobble-with-visual-studio-code","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/visualstudio\/node-js-zero-to-bobble-with-visual-studio-code\/","title":{"rendered":"Node.js: From Zero to Bobble with Visual Studio Code"},"content":{"rendered":"<p>Node.js is a platform for building fast, scalable applications using JavaScript. It\u2019s making its way just about everywhere \u2013 from servers, to Internet of Things devices, to desktop applications, to who knows what next?<\/p>\n<p>Ooh\u2014I know what next&#8230;<strong>bobbleheads!<\/strong><\/p>\n<p><img decoding=\"async\" class=\" aligncenter\" style=\"float: none;margin-left: auto;margin-right: auto\" title=\"Satya Nadella bobblehead\" src=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2016\/02\/2016-02-16-BobbleGen-01.gif\" alt=\"Satya Nadella bobblehead\" width=\"640\" height=\"360\" \/><\/p>\n<h2>Bobblehead Generator<\/h2>\n<p>Of course, we don&#8217;t just want one bobblehead&#8230;we want <em>so many <\/em>bobbleheads! So let\u2019s have a bit of fun with Node.js\u2014for beginners and experienced Node developers alike\u2014by implementing a bobblehead generator as follows:<\/p>\n<ol>\n<li>Build a simple web service for uploading images using the popular <code>express<\/code> Node.js web framework.<\/li>\n<li>Do face detection using the artificial intelligence based APIs from Microsoft\u2019s <a href=\"https:\/\/www.projectoxford.ai\/\">Project Oxford<\/a>.<\/li>\n<li>Crop, rotate, and paste the face rectangle onto the original image at various angles.<\/li>\n<li>Combine those images into a GIF!<\/li>\n<\/ol>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/4\/2019\/06\/2016-02-16-BobbleGen-02.png\"><img decoding=\"async\" class=\" aligncenter\" style=\"float: none;padding-top: 0px;padding-left: 0px;margin-left: auto;padding-right: 0px;margin-right: auto;border-width: 0px\" title=\"Overall flow of the Bobblehead Generator\" src=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2016\/02\/2016-02-16-BobbleGen-02.png\" alt=\"Overall flow of the Bobblehead Generator\" width=\"640\" height=\"301\" border=\"0\" \/><\/a><\/p>\n<h2>Ready, set, Node!<\/h2>\n<p>To start, go ahead and install the following:<\/p>\n<ul>\n<li><a href=\"http:\/\/nodejs.org\/\"><b>Node.js v5.x<\/b><\/a>: the latest stable Node.js release, which comes bundled with npm v3 for installing dependencies maximally flat.<\/li>\n<li><a href=\"http:\/\/code.visualstudio.com\/\"><b>Visual Studio Code<\/b><\/a>: Microsoft\u2019s free, cross-platform editor (Windows, OS X, and Linux) that comes with some nifty debugging and IntelliSense features for Node.js.<\/li>\n<li><a href=\"https:\/\/git-scm.com\/downloads\"><b>Git<\/b><\/a>: which we\u2019ll use to deploy our app to Azure.<\/li>\n<\/ul>\n<h2>Scaffolding the application<\/h2>\n<p>First, use <code>npm <\/code>to install the <i>express-generator<\/i> package globally.<\/p>\n<blockquote>\n<pre>C:src&gt; npm install express-generator -g<\/pre>\n<\/blockquote>\n<p>Next, run the following commands (and of course you don\u2019t need to enter the comments!):<\/p>\n<blockquote>\n<pre>C:src&gt; express myapp #generate Express scaffolding in a project folder\nC:src&gt; cd myapp #switch to the project folder\nC:srcmyapp&gt; npm install #install dependencies in package.json\nC:srcmyapp&gt; code . #start Visual Studio Code in this folder!<\/pre>\n<\/blockquote>\n<p>In Visual Studio Code, open the Explore pane on the left hand side to see what&#8217;s been generated.<\/p>\n<p><img decoding=\"async\" class=\" aligncenter\" style=\"float: none;margin-left: auto;margin-right: auto;border-width: 1px\" title=\"Explore pane in Visual Studio Code\" src=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2016\/02\/2016-02-16-BobbleGen-03.png\" alt=\"Explore pane in Visual Studio Code\" border=\"1\" \/><\/p>\n<ul>\n<li><b>package.json<\/b>: lists required 3<sup>rd<\/sup>-party dependencies and other useful configuration info. <code>npm install<\/code> goes through this file to download and installs each dependency automatically.<\/li>\n<li><b>node_modules<\/b>: this is where <code>npm install<\/code> stores all those dependencies.<\/li>\n<li><b>bin\/www<\/b>: the application entry point (<b>www<\/b> is a JavaScript file even though it doesn\u2019t have a .js extension). Note that it uses <code>require('..\/app.js')<\/code> to invoke the code in <b>app.js<\/b> before it goes on to spin up the relevant ports.<\/li>\n<li><b>app.js<\/b>: the application configuration boilerplate.<\/li>\n<li><b>views\/*:<\/b> templates that are rendered as client-side UI; here we\u2019re using the Jade templating engine (see app.js). There are many such engines to choose from, depending on your preference.<\/li>\n<li><b>routes\/*<\/b>: defines how various requests are handled. By default, the generated template handles GET requests to <code>\/<\/code>, and <code>\/users<\/code>.<\/li>\n<\/ul>\n<p>Let\u2019s verify that this newly-scaffolded app is working. Just run <code>node .\/bin\/www<\/code> from the command line, then visit <b>localhost:3000 <\/b>in a browser to see the app running.<\/p>\n<p><img decoding=\"async\" class=\" aligncenter\" style=\"float: none;padding-top: 0px;padding-left: 0px;margin-left: auto;padding-right: 0px;margin-right: auto;border-width: 1px\" src=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2016\/02\/2016-02-16-BobbleGen-04.png\" alt=\"\" width=\"640\" height=\"316\" border=\"1\" \/><\/p>\n<p>Press <code>Ctrl+C<\/code> on the command line to stop the server, because we now need to install a few other npm packages as follows:<\/p>\n<blockquote>\n<pre>C:srcmyapp&gt; npm install --save gifencoder jimp multer png-file-stream project-oxford<\/pre>\n<\/blockquote>\n<p>If you\u2019re new to npm, the <code>--save<\/code> parameter instructs npm to also create entries for these packages in the \u201cdependencies\u201d section of your <b>package.json<\/b>. This way, if you give your source code to other developers without all the packages in <b>node_modules <\/b>(as when you put code in a repo), they can just do <code>npm install<\/code> to quickly download all those dependencies.<\/p>\n<p>Additionally, you can always just add dependencies directly to <code>package.json<\/code>, where Visual Studio Code gives you IntelliSense and auto-complete for available packages and their current versions! Then you can just run <code>npm install<\/code> again to do the work.<\/p>\n<p>Here are two more very helpful npm tips:<\/p>\n<ul>\n<li>To view the documentation for a dependencies, run <code>npm doc &lt;package-name&gt;<\/code><\/li>\n<li>If you use the <code>--save-dev<\/code> parameter instead of <code>--save<\/code>, the dependency is written into a section called \u201cdev-dependencies\u201d. This is where you list packages for development tools like test frameworks and task runners that won\u2019t be included in the deployed application.<\/li>\n<\/ul>\n<h2>Configuring your Editor: debugger launch and IntelliSense<\/h2>\n<p>To minimize context-switching, let&#8217;s configure Visual Studio Code to launch the application directly from the editor. Press <b>F5<\/b> and select the <b>Node.js<\/b> debug engine to automatically generate the <b>.vscode\/launch.json<\/b> configuration file. Now, simply press <b>F5<\/b> again to launch the app with the debugger attached. Set a breakpoint in <b>routes\/index.js<\/b> and try reloading <b>localhost:3000<\/b>. You&#8217;ll find that you can use the debugging pane to inspect the call stack, variables, etc.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/4\/2019\/06\/2016-02-16-BobbleGen-05.png\"><img decoding=\"async\" class=\" aligncenter\" style=\"float: none;padding-top: 0px;padding-left: 0px;margin-left: auto;padding-right: 0px;margin-right: auto;border-width: 0px\" title=\"Inspecting variables in the debugger\" src=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2016\/02\/2016-02-16-BobbleGen-05.png\" alt=\"Inspecting variables in the debugger\" width=\"640\" height=\"243\" border=\"0\" \/><\/a><\/p>\n<p>Visual Studio Code also provides code completion and IntelliSense for Node.js and many popular packages:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/4\/2019\/06\/2016-02-16-BobbleGen-06.png\"><img decoding=\"async\" class=\" aligncenter\" style=\"float: none;padding-top: 0px;padding-left: 0px;margin-left: auto;padding-right: 0px;margin-right: auto;border-width: 0px\" title=\"Code completion and IntelliSense for Node.js\" src=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2016\/02\/2016-02-16-BobbleGen-06.png\" alt=\"Code completion and IntelliSense for Node.js\" width=\"640\" height=\"214\" border=\"0\" \/><\/a><\/p>\n<p>Because JavaScript is a dynamically-typed language, IntelliSense relies heavily on <a href=\"https:\/\/github.com\/Microsoft\/TypeScript\/wiki\/Typings-for-npm-packages\">typings files<\/a> (.d.ts) that are often included with npm packages. The community has also contributed typings files that you install using the <b>tsd<\/b> (TypeScript definitions) package:<\/p>\n<blockquote>\n<pre>C:src&gt; npm install tsd \u2013g\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 #install tsd as a global tool\nC:src&gt; cd myapp\nC:srcmyapp&gt; tsd install express\u00a0\u00a0 #install IntelliSense for express<\/pre>\n<\/blockquote>\n<h2>Uploading a file<\/h2>\n<p>The scaffolding for the application includes a basic Express web service, so let\u2019s have it accept a file upload. First, add a basic browse and upload UI by replacing the contents of <code>views\/index.jade<\/code> with the following template:<\/p>\n<blockquote>\n<pre>&lt;!-- views\/index.jade --&gt;\n\u00a0\n<span style=\"color: #ff4500\">extends<\/span> layout\n\u00a0\n<span style=\"color: #ff4500\">block<\/span> content\n  <span style=\"color: #800000\">div<\/span>(<span style=\"color: #ff0000\">style<\/span><span style=\"color: #0000ff\">='width:400px'<\/span>)\n    <span style=\"color: #800000\">h1<\/span><span style=\"color: #0000ff\">=<\/span> title\n    <span style=\"color: #800000\">p<\/span><span style=\"color: #0000ff\">=<\/span> location\n    <span style=\"color: #800000\">p<\/span> Upload a picture of a head to get started!\n\u00a0\n    <span style=\"color: #800000\">form<\/span>(<span style=\"color: #ff0000\">action<\/span><span style=\"color: #0000ff\">='\/'<\/span>       <span style=\"color: #ff0000\">method<\/span><span style=\"color: #0000ff\">='post'<\/span> <span style=\"color: #ff0000\">enctype<\/span><span style=\"color: #0000ff\">=\"multipart\/form-data\"<\/span>)\n      <span style=\"color: #800000\">input<\/span>(<span style=\"color: #ff0000\">type<\/span><span style=\"color: #0000ff\">=\"file\"<\/span> <span style=\"color: #ff0000\">name<\/span><span style=\"color: #0000ff\">=\"userPhoto\"<\/span>)\n      <span style=\"color: #800000\">input<\/span>(<span style=\"color: #ff0000\">type<\/span><span style=\"color: #0000ff\">=\"submit\"<\/span> <span style=\"color: #ff0000\">value<\/span><span style=\"color: #0000ff\">=\"Upload Image\"<\/span> <span style=\"color: #ff0000\">name<\/span><span style=\"color: #0000ff\">=\"submit\"<\/span>)\n\n    <span style=\"color: #800000\">img<\/span>(<span style=\"color: #ff0000\">src<\/span><span style=\"color: #0000ff\">=<\/span> <span style=\"color: #0000ff\">image<\/span>)\n\n<\/pre>\n<\/blockquote>\n<p>If you restart the app here in Visual Studio code and refresh <b>localhost:3000<\/b> in the browser, the UI is available attempting to upload a file gives you a 404 error because we&#8217;re not yet handling the POST request. To do that, stop the debugger and append the following code to <b>routes\/index.js <\/b>to process the file in <code>req.file.path<\/code>, ultimately to display the output bobblehead on the page.<\/p>\n<blockquote>\n<pre><span style=\"color: #008000\">\/\/ Required Dependencies<\/span>\n<span style=\"color: #0000ff\">var<\/span> fs = <span style=\"color: #0000ff\">require<\/span>(<span style=\"color: #a31515\">'fs'<\/span>);\n<span style=\"color: #0000ff\">var<\/span> oxford = <span style=\"color: #0000ff\">require<\/span>(<span style=\"color: #a31515\">'project-oxford'<\/span>);\n<span style=\"color: #0000ff\">var<\/span> Jimp = <span style=\"color: #0000ff\">require<\/span>(<span style=\"color: #a31515\">'jimp'<\/span>);\n<span style=\"color: #0000ff\">var<\/span> pngFileStream = <span style=\"color: #0000ff\">require<\/span>(<span style=\"color: #a31515\">'png-file-stream'<\/span>);\n<span style=\"color: #0000ff\">var<\/span> GIFEncoder = <span style=\"color: #0000ff\">require<\/span>(<span style=\"color: #a31515\">'gifencoder'<\/span>);\n\n<span style=\"color: #008000\">\/\/ Handle POST request<\/span>\nrouter.post(<span style=\"color: #a31515\">'\/'<\/span>, <span style=\"color: #0000ff\">function<\/span> (req, res, next) {\n\u00a0\u00a0\u00a0 <span style=\"color: #0000ff\">var<\/span> imgSrc = req.file ? req.file.path : <span style=\"color: #a31515\">''<\/span>;\n\u00a0\u00a0\u00a0 Promise.resolve(imgSrc)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 .then(<span style=\"color: #0000ff\">function<\/span> detectFace(image) {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 console.log(<span style=\"color: #a31515\">\"TODO: detect face using Oxford API.\"<\/span>);\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 })\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 .then(<span style=\"color: #0000ff\">function<\/span> generateBobblePermutations (response) {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 console.log(<span style=\"color: #a31515\">\"TODO: generate multiple images with head rotated.\"<\/span>);\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 })\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 .then(<span style=\"color: #0000ff\">function<\/span> generateGif (dimensions) {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 console.log(<span style=\"color: #a31515\">'TODO: generate GIF'<\/span>)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 <span style=\"color: #0000ff\">return<\/span> imgSrc;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 }).then(<span style=\"color: #0000ff\">function<\/span> displayGif(gifLocation) {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 res.render(<span style=\"color: #a31515\">'index'<\/span>, { title: <span style=\"color: #a31515\">'Done!'<\/span>, image: gifLocation })\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 });\n});\n<\/pre>\n<\/blockquote>\n<p>JavaScript&#8217;s asynchronous nature sometimes makes it challenging to follow application flow. Here we\u2019re using the new EcmaScript 6 feature of Promises to sequentially execute <code>detectFace<\/code>, <code>generateBobblePermutations<\/code>, and <code>generateGif<\/code> while keeping our code readable.<\/p>\n<p>Now when you run the app you should see the three TODOs on the console, but we&#8217;re still not saving the file to any particular location. To do that, add the following code to <b>app.js<\/b> right before where the <code>\/<\/code> and <code>\/users<\/code> routes are defined with <code>app.use<\/code> (around like 25):<\/p>\n<blockquote>\n<pre><span style=\"color: #008000\">\/\/ Expose files available in public\/images so they can be viewed in the browser. <\/span>\napp.use(<span style=\"color: #a31515\">'\/public\/images'<\/span>, express.static(<span style=\"color: #a31515\">'public\/images'<\/span>));\n\n<span style=\"color: #008000\">\/\/ Use multer middleware to upload a photo to public\/images<\/span>\n<span style=\"color: #0000ff\">var<\/span> multer = <span style=\"color: #0000ff\">require<\/span>(<span style=\"color: #a31515\">'multer'<\/span>);\napp.use(multer({dest: <span style=\"color: #a31515\">'.\/public\/images'<\/span>}).single(<span style=\"color: #a31515\">'userPhoto'<\/span>));\n<\/pre>\n<\/blockquote>\n<p>With this, restart the application and you\u2019ll see it render an uploaded photo, which is stored in <b>public\/images<\/b>.<\/p>\n<h2>Detect the face<\/h2>\n<p>It sounds like a lot of work, but fortunately this kind of artificial intelligence is ready accessible through the Face APIs of <a href=\"https:\/\/www.projectoxford.ai\/\">Project Oxford<\/a>. In <b>routes\/index.js, <\/b>make the <code>detectFace<\/code> function in the promise chain look like the following:<\/p>\n<blockquote>\n<pre><span style=\"color: #0000ff\">function<\/span> detectFace(image) {\n\u00a0\u00a0\u00a0 <span style=\"color: #0000ff\">var<\/span> client = <span style=\"color: #0000ff\">new<\/span> oxford.Client(process.env.OXFORD_API);\n\u00a0\u00a0\u00a0 <span style=\"color: #0000ff\">return<\/span> client.face.detect({path: image});\n}\n<\/pre>\n<\/blockquote>\n<p>As you can see, you&#8217;ll need an API key retrieved from the <b>OXFORD_API<\/b> environment variable to use the Project Oxford client. <a href=\"https:\/\/www.projectoxford.ai\/Account\/Login?callbackUrl=\/Subscription\/Index?productId=\/products\/54d85c5b5eefd00dc474a0f0\">Click here to sign up (free)<\/a>, then request an also-free Face API key. This will appear on your subscriptions page (click <b>Show<\/b> to see the key): <a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/4\/2019\/06\/2016-02-16-BobbleGen-07.png\"><img decoding=\"async\" class=\" aligncenter\" style=\"float: none;padding-top: 0px;padding-left: 0px;margin-left: auto;padding-right: 0px;margin-right: auto;border-width: 0px\" title=\"API keys for Project Oxford\" src=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2016\/02\/2016-02-16-BobbleGen-07.png\" alt=\"API keys for Project Oxford\" width=\"640\" height=\"201\" border=\"0\" \/><\/a> Next set the <b>OXFORD_API<\/b> environment variable on your machine to the Primary Key value, so that it is available to your code through the <code>process.env.OXFORD_API<\/code> property. (Note: you may need to restart Visual Studio Code after setting the variable for it to be picked up.) This is generally a much better practice than pasting a secure key into code that might be publicly visible in a repository.) Now set a breakpoint on the <code>console.log<\/code> call within the <code>generateBobblePermutations<\/code> step, run the application, and verify that face detection worked by checking <code>response[0].faceRectangle<\/code>. (Again, restart Visual Studio Code if you see an error about the API key not being there.) <a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/4\/2019\/06\/2016-02-16-BobbleGen-08.png\"><img decoding=\"async\" class=\" aligncenter\" style=\"float: none;padding-top: 0px;padding-left: 0px;margin-left: auto;padding-right: 0px;margin-right: auto;border-width: 0px\" title=\"Verifying that face detection works by checking response[0].faceRectangle\" src=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2016\/02\/2016-02-16-BobbleGen-08.png\" alt=\"Verifying that face detection works by checking response[0].faceRectangle\" width=\"640\" height=\"119\" border=\"0\" \/><\/a> The Project Oxford APIs are pretty neat, so definitely explore the other APIs and options you can set. For instance, passing the following options into <code>client.face.detect<\/code> tries Project Oxford&#8217;s hand at guessing an age and gender for the person in the photo (this is the same technology that powers <a href=\"https:\/\/how-old.net\/\">https:\/\/how-old.net\/<\/a>).<\/p>\n<blockquote>\n<pre>{\n\u00a0\u00a0\u00a0 path: image,\n\u00a0\u00a0\u00a0 analyzesAge: true,\n\u00a0\u00a0\u00a0 analyzesGender: true\n}\n<\/pre>\n<\/blockquote>\n<h2>Crop, rotate, and paste the face in various configurations<\/h2>\n<p>To produce an animated bobblehead GIF, we&#8217;ll create three images with different rotations of the detected face area. For this, paste the code below in place of the <code>generateBobblePermutations<\/code> function in <b>routes\/index.js<\/b>:<\/p>\n<blockquote>\n<pre><span style=\"color: #0000ff\">function<\/span> generateBobblePermutations(response) {\n \u00a0\u00a0\u00a0 <span style=\"color: #0000ff\">var<\/span> promises = [];\n \u00a0\u00a0\u00a0 <span style=\"color: #0000ff\">var<\/span> degrees = [<span style=\"color: #09885a\">10<\/span>, <span style=\"color: #09885a\">0<\/span>, -<span style=\"color: #09885a\">10<\/span>];\n\n<span style=\"color: #0000ff\">\u00a0 \u00a0 \u00a0    for<\/span> (<span style=\"color: #0000ff\">var<\/span> i = <span style=\"color: #09885a\">0<\/span>; i &lt; degrees.length; i++) {\n<span style=\"color: #0000ff\">             var<\/span> outputName = req.file.path + <span style=\"color: #a31515\">'-'<\/span> + i + <span style=\"color: #a31515\">'.png'<\/span>;\n             promises.push(cropHeadAndPasteRotated(req.file.path,\n                 response[<span style=\"color: #09885a\">0<\/span>].faceRectangle, degrees[i], outputName))\n         }\n<span style=\"color: #0000ff\">    return<\/span> Promise.all(promises);\n}<\/pre>\n<\/blockquote>\n<p>The workhorse here is the following <code>cropHeadAndPasteRotated<\/code> function that you need to append to <b>routes\/index.js<\/b>:<\/p>\n<blockquote>\n<pre><span style=\"color: #0000ff\">function<\/span> cropHeadAndPasteRotated(inputFile, faceRectangle, degrees, outputName) {\n\u00a0\u00a0\u00a0 <span style=\"color: #0000ff\">return<\/span> <span style=\"color: #0000ff\">new<\/span> Promise (<span style=\"color: #0000ff\">function<\/span> (resolve, reject) {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Jimp.read(inputFile).then(<span style=\"color: #0000ff\">function<\/span> (image) {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 <span style=\"color: #008000\">\/\/ Face detection only captures a small portion of the face,<\/span>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 <span style=\"color: #008000\">\/\/ so compensate for this by expanding the area appropriately.<\/span>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 <span style=\"color: #0000ff\">var<\/span> height = faceRectangle[<span style=\"color: #a31515\">'height'<\/span>];\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 <span style=\"color: #0000ff\">var<\/span> top = faceRectangle[<span style=\"color: #a31515\">'top'<\/span>] - height * <span style=\"color: #09885a\">0.5<\/span>;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 height *= <span style=\"color: #09885a\">1.6<\/span>;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 <span style=\"color: #0000ff\">var<\/span> left = faceRectangle[<span style=\"color: #a31515\">'left'<\/span>];\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 <span style=\"color: #0000ff\">var<\/span> width = faceRectangle[<span style=\"color: #a31515\">'width'<\/span>];\n<span style=\"color: #a31515\">\u00a0<\/span>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 <span style=\"color: #008000\">\/\/ Crop head, scale up slightly, rotate, and paste on original image<\/span>\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 image.crop(left, top, width, height)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 .scale(<span style=\"color: #09885a\">1.05<\/span>)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 .rotate(degrees, <span style=\"color: #0000ff\">function<\/span>(err, rotated) {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 Jimp.read(inputFile).then(<span style=\"color: #0000ff\">function<\/span> (original) {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 original.composite(rotated, left-<span style=\"color: #09885a\">0.1<\/span>*width, top-<span style=\"color: #09885a\">0.05<\/span>*height)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 .write(outputName, <span style=\"color: #0000ff\">function<\/span> () {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 resolve([original.bitmap.width, original.bitmap.height]);\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 });\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 });\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 });\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 });\n\u00a0\u00a0\u00a0 });\n}\n<\/pre>\n<\/blockquote>\n<p>This function reads the uploaded image, then expands the boundaries of <code>faceRectangle<\/code> to capture the full head (rather than just a portion of the face). We then crop this area, scale it up a bit, rotate it, and paste back to the original image.<\/p>\n<p>Because we\u2019re doing asynchronous work here, the images created by from <code>cropHeadAndPasteRotated<\/code> are not available immediately. This is why we call <code>resolve<\/code> to inform the application that the file has been written successfully.<\/p>\n<p>Running the application now, you&#8217;ll find three PNG files in <code>public\/images<\/code> alongside the original image. You can click on these in Visual Studio Code to see them directly in the editor.<\/p>\n<h2>Produce a GIF<\/h2>\n<p>We\u2019re ready for the final step! We&#8217;ll use the <b>gifencoder<\/b> and <b>png-file-stream<\/b> libraries (we installed these with npm earlier) to compose the images generated above into a single GIF. Just replace the <code>generateGif<\/code> code in <b>routes\/index.js<\/b> with the following:<\/p>\n<blockquote>\n<pre><span style=\"color: #0000ff\">function<\/span> generateGif(dimensions) {\n\u00a0\u00a0\u00a0 <span style=\"color: #0000ff\">return<\/span> <span style=\"color: #0000ff\">new<\/span> Promise(<span style=\"color: #0000ff\">function<\/span> (resolve, reject) {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 <span style=\"color: #0000ff\">var<\/span> encoder = <span style=\"color: #0000ff\">new<\/span> GIFEncoder(dimensions[<span style=\"color: #09885a\">0<\/span>][<span style=\"color: #09885a\">0<\/span>], dimensions[<span style=\"color: #09885a\">0<\/span>][<span style=\"color: #09885a\">1<\/span>]);\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 pngFileStream(req.file.path + <span style=\"color: #a31515\">'-?.png'<\/span>)\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 .pipe(encoder.createWriteStream({ repeat: <span style=\"color: #09885a\">0<\/span>, delay: <span style=\"color: #09885a\">500<\/span> }))\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 .pipe(fs.createWriteStream(req.file.path + <span style=\"color: #a31515\">'.gif'<\/span>))\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 .on(<span style=\"color: #a31515\">'finish'<\/span>, <span style=\"color: #0000ff\">function<\/span> () {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 resolve(req.file.path + <span style=\"color: #a31515\">'.gif'<\/span>);\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 });\n\u00a0\u00a0\u00a0 })\n}<\/pre>\n<\/blockquote>\n<p>Go ahead, run the code, and start generating bobbleheads!<\/p>\n<p><img decoding=\"async\" class=\" aligncenter\" style=\"float: none;padding-top: 0px;padding-left: 0px;margin-left: auto;padding-right: 0px;margin-right: auto;border-width: 0px\" title=\"Locally running bobblehead generator\" src=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2016\/02\/2016-02-16-BobbleGen-09.png\" alt=\"Locally running bobblehead generator\" width=\"582\" height=\"480\" border=\"1\" \/><\/p>\n<h2>To the cloud!<\/h2>\n<p>There&#8217;s no way we&#8217;re going to achieve viral-quality bobbleheads with a mere locally-running app, so let&#8217;s see what we can do about that by using Git Deploy to deploy our app to Azure.<\/p>\n<p>To initalize our repository, open the <b>Git<\/b> pane on the left side of Visual Studio Code and select <code>Initialize git repository<\/code>:<\/p>\n<p align=\"center\"><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/4\/2019\/06\/2016-02-16-BobbleGen-10.png\"><img decoding=\"async\" style=\"padding-top: 0px;padding-left: 0px;padding-right: 0px;border-width: 0px\" title=\"Git pane in Visual Studio Code, initialization step\" src=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2016\/02\/2016-02-16-BobbleGen-10.png\" alt=\"Git pane in Visual Studio Code, initialization step\" width=\"278\" height=\"202\" border=\"0\" \/><\/a>\u00a0<a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/4\/2019\/06\/2016-02-16-BobbleGen-11.png\"><img decoding=\"async\" style=\"padding-top: 0px;padding-left: 0px;padding-right: 0px;border-width: 0px\" title=\"Git pane in Visual Studio Code showing changes\" src=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2016\/02\/2016-02-16-BobbleGen-11.png\" alt=\"Git pane in Visual Studio Code showing changes\" width=\"304\" height=\"208\" border=\"0\" \/><\/a><\/p>\n<p>\u00a0Whoa. <i>1000\u2019s of changes??<\/i> That&#8217;s way too much. Let&#8217;s cut that down a bit. Create a file in the project root with the File &gt; New File command (Ctrl+N), paste in the text below, and save the file as <code>.gitignore<\/code>:<\/p>\n<blockquote>\n<pre># .gitignore\n\u00a0\nnode_modules\npublic\/images\n<\/pre>\n<\/blockquote>\n<p>That\u2019s better! We don\u2019t need to add all the packages in <b>node_modules<\/b> to the repo, and we can certainly ignore our uploaded and generated test images. In the Git pane, now you\u2019ll see just a few files to commit to your local repo, entering a message and clicking the checkmark:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/4\/2019\/06\/2016-02-16-BobbleGen-12.png\"><img decoding=\"async\" class=\" aligncenter\" style=\"float: none;padding-top: 0px;padding-left: 0px;margin-left: auto;padding-right: 0px;margin-right: auto;border-width: 0px\" title=\"Commit code to Git in Visual Studio Code\" src=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2016\/02\/2016-02-16-BobbleGen-12.png\" alt=\"Commit code to Git in Visual Studio Code\" border=\"0\" \/><\/a><\/p>\n<p>Next, head on over to <a href=\"https:\/\/try.azurewebsites.net\">https:\/\/try.azurewebsites.net<\/a> to create a free one-hour trial website:<\/p>\n<ul>\n<li>Select <b>Web App <\/b>for the app type and click Next.<\/li>\n<li>Select <b>Empty Site <\/b>for the template and click Create<\/li>\n<li>Select a login provider, and in a few moments you\u2019ll have a new site to use for the next hour!<\/li>\n<\/ul>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/4\/2019\/06\/2016-02-16-BobbleGen-13.png\"><img decoding=\"async\" class=\" aligncenter\" style=\"float: none;padding-top: 0px;padding-left: 0px;margin-left: auto;padding-right: 0px;margin-right: auto;border-width: 0px\" title=\"Portal for try.azurewebsites.net after creating an web app\" src=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2016\/02\/2016-02-16-BobbleGen-13.png\" alt=\"Portal for try.azurewebsites.net after creating an web app\" width=\"640\" height=\"291\" border=\"0\" \/><\/a><\/p>\n<p>Now, grab the git url for your web app (as outlined above), and push your code to the remote repository using the following command, replacing <i>&lt;git url&gt;<\/i> with the long bit you just copied from the portal:<\/p>\n<blockquote>\n<pre>C:srcmyapp&gt; git push --set-upstream <i>&lt;git url&gt; <\/i>master<code><\/code><\/pre>\n<\/blockquote>\n<p>The command window shows the status of your deployment. Especially notice that in addition to copying the files in your project, Azure automatically runs an <code>npm install<\/code> for all your required dependencies as specified in <code>package.json<\/code>. Remember earlier that by listing all your dependencies in package.json, anyone who gets your source code without everything in <b>node_modules<\/b> can easily restore all the required packages. Deploying to Azure works exactly the same way, and it\u2019s why you don\u2019t need to add everything under node_modules to the repo.<\/p>\n<p>Now although you can visit this new site, you won&#8217;t be able to generate the bobblehead just yet because the <b>OXFORD_API<\/b> environment variable is not set. Azure&#8217;s temporary 1-hour sites do not permit you to set environment variables, so we\u2019ll just edit <b>routes\/index.js<\/b> directly and drop in the primary key. To do this, click the \u201cEdit with Visual Studio Online \u2018Monaco\u2019\u201d link:<\/p>\n<p><img decoding=\"async\" class=\" aligncenter\" style=\"float: none;padding-top: 0px;padding-left: 0px;margin-left: auto;padding-right: 0px;margin-right: auto;border-width: 0px\" title=\"Edit with Visual Studio Online &quot;Monaco&quot; link\" src=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2016\/02\/2016-02-16-BobbleGen-14-e1455564214671.png\" alt=\"Edit with Visual Studio Online &quot;Monaco&quot; link\" border=\"0\" \/><\/p>\n<p>This takes you to an editor interface that looks very much like Visual Studio Code\u2014open the Explore pane, navigate to <b>routes\/index.js<\/b>, and paste in your primary key in quotes. Your change will be automatically saved:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/4\/2019\/06\/2016-02-16-BobbleGen-15.png\"><img decoding=\"async\" class=\" aligncenter\" style=\"float: none;padding-top: 0px;padding-left: 0px;margin-left: auto;padding-right: 0px;margin-right: auto;border-width: 0px\" title=\"Editing in Visual Studo Online &quot;Monaco&quot; to hard-code the primary key\" src=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2016\/02\/2016-02-16-BobbleGen-15.png\" alt=\"Editing in Visual Studo Online &quot;Monaco&quot; to hard-code the primary key\" width=\"640\" height=\"207\" border=\"0\" \/><\/a><\/p>\n<p>Now in the browser, click on the URL after <b>Work with your web app at \u2026 <\/b>and Bobble away! (I\u2019d suggest you can share your bobbleheard generator with the world, but you probably have only about 35 minutes left!)<\/p>\n<h2>Next steps<\/h2>\n<p>Our bobblehead generator is clearly demo-ware and nowhere close to production ready. Here are some things you can do to take it in that direction:<\/p>\n<ul>\n<li>Try refactoring and separating out some of the code into separate modules.<\/li>\n<li>Try passing in different image types, or images with multiple or no faces, etc. Debug any issues you run into using Visual Studio Code, and see how you might be able to do even better!<\/li>\n<li>Instead of saving images locally, try playing around with the Azure Storage APIs or MongoDB.<\/li>\n<li>Explore npmjs.com and find other useful packages to play around with, or\u2014better yet\u2014 publish your own!<\/li>\n<\/ul>\n<p>Be sure to also check out the following set of resources that should help you along the way:<\/p>\n<ul>\n<li><a href=\"https:\/\/code.visualstudio.com\"><b>Visual Studio Code<\/b><\/a>: our new lightweight and cross-platform editor that offers powerful debugging and IntelliSense for Node.js.<\/li>\n<li><a href=\"https:\/\/www.visualstudio.com\/features\/node-js-vs\"><b>Node.js Tools for Visual Studio<\/b><\/a><b> (NTVS)<\/b>: Can&#8217;t get enough of Visual Studio? NTVS is free, open-source extension that turns Visual Studio into a full-blown Node.js IDE.<\/li>\n<li><a href=\"https:\/\/github.com\/Microsoft\/nodejs-guidelines\"><b>Microsoft\/nodejs-guidelines<\/b><\/a>: A helpful set of tips and tricks for using Node.js, as well as links to some of the other cool Node.js efforts going on at Microsoft.<\/li>\n<\/ul>\n<h3>Questions, compliments, complaints?<\/h3>\n<p>We&#8217;d love to hear your feedback. Please comment below or shoot me a <a href=\"https:\/\/twitter.com\/mousetraps\">tweet<\/a>!\u00a0ALso be sure to check out <a href=\"https:\/\/blogs.msdn.microsoft.com\/visualstudio\/2016\/02\/17\/10-things-you-should-try-on-the-leap-day\/\">the other nine (or ten) things to\u00a0try on the leap day<\/a>!<\/p>\n<table style=\"width: 620px\" border=\"0\" cellspacing=\"0\" cellpadding=\"2\">\n<tbody>\n<tr>\n<td valign=\"top\" width=\"181\"><img decoding=\"async\" title=\"Sara Itani\" src=\"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-content\/uploads\/sites\/4\/2016\/02\/Sara-Itani-Bobble.gif\" alt=\"Sara Itani\" \/><\/td>\n<td valign=\"top\" width=\"439\"><strong>Sara Itani <\/strong><em>(<\/em><a href=\"https:\/\/twitter.com\/mousetraps\"><i>@mousetraps<\/i><\/a><em>)<\/em>, Software Engineer, Node.js Tools\nSara is an engineer focused on building best-of-breed Node.js experiences for Visual Studio and VS Code. At first, she was skeptical about Node.js \u2013 that is, until she realized its full potential\u2026. Now, she\u2019s all in, and excited to help it take over the world by bringing the power of Visual Studio to the Node.js community. She, for one, welcomes our new JavaScript overlords. \ud83d\ude42<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n","protected":false},"excerpt":{"rendered":"<p>Node.js is a platform for building fast, scalable applications using JavaScript. It\u2019s making its way just about everywhere \u2013 from servers, to Internet of Things devices, to desktop applications, to who knows what next? Ooh\u2014I know what next&#8230;bobbleheads! Bobblehead Generator Of course, we don&#8217;t just want one bobblehead&#8230;we want so many bobbleheads! So let\u2019s have [&hellip;]<\/p>\n","protected":false},"author":13,"featured_media":255385,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1085,1195,1030,1196,472,4980,155,1029],"tags":[237,1055,242,9,376,124,185,125,182,12,196],"class_list":["post-4753","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-cloud","category-cross-platform","category-data","category-desktop","category-gaming","category-java","category-visual-studio","category-web","tag-net","tag-ai","tag-azure","tag-debug","tag-java","tag-javascript","tag-node-js","tag-typescript","tag-unity","tag-visual-studio","tag-visual-studio-2015"],"acf":[],"blog_post_summary":"<p>Node.js is a platform for building fast, scalable applications using JavaScript. It\u2019s making its way just about everywhere \u2013 from servers, to Internet of Things devices, to desktop applications, to who knows what next? Ooh\u2014I know what next&#8230;bobbleheads! Bobblehead Generator Of course, we don&#8217;t just want one bobblehead&#8230;we want so many bobbleheads! So let\u2019s have [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/posts\/4753","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/users\/13"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/comments?post=4753"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/posts\/4753\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/media\/255385"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/media?parent=4753"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/categories?post=4753"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/visualstudio\/wp-json\/wp\/v2\/tags?post=4753"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}