Category Archives: JavaScript

React Native bundle loading failing on a physical device

I’m building a React Native application and recently updated to v0.31.0 and at first things were working well debugging on the device benefiting from a feature of the react-native-xcode.sh script. The script copies your Dev machine’s IP address to a text file called ip.txt which is used for establishing the connection to your machine from your device since localhost points to the wrong place. Here’s the line of code in ./node_modules/react-native/packager/react-native-xcode.sh:

echo "$IP.xip.io" > "$DEST/ip.txt"

Continue reading

ReactNativeJNI: Check failed: *m_isDestroyed JSCExecutor::destroy() must be called before its destructor

Short post to get this indexed as we didn’t find it elsewhere on the web.

While working to ship a new release of the Find&Save Android app we ran into a crash on launch which only occurred in our release build. The crash was in JSCExecutor.cpp which is part of React Native and left very few hints as to what was wrong with no call stack, Crashlytics logs etc. The only error we had was:

ReactNativeJNI: Check failed: *m_isDestroyed JSCExecutor::destroy() must be called before its destructor
Continue reading

Using flot to chart data using a date range

jquery flot chart I’m working on developing Bloglines these days and one of the features I wanted as an admin was the ability to see various pieces of data related to the site over time. Ideally what I wanted were some charts like those on $g(Google Analytics) for things like:

  • users joining/day
  • votes cast/day
  • blogs submitted per day

I’ve previously experimented with the $l(Google Chart Tools) and that’s where my search started but that lead to a bit of a dead end. I found a related post on Tom Fotherby’s blog but as Greg Fitzgerald pointed out there are still a few more issues to be worked out. Since we use jQuery on the site I started searching along that vein which led me to flot and more specifically this example (caution the examples site seems really slow) which fit perfectly.

Looking at the code and markup I quickly found this was something I could have working right away. The data in JavaScript looks like this:

var d = [[1196463600000, 0], [1196550000000, 0], [1196636400000, 0], ...];
 

Where the first value is a $g(JavaScript timestamp) and the second is the actual data to be plotted. There are a couple of notes regarding the timestamp mentioned here:

The timestamps must be specified as Javascript timestamps, as milliseconds since January 1, 1970 00:00. This is like Unix timestamps, but in milliseconds instead of seconds (remember to multiply with 1000!).

As an extra caveat, the timestamps are interpreted according to UTC to avoid having the graph shift with each visitor’s local time zone. So you might have to add your local time zone offset to the timestamps or simply pretend that the data was produced in UTC instead of your local time zone.

We’re using $g(Postgres) and the tables I need to query all have a date_created field of timestamp without timezone. Here’s the SQL to fetch the data:

SELECT extract(epoch from date_trunc('day', date_created)) * 1000, count(*) from blog group by extract(epoch from date_trunc('day', date_created)) * 1000 order by extract(epoch from date_trunc('day', date_created)) * 1000 DESC

From the results I use the following python method to create the above data structure which is ready to feed into the flot chart:

    @staticmethod
    def statsByDay(query):
        data = PubBase.sqlQuery(query)
        dl = []
        for d in data:
            if d[0] != None and d[1] != None:
                dl.append([int(d[0]), int(d[1])])
        return dl         

I’ve been working with a lot of JavaScript frameworks/libraries lately and this is on that integrated into the project pretty flawlessly so kudos to the flot folks!

Google Calendar on a Simile Timeline

At Falafel Software Google calendar is a core tool used by the company. I’ve been working to leverage the data calendar in a number of interesting ways such as in the DIV below rendered using JavaScript based on calendar data from Falafel training calendar displaying upcoming training events over the next 120 days.

February 2

Telerik Advanced RadGrid Data Editing and Validation
FREE! (Click to register)

February 23

Telerik Advanced RadGrid Paging, Sorting, and Filtering
FREE! (Click to register)

March 1

Telerik Sitefinity Online Training
$399/person

I’ve mentioned the above example before from Google’s playground and I found another example which uses $g(MIT’s Simile) project Timeline control to render calendar data. As you can see from that example it’s not actually working so I thought I’d post an update with some changes I made to get it working. Here is my example. I’ve made changes to get the import of the data working though there remains a number of other improvements that could be made. I’ve yet to determine if this timeline view is really all that useful and haven’t settled on a view that I really like. At any rate, here is the code, again take a look at the source for my example above for a complete working page.

var gEventSource;
 
function loadGDataCallback(json) {
  var entries = json.feed.entry;
  var timelinerEntries = [];
  for (var i = 0; i < entries.length; ++i) {
    var entry = entries[i];
    if(entry["gd$when"] == null) continue;
    var when = entry["gd$when"][0];
    var start = convertFromGDataDate(when.startTime);
    var end = convertFromGDataDate(when.endTime);
    var webContent = null;
    var links = entry.link;
    for (var j = 0; j < links.length; ++j) {
      if (links[j].rel == "alternate") {
        webContent = links[j];
        break;
      }
    }
    var title = entry.title.$t;
    var link = entry.link;
    var icon = entry.link[0].href;

    var description = '<img src="' + link + '">';
    timelinerEntries.push(new Timeline.DefaultEventSource.Event(
      start,
      end, // end - when not set, event displayed with icon (looks better)
      null, // latestStart
      null, // latestEnd
      false, // not isDuration
      entry.title.$t,
      entry.content.$t,
      icon, // image
      entry.link[0].href, // link - destination when clicking on title
      entry.link[0].href,
      undefined, // color
      undefined  // textColor
    ));
  }
  gEventSource.addMany(timelinerEntries);
};
 
function zeroPad(n) {
  if (n < 0) throw new Error('n is negative');
  return (n < 10) ? '0' + n : n;
}
 
function convertToGDataDate(/*Date*/ date) {
  return date.getFullYear() + '-' +
         zeroPad(date.getMonth() + 1) + '-' +
         zeroPad(date.getDate());
}
 
function convertFromGDataDate(/*string<YYYY-MM-DD>*/ date) {
  var match = date.match(/(\d{4})-(\d{2})-(\d{2})/);
  return new Date(parseInt(match[1], 10), parseInt(match[2], 10) - 1, parseInt(match[3], 10));
}
 
function onLoad() {
  gEventSource = new Timeline.DefaultEventSource();
 
  var theme = Timeline.ClassicTheme.create();
  theme.event.bubble.width = 320;
  theme.event.bubble.height = 180;
 
  // centering the timeline three months previous makes it look nicer on load
  var threeDaysFromNow =
      new Date(((new Date).getTime()) + 3 * 24 * 60 * 60 * 1000);
  var bandInfos = [
    Timeline.createBandInfo({
        eventSource:    gEventSource,
        date:           threeDaysFromNow,
        width:          "40%", 
        intervalUnit:   Timeline.DateTime.WEEK, 
        intervalPixels: 300,
        theme:          theme
    }),
    Timeline.createBandInfo({
        eventSource:    gEventSource,
        date:           threeDaysFromNow,
        width:          "60%", 
        intervalUnit:   Timeline.DateTime.MONTH, 
        intervalPixels: 550,
        theme:          theme
    })
/*    ,
    Timeline.createBandInfo({
        showEventText:  false,
        trackHeight:    0.5,
        trackGap:       0.2,
        eventSource:    gEventSource,
        date:           threeDaysFromNow,
        width:          "10%", 
        intervalUnit:   Timeline.DateTime.YEAR, 
        intervalPixels: 200
    })
*/    
  ];
  bandInfos[1].syncWith = 0;
  bandInfos[1].highlight = true;
/*  
  bandInfos[2].syncWith = 0;
  bandInfos[2].highlight = true;
*/  
  tl = Timeline.create(document.getElementById("my-timeline"), bandInfos);
 
  // Atom feed from a Google calendar
  var feedUrl = "http://www.google.com/calendar/feeds/4u13qtkl3bcpao0ofgod94s960@group.calendar.google.com/public/full";
 
  var startDate = new Date((new Date).getDate());
  var endDate = new Date(((new Date).getTime()) + 3 * 30 * 24 * 60 * 60 * 1000);

 
  var getParams = '?start-min=' + convertToGDataDate(startDate) +
                  '&start-max=' + convertToGDataDate(endDate) +
                  '&alt=json-in-script' +
                  '&callback=loadGDataCallback' +
                  '&max-results=5000'; // choose 5000 as an arbitrarily large number
  feedUrl += getParams;
  var scriptTag = document.createElement('script');
  scriptTag.src = feedUrl;
  document.body.appendChild(scriptTag);
}
 
var resizeTimerID = null;
function onResize() {
    if (resizeTimerID == null) {
        resizeTimerID = window.setTimeout(function() {
            resizeTimerID = null;
            tl.layout();
        }, 500);
    }
}

I’m interested in any other ways people are using Google’s calendar data so let me know if you done/seen anything cool!