<commit_before>'use strict';

angular.module('emission.tripconfirm.posttrip.prompt', ['emission.plugin.logger'])
.factory("PostTripAutoPrompt", function($window, $ionicPlatform, $rootScope, $state,
    $ionicPopup, Logger, $translate) {
  var ptap = {};
  var REPORT = 737678; // REPORT on the phone keypad
  var TRIP_CONFIRM_TEXT = 'TRIP_CONFIRM';
  var TRIP_END_EVENT = "trip_ended";

  var reportMessage = function(platform) {
    var platformSpecificMessage = {
      "ios": $translate.instant('post-trip-prompt.platform-specific-message-ios'),
      "android": $translate.instant('post-trip-prompt.platform-specific-message-android')
    };
    var selMessage = platformSpecificMessage[platform];
    if (!angular.isDefined(selMessage)) {
      selMessage = $translate.instant('post-trip-prompt.platform-specific-message-other');
    }
    return selMessage;
  };

  var getTripEndReportNotification = function() {
    var actions = [{
       id: 'MUTE',
       title: $translate.instant('post-trip-prompt.notification-option-mute'),
       icon: 'res://ic_moreoptions',
       activationMode: 'background',
       destructive: false,
       authenticationRequired: false
    }, {
       id: 'SNOOZE',
       title: $translate.instant('post-trip-prompt.notification-option-snooze'),
       icon: 'res://ic_moreoptions',
       activationMode: 'background',
       destructive: false,
       authenticationRequired: false
    }, {
        id: 'CHOOSE',
        title: $translate.instant('post-trip-prompt.notification-option-choose'),
        icon: 'res://ic_signin',
        activationMode: 'foreground',
        destructive: false,
        authenticationRequired: false
    }];

    var reportNotifyConfig = {
      id: REPORT,
      title: $translate.instant('post-trip-prompt.notification-title'),
      text: reportMessage(ionic.Platform.platform()),
      icon: 'file://img/icon.png',
      smallIcon: 'res://ic_mood_question.png',
      sound: null,
      actions: actions,
      category: TRIP_CONFIRM_TEXT,
      autoClear: true
    };
    Logger.log("Returning notification config "+JSON.stringify(reportNotifyConfig));
    return reportNotifyConfig;
  }

  ptap.registerTripEnd = function() {
    Logger.log( "registertripEnd received!" );
    // iOS
    var notifyPlugin = $window.cordova.plugins.BEMTransitionNotification;
    notifyPlugin.addEventListener(notifyPlugin.TRIP_END, getTripEndReportNotification())
        .then(function(result) {
            // $window.broadcaster.addEventListener("TRANSITION_NAME",  function(result) {
            Logger.log("Finished registering "+notifyPlugin.TRIP_END+" with result "+JSON.stringify(result));
        })
        .catch(function(error) {
            Logger.displayError("Unable to register notifications for trip end", error);
        });
  }

  var getFormattedTime = function(ts_in_secs) {
    if (angular.isDefined(ts_in_secs)) {
      return moment(ts_in_secs * 1000).format('LT');
    } else {
      return "---";
    }
  };

  var promptReport = function(notification, state, data) {
    Logger.log("About to prompt choose the mode for the trip");
    var newScope = $rootScope.$new();
    angular.extend(newScope, notification.data);
    newScope.getFormattedTime = getFormattedTime;
    Logger.log("notification = "+JSON.stringify(notification));
    Logger.log("state = "+JSON.stringify(state));
    Logger.log("data = "+JSON.stringify(data));
    return $ionicPopup.show({title: "Choose the travel mode and purpose of this trip",
        scope: newScope,
        template: "{{getFormattedTime(start_ts)}} -> {{getFormattedTime(end_ts)}}",
        buttons: [{
          text: $translate.instant('post-trip-prompt.choose-mode'),
          type: 'button-positive',
          onTap: function(e) {
            // e.preventDefault() will stop the popup from closing when tapped.
            return true;
          }
        }, {
          text: $translate.instant('post-trip-prompt.skip'),
          type: 'button-positive',
          onTap: function(e) {
            return false;
          }
        }]
    })
  }

  var cleanDataIfNecessary = function(notification, eventOpts) {
    // as of version 0.9.0-beta.4, cleaning data is not necessary, since iOS also returns
    // pre-parsed notification data. Let's leave this here for a bit in case we need it
    // later, but we can also remove it if we don't need it for a year or so
  };

  var displayCompletedTrip = function(notification, eventOpts) {
    $rootScope.tripConfirmParams = notification.data;
      Logger.log("About to display completed trip from notification "+
        JSON.stringify(notification.data));
      $state.go("root.main.tripconfirm", notification.data);
  };

  var checkCategory = function(notification) {
    if (notification.category == TRIP_CONFIRM_TEXT) {
        return true;
    } else {
        return false;
    }
  }

  ptap.registerUserResponse = function() {
    Logger.log( "registerUserResponse received!" );
    $window.cordova.plugins.notification.local.on('CHOOSE', function (notification, eventOpts) {
      if (!checkCategory(notification)) {
          Logger.log("notification "+notification+" is not an mode choice, returning...");
          return;
      }
      Logger.log("Notification, action event");
      cleanDataIfNecessary(notification, eventOpts);
      displayCompletedTrip(notification, eventOpts);
    });
    $window.cordova.plugins.notification.local.on('SNOOZE', function (notification, eventOpts) {
      if (!checkCategory(notification)) {
          Logger.log("notification "+notification+" is not an mode choice, returning...");
          return;
      }
      var now = new Date().getTime(),
          _30_mins_from_now = new Date(now + 30 * 60 * 1000);
      var after_30_mins_prompt = getTripEndReportNotification();
      after_30_mins_prompt.at = _30_mins_from_now;
      $window.cordova.plugins.notification.local.schedule([after_30_mins_prompt]);
      if ($ionicPlatform.is('android')) {
          $ionicPopup.alert({
            title: $translate.instant('post-trip-prompt.snoozed-reminder'),
            template: $translate.instant('post-trip-prompt.snoozed-reapper-message')
          });
      }
    });
    $window.cordova.plugins.notification.local.on('MUTE', function (notification, eventOpts) {
      if (!checkCategory(notification)) {
          Logger.log("notification "+notification+" is not an mode choice, returning...");
          return;
      }
      var now = new Date().getTime(),
          _1_min_from_now = new Date(now + 60 * 1000);
      var notifyPlugin = $window.cordova.plugins.BEMTransitionNotification;
      notifyPlugin.disableEventListener(notifyPlugin.TRIP_END, notification).then(function() {
          if ($ionicPlatform.is('ios')) {
              $window.cordova.plugins.notification.local.schedule([{
                  id: REPORT,
                  title: $translate.instant('post-trip-prompt.notifications-muted'),
                  text: $translate.instant('post-trip-prompt.notifications-reenabled'),
                  at: _1_min_from_now,
                  data: {redirectTo: "root.main.control"}
              }]);
          } else if ($ionicPlatform.is('android')) {
              $ionicPopup.show({
                  title: $translate.instant('post-trip-prompt.muted'),
                  template: $translate.instant('post-trip-prompt.notifications-muted'),
                  buttons: [{
                    text: $translate.instant('post-trip-prompt.unmute'),
                    type: 'button-positive',
                    onTap: function(e) {
                      return true;
                    }
                  }, {
                    text: $translate.instant('post-trip-prompt.keep-muted'),
                    type: 'button-positive',
                    onTap: function(e) {
                      return false;
                    }
                  }]
              }).then(function(res) {
                  if(res == true) {
                      notifyPlugin.enableEventListener(notifyPlugin.TRIP_END, notification);
                  } else {
                      Logger.log("User chose to keep the transition muted");
                  }
              });
            }
      }).catch(function(error) {
          Logger.displayError("Error while muting notifications for trip end. Try again later.", error);
      });
    });
    $window.cordova.plugins.notification.local.on('clear', function (notification, eventOpts) {
        // alert("notification cleared, no report");
    });
    $window.cordova.plugins.notification.local.on('cancel', function (notification, eventOpts) {
        // alert("notification cancelled, no report");
    });
    $window.cordova.plugins.notification.local.on('trigger', function (notification, eventOpts) {
        // alert("triggered, no action");
        Logger.log("Notification triggered");
        if (!checkCategory(notification)) {
            Logger.log("notification "+notification+" is not an mode choice, returning...");
            return;
        }
        cleanDataIfNecessary(notification, eventOpts);
        if($ionicPlatform.is('ios')) {
            promptReport(notification, eventOpts).then(function(res) {
              if (res == true) {
                  Logger.log("About to go to prompt page");
                displayCompletedTrip(notification, eventOpts);
              } else {
                Logger.log("Skipped confirmation reporting");
              }
            });
        } else {
          Logger.log("About to go to prompt page");
          displayCompletedTrip(notification, eventOpts);
        }
    });
    $window.cordova.plugins.notification.local.on('click', function (notification, eventOpts) {
      // alert("clicked, no action");
      Logger.log("Notification, click event");
      if (!checkCategory(notification)) {
          Logger.log("notification "+notification+" is not an mode choice, returning...");
          return;
      }
      cleanDataIfNecessary(notification, eventOpts);
      displayCompletedTrip(notification, eventOpts);
    });
  };

  $ionicPlatform.ready().then(function() {
    ptap.registerTripEnd();
    ptap.registerUserResponse();
  });

  return ptap;

});
<commit_msg>Reformat the actions to be consistent with the new spec<commit_after>'use strict';

angular.module('emission.tripconfirm.posttrip.prompt', ['emission.plugin.logger'])
.factory("PostTripAutoPrompt", function($window, $ionicPlatform, $rootScope, $state,
    $ionicPopup, Logger, $translate) {
  var ptap = {};
  var REPORT = 737678; // REPORT on the phone keypad
  var TRIP_CONFIRM_TEXT = 'TRIP_CONFIRM';
  var TRIP_END_EVENT = "trip_ended";

  var reportMessage = function(platform) {
    var platformSpecificMessage = {
      "ios": $translate.instant('post-trip-prompt.platform-specific-message-ios'),
      "android": $translate.instant('post-trip-prompt.platform-specific-message-android')
    };
    var selMessage = platformSpecificMessage[platform];
    if (!angular.isDefined(selMessage)) {
      selMessage = $translate.instant('post-trip-prompt.platform-specific-message-other');
    }
    return selMessage;
  };

  var getTripEndReportNotification = function() {
    var actions = [{
       id: 'MUTE',
       type: 'button',
       title: $translate.instant('post-trip-prompt.notification-option-mute'),
       icon: 'res://ic_moreoptions',
       launch: true,
       destructive: false,
       authenticationRequired: false
    }, {
       id: 'SNOOZE',
       type: 'button',
       title: $translate.instant('post-trip-prompt.notification-option-snooze'),
       icon: 'res://ic_moreoptions',
       launch: true,
       destructive: false,
       authenticationRequired: false
    }, {
        id: 'CHOOSE',
        type: 'button',
        title: $translate.instant('post-trip-prompt.notification-option-choose'),
        icon: 'res://ic_signin',
        launch: true,
        destructive: false,
        authenticationRequired: false
    }];

    var reportNotifyConfig = {
      id: REPORT,
      title: $translate.instant('post-trip-prompt.notification-title'),
      text: reportMessage(ionic.Platform.platform()),
      icon: 'file://img/icon.png',
      smallIcon: 'res://ic_mood_question.png',
      sound: null,
      actions: actions,
      actionGroupId: TRIP_CONFIRM_TEXT,
      autoClear: true
    };
    Logger.log("Returning notification config "+JSON.stringify(reportNotifyConfig));
    return reportNotifyConfig;
  }

  ptap.registerTripEnd = function() {
    Logger.log( "registertripEnd received!" );
    // iOS
    var notifyPlugin = $window.cordova.plugins.BEMTransitionNotification;
    notifyPlugin.addEventListener(notifyPlugin.TRIP_END, getTripEndReportNotification())
        .then(function(result) {
            // $window.broadcaster.addEventListener("TRANSITION_NAME",  function(result) {
            Logger.log("Finished registering "+notifyPlugin.TRIP_END+" with result "+JSON.stringify(result));
        })
        .catch(function(error) {
            Logger.displayError("Unable to register notifications for trip end", error);
        });
  }

  var getFormattedTime = function(ts_in_secs) {
    if (angular.isDefined(ts_in_secs)) {
      return moment(ts_in_secs * 1000).format('LT');
    } else {
      return "---";
    }
  };

  var promptReport = function(notification, state, data) {
    Logger.log("About to prompt choose the mode for the trip");
    var newScope = $rootScope.$new();
    angular.extend(newScope, notification.data);
    newScope.getFormattedTime = getFormattedTime;
    Logger.log("notification = "+JSON.stringify(notification));
    Logger.log("state = "+JSON.stringify(state));
    Logger.log("data = "+JSON.stringify(data));
    return $ionicPopup.show({title: "Choose the travel mode and purpose of this trip",
        scope: newScope,
        template: "{{getFormattedTime(start_ts)}} -> {{getFormattedTime(end_ts)}}",
        buttons: [{
          text: $translate.instant('post-trip-prompt.choose-mode'),
          type: 'button-positive',
          onTap: function(e) {
            // e.preventDefault() will stop the popup from closing when tapped.
            return true;
          }
        }, {
          text: $translate.instant('post-trip-prompt.skip'),
          type: 'button-positive',
          onTap: function(e) {
            return false;
          }
        }]
    })
  }

  var cleanDataIfNecessary = function(notification, eventOpts) {
    // as of version 0.9.0-beta.4, cleaning data is not necessary, since iOS also returns
    // pre-parsed notification data. Let's leave this here for a bit in case we need it
    // later, but we can also remove it if we don't need it for a year or so
  };

  var displayCompletedTrip = function(notification, eventOpts) {
    $rootScope.tripConfirmParams = notification.data;
      Logger.log("About to display completed trip from notification "+
        JSON.stringify(notification.data));
      $state.go("root.main.tripconfirm", notification.data);
  };

  var checkCategory = function(notification) {
    if (notification.actionGroupId == TRIP_CONFIRM_TEXT) {
        return true;
    } else {
        return false;
    }
  }

  ptap.registerUserResponse = function() {
    Logger.log( "registerUserResponse received!" );
    $window.cordova.plugins.notification.local.on('CHOOSE', function (notification, eventOpts) {
      if (!checkCategory(notification)) {
          Logger.log("notification "+notification+" is not an mode choice, returning...");
          return;
      }
      Logger.log("Notification, action event");
      cleanDataIfNecessary(notification, eventOpts);
      displayCompletedTrip(notification, eventOpts);
    });
    $window.cordova.plugins.notification.local.on('SNOOZE', function (notification, eventOpts) {
      if (!checkCategory(notification)) {
          Logger.log("notification "+notification+" is not an mode choice, returning...");
          return;
      }
      var now = new Date().getTime(),
          _30_mins_from_now = new Date(now + 30 * 60 * 1000);
      var after_30_mins_prompt = getTripEndReportNotification();
      after_30_mins_prompt.at = _30_mins_from_now;
      $window.cordova.plugins.notification.local.schedule([after_30_mins_prompt]);
      if ($ionicPlatform.is('android')) {
          $ionicPopup.alert({
            title: $translate.instant('post-trip-prompt.snoozed-reminder'),
            template: $translate.instant('post-trip-prompt.snoozed-reapper-message')
          });
      }
    });
    $window.cordova.plugins.notification.local.on('MUTE', function (notification, eventOpts) {
      if (!checkCategory(notification)) {
          Logger.log("notification "+notification+" is not an mode choice, returning...");
          return;
      }
      var now = new Date().getTime(),
          _1_min_from_now = new Date(now + 60 * 1000);
      var notifyPlugin = $window.cordova.plugins.BEMTransitionNotification;
      notifyPlugin.disableEventListener(notifyPlugin.TRIP_END, notification).then(function() {
          if ($ionicPlatform.is('ios')) {
              $window.cordova.plugins.notification.local.schedule([{
                  id: REPORT,
                  title: $translate.instant('post-trip-prompt.notifications-muted'),
                  text: $translate.instant('post-trip-prompt.notifications-reenabled'),
                  at: _1_min_from_now,
                  data: {redirectTo: "root.main.control"}
              }]);
          } else if ($ionicPlatform.is('android')) {
              $ionicPopup.show({
                  title: $translate.instant('post-trip-prompt.muted'),
                  template: $translate.instant('post-trip-prompt.notifications-muted'),
                  buttons: [{
                    text: $translate.instant('post-trip-prompt.unmute'),
                    type: 'button-positive',
                    onTap: function(e) {
                      return true;
                    }
                  }, {
                    text: $translate.instant('post-trip-prompt.keep-muted'),
                    type: 'button-positive',
                    onTap: function(e) {
                      return false;
                    }
                  }]
              }).then(function(res) {
                  if(res == true) {
                      notifyPlugin.enableEventListener(notifyPlugin.TRIP_END, notification);
                  } else {
                      Logger.log("User chose to keep the transition muted");
                  }
              });
            }
      }).catch(function(error) {
          Logger.displayError("Error while muting notifications for trip end. Try again later.", error);
      });
    });
    $window.cordova.plugins.notification.local.on('clear', function (notification, eventOpts) {
        // alert("notification cleared, no report");
    });
    $window.cordova.plugins.notification.local.on('cancel', function (notification, eventOpts) {
        // alert("notification cancelled, no report");
    });
    $window.cordova.plugins.notification.local.on('trigger', function (notification, eventOpts) {
        // alert("triggered, no action");
        Logger.log("Notification triggered");
        if (!checkCategory(notification)) {
            Logger.log("notification "+notification+" is not an mode choice, returning...");
            return;
        }
        cleanDataIfNecessary(notification, eventOpts);
        if($ionicPlatform.is('ios')) {
            promptReport(notification, eventOpts).then(function(res) {
              if (res == true) {
                  Logger.log("About to go to prompt page");
                displayCompletedTrip(notification, eventOpts);
              } else {
                Logger.log("Skipped confirmation reporting");
              }
            });
        } else {
          Logger.log("About to go to prompt page");
          displayCompletedTrip(notification, eventOpts);
        }
    });
    $window.cordova.plugins.notification.local.on('click', function (notification, eventOpts) {
      // alert("clicked, no action");
      Logger.log("Notification, click event");
      if (!checkCategory(notification)) {
          Logger.log("notification "+notification+" is not an mode choice, returning...");
          return;
      }
      cleanDataIfNecessary(notification, eventOpts);
      displayCompletedTrip(notification, eventOpts);
    });
  };

  $ionicPlatform.ready().then(function() {
    ptap.registerTripEnd();
    ptap.registerUserResponse();
  });

  return ptap;

});
<|endoftext|>


<commit_before>/* @flow */
/** @jsx etch.dom */

import etch from 'etch'

import type {TextEditor} from 'atom'
const TextEditorComponent = atom.workspace.buildTextEditor

export default class CommitEditorComponent {
  element: HTMLElement;
  refs: {editor: ?TextEditor};

  constructor () {
    try {
      etch.initialize(this)
    } catch (e) {
      // We depend on some changes to `buildTextEditor` that aren't in a release
      // yet. So ignore errors that happen on CI because of that.
      if (!process.env.TRAVIS) throw e
    }
  }

  getText (): string {
    const textEditor = this.refs.editor
    if (!textEditor) return ''

    return textEditor.getText()
  }

  setText (t: string) {
    const textEditor = this.refs.editor
    if (!textEditor) return

    textEditor.setText(t)
  }

  update (props: {}, children: Array<any>): Promise<void> {
    // Don't re-render.
    return Promise.resolve()
  }

  render () {
    return (

        <TextEditorComponent
          ref='editor'
          placeholderText='Commit message'
          lineNumberGutterVisible={false}
          grammar={atom.grammars.grammarForScopeName('text.git-commit')}
          showInvisibles={false}
          autoHeight={false}
          scrollPastEnd={false}/>

    )
  }
}
<commit_msg>Bubble up change events.<commit_after>/* @flow */
/** @jsx etch.dom */

import etch from 'etch'
import {CompositeDisposable} from 'atom'

import type {TextEditor} from 'atom'
const TextEditorComponent = atom.workspace.buildTextEditor

type CommitEditorComponentProps = {onDidChange: Function}

export default class CommitEditorComponent {
  element: HTMLElement;
  refs: {editor: ?TextEditor};
  subscriptions: CompositeDisposable;
  onDidChange: Function;

  constructor (props: CommitEditorComponentProps) {
    this.subscriptions = new CompositeDisposable()

    this.acceptProps(props)

    try {
      etch.initialize(this)
    } catch (e) {
      // We depend on some changes to `buildTextEditor` that aren't in a release
      // yet. So ignore errors that happen on CI because of that.
      if (!process.env.TRAVIS) throw e
    }

    const editor = this.refs.editor
    if (editor) {
      this.subscriptions.add(editor.onDidChange(() => this.onDidChange()))
    }
  }

  destroy (): Promise<void> {
    this.subscriptions.dispose()

    return etch.destroy(this)
  }

  acceptProps ({onDidChange}: CommitEditorComponentProps) {
    this.onDidChange = onDidChange
  }

  getText (): string {
    const textEditor = this.refs.editor
    if (!textEditor) return ''

    return textEditor.getText()
  }

  setText (t: string) {
    const textEditor = this.refs.editor
    if (!textEditor) return

    textEditor.setText(t)
  }

  update (props: CommitEditorComponentProps, children: Array<any>): Promise<void> {
    this.acceptProps(props)

    // Don't re-render. We'll update the editor in place.
    return Promise.resolve()
  }

  render () {
    return (

        <TextEditorComponent
          ref='editor'
          placeholderText='Commit message'
          lineNumberGutterVisible={false}
          grammar={atom.grammars.grammarForScopeName('text.git-commit')}
          showInvisibles={false}
          autoHeight={false}
          scrollPastEnd={false}/>

    )
  }
}
<|endoftext|>


<commit_before>"use strict";

var gl = null;
var vao = null;
var program = null;
var world_texture = null;
var zoom_loc = 0;
var zoom = 1.0; // half-screens per radian

var vertexShader = `#version 300 es
#line 12
const vec4 SCREEN_QUAD[4] = vec4[4](
  vec4(-1, -1, 0.5, 1),
  vec4( 1, -1, 0.5, 1),
  vec4(-1,  1, 0.5, 1),
  vec4( 1,  1, 0.5, 1));
// todo: scale
const vec2 SCREEN_COORD[4] = vec2[4](
  vec2(-1, -1),
  vec2( 1, -1),
  vec2(-1,  1),
  vec2( 1,  1));

uniform float zoom; // half-screens per radian

out vec2 screen_xy;

void main() {
  gl_Position = SCREEN_QUAD[gl_VertexID];
  screen_xy = SCREEN_COORD[gl_VertexID] / zoom;
}
`;

var fragmentShader = `#version 300 es
#line 36
precision mediump float;
uniform sampler2D world_texture;
in vec2 screen_xy;
out vec4 out_color;

vec2 longlatFromXyz(in vec3 xyz) {
  float r = length(xyz.xz);
  return vec2(atan(xyz.x, xyz.z),
              atan(xyz.y, r));
}

// Convert from input equirectangular image, to unit sphere surface xyz
vec2 texCoordFromXyz(in vec3 xyz) {
  vec2 longlat = longlatFromXyz(xyz);
  const float PI = 3.14159265359;
  vec2 uv = vec2(
    longlat.x / PI * 0.5 + 0.5,
    -longlat.y / PI + 0.5);
  return uv;
}

vec3 sphereFromOrthographic(in vec2 screenXy) {
  // orthographic
  float y = screenXy.y;
  float x = screenXy.x;
  float z = 1.0 - x*x - y*y;
  if (z < 0.0) discard;
  z = sqrt(z);
  return vec3(x, y, z);
}

void main() {
  vec3 xyz = sphereFromOrthographic(screen_xy);
  vec2 uv = texCoordFromXyz(xyz);
  out_color =
      // vec4(uv, 1, 1);
      texture(world_texture, uv);
}
`;

function resize(canvas) {
  // Lookup the size the browser is displaying the canvas.
  var displayWidth  = ~~(0.9 * canvas.clientWidth);
  var displayHeight = ~~(0.9 * canvas.clientHeight);

  // Check if the canvas is not the same size.
  if (canvas.width  != displayWidth ||
      canvas.height != displayHeight) {

    // Make the canvas the same size
    canvas.width  = displayWidth;
    canvas.height = displayHeight;
  }
}

function initGL(canvas) {
  gl = canvas.getContext("webgl2");
  if (!gl) {
    alert("Could not initialise WebGL, sorry :-(");
    return;
  }
  gl.clearColor(0.2, 0.2, 0.2, 1.0);
  gl.disable(gl.DEPTH_TEST);
  vao = gl.createVertexArray(); // webgl2 only
  gl.bindVertexArray(vao);
  var vs = gl.createShader(gl.VERTEX_SHADER);
  gl.shaderSource(vs, vertexShader);
  gl.compileShader(vs);
  // Check if it compiled
  var success = gl.getShaderParameter(vs, gl.COMPILE_STATUS);
  if (!success) {
    // Something went wrong during compilation; get the error
    throw "could not compile shader:" + gl.getShaderInfoLog(vs);
  }
  var fs = gl.createShader(gl.FRAGMENT_SHADER);
  gl.shaderSource(fs, fragmentShader);
  gl.compileShader(fs);
  // Check if it compiled
  success = gl.getShaderParameter(fs, gl.COMPILE_STATUS);
  if (!success) {
    // Something went wrong during compilation; get the error
    throw "could not compile shader:" + gl.getShaderInfoLog(fs);
  }
  program = gl.createProgram();
  gl.attachShader(program, vs);
  gl.attachShader(program, fs);
  gl.linkProgram(program);
  success = gl.getProgramParameter(program, gl.LINK_STATUS);
  if (!success) {
      // something went wrong with the link
      throw ("program filed to link:" + gl.getProgramInfoLog (program));
  }
  var world_texture_loc = gl.getUniformLocation(program, 'world_texture');
  zoom_loc = gl.getUniformLocation(program, 'zoom');
  gl.useProgram(program);
  gl.uniform1i(world_texture_loc, 0);
  gl.uniform1f(zoom_loc, zoom);
  world_texture = gl.createTexture();
  gl.bindTexture(gl.TEXTURE_2D, world_texture);
}

function drawScene() {
  resize(gl.canvas);
  gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
  gl.clear(gl.COLOR_BUFFER_BIT);
  gl.bindVertexArray(vao);
  gl.useProgram(program);
  gl.uniform1f(zoom_loc, zoom);
  gl.activeTexture(gl.TEXTURE0);
  gl.bindTexture(gl.TEXTURE_2D, world_texture);
  gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
  requestAnimationFrame(drawScene);
}

function globeviewStart() {
  var canvas = document.getElementById("globeview_canvas");
  initGL(canvas);
  var image = new Image();
  image.src = 'world.topo.bathy.200411.3x5400x2700.jpg';
  image.onload = function() {
    gl.texImage2D(gl.TEXTURE_2D,
      0, // mipLevel
      gl.RGB, // internalFormat,
      gl.RGB, // source format,
      gl.UNSIGNED_BYTE,
      image);
    gl.generateMipmap(gl.TEXTURE_2D);
    requestAnimationFrame(drawScene);
  }

  function zoomInOut(event) {
    event.preventDefault();
    var e = window.event || event;
    var delta = Math.max(-1, Math.min(1, (e.wheelDelta || -e.detail)));
    if (delta > 0) {
      zoom *= 1.1;
    }
    else {
      zoom *= 1.0/1.1;
    }
    return false;
  }

  canvas.addEventListener('mousewheel', zoomInOut, false);
  canvas.addEventListener('DOMMouseScroll', zoomInOut, false);
}
<commit_msg>Rename zoomInOut to scrollZoom, to distinguish it from future pinch zoom.<commit_after>"use strict";

var gl = null;
var vao = null;
var program = null;
var world_texture = null;
var zoom_loc = 0;
var zoom = 1.0; // half-screens per radian

var vertexShader = `#version 300 es
#line 12
const vec4 SCREEN_QUAD[4] = vec4[4](
  vec4(-1, -1, 0.5, 1),
  vec4( 1, -1, 0.5, 1),
  vec4(-1,  1, 0.5, 1),
  vec4( 1,  1, 0.5, 1));
// todo: scale
const vec2 SCREEN_COORD[4] = vec2[4](
  vec2(-1, -1),
  vec2( 1, -1),
  vec2(-1,  1),
  vec2( 1,  1));

uniform float zoom; // half-screens per radian

out vec2 screen_xy;

void main() {
  gl_Position = SCREEN_QUAD[gl_VertexID];
  screen_xy = SCREEN_COORD[gl_VertexID] / zoom;
}
`;

var fragmentShader = `#version 300 es
#line 36
precision mediump float;
uniform sampler2D world_texture;
in vec2 screen_xy;
out vec4 out_color;

vec2 longlatFromXyz(in vec3 xyz) {
  float r = length(xyz.xz);
  return vec2(atan(xyz.x, xyz.z),
              atan(xyz.y, r));
}

// Convert from input equirectangular image, to unit sphere surface xyz
vec2 texCoordFromXyz(in vec3 xyz) {
  vec2 longlat = longlatFromXyz(xyz);
  const float PI = 3.14159265359;
  vec2 uv = vec2(
    longlat.x / PI * 0.5 + 0.5,
    -longlat.y / PI + 0.5);
  return uv;
}

vec3 sphereFromOrthographic(in vec2 screenXy) {
  // orthographic
  float y = screenXy.y;
  float x = screenXy.x;
  float z = 1.0 - x*x - y*y;
  if (z < 0.0) discard;
  z = sqrt(z);
  return vec3(x, y, z);
}

void main() {
  vec3 xyz = sphereFromOrthographic(screen_xy);
  vec2 uv = texCoordFromXyz(xyz);
  out_color =
      // vec4(uv, 1, 1);
      texture(world_texture, uv);
}
`;

function resize(canvas) {
  // Lookup the size the browser is displaying the canvas.
  var displayWidth  = ~~(0.9 * canvas.clientWidth);
  var displayHeight = ~~(0.9 * canvas.clientHeight);

  // Check if the canvas is not the same size.
  if (canvas.width  != displayWidth ||
      canvas.height != displayHeight) {

    // Make the canvas the same size
    canvas.width  = displayWidth;
    canvas.height = displayHeight;
  }
}

function initGL(canvas) {
  gl = canvas.getContext("webgl2");
  if (!gl) {
    alert("Could not initialise WebGL, sorry :-(");
    return;
  }
  gl.clearColor(0.2, 0.2, 0.2, 1.0);
  gl.disable(gl.DEPTH_TEST);
  vao = gl.createVertexArray(); // webgl2 only
  gl.bindVertexArray(vao);
  var vs = gl.createShader(gl.VERTEX_SHADER);
  gl.shaderSource(vs, vertexShader);
  gl.compileShader(vs);
  // Check if it compiled
  var success = gl.getShaderParameter(vs, gl.COMPILE_STATUS);
  if (!success) {
    // Something went wrong during compilation; get the error
    throw "could not compile shader:" + gl.getShaderInfoLog(vs);
  }
  var fs = gl.createShader(gl.FRAGMENT_SHADER);
  gl.shaderSource(fs, fragmentShader);
  gl.compileShader(fs);
  // Check if it compiled
  success = gl.getShaderParameter(fs, gl.COMPILE_STATUS);
  if (!success) {
    // Something went wrong during compilation; get the error
    throw "could not compile shader:" + gl.getShaderInfoLog(fs);
  }
  program = gl.createProgram();
  gl.attachShader(program, vs);
  gl.attachShader(program, fs);
  gl.linkProgram(program);
  success = gl.getProgramParameter(program, gl.LINK_STATUS);
  if (!success) {
      // something went wrong with the link
      throw ("program filed to link:" + gl.getProgramInfoLog (program));
  }
  var world_texture_loc = gl.getUniformLocation(program, 'world_texture');
  zoom_loc = gl.getUniformLocation(program, 'zoom');
  gl.useProgram(program);
  gl.uniform1i(world_texture_loc, 0);
  gl.uniform1f(zoom_loc, zoom);
  world_texture = gl.createTexture();
  gl.bindTexture(gl.TEXTURE_2D, world_texture);
}

function drawScene() {
  resize(gl.canvas);
  gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
  gl.clear(gl.COLOR_BUFFER_BIT);
  gl.bindVertexArray(vao);
  gl.useProgram(program);
  gl.uniform1f(zoom_loc, zoom);
  gl.activeTexture(gl.TEXTURE0);
  gl.bindTexture(gl.TEXTURE_2D, world_texture);
  gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
  requestAnimationFrame(drawScene);
}

function globeviewStart() {
  var canvas = document.getElementById("globeview_canvas");
  initGL(canvas);
  var image = new Image();
  image.src = 'world.topo.bathy.200411.3x5400x2700.jpg';
  image.onload = function() {
    gl.texImage2D(gl.TEXTURE_2D,
      0, // mipLevel
      gl.RGB, // internalFormat,
      gl.RGB, // source format,
      gl.UNSIGNED_BYTE,
      image);
    gl.generateMipmap(gl.TEXTURE_2D);
    requestAnimationFrame(drawScene);
  }

  function scrollZoom(event) {
    event.preventDefault();
    var e = window.event || event;
    var delta = Math.max(-1, Math.min(1, (e.wheelDelta || -e.detail)));
    if (delta > 0) {
      zoom *= 1.1;
    }
    else {
      zoom *= 1.0/1.1;
    }
    return false;
  }
  canvas.addEventListener('mousewheel', scrollZoom, false);
  canvas.addEventListener('DOMMouseScroll', scrollZoom, false);
}
<|endoftext|>


<commit_before>module.exports = {
  up: function(migration, DataTypes, done) {
		migration.createTable(
		  'Media',
		  {
				id: { type: DataTypes.INTEGER, autoIncrement: true, primaryKey: true },
				instagramId: { type: DataTypes.STRING, allowNull: false },
				date: { type: DataTypes.DATE, allowNull: true },
				thumbnailUrl: { type: DataTypes.STRING, allowNull: false },
				imageUrl: { type: DataTypes.STRING, allowNull: false }
		  },
		  {
		    engine: 'InnoDB', // default: 'InnoDB'
		    charset: 'latin1' // default: null
		  }
		)
		migration.createTable(
		  'Issue',
		  {
				id: { type: DataTypes.INTEGER, autoIncrement: true, primaryKey: true },
				name: { type: DataTypes.STRING, allowNull: false },
				description: { type: DataTypes.STRING, allowNull: true },
				date: { type: DataTypes.DATE, allowNull: true }
		  },
		  {
		    engine: 'InnoDB', // default: 'InnoDB'
		    charset: 'latin1' // default: null
		  }
		)
		migration.createTable(
		  'Tag',
		  {
				name: { type: DataTypes.STRING, allowNull: false, primaryKey: true }
			},
		  {
		    engine: 'InnoDB', // default: 'InnoDB'
		    charset: 'latin1' // default: null
		  }
		)
    done()
  },
  down: function(migration, DataTypes, done) {
		migration.dropAllTables()
    done()
  }
}
<commit_msg>ssdfhjfdsjkh<commit_after>module.exports = {
  up: function(migration, DataTypes, done) {
		migration.createTable(
		  'Media',
		  {
				id: { type: DataTypes.INTEGER, autoIncrement: true, primaryKey: true },
				instagramId: { type: DataTypes.STRING, allowNull: false },
				date: { type: DataTypes.DATE, allowNull: true },
				thumbnailUrl: { type: DataTypes.STRING, allowNull: false },
				imageUrl: { type: DataTypes.STRING, allowNull: false },
				createdAt: {
		      type: DataTypes.DATE
		    },
		    updatedAt: {
		      type: DataTypes.DATE
		    },
		  },
		  {
		    engine: 'InnoDB', // default: 'InnoDB'
		    charset: 'latin1' // default: null
		  }
		)
		migration.createTable(
		  'Issue',
		  {
				id: { type: DataTypes.INTEGER, autoIncrement: true, primaryKey: true },
				name: { type: DataTypes.STRING, allowNull: false },
				description: { type: DataTypes.STRING, allowNull: true },
				date: { type: DataTypes.DATE, allowNull: true },
				createdAt: {
		      type: DataTypes.DATE
		    },
		    updatedAt: {
		      type: DataTypes.DATE
		    },
		  },
		  {
		    engine: 'InnoDB', // default: 'InnoDB'
		    charset: 'latin1' // default: null
		  }
		)
		migration.createTable(
		  'Tag',
		  {
				name: { type: DataTypes.STRING, allowNull: false, primaryKey: true },
				createdAt: {
		      type: DataTypes.DATE
		    },
		    updatedAt: {
		      type: DataTypes.DATE
		    },
			},
		  {
		    engine: 'InnoDB', // default: 'InnoDB'
		    charset: 'latin1' // default: null
		  }
		)
    done()
  },
  down: function(migration, DataTypes, done) {
		migration.dropAllTables()
    done()
  }
}
<|endoftext|>


<commit_before>import is from '@sindresorhus/is';

const hasha = require('hasha');
const URL = require('url');
const parseLinkHeader = require('parse-link-header');
const wwwAuthenticate = require('www-authenticate');
const { logger } = require('../../logger');

const got = require('../../util/got');
const hostRules = require('../../util/host-rules');

export { getDigest, getPkgReleases };

/**
 *
 * @param {string} lookupName
 * @param {string[]=} registryUrls
 */
function getRegistryRepository(lookupName, registryUrls) {
  /** @type string */
  let registry;
  const split = lookupName.split('/');
  if (split.length > 1 && split[0].includes('.')) {
    [registry] = split;
    split.shift();
  }
  let repository = split.join('/');
  if (!registry && is.nonEmptyArray(registryUrls)) {
    [registry] = registryUrls;
  }
  if (!registry || registry === 'docker.io') {
    registry = 'index.docker.io';
  }
  if (!registry.match('^https?://')) {
    registry = `https://${registry}`;
  }
  if (registry.endsWith('.docker.io') && !repository.includes('/')) {
    repository = 'library/' + repository;
  }
  return {
    registry,
    repository,
  };
}

async function getAuthHeaders(registry, repository) {
  try {
    const apiCheckUrl = `${registry}/v2/`;
    const apiCheckResponse = await got(apiCheckUrl, { throwHttpErrors: false });
    if (apiCheckResponse.headers['www-authenticate'] === undefined) {
      return {};
    }
    const authenticateHeader = new wwwAuthenticate.parsers.WWW_Authenticate(
      apiCheckResponse.headers['www-authenticate']
    );

    /** @type any */
    const opts = hostRules.find({ hostType: 'docker', url: apiCheckUrl });
    opts.json = true;
    if (opts.username && opts.password) {
      const auth = Buffer.from(`${opts.username}:${opts.password}`).toString(
        'base64'
      );
      opts.headers = { authorization: `Basic ${auth}` };
    }
    delete opts.username;
    delete opts.password;

    if (authenticateHeader.scheme.toUpperCase() === 'BASIC') {
      logger.debug(`Using Basic auth for docker registry ${repository}`);
      await got(apiCheckUrl, opts);
      return opts.headers;
    }

    // prettier-ignore
    const authUrl = `${authenticateHeader.parms.realm}?service=${authenticateHeader.parms.service}&scope=repository:${repository}:pull`;
    logger.trace(
      `Obtaining docker registry token for ${repository} using url ${authUrl}`
    );
    const { token } = (await got(authUrl, opts)).body;
    // istanbul ignore if
    if (!token) {
      logger.warn('Failed to obtain docker registry token');
      return null;
    }
    return {
      authorization: `Bearer ${token}`,
    };
  } catch (err) /* istanbul ignore next */ {
    if (err.statusCode === 401) {
      logger.info(
        { registry, dockerRepository: repository },
        'Unauthorized docker lookup'
      );
      logger.debug({ err });
      return null;
    }
    if (err.statusCode === 403) {
      logger.info(
        { registry, dockerRepository: repository },
        'Not allowed to access docker registry'
      );
      logger.debug({ err });
      return null;
    }
    if (err.statusCode === 429 && registry.endsWith('docker.io')) {
      logger.warn({ err }, 'docker registry failure: too many requests');
      throw new Error('registry-failure');
    }
    if (err.statusCode >= 500 && err.statusCode < 600) {
      logger.warn({ err }, 'docker registry failure: internal error');
      throw new Error('registry-failure');
    }
    logger.warn(
      { registry, dockerRepository: repository, err },
      'Error obtaining docker token'
    );
    return null;
  }
}

function digestFromManifestStr(str) {
  return 'sha256:' + hasha(str, { algorithm: 'sha256' });
}

function extractDigestFromResponse(manifestResponse) {
  if (manifestResponse.headers['docker-content-digest'] === undefined) {
    return digestFromManifestStr(manifestResponse.body);
  }
  return manifestResponse.headers['docker-content-digest'];
}

async function getManifestResponse(registry, repository, tag) {
  logger.debug(`getManifestResponse(${registry}, ${repository}, ${tag})`);
  try {
    const headers = await getAuthHeaders(registry, repository);
    if (!headers) {
      logger.info('No docker auth found - returning');
      return null;
    }
    headers.accept = 'application/vnd.docker.distribution.manifest.v2+json';
    const url = `${registry}/v2/${repository}/manifests/${tag}`;
    const manifestResponse = await got(url, {
      headers,
    });
    return manifestResponse;
  } catch (err) /* istanbul ignore next */ {
    if (err.message === 'registry-failure') {
      throw err;
    }
    if (err.statusCode === 401) {
      logger.info(
        { registry, dockerRepository: repository },
        'Unauthorized docker lookup'
      );
      logger.debug({ err });
      return null;
    }
    if (err.statusCode === 404) {
      logger.info(
        {
          err,
          registry,
          dockerRepository: repository,
          tag,
        },
        'Docker Manifest is unknown'
      );
      return null;
    }
    if (err.statusCode === 429 && registry.endsWith('docker.io')) {
      logger.warn({ err }, 'docker registry failure: too many requests');
      throw new Error('registry-failure');
    }
    if (err.statusCode >= 500 && err.statusCode < 600) {
      logger.info(
        {
          err,
          registry,
          dockerRepository: repository,
          tag,
        },
        'docker registry failure: internal error'
      );
      throw new Error('registry-failure');
    }
    if (err.code === 'ETIMEDOUT') {
      logger.info(
        { registry },
        'Timeout when attempting to connect to docker registry'
      );
      logger.debug({ err });
      return null;
    }
    logger.info(
      {
        err,
        registry,
        dockerRepository: repository,
        tag,
      },
      'Unknown Error looking up docker manifest'
    );
    return null;
  }
}

/**
 * docker.getDigest
 *
 * The `newValue` supplied here should be a valid tag for the docker image.
 *
 * This function will:
 *  - Look up a sha256 digest for a tag on its registry
 *  - Return the digest as a string
 * @param {{registryUrls? : string[], lookupName: string}} args
 * @param {string=} newValue
 */
async function getDigest({ registryUrls, lookupName }, newValue) {
  const { registry, repository } = getRegistryRepository(
    lookupName,
    registryUrls
  );
  logger.debug(`getDigest(${registry}, ${repository}, ${newValue})`);
  const newTag = newValue || 'latest';
  try {
    const cacheNamespace = 'datasource-docker-digest';
    const cacheKey = `${registry}:${repository}:${newTag}`;
    const cachedResult = await renovateCache.get(cacheNamespace, cacheKey);
    // istanbul ignore if
    if (cachedResult) {
      return cachedResult;
    }
    const manifestResponse = await getManifestResponse(
      registry,
      repository,
      newTag
    );
    if (!manifestResponse) {
      return null;
    }
    const digest = extractDigestFromResponse(manifestResponse);
    logger.debug({ digest }, 'Got docker digest');
    const cacheMinutes = 30;
    await renovateCache.set(cacheNamespace, cacheKey, digest, cacheMinutes);
    return digest;
  } catch (err) /* istanbul ignore next */ {
    if (err.message === 'registry-failure') {
      throw err;
    }
    logger.info(
      {
        err,
        lookupName,
        newTag,
      },
      'Unknown Error looking up docker image digest'
    );
    return null;
  }
}

async function getTags(registry, repository) {
  let tags = [];
  try {
    const cacheNamespace = 'datasource-docker-tags';
    const cacheKey = `${registry}:${repository}`;
    const cachedResult = await renovateCache.get(cacheNamespace, cacheKey);
    // istanbul ignore if
    if (cachedResult) {
      return cachedResult;
    }
    let url = `${registry}/v2/${repository}/tags/list?n=10000`;
    const headers = await getAuthHeaders(registry, repository);
    if (!headers) {
      logger.debug('Failed to get authHeaders for getTags lookup');
      return null;
    }
    let page = 1;
    do {
      const res = await got(url, { json: true, headers });
      tags = tags.concat(res.body.tags);
      const linkHeader = parseLinkHeader(res.headers.link);
      url =
        linkHeader && linkHeader.next
          ? URL.resolve(url, linkHeader.next.url)
          : null;
      page += 1;
    } while (url && page < 20);
    const cacheMinutes = 15;
    await renovateCache.set(cacheNamespace, cacheKey, tags, cacheMinutes);
    return tags;
  } catch (err) /* istanbul ignore next */ {
    if (err.message === 'registry-failure') {
      throw err;
    }
    logger.debug(
      {
        err,
      },
      'docker.getTags() error'
    );
    if (err.statusCode === 404 && !repository.includes('/')) {
      logger.info(
        `Retrying Tags for ${registry}/${repository} using library/ prefix`
      );
      return getTags(registry, 'library/' + repository);
    }
    if (err.statusCode === 401 || err.statusCode === 403) {
      logger.info(
        { registry, dockerRepository: repository, err },
        'Not authorised to look up docker tags'
      );
      return null;
    }
    if (err.statusCode === 429 && registry.endsWith('docker.io')) {
      logger.warn(
        { registry, dockerRepository: repository, err },
        'docker registry failure: too many requests'
      );
      throw new Error('registry-failure');
    }
    if (err.statusCode >= 500 && err.statusCode < 600) {
      logger.warn(
        { registry, dockerRepository: repository, err },
        'docker registry failure: internal error'
      );
      throw new Error('registry-failure');
    }
    if (err.code === 'ETIMEDOUT') {
      logger.info(
        { registry },
        'Timeout when attempting to connect to docker registry'
      );
      return null;
    }
    logger.warn(
      { registry, dockerRepository: repository, err },
      'Error getting docker image tags'
    );
    return null;
  }
}

/*
 * docker.getLabels
 *
 * This function will:
 *  - Return the labels for the requested image
 */

// istanbul ignore next
async function getLabels(registry, repository, tag) {
  logger.debug(`getLabels(${registry}, ${repository}, ${tag})`);
  const cacheNamespace = 'datasource-docker-labels';
  const cacheKey = `${registry}:${repository}:${tag}`;
  const cachedResult = await renovateCache.get(cacheNamespace, cacheKey);
  // istanbul ignore if
  if (cachedResult) {
    return cachedResult;
  }
  try {
    const manifestResponse = await getManifestResponse(
      registry,
      repository,
      tag
    );
    // If getting the manifest fails here, then abort
    // This means that the latest tag doesn't have a manifest, which shouldn't
    // be possible
    if (!manifestResponse) {
      logger.info(
        {
          registry,
          dockerRepository: repository,
          tag,
        },
        'docker registry failure: failed to get manifest for tag'
      );
      return {};
    }
    const manifest = JSON.parse(manifestResponse.body);
    let labels = {};
    // istanbul ignore if
    if (!manifest.config) {
      logger.warn({ manifest }, 'Docker manifest error: no config');
      throw new Error('registry-failure');
    }
    const configDigest = manifest.config.digest;
    const headers = await getAuthHeaders(registry, repository);
    if (!headers) {
      logger.info('No docker auth found - returning');
      return {};
    }
    const url = `${registry}/v2/${repository}/blobs/${configDigest}`;
    const configResponse = await got(url, {
      headers,
      hooks: {
        beforeRedirect: [
          options => {
            if (
              options.search &&
              options.search.indexOf('X-Amz-Algorithm') !== -1
            ) {
              // docker registry is hosted on amazon, redirect url includes authentication.
              // eslint-disable-next-line no-param-reassign
              delete options.headers.authorization;
            }
          },
        ],
      },
    });
    labels = JSON.parse(configResponse.body).config.Labels;

    if (labels) {
      logger.debug(
        {
          labels,
        },
        'found labels in manifest'
      );
    }
    const cacheMinutes = 60;
    await renovateCache.set(cacheNamespace, cacheKey, labels, cacheMinutes);
    return labels;
  } catch (err) {
    if (err.message === 'registry-failure') {
      throw err;
    }
    if (err.statusCode === 401) {
      logger.info(
        { registry, dockerRepository: repository },
        'Unauthorized docker lookup'
      );
      logger.debug({ err });
    } else if (err.statusCode === 404) {
      logger.warn(
        {
          err,
          registry,
          dockerRepository: repository,
          tag,
        },
        'Config Manifest is unknown'
      );
    } else if (err.statusCode === 429 && registry.endsWith('docker.io')) {
      logger.warn({ err }, 'docker registry failure: too many requests');
    } else if (err.statusCode >= 500 && err.statusCode < 600) {
      logger.warn(
        {
          err,
          registry,
          dockerRepository: repository,
          tag,
        },
        'docker registry failure: internal error'
      );
    } else if (err.code === 'ETIMEDOUT') {
      logger.info(
        { registry },
        'Timeout when attempting to connect to docker registry'
      );
      logger.debug({ err });
    } else {
      logger.warn({ err }, 'Unknown error getting Docker labels');
    }
    return {};
  }
}

/**
 * docker.getPkgReleases
 *
 * A docker image usually looks something like this: somehost.io/owner/repo:8.1.0-alpine
 * In the above:
 *  - 'somehost.io' is the registry
 *  - 'owner/repo' is the package name
 *  - '8.1.0-alpine' is the tag
 *
 * This function will filter only tags that contain a semver version
 * @param {{lookupName :string, registryUrls?: string[]  }} args
 */
async function getPkgReleases({ lookupName, registryUrls }) {
  const { registry, repository } = getRegistryRepository(
    lookupName,
    registryUrls
  );
  const tags = await getTags(registry, repository);
  if (!tags) {
    return null;
  }
  const releases = tags.map(version => ({ version }));
  const ret = {
    dockerRegistry: registry,
    dockerRepository: repository,
    releases,
  };

  const latestTag = tags.includes('latest') ? 'latest' : tags[tags.length - 1];
  const labels = await getLabels(registry, repository, latestTag);
  // istanbul ignore if
  if (labels && 'org.opencontainers.image.source' in labels) {
    ret.sourceUrl = labels['org.opencontainers.image.source'];
  }
  return ret;
}
<commit_msg>fix(docker): info not warn for no labels<commit_after>import is from '@sindresorhus/is';

const hasha = require('hasha');
const URL = require('url');
const parseLinkHeader = require('parse-link-header');
const wwwAuthenticate = require('www-authenticate');
const { logger } = require('../../logger');

const got = require('../../util/got');
const hostRules = require('../../util/host-rules');

export { getDigest, getPkgReleases };

/**
 *
 * @param {string} lookupName
 * @param {string[]=} registryUrls
 */
function getRegistryRepository(lookupName, registryUrls) {
  /** @type string */
  let registry;
  const split = lookupName.split('/');
  if (split.length > 1 && split[0].includes('.')) {
    [registry] = split;
    split.shift();
  }
  let repository = split.join('/');
  if (!registry && is.nonEmptyArray(registryUrls)) {
    [registry] = registryUrls;
  }
  if (!registry || registry === 'docker.io') {
    registry = 'index.docker.io';
  }
  if (!registry.match('^https?://')) {
    registry = `https://${registry}`;
  }
  if (registry.endsWith('.docker.io') && !repository.includes('/')) {
    repository = 'library/' + repository;
  }
  return {
    registry,
    repository,
  };
}

async function getAuthHeaders(registry, repository) {
  try {
    const apiCheckUrl = `${registry}/v2/`;
    const apiCheckResponse = await got(apiCheckUrl, { throwHttpErrors: false });
    if (apiCheckResponse.headers['www-authenticate'] === undefined) {
      return {};
    }
    const authenticateHeader = new wwwAuthenticate.parsers.WWW_Authenticate(
      apiCheckResponse.headers['www-authenticate']
    );

    /** @type any */
    const opts = hostRules.find({ hostType: 'docker', url: apiCheckUrl });
    opts.json = true;
    if (opts.username && opts.password) {
      const auth = Buffer.from(`${opts.username}:${opts.password}`).toString(
        'base64'
      );
      opts.headers = { authorization: `Basic ${auth}` };
    }
    delete opts.username;
    delete opts.password;

    if (authenticateHeader.scheme.toUpperCase() === 'BASIC') {
      logger.debug(`Using Basic auth for docker registry ${repository}`);
      await got(apiCheckUrl, opts);
      return opts.headers;
    }

    // prettier-ignore
    const authUrl = `${authenticateHeader.parms.realm}?service=${authenticateHeader.parms.service}&scope=repository:${repository}:pull`;
    logger.trace(
      `Obtaining docker registry token for ${repository} using url ${authUrl}`
    );
    const { token } = (await got(authUrl, opts)).body;
    // istanbul ignore if
    if (!token) {
      logger.warn('Failed to obtain docker registry token');
      return null;
    }
    return {
      authorization: `Bearer ${token}`,
    };
  } catch (err) /* istanbul ignore next */ {
    if (err.statusCode === 401) {
      logger.info(
        { registry, dockerRepository: repository },
        'Unauthorized docker lookup'
      );
      logger.debug({ err });
      return null;
    }
    if (err.statusCode === 403) {
      logger.info(
        { registry, dockerRepository: repository },
        'Not allowed to access docker registry'
      );
      logger.debug({ err });
      return null;
    }
    if (err.statusCode === 429 && registry.endsWith('docker.io')) {
      logger.warn({ err }, 'docker registry failure: too many requests');
      throw new Error('registry-failure');
    }
    if (err.statusCode >= 500 && err.statusCode < 600) {
      logger.warn({ err }, 'docker registry failure: internal error');
      throw new Error('registry-failure');
    }
    logger.warn(
      { registry, dockerRepository: repository, err },
      'Error obtaining docker token'
    );
    return null;
  }
}

function digestFromManifestStr(str) {
  return 'sha256:' + hasha(str, { algorithm: 'sha256' });
}

function extractDigestFromResponse(manifestResponse) {
  if (manifestResponse.headers['docker-content-digest'] === undefined) {
    return digestFromManifestStr(manifestResponse.body);
  }
  return manifestResponse.headers['docker-content-digest'];
}

async function getManifestResponse(registry, repository, tag) {
  logger.debug(`getManifestResponse(${registry}, ${repository}, ${tag})`);
  try {
    const headers = await getAuthHeaders(registry, repository);
    if (!headers) {
      logger.info('No docker auth found - returning');
      return null;
    }
    headers.accept = 'application/vnd.docker.distribution.manifest.v2+json';
    const url = `${registry}/v2/${repository}/manifests/${tag}`;
    const manifestResponse = await got(url, {
      headers,
    });
    return manifestResponse;
  } catch (err) /* istanbul ignore next */ {
    if (err.message === 'registry-failure') {
      throw err;
    }
    if (err.statusCode === 401) {
      logger.info(
        { registry, dockerRepository: repository },
        'Unauthorized docker lookup'
      );
      logger.debug({ err });
      return null;
    }
    if (err.statusCode === 404) {
      logger.info(
        {
          err,
          registry,
          dockerRepository: repository,
          tag,
        },
        'Docker Manifest is unknown'
      );
      return null;
    }
    if (err.statusCode === 429 && registry.endsWith('docker.io')) {
      logger.warn({ err }, 'docker registry failure: too many requests');
      throw new Error('registry-failure');
    }
    if (err.statusCode >= 500 && err.statusCode < 600) {
      logger.info(
        {
          err,
          registry,
          dockerRepository: repository,
          tag,
        },
        'docker registry failure: internal error'
      );
      throw new Error('registry-failure');
    }
    if (err.code === 'ETIMEDOUT') {
      logger.info(
        { registry },
        'Timeout when attempting to connect to docker registry'
      );
      logger.debug({ err });
      return null;
    }
    logger.info(
      {
        err,
        registry,
        dockerRepository: repository,
        tag,
      },
      'Unknown Error looking up docker manifest'
    );
    return null;
  }
}

/**
 * docker.getDigest
 *
 * The `newValue` supplied here should be a valid tag for the docker image.
 *
 * This function will:
 *  - Look up a sha256 digest for a tag on its registry
 *  - Return the digest as a string
 * @param {{registryUrls? : string[], lookupName: string}} args
 * @param {string=} newValue
 */
async function getDigest({ registryUrls, lookupName }, newValue) {
  const { registry, repository } = getRegistryRepository(
    lookupName,
    registryUrls
  );
  logger.debug(`getDigest(${registry}, ${repository}, ${newValue})`);
  const newTag = newValue || 'latest';
  try {
    const cacheNamespace = 'datasource-docker-digest';
    const cacheKey = `${registry}:${repository}:${newTag}`;
    const cachedResult = await renovateCache.get(cacheNamespace, cacheKey);
    // istanbul ignore if
    if (cachedResult) {
      return cachedResult;
    }
    const manifestResponse = await getManifestResponse(
      registry,
      repository,
      newTag
    );
    if (!manifestResponse) {
      return null;
    }
    const digest = extractDigestFromResponse(manifestResponse);
    logger.debug({ digest }, 'Got docker digest');
    const cacheMinutes = 30;
    await renovateCache.set(cacheNamespace, cacheKey, digest, cacheMinutes);
    return digest;
  } catch (err) /* istanbul ignore next */ {
    if (err.message === 'registry-failure') {
      throw err;
    }
    logger.info(
      {
        err,
        lookupName,
        newTag,
      },
      'Unknown Error looking up docker image digest'
    );
    return null;
  }
}

async function getTags(registry, repository) {
  let tags = [];
  try {
    const cacheNamespace = 'datasource-docker-tags';
    const cacheKey = `${registry}:${repository}`;
    const cachedResult = await renovateCache.get(cacheNamespace, cacheKey);
    // istanbul ignore if
    if (cachedResult) {
      return cachedResult;
    }
    let url = `${registry}/v2/${repository}/tags/list?n=10000`;
    const headers = await getAuthHeaders(registry, repository);
    if (!headers) {
      logger.debug('Failed to get authHeaders for getTags lookup');
      return null;
    }
    let page = 1;
    do {
      const res = await got(url, { json: true, headers });
      tags = tags.concat(res.body.tags);
      const linkHeader = parseLinkHeader(res.headers.link);
      url =
        linkHeader && linkHeader.next
          ? URL.resolve(url, linkHeader.next.url)
          : null;
      page += 1;
    } while (url && page < 20);
    const cacheMinutes = 15;
    await renovateCache.set(cacheNamespace, cacheKey, tags, cacheMinutes);
    return tags;
  } catch (err) /* istanbul ignore next */ {
    if (err.message === 'registry-failure') {
      throw err;
    }
    logger.debug(
      {
        err,
      },
      'docker.getTags() error'
    );
    if (err.statusCode === 404 && !repository.includes('/')) {
      logger.info(
        `Retrying Tags for ${registry}/${repository} using library/ prefix`
      );
      return getTags(registry, 'library/' + repository);
    }
    if (err.statusCode === 401 || err.statusCode === 403) {
      logger.info(
        { registry, dockerRepository: repository, err },
        'Not authorised to look up docker tags'
      );
      return null;
    }
    if (err.statusCode === 429 && registry.endsWith('docker.io')) {
      logger.warn(
        { registry, dockerRepository: repository, err },
        'docker registry failure: too many requests'
      );
      throw new Error('registry-failure');
    }
    if (err.statusCode >= 500 && err.statusCode < 600) {
      logger.warn(
        { registry, dockerRepository: repository, err },
        'docker registry failure: internal error'
      );
      throw new Error('registry-failure');
    }
    if (err.code === 'ETIMEDOUT') {
      logger.info(
        { registry },
        'Timeout when attempting to connect to docker registry'
      );
      return null;
    }
    logger.warn(
      { registry, dockerRepository: repository, err },
      'Error getting docker image tags'
    );
    return null;
  }
}

/*
 * docker.getLabels
 *
 * This function will:
 *  - Return the labels for the requested image
 */

// istanbul ignore next
async function getLabels(registry, repository, tag) {
  logger.debug(`getLabels(${registry}, ${repository}, ${tag})`);
  const cacheNamespace = 'datasource-docker-labels';
  const cacheKey = `${registry}:${repository}:${tag}`;
  const cachedResult = await renovateCache.get(cacheNamespace, cacheKey);
  // istanbul ignore if
  if (cachedResult) {
    return cachedResult;
  }
  try {
    const manifestResponse = await getManifestResponse(
      registry,
      repository,
      tag
    );
    // If getting the manifest fails here, then abort
    // This means that the latest tag doesn't have a manifest, which shouldn't
    // be possible
    if (!manifestResponse) {
      logger.info(
        {
          registry,
          dockerRepository: repository,
          tag,
        },
        'docker registry failure: failed to get manifest for tag'
      );
      return {};
    }
    const manifest = JSON.parse(manifestResponse.body);
    let labels = {};
    // istanbul ignore if
    if (!manifest.config) {
      logger.info(
        { dockerRepository: repository, tag, manifest },
        'Docker manifest error: no config'
      );
      return {};
    }
    const configDigest = manifest.config.digest;
    const headers = await getAuthHeaders(registry, repository);
    if (!headers) {
      logger.info('No docker auth found - returning');
      return {};
    }
    const url = `${registry}/v2/${repository}/blobs/${configDigest}`;
    const configResponse = await got(url, {
      headers,
      hooks: {
        beforeRedirect: [
          options => {
            if (
              options.search &&
              options.search.indexOf('X-Amz-Algorithm') !== -1
            ) {
              // docker registry is hosted on amazon, redirect url includes authentication.
              // eslint-disable-next-line no-param-reassign
              delete options.headers.authorization;
            }
          },
        ],
      },
    });
    labels = JSON.parse(configResponse.body).config.Labels;

    if (labels) {
      logger.debug(
        {
          labels,
        },
        'found labels in manifest'
      );
    }
    const cacheMinutes = 60;
    await renovateCache.set(cacheNamespace, cacheKey, labels, cacheMinutes);
    return labels;
  } catch (err) {
    if (err.message === 'registry-failure') {
      throw err;
    }
    if (err.statusCode === 401) {
      logger.info(
        { registry, dockerRepository: repository },
        'Unauthorized docker lookup'
      );
      logger.debug({ err });
    } else if (err.statusCode === 404) {
      logger.warn(
        {
          err,
          registry,
          dockerRepository: repository,
          tag,
        },
        'Config Manifest is unknown'
      );
    } else if (err.statusCode === 429 && registry.endsWith('docker.io')) {
      logger.warn({ err }, 'docker registry failure: too many requests');
    } else if (err.statusCode >= 500 && err.statusCode < 600) {
      logger.warn(
        {
          err,
          registry,
          dockerRepository: repository,
          tag,
        },
        'docker registry failure: internal error'
      );
    } else if (err.code === 'ETIMEDOUT') {
      logger.info(
        { registry },
        'Timeout when attempting to connect to docker registry'
      );
      logger.debug({ err });
    } else {
      logger.warn({ err }, 'Unknown error getting Docker labels');
    }
    return {};
  }
}

/**
 * docker.getPkgReleases
 *
 * A docker image usually looks something like this: somehost.io/owner/repo:8.1.0-alpine
 * In the above:
 *  - 'somehost.io' is the registry
 *  - 'owner/repo' is the package name
 *  - '8.1.0-alpine' is the tag
 *
 * This function will filter only tags that contain a semver version
 * @param {{lookupName :string, registryUrls?: string[]  }} args
 */
async function getPkgReleases({ lookupName, registryUrls }) {
  const { registry, repository } = getRegistryRepository(
    lookupName,
    registryUrls
  );
  const tags = await getTags(registry, repository);
  if (!tags) {
    return null;
  }
  const releases = tags.map(version => ({ version }));
  const ret = {
    dockerRegistry: registry,
    dockerRepository: repository,
    releases,
  };

  const latestTag = tags.includes('latest') ? 'latest' : tags[tags.length - 1];
  const labels = await getLabels(registry, repository, latestTag);
  // istanbul ignore if
  if (labels && 'org.opencontainers.image.source' in labels) {
    ret.sourceUrl = labels['org.opencontainers.image.source'];
  }
  return ret;
}
<|endoftext|>


<commit_before>module.exports = (function (){
    "use strict";

    var db = {},
        mongoose = require('mongoose'),
        _ = require("underscore");

    db.collectionName = 'contentTypes';
    db.schema = require('./schemas/contentType'),
    db.model = mongoose.model(db.collectionName, db.schema);

    return _.extend(require("./mixins/crud"), db);
})();
<commit_msg>Updated the contentTypes module to use the new way of extending the crud module.<commit_after>"use strict";

var mongoose = require('mongoose'),
    crud = require("./mixins/crud"),
    collectionName = "contentTypes",
    schema = require('./schemas/contentType'),
    contentType = Object.create(crud,
        {model: {value: mongoose.model(collectionName, schema)}}
    );

module.exports = contentType;<|endoftext|>


<commit_before>var Utils         = require("../../utils")
  , AbstractQuery = require('../abstract/query')
  , DataTypes     = require('../../data-types')
  , hstore        = require('./hstore')
  , QueryTypes    = require('../../query-types')

module.exports = (function() {
  var Query = function(client, sequelize, callee, options) {
    this.client = client
    this.sequelize = sequelize
    this.callee = callee
    this.options = Utils._.extend({
      logging: console.log,
      plain: false,
      raw: false
    }, options || {})

    this.checkLoggingOption()
  }
  Utils.inherit(Query, AbstractQuery)

  Query.prototype.run = function(sql) {
    this.sql = sql

    var self          = this
      , receivedError = false
      , query         = this.client.query(sql)
      , rows          = []

    if (this.options.logging !== false) {
      this.options.logging('Executing (' + this.options.uuid + '): ' + this.sql)
    }

    query.on('row', function(row) {
      rows.push(row)
    })

    query.on('error', function(err) {
      receivedError = true
      err.sql = sql
      self.emit('sql', sql)
      self.emit('error', err, self.callee)
    })

    query.on('end', function(result) {
      self.emit('sql', self.sql)

      if (receivedError) {
        return
      }

      onSuccess.call(self, rows, sql, result)
    })

    return this
  }

  Query.prototype.getInsertIdField = function() {
    return 'id'
  }

  var onSuccess = function(rows, sql, result) {
    var results          = rows
      , self             = this
      , isTableNameQuery = (sql.indexOf('SELECT table_name FROM information_schema.tables') === 0)
      , isRelNameQuery   = (sql.indexOf('SELECT relname FROM pg_class WHERE oid IN') === 0)

    if (isTableNameQuery || isRelNameQuery) {
      if (isRelNameQuery) {
        results = rows.map(function(row) {
          return {
            name:       row.relname,
            tableName:  row.relname.split('_')[0]
          }
        })
      } else {
        results = rows.map(function(row) { return Utils._.values(row) })
      }
      return this.emit('success', results)
    }

    if (this.send('isSelectQuery')) {
      if (this.sql.toLowerCase().indexOf('select c.column_name') === 0) {
        var result = {}

        rows.forEach(function(_result) {
          result[_result.Field] = {
            type:         _result.Type.toUpperCase(),
            allowNull:    (_result.Null === 'YES'),
            defaultValue: _result.Default,
            special: (!!_result.special ? self.sequelize.queryInterface.QueryGenerator.fromArray(_result.special) : [])
          }

          if (result[_result.Field].type === 'BOOLEAN') {
            result[_result.Field].defaultValue = { 'false': false, 'true': true }[result[_result.Field].defaultValue]

            if (result[_result.Field].defaultValue === undefined) {
              result[_result.Field].defaultValue = null
            }
          }

          if (typeof result[_result.Field].defaultValue === 'string') {
            result[_result.Field].defaultValue = result[_result.Field].defaultValue.replace(/'/g, "")

            if (result[_result.Field].defaultValue.indexOf('::') > -1) {
              var split = result[_result.Field].defaultValue.split('::')
              if (split[1].toLowerCase() !== "regclass)") {
                result[_result.Field].defaultValue = split[0]
              }
            }
          }
        })

        this.emit('success', result)
      } else {
        // Postgres will treat tables as case-insensitive, so fix the case
        // of the returned values to match attributes
        if(this.options.raw === false && this.sequelize.options.quoteIdentifiers === false) {
          var attrsMap = Utils._.reduce(this.callee.attributes, function(m, v, k) { m[k.toLowerCase()] = k; return m}, {})
          rows.forEach(function(row) {
            Utils._.keys(row).forEach(function(key) {
              var targetAttr = attrsMap[key]
              if(targetAttr != key) {
                row[targetAttr] = row[key]
                delete row[key]
              }
            })
          })
        }

        this.emit('success', this.send('handleSelectQuery', rows))
      }
    } else if (this.send('isShowOrDescribeQuery')) {
      this.emit('success', results)
    } else if (this.send('isInsertQuery')) {
      if(this.callee !== null) { // may happen for bulk inserts
        for (var key in rows[0]) {
          if (rows[0].hasOwnProperty(key)) {
            var record = rows[0][key]
            if (!!this.callee.Model && !!this.callee.Model.rawAttributes && !!this.callee.Model.rawAttributes[key] && !!this.callee.Model.rawAttributes[key].type && !!this.callee.Model.rawAttributes[key].type.type && this.callee.Model.rawAttributes[key].type.type === DataTypes.HSTORE.type) {
              record = hstore.parse(record)
            }
            this.callee.dataValues[key] = record
          }
        }
      }
      this.emit('success', this.callee)
    } else if ([QueryTypes.BULKUPDATE, QueryTypes.BULKDELETE].indexOf(this.options.type) !== -1) {
      this.emit('success', result.rowCount)
    } else if (this.send('isUpdateQuery')) {
      if(this.callee !== null) { // may happen for bulk updates
        for (var key in rows[0]) {
          if (rows[0].hasOwnProperty(key)) {
            var record = rows[0][key]
            if (!!this.callee.Model && !!this.callee.Model.rawAttributes && !!this.callee.Model.rawAttributes[key] && !!this.callee.Model.rawAttributes[key].type && !!this.callee.Model.rawAttributes[key].type.type && this.callee.Model.rawAttributes[key].type.type === DataTypes.HSTORE.type) {
              record = hstore.parse(record)
            }
            this.callee.dataValues[key] = record
          }
        }
      }

      this.emit('success', this.callee)
    } else {
      this.emit('success', results)
    }
  }

  return Query
})()
<commit_msg>fix(dialects): replace HSTORE checking fn with toString<commit_after>var Utils         = require("../../utils")
  , AbstractQuery = require('../abstract/query')
  , DataTypes     = require('../../data-types')
  , hstore        = require('./hstore')
  , QueryTypes    = require('../../query-types')

module.exports = (function() {
  var Query = function(client, sequelize, callee, options) {
    this.client = client
    this.sequelize = sequelize
    this.callee = callee
    this.options = Utils._.extend({
      logging: console.log,
      plain: false,
      raw: false
    }, options || {})

    this.checkLoggingOption()
  }
  Utils.inherit(Query, AbstractQuery)

  Query.prototype.run = function(sql) {
    this.sql = sql

    var self          = this
      , receivedError = false
      , query         = this.client.query(sql)
      , rows          = []

    if (this.options.logging !== false) {
      this.options.logging('Executing (' + this.options.uuid + '): ' + this.sql)
    }

    query.on('row', function(row) {
      rows.push(row)
    })

    query.on('error', function(err) {
      receivedError = true
      err.sql = sql
      self.emit('sql', sql)
      self.emit('error', err, self.callee)
    })

    query.on('end', function(result) {
      self.emit('sql', self.sql)

      if (receivedError) {
        return
      }

      onSuccess.call(self, rows, sql, result)
    })

    return this
  }

  Query.prototype.getInsertIdField = function() {
    return 'id'
  }

  var onSuccess = function(rows, sql, result) {
    var results          = rows
      , self             = this
      , isTableNameQuery = (sql.indexOf('SELECT table_name FROM information_schema.tables') === 0)
      , isRelNameQuery   = (sql.indexOf('SELECT relname FROM pg_class WHERE oid IN') === 0)

    if (isTableNameQuery || isRelNameQuery) {
      if (isRelNameQuery) {
        results = rows.map(function(row) {
          return {
            name:       row.relname,
            tableName:  row.relname.split('_')[0]
          }
        })
      } else {
        results = rows.map(function(row) { return Utils._.values(row) })
      }
      return this.emit('success', results)
    }

    if (this.send('isSelectQuery')) {
      if (this.sql.toLowerCase().indexOf('select c.column_name') === 0) {
        var result = {}

        rows.forEach(function(_result) {
          result[_result.Field] = {
            type:         _result.Type.toUpperCase(),
            allowNull:    (_result.Null === 'YES'),
            defaultValue: _result.Default,
            special: (!!_result.special ? self.sequelize.queryInterface.QueryGenerator.fromArray(_result.special) : [])
          }

          if (result[_result.Field].type === 'BOOLEAN') {
            result[_result.Field].defaultValue = { 'false': false, 'true': true }[result[_result.Field].defaultValue]

            if (result[_result.Field].defaultValue === undefined) {
              result[_result.Field].defaultValue = null
            }
          }

          if (typeof result[_result.Field].defaultValue === 'string') {
            result[_result.Field].defaultValue = result[_result.Field].defaultValue.replace(/'/g, "")

            if (result[_result.Field].defaultValue.indexOf('::') > -1) {
              var split = result[_result.Field].defaultValue.split('::')
              if (split[1].toLowerCase() !== "regclass)") {
                result[_result.Field].defaultValue = split[0]
              }
            }
          }
        })

        this.emit('success', result)
      } else {
        // Postgres will treat tables as case-insensitive, so fix the case
        // of the returned values to match attributes
        if(this.options.raw === false && this.sequelize.options.quoteIdentifiers === false) {
          var attrsMap = Utils._.reduce(this.callee.attributes, function(m, v, k) { m[k.toLowerCase()] = k; return m}, {})
          rows.forEach(function(row) {
            Utils._.keys(row).forEach(function(key) {
              var targetAttr = attrsMap[key]
              if(targetAttr != key) {
                row[targetAttr] = row[key]
                delete row[key]
              }
            })
          })
        }

        this.emit('success', this.send('handleSelectQuery', rows))
      }
    } else if (this.send('isShowOrDescribeQuery')) {
      this.emit('success', results)
    } else if (this.send('isInsertQuery')) {
      if(this.callee !== null) { // may happen for bulk inserts
        for (var key in rows[0]) {
          if (rows[0].hasOwnProperty(key)) {
            var record = rows[0][key]
            if (!!this.callee.Model && !!this.callee.Model.rawAttributes && !!this.callee.Model.rawAttributes[key] && !!this.callee.Model.rawAttributes[key].type && this.callee.Model.rawAttributes[key].type.toString() === DataTypes.HSTORE.toString()) {
              record = hstore.parse(record)
            }
            this.callee.dataValues[key] = record
          }
        }
      }
      this.emit('success', this.callee)
    } else if ([QueryTypes.BULKUPDATE, QueryTypes.BULKDELETE].indexOf(this.options.type) !== -1) {
      this.emit('success', result.rowCount)
    } else if (this.send('isUpdateQuery')) {
      if(this.callee !== null) { // may happen for bulk updates
        for (var key in rows[0]) {
          if (rows[0].hasOwnProperty(key)) {
            var record = rows[0][key]
            if (!!this.callee.Model && !!this.callee.Model.rawAttributes && !!this.callee.Model.rawAttributes[key] && !!this.callee.Model.rawAttributes[key].type && this.callee.Model.rawAttributes[key].type.toString() === DataTypes.HSTORE.toString()) {
              record = hstore.parse(record)
            }
            this.callee.dataValues[key] = record
          }
        }
      }

      this.emit('success', this.callee)
    } else {
      this.emit('success', results)
    }
  }

  return Query
})()
<|endoftext|>


<commit_before>module.exports = function(grunt) {

    //grunt-sass
    grunt.config('sass', {
        options: {
            outputStyle: 'expanded',
            //includePaths: ['<%= config.scss.includePaths  %>'],
            imagePath: '../<%= config.image.dir  %>'
        },
        dist: {
            files: {
                '<%= config.css.dir  %>/<%= config.css.fileExpanded  %>': '<%= config.scss.dir  %>/<%= config.scss.file  %>'
            }
        }
    });

    //grunt-autoprefixer
    grunt.config('autoprefixer', {
        options: {
            browsers: ['> 1%', 'last 2 versions', 'ie 8', 'ie 9', 'ie 10']
        },
        dist: {
            files: {
                '<%= config.css.dir  %>/<%= config.css.fileExpanded  %>': '<%= config.css.dir  %>/<%= config.css.fileExpanded  %>'
            }
        }
    });

    //grunt-contrib-cssmin
    grunt.config('cssmin', {
        target: {
            src: '<%= config.css.dir  %>/<%= config.css.fileExpanded  %>',
            dest: '<%= config.css.dir  %>/<%= config.css.file  %>'
        }
    });

    //grunt-contrib-csslint
    grunt.config('csslint', {
        options: {
            csslintrc: 'grunt/.csslintrc'
        },
        strict: {
            src: ['<%= config.css.dir  %>/<%= config.css.file  %>']
        }
    });
};<commit_msg>Enable debug comments in grunt-sass output file<commit_after>module.exports = function(grunt) {

    //grunt-sass
    grunt.config('sass', {
        options: {
            outputStyle: 'expanded',
            //includePaths: ['<%= config.scss.includePaths  %>'],
            imagePath: '../<%= config.image.dir  %>',
            sourceComments: true
        },
        dist: {
            files: {
                '<%= config.css.dir  %>/<%= config.css.fileExpanded  %>': '<%= config.scss.dir  %>/<%= config.scss.file  %>'
            }
        }
    });

    //grunt-autoprefixer
    grunt.config('autoprefixer', {
        options: {
            browsers: ['> 1%', 'last 2 versions', 'ie 8', 'ie 9', 'ie 10']
        },
        dist: {
            files: {
                '<%= config.css.dir  %>/<%= config.css.fileExpanded  %>': '<%= config.css.dir  %>/<%= config.css.fileExpanded  %>'
            }
        }
    });

    //grunt-contrib-cssmin
    grunt.config('cssmin', {
        target: {
            src: '<%= config.css.dir  %>/<%= config.css.fileExpanded  %>',
            dest: '<%= config.css.dir  %>/<%= config.css.file  %>'
        }
    });

    //grunt-contrib-csslint
    grunt.config('csslint', {
        options: {
            csslintrc: 'grunt/.csslintrc'
        },
        strict: {
            src: ['<%= config.css.dir  %>/<%= config.css.file  %>']
        }
    });
};<|endoftext|>


<commit_before>const bl     = require('bl');
const http   = require('http');

const PageBuffer = function(url) {
    return { 'url'  : url
           , 'bl'   : bl()
           , 'ended': false
           };
};

const numPages = process.argv.length - 2;
var pages = Array(numPages);
for (var i = 0; i < numPages; ++i) {
    pages[i] = PageBuffer( process.argv[i+2] );
}

function printIfDone() {
    // Check if all buffers are ended
    for (var i = 0; i < pages.length; ++i) {
        if (! pages[i].ended) {
            return;
        }
    }
    // Dump received content
    for (var i = 0; i < pages.length; ++i) {
        console.log( pages[i].bl.toString() );
    }
}

for (var i = 0; i < pages.length; ++i) {
    http.get( pages[i].url, function(i) { return function(response) {
        response.setEncoding('utf8');
        response.on('data', function(d) { pages[i].bl.append(d); } );  // Why can't this be eta-reduced?
        response.on('end' , function( ) { pages[i].ended = true; printIfDone(); } );
        response.on('error', console.error);
    } }(i) );  // JavaScript's scoping is broken
}

<commit_msg>Don't redeclare variable<commit_after>const bl     = require('bl');
const http   = require('http');

const PageBuffer = function(url) {
    return { 'url'  : url
           , 'bl'   : bl()
           , 'ended': false
           };
};

const numPages = process.argv.length - 2;
var pages = Array(numPages);
for (var i = 0; i < numPages; ++i) {
    pages[i] = PageBuffer( process.argv[i+2] );
}

function printIfDone() {
    // Check if all buffers are ended
    for (var i = 0; i < pages.length; ++i) {
        if (! pages[i].ended) {
            return;
        }
    }
    // Dump received content
    for (i = 0; i < pages.length; ++i) {
        console.log( pages[i].bl.toString() );
    }
}

for (i = 0; i < pages.length; ++i) {
    http.get( pages[i].url, function(i) { return function(response) {
        response.setEncoding('utf8');
        response.on('data', function(d) { pages[i].bl.append(d); } );  // Why can't this be eta-reduced?
        response.on('end' , function( ) { pages[i].ended = true; printIfDone(); } );
        response.on('error', console.error);
    } }(i) );  // JavaScript's scoping is broken
}

<|endoftext|>