text:
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

'use strict';

/**
 * @fileoverview The event page for Google Now for Chrome implementation.
 * The Google Now event page gets Google Now cards from the server and shows
 * them as Chrome notifications.
 * The service performs periodic updating of Google Now cards.
 * Each updating of the cards includes 4 steps:
 * 1. Processing requests for cards dismissals that are not yet sent to the
 *    server.
 * 2. Making a server request.
 * 3. Showing the received cards as notifications.
 */

// TODO(vadimt): Decide what to do in incognito mode.
// TODO(vadimt): Figure out the final values of the constants.

/**
 * Standard response code for successful HTTP requests. This is the only success
 * code the server will send.
 */
var HTTP_OK = 200;
var HTTP_NOCONTENT = 204;

var HTTP_BAD_REQUEST = 400;
var HTTP_UNAUTHORIZED = 401;
var HTTP_FORBIDDEN = 403;
var HTTP_METHOD_NOT_ALLOWED = 405;

var MS_IN_SECOND = 1000;
var MS_IN_MINUTE = 60 * 1000;

/**
 * Initial period for polling for Google Now Notifications cards to use when the
 * period from the server is not available.
 */
var INITIAL_POLLING_PERIOD_SECONDS = 5 * 60;  // 5 minutes

/**
 * Mininal period for polling for Google Now Notifications cards.
 */
var MINIMUM_POLLING_PERIOD_SECONDS = 5 * 60;  // 5 minutes

/**
 * Maximal period for polling for Google Now Notifications cards to use when the
 * period from the server is not available.
 */
var MAXIMUM_POLLING_PERIOD_SECONDS = 60 * 60;  // 1 hour

/**
 * Initial period for retrying the server request for dismissing cards.
 */
var INITIAL_RETRY_DISMISS_PERIOD_SECONDS = 60;  // 1 minute

/**
 * Maximum period for retrying the server request for dismissing cards.
 */
var MAXIMUM_RETRY_DISMISS_PERIOD_SECONDS = 60 * 60;  // 1 hour

/**
 * Time we keep retrying dismissals.
 */
var MAXIMUM_DISMISSAL_AGE_MS = 24 * 60 * 60 * 1000; // 1 day

/**
 * Time we keep dismissals after successful server dismiss requests.
 */
var DISMISS_RETENTION_TIME_MS = 20 * 60 * 1000;  // 20 minutes

/**
 * Default period for checking whether the user is opted in to Google Now.
 */
var DEFAULT_OPTIN_CHECK_PERIOD_SECONDS = 60 * 60 * 24 * 7; // 1 week

/**
 * URL to open when the user clicked on a link for the our notification
 * settings.
 */
var SETTINGS_URL = 'https://support.google.com/chrome/?p=ib_google_now_welcome';

/**
 * Number of cards that need an explanatory link.
 */
var EXPLANATORY_CARDS_LINK_THRESHOLD = 4;

/**
 * Names for tasks that can be created by the extension.
 */
var UPDATE_CARDS_TASK_NAME = 'update-cards';
var DISMISS_CARD_TASK_NAME = 'dismiss-card';
var RETRY_DISMISS_TASK_NAME = 'retry-dismiss';
var STATE_CHANGED_TASK_NAME = 'state-changed';
var SHOW_ON_START_TASK_NAME = 'show-cards-on-start';
var ON_PUSH_MESSAGE_START_TASK_NAME = 'on-push-message';

/**
 * Group as received from the server.
 *
 * @typedef {{
 *   nextPollSeconds: (string|undefined),
 *   rank: (number|undefined),
 *   requested: (boolean|undefined)
 * }}
 */
var ReceivedGroup;

/**
 * Server response with notifications and groups.
 *
 * @typedef {{
 *   googleNowDisabled: (boolean|undefined),
 *   groups: Object.<string, ReceivedGroup>,
 *   notifications: Array.<ReceivedNotification>
 * }}
 */
var ServerResponse;

/**
 * Notification group as the client stores it. |cardsTimestamp| and |rank| are
 * defined if |cards| is non-empty. |nextPollTime| is undefined if the server
 * (1) never sent 'nextPollSeconds' for the group or
 * (2) didn't send 'nextPollSeconds' with the last group update containing a
 *     cards update and all the times after that.
 *
 * @typedef {{
 *   cards: Array.<ReceivedNotification>,
 *   cardsTimestamp: (number|undefined),
 *   nextPollTime: (number|undefined),
 *   rank: (number|undefined)
 * }}
 */
var StoredNotificationGroup;

/**
 * Pending (not yet successfully sent) dismissal for a received notification.
 * |time| is the moment when the user requested dismissal.
 *
 * @typedef {{
 *   chromeNotificationId: ChromeNotificationId,
 *   time: number,
 *   dismissalData: DismissalData
 * }}
 */
var PendingDismissal;

/**
 * Checks if a new task can't be scheduled when another task is already
 * scheduled.
 * @param {string} newTaskName Name of the new task.
 * @param {string} scheduledTaskName Name of the scheduled task.
 * @return {boolean} Whether the new task conflicts with the existing task.
 */
function areTasksConflicting(newTaskName, scheduledTaskName) {
  if (newTaskName == UPDATE_CARDS_TASK_NAME &&
      scheduledTaskName == UPDATE_CARDS_TASK_NAME) {
    // If a card update is requested while an old update is still scheduled, we
    // don't need the new update.
    return true;
  }

  if (newTaskName == RETRY_DISMISS_TASK_NAME &&
      (scheduledTaskName == UPDATE_CARDS_TASK_NAME ||
       scheduledTaskName == DISMISS_CARD_TASK_NAME ||
       scheduledTaskName == RETRY_DISMISS_TASK_NAME)) {
    // No need to schedule retry-dismiss action if another action that tries to
    // send dismissals is scheduled.
    return true;
  }

  return false;
}

var tasks = buildTaskManager(areTasksConflicting);

// Add error processing to API calls.
wrapper.instrumentChromeApiFunction('metricsPrivate.getVariationParams', 1);
wrapper.instrumentChromeApiFunction('notifications.clear', 1);
wrapper.instrumentChromeApiFunction('notifications.create', 2);
wrapper.instrumentChromeApiFunction('notifications.getPermissionLevel', 0);
wrapper.instrumentChromeApiFunction('notifications.update', 2);
wrapper.instrumentChromeApiFunction('notifications.getAll', 0);
wrapper.instrumentChromeApiFunction(
    'notifications.onButtonClicked.addListener', 0);
wrapper.instrumentChromeApiFunction('notifications.onClicked.addListener', 0);
wrapper.instrumentChromeApiFunction('notifications.onClosed.addListener', 0);
wrapper.instrumentChromeApiFunction(
    'notifications.onPermissionLevelChanged.addListener', 0);
wrapper.instrumentChromeApiFunction(
    'notifications.onShowSettings.addListener', 0);
wrapper.instrumentChromeApiFunction('permissions.contains', 1);
wrapper.instrumentChromeApiFunction('pushMessaging.onMessage.addListener', 0);
wrapper.instrumentChromeApiFunction('runtime.onInstalled.addListener', 0);
wrapper.instrumentChromeApiFunction('runtime.onStartup.addListener', 0);
wrapper.instrumentChromeApiFunction('tabs.create', 1);

var updateCardsAttempts = buildAttemptManager(
    'cards-update',
    requestCards,
    INITIAL_POLLING_PERIOD_SECONDS,
    MAXIMUM_POLLING_PERIOD_SECONDS);
var dismissalAttempts = buildAttemptManager(
    'dismiss',
    retryPendingDismissals,
    INITIAL_RETRY_DISMISS_PERIOD_SECONDS,
    MAXIMUM_RETRY_DISMISS_PERIOD_SECONDS);
var cardSet = buildCardSet();

var authenticationManager = buildAuthenticationManager();

/**
 * Google Now UMA event identifier.
 * @enum {number}
 */
var GoogleNowEvent = {
  REQUEST_FOR_CARDS_TOTAL: 0,
  REQUEST_FOR_CARDS_SUCCESS: 1,
  CARDS_PARSE_SUCCESS: 2,
  DISMISS_REQUEST_TOTAL: 3,
  DISMISS_REQUEST_SUCCESS: 4,
  LOCATION_REQUEST: 5,
  DELETED_LOCATION_UPDATE: 6,
  EXTENSION_START: 7,
  DELETED_SHOW_WELCOME_TOAST: 8,
  STOPPED: 9,
  DELETED_USER_SUPPRESSED: 10,
  EVENTS_TOTAL: 11  // EVENTS_TOTAL is not an event; all new events need to be
                    // added before it.
};

/**
 * Records a Google Now Event.
 * @param {GoogleNowEvent} event Event identifier.
 */
function recordEvent(event) {
  var metricDescription = {
    metricName: 'GoogleNow.Event',
    type: 'histogram-linear',
    min: 1,
    max: GoogleNowEvent.EVENTS_TOTAL,
    buckets: GoogleNowEvent.EVENTS_TOTAL + 1
  };

  chrome.metricsPrivate.recordValue(metricDescription, event);
}

/**
 * Checks the result of the HTTP Request and updates the authentication
 * manager on any failure.
 * @param {XMLHttpRequest} request XMLHttpRequest that sent the authenticated
 *     request.
 */
function checkAuthenticationStatus(request) {
  if (request.status == HTTP_FORBIDDEN ||
      request.status == HTTP_UNAUTHORIZED) {
    authenticationManager.removeToken(token);
  }
}

/**
 * Builds and sends an authenticated request to the notification server.
 * @param {string} method Request method.
 * @param {string} handlerName Server handler to send the request to.
 * @param {string=} opt_contentType Value for the Content-type header.
 * @return {Promise} A promise to issue a request to the server.
 *     The promise rejects if there is a client-side authentication issue.
 */
function requestFromServer(method, handlerName, opt_contentType) {
  return authenticationManager.getAuthToken().then(function(token) {
    var request = buildServerRequest(method, handlerName, opt_contentType);
    request.setRequestHeader('Authorization', 'Bearer ' + token);
    var requestPromise = new Promise(function(resolve) {
      request.addEventListener('loadend', function() {
        resolve(request);
      }, false);
      request.send();
    });
    requestPromise.then(checkAuthenticationStatus);
    return requestPromise;
  });
}

/**
 * Shows parsed and combined cards as notifications.
 * @param {Object.<string, StoredNotificationGroup>} notificationGroups Map from
 *     group name to group information.
 * @param {Object.<ChromeNotificationId, CombinedCard>} cards Map from
 *     chromeNotificationId to the combined card, containing cards to show.
 * @param {function()} onSuccess Called on success.
 * @param {function(ReceivedNotification)=} onCardShown Optional parameter
 *     called when each card is shown.
 */
function showNotificationCards(
    notificationGroups, cards, onSuccess, onCardShown) {
  console.log('showNotificationCards ' + JSON.stringify(cards));

  instrumented.notifications.getAll(function(notifications) {
    console.log('showNotificationCards-getAll ' +
        JSON.stringify(notifications));
    notifications = notifications || {};

    // Mark notifications that didn't receive an update as having received
    // an empty update.
    for (var chromeNotificationId in notifications) {
      cards[chromeNotificationId] = cards[chromeNotificationId] || [];
    }

    /** @type {Object.<string, NotificationDataEntry>} */
    var notificationsData = {};

    // Create/update/delete notifications.
    for (var chromeNotificationId in cards) {
      notificationsData[chromeNotificationId] = cardSet.update(
          chromeNotificationId,
          cards[chromeNotificationId],
          notificationGroups,
          onCardShown);
    }
    chrome.storage.local.set({notificationsData: notificationsData});
    onSuccess();
  });
}

/**
 * Removes all cards and card state on Google Now close down.
 */
function removeAllCards() {
  console.log('removeAllCards');

  // TODO(robliao): Once Google Now clears its own checkbox in the
  // notifications center and bug 260376 is fixed, the below clearing
  // code is no longer necessary.
  instrumented.notifications.getAll(function(notifications) {
    notifications = notifications || {};
    for (var chromeNotificationId in notifications) {
      instrumented.notifications.clear(chromeNotificationId, function() {});
    }
    chrome.storage.local.remove(['notificationsData', 'notificationGroups']);
  });
}

/**
 * Adds a card group into a set of combined cards.
 * @param {Object.<ChromeNotificationId, CombinedCard>} combinedCards Map from
 *     chromeNotificationId to a combined card.
 *     This is an input/output parameter.
 * @param {StoredNotificationGroup} storedGroup Group to combine into the
 *     combined card set.
 */
function combineGroup(combinedCards, storedGroup) {
  for (var i = 0; i < storedGroup.cards.length; i++) {
    /** @type {ReceivedNotification} */
    var receivedNotification = storedGroup.cards[i];

    /** @type {UncombinedNotification} */
    var uncombinedNotification = {
      receivedNotification: receivedNotification,
      showTime: receivedNotification.trigger.showTimeSec &&
                (storedGroup.cardsTimestamp +
                 receivedNotification.trigger.showTimeSec * MS_IN_SECOND),
      hideTime: storedGroup.cardsTimestamp +
                receivedNotification.trigger.hideTimeSec * MS_IN_SECOND
    };

    var combinedCard =
        combinedCards[receivedNotification.chromeNotificationId] || [];
    combinedCard.push(uncombinedNotification);
    combinedCards[receivedNotification.chromeNotificationId] = combinedCard;
  }
}

/**
 * Schedules next cards poll.
 * @param {Object.<string, StoredNotificationGroup>} groups Map from group name
 *     to group information.
 * @param {boolean} isOptedIn True if the user is opted in to Google Now.
 */
function scheduleNextPoll(groups, isOptedIn) {
  if (isOptedIn) {
    var nextPollTime = null;

    for (var groupName in groups) {
      var group = groups[groupName];
      if (group.nextPollTime !== undefined) {
        nextPollTime = nextPollTime == null ?
            group.nextPollTime : Math.min(group.nextPollTime, nextPollTime);
      }
    }

    // At least one of the groups must have nextPollTime.
    verify(nextPollTime != null, 'scheduleNextPoll: nextPollTime is null');

    var nextPollDelaySeconds = Math.max(
        (nextPollTime - Date.now()) / MS_IN_SECOND,
        MINIMUM_POLLING_PERIOD_SECONDS);
    updateCardsAttempts.start(nextPollDelaySeconds);
  } else {
    instrumented.metricsPrivate.getVariationParams(
        'GoogleNow', function(params) {
      var optinPollPeriodSeconds =
          parseInt(params && params.optinPollPeriodSeconds, 10) ||
          DEFAULT_OPTIN_CHECK_PERIOD_SECONDS;
      updateCardsAttempts.start(optinPollPeriodSeconds);
    });
  }
}

/**
 * Combines notification groups into a set of Chrome notifications and shows
 * them.
 * @param {Object.<string, StoredNotificationGroup>} notificationGroups Map from
 *     group name to group information.
 * @param {function()} onSuccess Called on success.
 * @param {function(ReceivedNotification)=} onCardShown Optional parameter
 *     called when each card is shown.
 */
function combineAndShowNotificationCards(
    notificationGroups, onSuccess, onCardShown) {
  console.log('combineAndShowNotificationCards ' +
      JSON.stringify(notificationGroups));
  /** @type {Object.<ChromeNotificationId, CombinedCard>} */
  var combinedCards = {};

  for (var groupName in notificationGroups)
    combineGroup(combinedCards, notificationGroups[groupName]);

  showNotificationCards(
      notificationGroups, combinedCards, onSuccess, onCardShown);
}

/**
 * Based on a response from the notification server, shows notifications and
 * schedules next update.
 * @param {ServerResponse} response Server response.
 * @param {function(ReceivedNotification)=} onCardShown Optional parameter
 *     called when each card is shown.
 */
function processServerResponse(response, onCardShown) {
  console.log('processServerResponse ' + JSON.stringify(response));

  if (response.googleNowDisabled) {
    chrome.storage.local.set({googleNowEnabled: false});
    // TODO(vadimt): Remove the line below once the server stops sending groups
    // with 'googleNowDisabled' responses.
    response.groups = {};
    // Google Now was enabled; now it's disabled. This is a state change.
    onStateChange();
  }

  var receivedGroups = response.groups;

  fillFromChromeLocalStorage({
    /** @type {Object.<string, StoredNotificationGroup>} */
    notificationGroups: {},
    /** @type {Object.<NotificationId, number>} */
    recentDismissals: {}
  }).then(function(items) {
    console.log('processServerResponse-get ' + JSON.stringify(items));

    // Build a set of non-expired recent dismissals. It will be used for
    // client-side filtering of cards.
    /** @type {Object.<NotificationId, number>} */
    var updatedRecentDismissals = {};
    var now = Date.now();
    for (var notificationId in items.recentDismissals) {
      var dismissalAge = now - items.recentDismissals[notificationId];
      if (dismissalAge < DISMISS_RETENTION_TIME_MS) {
        updatedRecentDismissals[notificationId] =
            items.recentDismissals[notificationId];
      }
    }

    // Populate groups with corresponding cards.
    if (response.notifications) {
      for (var i = 0; i < response.notifications.length; ++i) {
        /** @type {ReceivedNotification} */
        var card = response.notifications[i];
        if (!(card.notificationId in updatedRecentDismissals)) {
          var group = receivedGroups[card.groupName];
          group.cards = group.cards || [];
          group.cards.push(card);
        }
      }
    }

    // Build updated set of groups.
    var updatedGroups = {};

    for (var groupName in receivedGroups) {
      var receivedGroup = receivedGroups[groupName];
      var storedGroup = items.notificationGroups[groupName] || {
        cards: [],
        cardsTimestamp: undefined,
        nextPollTime: undefined,
        rank: undefined
      };

      if (receivedGroup.requested)
        receivedGroup.cards = receivedGroup.cards || [];

      if (receivedGroup.cards) {
        // If the group contains a cards update, all its fields will get new
        // values.
        storedGroup.cards = receivedGroup.cards;
        storedGroup.cardsTimestamp = now;
        storedGroup.rank = receivedGroup.rank;
        storedGroup.nextPollTime = undefined;
        // The code below assigns nextPollTime a defined value if
        // nextPollSeconds is specified in the received group.
        // If the group's cards are not updated, and nextPollSeconds is
        // unspecified, this method doesn't change group's nextPollTime.
      }

      // 'nextPollSeconds' may be sent even for groups that don't contain
      // cards updates.
      if (receivedGroup.nextPollSeconds !== undefined) {
        storedGroup.nextPollTime =
            now + receivedGroup.nextPollSeconds * MS_IN_SECOND;
      }

      updatedGroups[groupName] = storedGroup;
    }

    scheduleNextPoll(updatedGroups, !response.googleNowDisabled);
    combineAndShowNotificationCards(
        updatedGroups,
        function() {
          chrome.storage.local.set({
            notificationGroups: updatedGroups,
            recentDismissals: updatedRecentDismissals
          });
          recordEvent(GoogleNowEvent.CARDS_PARSE_SUCCESS);
        },
        onCardShown);
  });
}

/**
 * Update the Explanatory Total Cards Shown Count.
 */
function countExplanatoryCard() {
  localStorage['explanatoryCardsShown']++;
}

/**
 * Requests notification cards from the server for specified groups.
 * @param {Array.<string>} groupNames Names of groups that need to be refreshed.
 */
function requestNotificationGroups(groupNames) {
  console.log('requestNotificationGroups from ' + NOTIFICATION_CARDS_URL +
      ', groupNames=' + JSON.stringify(groupNames));

  recordEvent(GoogleNowEvent.REQUEST_FOR_CARDS_TOTAL);

  var requestParameters = '?timeZoneOffsetMs=' +
    (-new Date().getTimezoneOffset() * MS_IN_MINUTE);

  var cardShownCallback = undefined;
  var belowExplanatoryThreshold =
      localStorage['explanatoryCardsShown'] < EXPLANATORY_CARDS_LINK_THRESHOLD;
  if (belowExplanatoryThreshold) {
    requestParameters += '&cardExplanation=true';
    cardShownCallback = countExplanatoryCard;
  }

  groupNames.forEach(function(groupName) {
    requestParameters += ('&requestTypes=' + groupName);
  });

  requestParameters += '&uiLocale=' + navigator.language;

  console.log('requestNotificationGroups: request=' + requestParameters);

  requestFromServer('GET', 'notifications' + requestParameters).then(
    function(request) {
      console.log('requestNotificationGroups-received ' + request.status);
      if (request.status == HTTP_OK) {
        recordEvent(GoogleNowEvent.REQUEST_FOR_CARDS_SUCCESS);
        processServerResponse(
            JSON.parse(request.responseText), cardShownCallback);
      }
    });
}

/**
 * Requests the account opted-in state from the server.
 * @param {function()} optedInCallback Function that will be called if
 *     opted-in state is 'true'.
 */
function requestOptedIn(optedInCallback) {
  console.log('requestOptedIn from ' + NOTIFICATION_CARDS_URL);

  requestFromServer('GET', 'settings/optin').then(function(request) {
    console.log(
        'requestOptedIn-received ' + request.status + ' ' + request.response);
    if (request.status == HTTP_OK) {
      var parsedResponse = JSON.parse(request.responseText);
      if (parsedResponse.value) {
        chrome.storage.local.set({googleNowEnabled: true});
        optedInCallback();
        // Google Now was disabled, now it's enabled. This is a state change.
        onStateChange();
      } else {
        scheduleNextPoll({}, false);
      }
    }
  });
}

/**
 * Requests notification cards from the server.
 */
function requestNotificationCards() {
  console.log('requestNotificationCards');

  fillFromChromeLocalStorage({
    /** @type {Object.<string, StoredNotificationGroup>} */
    notificationGroups: {},
    googleNowEnabled: false
  }).then(function(items) {
    console.log(
        'requestNotificationCards-storage-get ' + JSON.stringify(items));

    var groupsToRequest = [];

    var now = Date.now();

    for (var groupName in items.notificationGroups) {
      var group = items.notificationGroups[groupName];
      if (group.nextPollTime !== undefined && group.nextPollTime <= now)
        groupsToRequest.push(groupName);
    }

    if (items.googleNowEnabled) {
      requestNotificationGroups(groupsToRequest);
    } else {
      requestOptedIn(function() {
        requestNotificationGroups(groupsToRequest);
      });
    }
  });
}

/**
 * Requests and shows notification cards.
 */
function requestCards() {
  console.log('requestCards @' + new Date());
  // LOCATION_REQUEST is a legacy histogram value when we requested location.
  // This corresponds to the extension attempting to request for cards.
  // We're keeping the name the same to keep our histograms in order.
  recordEvent(GoogleNowEvent.LOCATION_REQUEST);
  tasks.add(UPDATE_CARDS_TASK_NAME, function() {
    console.log('requestCards-task-begin');
    updateCardsAttempts.isRunning(function(running) {
      if (running) {
        updateCardsAttempts.planForNext(function() {
          // The cards are requested only if there are no unsent dismissals.
          processPendingDismissals().then(requestNotificationCards);
        });
      }
    });
  });
}

/**
 * Sends a server request to dismiss a card.
 * @param {ChromeNotificationId} chromeNotificationId chrome.notifications ID of
 *     the card.
 * @param {number} dismissalTimeMs Time of the user's dismissal of the card in
 *     milliseconds since epoch.
 * @param {DismissalData} dismissalData Data to build a dismissal request.
 * @return {Promise} A promise to request the card dismissal, rejects on error.
 */
function requestCardDismissal(
    chromeNotificationId, dismissalTimeMs, dismissalData) {
  console.log('requestDismissingCard ' + chromeNotificationId +
      ' from ' + NOTIFICATION_CARDS_URL +
      ', dismissalData=' + JSON.stringify(dismissalData));

  var dismissalAge = Date.now() - dismissalTimeMs;

  if (dismissalAge > MAXIMUM_DISMISSAL_AGE_MS) {
    callbackBoolean(true);
    return;
  }

  recordEvent(GoogleNowEvent.DISMISS_REQUEST_TOTAL);

  var requestParameters = 'notifications/' + dismissalData.notificationId +
      '?age=' + dismissalAge +
      '&chromeNotificationId=' + chromeNotificationId;

  for (var paramField in dismissalData.parameters)
    requestParameters += ('&' + paramField +
    '=' + dismissalData.parameters[paramField]);

  console.log('requestCardDismissal: requestParameters=' + requestParameters);

  return requestFromServer('DELETE', requestParameters).then(function(request) {
    console.log('requestDismissingCard-onloadend ' + request.status);
    if (request.status == HTTP_NOCONTENT)
      recordEvent(GoogleNowEvent.DISMISS_REQUEST_SUCCESS);

    // A dismissal doesn't require further retries if it was successful or
    // doesn't have a chance for successful completion.
    var done = request.status == HTTP_NOCONTENT ||
        request.status == HTTP_BAD_REQUEST ||
        request.status == HTTP_METHOD_NOT_ALLOWED;
    return done ? Promise.resolve() : Promise.reject();
  });
}

/**
 * Tries to send dismiss requests for all pending dismissals.
 * @return {Promise} A promise to process the pending dismissals.
 *     The promise is rejected if a problem was encountered.
 */
function processPendingDismissals() {
  return fillFromChromeLocalStorage({
    /** @type {Array.<PendingDismissal>} */
    pendingDismissals: [],
    /** @type {Object.<NotificationId, number>} */
    recentDismissals: {}
  }).then(function(items) {
    console.log(
        'processPendingDismissals-storage-get ' + JSON.stringify(items));

    var dismissalsChanged = false;

    function onFinish(success) {
      if (dismissalsChanged) {
        chrome.storage.local.set({
          pendingDismissals: items.pendingDismissals,
          recentDismissals: items.recentDismissals
        });
      }
      return success ? Promise.resolve() : Promise.reject();
    }

    function doProcessDismissals() {
      if (items.pendingDismissals.length == 0) {
        dismissalAttempts.stop();
        return onFinish(true);
      }

      // Send dismissal for the first card, and if successful, repeat
      // recursively with the rest.
      /** @type {PendingDismissal} */
      var dismissal = items.pendingDismissals[0];
      return requestCardDismissal(
          dismissal.chromeNotificationId,
          dismissal.time,
          dismissal.dismissalData).then(function() {
            dismissalsChanged = true;
            items.pendingDismissals.splice(0, 1);
            items.recentDismissals[dismissal.dismissalData.notificationId] =
                Date.now();
            return doProcessDismissals();
          }).catch(function() {
            return onFinish(false);
          });
    }

    return doProcessDismissals();
  });
}

/**
 * Submits a task to send pending dismissals.
 */
function retryPendingDismissals() {
  tasks.add(RETRY_DISMISS_TASK_NAME, function() {
    dismissalAttempts.planForNext(function() {
      processPendingDismissals();
     });
  });
}

/**
 * Opens a URL in a new tab.
 * @param {string} url URL to open.
 */
function openUrl(url) {
  instrumented.tabs.create({url: url}, function(tab) {
    if (tab)
      chrome.windows.update(tab.windowId, {focused: true});
    else
      chrome.windows.create({url: url, focused: true});
  });
}

/**
 * Opens URL corresponding to the clicked part of the notification.
 * @param {ChromeNotificationId} chromeNotificationId chrome.notifications ID of
 *     the card.
 * @param {function((ActionUrls|undefined)): (string|undefined)} selector
 *     Function that extracts the url for the clicked area from the button
 *     action URLs info.
 */
function onNotificationClicked(chromeNotificationId, selector) {
  fillFromChromeLocalStorage({
    /** @type {Object.<string, NotificationDataEntry>} */
    notificationsData: {}
  }).then(function(items) {
    /** @type {(NotificationDataEntry|undefined)} */
    var notificationData = items.notificationsData[chromeNotificationId];
    if (!notificationData)
      return;

    var url = selector(notificationData.actionUrls);
    if (!url)
      return;

    openUrl(url);
  });
}

/**
 * Callback for chrome.notifications.onClosed event.
 * @param {ChromeNotificationId} chromeNotificationId chrome.notifications ID of
 *     the card.
 * @param {boolean} byUser Whether the notification was closed by the user.
 */
function onNotificationClosed(chromeNotificationId, byUser) {
  if (!byUser)
    return;

  // At this point we are guaranteed that the notification is a now card.
  chrome.metricsPrivate.recordUserAction('GoogleNow.Dismissed');

  tasks.add(DISMISS_CARD_TASK_NAME, function() {
    dismissalAttempts.start();

    fillFromChromeLocalStorage({
      /** @type {Array.<PendingDismissal>} */
      pendingDismissals: [],
      /** @type {Object.<string, NotificationDataEntry>} */
      notificationsData: {},
      /** @type {Object.<string, StoredNotificationGroup>} */
      notificationGroups: {}
    }).then(function(items) {
      /** @type {NotificationDataEntry} */
      var notificationData =
          items.notificationsData[chromeNotificationId] ||
          {
            timestamp: Date.now(),
            combinedCard: []
          };

      var dismissalResult =
          cardSet.onDismissal(
              chromeNotificationId,
              notificationData,
              items.notificationGroups);

      for (var i = 0; i < dismissalResult.dismissals.length; i++) {
        /** @type {PendingDismissal} */
        var dismissal = {
          chromeNotificationId: chromeNotificationId,
          time: Date.now(),
          dismissalData: dismissalResult.dismissals[i]
        };
        items.pendingDismissals.push(dismissal);
      }

      items.notificationsData[chromeNotificationId] =
          dismissalResult.notificationData;

      chrome.storage.local.set(items);

      processPendingDismissals();
    });
  });
}

/**
 * Initializes the polling system to start fetching cards.
 */
function startPollingCards() {
  console.log('startPollingCards');
  // Create an update timer for a case when for some reason requesting
  // cards gets stuck.
  updateCardsAttempts.start(MAXIMUM_POLLING_PERIOD_SECONDS);

  requestCards();
}

/**
 * Stops all machinery in the polling system.
 */
function stopPollingCards() {
  console.log('stopPollingCards');
  updateCardsAttempts.stop();
  removeAllCards();
  // Mark the Google Now as disabled to start with checking the opt-in state
  // next time startPollingCards() is called.
  chrome.storage.local.set({googleNowEnabled: false});
}

/**
 * Initializes the event page on install or on browser startup.
 */
function initialize() {
  recordEvent(GoogleNowEvent.EXTENSION_START);
  onStateChange();
}

/**
 * Starts or stops the polling of cards.
 * @param {boolean} shouldPollCardsRequest true to start and
 *     false to stop polling cards.
 */
function setShouldPollCards(shouldPollCardsRequest) {
  updateCardsAttempts.isRunning(function(currentValue) {
    if (shouldPollCardsRequest != currentValue) {
      console.log('Action Taken setShouldPollCards=' + shouldPollCardsRequest);
      if (shouldPollCardsRequest)
        startPollingCards();
      else
        stopPollingCards();
    } else {
      console.log(
          'Action Ignored setShouldPollCards=' + shouldPollCardsRequest);
    }
  });
}

/**
 * Enables or disables the Google Now background permission.
 * @param {boolean} backgroundEnable true to run in the background.
 *     false to not run in the background.
 */
function setBackgroundEnable(backgroundEnable) {
  instrumented.permissions.contains({permissions: ['background']},
      function(hasPermission) {
        if (backgroundEnable != hasPermission) {
          console.log('Action Taken setBackgroundEnable=' + backgroundEnable);
          if (backgroundEnable)
            chrome.permissions.request({permissions: ['background']});
          else
            chrome.permissions.remove({permissions: ['background']});
        } else {
          console.log('Action Ignored setBackgroundEnable=' + backgroundEnable);
        }
      });
}

/**
 * Does the actual work of deciding what Google Now should do
 * based off of the current state of Chrome.
 * @param {boolean} signedIn true if the user is signed in.
 * @param {boolean} canEnableBackground true if
 *     the background permission can be requested.
 * @param {boolean} notificationEnabled true if
 *     Google Now for Chrome is allowed to show notifications.
 * @param {boolean} googleNowEnabled true if
 *     the Google Now is enabled for the user.
 */
function updateRunningState(
    signedIn,
    canEnableBackground,
    notificationEnabled,
    googleNowEnabled) {
  console.log(
      'State Update signedIn=' + signedIn + ' ' +
      'canEnableBackground=' + canEnableBackground + ' ' +
      'notificationEnabled=' + notificationEnabled + ' ' +
      'googleNowEnabled=' + googleNowEnabled);

  var shouldPollCards = false;
  var shouldSetBackground = false;

  if (signedIn && notificationEnabled) {
    if (canEnableBackground && googleNowEnabled)
      shouldSetBackground = true;

    shouldPollCards = true;
  } else {
    recordEvent(GoogleNowEvent.STOPPED);
  }

  console.log(
      'Requested Actions shouldSetBackground=' + shouldSetBackground + ' ' +
      'setShouldPollCards=' + shouldPollCards);

  setBackgroundEnable(shouldSetBackground);
  setShouldPollCards(shouldPollCards);
}

/**
 * Coordinates the behavior of Google Now for Chrome depending on
 * Chrome and extension state.
 */
function onStateChange() {
  tasks.add(STATE_CHANGED_TASK_NAME, function() {
    Promise.all([
        authenticationManager.isSignedIn(),
        canEnableBackground(),
        isNotificationsEnabled(),
        isGoogleNowEnabled()])
        .then(function(results) {
          updateRunningState.apply(null, results);
        });
  });
}

/**
 * Determines if background mode should be requested.
 * @return {Promise} A promise to determine if background can be enabled.
 */
function canEnableBackground() {
  return new Promise(function(resolve) {
    instrumented.metricsPrivate.getVariationParams(
        'GoogleNow',
        function(response) {
          resolve(!response || (response.canEnableBackground != 'false'));
        });
  });
}

/**
 * Checks if Google Now is enabled in the notifications center.
 * @return {Promise} A promise to determine if Google Now is enabled
 *     in the notifications center.
 */
function isNotificationsEnabled() {
  return new Promise(function(resolve) {
    instrumented.notifications.getPermissionLevel(function(level) {
      resolve(level == 'granted');
    });
  });
}

/**
 * Gets the previous Google Now opt-in state.
 * @return {Promise} A promise to determine the previous Google Now
 *     opt-in state.
 */
function isGoogleNowEnabled() {
  return fillFromChromeLocalStorage({googleNowEnabled: false})
      .then(function(items) {
        return items.googleNowEnabled;
      });
}

instrumented.runtime.onInstalled.addListener(function(details) {
  console.log('onInstalled ' + JSON.stringify(details));
  if (details.reason != 'chrome_update') {
    initialize();
  }
});

instrumented.runtime.onStartup.addListener(function() {
  console.log('onStartup');

  // Show notifications received by earlier polls. Doing this as early as
  // possible to reduce latency of showing first notifications. This mimics how
  // persistent notifications will work.
  tasks.add(SHOW_ON_START_TASK_NAME, function() {
    fillFromChromeLocalStorage({
      /** @type {Object.<string, StoredNotificationGroup>} */
      notificationGroups: {}
    }).then(function(items) {
      console.log('onStartup-get ' + JSON.stringify(items));

      combineAndShowNotificationCards(items.notificationGroups, function() {
        chrome.storage.local.set(items);
      });
    });
  });

  initialize();
});

authenticationManager.addListener(function() {
  console.log('signIn State Change');
  onStateChange();
});

instrumented.notifications.onClicked.addListener(
    function(chromeNotificationId) {
      chrome.metricsPrivate.recordUserAction('GoogleNow.MessageClicked');
      onNotificationClicked(chromeNotificationId, function(actionUrls) {
        return actionUrls && actionUrls.messageUrl;
      });
    });

instrumented.notifications.onButtonClicked.addListener(
    function(chromeNotificationId, buttonIndex) {
      chrome.metricsPrivate.recordUserAction(
          'GoogleNow.ButtonClicked' + buttonIndex);
      onNotificationClicked(chromeNotificationId, function(actionUrls) {
        var url = actionUrls.buttonUrls[buttonIndex];
        verify(url !== undefined, 'onButtonClicked: no url for a button');
        return url;
      });
    });

instrumented.notifications.onClosed.addListener(onNotificationClosed);

instrumented.notifications.onPermissionLevelChanged.addListener(
    function(permissionLevel) {
      console.log('Notifications permissionLevel Change');
      onStateChange();
    });

instrumented.notifications.onShowSettings.addListener(function() {
  openUrl(SETTINGS_URL);
});

instrumented.pushMessaging.onMessage.addListener(function(message) {
  // message.payload will be '' when the extension first starts.
  // Each time after signing in, we'll get latest payload for all channels.
  // So, we need to poll the server only when the payload is non-empty and has
  // changed.
  console.log('pushMessaging.onMessage ' + JSON.stringify(message));
  if (message.payload.indexOf('REQUEST_CARDS') == 0) {
    tasks.add(ON_PUSH_MESSAGE_START_TASK_NAME, function() {
      // Accept promise rejection on failure since it's safer to do nothing,
      // preventing polling the server when the payload really didn't change.
      fillFromChromeLocalStorage({
        lastPollNowPayloads: {},
        /** @type {Object.<string, StoredNotificationGroup>} */
        notificationGroups: {}
      }, PromiseRejection.ALLOW).then(function(items) {
        if (items.lastPollNowPayloads[message.subchannelId] !=
            message.payload) {
          items.lastPollNowPayloads[message.subchannelId] = message.payload;

          items.notificationGroups['PUSH' + message.subchannelId] = {
            cards: [],
            nextPollTime: Date.now()
          };

          chrome.storage.local.set({
            lastPollNowPayloads: items.lastPollNowPayloads,
            notificationGroups: items.notificationGroups
          });

          requestCards();
        }
      });
    });
  }
});

redpajama_set_name: RedPajamaGithub


text:
Pic: Grigoris Miliaresis
The Giant Tomb Next to the Tokyo Tower...Have You Noticed It?
January 6th, 2016	| Grigoris Miliaresis
Just one of the pairings responsible for the cliché about Japan being a land of contradictions | Photo by Roxanne Ready used under CC
My first experience with an actual kofun was rather awkward: I had spent a very tiring and extremely hot day at Zojoji Temple in Minato Ward, which is arguably one of the most important temples in Tokyo. Located almost exactly below the temple is Tokyo Tower—just one of the pairings responsible for the cliché about Japan being a land of contradictions—and at some point I went to the Shibakoen Park right next to the tower for a rest and a cold tea. The park is actually a big square with grass and benches around it and in the back I saw a hill with trees and everything and thought, "Well, that's a nice place to sit down and contemplate the wonderful contradictions of Tokyo" (clichés are clichés for a reason, after all). The hill wasn't very big, just a few steps to its top and up there there was another plateau with benches and a small shrine and a couple of monuments so I sat down and drank my tea and smoked my pipe and, well, contemplated and then got up to leave. This time I went down the other way (there are two paths) and as soon as I was down, I saw a sign that read "Maruyama Kofun". And of course my reaction was "What?! *That's* a kofun?! That's a friggin' hill!"
Get a Japanese cell phone number, with voice calling and 7GB of monthly data, quickly and easily—in English—through our partner Mobal. No contract required, and flexible payment options. Bonus—the majority of profits go to charity!
Maruyama Kofun: one of many keyhole-shaped tombs in Japan | Photo by Google Maps
The thing is, it *was* a kofun; actually it was (and still is: it's dated to the 5th century so if it has lasted 1,500 years it will probably last another few) the biggest of its kind in Tokyo. I've read that out of the 161,560 kofun in Japan over 200 are in Tokyo, but the only other that I know of is the Musashi Fuchu Kumano Jinja Kofun in Fuchu. The problem is that these structures are huge so the only way to understand that they are indeed a structure is if you see them from above (above like "helicopter", some of them are longer than the pyramids). Maruyama Kofun in Shibakoen is 557 ft (170 m) long and 26 ft (8 m) high, hence my thought that it was a hill, but the ones in Osaka's Sakai area (aka Mozu and Furuichi Kofungun) or the Saki Kofun in Nara are much bigger.
| Photo by Grigoris Miliaresis
OK, so we established that kofun are old and that they are huge. But what are they? Well, you could think of them as the Japanese version of the aforementioned pyramids: burial mounds of important people of early Japan (roughly from the 3rd to the 7th century)—and in this case "important" means people from the Yamato state, i.e. the beginnings of Japan's race and especially its Imperial Family (some of them are even believed to contain the remains of early emperors and empresses). Therefore it's no wonder that they are considered private property of the Imperial Family and fall under the jurisdiction of what is probably Japan's most powerful public service, the Kunaicho or Imperial Household Agency. Being responsible for the kofun, the Kunaicho has restricted the archaeologists' access to them; the official reason is to not disturb the dead but there's also some speculation about the possibility of the discovery of unwelcome ties to Korea (kofun have been found in Korea as well).
The most distinctive characteristic of kofun (the word, by the way means "ancient mound") is their shape: they look like keyholes with an oblong part and a round part—not all of them have this shape but the biggest do and the Maruyama Kofun does too. As expected, the oblong part is the entrance and the round part the funeral chamber and they were created by megaliths (i.e. huge stones: think Stonehenge). In some of them that have been excavated, funerary objects and human remains have been found: if you have seen the Haniwa terracotta clay figures that are among the oldest pieces of art in Japan, this is where they come from. Kofun were important enough to signify a whole era in Japanese history: its the period from 250 to roughly 540 CE and facts from that period are contained in Japan's earliest records, the "Kojiki" and the "Nihon Shoki".
So enough with the history lesson: should you go to the Maruyama Kofun? If you are going to Zojoji and/or the Tokyo Tower anyway, certainly! It makes up the most park-like part of the Shibakoen Park, it's nice and quiet and there are also a couple of interesting smaller shrines to see—the one on the kofun's top, at the place were the round part of the kofun meets its oblong part is Maruyama Zuishin Inari Daimyojin, complete with red torii gates and all. Also you can find a monument dedicated to Tadataka Ino (1745-1818), the man who created the first map of Japan using modern surveying techniques: it is right on the center of the plateau in the top of the kofun's round part. And yes, if you stop and think where you are and when it was built, you will get an opportunity to contemplate the contradictions that make up Japan—but in this case, it won't be a cliché.
Zozoji Temple | Photo by Grigoris Miliaresis
Name Maruyama Kofun| 丸山古墳
Pricing info Free
Address Shiba Park
Shibakoen
Shiba Park
Written by: Grigoris Miliaresis
Filed under: Things to do
Tokyo Escapes: A Winter Camper Van Adventure in Nagano
January 8th, 2021 | Lily Crossley-Baxter
Follow our Tokyo to Nagano road trip itinerary for winter travel ideas—plus tips on winter driving and camper van rentals in Japan.
Getting around Things to do
January 2021: 5 Events Not to Miss
December 29th, 2020 | Tokyo Cheapo
Start the new year with these festive events and ward off the winter-weather blues.
Your Japanese New Year: Traditions and Celebrations in Tokyo
December 21st, 2020 | Tiffany
Everything you need to know, including food, the first sunrise and where to celebrate.
Events Holidays Things to do
Low(er) Cost Lovin': The Cheapo's Guide to Tokyo Love Hotels
December 15th, 2020 | Selena Hoy
What they are, where to find them, how much they cost & how to book.
Places to stay Things to do
3-Day Tokyo to Kyoto Itinerary
December 14th, 2020 | Lily Crossley-Baxter
Our 3-day Tokyo to Kyoto itinerary breaks down the ancient capital by area (northwest, east & south Kyoto) so you can easily see all of the best sights.
10,000 Yen City Escape Challenge: Tokyo to Kanazawa
December 7th, 2020 | Lily Crossley-Baxter
How far can 10,000 yen take you beyond the borders of Tokyo? Follow our budget Tokyo to Kanazawa itinerary without missing all the best sights!
Top 25 Easy Day Trips from Tokyo
Add a few of these to the wander-list.
Japan's "Go To Event" Campaign: Everything You Need to Know
Find out how to save money on events & excursions, as part of the government's new COVID-19 economic recovery initiative.
Recommended hotels located nearby
More Tokyo Hotels
HOTEL MYSTAYS PREMIER Hamamatsucho
Hamamatsucho 0.9 km
from ¥9,333
HOTEL MYSTAYS Hamamatsucho
The Okura Tokyo
Toranomon 1.4 km
HOTEL MYSTAYS PREMIER Akasaka
Akasaka 1.9 km

redpajama_set_name: RedPajamaCommonCrawl


text:
layout: ../../layouts/Markdown.astro
title: January 2022 Xonotic Night
---

# Xonotic Night

<br />

![](https://www.cs.mun.ca/~csclub/assets/posters/2022/xonotic_jan_2022.jpg)


3 yellow squash--made into pancakes with eggs and cheese, which Johanna just gobbled up. Winner!
2 bunches tatsoi (one in the box, one taken from the swap box in exchange for a bunch of beets)--wilted with a Japanese-style onion, sesame, and tamari dressing to accompany Thai-style fried rice with shrimp. Yep, folks, I'm trying to reintroduce soy this week. Fingers crossed!
At the end of this stretch, I still have some red potatoes left, but that's it. The only item tossed out so far has been the frisee. Week 7 is almost over, but I'll save that for next time.


text:
Fucked Up
Tankcrimes
by Saby Reyes-Kulkarni
On the latest of the Toronto band's experimental zodiac EPs, Fucked Up continue to break and rebuild the definition of hardcore, venturing further out into realms of drone, ambient, and psychedelia.
Over the band's 16-year career, Fucked Up has alternated between more straight-ahead hardcore on its proper albums and a parallel lane of experimental releases named after the Chinese zodiac. That's a bit of an oversimplification, but the dichotomy between the two modes is still intact enough where it's fair to say Fucked Up has operated as two different bands. For perspective, compare how 2014's Glass Boys featured Tragically Hip frontman Gord Downie, while 2012's Year of the Tiger featured Jim Jarmusch.
Like last year's two-track, 45-minute release, This Mother Forever, Year of the Snake sees Fucked Up venturing further out into realms of drone, ambient, and psychedelia with shades of prog and fusion thrown in for good measure. In fact, the two releases work as companion pieces and make the most sense as a pair. Both feature epic-length songs in the 15-to-30-minute range. But it's their differences that reveal the full breadth of Fucked Up's ambitions.
Where This Mother Forever sticks to a uniform structure of slow building—its two songs are basically single ideas stretched about as far as they can go—Year of the Snake flows in a less linear fashion, its ideas materializing and de-materializing as if the band could have turned them into separate songs but chose instead to let them bleed into one another. Over its 24-minute span, the title track encompasses simplistic riffing that verges on stoner metal, pastoral new-age psychedelia (complete with pan flute, recorder, and prayer bowl), epic hard rock, and a violin section that lands convincingly close to post-rock. Each section has ample time to simmer and it never feels like the band sacrifices flow for the sake of experimentation.
About halfway through the title track, when Fucked Up are going full bore channeling 2112-era Rush at their most majestic, the song transitions so that a synth figure bubbles up from underneath. The two parts initially clash, like someone bumping loud music in a car not far away. For that moment, Year of the Snake sounds almost like a mashup, but it's short-lived. It also exemplifies how carefully considered all of the decisions on Year of the Snake are.
On the other hand, nothing feels especially careful about the voice of Damian Abraham, whose bark sounds so large and forceful it's like listening to King Kong next to an orchestra. That contrast gives Year of the Snake its distinct character. And as Fucked Up have delved into ever more delicate forms of expression, it's been interesting to see how the band addresses the discrepancy between Abraham's style and the rest of the instrumentation. Abraham doesn't appear on the second track, drummer Jonah Falco's six-minute instrumental "Passacaglia," and guitarist Mike Haliechuk composed the title track in a way that employs Abraham as an intermittent texture rather than a focal point. Which isn't to say that there isn't plenty of Abraham to go around, but only that if his voice was a dealbreaker for you before, Year of the Snake might be your best shot at appreciating everything that Fucked Up have to offer. (Guitarists Josh Zucker and Ben Cook do not appear on the EP.)
At the beginning of "Passacaglia," which functions as a kind of denouement for the title track, the guitars (played by Falco) contain echoes of Killing Joke's groundbreaking 1980 self-titled debut. As revolutionary as Killing Joke sounded at the time, they approached their music as if it was a given that punk's rules were there to be shattered. Likewise, even after decades' worth of relaxing boundaries, Fucked Up bastardize hardcore in a way that gives off the thrill of creative heresy. As a creative insurgency waged from within its own ranks, Year of the Snake makes the genre sound more pliable than ever.


text:
Q: Android Alertdialog crashes with "Unable to add window" exception, when calling it from another class as the main activity I have a problem with an AlertDialog in Android.
In a class "Misc" there is a method which creates an alertdialog.
public static void getAlert (Context context)
{
Builder builder = new AlertDialog.Builder(context);
builder.setTitle("Notruf absenden?");
builder.setMessage("automatischer Notruf in 60 sec.");
builder.setCancelable(true);
builder.setPositiveButton("Ja", new DialogInterface.OnClickListener() {
           public void onClick(DialogInterface dialog, int id) {
               callEmergency(context);
           }
       });
builder.setNegativeButton("Abbrechen", new DialogInterface.OnClickListener() {
           public void onClick(DialogInterface dialog, int id) {
              countdown.cancel();
           }
       });

 final AlertDialog alertBox = builder.create();
 alertBox.show();

 countdown = new CountDownTimer(60000, 1000)
 {
   public void onTick(long millisUntilFinished)
   {
     alertBox.setMessage("automatischer Notruf in "+ (millisUntilFinished/1000) + " sec.");
   }
   public void onFinish()
   {
   alertBox.cancel();
   callEmergency(context);
   }
}.start();

When I call the method in the main activity by typing:
Misc.getAlert(this)

it works, but in another class named Algorithm I call it in the same way:
Misc.getAlert(context)

But then there is this exception:
09-16 17:15:32.304: E/AndroidRuntime(19797): FATAL EXCEPTION: main
09-16 17:15:32.304: E/AndroidRuntime(19797): android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application
09-16 17:15:32.304: E/AndroidRuntime(19797):    at android.view.ViewRoot.setView(ViewRoot.java:536)
09-16 17:15:32.304: E/AndroidRuntime(19797):    at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:177)
09-16 17:15:32.304: E/AndroidRuntime(19797):    at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:91)
09-16 17:15:32.304: E/AndroidRuntime(19797):    at android.app.Dialog.show(Dialog.java:241)
09-16 17:15:32.304: E/AndroidRuntime(19797):    at de.smehner.Sturzerkennung.Misc.getAlert(Misc.java:220)
09-16 17:15:32.304: E/AndroidRuntime(19797):    at de.smehner.Sturzerkennung.Algorithm.fall(Algorithm.java:203)
09-16 17:15:32.304: E/AndroidRuntime(19797):    at de.smehner.Sturzerkennung.Algorithm.performNonGraphical(Algorithm.java:68)
09-16 17:15:32.304: E/AndroidRuntime(19797):    at de.smehner.Sturzerkennung.SensorValueReceiver.onSensorChanged(SensorValueReceiver.java:66)
09-16 17:15:32.304: E/AndroidRuntime(19797):    at android.hardware.SensorManager$ListenerDelegate$1.handleMessage(SensorManager.java:538)

I tried to set in getAlert
Builder builder = new AlertDialog.Builder(Sturzerkennung.this); // Sturzerkenung is the main activity

But then there is the error: "No enclosing instance of the type Sturzerkennung is accessible in scope"
context.getApplicationContext instead of Sturzerkennung.this didn't solve the problem either.
Has anybody an idea for this problem?

A: Problem solved..
The context in the Algorithm class was not from the Activity Sturzerkennung...
In Sturzerkennung I put
public static Context context;
...
context = this;

and then in Algorithm the parameter for getAlert is
Misc.getAlert(Sturzerkennung.context)

Now it works..

redpajama_set_name: RedPajamaStackExchange


text:
Q: SAS - Creating a Numbered Range List of character variables? I can create a Numbered Range List of numeric type, but not character type.
My code is similar to this:
DATA TestDataset;
    INPUT a1-a3 $;
    DATALINES;
    A   B   C
    ;
RUN;

This produces 3 variables - [a1], [a2] and [a3] as expected. However [a3] is character, but [a1] and [a2] are numeric. This leaves me with missing values as per the following table:
a1  a2  a3
.   .   C

The following code works, but obviously it does not scale nicely.
INPUT a1 $ a2 $ a3 $;

Am I missing something?

A: I came up with a macro solution:
%MACRO var_list_char (var_prefix, n);
    %LOCAL i ;

    %DO i = 1 %TO &n;
        &var_prefix&i$
    %END;
%MEND;

DATA TestDataset;
    INPUT %var_list_char (a, 3);

    DATALINES;
        A   B   C
    ;
RUN;

I wish I could find a way to do this without macros - I will keep digging for a bit and will update this post if I find more.  In the meantime, the above approach will definitely work.
UPDATE 1:  @carolinajay65's solution above is the correct non-macro approach.
UPDATE 2:  There is another way that I found.
DATA TestDataset;
    INPUT (a1-a3) ($);
    DATALINES;
    A   B   C
    ;
RUN;

More documentation of the language features supporting this technique can be found here, in the section labeled "How to Group Variables and Informats".

A: I believe you can use the hyphen notation on the length statement to get what you want. You really should use a length statement regardless..otherwise it defaults to $8.
DATA TestDataset;
 length a1-a3 $20;
 INPUT a1-a3 ;
 DATALINES;
 A   B   C
 ;
RUN;


text:
Q: Filter correlation matrix R I am a little bit stuck trying to extract the data from a correlation matrix, I'm looking to extract values that are higher than 0.8 and lower than 0.99 since I want to exclude the correlation of two stocks that are exactly 1.
this is my code:
  #Test

#load the packages
library(corrr)
library(ggplot2)
library(ggcorrplot)
library(dplyr)
library(quantmod)

#get the data needed
startdate <- "2001-01-03"

tickers <- c("MMM", "AA", "AXP", "T", "BAC")
portfolioprices <- NULL

for(ticker in tickers)
  portfolioprices <- cbind(portfolioprices, getSymbols(ticker, from=startdate, auto.assign=F)[,4])
colnames(portfolioprices) <- tickers

#check if there is nothing wrong with the data
print(portfolioprices)

#create a correlation matrix and plot it
correlations <- cor(as.matrix(portfolioprices))
correlations <- as.data.frame(correlations)
correlations
ggcorrplot(correlations, hc.order = TRUE, type = "lower",
           lab = TRUE)

as output I get:
           MMM          AA        AXP           T        BAC
MMM  1.0000000 -0.40325223  0.8772498  0.39019025 -0.2406640
AA  -0.4032522  1.00000000 -0.3029517  0.06347736  0.8383226
AXP  0.8772498 -0.30295171  1.0000000  0.41189453 -0.1304659
T    0.3901902  0.06347736  0.4118945  1.00000000 -0.1297723
BAC -0.2406640  0.83832262 -0.1304659 -0.12977234  1.0000000

This is the data frame where I would ideally extract the data that are positively correlated with a minimum value of 0.8.
I don't know if I am going about this completely the wrong way or not and any feedback is welcome!
EDIT:
Ideally I would prefer the data to come out like this:
          MMM          AA        AXP           T        BAC
MMM                          0.8772498
AA                                                  0.8383226
AXP  0.8772498
T
BAC               0.83832262

Where only the relevant positive values would get filtered.
Removing the non identical values.
MMM:AXP = 0.8772498
BAC:AA = 0.8382262
If this is possible at all.
Thank you very much in advance!

A: Simply add this line at the end of your code
correlations[correlations < 0.8 | correlations ==1] <- ""

Hope it helps!

A: Load in your data that makes it easy for others to reproduce your results:
dat <- structure(list(MMM = c(1, -0.4032522, 0.8772498, 0.3901902, -0.240664
), AA = c(-0.40325223, 1, -0.30295171, 0.06347736, 0.83832262
), AXP = c(0.8772498, -0.3029517, 1, 0.4118945, -0.1304659),
T = c(0.39019025, 0.06347736, 0.41189453, 1, -0.12977234),
BAC = c(-0.240664, 0.8383226, -0.1304659, -0.1297723, 1)),
.Names = c("MMM", "AA", "AXP", "T", "BAC"),
class = "data.frame",
row.names = c("MMM", "AA", "AXP", "T", "BAC"))

Now just get the index and use subsetting on the names of the matrix.
index <- which(abs(dat) > .80 & abs(dat) < 1, # your criteria
               arr.ind = T) # the result of the which function is now in rows & columns
cbind.data.frame(stock1 = rownames(dat)[index[,1]], # get the row name
                 stock2 = colnames(dat)[index[,2]]) # get the column name
#      stock1 stock2
#1    AXP    MMM
#2    BAC     AA
#3    MMM    AXP
#4     AA    BAC

**I've assumed you wanted high absolute correlation (for predictability) -- but if you only want stocks that move in tandem in the same direction, simply remove the abs functions.


Omron Electronics introduces a new line of compact vision sensors incorporating full-blown image processing capabilities in a palm-size footprint.
Low cost inspections are traditionally carried out using smart cameras or photoelectric sensors that have limited functionality and performance.
Conversely, higher grade vision sensors demand extensive configurations as well as the know-how for making good use of technology.
Type FQ Series vision sensors launched recently by Omron address these problems specifically, and are designed to simultaneously meet inspection reliability, ease of use and cost performance requirements.
The new vision sensors incorporate Omron's image processing technologies used in higher models, allowing reliable inspections for metal parts or shiny materials to be easily achieved without being affected by the installed environment.
Type FQ Series vision sensors integrate camera, lighting and core processor, eliminating special know-how or complicated configuration work for selecting optimum combination of peripheral devices.
Type FQ Series vision sensors also address applications in nine languages including German, Chinese, English and Japanese.


Firewire® PPS (Polyphenylene Sulfide) is a high-performance polymer that exhibits exceptional chemical resistance along with high thermal and mechanical properties. Widely known as one of the most chemically resistant thermoplastic materials available, PPS is insoluble in any known solvent under 200°C.
High-Temp Reels: We use reels made using PC/ABS and PC for our high-temp materials. This allows you to dry them out at higher temps once the filament absorbs moisture (which will happen to everyone eventually). The 250g and 500g reel are made using Polycarbonate (PC) and can be dried at 120°C if the filament gets wet. The 1kg reel is made using PC/ABS and can be safely dried at 115°C when it becomes necessary.


letsallplaygames : schlage deadbolt installation. locks lowes. commercial door accessories. how to install door closers. commercial door locks. parts of a door lock. installing pro armor doors. business door locks. door handle interior. home depot window locks.
Lili Cutlip, April 13th , 2017. Backyards: schlage deadbolt installation.
Tillie Mayville, April 13th , 2017. Backyards: locks lowes.
Jeanina Lagarde, April 13th , 2017. Backyards: commercial door accessories.
Dawna Putnam, April 13th , 2017. Backyards: how to install door closers.
Dawna Putnam, April 13th , 2017. Backyards: commercial door locks.
Joanna Ozuna, April 13th , 2017. Backyards: parts of a door lock.
Annelle Noe, April 13th , 2017. Backyards: installing pro armor doors.
Tonisha Maron, April 13th , 2017. Backyards: business door locks.
Sanda Crim, April 13th , 2017. Backyards: door handle interior.
Gregoria Huckaby, April 13th , 2017. Backyards: home depot window locks.


Copper. Copper is a reddish . When copper ends up in soil it strongly attaches to organic matter and minerals. . Due to the effects upon plants copper is a .
The Function of Soil Minerals and Trace Elements in Soil .
The Truth About Minerals in Nutritional Supplements . . with copper, iron, manganese, or other minerals . absorption of minerals. Plants actually have the .
copper ore mining mineral processing plant .
copper ore mining mineral processing plant . copper ore mining mineral processing plant manufacturers Processing And Refining The MineralScrap Gold Recovery Copper Refining Flotation Machine.
Copper is regulated by plants because it is an essential mineral. Too much copper can be toxic to plants as it inhibits photosynthesis.
copper beneficiation china | Ore plant,Benefication, Oct 23, 2013· copper beneficiation china Copper mineral processing plants - Copper Ore Beneficiation, Beneficiation process of copper ore Beneficiation .
Copper in health Normal absorption . to the consumption of plant foods in which copper . who consumed 30–60 mg/d of copper as a mineral .
Mineral Restoration of Your Garden Soil Part II | Terroir .
Copper is a plant immune . read Mineral Restoration of Your Garden Soil for the first part and Mineral . 2011 Terroir Seeds Growing Season- Intro and Updates .
mineral plant for copper - brothersofstmartin. mineral plant for copper antriksharalias. Mining & Quarry Plant Processing equipment for mineral .
mineral plants copper - greenwoodsclub. Copper mineral processing plants – Copper Ore Beneficiation Plant. Copper mineral processing plants . flow diagram for a typical copper smelting operation .
Nutrient Dense Foods and the Copper-Zinc Connection. . Discover how a zinc-copper mineral imbalance may be . with four times the absorption rate of their plant .
Tables showing elements recognized as essential components of plants, animals and man, . only for plant growth. Such mineral nutrient parameters for . Copper (Cu .
Ionic Ocean Minerals are non-synthetic plant growth minerals, and are the best way to ensure healthy, nutrient-dense foods to nourish you and your family.
Mineral Elements Required in Plant Nutrition. . Functions in plants - copper is a catalyst in . -Mo Required in smallest amounts of any mineral .
Mine plants and operations for commodities monitored by the National Minerals . which may indicate areas permissive of gold and copper mineral deposits. .
Copper is essential for normal growth and health. Thus, it is very important to include this mineral in balanced levels in your regular diet. It is also helpful for the protection of the skeletal, nervous, and cardiovascular systems. If you suffer from its deficiency, the normal and healthy growth .
Copper and Drinking Water from Private Wells | Wells .
Education and information about copper and drinking water from private wells, . plants, animals, and water. Since copper is easily shaped or molded, .
BP-69-W Disease Management Strategies - Purdue .
Disease Management Strategies Photo by Dan . taken to prevent copper from damaging the host plant. Copper sulfate . Mineral oils .


text:
The Obvious Star
The Casual Genius of Jenny Slate: 'Marcel the Shell,' 'Obvious Child,' and the Ghost of 'SNL'
How do you make everyone forget about cursing on 'SNL'? You stun critics in a hit indie film. And you charm them with the return of a talking seashell.
Jessica Chou/Redux
"I spend so much time hoping things for myself," Jenny Slate tells me, near the end of an interview that covers everything from her time on Saturday Night Live, her quietly explosive performance in the indie "abortion comedy" Obvious Child, and a teeny-tiny talking conch shell with a googly eye and jazzy pink sneakers (who may just have changed her life).
"I hope that the restaurant I go to will have buffalo chicken fingers," she continues. "I hope that one day I can work with Matt Damon. I have big and little dreams and they're all equally important to me. A life without buffalo chicken fingers, I don't know if I would want that life. Even if it meant I got to work with Matt Damon. Everything has its worth."
As the most prolific, exciting, and game-changing year of her career draws to a close, it's becoming ever-more clear that Slate might soon find her hopes fulfilled. She might actually get to have her Damon-cake and eat her buffalo chicken fingers, too.
The occasion of our conversation is the upcoming release of the follow-up to her New York Times best-selling children's book Marcel the Shell With Shoes On. The next adventure from her precocious creation, The Most Surprised I've Ever Been, recounts a dramatic day in the life of our thimble-size hero, who we first met in 2010 when Slate and her husband, Dean Fleischer-Camp, put together a stop-motion video introducing the tiny seashell character.
The earnestness of the clip, which finds Marcel the Shell waxing about his small-scale life with grand sincerity—"Guess what I wear as a hat? Lentil;" "One time I nibbled on a piece of cheese and my cholesterol went to 900"—helped it go instantly viral, with upwards of 23.5 million viewers cooing at Marcel's irresistible blend of Borscht Belt one-liners and casual confidence.
Much has happened since Marcel and his dog on a leash (actually a hair tied to a piece of lint that he drags around) walked into Slate's life three years ago: scene-stealing arcs on Parks and Recreation and House of Lies, a starring role on the FX comedy Married, and a transcendent performance in Obvious Child that's gotten Slate marked as a darkhorse Oscar contender. And in a strange way, Marcel, with all of his stuttering, sly gregariousness, and optimism, may have actually made all of this possible.
"At the time I was just trying to be free and creative, because I felt like that was something that was being drained from my life and I didn't like that," Slate says about conceiving her shell. "I wanted to find a way to address it without it being a huge fight or a statement. I wanted to somehow plug into it with gentleness and love, because those are things I feel comfortable with. I don't always feel comfortable being outwardly aggressive."
She doesn't mention it explicitly—because it's already mentioned exhaustively when Slate's career is brought into conversation—but the period of her life she's referring to is just after she was fired from Saturday Night Live.
Slate spent exactly one season, from 2009 to 2010, in Studio 8H. On her first episode live from New York, she accidentally said the f-word. Despite performing in a respectable amount of sketches for a SNL freshman throughout the season, her contract was not renewed.
That August, she and Camp co-wrote the first Marcel the Shell video.
We begin talking about the directness and casual sweetness that belies Marcel's remarkable self-assured nature, despite living in a world that could, quite literally, make him feel small.
"I think it comes from me during that time when I was trying to figure out how to speak that feeling," she says. "How you say that you like yourself when you also feel small? Reconciling those two, of course they can exist at once. You don't have to be in the brightest, shiniest state of being an individual to feel like you're exceptional."
Slate found Marcel's voice, and by extension her own, thanks to the quiet privacy with which he was conceived in with her husband. And when Marcel gives his charming quotes, which double as unintentional life affirmations ("Sometimes people say my head is too big for my body and then I say compared to what?"), it's in the intimate confidence of the person who is conducting his fictional interview.
"It's momentary expression," Slate says. "It's not a parade of self-confidence. Sometimes I think kids and adults forget that's enough."
That struggle is a big part of her character's journey in Obvious Child, too.
Bracingly honest, unexpectedly touching, and gloriously matter-of-fact, Obvious Child was released in June, a teeny-tiny indie that garnered big-scale attention thanks to its frank handling of a delicate issue and Slate's star-is-born performance as its lead.
Unable to manage a suffocating amount of self-loathing after getting dumped, Donna (Slate's character) has a one night stand, from which she gets pregnant and decides to have an abortion. In the time period between the decision and her scheduled procedure, the father of the baby charms her with all the hipster swooning of a romantic comedy set in Brooklyn. Donna has to convince herself that she's deserving of his love, even while deciding not to keep their child.
The dexterity with which Slate danced between Donna's quirky, pixie-like comedic tendencies and the complexities of the film's grounded, tenderer dramatic moments earned the actress raves. In turn Slate did a lot of press leading up to its release.
Scan the profiles and interviews, though, and you'll see the same talking points hit upon, time after time. There's its reductive and not-all-that accurate branding of Obvious Child as an "abortion comedy." ("It has an abortion in it, but it's not an abortion movie," Slate says. "I just think of it as a modern romcom.") There's her stepping out into a leading role. There's her firing from SNL.
So instead, we begin discussing things she wished she had been asked about, that she feels were glossed over and reporters checked their boxes while she was on the film's press marathon.
"We put a great amount of thought into the look of Donna, a woman you wanted to believe was in the real world and was both a mess and kind of catch" she says. "For me, it was really special to be able to look that way—to be able to wear no makeup and not have reality show curling-ironed and hair-sprayed hair, which is what I'm normally given."
But she takes another beat before talking about how surprised she was by the number of times she was asked the same questions, the answers to which could be found easily by Googling, when everyone was given the opportunity to ask something new and different about a rich and complicated film.
"I became very weary of the amount of times I was asked about Saturday Night Live in the exact same way," she says. "And I get why people ask about it but I don't understand why they ask about it in the same way."
By the time the press tour had neared the end with an appearance on NPR's Fresh Air with Terry Gross, "I was like, 'I don't mean to be disrespectful, but I've said everything I could say,'" she says. "And it really embarrasses me to be on four different TV shows, two cartoons, have this movie, and be a New York Times best-selling author and continually have to talk about one time I said a swear."
It's abundantly clear that Slate doesn't begrudge the fascination over the episode, or wish that she could bury that period of her life into the recesses of her memory. But there's also confusion as to why the dialogue hasn't progressed beyond that, even as her career has.
"What if Seth Meyers had been tuning in? Or Amy Poehler? Or Kristin Wiig?" she says. "Any of those people who I love and respect and want to work with again, and they heard me talking about this like I was victim or that it was the most important thing that ever happened to me, when I have done all this other stuff?"
Other aspects of the Obvious Child press onslaught were more than welcome by her, specifically the opportunity to become an accidental activist for issues she believes in.
"When we went to on the road, right before we were about to do it I said to [director] Gillian Robespierre, 'I know how I feel. I know how I feel about fighting for my rights as a human and my reproductive rights and I don't want anyone to tell me what to do with my body. But I'm not an expert on abortion, and I'm afraid that I'm going to say something stupid. But I feel more than ever that I want to talk about this,'" Slate remembers. "And she was like, 'I think it's cool to be an activist in your way.'"
That's the value of the film, she thinks, and part of why it became so well-received.
"There should be imagination and flexibility and openness, and maybe even a little bit of humor in the discussion," she says." Because we have to create an environment that's a little bit hospitable. If it's just two camps standing on opposite sides of the field hurling arrows at each other, I don't understand how that will lead to progress. Even if I'm a part of a group of silly, fun people who go in the middle of that field and just sit down and start to talk, I'd want to be in that group."
Thanks to the reception to Obvious Child—and not to mention the impressive roster of TV series she is currently starring in—Slate is also finding herself as part of another group, of "actresses," perhaps instead of, as she puts it, "a floating comedian who pops in and out of shows."
"It's nice to feel like I'm on the road to being an American movie actress," Slate says. "But whatever the road is it does feel new, and it does feel good, and it feels like I made it for myself with people I know and love."


text:
EU Cohesion policy: Commission announces the winners of the REGIOSTARS Awards 2021
Press release2 December 2021Representation in Cyprus
Today, the European Commission has announced the winners of the 2021 edition of the REGIOSTARS Awards that reward the best Cohesion policy projects in the whole EU.
This year's REGIOSTARS competition received a record 214 applications and 14,156 people voted in the public choice's category.
Commissioner for Cohesion and Reforms, Elisa Ferreira, commented: "My warm congratulations to the 10 winners of the EU Cohesion policy projects of 2021. They are role models for everyone who wishes to better the life of people with the use of EU funds. I hope they will inspire many others across the continent. For sure, with REGIOSTARS we have learnt that excellence and innovation are everywhere in Europe. You just need to look for them and highlight them as they deserve. We will keep looking for them and we will keep supporting them."
The awards cover five categories and a public choice prize:
For 'SMART Europe: Increasing the competitiveness of local businesses in a digital world' (1st category) the award went to Integration 3D metal printing from Belgium. The project supports the implementation of the 3D metal printing technology in small and medium-sized companies (SMEs) through a very innovative integrated approach to knowledge and technology. The idea is easily transferable to other contexts with industrial tradition.
For 'GREEN Europe: Green and resilient communities in urban and rural setting' (2nd category) the award was given to ICCARUS (Gent knapt op) for providing a unique housing renovation financial scheme for 100 vulnerable homeowners in Ghent, Belgium. This project has a strong social component and is easily transferable, both to other places, including to less developed regions, and other sector.
The award for 'FAIR Europe: Fostering inclusion and anti-discrimination' (3rd category) went to TREE - Training for integrating Refugees in the Euregion, which facilitates the integration of refugees through the development of a needs-based training programme for practitioners working with refugees and migrants, and a qualification programme for social interpreters. The winners are from the Netherlands, Germany, and Belgium.
Travelling Solidary Cannery received the award in the 4th category, 'URBAN Europe: Promoting green, sustainable and circular food systems in functional urban areas'. The project provides the disadvantaged access to healthy and fair food at affordable prices all year round. At the same time, it develops a new range of professions centred on the production, valorisation, logistics and marketing of local products, but also of unsold products from supermarkets or surplus harvests. The winner is from Belgium.
Under the topic of the year: 'Enhancing green mobility in the regions - European Year of Rail 2021' (5th category) the winner is North-West Multimodal Transport Hub from the United Kingdom and Ireland. This project provides an increased rail capacity, a strong balance of services for cycling, public transport and active travel users in Londonderry and an encouraging modal shift from car to public transport.
Finally, the 'Public Choice Award' goes to BEGIN, a project that unites cities, citizens, and stakeholders through the co-creation of blue and green infrastructure projects in 10 cities in the Netherlands, the United Kingdom, Sweden, Belgium, Norway and Germany. The project aims at reducing flood risk by up to 30% and improving livability. Other public favorites were Balkan Road (under the 1st category), Baltazar (3rd category), Digital Farming Specialist (4th category) and Transporte A Pedido (5th category).
The REGIOSTARS Awards are the yearly competition organised by the Commission since 2008: it has become Europe's label of excellence for EU-funded projects under Cohesion policy that demonstrate innovative and inclusive approaches to regional development.
Each year, hundreds of projects compete in five categories: 'Smart Europe', 'Green Europe', 'Fair Europe', 'Urban Europe', and the topic of the year. The public can participate by voting for their favourite project among all finalists for the public choice award.
By bringing about solutions to common challenges and tapping into the biggest opportunities, the REGIOSTARS have inspired regions to deliver evermore-impactful EU Cohesion policy.
REGIOSTARS Awards
REGIOSTARS 2021 Finalists


text:
DR Congo: UN deploys nearly all its 17,500 peacekeepers to strife-torn east
More than 90 per cent of the nearly 17,500 United Nations peacekeepers in the Democratic Republic of the Congo (DRC) are now deployed in the strife-torn east of the vast country, including over 6,000 in North Kivu province which has seen an upsurge of fighting between various rebels groups and the national army.
UN Photo/Yosuke Yamahata
Marking Hiroshima anniversary, Ban sees hope for nuclear-free future
Commemorating the 63rd anniversary of the first-ever atomic bomb attack, Secretary-General Ban Ki-moon today expressed optimism for a world free of nuclear weapons.
Security Council stresses need for peaceful end to dispute over Abyei, Sudan
The Security Council today welcomed the recent joint plan unveiled by the Sudanese Government of National Unity's main parties to resolve their dispute over the situation in the oil-rich area around Abyei, which lies close to the boundary between the north and south of the country.
Sudan: Ban welcomes agreement to resolve dispute over Abyei
Secretary-General Ban Ki-moon today welcomed an agreement to resolve a dispute over the town of Abyei, which lies in an oil-rich area close to the boundary between northern and southern Sudan, and has recently been the scene of violent clashes that have displaced as many as 50,000 people.
Ban Ki-moon hails Nobel laureates Al Gore, Intergovernmental Panel on Climate Change
United Nations Secretary-General Ban Ki-moon today hailed the awarding of the 2007 Nobel Peace Prize to Al Gore and the Intergovernmental Panel on Climate Change (IPCC) and urged governments to build on the momentum they have generated by adopting a new set of binding commitments to contain greenhouse gas emissions.
Accepting Nobel Prize, UN nuclear agency chief lays out vision for peace
Accepting this year's Nobel Peace Prize, United Nations International Atomic Energy Agency (IAEA) Director-General Mohamed ElBaradei has laid out a three-point programme to save the world from self-destruction by ensuring that nuclear weapons have no place in the collective conscience and no role in security.
UN nuclear agency agrees to use Nobel Peace Prize money to developing countries
The United Nations International Atomic Energy Agency (IAEA), this year's Nobel peace Prize co-laureate, has agreed to use its share of the award money to funding the needs of developing countries in the peaceful application of nuclear energy and, especially in connection with human health and food production.
Annan praises UN nuclear watchdog agency on winning Nobel Peace prize
Hailing their "vital mission" in stemming the proliferation of nuclear weapons, Secretary-General Kofi Annan today lauded the United Nations International Atomic Energy Agency (IAEA) and its Director General, Mohamed ElBaradei, on winning the 2005 Nobel Peace Prize, the latest in a long series of UN laureates.
UN Photo/Mitsuo Matsushige
UN renews call for total nuclear ban on 60th anniversary of bombing of Japan
The United Nations is marking the sombre 60th anniversary of the atomic bombing of Hiroshima and Nagasaki with renewed calls for a nuclear-weapons-free world, and for all States to prevent the spread of such weapons by reaffirming their commitment to international nuclear non-proliferation treaties and accords.
Condemning violence in Kosovo, Security Council demands return to rule of law
Denouncing "the large-scale inter-ethnic violence" that has led to the deaths of at least 31 people in Kosovo since yesterday, the United Nations Security Council today called for the province's authorities to ensure that the rule of law is maintained, all ethnic communities feel properly secure and the perpetrators of crimes are brought to justice.


text:
Daily DriveThru: Nissan partners with Lucasfilm for 'Rogue One' campaign, GM cries foul in Texas lawsuit and more
Nissan's 'Rogue One' campaign, GM cries foul in court , and more
BY Kyle Campbell
Tuesday, August 23, 2016, 7:30 AM
Lucasfilm announced that it is teaming up Duracell, General Mills, Gillette, Nissan and Verizon for the launch of an extensive global promotional campaign in support of "Rogue One: A Star Wars Story," which opens on December 16.
(Nissan)
From Texas lawsuits, European shift cuts and a safety recall for a certain South Korean automaker, today's news features more cars coming off the road than getting on it. At least Toyota is doing its part by introducing a couple new(-ish) models for its flagship brand.
Before we get into any of that, first let's take a trip to a galaxy far, far away where five powerful federations have joined forces in a campaign for intergalactic domination.
This is your Tuesday episode of the Daily Drive-Thru. May the Force be with you.
Nissan goes Rogue (One) for Star Wars promotion
You can expect to see many ads featuring the Nissan Rogue and the upcoming film "Rogue One: A Star Wars Story."
It's a marketing match for the galactic ages: Nissan, makers of the popular Rogue SUV, will partner with Lucasfilm for the promotion of the upcoming film "Rogue One: A Star Wars Story." Lucasfilm, which is owned by The Walt Disney Company, appears to have dropped Dodge as a partner after teaming up with the Fiat Chrysler subsidiary to promote last year's highly-anticipated premiere of "Star Wars Episode VII: The Force Awakens." Considering the Rogue has been Nissan's second-best-selling nameplate this year after the Altima, not even the powers of the Force could have kept these two brands apart.
Nissan joins Duracell, General Mills, Gillette and Verizon as co-sponsors, meaning you can expect to see a heavy rotation of commercials and an array of out-of-home ads for all five companies, especially as we approach the film's December 16 premiere date. The official announcement that Nissan would be joining the campaign mentioned the class-leading sales of the Leaf, Nissan's all-electric offering, so you can expect that to be featured prominently in advertisements as well.
Source: Nissan
GM accuses family of falsifying evidence for ignition switch lawsuit
General Motors is hoping a Texas judge will throw out a lawsuit filed against it for installing a faulty ignition switch in a vehicle that was involved in fatal accident in 2011.
(Paul Sancya/AP)
General Motors accused a Texas family and its lawyers of falsifying evidence for a lawsuit they filed against the carmaker over a faulty ignition switch in their 2007 Saturn Sky. GM said the plaintiffs, Zachary Stevens and his family, produced a key as evidence, claiming it belonged to the vehicle Stevens was driving when he was involved in a crash in 2011, when in fact, it did not. GM is asking the judge presiding over the case to throw out the suit entirely or inform jurors of the false statements.
The key shown in court was on a three-ringed chain containing several other items, including a model of the Eifel Tower and a gym membership card. GM maintains that the keys originally shown contained just a few items and the additional weight was added to give credence to the family's claim that an issue with the ignition switch was to blame for the crash, not Stevens' driving. When GM recalled 2.6 million cars in 2014 for containing faulty ignition switches, it warned that added weight to key chains could cause the keys to slip out of position, thus shutting off vital safety features in the cars, such as power steering.
Stevens was originally charged with manslaughter because the crash killed the driver of another vehicle, but that charge was dropped after GM issued the recall. The Stevens family is seeking compensation for medical bills and legal fees incurred after the accident. This is the first of 20 such lawsuits filed against GM in Texas state court.
Scion FR-S, iM officially reborn to Toyota brand
The 2017 Toyota 86 will start at $26,255 when equipped with a six-speed manual transmission.
(Toyota)
The Scion FR-S and iM are officially dead, gone and have now been replaced by vehicles with Toyota nameplates. Toyota stated its intention of keeping these models the moment it announced its plan to contract the Scion brand, but Monday it officially released pricing, specs and photos of the Toyota 86 and the Corolla iM.
The FR-S is reborn as the 86 (a nameplate used by Toyota in other global markets) and features an aggressive design for the 2017 model year, with a wide, low stance, large center air intake and sharp LED headlights and running lights. The 86 will debut later this month and start at $26,255 with a six-speed manual transmission or $26,975 for a six-speed automatic, an increase of $950 and $570, respectively, from the previous Scion incarnations.
The iM, meanwhile, is back as a hatchback trim for the Toyota Corolla. Set to debut in September alongside other new five-door hatchback offerings from Chevrolet and Honda, the iM will have its work cut out for it, but a base price of $18,750 for the six-speed manual (up just $290 from last year's iM) should make it competitive.
Source: Toyota
In wake of Brexit, General Motors to cut hours at German plant
Nearly 6,000 factory workers at GM's two German plants could see shift cuts in the near future.
(Sean Gallup/Getty Images)
General Motors will cut shifts at two plants operated by its European subsidiary Opel in Germany as it downsizes in the wake of the United Kingdom's vote to leave the European Union. GM expects sales in the U.K. to fall between 5 and 10 percent once it officially leaves the E.U.'s free trade zone.
GM will cut hours at its Rüsselsheim plant, where the Opel/Vauxhall Insignia is made as well as at its Eisenach plant where Opel/Vauxhall Corsa and Adam cars are made. The plants employ 4,000 and 1,850 workers, respectively. Before the economic uncertainty of today's post-Brexit world, Europe had not been a very profitable place for General Motors; the Detroit automaker hasn't broken even in the market in more than 15.
Source: The Detroit News
Hyundai launches Elantra recall for faulty brake pedal stoppers
Next month, 64,500 Hyundai Elantra sedans from the 2013 model year will be recalled to address an issue with their brake pedal stopper pads.
(Hyundai)
Hyundai will recall 64,500 Elantra sedans from the 2013 model year next month to replace faulty brake pedal stopper pads that deteriorate over time and leave the vehicles vulnerable to accidents. The pedal stopper pads can cause the brake lights to stay on and allow the vehicle to be shifted out of park without pressing the brake, according to documents obtained Automotive News.
The Korean automaker is not aware of any accidents or injuries related to this issue, but it has already conducted a similar recall for Hyundai Sonatas with the same issue. The affected Elantras were made between December 2012 and April 2013 at a plant in South Korea as well as the company's Alabama assembly plant. The recall will begin on September 30.
Source: Automotive News
Check the Daily Drive-Thru every weekday morning to get the latest on the most important news and trends in the automotive world.
You can find Monday's installment of the Drive-Thru here and view the rest of our archives here.
Got a news tip or a comment? You can find me on Twitter where I go by @ByKyleCampbell or email me at kcampbell@nydailynews.com.
daily drive thru


CVS ~ FREE Flavor Chews Antacids – 10 FREE boxes w/NO coupon needed!
Attention CVS shoppers! Â For the month of April you can purchase one box of CVS Flavor Chews at $1.49 Â and get $1.49 ECBs. Â You can redeem this deal 10 times! Â It's time to stock up on antacids!!
CVS Flavor Chews Antacids (12 ct), $1.49 ea.
Below are CVS deals for the week of 2/9.
$0.99 each after coupon and ECBs!
$0.24 each after coupon and ECBs!
$0.69 each wyb 2 after coupon and ECBs!
$1.49 each after coupon and ECBs!
Below are CVS deals for the week of 1/12.
Two FREE after coupon and ECBs!
$1 each wyb 2 after coupon and ECBs!
$0.66 each wyb 3 after coupon!
$0.75 each wyb 2 after coupon, CRT and ECBs!
Here's a new $2/2 Right Guard Total Defense or Xtreme Deodorant or Personal Care Product printable coupon that will help make a great deal at CVS next week. Starting Sunday (4/28) CVS will be offering $1.50 Extra Care Bucks when you buy two participating Right Guard products. Combine this offer with your coupon to pick up two bottles of body wash for as low as $1.25 each!
$1.25 each after coupon and ECBs!
FREE Alcohol Prep Swabs at CVS!
Visit CVS to print your in-store coupon for a FREE box of Sterile Alcohol Prep Swabs (a $2.59 value). Your coupon is valid in-store only and is valid through 4/30/13.
Carmex Lip Care Products, $1.67 ea.
$1.68 wyb 4 ($0.42 each) after coupons and ECBs!


text:
The East German Republic Day Parade of 1974 was a military parade of the National People's Army on Karl-Marx-Allee in East Berlin on 7 October 1974, the GDR's Republic Day, commemorating the 25th anniversary of the establishment of East Germany. This parade was held in the presence of Soviet Leader Leonid Brezhnev.

Gallery

See also

25 Jahre DDR - Ehrenparade der NVA - 1974
Nationale Volksarmee parade rehearsal 1974
Public holidays in Germany

References

Military parades in East Germany
1974 in East Germany
October 1974 events in Europe

redpajama_set_name: RedPajamaWikipedia


You might have heard the saying that "breakfast is one of the most important meals of the day" and it couldn't be truer! A good breakfast is a perfect way to give your body what it needs to kick start your metabolism. Here are some favourite healthy breakfast ideas to give you lots of energy to start your day feeling fantastic!
Not only are eggs really high in protein, they are also very filling. If you seem to have sugar cravings in the day, try having eggs for breakfast. There so many options when it comes to preparing them, but here are two healthy breakfast ideas.
Boiled Egg with vegemite soldiers. This is a favourite Australian breakfast. Not only is it quick to prepare but it's fun to eat. All you need to do is soft boil a few eggs. While these are cooking, toast a slice or two of sourdough bread. Give your toast a quick spread of vegemite and cut into 6-8 rectangles. When your egg is ready, pop it in an egg cup and knock off the top. Use your dippers to get into that lovely soft yolk.
Omelettes are perfect for using up what you have in the fridge. A favourite omellete is mushroom, spinach, tomatoes, and feta but you add anything you might have laying around. An omelette only takes a few minutes which is perfect for a quick breakfast. Try serving it with some avocado and chili to really amp up the flavours.
If you're not used to having breakfast, smoothies are a great way to ease yourself into it. All the good stuff in a smoothie will keep you energized and feeling full until lunchtime. A strawberry banana smoothie is a classic, but you can also add extra ingredients like avocado or chia seeds to make it healthier.
You can also pop ingredients in a snap lock bag and keep them in the freezer for when you're in a rush! You can also use pre-prepped smoothie mixes like Garden of Life's RAW Fit for an easy, nutrition-packed breakfast.
If your morning are ultra-busy, prep your smoothie the day/night before. That way all you need to do is whiz it up before you eating. If you leave home early, smoothies are a perfect meal as you can put it in a to-go cup and take it with you.
Coconut yogurt is a perfect alternative to yogurt. If you want to try something different or have trouble with dairy, this is perfect for you. You can pick it up from most supermarkets as well as health food shops or make it yourself at home.
Coconut yogurt is perfect with fresh fruit, homemade granola, and honey. Otherwise pair it with some nuts, seeds and goji berries for a superfood start to the day!
Some of our favourite seeds and nuts include almonds, sunflower seeds, and linseed. This blend otherwise known as LSA can help with your digestive system, skin, liver and immune system. It is also rich in essential fatty acids and full of fibre.
Oatmeal for breakfast is incredibly good for you, with a good dose of fibre and some important minerals such as magnesium, phosphorus, zinc, and more!
Berries and oats are always a good combo, but go ahead and switch in any other seasonal fruits that you enjoy. If you looking for something a little more exciting with your oats try baked oats bars as they are perfect for a busy morning. A delicious flavour is baked apple pie. They only take an hour to make and you will be prepped for a whole week worth of breakfasts.
You will notice your seeds starting to swell and become jelly-like consistency. This chia pudding lasts well in the fridge, so it is perfect to make ahead of time and have at any time of the day. Low Carb on the Go has some great ideas for chia seed puddings, as well as ways to prep them ahead of time and take them with you.
So as you can see it is easy start your day off with a good healthy meal. With just a little bit of forward thinking and awareness, you can easily create a repertoire of healthy breakfast ideas you will love to eat.
What are your favourite healthy breakfast ideas?
Brittnay makes her home in Melbourne, Australia. She likes keeping her family healthy and exploring Australia in her campervan. She's also a long-term house sitter. Drop by her blog, The Nut Butter Hub, for more tasty recipes and travel stories.