RottenNeighbor featured in Google’s Top 5 Trends

RottenNeighbor climbed into the top 5 Google Hot Trends today and caused a huge surge of traffic on the site. Since its launch, RottenNeighbor.com has averaged several hundred thousand hits per day and been featured in over 200 media outlets courtesy of the Associated Press. Read more


RottenNeighbor featured on the AP Newswire

AP Newswire featured RottenNeighbor today as a “website seemingly tailor-made for such suburban woes.” The article covered some of the most popular posts on the site, discussed changing neighborhood trends demonstrated on RottenNeighbor, and touched on the possibility of a reality show based on the site. The story was picked up by more than 200 media outlets including CNN.com. To read more on this story, click here. Read more


Exploring Data with Serverless and Vue: Filtering and Using the Data

In this second article of this tutorial, we'll take the data we got from our serverless function and use Vue and Vuex to disseminate the data, update our table, and modify the data to use in our WebGL globe. This article assumes some base knowledge of Vue. By far the coolest/most useful thing we'll address in this article is the use of the computed properties in Vue.js to create the performant filtering of the table. Read on!

Article Series:

Automatically Update GitHub Files With Serverless Functions
Filtering and Using the Data (you are here!)

You can check out the live demo here, or explore the code on GitHub.
First, we'll spin up an entire Vue app with server-side rendering, routing, and code-splitting with a tool called Nuxt. (This is similar to Zeit's Next.js for React). If you don't already have the Vue CLI tool installed, run
npm install -g vue-cli
# or
yarn global add vue-cli
This installs the Vue CLI globally so that we can use it whenever we wish. Then we'll run:
vue init nuxt/starter my-project
cd my-project
yarn
That creates this application in particular. Now we can kick off our local dev server with:
npm run dev
If you're not already familiar with Vuex, it's similar to React's Redux. There's more in depth information on what it is and does in this article here.
import Vuex from 'vuex';
import speakerData from './../assets/cda-data.json';

const createStore = () => {
return new Vuex.Store({
state: {
speakingColumns: ['Name', 'Conference', 'From', 'To', 'Location'],
speakerData
}
});
};

export default createStore;
Here, we're pulling the speaker data from our `cda.json` file that has now been updated with latitude and longitude from our Serverless function. As we import it, we're going to store it in our state so that we have application-wide access to it. You may also notice that now that we've updated the JSON with our Serverless function, the columns no longer correspond to what we're want to use in our table. That's fine! We'll store only the columns we need as well to use to create the table.
Now in the pages directory of our app, we'll have an `Index.vue` file. If we wanted more pages, we would merely need to add them to this directory. We're going to use this index page for now and use a couple of components in our template.
<template>
<section>
<h1>Cloud Developer Advocate Speaking</h1>
<h3>Microsoft Azure</h3>
<div class="tablecontain">
...
<speaking-table></speaking-table>
</div>
<more-info></more-info>
<speaking-globe></speaking-globe>
</section>
</template>
We're going to bring all of our data in from the Vuex store, and we'll use a computed property for this. We'll also create a way to filter that data in a computed property here as well. We'll end up passing that filtered property to both the speaking table and the speaking globe.
computed: {
speakerData() {
return this.$store.state.speakerData;
},
columns() {
return this.$store.state.speakingColumns;
},
filteredData() {
const x = this.selectedFilter,
filter = new RegExp(this.filteredText, 'i')
return this.speakerData.filter(el => {
if (el[x] !== undefined) { return el[x].match(filter) }
else return true;
})
}
}
}</script>
You'll note that we're using the names of the computed properties, even in other computed properties, the same way that we use data- i.e. speakerData() becomes this.speakerData in the filter. It would also be available to us as {{ speakerData }} in our template and so forth. This is how they are used. Quickly sorting and filtering a lot of data in a table based on user input, is definitely a job for computed properties. In this filter, we'll also check and make sure we're not throwing things out for case-sensitivity, or trying to match up a row that's undefined as our data sometimes has holes in it.
Here's an important part to understand, because computed properties in Vue are incredibly useful. They are calculations that will be cached based on their dependencies and will only update when needed. This means they're extremely performant when used well. Computed properties aren't used like methods, though at first, they might look similar. We may register them in the same way, typically with some accompanying logic, they're actually used more like data. You can consider them another view into your data.
Computed values are very valuable for manipulating data that already exists. Anytime you're building something where you need to sort through a large group of data, and you don't want to rerun those calculations on every keystroke, think about using a computed value. Another good candidate would be when you're getting information from your Vuex store. You'd be able to gather that data and cache it.
Creating the inputs
Now, we want to allow the user to pick which type of data they are going to filter. In order to use that computed property to filter based on user input, we can create a value as an empty string in our data, and use v-model to establish a relationship between what is typed in this search box with the data we want filtered in that filteredData function from earlier. We'd also like them to be able to pick a category to narrow down their search. In our case, we already have access to these categories, they are the same as the columns we used for the table. So we can create a select with a corresponding label:
<label for="filterLabel">Filter By</label>
<select id="filterLabel" name="select" v-model="selectedFilter">
<option v-for="column in columns" key="column" :value="column">
{{ column }}
</option>
</select>
We'll also wrap that extra filter input in a v-if directive, because it should only be available to the user if they have already selected a column:
<span v-if="selectedFilter">
<label for="filterText" class="hidden">{{ selectedFilter }}</label>
<input id="filteredText" type="text" name="textfield" v-model="filteredText"></input>
</span>
Creating the table
Now, we'll pass the filtered data down to the speaking table and speaking globe:
<speaking-globe :filteredData="filteredData"></speaking-globe>
Which makes it available for us to update our table very quickly. We can also make good use of directives to keep our table small, declarative, and legible.
<table class="scroll">
<thead>
<tr>
<th v-for="key in columns">
{{ key }}
</th>
</tr>
</thead>
<tbody>
<tr v-for="(post, i) in filteredData">
<td v-for="entry in columns">
<a :href="post.Link" target="_blank">
{{ post[entry] }}
</a>
</td>
</tr>
</tbody>
</table>
Since we're using that computed property we passed down that's being updated from the input, it will take this other view of the data and use that instead, and will only update if the data is somehow changed, which will be pretty rare.
And now we have a performant way to scan through a lot of data on a table with Vue. The directives and computed properties are the heroes here, making it very easy to write this declaratively.

I love how fast it filters the information with very little effort on our part. Computed properties leverage Vue's ability to cache wonderfully.
Creating the Globe Visualization
As mentioned previously, I'm using a library from Google dataarts for the globe, found in this repo.
The globe is beautiful out of the box but we need two things in order to work with it: we need to modify our data to create the JSON that the globe expects, and we need to know enough about three.js to update its appearance and make it work in Vue.
It's an older repo, so it's not available to install as an npm module, which is actually just fine in our case, because we're going to manipulate the way it looks a bit because I'm a control freak ahem I mean, we'd like to play with it to make it our own.
Dumping all of this repo's contents into a method isn't that clean though, so I'm going to make use of a mixin. The mixin allows us to do two things: it keeps our code modular so that we're not scanning through a giant file, and it allows us to reuse this globe if we ever wanted to put it on another page in our app.
I register the globe like this:
import * as THREE from 'three';
import { createGlobe } from './../mixins/createGlobe';

export default {
mixins: [createGlobe],

}
and create a separate file in a directory called mixins (in case I'd like to make more mixins) named `createGlobe.js`. For more information on mixins and how they work and what they do, check out this other article I wrote on how to work with them.
Modifying the data
If you recall from the first article, in order to create the globe, we need feed it values that look like this:
var data = [
[
'seriesA', [ latitude, longitude, magnitude, latitude, longitude, magnitude, ... ]
],
[
'seriesB', [ latitude, longitude, magnitude, latitude, longitude, magnitude, ... ]
]
];
So far, the filteredData computed value we're returning from our store will give us our latitude and longitude for each entry, because we got that information from our computed property. For now we just want one view of that dataset, just my team's data, but in the future we might want to collect information from other teams as well so we should build it out to add new values fairly easily.
Let's make another computed value that returns the data the way that we need it. We're going to make it as an object first because that will be more efficient while we're building it, and then we'll create an array.
teamArr() {
//create it as an object first because that's more efficient than an array
var endUnit = {};
//our logic to build the data will go here

//we'll turn it into an array here
let x = Object.entries(endUnit);
let area = [],
places,
all;

for (let i = 0; i < x.length; i++) {
[all, places] = x[i];
area.push([all, [].concat(...Object.values(places))]);
}
return area;
}
In the object we just created, we'll see if our values exist already, and if not, we'll create a new one. We'll also have to create a key from the latitude and longitude put together so that we can check for repeat instances. This is particularly helpful because I don't know if my teammates will put the location in as just the city or the city and the state. Google maps API is pretty forgiving in this way- they'll be able to find one consistent location for either string.
We'll also decide what the smallest and incremental value of the magnification will be. Our decision for the magnification will mainly be from trial and error of adjusting this value and seeing what fits in a way that makes sense for the viewer. My first try here was long stringy wobbly poles and looked like a balding broken porcupine, it took a minute or so to find a value that worked.
this.speakerData.forEach(function(index) {
let lat = index.Latitude,
long = index.Longitude,
key = lat + ", " + long,
magBase = 0.1,
val = 'Microsoft CDAs';

//if we either the latitude or longitude are missing, skip it
if (lat === undefined || long === undefined) return;

//because the pins are grouped together by magnitude, as we build out the data, we need to check if one exists or increment the value
if (val in endUnit) {

//if we already have this location (stored together as key) let's increment it
if (key in endUnit[val]) {
//we'll increase the maginifation here
}
} else {
//we'll create the new values here
}

})
Now, we'll check if the location already exists, and if it does, we'll increment it. If not, we'll create new values for them.
this.speakerData.forEach(function(index) {
...

if (val in endUnit) {
//if we already have this location (stored together as key) let's increment it
if (key in endUnit[val]) {
endUnit[val][key][2] += magBase;
} else {
endUnit[val][key] = [lat, long, magBase];
}
} else {
let y = {};
y[key] = [lat, long, magBase];
endUnit[val] = y;
}

})
Make it look interesting
I mentioned earlier that part of the reason we'd want to store the base dataarts JavaScript in a mixin is that we'd want to make some modifications to its appearance. Let's talk about that for a minute as well because it's an aspect of any interesting data visualization.
If you don't know very much about working with three.js, it's a library that's pretty well documented and has a lot of examples to work off of. The real breakthrough in my understanding of what it was and how to work with it didn't really come from either of these sources, though. I got a lot out of Rachel Smith's series on codepen and Chris Gammon's (not to be confused with Chris Gannon) excellent YouTube series. If you don't know much about three.js and would like to use it for 3D data visualization, my suggestion is to start there.
The first thing we'll do is adjust the colors of the pins on the globe. The ones out of the box are beautiful, but they don't fit the style of our page, or the magnification we need for this data. The code to update is on line 11 of our mixin:
const colorFn = opts.colorFn || function(x) {
let c = new THREE.Color();
c.setHSL(0.1 - x * 0.19, 1.0, 0.6);
return c;
};
If you're not familiar with it, HSL is a wonderfully human-readable color format, which makes it easy to update the colors of our pins on a range:

H stands for hue, which is given to us as a circle. This is great for generative projects like this because unlike a lot of other color formats, it will never fail. 20 degrees will give us the same value as 380 degrees, and so on. The x that we pass in here have a relationship with our magnification, so we'll want to figure out where that range begins, and what it will increase by.
The second value will be Saturation, which we'll pump up to full blast here so that it will stand out- on a range from 0 to 1, 1.0 is the highest.
The third value is Lightness. Like Saturation, we'll get a value from 0 to 1, and we'll use this halfway at 0.5.

You can see if I just made a slight modification, to that one line of code to c.setHSL(0.6 - x * 0.7, 1.0, 0.4); it would change the color range dramatically.

We'll also make some other fine-tuned adjustments: the globe will be a circle, but it will use an image for the texture. If we wanted to change that shape to a a icosahedron or even a torus knot, we could do so, we'd need only to change one line of code here:
//from
const geometry = new THREE.SphereGeometry(200, 40, 30);
//to
const geometry = new THREE.IcosahedronGeometry(200, 0);
and we'd get something like this, you can see that the texture will still even map to this new shape:

Strange and cool, and maybe not useful in this instance, but it's really nice that creating a three-dimensional shape is so easy to update with three.js. Custom shapes get a bit more complex, though.
We load that texture differently in Vue than the way the library would- we'll need to get it as the component is mounted and load it in, passing it in as a parameter when we also instantiate the globe. You'll notice that we don't have to create a relative path to the assets folder because Nuxt and Webpack will do that for us behind the scenes. We can easily use static image files this way.
mounted() {
let earthmap = THREE.ImageUtils.loadTexture('https://cdn.css-tricks.com/world4.jpg');
this.initGlobe(earthmap);
}
We'll then apply that texture we passed in here, when we create the material:
uniforms = THREE.UniformsUtils.clone(shader.uniforms);
uniforms['texture'].value = imageLoad;

material = new THREE.ShaderMaterial({
uniforms: uniforms,
vertexShader: shader.vertexShader,
fragmentShader: shader.fragmentShader
});
There are so many ways we could work with this data and change the way it outputs- we could adjust the white bands around the globe, we could change the shape of the globe with one line of code, we could surround it in particles. The sky's the limit!

And there we have it! We're using a serverless function to interact with the Google Maps API, we're using Nuxt to create the application with Server Side Rendering, we're using computed values in Vue to make that table slick, declarative and performant. Working with all of these technologies can yield really fun exploratory ways to look at data.

Article Series:

Automatically Update GitHub Files With Serverless Functions
Filtering and Using the Data (you are here!)

Exploring Data with Serverless and Vue: Filtering and Using the Data is a post from CSS-Tricks
Source: CssTricks


Exploring Data with Serverless and Vue: Automatically Update GitHub Files With Serverless Functions

I work on a large team with amazing people like Simona Cotin, John Papa, Jessie Frazelle, Burke Holland, and Paige Bailey. We all speak a lot, as it's part of a developer advocate's job, and we're also frequently asked where we'll be speaking. For the most part, we each manage our own sites where we list all of this speaking, but that's not a very good experience for people trying to explore, so I made a demo that makes it easy to see who's speaking, at which conferences, when, with links to all of this information. Just for fun, I made use of three.js so that you can quickly visualize how many places we're all visiting.

You can check out the live demo here, or explore the code on GitHub.
In this tutorial, I'll run through how we set up the globe by making use of a Serverless function that gets geolocation data from Google for all of our speaking locations. I'll also run through how we're going to use Vuex (which is basically Vue's version of Redux) to store all of this data and output it to the table and globe, and how we'll use computed properties in Vue to make sorting through that table super performant and slick.

Article Series:

Automatically Update GitHub Files With Serverless Functions (you are here!)
Filtering and Using the Data (coming soon!)

Serverless Functions
What the heck?
Recently I tweeted that "Serverless is an actually interesting thing with the most clickbaity title." I'm going to stand by that here and say that the first thing anyone will tell you is that serverless is a misnomer because you're actually still using servers. This is true. So why call it serverless? The promise of serverless is to spend less time setting up and maintaining a server. You're essentially letting the service handle maintenance and scaling for you, and you boil what you need down to functions that state: when this request comes in, run this code. For this reason, sometimes people refer to them as functions as a service, or FaaS.
Is this useful? You bet! I love not having to babysit a server when it's unnecessary, and the payment scales automatically as well, which means you're not paying for anything you're not using.
Is FaaS the right thing to use all the time? Eh, not exactly. It's really useful if you'd like to manage small executions. Serverless functions can retrieve data, they can send email notifications, they can even do things like crop images on the fly. But for anything where you have processes that might hold up resources or a ton of computation, being able to communicate with a server as you normally do might actually be more efficient.
Our demo here is a good example of something we'd want to use serverless for, though. We're mostly just maintaining and updating a single JSON file. We'll have all of our initial speaker data, and we need to get geolocation data from Google to create our globe. We can have it all work triggered with GitHub commits, too. Let's dig in.
Creating the Serverless Function
We're going to start with a big JSON file that I outputted from a spreadsheet of my coworker's speaking engagements. That file has everything I need in order to make the table, but for the globe I'm going to use this webgl-globe from Google data arts that I'll modify. You can see in the readme that eventually I'll format my data to extract the years, but I'll also need the latitude and longitude of every location we're visiting
var data = [
[
'seriesA', [ latitude, longitude, magnitude, latitude, longitude, magnitude, ... ]
],
[
'seriesB', [ latitude, longitude, magnitude, latitude, longitude, magnitude, ... ]
]
];
Eventually, I'll also have to reduce the duplicated instances per year to make the magnitude, but we'll tackle that modification of our data within Vue in the second part of this series.
To get started, if you haven't already, create a free Azure trial account. Then go to the portal: ms.portal.azure.com
Inside, you'll see a sidebar that has a lot of options. At the top it will say new. Click that.

Next, we'll select function app from the list and fill in the new name of our function. This will give us some options. You can see that it will already pick up our resource group, subscription, and create a storage account. It will also use the location data from the resource group so, happily, it's pretty easy to populate, as you can see in the GIF below.

The defaults are probably pretty good for your needs. As you can see in the GIF above, it will autofill most of the fields just from the App name. You may want to change your location based on where most of your traffic is coming from, or from a midpoint (i.e. if you have a lot of traffic both in San Francisco and New York), it might be best to choose a location in the middle of the United States.
The hosting plan can be Consumption (the default) or App Service Plan. I choose Consumption because resources are added or subtracted dynamically, which the magic of this whole serverless thing. If you'd like a higher level of control or detail, you'd probably want the App Service plan, but keep in mind that this means you'll be manually scaling and adding resources, so it's extra work on your part.

You'll be taken to a screen that shows you a lot of information about your function. Check to see that everything is in order, and then click the functions plus sign on the sidebar.

From there you'll be able to pick a template, we're going to page down a bit and pick GitHub Webhook - JavaScript from the options given.

Selecting this will bring you to a page with an `index.js` file. You'll be able to enter code if you like, but they give us some default code to run an initial test to see everything's working properly. Before we create our function, let's first test it out to see that everything looks ok.

We'll hit the save and run buttons at the top, and here's what we get back. You can see the output gives us a comment, we get a status of 200 OK in green, and we get some logs that validate our GitHub webhook successfully triggered.

Pretty nice! Now here's the fun part: let's write our own function.
Writing our First Serverless Function
In our case, we have the location data for all of the speeches, which we need for our table, but in order to make the JSON for our globe, we will need one more bit of data: we need latitude and longitude for all of the speaking events. The JSON file will be read by our Vuex central store, and we can pass out the parts that need to be read to each component.
The file that I used for the serverless function is stored in my github repo, you can explore the whole file here, but let's also walk through it a bit:
The first thing I'll mention is that I've populated these variables with config options for the purposes of this tutorial because I don't want to give you all my private info. I mean, it's great, we're friends and all, but I just met you.
// GitHub configuration is read from process.env
let GH_USER = process.env.GH_USER;
let GH_KEY = process.env.GH_KEY;
let GH_REPO = process.env.GH_REPO;
let GH_FILE = process.env.GH_FILE;
In a real world scenario, I could just drop in the data:
// GitHub configuration is read from process.env
let GH_USER = sdras;
… and so on. In order to use these environment variables (in case you'd also like to store them and keep them private), you can use them like I did above, and go to your function in the dashboard. There you will see an area called Configured Features. Click application settings and you'll be taken to a page with a table where you can enter this information.
Working with our dataset
First, we'll retrieve the original JSON file from GitHub and decode/parse it. We're going to use a method that gets the file from a GitHub response and base64 encodes it (more information on that here).
module.exports = function(context, data) {
// Make the context available globally
gContext = context;

getGithubJson(githubFilename(), (data, err) => {
if (!err) {
// No error; base64 decode and JSON parse the data from the Github response
let content = JSON.parse(
new Buffer(data.content, 'base64').toString('ascii')
);
Then we'll retrieve the geo-information for each item in the original data, if it went well, we'll push it back up to GitHub, otherwise, it will error. We'll have two errors: one for a general error, and another for if we get a correct response but there is a geo error, so we can tell them apart. You'll note that we're using gContext.log to output to our portal console.
getGeo(makeIterator(content), (updatedContent, err) => {
if (!err) {
// we need to base64 encode the JSON to embed it into the PUT (dear god, why)
let updatedContentB64 = new Buffer(
JSON.stringify(updatedContent, null, 2)
).toString('base64');
let pushData = {
path: GH_FILE,
message: 'Looked up locations, beep boop.',
content: updatedContentB64,
sha: data.sha
};
putGithubJson(githubFilename(), pushData, err => {
context.log('All done!');
context.done();
});
} else {
gContext.log('All done with get Geo error: ' + err);
context.done();
}
});
} else {
gContext.log('All done with error: ' + err);
context.done();
}
});
};
Great! Now, given an array of entries (wrapped in an iterator), we'll walk over each of them and populate the latitude and longitude, using Google Maps API. Note that we also cache locations to try and save some API calls.
function getGeo(itr, cb) {
let curr = itr.next();
if (curr.done) {
// All done processing- pass the (now-populated) entries to the next callback
cb(curr.data);
return;
}

let location = curr.value.Location;
Now let's check the cache to see if we've already looked up this location:
if (location in GEO_CACHE) {
gContext.log(
'Cached ' +
location +
' -> ' +
GEO_CACHE[location].lat +
' ' +
GEO_CACHE[location].long
);
curr.value.Latitude = GEO_CACHE[location].lat;
curr.value.Longitude = GEO_CACHE[location].long;
getGeo(itr, cb);
return;
}
Then if there's nothing found in cache, we'll do a lookup and cache the result, or let ourselves know that we didn't find anything:
getGoogleJson(location, (data, err) => {
if (err) {
gContext.log('Error on ' + location + ' :' + err);
} else {
if (data.results.length > 0) {
let info = {
lat: data.results[0].geometry.location.lat,
long: data.results[0].geometry.location.lng
};
GEO_CACHE[location] = info;
curr.value.Latitude = info.lat;
curr.value.Longitude = info.long;
gContext.log(location + ' -> ' + info.lat + ' ' + info.long);
} else {
gContext.log(
"Didn't find anything for " + location + ' ::' + JSON.stringify(data)
);
}
}
setTimeout(() => getGeo(itr, cb), 1000);
});
}
We've made use of some helper functions along the way that help get Google JSON, and get and put GitHub JSON.
Now if we run this function in the portal, we'll see our output:

It works! Our serverless function updates our JSON file with all of the new data. I really like that I can work with backend services without stepping outside of JavaScript, which is familiar to me. We need only git pull and we can use this file as the state in our Vuex central store. This will allow us to populate the table, which we'll tackle the next part of our series, and we'll also use that to update our globe. If you'd like to play around with a serverless function and see it in action for yourself, you can create one with a free trial account.
Stay tuned for the next installment!

Article Series:

Automatically Update GitHub Files With Serverless Functions (you are here!)
Filtering and Using the Data (coming soon!)

Exploring Data with Serverless and Vue: Automatically Update GitHub Files With Serverless Functions is a post from CSS-Tricks
Source: CssTricks


Rotten Neighbor listed on MSN.com Top 10 Trends

Traffic on the RottenNeighbor.com site boomed once again as MSN.com listed it in their Top 10 Trends of the Internet.

Since Pixeldust launched Rottenneighbor.com last October, it has seen over 10 million page views and also been featured on Good Morning America, Yahoo, CNN, MSN and Google.

What are your neighbors saying about you? Read more


Today Show features Rotten Neighbor

Rottenneighbor.com was featured on the Today Show this morning and traffic on the site soared! Watch the full story here.

Since Pixeldust launched Rottenneighbor.com last October, it has seen over 10 million page views and also been featured on Good Morning America, Yahoo, CNN, MSN and Google.

What are your neighbors saying about you? Read more


Rotten Neighbor on front page of CNN.com and #1 on Google Trends

RottenNeighbor.com was featured on Top Ten stories on CNN.com today for the entire day. The site traffic increased to over two million page views and brought Rotten Neighbor all the way to #1 on Google trends . See the full story on CNN here.

Since Pixeldust launched Rottenneighbor.com last October, it has seen over 10 million page views and also been featured on Good Morning America, the Today Show, Yahoo, CNN, MSN and Google.

What are your neighbors saying about you? Read more