<commit_before>// Constructor for an exception which is thrown if the file
// being parsed is not in a valid IGC format.
function IGCException(message) {
    'use strict';

    this.message = message;
    this.name = "IGCException";
}

// Parses an IGC logger file.
function parseIGC(igcFile) {
    'use strict';

    // Looks up the manufacturer name corresponding to
    // the three letter code in the first line of the IGC file
    // (the 'A' record).
    function parseManufacturer(aRecord) {
        var manufacturers = {
            'GCS': 'Garrecht',
            'CAM': 'Cambridge Aero Instruments',
            'DSX': 'Data Swan',
            'EWA': 'EW Avionics',
            'FIL': 'Filser',
            'FLA': 'FLARM',
            'SCH': 'Scheffel',
            'ACT': 'Aircotec',
            'NKL': 'Nielsen Kellerman',
            'LXN': 'LX Navigation',
            'IMI': 'IMI Gliding Equipment',
            'NTE': 'New Technologies s.r.l.',
            'PES': 'Peschges',
            'PRT': 'Print Technik',
            'SDI': 'Streamline Data Instruments',
            'TRI': 'Triadis Engineering GmbH',
            'LXV': 'LXNAV d.o.o.',
            'WES': 'Westerboer',
            'XCS': 'XCSoar',
            'ZAN': 'Zander'
        };

        var manufacturerInfo = {
            manufacturer: 'Unknown',
            serial: aRecord.substring(4)
        };

        var manufacturerCode = aRecord.substring(1, 4);
        if (manufacturers[manufacturerCode]) {
            manufacturerInfo.manufacturer = manufacturers[manufacturerCode];
        }

        return manufacturerInfo;
    }

    // Extracts the flight date from the IGC file.
    function extractDate(igcFile) {
        // Date is recorded as: HFDTEddmmyy (where HFDTE is a literal and dddmmyy are digits).
        var dateRecord = igcFile.match(/H[FO]DTE([\d]{2})([\d]{2})([\d]{2})/);
        if (dateRecord === null) {
            throw new IGCException('The file does not contain a date header.');
        }

        var day = parseInt(dateRecord[1], 10);
        // Javascript numbers months from zero, not 1!
        var month = parseInt(dateRecord[2], 10) - 1;
        // The IGC specification has a built-in Millennium Bug (2-digit year).
        // I will arbitrarily assume that any year before "80" is in the 21st century.
        var year = parseInt(dateRecord[3], 10);

        if (year < 80) {
            year += 2000;
        } else {
            year += 1900;
        }
        return new Date(Date.UTC(year, month, day));
    }

    function parseHeader(headerRecord) {
        var headerSubtypes = {
            'PLT': 'Pilot',
            'CM2': 'Crew member 2',
            'GTY': 'Glider type',
            'GID': 'Glider ID',
            'DTM': 'GPS Datum',
            'RFW': 'Firmware version',
            'RHW': 'Hardware version',
            'FTY': 'Flight recorder type',
            'GPS': 'GPS',
            'PRS': 'Pressure sensor',
            'FRS': 'Security suspect, use validation program',
            'CID': 'Competition ID',
            'CCL': 'Competition class'
        };

        var headerName = headerSubtypes[headerRecord.substring(2, 5)];
        if (headerName !== undefined) {
            var colonIndex = headerRecord.indexOf(':');
            if (colonIndex !== -1) {
                var headerValue = headerRecord.substring(colonIndex + 1);
                if (headerValue.length > 0 && /([^\s]+)/.test(headerValue)) {
                    return {
                        name: headerName,
                        value: headerValue
                    };
                }
            }
        }
    }

    // Parses a latitude and longitude in the form:
    // DDMMmmmNDDDMMmmmE
    // where M = minutes and m = decimal places of minutes.
    function parseLatLong(latLongString) {
        var latitude = parseFloat(latLongString.substring(0, 2)) +
            parseFloat(latLongString.substring(2, 7)) / 60000.0;
        if (latLongString.charAt(7) === 'S') {
            latitude = -latitude;
        }

        var longitude = parseFloat(latLongString.substring(8, 11)) +
            parseFloat(latLongString.substring(11, 16)) / 60000.0;
        if (latLongString.charAt(16) === 'W') {
            longitude = -longitude;
        }

        return [latitude, longitude];
    }

    function parsePosition(positionRecord,  model, flightDate) {
        // Regex to match position records:
        // Hours, minutes, seconds, latitude, N or S, longitude, E or W,
        // Fix validity ('A' = 3D fix, 'V' = 2D or no fix),
        // pressure altitude, GPS altitude.
        // Latitude and longitude are in degrees and minutes, with the minutes
        // value multiplied by 1000 so that no decimal point is needed.
        //                      hours    minutes  seconds  latitude    longitude        press alt  gps alt
        var positionRegex = /^B([\d]{2})([\d]{2})([\d]{2})([\d]{7}[NS][\d]{8}[EW])([AV])([\d]{5})([\d]{5})/;
        var positionMatch = positionRecord.match(positionRegex);
        if (positionMatch) {
            // Convert the time to a date and time. Start by making a clone of the date
            // object that represents the date given in the headers:
            var positionTime = new Date(flightDate.getTime());
            positionTime.setUTCHours(parseInt(positionMatch[1], 10), parseInt(positionMatch[2], 10), parseInt(positionMatch[3], 10));
            // If the flight crosses midnight (UTC) then we now have a time that is 24 hours out.
            // We know that this is the case if the time is earlier than the one for the previous position fix.
            if (model.recordTime.length > 0 &&
                model.recordTime[model.recordTime.length - 1] > positionTime) {
                positionTime.setDate(flightDate.getDate() + 1);
            }

            return {
                recordTime: positionTime,
                latLong: parseLatLong(positionMatch[4]),
                pressureAltitude: parseInt(positionMatch[6], 10),
                gpsAltitude: parseInt(positionMatch[7], 10)
            };
        }
    }

    function parseTask(taskRecord) {
        var taskRegex = /^C([\d]{7}[NS][\d]{8}[EW])(.*)/;
        var taskMatch = taskRecord.match(taskRegex);
        var degreeSymbol = '\u00B0';

        if (taskMatch) {
            var name = taskMatch[2];

            // If the turnpoint name is blank, use the latitude and longitude.
            if (name.trim().length === 0) {
                name = taskRecord.substring(1, 3) +
                degreeSymbol +
                taskRecord.substring(3, 5) +
                '.' +
                taskRecord.substring(5, 8) +
                "' " +
                taskRecord.charAt(8) +
                ', ' +
                taskRecord.substring(9, 12) +
                degreeSymbol +
                taskRecord.substring(12, 14) +
                '.' +
                taskRecord.substring(14, 17) +
                "' " +
                taskRecord.charAt(17);
            }

            return {
                latLong: parseLatLong(taskMatch[1]),
                name: name
            };
        }
    }

    // ---- Start of IGC parser code ----

    var invalidFileMessage = 'This does not appear to be an IGC file.';
    var igcLines = igcFile.split('\n');
    if (igcLines.length < 2) {
        throw new IGCException(invalidFileMessage);
    }

    // Declare the model object that is to be returned;
    // this contains the position and altitude data and the header
    // values.
    var model = {
        headers: [],
        recordTime: [],
        latLong: [],
        pressureAltitude: [],
        gpsAltitude: [],
        task: {
            coordinates: [],
            names: []
        }
    };

    // The first line should begin with 'A' followed by
    // a 3-character manufacturer Id and a 3-character serial number.
    if (!(/^A[\w]{6}/).test(igcLines[0])) {
        throw new IGCException(invalidFileMessage);
    }

    var manufacturerInfo = parseManufacturer(igcLines[0]);
    model.headers.push({
        name: 'Logger manufacturer',
        value: manufacturerInfo.manufacturer
    });

    model.headers.push({
        name: 'Logger serial number',
        value: manufacturerInfo.serial
    });

    var flightDate = extractDate(igcFile);

    var lineIndex;
    var positionData;
    var recordType;
    var currentLine;
    var turnpoint; // for task declaration lines
    var headerData;
    for (lineIndex = 0; lineIndex < igcLines.length; lineIndex++) {
        currentLine = igcLines[lineIndex];
        recordType = currentLine.charAt(0);
        switch (recordType) {
            case 'B': // Position fix
                positionData = parsePosition(currentLine, model, flightDate);
                if (positionData) {
                    model.recordTime.push(positionData.recordTime);
                    model.latLong.push(positionData.latLong);
                    model.pressureAltitude.push(positionData.pressureAltitude);
                    model.gpsAltitude.push(positionData.gpsAltitude);
                }
                break;

            case 'C': // Task declaration
                turnpoint = parseTask(currentLine);
                if (turnpoint) {
                    model.task.coordinates.push(turnpoint.latLong);
                    model.task.names.push(turnpoint.name);
                }
                break;

            case 'H': // Header information
                headerData = parseHeader(currentLine);
                if (headerData) {
                    model.headers.push(headerData);
                }
                break;
        }
    }

    // We want to show the flight date including the time.
    // This is important because if we force the display to be UTC,
    // the time is shown as well. The toDateString method gives a date
    // without a time, but converts implicitly to local, causing the
    // day to be incorrect if the system clock is set to a negative offset
    // from UTC (issue #3).
    if (model.recordTime.length > 0) {
        model.headers.Date = model.recordTime[0].toUTCString();
    }
    else {
        model.headers.Date = flightDate.toUTCString();
    }

    // If the file contains a declared task, then it may start or end with
    // 'turnpoints' at 0 degrees N, 0 degrees E. These represent the takeoff
    // and landing positions, which could not have been known at the time when
    // the declaration was made. Replace them with the actual values so that
    // the task can be plotted correctly on a map.

    if (model.task.coordinates.length > 0) {
        if (model.task.coordinates[0][0] === 0.0 && model.task.coordinates[0][1] === 0.0) {
            model.task.coordinates[0] = model.latLong[0];
            model.task.names[0] = 'Takeoff';
        }
        var lastTask = model.task.coordinates.length - 1;
        if (model.task.coordinates[lastTask][0] === 0.0 && model.task.coordinates[lastTask][1] === 0.0) {
            model.task.coordinates[lastTask] = model.latLong[model.latLong.length - 1];
            model.task.names[lastTask] = 'Landing';
        }
    }

    return model;
}
<commit_msg>Restore date display.<commit_after>// Constructor for an exception which is thrown if the file
// being parsed is not in a valid IGC format.
function IGCException(message) {
    'use strict';

    this.message = message;
    this.name = "IGCException";
}

// Parses an IGC logger file.
function parseIGC(igcFile) {
    'use strict';

    // Looks up the manufacturer name corresponding to
    // the three letter code in the first line of the IGC file
    // (the 'A' record).
    function parseManufacturer(aRecord) {
        var manufacturers = {
            'GCS': 'Garrecht',
            'CAM': 'Cambridge Aero Instruments',
            'DSX': 'Data Swan',
            'EWA': 'EW Avionics',
            'FIL': 'Filser',
            'FLA': 'FLARM',
            'SCH': 'Scheffel',
            'ACT': 'Aircotec',
            'NKL': 'Nielsen Kellerman',
            'LXN': 'LX Navigation',
            'IMI': 'IMI Gliding Equipment',
            'NTE': 'New Technologies s.r.l.',
            'PES': 'Peschges',
            'PRT': 'Print Technik',
            'SDI': 'Streamline Data Instruments',
            'TRI': 'Triadis Engineering GmbH',
            'LXV': 'LXNAV d.o.o.',
            'WES': 'Westerboer',
            'XCS': 'XCSoar',
            'ZAN': 'Zander'
        };

        var manufacturerInfo = {
            manufacturer: 'Unknown',
            serial: aRecord.substring(4)
        };

        var manufacturerCode = aRecord.substring(1, 4);
        if (manufacturers[manufacturerCode]) {
            manufacturerInfo.manufacturer = manufacturers[manufacturerCode];
        }

        return manufacturerInfo;
    }

    // Extracts the flight date from the IGC file.
    function extractDate(igcFile) {
        // Date is recorded as: HFDTEddmmyy (where HFDTE is a literal and dddmmyy are digits).
        var dateRecord = igcFile.match(/H[FO]DTE([\d]{2})([\d]{2})([\d]{2})/);
        if (dateRecord === null) {
            throw new IGCException('The file does not contain a date header.');
        }

        var day = parseInt(dateRecord[1], 10);
        // Javascript numbers months from zero, not 1!
        var month = parseInt(dateRecord[2], 10) - 1;
        // The IGC specification has a built-in Millennium Bug (2-digit year).
        // I will arbitrarily assume that any year before "80" is in the 21st century.
        var year = parseInt(dateRecord[3], 10);

        if (year < 80) {
            year += 2000;
        } else {
            year += 1900;
        }
        return new Date(Date.UTC(year, month, day));
    }

    function parseHeader(headerRecord) {
        var headerSubtypes = {
            'PLT': 'Pilot',
            'CM2': 'Crew member 2',
            'GTY': 'Glider type',
            'GID': 'Glider ID',
            'DTM': 'GPS Datum',
            'RFW': 'Firmware version',
            'RHW': 'Hardware version',
            'FTY': 'Flight recorder type',
            'GPS': 'GPS',
            'PRS': 'Pressure sensor',
            'FRS': 'Security suspect, use validation program',
            'CID': 'Competition ID',
            'CCL': 'Competition class'
        };

        var headerName = headerSubtypes[headerRecord.substring(2, 5)];
        if (headerName !== undefined) {
            var colonIndex = headerRecord.indexOf(':');
            if (colonIndex !== -1) {
                var headerValue = headerRecord.substring(colonIndex + 1);
                if (headerValue.length > 0 && /([^\s]+)/.test(headerValue)) {
                    return {
                        name: headerName,
                        value: headerValue
                    };
                }
            }
        }
    }

    // Parses a latitude and longitude in the form:
    // DDMMmmmNDDDMMmmmE
    // where M = minutes and m = decimal places of minutes.
    function parseLatLong(latLongString) {
        var latitude = parseFloat(latLongString.substring(0, 2)) +
            parseFloat(latLongString.substring(2, 7)) / 60000.0;
        if (latLongString.charAt(7) === 'S') {
            latitude = -latitude;
        }

        var longitude = parseFloat(latLongString.substring(8, 11)) +
            parseFloat(latLongString.substring(11, 16)) / 60000.0;
        if (latLongString.charAt(16) === 'W') {
            longitude = -longitude;
        }

        return [latitude, longitude];
    }

    function parsePosition(positionRecord,  model, flightDate) {
        // Regex to match position records:
        // Hours, minutes, seconds, latitude, N or S, longitude, E or W,
        // Fix validity ('A' = 3D fix, 'V' = 2D or no fix),
        // pressure altitude, GPS altitude.
        // Latitude and longitude are in degrees and minutes, with the minutes
        // value multiplied by 1000 so that no decimal point is needed.
        //                      hours    minutes  seconds  latitude    longitude        press alt  gps alt
        var positionRegex = /^B([\d]{2})([\d]{2})([\d]{2})([\d]{7}[NS][\d]{8}[EW])([AV])([\d]{5})([\d]{5})/;
        var positionMatch = positionRecord.match(positionRegex);
        if (positionMatch) {
            // Convert the time to a date and time. Start by making a clone of the date
            // object that represents the date given in the headers:
            var positionTime = new Date(flightDate.getTime());
            positionTime.setUTCHours(parseInt(positionMatch[1], 10), parseInt(positionMatch[2], 10), parseInt(positionMatch[3], 10));
            // If the flight crosses midnight (UTC) then we now have a time that is 24 hours out.
            // We know that this is the case if the time is earlier than the one for the previous position fix.
            if (model.recordTime.length > 0 &&
                model.recordTime[model.recordTime.length - 1] > positionTime) {
                positionTime.setDate(flightDate.getDate() + 1);
            }

            return {
                recordTime: positionTime,
                latLong: parseLatLong(positionMatch[4]),
                pressureAltitude: parseInt(positionMatch[6], 10),
                gpsAltitude: parseInt(positionMatch[7], 10)
            };
        }
    }

    function parseTask(taskRecord) {
        var taskRegex = /^C([\d]{7}[NS][\d]{8}[EW])(.*)/;
        var taskMatch = taskRecord.match(taskRegex);
        var degreeSymbol = '\u00B0';

        if (taskMatch) {
            var name = taskMatch[2];

            // If the turnpoint name is blank, use the latitude and longitude.
            if (name.trim().length === 0) {
                name = taskRecord.substring(1, 3) +
                degreeSymbol +
                taskRecord.substring(3, 5) +
                '.' +
                taskRecord.substring(5, 8) +
                "' " +
                taskRecord.charAt(8) +
                ', ' +
                taskRecord.substring(9, 12) +
                degreeSymbol +
                taskRecord.substring(12, 14) +
                '.' +
                taskRecord.substring(14, 17) +
                "' " +
                taskRecord.charAt(17);
            }

            return {
                latLong: parseLatLong(taskMatch[1]),
                name: name
            };
        }
    }

    // ---- Start of IGC parser code ----

    var invalidFileMessage = 'This does not appear to be an IGC file.';
    var igcLines = igcFile.split('\n');
    if (igcLines.length < 2) {
        throw new IGCException(invalidFileMessage);
    }

    // Declare the model object that is to be returned;
    // this contains the position and altitude data and the header
    // values.
    var model = {
        headers: [],
        recordTime: [],
        latLong: [],
        pressureAltitude: [],
        gpsAltitude: [],
        task: {
            coordinates: [],
            names: []
        }
    };

    // The first line should begin with 'A' followed by
    // a 3-character manufacturer Id and a 3-character serial number.
    if (!(/^A[\w]{6}/).test(igcLines[0])) {
        throw new IGCException(invalidFileMessage);
    }

    var manufacturerInfo = parseManufacturer(igcLines[0]);
    model.headers.push({
        name: 'Logger manufacturer',
        value: manufacturerInfo.manufacturer
    });

    model.headers.push({
        name: 'Logger serial number',
        value: manufacturerInfo.serial
    });

    var flightDate = extractDate(igcFile);

    var lineIndex;
    var positionData;
    var recordType;
    var currentLine;
    var turnpoint; // for task declaration lines
    var headerData;
    for (lineIndex = 0; lineIndex < igcLines.length; lineIndex++) {
        currentLine = igcLines[lineIndex];
        recordType = currentLine.charAt(0);
        switch (recordType) {
            case 'B': // Position fix
                positionData = parsePosition(currentLine, model, flightDate);
                if (positionData) {
                    model.recordTime.push(positionData.recordTime);
                    model.latLong.push(positionData.latLong);
                    model.pressureAltitude.push(positionData.pressureAltitude);
                    model.gpsAltitude.push(positionData.gpsAltitude);
                }
                break;

            case 'C': // Task declaration
                turnpoint = parseTask(currentLine);
                if (turnpoint) {
                    model.task.coordinates.push(turnpoint.latLong);
                    model.task.names.push(turnpoint.name);
                }
                break;

            case 'H': // Header information
                headerData = parseHeader(currentLine);
                if (headerData) {
                    model.headers.push(headerData);
                }
                break;
        }
    }

    // We want to show the flight date including the time.
    // This is important because if we force the display to be UTC,
    // the time is shown as well. The toDateString method gives a date
    // without a time, but converts implicitly to local, causing the
    // day to be incorrect if the system clock is set to a negative offset
    // from UTC (issue #3).
    var displayDate;
    if (model.recordTime.length > 0) {
        displayDate = model.recordTime[0].toUTCString();
    }
    else {
        displayDate = flightDate.toUTCString();
    }

    model.headers.unshift({
        name: 'Date',
        value: displayDate
    });

    // If the file contains a declared task, then it may start or end with
    // 'turnpoints' at 0 degrees N, 0 degrees E. These represent the takeoff
    // and landing positions, which could not have been known at the time when
    // the declaration was made. Replace them with the actual values so that
    // the task can be plotted correctly on a map.

    if (model.task.coordinates.length > 0) {
        if (model.task.coordinates[0][0] === 0.0 && model.task.coordinates[0][1] === 0.0) {
            model.task.coordinates[0] = model.latLong[0];
            model.task.names[0] = 'Takeoff';
        }
        var lastTask = model.task.coordinates.length - 1;
        if (model.task.coordinates[lastTask][0] === 0.0 && model.task.coordinates[lastTask][1] === 0.0) {
            model.task.coordinates[lastTask] = model.latLong[model.latLong.length - 1];
            model.task.names[lastTask] = 'Landing';
        }
    }

    return model;
}
<|endoftext|>


<commit_before>function convertDiff(name, table) {
  var inline = table.className == 'inline';
  var ths = table.tHead.rows[0].cells;
  var lines = [
    "Index: " + name,
    "===================================================================",
    "--- " + (inline ? ths[0].title : $(ths[0]).find('a').text()),
    "+++ " + (inline ? ths[1].title : $(ths[1]).find('a').text()),
  ];
  var sepIndex = 0;
  var oldOffset = 0, oldLength = 0, newOffset = 0, newLength = 0;

  for (var i = 0; i
 0) {
        if (!oldOffset && oldLength) oldOffset = 1
        if (!newOffset && newLength) newOffset = 1
        lines[sepIndex] = lines[sepIndex]
          .replace("{1}", oldOffset).replace("{2}", oldLength)
          .replace("{3}", newOffset).replace("{4}", newLength);
      }
      sepIndex = lines.length;
      lines.push("@@ -{1},{2}, +{3},{4} @@");
      oldOffset = 0, oldLength = 0, newOffset = 0, newLength = 0;
      if (tBody.className == "skipped") continue;
    }
    var tmpLines = [];
    for (var j = 0; j < tBody.rows.length; j++) {
      var cells = tBody.rows[j].cells;
      var oldLineNo = parseInt($(cells[0]).text());
      var newLineNo = parseInt($(cells[inline ? 1 : 2]).text());
      if (tBody.className == 'unmod') {
        lines.push("  " + $(cells[inline ? 2 : 1]).text());
        oldLength += 1;
        newLength += 1;
        if (!oldOffset) oldOffset = oldLineNo;
        if (!newOffset) newOffset = newLineNo;
      } else {
        var oldLine;
        var newLine;
        if (inline) {
          oldLine = newLine = $(cells[2]).text();
        } else {
          oldLine = $(cells[1]).text();
          newLine = $(cells[3]).text();
        }
        if (!isNaN(oldLineNo)) {
          lines.push("- " + oldLine);
          oldLength += 1;
        }
        if (!isNaN(newLineNo)) {
          tmpLines.push("+ " + newLine);
          newLength += 1;
        }
      }
    }
    if (tmpLines.length > 0) {
      lines = lines.concat(tmpLines);
    }
  }

  if (!oldOffset && oldLength) oldOffset = 1
  if (!newOffset && newLength) newOffset = 1
  lines[sepIndex] = lines[sepIndex]
    .replace("{1}", oldOffset).replace("{2}", oldLength)
    .replace("{3}", newOffset).replace("{4}", newLength);

  return lines.join($.browser.msie ? "\r\n" : "\n");
}

$(document).ready(function() {
  $("div.diff h2").each(function() {
    var switcher = $("").prependTo(this);
    var name = $.trim($(this).text());
    var table = $(this).siblings("table").get(0);
    var pre = $("

").hide().insertAfter(table);
    $("Tabular").click(function() {
      $(pre).hide();
      $(table).show();
      $(this).addClass("active").siblings("span").removeClass("active");
      return false;
    }).addClass("active").appendTo(switcher);
    $("Unified").click(function() {
      $(table).hide();
      if (!pre.get(0).firstChild) pre.text(convertDiff(name, table));
      $(pre).fadeIn("fast")
      $(this).addClass("active").siblings("span").removeClass("active");
      return false;
    }).appendTo(switcher);
  });
});
<commit_msg>Diff Tabular/Inline switcher: some diff divs may have no diff table (e.g. property changes only)<commit_after>function convertDiff(name, table) {
  var inline = table.className == 'inline';
  var ths = table.tHead.rows[0].cells;
  var lines = [
    "Index: " + name,
    "===================================================================",
    "--- " + (inline ? ths[0].title : $(ths[0]).find('a').text()),
    "+++ " + (inline ? ths[1].title : $(ths[1]).find('a').text()),
  ];
  var sepIndex = 0;
  var oldOffset = 0, oldLength = 0, newOffset = 0, newLength = 0;

  for (var i = 0; i
 0) {
        if (!oldOffset && oldLength) oldOffset = 1
        if (!newOffset && newLength) newOffset = 1
        lines[sepIndex] = lines[sepIndex]
          .replace("{1}", oldOffset).replace("{2}", oldLength)
          .replace("{3}", newOffset).replace("{4}", newLength);
      }
      sepIndex = lines.length;
      lines.push("@@ -{1},{2}, +{3},{4} @@");
      oldOffset = 0, oldLength = 0, newOffset = 0, newLength = 0;
      if (tBody.className == "skipped") continue;
    }
    var tmpLines = [];
    for (var j = 0; j < tBody.rows.length; j++) {
      var cells = tBody.rows[j].cells;
      var oldLineNo = parseInt($(cells[0]).text());
      var newLineNo = parseInt($(cells[inline ? 1 : 2]).text());
      if (tBody.className == 'unmod') {
        lines.push("  " + $(cells[inline ? 2 : 1]).text());
        oldLength += 1;
        newLength += 1;
        if (!oldOffset) oldOffset = oldLineNo;
        if (!newOffset) newOffset = newLineNo;
      } else {
        var oldLine;
        var newLine;
        if (inline) {
          oldLine = newLine = $(cells[2]).text();
        } else {
          oldLine = $(cells[1]).text();
          newLine = $(cells[3]).text();
        }
        if (!isNaN(oldLineNo)) {
          lines.push("- " + oldLine);
          oldLength += 1;
        }
        if (!isNaN(newLineNo)) {
          tmpLines.push("+ " + newLine);
          newLength += 1;
        }
      }
    }
    if (tmpLines.length > 0) {
      lines = lines.concat(tmpLines);
    }
  }

  if (!oldOffset && oldLength) oldOffset = 1
  if (!newOffset && newLength) newOffset = 1
  lines[sepIndex] = lines[sepIndex]
    .replace("{1}", oldOffset).replace("{2}", oldLength)
    .replace("{3}", newOffset).replace("{4}", newLength);

  return lines.join($.browser.msie ? "\r\n" : "\n");
}

$(document).ready(function() {
  $("div.diff h2").each(function() {
    var switcher = $("").prependTo(this);
    var name = $.trim($(this).text());
    var table = $(this).siblings("table").get(0);
    if (! table) return;
    var pre = $("

").hide().insertAfter(table);
    $("Tabular").click(function() {
      $(pre).hide();
      $(table).show();
      $(this).addClass("active").siblings("span").removeClass("active");
      return false;
    }).addClass("active").appendTo(switcher);
    $("Unified").click(function() {
      $(table).hide();
      if (!pre.get(0).firstChild) pre.text(convertDiff(name, table));
      $(pre).fadeIn("fast")
      $(this).addClass("active").siblings("span").removeClass("active");
      return false;
    }).appendTo(switcher);
  });
});
<|endoftext|>


<commit_before>const create = require('../create')
const util = require('util')
const Stream = require('stream')
const sqlstring = require('../sqlstring')

const fmt = util.format.bind(util)

const JOIN_SEP = ':@:'

module.exports = {
  escape: function escape(value) {
    return sqlstring.escape(value)
  },
  escapeId: function escapeId(id) {
    return sqlstring.escapeId(id)
  },
  whereSql: function whereSql(table, conditions) {
    const hasConditons = conditions && keys(conditions).length
    if (!hasConditons) return ''

    const escape = this.escape
    const escapeId = this.escapeId
    var where = ' WHERE '

    var clauses = map(conditions, function (val, key) {
      const field = escapeId([table, key].join('.'))
      var cnd = conditions[key]

      if (Array.isArray(cnd)) {
        // if the condition is a simple array,
        // e.g { release_date: [2000,1996] }
        // use an `in` operator.
        if (typeof cnd[0] != 'object') {
          cnd = cnd.map(function (x) { return escape(x) })
          return fmt('%s IN (%s)', field, cnd.join(','))
        }

        return cnd.map(function (subcnd) {
          const operation = subcnd.op
          const value = escape(subcnd.value)
          return fmt('%s %s %s', field, operation, value)
        }).join(' AND ')
      }

      const op = cnd.operation || cnd.op || '='
      if (cnd.value) cnd = cnd.value
      return fmt('%s %s %s', field, op, escape(cnd))
    })

    where += clauses.join(' AND ')
    return where
  },
  orderSql: function orderSql(table, order) {
    if (!order) return ''

    const escape = this.escape
    const escapeId = this.escapeId

    // order can be one of three styles:
    // * implicit ascending, single: 'title'
    // * implicit ascending, multi: ['release_date', 'title']
    // * explicit: { title: 'desc', release_date: 'asc' }

    if (typeof order == 'string') {
      return fmt(' ORDER BY %s ', escapeId(order))
    }

    if (Array.isArray(order))
      return fmt(' ORDER BY %s ', order.map(escapeId).join(','))

    // must be an object
    return fmt(' ORDER BY %s ', map(order, function (value, key) {
      return fmt('%s %s', escapeId(key), value.toUpperCase())
    }).join(','))
  },
  limitSql: function limitSql(limit, page) {
    if (!limit) return ''
    if (!page) return fmt(' LIMIT %s ', limit)
    const beginning = (page - 1) * limit
    return fmt(' LIMIT %s,%s ', beginning, limit)
  },

  selectSql: function selectSql(opts) {
    const escapeId = this.escapeId
    const escape = this.escape
    const table = opts.table
    const tables = opts.tables
    const fields = opts.fields
    const conds = opts.conditions
    const includeFields = opts.include
    const excludeFields = opts.exclude
    const relationships = opts.relationships
    const useRaw = Array.isArray(conds)
    const useJoin = (relationships && keys(relationships).length)

    if (useRaw) return rawSql.call(this)
    if (useJoin) return withJoin.call(this)

    const fieldList = filterFields(fields, includeFields, excludeFields)
      .map(escapeId).join(',')

    const statement = ''
      + fmt('SELECT %s FROM %s', fieldList, escapeId(table))
      + this.whereSql(table, conds)
      + this.orderSql(table, opts.order)
      + this.limitSql(opts.limit, opts.page)

    return statement

    function rawSql() {
      const sql = conds[0].replace(/\$table/i, escapeId(table))
      const values = conds[1].map(escape)
      const statement = values.reduce(function (sql, value) {
        return sql.replace('?', value)
      }, sql)
      return statement
    }

    function withJoin() {
      var allFields = fields
        .slice().map(function (field) {
          return [table, field].join('.')
        })

      var joinString = ''

      this.normalizeRelationships(table, relationships)

      // in the loop below, rel -->
      // { 'type': <string>,
      //   'local': <{table, key}>,
      //   'foreign': <{table, key, [as]}>,
      //   'optional': <null | boolean>  }

      forEach(relationships, function (rel) {
        if (rel.type == 'hasMany') return
        allFields = allFields.concat(getFields(rel.foreign, tables))
        joinString += this.joinSql(rel)
      }.bind(this))

      const selectFields =
        filterFields(allFields, includeFields, excludeFields)

      const joinStatement =
        fmt('SELECT %s FROM %s %s',
        selectAs(selectFields),
        escapeId(table),
        joinString)

      const statement = joinStatement
        + this.orderSql(table, opts.order)
        + this.limitSql(opts.limit, opts.page)

      return statement
    }

    function selectAs(fields) {
      return fields.map(function (field) {
        return fmt(
          '%s AS %s',
          escapeId(field),
          escapeId(field.replace('.', JOIN_SEP)))
      }).join(',')
    }

    function getFields(tableWithAlias, tables) {
      // XXX: probably shouldn't throw
      const name = tableWithAlias.table
      const alias = tableWithAlias.as || name
      const tableDef = tables[name]
      if (!tableDef)
        throw new Error(fmt('table %s is not registered', escapeId(name)))
      return tableDef.fields.map(function (field) {
        return [alias, field].join('.')
      })
    }

  },
  parseJoinRow: function (row, table, relationships) {
    const fixed = {}

    forEach(row, function (val, key) {
      fixLocalTable(key, fixed)
      forEach(relationships, function (_, relKey) {
        fixRelatedTable(key, relKey, fixed)
      })
    })

    function fixLocalTable(key, fixed) {
      const tablePrefix = table + JOIN_SEP
      if (key.indexOf(tablePrefix) !== 0)
        return
      fixed[key.replace(tablePrefix, '')] = row[key]
    }

    function fixRelatedTable(key, relKey, fixed) {
      const rel = relationships[relKey]
      const tableName = rel.foreign.as || rel.foreign.table
      const tablePrefix = tableName + JOIN_SEP

      if (key.indexOf(tablePrefix) !== 0)
        return

      const subObject = fixed[relKey] || {}
      const fixedKey = key.replace(tablePrefix, '')
      subObject[fixedKey] = row[key]
      fixed[relKey] = subObject
    }

    return fixed
  },
  fixHasOne: function (row, opts) {
    const table = opts.table
    const relationships = opts.relationships
    const tableCache = opts.tableCache
    row = this.parseJoinRow(row, table, relationships)
    forEach(relationships, function (rel, relKey) {
      if (rel.type !== 'hasOne') return
      const foreign = rel.foreign
      const foreignProto = tableCache[foreign.table].row
      row[relKey] = create(foreignProto, row[relKey])
    })

    return row
  },

  fixHasMany: function (globalRow, opts, callback) {
    var globalError
    const table = opts.table
    const tableCache = opts.tableCache
    const hasMany = {}
    forEach(opts.relationships, function (rel, relKey) {
      if (rel.type == 'hasMany')
        hasMany[relKey] = rel
    })

    if (!keys(hasMany).length) {
      return process.nextTick(function () {
        callback(null, globalRow)
      })
    }

    this.normalizeRelationships(table, hasMany)

    var waiting = keys(hasMany).length

    forEach(hasMany, function (rel, relKey) {
      if (globalError) return
      const cond = {}
      const foreign = tableCache[rel.foreign.table]
      const foreignProto = foreign.row

      cond[rel.foreign.key] = globalRow[rel.local.key]

      foreign.get(cond, function (err, rows) {
        if (globalError) return
        if (err) {
          globalError = err
          return callback(err, null)
        }

        globalRow[relKey] = rows.map(function (row) {
          return create(foreignProto, row)
        })

        return checkDone()
      })
    })

    function checkDone() {
      if (globalError) return
      if (--waiting > 0) return
      return callback(null, globalRow)
    }
  },
  hydrateRow: function (row, opts, callback) {
    if (isEmpty(opts.relationships))
      return nextTickCallback(callback, null, row)

    row = this.fixHasOne(row, {
      table: opts.table,
      relationships: opts.relationships,
      tableCache: opts.tableCache,
    })

    this.fixHasMany(row, {
      table: opts.table,
      relationships: opts.relationships,
      tableCache: opts.tableCache,
    }, callback)
  },
  hydrateRows: function (rows, opts, callback) {
    const results = []
    var waiting = rows.length
    var globalError

    if (isEmpty(opts.relationships))
      return nextTickCallback(callback, null, rows)

    rows.forEach(function (row, idx) {
      this.hydrateRow(row, opts, function (err, result) {
        if (globalError) return
        if (err) {
          globalError = err
          return callback(err)
        }
        storeResult(result, idx)
      })
    }, this)

    function storeResult(result, pos) {
      results[pos] = result
      if (--waiting > 0) return
      callback(null, results)
    }
  },
  streamHandlers: function (stream, opts) {
    var waiting = 0
    var finishing = false

    const driver = this
    const table = opts.table
    const rowProto = opts.rowPrototype
    const relationships = opts.relationships
    const tableCache = opts.tableCache

    const withRelationships =
      (relationships && keys(relationships).length)

    function onResult(row) {
      if (!withRelationships) {
        row = create(rowProto, row)
        return stream.emit('data', row)
      }

      waiting ++

      // fulfills both hasOne and hasMany relationships
      driver.hydrateRow(row, {
        table: table,
        relationships: relationships,
        tableCache: tableCache,
      }, function (err, row) {
        waiting --
        if (err) return stream.emit(err)
        stream.emit('data', create(rowProto, row))
        checkDone()
      })
    }

    function endCallback(err) {
      if (err) return stream.emit('error', err)
      if (waiting > 0) {
        finishing = true
        return false
      }
      stream.emit('end')
    }

    function checkDone() {
      if (finishing && !waiting)
        stream.emit('end')
    }

    return { row: onResult, done: endCallback }

  },
  normalizeRelationships: function (table, relationships) {
    forEach(relationships, function (rel, relKey) {
      if (!rel.local)
        rel.local = { table: table, key: relKey }

      if (typeof rel.local === 'string')
        rel.local = { table: table, key: rel.local }
    })
    return relationships
  },

  joinSql: function (opts) {
    // opts --> <see `withJoin` above>
    const local = opts.local
    const foreign = opts.foreign
    const joinType = opts.optional ? ' LEFT ' : ' INNER '
    const localKey = fmt('%s.%s', local.table, local.key)
    const foreignTableAlias = foreign.as || foreign.table
    const foreignKey = fmt('%s.%s', foreignTableAlias, foreign.key)

    const statement = joinType
      + ' JOIN ' + this.escapeId(foreign.table)
      + ' AS '   + this.escapeId(foreignTableAlias)
      + ' ON '   + this.escapeId(localKey)
      + ' = '    + this.escapeId(foreignKey)

    return statement
  },
  insertSql: function insertSql(table, row) {
    const columns = keys(row)
    const values = vals(row)

    const tpl = 'INSERT INTO %s (%s) VALUES (%s)'
    return fmt(tpl, this.escapeId(table),
               map(columns, this.escapeId),
               map(values, this.escape))
  },
  updateSql: function updateSql(table, row, primaryKey) {
    const escape = this.escape
    const escapeId = this.escapeId
    const pairs = map(row, function (val, col) {
      return fmt('%s = %s', escapeId(col), escape(val))
    })
    return fmt('UPDATE %s SET %s WHERE %s = %s',
               escapeId(table),
               pairs,
               escapeId(primaryKey),
               escape(row[primaryKey]))
  },
  deleteSql: function deleteSql(opts) {
    const table = opts.table
    const conds = opts.conditions
    const limit = opts.limit

    const statement = ''
      + fmt('DELETE FROM %s', this.escapeId(table))
      + this.whereSql(table, conds)
      + this.limitSql(limit)

    return statement
  },
}

function appearsLast(string, sub) {
  const index = string.indexOf(sub)
  if (index == -1) return false
  return string.slice(index) == sub
}

function filterFields(fields, includeFields, excludeFields) {
  if (!includeFields && !excludeFields)
    return fields

  // we always include ids because they are needed for proper
  // relationship fulfillment
  if (includeFields)
    includeFields.push('id')

  return fields.filter(function (field) {
    function search(needle) {
      return appearsLast(field, needle)
    }
    if (includeFields)
      return includeFields.some(search)
    if (excludeFields)
      return !excludeFields.some(search)
    return field
  })
}

function map(obj, fn) {
  return Object.keys(obj).map(function (key) {
    return fn(obj[key], key)
  })
}

function forEach(obj, fn) {
  return Object.keys(obj).forEach(function (key) {
    fn(obj[key], key)
  })
}

function keys(o) {
  return Object.keys(o)
}

function vals(o) {
  return map(o, function (val) { return val })
}

function isEmpty(obj) {
  return (!obj || !keys(obj).length)
}

function nextTickCallback(callback, err, arg) {
  return process.nextTick(function () {
    callback(null, arg)
  })
}
<commit_msg>Adding `where` clause to joined queries<commit_after>const create = require('../create')
const util = require('util')
const Stream = require('stream')
const sqlstring = require('../sqlstring')

const fmt = util.format.bind(util)

const JOIN_SEP = ':@:'

module.exports = {
  escape: function escape(value) {
    return sqlstring.escape(value)
  },
  escapeId: function escapeId(id) {
    return sqlstring.escapeId(id)
  },
  whereSql: function whereSql(table, conditions) {
    const hasConditons = conditions && keys(conditions).length
    if (!hasConditons) return ''

    const escape = this.escape
    const escapeId = this.escapeId
    var where = ' WHERE '

    var clauses = map(conditions, function (val, key) {
      const field = escapeId([table, key].join('.'))
      var cnd = conditions[key]

      if (Array.isArray(cnd)) {
        // if the condition is a simple array,
        // e.g { release_date: [2000,1996] }
        // use an `in` operator.
        if (typeof cnd[0] != 'object') {
          cnd = cnd.map(function (x) { return escape(x) })
          return fmt('%s IN (%s)', field, cnd.join(','))
        }

        return cnd.map(function (subcnd) {
          const operation = subcnd.op
          const value = escape(subcnd.value)
          return fmt('%s %s %s', field, operation, value)
        }).join(' AND ')
      }

      const op = cnd.operation || cnd.op || '='
      if (cnd.value) cnd = cnd.value
      return fmt('%s %s %s', field, op, escape(cnd))
    })

    where += clauses.join(' AND ')
    return where
  },
  orderSql: function orderSql(table, order) {
    if (!order) return ''

    const escape = this.escape
    const escapeId = this.escapeId

    // order can be one of three styles:
    // * implicit ascending, single: 'title'
    // * implicit ascending, multi: ['release_date', 'title']
    // * explicit: { title: 'desc', release_date: 'asc' }

    if (typeof order == 'string') {
      return fmt(' ORDER BY %s ', escapeId(order))
    }

    if (Array.isArray(order))
      return fmt(' ORDER BY %s ', order.map(escapeId).join(','))

    // must be an object
    return fmt(' ORDER BY %s ', map(order, function (value, key) {
      return fmt('%s %s', escapeId(key), value.toUpperCase())
    }).join(','))
  },
  limitSql: function limitSql(limit, page) {
    if (!limit) return ''
    if (!page) return fmt(' LIMIT %s ', limit)
    const beginning = (page - 1) * limit
    return fmt(' LIMIT %s,%s ', beginning, limit)
  },

  selectSql: function selectSql(opts) {
    const escapeId = this.escapeId
    const escape = this.escape
    const table = opts.table
    const tables = opts.tables
    const fields = opts.fields
    const conds = opts.conditions
    const includeFields = opts.include
    const excludeFields = opts.exclude
    const relationships = opts.relationships
    const useRaw = Array.isArray(conds)
    const useJoin = (relationships && keys(relationships).length)

    if (useRaw) return rawSql.call(this)
    if (useJoin) return withJoin.call(this)

    const fieldList = filterFields(fields, includeFields, excludeFields)
      .map(escapeId).join(',')

    const statement = ''
      + fmt('SELECT %s FROM %s', fieldList, escapeId(table))
      + this.whereSql(table, conds)
      + this.orderSql(table, opts.order)
      + this.limitSql(opts.limit, opts.page)

    return statement

    function rawSql() {
      const sql = conds[0].replace(/\$table/i, escapeId(table))
      const values = conds[1].map(escape)
      const statement = values.reduce(function (sql, value) {
        return sql.replace('?', value)
      }, sql)
      return statement
    }

    function withJoin() {
      var allFields = fields
        .slice().map(function (field) {
          return [table, field].join('.')
        })

      var joinString = ''

      this.normalizeRelationships(table, relationships)

      // in the loop below, rel -->
      // { 'type': <string>,
      //   'local': <{table, key}>,
      //   'foreign': <{table, key, [as]}>,
      //   'optional': <null | boolean>  }

      forEach(relationships, function (rel) {
        if (rel.type == 'hasMany') return
        allFields = allFields.concat(getFields(rel.foreign, tables))
        joinString += this.joinSql(rel)
      }.bind(this))

      const selectFields =
        filterFields(allFields, includeFields, excludeFields)

      const joinStatement =
        fmt('SELECT %s FROM %s %s',
        selectAs(selectFields),
        escapeId(table),
        joinString)

      const statement = joinStatement
        + this.whereSql(table, conds)
        + this.orderSql(table, opts.order)
        + this.limitSql(opts.limit, opts.page)

      return statement
    }

    function selectAs(fields) {
      return fields.map(function (field) {
        return fmt(
          '%s AS %s',
          escapeId(field),
          escapeId(field.replace('.', JOIN_SEP)))
      }).join(',')
    }

    function getFields(tableWithAlias, tables) {
      // XXX: probably shouldn't throw
      const name = tableWithAlias.table
      const alias = tableWithAlias.as || name
      const tableDef = tables[name]
      if (!tableDef)
        throw new Error(fmt('table %s is not registered', escapeId(name)))
      return tableDef.fields.map(function (field) {
        return [alias, field].join('.')
      })
    }

  },
  parseJoinRow: function (row, table, relationships) {
    const fixed = {}

    forEach(row, function (val, key) {
      fixLocalTable(key, fixed)
      forEach(relationships, function (_, relKey) {
        fixRelatedTable(key, relKey, fixed)
      })
    })

    function fixLocalTable(key, fixed) {
      const tablePrefix = table + JOIN_SEP
      if (key.indexOf(tablePrefix) !== 0)
        return
      fixed[key.replace(tablePrefix, '')] = row[key]
    }

    function fixRelatedTable(key, relKey, fixed) {
      const rel = relationships[relKey]
      const tableName = rel.foreign.as || rel.foreign.table
      const tablePrefix = tableName + JOIN_SEP

      if (key.indexOf(tablePrefix) !== 0)
        return

      const subObject = fixed[relKey] || {}
      const fixedKey = key.replace(tablePrefix, '')
      subObject[fixedKey] = row[key]
      fixed[relKey] = subObject
    }

    return fixed
  },
  fixHasOne: function (row, opts) {
    const table = opts.table
    const relationships = opts.relationships
    const tableCache = opts.tableCache
    row = this.parseJoinRow(row, table, relationships)
    forEach(relationships, function (rel, relKey) {
      if (rel.type !== 'hasOne') return
      const foreign = rel.foreign
      const foreignProto = tableCache[foreign.table].row
      row[relKey] = create(foreignProto, row[relKey])
    })

    return row
  },

  fixHasMany: function (globalRow, opts, callback) {
    var globalError
    const table = opts.table
    const tableCache = opts.tableCache
    const hasMany = {}
    forEach(opts.relationships, function (rel, relKey) {
      if (rel.type == 'hasMany')
        hasMany[relKey] = rel
    })

    if (!keys(hasMany).length) {
      return process.nextTick(function () {
        callback(null, globalRow)
      })
    }

    this.normalizeRelationships(table, hasMany)

    var waiting = keys(hasMany).length

    forEach(hasMany, function (rel, relKey) {
      if (globalError) return
      const cond = {}
      const foreign = tableCache[rel.foreign.table]
      const foreignProto = foreign.row

      cond[rel.foreign.key] = globalRow[rel.local.key]

      foreign.get(cond, function (err, rows) {
        if (globalError) return
        if (err) {
          globalError = err
          return callback(err, null)
        }

        globalRow[relKey] = rows.map(function (row) {
          return create(foreignProto, row)
        })

        return checkDone()
      })
    })

    function checkDone() {
      if (globalError) return
      if (--waiting > 0) return
      return callback(null, globalRow)
    }
  },
  hydrateRow: function (row, opts, callback) {
    if (isEmpty(opts.relationships))
      return nextTickCallback(callback, null, row)

    row = this.fixHasOne(row, {
      table: opts.table,
      relationships: opts.relationships,
      tableCache: opts.tableCache,
    })

    this.fixHasMany(row, {
      table: opts.table,
      relationships: opts.relationships,
      tableCache: opts.tableCache,
    }, callback)
  },
  hydrateRows: function (rows, opts, callback) {
    const results = []
    var waiting = rows.length
    var globalError

    if (isEmpty(opts.relationships))
      return nextTickCallback(callback, null, rows)

    rows.forEach(function (row, idx) {
      this.hydrateRow(row, opts, function (err, result) {
        if (globalError) return
        if (err) {
          globalError = err
          return callback(err)
        }
        storeResult(result, idx)
      })
    }, this)

    function storeResult(result, pos) {
      results[pos] = result
      if (--waiting > 0) return
      callback(null, results)
    }
  },
  streamHandlers: function (stream, opts) {
    var waiting = 0
    var finishing = false

    const driver = this
    const table = opts.table
    const rowProto = opts.rowPrototype
    const relationships = opts.relationships
    const tableCache = opts.tableCache

    const withRelationships =
      (relationships && keys(relationships).length)

    function onResult(row) {
      if (!withRelationships) {
        row = create(rowProto, row)
        return stream.emit('data', row)
      }

      waiting ++

      // fulfills both hasOne and hasMany relationships
      driver.hydrateRow(row, {
        table: table,
        relationships: relationships,
        tableCache: tableCache,
      }, function (err, row) {
        waiting --
        if (err) return stream.emit(err)
        stream.emit('data', create(rowProto, row))
        checkDone()
      })
    }

    function endCallback(err) {
      if (err) return stream.emit('error', err)
      if (waiting > 0) {
        finishing = true
        return false
      }
      stream.emit('end')
    }

    function checkDone() {
      if (finishing && !waiting)
        stream.emit('end')
    }

    return { row: onResult, done: endCallback }

  },
  normalizeRelationships: function (table, relationships) {
    forEach(relationships, function (rel, relKey) {
      if (!rel.local)
        rel.local = { table: table, key: relKey }

      if (typeof rel.local === 'string')
        rel.local = { table: table, key: rel.local }
    })
    return relationships
  },

  joinSql: function (opts) {
    // opts --> <see `withJoin` above>
    const local = opts.local
    const foreign = opts.foreign
    const joinType = opts.optional ? ' LEFT ' : ' INNER '
    const localKey = fmt('%s.%s', local.table, local.key)
    const foreignTableAlias = foreign.as || foreign.table
    const foreignKey = fmt('%s.%s', foreignTableAlias, foreign.key)

    const statement = joinType
      + ' JOIN ' + this.escapeId(foreign.table)
      + ' AS '   + this.escapeId(foreignTableAlias)
      + ' ON '   + this.escapeId(localKey)
      + ' = '    + this.escapeId(foreignKey)

    return statement
  },
  insertSql: function insertSql(table, row) {
    const columns = keys(row)
    const values = vals(row)

    const tpl = 'INSERT INTO %s (%s) VALUES (%s)'
    return fmt(tpl, this.escapeId(table),
               map(columns, this.escapeId),
               map(values, this.escape))
  },
  updateSql: function updateSql(table, row, primaryKey) {
    const escape = this.escape
    const escapeId = this.escapeId
    const pairs = map(row, function (val, col) {
      return fmt('%s = %s', escapeId(col), escape(val))
    })
    return fmt('UPDATE %s SET %s WHERE %s = %s',
               escapeId(table),
               pairs,
               escapeId(primaryKey),
               escape(row[primaryKey]))
  },
  deleteSql: function deleteSql(opts) {
    const table = opts.table
    const conds = opts.conditions
    const limit = opts.limit

    const statement = ''
      + fmt('DELETE FROM %s', this.escapeId(table))
      + this.whereSql(table, conds)
      + this.limitSql(limit)

    return statement
  },
}

function appearsLast(string, sub) {
  const index = string.indexOf(sub)
  if (index == -1) return false
  return string.slice(index) == sub
}

function filterFields(fields, includeFields, excludeFields) {
  if (!includeFields && !excludeFields)
    return fields

  // we always include ids because they are needed for proper
  // relationship fulfillment
  if (includeFields)
    includeFields.push('id')

  return fields.filter(function (field) {
    function search(needle) {
      return appearsLast(field, needle)
    }
    if (includeFields)
      return includeFields.some(search)
    if (excludeFields)
      return !excludeFields.some(search)
    return field
  })
}

function map(obj, fn) {
  return Object.keys(obj).map(function (key) {
    return fn(obj[key], key)
  })
}

function forEach(obj, fn) {
  return Object.keys(obj).forEach(function (key) {
    fn(obj[key], key)
  })
}

function keys(o) {
  return Object.keys(o)
}

function vals(o) {
  return map(o, function (val) { return val })
}

function isEmpty(obj) {
  return (!obj || !keys(obj).length)
}

function nextTickCallback(callback, err, arg) {
  return process.nextTick(function () {
    callback(null, arg)
  })
}
<|endoftext|>


<commit_before>import React from 'react'
import { Provider } from 'react-redux'
import configureStore from './store'
import App from './containers/App'
import { fetchConferences } from './actions/conference'
import { fetchSessions } from './actions/session'
import { setDays, setSelectedDay } from './actions/filter'
import { getDays, getSelectedDayBySlug } from './util'
import config from './config'

const initialState = {}
const slug = config.conferenceSlug
const store = configureStore(initialState)

store.dispatch(fetchConferences())
store.dispatch(fetchSessions(slug))
store.dispatch(setDays(getDays(slug)))
store.dispatch(setSelectedDay(getSelectedDayBySlug(slug)))

const Main = () => (
    <Provider store={store}>
        <App />
    </Provider>
)

export default Main<commit_msg>refac to set  uuid on mount<commit_after>import React, { Component } from 'react'
import { Provider } from 'react-redux'
import configureStore from './store'
import App from './containers/App'
import { fetchConferences } from './actions/conference'
import { fetchSessions } from './actions/session'
import { setUUID } from './actions/uuid'
import { setDays, setSelectedDay } from './actions/filter'
import { getDays, getSelectedDayBySlug, createUUID } from './util'
import config from './config'

const initialState = {}
const slug = config.conferenceSlug
const store = configureStore(initialState)

class Main extends Component {
    componentWillMount() {
      store.dispatch(fetchConferences())
      store.dispatch(fetchSessions(slug))
      store.dispatch(setDays(getDays(slug)))
      store.dispatch(setSelectedDay(getSelectedDayBySlug(slug)))
      store.dispatch(setUUID(createUUID()))
    }

    render() {
      return (
        <Provider store={store}>
          <App />
        </Provider>
      )
    }
}

export default Main<|endoftext|>


<commit_before>
module.exports = readJson
readJson.processJson = processJson
readJson.unParsePeople = unParsePeople
readJson.parsePeople = parsePeople

var fs = require("./graceful-fs")
  , semver = require("./semver")
  , path = require("path")
  , log = require("./log")
  , npm = require("../../npm")
  , cache = {}
  , timers = {}
function readJson (jsonFile, opts, cb) {
  if (typeof cb !== "function") cb = opts, opts = {}
  if (cache.hasOwnProperty(jsonFile)) {
    log.verbose(jsonFile, "from cache")
    return cb(null, cache[jsonFile])
  }
  fs.readFile( path.join(path.dirname(jsonFile), "wscript")
             , function (er, data) {
    opts.file = jsonFile
    if (er) opts.wscript = false
    else opts.wscript = data.toString().match(/(^|\n)def build\b/)
                      && data.toString().match(/(^|\n)def configure\b/)
    fs.readFile(jsonFile, processJson(opts, cb))
  })
}
function processJson (opts, cb) {
  if (typeof cb !== "function") cb = opts, opts = {}
  if (typeof cb !== "function") {
    var thing = cb, cb = null
    return P(null, thing)
  } else return P

  function P (er, thing) {
    if (er) {
      if (cb) return cb(er, thing)
      throw er
    }
    if (typeof thing === "object" && !Buffer.isBuffer(thing)) {
      return processObject(opts, cb)(er, thing)
    } else {
      return processJsonString(opts, cb)(er, thing)
    }
  }
}
function processJsonString (opts, cb) { return function (er, jsonString) {
  jsonString += ""
  if (er) return cb(er, jsonString)
  var json
  try {
    json = JSON.parse(jsonString)
  } catch (ex2) { try {
    json = process.binding("evals").Script.runInNewContext(
      "(\n"+jsonString+"\n)")
  } catch (ex) {
    var e = new Error(
      "Failed to parse json\n"+ex.message+"\n"+ex2.message+"\n"+jsonString)
    if (cb) return cb(e)
    throw e
  }}
  return processObject(opts, cb)(er, json)
}}
function processObject (opts, cb) { return function (er, json) {
  if (json.overlay) {
    ;["node", "npm"].forEach(function (k) {
      if (!json.overlay[k]) return undefined
      for (var i in json.overlay[k]) json[i] = json.overlay[k][i]
    })
  }

  // slashes would be a security risk.
  // anything else will just fail harmlessly.
  if (!json.name) {
    var e = new Error("No 'name' field found in package.json")
    if (cb) return cb(e)
    throw e
  }
  json.name = json.name.trim()
  if (json.name.charAt(0) === "." || json.name.match(/[\/@\s\+%:]/)) {
    var msg = "Invalid name: "
            + JSON.stringify(json.name)
            + " may not start with '.' or contain %/@+: or whitespace"
      , e = new Error(msg)
    if (cb) return cb(e)
    throw e
  }
  if (json.name === "favicon.ico") {
    var msg = "Sorry, favicon.ico is a picture, not a package."
      , e = new Error(msg)
    if (cb) return cb(e)
    throw e
  }
  var tag = opts.tag
  if (tag) json.version = tag//+"-"+json.version

  // FIXME: uncomment in 0.3.0, once it's not likely that people will
  // have a bunch of main.js files kicking around any more, and remove
  // this functionality from lib/build.js
  //
  // if (json.main) {
  //   if (!json.modules) json.modules = {}
  //   json.modules.index = json.main
  //   delete json.main
  // }
  if (json.modules) {
    if (typeof json.modules !== "object") {
      var e = new Error("Invalid modules object")
      if (cb) return cb(e)
      throw e
    }
    Object.keys(json.modules).forEach(function (mod) {
      if (typeof json.modules[mod] !== "string") {
        var e = new Error("Invalid module "+mod+", not a string: "
                         +JSON.stringify(json.modules[mod]))
        if (cb) return cb(e)
        throw e
      }
    })
  }

  if (opts.wscript) {
    var scripts = json.scripts = json.scripts || {}
    if (!scripts.install && !scripts.preinstall) {
      // don't fail if it was unexpected, just try.
      scripts.preinstall = "node-waf configure build"
    }
  }

  if (!(semver.valid(json.version))) {
    var e = new Error("Invalid version: "+json.version+"\n"
                     +"Must be X.Y.Z, with an optional trailing tag.\n"
                     +"See the section on 'version' in `npm help json`"
                     )
    if (cb) return cb(e)
    throw e
  }
  json.version = semver.clean(json.version)

  if (json.main) json.main = json.main.replace(/(\.js|\.node)$/, '')

  if (json.bin && typeof json.bin === "string") {
    var b = {}
    b[ path.basename( json.bin ) ] = json.bin
    json.bin = b
  }

  if (json["dev-dependencies"] && !json.devDependencies) {
    json.devDependencies = json["dev-dependencies"]
    delete json["dev-dependencies"]
  }
  ;["dependencies", "devDependencies"].forEach(function (d) {
    if (!json[d]) return
    json[d] = depObjectify(json[d])
  })

  json._id = json.name+"@"+json.version
  json = testEngine(json)
  json = parsePeople(unParsePeople(json))
  if ( json.bugs ) json.bugs = parsePerson(unParsePerson(json.bugs))
  json._npmVersion = npm.version
  json._nodeVersion = process.version
  if (opts.file) {
    log.verbose(opts.file, "caching")
    cache[opts.file] = json
    // arbitrary
    var keys = Object.keys(cache)
      , l = keys.length
    if (l > 10000) for (var i = 5000; i < l; i ++) {
     delete cache[keys[i]]
    }
  }
  if (cb) cb(null,json)
  return json
}}
function depObjectify (deps) {
  if (!Array.isArray(deps)) return deps
  var o = {}
  deps.forEach(function (d) {
    d = d.trim().split(/(:?[@\s><=])/)
    o[d.shift()] = d.join("").trim().replace(/^@/, "")
  })
  return o
}
function testEngine (json) {
  // if engines is empty, then assume that node is allowed.
  log.silly(json, "testEngine")
  if ( !json.engines
      || Array.isArray(json.engines)
        && !json.engines.length
      || typeof json.engines === "object"
        && !Object.keys(json.engines).length
      ) {
    json.engines = { "node" : "*" }
  }
  if (typeof json.engines === "string") {
    if (semver.validRange(json.engines) !== null) {
      json.engines = { "node" : json.engines }
    } else json.engines = [ json.engines ]
  }

  var nodeVer = process.version.replace(/\+$/, '')
    , ok = false
  if (Array.isArray(json.engines)) {
    // Packages/1.0 commonjs style, with an array.
    // hack it to just hang a "node" member with the version range,
    // then do the npm-style check below.
    for (var i = 0, l = json.engines.length; i < l; i ++) {
      var e = json.engines[i].trim()
      if (e.substr(0, 4) === "node") {
        json.engines.node = e.substr(4)
      } else if (e.substr(0, 3) === "npm") {
        json.engines.npm = e.substr(3)
      }
    }
  }
  if (json.engines.node === "") json.engines.node = "*"
  if (json.engines.node && null === semver.validRange(json.engines.node)) {
    log.warn( json.engines.node
            , "not a valid range.  Please see `npm help json`" )
  }

  json._engineSupported = semver.satisfies(nodeVer, json.engines.node||"null")
  if (json.engines.hasOwnProperty("npm") && json._engineSupported) {
    json._engineSupported = semver.satisfies(npm.version, json.engines.npm)
  }
  return json
}

function unParsePeople (json) { return parsePeople(json, true) }
function parsePeople (json, un) {
  var fn = un ? unParsePerson : parsePerson
  if (json.author) json.author = fn(json.author)
  ;["maintainers", "contributors"].forEach(function (set) {
    if (Array.isArray(json[set])) json[set] = json[set].map(fn)
  })
  return json
}
function unParsePerson (person) {
  if (typeof person === "string") return person
  var name = person.name || ""
    , u = person.url || person.web
    , url = u ? (" ("+u+")") : ""
    , e = person.email || person.mail
    , email = e ? (" <"+e+">") : ""
  return name+email+url
}
function parsePerson (person) {
  if (typeof person !== "string") return person
  var name = person.match(/^([^\(<]+)/)
    , url = person.match(/\(([^\)]+)\)/)
    , email = person.match(/<([^>]+)>/)
    , obj = {}
  if (name && name[0].trim()) obj.name = name[0].trim()
  if (email) obj.email = email[1]
  if (url) obj.url = url[1]
  return obj
}
<commit_msg>Clear LRU from cache first.<commit_after>
module.exports = readJson
readJson.processJson = processJson
readJson.unParsePeople = unParsePeople
readJson.parsePeople = parsePeople

var fs = require("./graceful-fs")
  , semver = require("./semver")
  , path = require("path")
  , log = require("./log")
  , npm = require("../../npm")
  , cache = {}
  , timers = {}
function readJson (jsonFile, opts, cb) {
  if (typeof cb !== "function") cb = opts, opts = {}
  if (cache.hasOwnProperty(jsonFile)) {
    log.verbose(jsonFile, "from cache")
    return cb(null, cache[jsonFile])
  }
  fs.readFile( path.join(path.dirname(jsonFile), "wscript")
             , function (er, data) {
    opts.file = jsonFile
    if (er) opts.wscript = false
    else opts.wscript = data.toString().match(/(^|\n)def build\b/)
                      && data.toString().match(/(^|\n)def configure\b/)
    fs.readFile(jsonFile, processJson(opts, cb))
  })
}
function processJson (opts, cb) {
  if (typeof cb !== "function") cb = opts, opts = {}
  if (typeof cb !== "function") {
    var thing = cb, cb = null
    return P(null, thing)
  } else return P

  function P (er, thing) {
    if (er) {
      if (cb) return cb(er, thing)
      throw er
    }
    if (typeof thing === "object" && !Buffer.isBuffer(thing)) {
      return processObject(opts, cb)(er, thing)
    } else {
      return processJsonString(opts, cb)(er, thing)
    }
  }
}
function processJsonString (opts, cb) { return function (er, jsonString) {
  jsonString += ""
  if (er) return cb(er, jsonString)
  var json
  try {
    json = JSON.parse(jsonString)
  } catch (ex2) { try {
    json = process.binding("evals").Script.runInNewContext(
      "(\n"+jsonString+"\n)")
  } catch (ex) {
    var e = new Error(
      "Failed to parse json\n"+ex.message+"\n"+ex2.message+"\n"+jsonString)
    if (cb) return cb(e)
    throw e
  }}
  return processObject(opts, cb)(er, json)
}}
function processObject (opts, cb) { return function (er, json) {
  if (json.overlay) {
    ;["node", "npm"].forEach(function (k) {
      if (!json.overlay[k]) return undefined
      for (var i in json.overlay[k]) json[i] = json.overlay[k][i]
    })
  }

  // slashes would be a security risk.
  // anything else will just fail harmlessly.
  if (!json.name) {
    var e = new Error("No 'name' field found in package.json")
    if (cb) return cb(e)
    throw e
  }
  json.name = json.name.trim()
  if (json.name.charAt(0) === "." || json.name.match(/[\/@\s\+%:]/)) {
    var msg = "Invalid name: "
            + JSON.stringify(json.name)
            + " may not start with '.' or contain %/@+: or whitespace"
      , e = new Error(msg)
    if (cb) return cb(e)
    throw e
  }
  if (json.name === "favicon.ico") {
    var msg = "Sorry, favicon.ico is a picture, not a package."
      , e = new Error(msg)
    if (cb) return cb(e)
    throw e
  }
  var tag = opts.tag
  if (tag) json.version = tag//+"-"+json.version

  // FIXME: uncomment in 0.3.0, once it's not likely that people will
  // have a bunch of main.js files kicking around any more, and remove
  // this functionality from lib/build.js
  //
  // if (json.main) {
  //   if (!json.modules) json.modules = {}
  //   json.modules.index = json.main
  //   delete json.main
  // }
  if (json.modules) {
    if (typeof json.modules !== "object") {
      var e = new Error("Invalid modules object")
      if (cb) return cb(e)
      throw e
    }
    Object.keys(json.modules).forEach(function (mod) {
      if (typeof json.modules[mod] !== "string") {
        var e = new Error("Invalid module "+mod+", not a string: "
                         +JSON.stringify(json.modules[mod]))
        if (cb) return cb(e)
        throw e
      }
    })
  }

  if (opts.wscript) {
    var scripts = json.scripts = json.scripts || {}
    if (!scripts.install && !scripts.preinstall) {
      // don't fail if it was unexpected, just try.
      scripts.preinstall = "node-waf configure build"
    }
  }

  if (!(semver.valid(json.version))) {
    var e = new Error("Invalid version: "+json.version+"\n"
                     +"Must be X.Y.Z, with an optional trailing tag.\n"
                     +"See the section on 'version' in `npm help json`"
                     )
    if (cb) return cb(e)
    throw e
  }
  json.version = semver.clean(json.version)

  if (json.main) json.main = json.main.replace(/(\.js|\.node)$/, '')

  if (json.bin && typeof json.bin === "string") {
    var b = {}
    b[ path.basename( json.bin ) ] = json.bin
    json.bin = b
  }

  if (json["dev-dependencies"] && !json.devDependencies) {
    json.devDependencies = json["dev-dependencies"]
    delete json["dev-dependencies"]
  }
  ;["dependencies", "devDependencies"].forEach(function (d) {
    if (!json[d]) return
    json[d] = depObjectify(json[d])
  })

  json._id = json.name+"@"+json.version
  json = testEngine(json)
  json = parsePeople(unParsePeople(json))
  if ( json.bugs ) json.bugs = parsePerson(unParsePerson(json.bugs))
  json._npmVersion = npm.version
  json._nodeVersion = process.version
  if (opts.file) {
    log.verbose(opts.file, "caching")
    cache[opts.file] = json
    // arbitrary
    var keys = Object.keys(cache)
      , l = keys.length
    if (l > 10000) for (var i = 0; i < l - 5000; i ++) {
      delete cache[keys[i]]
    }
  }
  if (cb) cb(null,json)
  return json
}}
function depObjectify (deps) {
  if (!Array.isArray(deps)) return deps
  var o = {}
  deps.forEach(function (d) {
    d = d.trim().split(/(:?[@\s><=])/)
    o[d.shift()] = d.join("").trim().replace(/^@/, "")
  })
  return o
}
function testEngine (json) {
  // if engines is empty, then assume that node is allowed.
  log.silly(json, "testEngine")
  if ( !json.engines
      || Array.isArray(json.engines)
        && !json.engines.length
      || typeof json.engines === "object"
        && !Object.keys(json.engines).length
      ) {
    json.engines = { "node" : "*" }
  }
  if (typeof json.engines === "string") {
    if (semver.validRange(json.engines) !== null) {
      json.engines = { "node" : json.engines }
    } else json.engines = [ json.engines ]
  }

  var nodeVer = process.version.replace(/\+$/, '')
    , ok = false
  if (Array.isArray(json.engines)) {
    // Packages/1.0 commonjs style, with an array.
    // hack it to just hang a "node" member with the version range,
    // then do the npm-style check below.
    for (var i = 0, l = json.engines.length; i < l; i ++) {
      var e = json.engines[i].trim()
      if (e.substr(0, 4) === "node") {
        json.engines.node = e.substr(4)
      } else if (e.substr(0, 3) === "npm") {
        json.engines.npm = e.substr(3)
      }
    }
  }
  if (json.engines.node === "") json.engines.node = "*"
  if (json.engines.node && null === semver.validRange(json.engines.node)) {
    log.warn( json.engines.node
            , "not a valid range.  Please see `npm help json`" )
  }

  json._engineSupported = semver.satisfies(nodeVer, json.engines.node||"null")
  if (json.engines.hasOwnProperty("npm") && json._engineSupported) {
    json._engineSupported = semver.satisfies(npm.version, json.engines.npm)
  }
  return json
}

function unParsePeople (json) { return parsePeople(json, true) }
function parsePeople (json, un) {
  var fn = un ? unParsePerson : parsePerson
  if (json.author) json.author = fn(json.author)
  ;["maintainers", "contributors"].forEach(function (set) {
    if (Array.isArray(json[set])) json[set] = json[set].map(fn)
  })
  return json
}
function unParsePerson (person) {
  if (typeof person === "string") return person
  var name = person.name || ""
    , u = person.url || person.web
    , url = u ? (" ("+u+")") : ""
    , e = person.email || person.mail
    , email = e ? (" <"+e+">") : ""
  return name+email+url
}
function parsePerson (person) {
  if (typeof person !== "string") return person
  var name = person.match(/^([^\(<]+)/)
    , url = person.match(/\(([^\)]+)\)/)
    , email = person.match(/<([^>]+)>/)
    , obj = {}
  if (name && name[0].trim()) obj.name = name[0].trim()
  if (email) obj.email = email[1]
  if (url) obj.url = url[1]
  return obj
}
<|endoftext|>


<commit_before>import is_nil from 'lodash.isnil';
import noop from 'lodash.noop';
import uniq from 'lodash.uniq';

export function defaultOnBeforeRender(el) {
	el.innerHTML = '';
}

export function defaultOnDestroy(el) {
	el.remove();
}

export function createElement({el, attributes, classNames, id, tagName}) {
	if (is_nil(el)) {
		el = document.createElement(tagName);
		el.className = uniq(classNames).join(' ');
		el.id = id;
		for (let [key, value] of Object.entries(attributes)) {
			el.setAttribute(key, value);
		}
	}
	return el;
}

export function createEventsManager(state, render) {
	const events_handlers = Object.entries(state.events).map(([event, handler]) => ([
		event,
		ev => handler(ev, state.el, state.model)
	]));
	return {
		connect() {
			if (!state.connected) {
				state.connected = true;
				for (let [event, handler] of events_handlers) {
					state.el.addEventListener(event, handler);
				}
				if (!is_nil(state.model)) {
					state.model.on('changed', render);
				}
			}
		},
		disconnect() {
			state.connected = false;
			for (let [event, handler] of events_handlers) {
				state.el.removeEventListener(event, handler);
			}
			if (!is_nil(state.model)) {
				state.model.removeListener('changed', render);
			}
		}
	};
}

export default ({
	el = null,
	classNames = [],
	id = '',
	tagName = 'div',
	attributes = {},
	events = {},
	model = null,
	onBeforeDestroy = noop,
	onBeforeRender = defaultOnBeforeRender,
	onRender = noop
} = {}) => {
	const state = {
		connected: false,
		el: createElement({el, attributes, classNames, id, tagName}),
		events,
		model
	};
	const render = () => {
		const {el, model} = state;
		onBeforeRender(el, model);
		onRender(el, model);
	};
	const {connect, disconnect} = createEventsManager(state, render);
	return ({
		destroy() {
			disconnect();
			onBeforeDestroy(el, model);
			state.el.remove();
		},
		el() {
			return state.el;
		},
		model() {
			return state.model;
		},
		setModel(model) {
			disconnect();
			state.model = model;
			connect();
			render();
			return this;
		},
		render() {
			render();
			return this;
		},
		connect() {
			connect();
			return this;
		},
		disconnect() {
			disconnect();
			return this;
		}
	}).connect();
}
<commit_msg>render when event handler return a truthy value<commit_after>import is_nil from 'lodash.isnil';
import noop from 'lodash.noop';
import uniq from 'lodash.uniq';

export function defaultOnBeforeRender(el) {
	el.innerHTML = '';
}

export function defaultOnDestroy(el) {
	el.remove();
}

export function createElement({el, attributes, classNames, id, tagName}) {
	if (is_nil(el)) {
		el = document.createElement(tagName);
		el.className = uniq(classNames).join(' ');
		el.id = id;
		for (let [key, value] of Object.entries(attributes)) {
			el.setAttribute(key, value);
		}
	}
	return el;
}

export function createEventsManager(state, render) {
	const events_handlers = Object.entries(state.events).map(([event, handler]) => ([
		event,
		ev => {
			if (handler(ev, state.el, state.model)) {
				render();
			}
		}
	]));
	return {
		connect() {
			if (!state.connected) {
				state.connected = true;
				for (let [event, handler] of events_handlers) {
					state.el.addEventListener(event, handler);
				}
				if (!is_nil(state.model)) {
					state.model.on('changed', render);
				}
			}
		},
		disconnect() {
			state.connected = false;
			for (let [event, handler] of events_handlers) {
				state.el.removeEventListener(event, handler);
			}
			if (!is_nil(state.model)) {
				state.model.removeListener('changed', render);
			}
		}
	};
}

export default ({
	el = null,
	classNames = [],
	id = '',
	tagName = 'div',
	attributes = {},
	events = {},
	model = null,
	onBeforeDestroy = noop,
	onBeforeRender = defaultOnBeforeRender,
	onRender = noop
} = {}) => {
	const state = {
		connected: false,
		el: createElement({el, attributes, classNames, id, tagName}),
		events,
		model
	};
	const render = () => {
		const {el, model} = state;
		onBeforeRender(el, model);
		onRender(el, model);
	};
	const {connect, disconnect} = createEventsManager(state, render);
	return ({
		destroy() {
			disconnect();
			onBeforeDestroy(el, model);
			state.el.remove();
		},
		el() {
			return state.el;
		},
		model() {
			return state.model;
		},
		setModel(model) {
			disconnect();
			state.model = model;
			connect();
			render();
			return this;
		},
		render() {
			render();
			return this;
		},
		connect() {
			connect();
			return this;
		},
		disconnect() {
			disconnect();
			return this;
		}
	}).connect();
}
<|endoftext|>


<commit_before>$(document).ready(function() {
  $('.octopus img').on('click', function(event){
    selected_div = event.target.parentNode;
    rating_value = $(selected_div).children('input').attr('value')
    $('.rated').removeClass('rated')
    $(selected_div).addClass('rated')
    $(selected_div).find('input').prop('checked', true)
    $(selected_div).prevAll('.octopus').addClass('rated')
  })
   $('.octopus img').on('mouseover', function(event){
    selected_div = event.target.parentNode;
    rating_value = $(selected_div).children('input').attr('value')
    $('.rate').removeClass('rate')
    $(selected_div).addClass('rate')
    $(selected_div).prevAll('.octopus').addClass('rate')
  })
  $('.octopus img').on('mouseout', function(event){
  	$('.rate').removeClass('rate')
  })
});<commit_msg>modify rating js to make it look better when hovering/clicking on divs and images<commit_after>$(document).ready(function() {
  $('.octopus').on('click', function(event){
    if (event.target.nodeName == "DIV"){
      selected_div = event.target;
    } else if (event.target.nodeName == "IMG"){
      selected_div = event.target.parentElement;
    }
    rating_value = $(selected_div).children('input').attr('value')
    $('.rated').removeClass('rated')
    $(selected_div).addClass('rated')
    $(selected_div).find('input').prop('checked', true)
    $(selected_div).prevAll('.octopus').addClass('rated')
  })
  $('.octopus').on('mouseover', function(event){
    if (event.target.nodeName == "DIV"){
      selected_div = event.target;
    } else if (event.target.nodeName == "IMG"){
      selected_div = event.target.parentElement;
    }
    $(selected_div).addClass('rate')
    $(selected_div).nextAll('.octopus').removeClass('rate')
    $(selected_div).prevAll('.octopus').addClass('rate')
  })
  $('#rating').on('mouseout', function(event){
    $('.rate').removeClass('rate')
  })
});<|endoftext|>


<commit_before>// For getting a new Morphic world setup in old Lively
import { num, arr } from "lively.lang";
import { pt, Color, Point, Rectangle, Transform } from "lively.graphics";
import { Renderer, morph, Text, EventDispatcher, Menu } from "lively.morphic";
import { ObjectDrawer } from "lively.morphic/widgets.js";

export function setupMorphicWorldOn(htmlMorph) {

  var rootNode = htmlMorph.renderContext().shapeNode;
  var world = morph({type: "world", extent: Point.ensure(htmlMorph.getExtent())})
  var renderer = new Renderer(world, rootNode);
  renderer.startRenderWorldLoop()
  var eventDispatcher = new EventDispatcher(window, world);
  eventDispatcher.install();

  var drawer = world.addMorph(new ObjectDrawer({position: pt(20,10)}));

  // FIXME currently used for show()
  window.$$world = world;

  return {world, renderer, eventDispatcher};
}

function addMorphicSetupMethods(htmlMorph) {
  htmlMorph.doNotSerialize = ["state"];
  htmlMorph.addScript(function cleanupNewMorphicWorld() {
    if (this.state) {
      var {renderer, eventDispatcher} = this.state;
      renderer && renderer.clear();
      eventDispatcher && eventDispatcher.uninstall();
    }
    this.setHTML('');
    this.state = {};
  });

  htmlMorph.addScript(function setupNewMorphicWorld() {
    this.cleanupNewMorphicWorld();
    return window.lively.next.bootstrapped
      .then(() => window.lively.modules.importPackage("node_modules/lively.morphic"))
      .then(() => window.System.import("lively.morphic/old-lively-helpers.js"))
      .then(helpers => this.state = helpers.setupMorphicWorldOn(this))
      .catch(err => window.$world.logError(err));
  });

  htmlMorph.addScript(function onLoad() {
    this.setupNewMorphicWorld();
  });
}

function createHtmlMorph() {
  var htmlMorph = new lively.morphic.HtmlWrapperMorph(pt(666,600));
  htmlMorph.addScript(function onMouseDown() {});
  htmlMorph.addScript(function onContextMenu() {});
  htmlMorph.name = "lively.morphic world"
  htmlMorph.setHTML("");
  htmlMorph.setFill(window.Color.white);
  htmlMorph.onBackspacePressed = function(evt) {};
  addMorphicSetupMethods(htmlMorph);

  var win = htmlMorph.openInWindow();
  win.name = "window for lively.morphic world";

  var titleBar = htmlMorph.getWindow().titleBar;
  var resetButton = new lively.morphic.Button(window.rect(0,0,60,18), "reset");
  titleBar.addMorph(resetButton);
  var left = Math.min.apply(null, titleBar.buttons.invoke("getPosition").pluck("x"));
  resetButton.align(resetButton.bounds().topRight(), window.pt(left-10, 2))
  titleBar.buttons.push(resetButton);
  window.lively.bindings.connect(resetButton, 'fire', htmlMorph, 'setupNewMorphicWorld');

  return htmlMorph;
}

export function createWorld() {
  var htmlMorph = createHtmlMorph();
  htmlMorph.getWindow().openInWorldCenter()
  htmlMorph.onLoad()
  return htmlMorph;
}
<commit_msg>disable "old" onKeyDown() within lively.morphic world created by helper (supersedes 16fc87f8091a091c992061bd27f428b2830e4d0a)<commit_after>// For getting a new Morphic world setup in old Lively
import { num, arr } from "lively.lang";
import { pt, Color, Point, Rectangle, Transform } from "lively.graphics";
import { Renderer, morph, Text, EventDispatcher, Menu } from "lively.morphic";
import { ObjectDrawer } from "lively.morphic/widgets.js";

export function setupMorphicWorldOn(htmlMorph) {

  var rootNode = htmlMorph.renderContext().shapeNode;
  var world = morph({type: "world", extent: Point.ensure(htmlMorph.getExtent())})
  var renderer = new Renderer(world, rootNode);
  renderer.startRenderWorldLoop()
  var eventDispatcher = new EventDispatcher(window, world);
  eventDispatcher.install();

  var drawer = world.addMorph(new ObjectDrawer({position: pt(20,10)}));

  // FIXME currently used for show()
  window.$$world = world;

  return {world, renderer, eventDispatcher};
}

function addMorphicSetupMethods(htmlMorph) {
  htmlMorph.doNotSerialize = ["state"];
  htmlMorph.addScript(function cleanupNewMorphicWorld() {
    if (this.state) {
      var {renderer, eventDispatcher} = this.state;
      renderer && renderer.clear();
      eventDispatcher && eventDispatcher.uninstall();
    }
    this.setHTML('');
    this.state = {};
  });

  htmlMorph.addScript(function setupNewMorphicWorld() {
    this.cleanupNewMorphicWorld();
    return window.lively.next.bootstrapped
      .then(() => window.lively.modules.importPackage("node_modules/lively.morphic"))
      .then(() => window.System.import("lively.morphic/old-lively-helpers.js"))
      .then(helpers => this.state = helpers.setupMorphicWorldOn(this))
      .catch(err => window.$world.logError(err));
  });

  htmlMorph.addScript(function onLoad() {
    this.setupNewMorphicWorld();
  });
}

function createHtmlMorph() {
  var htmlMorph = new lively.morphic.HtmlWrapperMorph(pt(666,600));
  htmlMorph.addScript(function onMouseDown() {});
  htmlMorph.addScript(function onContextMenu() {});
  htmlMorph.addScript(function onKeyDown() {});
  htmlMorph.name = "lively.morphic world"
  htmlMorph.setHTML("");
  htmlMorph.setFill(window.Color.white);
  addMorphicSetupMethods(htmlMorph);

  var win = htmlMorph.openInWindow();
  win.name = "window for lively.morphic world";

  var titleBar = htmlMorph.getWindow().titleBar;
  var resetButton = new lively.morphic.Button(window.rect(0,0,60,18), "reset");
  titleBar.addMorph(resetButton);
  var left = Math.min.apply(null, titleBar.buttons.invoke("getPosition").pluck("x"));
  resetButton.align(resetButton.bounds().topRight(), window.pt(left-10, 2))
  titleBar.buttons.push(resetButton);
  window.lively.bindings.connect(resetButton, 'fire', htmlMorph, 'setupNewMorphicWorld');

  return htmlMorph;
}

export function createWorld() {
  var htmlMorph = createHtmlMorph();
  htmlMorph.getWindow().openInWorldCenter()
  htmlMorph.onLoad()
  return htmlMorph;
}
<|endoftext|>


<commit_before>var config = {
    "name": "Harry John",
    "taglines": [
        "Ninja Software Engineer",
        "Chasing dreams since 1993",
        "SDE II @ Amazon",
        "The odd one",
        "AKA @harry671003"
    ],
    "links": [
        {
            "label": "blog",
            "url": "/blog"
        },
        {
            "label": "github",
            "url": "https://github.com/harry671003"
        },
        {
            "label": "linkedIn",
            "url": "https://www.linkedin.com/in/harry671003"
        }
    ],
    "sections": [
        {
            "title": "Work",
            "items": [
                {
                    "label": "Software Development Engineer II",
                    "desc": "Amazon (June 2018 - Present)"
                },
                {
                    "label": "Software Engineer",
                    "desc": "Microsoft (June 2015 - May 2018)"
                }
            ]
        },
        {
            "title": "Side Projects",
            "items": [
                {
                    "label": "S.Y.L (Sylphrena)",
                    "url": "https://github.com/harry671003/syl-core",
                    "desc": "Building a bot with better context management. (2018)"
                },
                {
                    "label": "ng2-appinsights",
                    "url": "https://www.npmjs.com/package/ng2-appinsights",
                    "desc": "App insights logging for Angular 2+ apps. (2017)"
                }
            ]
        },
        {
            "title": "Education",
            "items": [
                {
                    "label": "B-Tech",
                    "desc": "Amrita Amrita Vishwa Vidyapeetham (2011 - 15)"
                }
            ]
        },
        {
            "title": "Stats",
            "items": [
                {
                    "label": "Hitting the Gym",
                    "desc": "257 days"
                },
                {
                    "label": "Social Media boycott",
                    "desc": diffDays(
                        new Date(), new Date(Date.parse('December 28, 2018'))
                    ) + " days"
                },
                {
                    "label": "Time spent on planet Earth",
                    "desc": diffHours(
                        new Date(), new Date(Date.parse('February 7, 1993'))
                    ) + " hours"
                }
            ]
        }
    ]
}

function diffDays(firstDate, secondDate) {
    console.log(firstDate, secondDate);
    var oneDay = 24*60*60*1000;

    return Math.round(Math.abs((firstDate.getTime() - secondDate.getTime())/(oneDay)));
}

function diffHours(firstDate, secondDate) {
    console.log(firstDate, secondDate);
    var oneHour = 60*60*1000;

    return Math.round(Math.abs((firstDate.getTime() - secondDate.getTime())/(oneHour)));
}
<commit_msg>Update config.js<commit_after>var config = {
    "name": "Harry John",
    "taglines": [
        "Ninja Software Engineer",
        "Chasing dreams since 1993",
        "SDE II @ Amazon",
        "The odd one",
        "AKA @harry671003"
    ],
    "links": [
        {
            "label": "blog",
            "url": "/blog"
        },
        {
            "label": "github",
            "url": "https://github.com/harry671003"
        },
        {
            "label": "linkedIn",
            "url": "https://www.linkedin.com/in/harry671003"
        }
    ],
    "sections": [
        {
            "title": "Work",
            "items": [
                {
                    "label": "Software Development Engineer II",
                    "desc": "Amazon (June 2018 - Present)"
                },
                {
                    "label": "Software Engineer",
                    "desc": "Microsoft (June 2015 - May 2018)"
                }
            ]
        },
        {
            "title": "Side Projects",
            "items": [
                {
                    "label": "S.Y.L (Sylphrena)",
                    "url": "https://github.com/harry671003/syl-core",
                    "desc": "Building a bot with better context management. (2018)"
                },
                {
                    "label": "ng2-appinsights",
                    "url": "https://www.npmjs.com/package/ng2-appinsights",
                    "desc": "App insights logging for Angular 2+ apps. (2017)"
                }
            ]
        },
        {
            "title": "Education",
            "items": [
                {
                    "label": "B-Tech",
                    "desc": "Amrita Amrita Vishwa Vidyapeetham (2011 - 15)"
                }
            ]
        },
        {
            "title": "Stats",
            "items": [
                {
                    "label": "Hitting the Gym",
                    "desc": "258 days"
                },
                {
                    "label": "Social Media boycott",
                    "desc": diffDays(
                        new Date(), new Date(Date.parse('December 28, 2018'))
                    ) + " days"
                },
                {
                    "label": "Time spent on planet Earth",
                    "desc": diffHours(
                        new Date(), new Date(Date.parse('February 7, 1993'))
                    ) + " hours"
                }
            ]
        }
    ]
}

function diffDays(firstDate, secondDate) {
    console.log(firstDate, secondDate);
    var oneDay = 24*60*60*1000;

    return Math.round(Math.abs((firstDate.getTime() - secondDate.getTime())/(oneDay)));
}

function diffHours(firstDate, secondDate) {
    console.log(firstDate, secondDate);
    var oneHour = 60*60*1000;

    return Math.round(Math.abs((firstDate.getTime() - secondDate.getTime())/(oneHour)));
}
<|endoftext|>