|
#! /usr/bin/env node |
|
// requires node 8 - v8.9.4, for instance |
|
|
|
const path = require('path'); |
|
const cwd = process.cwd(); |
|
const { polygonContains } = require('d3-polygon'); |
|
|
|
let countries = require('./world.geo.json/countries.geo.json').features; |
|
|
|
function country(point) { |
|
const index = countries.findIndex((country) => { |
|
return country.geometry.coordinates.some( |
|
(polys) => polys.some((poly) => polygonContains(poly, point)) |
|
); |
|
}); |
|
if (index === -1) { |
|
// console.warn(point); |
|
return '???'; |
|
} |
|
// reorder the array we test to have the last found country first: |
|
if (index) { |
|
countries = countries.splice(index, 1).concat(countries); |
|
} |
|
return countries[0].id; |
|
} |
|
|
|
const resolve = (fn) => path.resolve(cwd, fn); |
|
const json_files = process.argv.filter(fn => /\.json$/.test(fn)).map(resolve); |
|
|
|
// console.log(JSON.stringify(json_files, null, 2)); |
|
|
|
let dates = {}; |
|
|
|
json_files.forEach((fn) => { |
|
const days = require(fn); |
|
(days || []).forEach((day) => { |
|
const countries = {}; |
|
(day.segments || []).forEach((seg) => { |
|
const loc = seg.place && seg.place.location; |
|
if (loc) { |
|
const { lat, lon } = loc; |
|
countries[country([lon, lat])] = true; |
|
} |
|
}); |
|
const date = day.date.replace(/^(\d{4})(\d\d)(\d\d)$/, '$1-$2-$3'); |
|
dates[date] = Object.keys(countries).sort(); |
|
}); |
|
}); |
|
|
|
let ordered = Object.keys(dates).sort().map((date) => { |
|
return { date, countries: dates[date].join(' + ') }; |
|
}); |
|
|
|
ordered.forEach(({date, countries}) => { |
|
console.log(`${date}: ${countries}`); |
|
}); |
|
|
|
console.log('\ncountry detail:\n'); |
|
|
|
let non_empty = ordered.filter(({ countries }) => countries.length); |
|
|
|
const show = (c) => c === 'not' ? ' not' : c; |
|
|
|
let prior = non_empty[0]; |
|
console.log(non_empty.reduce( |
|
({ ranges }, {date, countries}) => { |
|
const last = ranges[ranges.length - 1]; |
|
if (JSON.stringify(countries) == JSON.stringify(last.countries)) { |
|
last.tail = date; |
|
} |
|
else { |
|
ranges.push({ countries, head: date }); |
|
} |
|
return { ranges }; |
|
}, |
|
{ ranges: [{ countries: prior.countries, head: prior.date }] } |
|
).ranges.map( |
|
({ countries, head, tail }) => `${head}...${tail||head}: ${show(countries)}` |
|
).join('\n')); |
|
|
|
|
|
|
|
console.log('\nUSA vs not:\n'); |
|
|
|
dates = {}; |
|
|
|
json_files.forEach((fn) => { |
|
const days = require(fn); |
|
(days || []).forEach((day) => { |
|
const countries = {}; |
|
(day.segments || []).forEach((seg) => { |
|
const loc = seg.place && seg.place.location; |
|
if (loc) { |
|
const { lat, lon } = loc; |
|
countries[country([lon, lat]) === 'USA' ? 'USA' : 'not'] = true; |
|
} |
|
}); |
|
const date = day.date.replace(/^(\d{4})(\d\d)(\d\d)$/, '$1-$2-$3'); |
|
dates[date] = Object.keys(countries).sort(); |
|
}); |
|
}); |
|
|
|
ordered = Object.keys(dates).sort().map((date) => { |
|
return { date, countries: dates[date].join(' + ') }; |
|
}); |
|
|
|
non_empty = ordered.filter(({ countries }) => countries.length); |
|
|
|
prior = non_empty[0]; |
|
console.log(non_empty.reduce( |
|
({ ranges }, {date, countries}) => { |
|
const last = ranges[ranges.length - 1]; |
|
if (JSON.stringify(countries) == JSON.stringify(last.countries)) { |
|
last.tail = date; |
|
} |
|
else { |
|
ranges.push({ countries, head: date }); |
|
} |
|
return { ranges }; |
|
}, |
|
{ ranges: [{ countries: prior.countries, head: prior.date }] } |
|
).ranges.map( |
|
({ countries, head, tail }) => `${head}...${tail||head}: ${show(countries)}` |
|
).join('\n')); |