<commit_before>const {app, BrowserWindow, Notification, ipcMain} = require('electron');
const urlLib = require('url');
const http = require('http');
const path = require('path');
const storage = require('electron-json-storage');
const settings = require('electron-settings');
const CssInjector = require('../js/css-injector');
const {download} = require('electron-dl');
const Lyrics = require('../js/lib/lyrics');
const fs = require('fs-extra');
const timeFormat = require('hh-mm-ss');
const UpdateController = require('./update-controller');

const playerUrl = 'http://www.xiami.com/play';
const playlistUrl = 'http://www.xiami.com/song/playlist';
const getLyricUrl = 'http://img.xiami.net/lyric/';

const language = settings.get('language', 'en');
const Locale = language === 'en' ? require('../locale/locale_en') : require('../locale/locale_sc');

class XiamiPlayer {
  constructor(lyricsController) {
    this.lyricsController = lyricsController;
    this.init();
  }

  init() {
    this.lyrics = new Lyrics('');
    const customLayout = settings.get('customLayout', 'default');

    if (customLayout === 'mini') {
      this.window = new BrowserWindow({
        show: false,
        width: 520,
        height: 160,
        frame: false,
        autoHideMenuBar: true,
        fullscreenable: false,
        resizable: false,
        webPreferences: {
          javascript: true,
          plugins: true,
          webSecurity: false,
          nodeIntegration: false,
          preload: path.join(__dirname, 'preload.js')
        }
      });
    } else {
      if (process.platform === 'darwin') {
        this.window = new BrowserWindow({
          show: false, width: 1000, height: 670, titleBarStyle: 'hiddenInset',
          webPreferences: {
            javascript: true,
            plugins: true,
            webSecurity: false,
            nodeIntegration: false,
            preload: path.join(__dirname, 'preload.js')
          }
        });
      } else {
        this.window = new BrowserWindow({
          show: false, width: 1000, height: 670, frame: true, autoHideMenuBar: true,
          webPreferences: {
            javascript: true,
            plugins: true,
            webSecurity: false,
            nodeIntegration: false,
            preload: path.join(__dirname, 'preload.js')
          }
        });
      }
    }

    // load xiami player page.
    this.window.loadURL(playerUrl);

    // inject the custom layout.
    this.window.webContents.on('dom-ready', () => {

      this.window.webContents.insertCSS(CssInjector.main);

      if (process.platform == 'darwin') {
        this.window.webContents.insertCSS(CssInjector.macos);
      }

      switch (customLayout) {
        case 'hideSidebar':
          this.window.webContents.insertCSS(CssInjector.hideSidebar);
          break;
        case 'hideLyrics':
          this.window.webContents.insertCSS(CssInjector.hideLyrics);
          break;
        case 'songListOnly':
          this.window.webContents.insertCSS(CssInjector.songListOnly);
          break;
        case 'mini':
          this.window.webContents.insertCSS(CssInjector.mini);
          break;
        default:
          // using the default layout from the xiami play
          break;
      }

      this.window.show();

      // check update
      new UpdateController().checkUpdate();
    });

    // triggering when user try to close the play window.
    this.window.on('close', (e) => {
      if (this.window.isVisible()) {
        e.preventDefault();
        this.window.hide();
      }
    });

    // triggering after the play window closed.
    this.window.on('closed', () => {
      ipcMain.removeAllListeners('playtime');
      this.window = null;
    });

    // intercept the ajax call response
    this.window.webContents.on('did-get-response-details', ((event, status, newURL, originalURL) => this.handleResponse(originalURL)));

    ipcMain.on('playtime', (event, value) => {
      const timeline = this.lyrics.select(timeFormat.toS(value));
      if (timeline !== this.previousTime) {
        this.previousTime = timeline;
        if (timeline >= 0) {
          let lyric = this.lyrics.getLyric(timeline);
          if (lyric) {
            let text = lyric.text;
            this.lyricsController.window.webContents.send('lyricsChange', this.prettyLyric(text));
          }
        } else {
          this.lyricsController.window.webContents.send('lyricsChange', '这首没有歌词 (-_-!)');
        }
      }
    });
  }

  // display and focus the player window.
  show() {
    this.window.show();
    this.window.focus();
  }

  // return a boolean to indicate if the window is visible or not
  isVisible() {
    return this.window.isVisible();
  }

  pause() {
    this.window.webContents.executeJavaScript("document.querySelector('.pause-btn').dispatchEvent(new MouseEvent('click'));");
  }

  play() {
    this.window.webContents.executeJavaScript("document.querySelector('.play-btn').dispatchEvent(new MouseEvent('click'));");
  }

  next() {
    this.window.webContents.executeJavaScript("document.querySelector('.next-btn').dispatchEvent(new MouseEvent('click'));");
  }

  previous() {
    this.window.webContents.executeJavaScript("document.querySelector('.prev-btn').dispatchEvent(new MouseEvent('click'));");
  }

  /**
   * Add the listener to monitor the play time.
   */
  addPlaytimeObserver() {
    this.window.webContents.executeJavaScript(`
        let playtime = document.querySelector('.player-position');
        let observer = new MutationObserver(mutations => {
            mutations.forEach(mutation => {
                ipc.send('playtime', playtime.innerHTML);
            });
        });

        observer.observe(playtime, {childList: true});
    `)
  }

  /**
   * Remove the listener to monitor the play time.
   */
  removePlaytimeObserver() {
    this.window.webContents.executeJavaScript(`
      observer.disconnect();
    `)
  }

  prettyLyric(lyric) {
    return lyric.replace(/<\d*>/g, '');
  }

  /**
   * Handle the received response after the web content make a request.
   * @param {*} requestUrl the request URL for the event
   */
  handleResponse(requestUrl) {
    const showNotification = settings.get('showNotification', 'check');

    if ('check' === showNotification) {
      requestUrl.startsWith(playlistUrl) && this.updatePlaylist(requestUrl);

      if (requestUrl.startsWith(getLyricUrl)) {

        this.loadLyrics(requestUrl).then(() => {
          const lyricPath = urlLib.parse(requestUrl).pathname;
          const songId = lyricPath.match(/\/(\d*)_/)[1];
          this.changeTrack(songId);
        }).catch(console.error);
      }
    }
  }

  /**
   * Update the playlist if the request URL is for playlist update.
   * @param {*} requestUrl the request URL for the event
   */
  updatePlaylist(requestUrl) {
    let urlWithPath = urlLib.parse(requestUrl, false);
    delete urlWithPath.search;
    // console.log('Retrieve the playlist from url ' + urlLib.format(urlWithPath));

    // get the cookie, make call with the cookie
    let session = this.window.webContents.session;
    session.cookies.get({url: 'http://www.xiami.com'}, (error, cookies) => {
      let cookieString = cookies.map((cookie) => `${cookie.name}=${cookie.value}`).join(';');

      http.get({
        hostname: urlWithPath.host, path: urlWithPath.pathname, headers: {
          'Referer': playerUrl,
          'Cookie': cookieString,
          'User-Agent': this.window.webContents.getUserAgent()
        }
      }, (response) => {
        let playlistData = '';

        response.on('data', (chunk) => {
          playlistData += chunk;
        });

        response.on('end', () => {
          let tracks = JSON.parse(playlistData).data.trackList;
          // refresh the local storage.
          tracks.forEach(track => {
            // console.log(track);
            storage.set(track.songId, track, (error) => {
              if (error) console.log(error);
            });
          });
        });
      });
    });
  }

  /**
   * Handle the track changed.
   * @param {*} songId the changed song ID
   */
  changeTrack(songId) {
    storage.get(songId, (error, trackInfo) => {

      if (error) throw error;

      // notify the current playing track
      if (Object.keys(trackInfo).length > 0) {
        // update the current playing track
        storage.set('currentTrackInfo', trackInfo, (error) => {
          if (error) console.log(error);
        })

        // download the covers
        return download(this.window, trackInfo.pic, {directory: `${app.getPath('userData')}/covers`})
            .then(dl => {
              const notification = new Notification({
                title: `${Locale.NOTIFICATION_TRACK}: ${trackInfo.songName}`,
                body: `${Locale.NOTIFICATION_ARTIST}: ${trackInfo.artist_name}
${Locale.NOTIFICATION_ALBUM}: ${trackInfo.album_name}`,
                silent: true,
                icon: dl.getSavePath()
              });

              notification.on("click", () => this.show());
              notification.show();
            });
      } else {
        setTimeout(() => this.changeTrack(songId), 1000);
      }
    });
  }

  loadLyrics(url) {
    return download(this.window, url, {directory: `${app.getPath('userData')}/lyrics`})
        .then(dl => {
          fs.readFile(dl.getSavePath(), 'utf8', (error, data) => {
            this.lyrics.load(data);
          });
        });
  }
}

module.exports = XiamiPlayer;<commit_msg>Fix the lyrics are not loaded when notification is disabled<commit_after>const {app, BrowserWindow, Notification, ipcMain} = require('electron');
const urlLib = require('url');
const http = require('http');
const path = require('path');
const storage = require('electron-json-storage');
const settings = require('electron-settings');
const CssInjector = require('../js/css-injector');
const {download} = require('electron-dl');
const Lyrics = require('../js/lib/lyrics');
const fs = require('fs-extra');
const timeFormat = require('hh-mm-ss');
const UpdateController = require('./update-controller');

const playerUrl = 'http://www.xiami.com/play';
const playlistUrl = 'http://www.xiami.com/song/playlist';
const getLyricUrl = 'http://img.xiami.net/lyric/';

const language = settings.get('language', 'en');
const Locale = language === 'en' ? require('../locale/locale_en') : require('../locale/locale_sc');

class XiamiPlayer {
  constructor(lyricsController) {
    this.lyricsController = lyricsController;
    this.init();
  }

  init() {
    this.lyrics = new Lyrics('');
    const customLayout = settings.get('customLayout', 'default');

    if (customLayout === 'mini') {
      this.window = new BrowserWindow({
        show: false,
        width: 520,
        height: 160,
        frame: false,
        autoHideMenuBar: true,
        fullscreenable: false,
        resizable: false,
        webPreferences: {
          javascript: true,
          plugins: true,
          webSecurity: false,
          nodeIntegration: false,
          preload: path.join(__dirname, 'preload.js')
        }
      });
    } else {
      if (process.platform === 'darwin') {
        this.window = new BrowserWindow({
          show: false, width: 1000, height: 670, titleBarStyle: 'hiddenInset',
          webPreferences: {
            javascript: true,
            plugins: true,
            webSecurity: false,
            nodeIntegration: false,
            preload: path.join(__dirname, 'preload.js')
          }
        });
      } else {
        this.window = new BrowserWindow({
          show: false, width: 1000, height: 670, frame: true, autoHideMenuBar: true,
          webPreferences: {
            javascript: true,
            plugins: true,
            webSecurity: false,
            nodeIntegration: false,
            preload: path.join(__dirname, 'preload.js')
          }
        });
      }
    }

    // load xiami player page.
    this.window.loadURL(playerUrl);

    // inject the custom layout.
    this.window.webContents.on('dom-ready', () => {

      this.window.webContents.insertCSS(CssInjector.main);

      if (process.platform == 'darwin') {
        this.window.webContents.insertCSS(CssInjector.macos);
      }

      switch (customLayout) {
        case 'hideSidebar':
          this.window.webContents.insertCSS(CssInjector.hideSidebar);
          break;
        case 'hideLyrics':
          this.window.webContents.insertCSS(CssInjector.hideLyrics);
          break;
        case 'songListOnly':
          this.window.webContents.insertCSS(CssInjector.songListOnly);
          break;
        case 'mini':
          this.window.webContents.insertCSS(CssInjector.mini);
          break;
        default:
          // using the default layout from the xiami play
          break;
      }

      this.window.show();

      // check update
      new UpdateController().checkUpdate();
    });

    // triggering when user try to close the play window.
    this.window.on('close', (e) => {
      if (this.window.isVisible()) {
        e.preventDefault();
        this.window.hide();
      }
    });

    // triggering after the play window closed.
    this.window.on('closed', () => {
      ipcMain.removeAllListeners('playtime');
      this.window = null;
    });

    // intercept the ajax call response
    this.window.webContents.on('did-get-response-details', ((event, status, newURL, originalURL) => this.handleResponse(originalURL)));

    ipcMain.on('playtime', (event, value) => {
      const timeline = this.lyrics.select(timeFormat.toS(value));
      if (timeline !== this.previousTime) {
        this.previousTime = timeline;
        if (timeline >= 0) {
          let lyric = this.lyrics.getLyric(timeline);
          if (lyric) {
            let text = lyric.text;
            this.lyricsController.window.webContents.send('lyricsChange', this.prettyLyric(text));
          }
        } else {
          this.lyricsController.window.webContents.send('lyricsChange', '这首没有歌词 (-_-!)');
        }
      }
    });
  }

  // display and focus the player window.
  show() {
    this.window.show();
    this.window.focus();
  }

  // return a boolean to indicate if the window is visible or not
  isVisible() {
    return this.window.isVisible();
  }

  pause() {
    this.window.webContents.executeJavaScript("document.querySelector('.pause-btn').dispatchEvent(new MouseEvent('click'));");
  }

  play() {
    this.window.webContents.executeJavaScript("document.querySelector('.play-btn').dispatchEvent(new MouseEvent('click'));");
  }

  next() {
    this.window.webContents.executeJavaScript("document.querySelector('.next-btn').dispatchEvent(new MouseEvent('click'));");
  }

  previous() {
    this.window.webContents.executeJavaScript("document.querySelector('.prev-btn').dispatchEvent(new MouseEvent('click'));");
  }

  /**
   * Add the listener to monitor the play time.
   */
  addPlaytimeObserver() {
    this.window.webContents.executeJavaScript(`
        let playtime = document.querySelector('.player-position');
        let observer = new MutationObserver(mutations => {
            mutations.forEach(mutation => {
                ipc.send('playtime', playtime.innerHTML);
            });
        });

        observer.observe(playtime, {childList: true});
    `)
  }

  /**
   * Remove the listener to monitor the play time.
   */
  removePlaytimeObserver() {
    this.window.webContents.executeJavaScript(`
      observer.disconnect();
    `)
  }

  prettyLyric(lyric) {
    return lyric.replace(/<\d*>/g, '');
  }

  /**
   * Handle the received response after the web content make a request.
   * @param {*} requestUrl the request URL for the event
   */
  handleResponse(requestUrl) {
    requestUrl.startsWith(playlistUrl) && this.updatePlaylist(requestUrl);

    if (requestUrl.startsWith(getLyricUrl)) {
      this.loadLyrics(requestUrl).then(() => {

        const showNotification = settings.get('showNotification', 'check');
        if ('check' === showNotification) {
          const lyricPath = urlLib.parse(requestUrl).pathname;
          const songId = lyricPath.match(/\/(\d*)_/)[1];
          this.changeTrack(songId);
        }
      }).catch(console.error);
    }
  }

  /**
   * Update the playlist if the request URL is for playlist update.
   * @param {*} requestUrl the request URL for the event
   */
  updatePlaylist(requestUrl) {
    let urlWithPath = urlLib.parse(requestUrl, false);
    delete urlWithPath.search;
    // console.log('Retrieve the playlist from url ' + urlLib.format(urlWithPath));

    // get the cookie, make call with the cookie
    let session = this.window.webContents.session;
    session.cookies.get({url: 'http://www.xiami.com'}, (error, cookies) => {
      let cookieString = cookies.map((cookie) => `${cookie.name}=${cookie.value}`).join(';');

      http.get({
        hostname: urlWithPath.host, path: urlWithPath.pathname, headers: {
          'Referer': playerUrl,
          'Cookie': cookieString,
          'User-Agent': this.window.webContents.getUserAgent()
        }
      }, (response) => {
        let playlistData = '';

        response.on('data', (chunk) => {
          playlistData += chunk;
        });

        response.on('end', () => {
          let tracks = JSON.parse(playlistData).data.trackList;
          // refresh the local storage.
          tracks.forEach(track => {
            // console.log(track);
            storage.set(track.songId, track, (error) => {
              if (error) console.log(error);
            });
          });
        });
      });
    });
  }

  /**
   * Handle the track changed.
   * @param {*} songId the changed song ID
   */
  changeTrack(songId) {
    storage.get(songId, (error, trackInfo) => {

      if (error) throw error;

      // notify the current playing track
      if (Object.keys(trackInfo).length > 0) {
        // update the current playing track
        storage.set('currentTrackInfo', trackInfo, (error) => {
          if (error) console.log(error);
        })

        // download the covers
        return download(this.window, trackInfo.pic, {directory: `${app.getPath('userData')}/covers`})
            .then(dl => {
              const notification = new Notification({
                title: `${Locale.NOTIFICATION_TRACK}: ${trackInfo.songName}`,
                body: `${Locale.NOTIFICATION_ARTIST}: ${trackInfo.artist_name}
${Locale.NOTIFICATION_ALBUM}: ${trackInfo.album_name}`,
                silent: true,
                icon: dl.getSavePath()
              });

              notification.on("click", () => this.show());
              notification.show();
            });
      } else {
        setTimeout(() => this.changeTrack(songId), 1000);
      }
    });
  }

  loadLyrics(url) {
    return download(this.window, url, {directory: `${app.getPath('userData')}/lyrics`})
        .then(dl => {
          fs.readFile(dl.getSavePath(), 'utf8', (error, data) => {
            this.lyrics.load(data);
          });
        });
  }
}

module.exports = XiamiPlayer;<|endoftext|>


<commit_before>"use strict";

var BlindingInformation = require("./types/blinding_information");
var blinding = require("./blinding");
var client = require("./client");
var util = require("./util");

var openpgp = require("openpgp");

/// TODO
function requestPseudonym()
{
  var blind_signature_packet = blinding.prepareBlindSignature();
  var token = client.getToken();

  /// blinding factor and modulus must be coprime
  ///   - ensured through the use of prime numbers
  ///   - blinding factor is generated through the multiplication of prime token and two additional prime numbers
  /// blinding factor must be smaller than Modulus
  ///   - number of bits after multiplication of two numbers with the same bit length (n) is 2n or less
  ///     (https://math.stackexchange.com/questions/682618/the-maximum-number-of-digits-in-binary-multiplication)
  ///   - TODO: unsure how to handle this properly
  var blinding_information = client.collectPublicBlindingInformation();
  var prime_bit_length = Math.floor((blinding_information.modulus.bitLength() - token.data.bitLength() - 1) / 2);

  return util.generateTwoPrimeNumbers(prime_bit_length)
    .then(function (primes) {

      blinding_information.hashed_token = util.bytes2MPI(util.hashMessage(token.data.toRadix())).data;
      blinding_information.blinding_factor = token.data.multiply(primes[0].multiply(primes[1]));

      /// TODO: workaround for unhandled length problem ... if blinding factor is to large this reduces its size
      if (blinding_information.blinding_factor.compareTo(blinding_information.modulus) > 0) {
        blinding_information.blinding_factor = token.data.multiply(primes[0]);
      }

      return blinding.blind_message(blind_signature_packet.unsigned_signature, blinding_information).toRadix();
    })
    .then(function (blinded_message) {
      return client.sendBlindingRequest(blinded_message, blinding_information);
    })
    .then(function (signed_blinded_message) {
      var unblinded_message = blinding.unblind_message(signed_blinded_message, blinding_information);
      if (unblinded_message === null) {
        throw new Error("Could not unblind the signed blinded message");
      }

      var signature_packet = blind_signature_packet;
      signature_packet.signature = unblinded_message.toMPI();

      var verify_me = new openpgp.packet.Literal();
      verify_me.setBytes(signature_packet.signature, 'binary');

      var public_key = client.getPublicKey();
      var result = signature_packet.verify(client.getServerPublicKey().primaryKey, {
        key: public_key.primaryKey,
        userid: public_key.getPrimaryUser().user.userId
      });

      console.log("Signature veryfied: " + result);

      /// DUMP
      var public_key = client.getPublicKey();
      var user = public_key.getPrimaryUser().user;

      if (!user.otherCertifications) {
        user.otherCertifications = [];
      }
      user.otherCertifications.push(signature_packet);

      console.log(public_key.armor());
      return public_key.armor();
    });
}

// TODO: refactoring necessary
// set request button active
if (typeof document !== "undefined" && document.getElementById("activate_pseudonym_button")) {
  document.getElementById("activate_pseudonym_button").onclick = requestPseudonym;
}

// exports requestPseudonym to allow testing
if(typeof exports !== 'undefined') {
  exports.requestPseudonym = requestPseudonym;
}<commit_msg>Client Main: adds simple error log to check if sth went wrong<commit_after>"use strict";

var BlindingInformation = require("./types/blinding_information");
var blinding = require("./blinding");
var client = require("./client");
var util = require("./util");

var openpgp = require("openpgp");

/// TODO
function requestPseudonym()
{
  var blind_signature_packet = blinding.prepareBlindSignature();
  var token = client.getToken();

  /// blinding factor and modulus must be coprime
  ///   - ensured through the use of prime numbers
  ///   - blinding factor is generated through the multiplication of prime token and two additional prime numbers
  /// blinding factor must be smaller than Modulus
  ///   - number of bits after multiplication of two numbers with the same bit length (n) is 2n or less
  ///     (https://math.stackexchange.com/questions/682618/the-maximum-number-of-digits-in-binary-multiplication)
  ///   - TODO: unsure how to handle this properly
  var blinding_information = client.collectPublicBlindingInformation();
  var prime_bit_length = Math.floor((blinding_information.modulus.bitLength() - token.data.bitLength() - 1) / 2);

  return util.generateTwoPrimeNumbers(prime_bit_length)
    .then(function (primes) {

      blinding_information.hashed_token = util.bytes2MPI(util.hashMessage(token.data.toRadix())).data;
      blinding_information.blinding_factor = token.data.multiply(primes[0].multiply(primes[1]));

      /// TODO: workaround for unhandled length problem ... if blinding factor is to large this reduces its size
      if (blinding_information.blinding_factor.compareTo(blinding_information.modulus) > 0) {
        blinding_information.blinding_factor = token.data.multiply(primes[0]);
      }

      return blinding.blind_message(blind_signature_packet.unsigned_signature, blinding_information).toRadix();
    })
    .then(function (blinded_message) {
      return client.sendBlindingRequest(blinded_message, blinding_information);
    })
    .then(function (signed_blinded_message) {
      var unblinded_message = blinding.unblind_message(signed_blinded_message, blinding_information);
      if (unblinded_message === null) {
        throw new Error("Could not unblind the signed blinded message");
      }

      var signature_packet = blind_signature_packet;
      signature_packet.signature = unblinded_message.toMPI();

      var verify_me = new openpgp.packet.Literal();
      verify_me.setBytes(signature_packet.signature, 'binary');

      var public_key = client.getPublicKey();
      var result = signature_packet.verify(client.getServerPublicKey().primaryKey, {
        key: public_key.primaryKey,
        userid: public_key.getPrimaryUser().user.userId
      });

      console.log("Signature veryfied: " + result);

      /// DUMP
      var public_key = client.getPublicKey();
      var user = public_key.getPrimaryUser().user;

      if (!user.otherCertifications) {
        user.otherCertifications = [];
      }
      user.otherCertifications.push(signature_packet);

      console.log(public_key.armor());
      return public_key.armor();
    })
    .catch(function(error) {console.log(error); });
}

// TODO: refactoring necessary
// set request button active
if (typeof document !== "undefined" && document.getElementById("activate_pseudonym_button")) {
  document.getElementById("activate_pseudonym_button").onclick = requestPseudonym;
}

// exports requestPseudonym to allow testing
if(typeof exports !== 'undefined') {
  exports.requestPseudonym = requestPseudonym;
}<|endoftext|>


<commit_before>/*
Copyright 2015 OpenMarket Ltd

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

var MatrixClientPeg = require("../../MatrixClientPeg");
var RoomListSorter = require("../../RoomListSorter");
var Presence = require("../../Presence");
var dis = require("../../dispatcher");
var q = require("q");

var sdk = require('../../index');
var MatrixTools = require('../../MatrixTools');

module.exports = {
    PageTypes: {
        RoomView: "room_view",
        UserSettings: "user_settings",
        CreateRoom: "create_room",
        RoomDirectory: "room_directory",
    },

    AuxPanel: {
        RoomSettings: "room_settings",
    },

    getInitialState: function() {
        var s = {
            logged_in: !!(MatrixClientPeg.get() && MatrixClientPeg.get().credentials),
            ready: false,
        };
        if (s.logged_in) {
            if (MatrixClientPeg.get().getRooms().length) {
                s.page_type = this.PageTypes.RoomView;
            } else {
                s.page_type = this.PageTypes.RoomDirectory;
            }
        }
        return s;
    },

    componentDidMount: function() {
        this.dispatcherRef = dis.register(this.onAction);
        if (this.state.logged_in) {
            this.startMatrixClient();
        }
        this.focusComposer = false;
        document.addEventListener("keydown", this.onKeyDown);
        window.addEventListener("focus", this.onFocus);
        if (this.state.logged_in) {
            this.notifyNewScreen('');
        } else {
            this.notifyNewScreen('login');
        }
    },

    componentWillUnmount: function() {
        dis.unregister(this.dispatcherRef);
        document.removeEventListener("keydown", this.onKeyDown);
        window.removeEventListener("focus", this.onFocus);
    },

    componentDidUpdate: function() {
        if (this.focusComposer) {
            dis.dispatch({action: 'focus_composer'});
            this.focusComposer = false;
        }
    },

    onAction: function(payload) {
        var roomIndexDelta = 1;
        var Notifier = sdk.getComponent('organisms.Notifier');

        var self = this;
        switch (payload.action) {
            case 'logout':
                this.replaceState({
                    logged_in: false,
                    ready: false
                });
                if (window.localStorage) {
                    window.localStorage.clear();
                }
                Notifier.stop();
                Presence.stop();
                MatrixClientPeg.get().stopClient();
                MatrixClientPeg.get().removeAllListeners();
                MatrixClientPeg.unset();
                this.notifyNewScreen('login');
                break;
            case 'start_registration':
                if (this.state.logged_in) return;
                var newState = payload.params || {};
                newState.screen = 'register';
                if (
                    payload.params &&
                    payload.params.client_secret &&
                    payload.params.session_id &&
                    payload.params.hs_url &&
                    payload.params.is_url &&
                    payload.params.sid
                ) {
                    newState.register_client_secret = payload.params.client_secret;
                    newState.register_session_id = payload.params.session_id;
                    newState.register_hs_url = payload.params.hs_url;
                    newState.register_is_url = payload.params.is_url;
                    newState.register_id_sid = payload.params.sid;
                }
                this.replaceState(newState);
                this.notifyNewScreen('register');
                break;
            case 'start_login':
                if (this.state.logged_in) return;
                this.replaceState({
                    screen: 'login'
                });
                this.notifyNewScreen('login');
                break;
            case 'view_room':
                this.focusComposer = true;
                var newState = {
                    currentRoom: payload.room_id,
                    page_type: this.PageTypes.RoomView,
                };
                if (this.sdkReady) {
                    // if the SDK is not ready yet, remember what room
                    // we're supposed to be on but don't notify about
                    // the new screen yet (we won't be showing it yet)
                    // The normal case where this happens is navigating
                    // to the room in the URL bar on page load.
                    var presentedId = payload.room_id;
                    var room = MatrixClientPeg.get().getRoom(payload.room_id);
                    if (room) {
                        var theAlias = MatrixTools.getCanonicalAliasForRoom(room);
                        if (theAlias) presentedId = theAlias;
                    }
                    this.notifyNewScreen('room/'+presentedId);
                }
                newState.ready = true;
                this.setState(newState);
                break;
            case 'view_prev_room':
                roomIndexDelta = -1;
            case 'view_next_room':
                var allRooms = RoomListSorter.mostRecentActivityFirst(
                    MatrixClientPeg.get().getRooms()
                );
                var roomIndex = -1;
                for (var i = 0; i < allRooms.length; ++i) {
                    if (allRooms[i].roomId == this.state.currentRoom) {
                        roomIndex = i;
                        break;
                    }
                }
                roomIndex = (roomIndex + roomIndexDelta) % allRooms.length;
                if (roomIndex < 0) roomIndex = allRooms.length - 1;
                this.focusComposer = true;
                this.setState({
                    currentRoom: allRooms[roomIndex].roomId
                });
                this.notifyNewScreen('room/'+allRooms[roomIndex].roomId);
                break;
            case 'view_indexed_room':
                var allRooms = RoomListSorter.mostRecentActivityFirst(
                    MatrixClientPeg.get().getRooms()
                );
                var roomIndex = payload.roomIndex;
                if (allRooms[roomIndex]) {
                    this.focusComposer = true;
                    this.setState({
                        currentRoom: allRooms[roomIndex].roomId
                    });
                    this.notifyNewScreen('room/'+allRooms[roomIndex].roomId);
                }
                break;
            case 'view_room_alias':
                MatrixClientPeg.get().getRoomIdForAlias(payload.room_alias).done(function(result) {
                    dis.dispatch({
                        action: 'view_room',
                        room_id: result.room_id
                    });
                });
                break;
            case 'view_user_settings':
                this.setState({
                    page_type: this.PageTypes.UserSettings,
                });
                break;
            case 'view_create_room':
                this.setState({
                    page_type: this.PageTypes.CreateRoom,
                });
                break;
            case 'view_room_directory':
                this.setState({
                    page_type: this.PageTypes.RoomDirectory,
                });
                break;
            case 'notifier_enabled':
                this.forceUpdate();
                break;
        }
    },

    onLoggedIn: function() {
        this.setState({
            screen: undefined,
            logged_in: true
        });
        this.startMatrixClient();
        this.notifyNewScreen('');
    },

    startMatrixClient: function() {
        var Notifier = sdk.getComponent('organisms.Notifier');
        var cli = MatrixClientPeg.get();
        var self = this;
        cli.on('syncComplete', function() {
            self.sdkReady = true;

            if (self.starting_room_alias) {
                dis.dispatch({
                    action: 'view_room_alias',
                    room_alias: self.starting_room_alias
                });
                delete self.starting_room_alias;
            } else {
                if (!self.state.currentRoom) {
                    var firstRoom = null;
                    if (cli.getRooms() && cli.getRooms().length) {
                        firstRoom = RoomListSorter.mostRecentActivityFirst(
                            cli.getRooms()
                        )[0].roomId;
                        self.setState({ready: true, currentRoom: firstRoom, page_type: self.PageTypes.RoomView});
                    } else {
                        self.setState({ready: true, page_type: self.PageTypes.RoomDirectory});
                    }
                } else {
                    self.setState({ready: true, page_type: self.PageTypes.RoomView});
                }

                // we notifyNewScreen now because now the room will actually be displayed,
                // and (mostly) now we can get the correct alias.
                var presentedId = self.state.currentRoom;
                var room = MatrixClientPeg.get().getRoom(self.state.currentRoom);
                if (room) {
                    var theAlias = MatrixTools.getCanonicalAliasForRoom(room);
                    if (theAlias) presentedId = theAlias;
                }
                self.notifyNewScreen('room/'+presentedId);
                dis.dispatch({action: 'focus_composer'});
            }
        });
        cli.on('Call.incoming', function(call) {
            dis.dispatch({
                action: 'incoming_call',
                call: call
            });
        });
        Notifier.start();
        Presence.start();
        cli.startClient();
    },

    onKeyDown: function(ev) {
        if (ev.altKey) {
            if (ev.ctrlKey && ev.keyCode > 48 && ev.keyCode < 58) {
                dis.dispatch({
                    action: 'view_indexed_room',
                    roomIndex: ev.keyCode - 49,
                });
                ev.stopPropagation();
                ev.preventDefault();
                return;
            }
            switch (ev.keyCode) {
                case 38:
                    dis.dispatch({action: 'view_prev_room'});
                    ev.stopPropagation();
                    ev.preventDefault();
                    break;
                case 40:
                    dis.dispatch({action: 'view_next_room'});
                    ev.stopPropagation();
                    ev.preventDefault();
                    break;
            }
        }
    },

    onFocus: function(ev) {
        dis.dispatch({action: 'focus_composer'});
    },

    showScreen: function(screen, params) {
        if (screen == 'register') {
            dis.dispatch({
                action: 'start_registration',
                params: params
            });
        } else if (screen == 'login') {
            dis.dispatch({
                action: 'start_login',
                params: params
            });
        } else if (screen.indexOf('room/') == 0) {
            var roomString = screen.split('/')[1];
            if (roomString[0] == '#') {
                if (this.state.logged_in) {
                    dis.dispatch({
                        action: 'view_room_alias',
                        room_alias: roomString
                    });
                } else {
                    // Okay, we'll take you here soon...
                    this.starting_room_alias = roomString;
                    // ...but you're still going to have to log in.
                    this.notifyNewScreen('login');
                }
            } else {
                dis.dispatch({
                    action: 'view_room',
                    room_id: roomString
                });
            }
        }
    },

    notifyNewScreen: function(screen) {
        if (this.props.onNewScreen) {
            this.props.onNewScreen(screen);
        }
    }
};
<commit_msg>Set state to ready only if the SDK is synced.<commit_after>/*
Copyright 2015 OpenMarket Ltd

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

var MatrixClientPeg = require("../../MatrixClientPeg");
var RoomListSorter = require("../../RoomListSorter");
var Presence = require("../../Presence");
var dis = require("../../dispatcher");
var q = require("q");

var sdk = require('../../index');
var MatrixTools = require('../../MatrixTools');

module.exports = {
    PageTypes: {
        RoomView: "room_view",
        UserSettings: "user_settings",
        CreateRoom: "create_room",
        RoomDirectory: "room_directory",
    },

    AuxPanel: {
        RoomSettings: "room_settings",
    },

    getInitialState: function() {
        var s = {
            logged_in: !!(MatrixClientPeg.get() && MatrixClientPeg.get().credentials),
            ready: false,
        };
        if (s.logged_in) {
            if (MatrixClientPeg.get().getRooms().length) {
                s.page_type = this.PageTypes.RoomView;
            } else {
                s.page_type = this.PageTypes.RoomDirectory;
            }
        }
        return s;
    },

    componentDidMount: function() {
        this.dispatcherRef = dis.register(this.onAction);
        if (this.state.logged_in) {
            this.startMatrixClient();
        }
        this.focusComposer = false;
        document.addEventListener("keydown", this.onKeyDown);
        window.addEventListener("focus", this.onFocus);
        if (this.state.logged_in) {
            this.notifyNewScreen('');
        } else {
            this.notifyNewScreen('login');
        }
    },

    componentWillUnmount: function() {
        dis.unregister(this.dispatcherRef);
        document.removeEventListener("keydown", this.onKeyDown);
        window.removeEventListener("focus", this.onFocus);
    },

    componentDidUpdate: function() {
        if (this.focusComposer) {
            dis.dispatch({action: 'focus_composer'});
            this.focusComposer = false;
        }
    },

    onAction: function(payload) {
        var roomIndexDelta = 1;
        var Notifier = sdk.getComponent('organisms.Notifier');

        var self = this;
        switch (payload.action) {
            case 'logout':
                this.replaceState({
                    logged_in: false,
                    ready: false
                });
                if (window.localStorage) {
                    window.localStorage.clear();
                }
                Notifier.stop();
                Presence.stop();
                MatrixClientPeg.get().stopClient();
                MatrixClientPeg.get().removeAllListeners();
                MatrixClientPeg.unset();
                this.notifyNewScreen('login');
                break;
            case 'start_registration':
                if (this.state.logged_in) return;
                var newState = payload.params || {};
                newState.screen = 'register';
                if (
                    payload.params &&
                    payload.params.client_secret &&
                    payload.params.session_id &&
                    payload.params.hs_url &&
                    payload.params.is_url &&
                    payload.params.sid
                ) {
                    newState.register_client_secret = payload.params.client_secret;
                    newState.register_session_id = payload.params.session_id;
                    newState.register_hs_url = payload.params.hs_url;
                    newState.register_is_url = payload.params.is_url;
                    newState.register_id_sid = payload.params.sid;
                }
                this.replaceState(newState);
                this.notifyNewScreen('register');
                break;
            case 'start_login':
                if (this.state.logged_in) return;
                this.replaceState({
                    screen: 'login'
                });
                this.notifyNewScreen('login');
                break;
            case 'view_room':
                this.focusComposer = true;
                var newState = {
                    currentRoom: payload.room_id,
                    page_type: this.PageTypes.RoomView,
                };
                if (this.sdkReady) {
                    // if the SDK is not ready yet, remember what room
                    // we're supposed to be on but don't notify about
                    // the new screen yet (we won't be showing it yet)
                    // The normal case where this happens is navigating
                    // to the room in the URL bar on page load.
                    var presentedId = payload.room_id;
                    var room = MatrixClientPeg.get().getRoom(payload.room_id);
                    if (room) {
                        var theAlias = MatrixTools.getCanonicalAliasForRoom(room);
                        if (theAlias) presentedId = theAlias;
                    }
                    this.notifyNewScreen('room/'+presentedId);
                    newState.ready = true;
                }
                this.setState(newState);
                break;
            case 'view_prev_room':
                roomIndexDelta = -1;
            case 'view_next_room':
                var allRooms = RoomListSorter.mostRecentActivityFirst(
                    MatrixClientPeg.get().getRooms()
                );
                var roomIndex = -1;
                for (var i = 0; i < allRooms.length; ++i) {
                    if (allRooms[i].roomId == this.state.currentRoom) {
                        roomIndex = i;
                        break;
                    }
                }
                roomIndex = (roomIndex + roomIndexDelta) % allRooms.length;
                if (roomIndex < 0) roomIndex = allRooms.length - 1;
                this.focusComposer = true;
                this.setState({
                    currentRoom: allRooms[roomIndex].roomId
                });
                this.notifyNewScreen('room/'+allRooms[roomIndex].roomId);
                break;
            case 'view_indexed_room':
                var allRooms = RoomListSorter.mostRecentActivityFirst(
                    MatrixClientPeg.get().getRooms()
                );
                var roomIndex = payload.roomIndex;
                if (allRooms[roomIndex]) {
                    this.focusComposer = true;
                    this.setState({
                        currentRoom: allRooms[roomIndex].roomId
                    });
                    this.notifyNewScreen('room/'+allRooms[roomIndex].roomId);
                }
                break;
            case 'view_room_alias':
                MatrixClientPeg.get().getRoomIdForAlias(payload.room_alias).done(function(result) {
                    dis.dispatch({
                        action: 'view_room',
                        room_id: result.room_id
                    });
                });
                break;
            case 'view_user_settings':
                this.setState({
                    page_type: this.PageTypes.UserSettings,
                });
                break;
            case 'view_create_room':
                this.setState({
                    page_type: this.PageTypes.CreateRoom,
                });
                break;
            case 'view_room_directory':
                this.setState({
                    page_type: this.PageTypes.RoomDirectory,
                });
                break;
            case 'notifier_enabled':
                this.forceUpdate();
                break;
        }
    },

    onLoggedIn: function() {
        this.setState({
            screen: undefined,
            logged_in: true
        });
        this.startMatrixClient();
        this.notifyNewScreen('');
    },

    startMatrixClient: function() {
        var Notifier = sdk.getComponent('organisms.Notifier');
        var cli = MatrixClientPeg.get();
        var self = this;
        cli.on('syncComplete', function() {
            self.sdkReady = true;

            if (self.starting_room_alias) {
                dis.dispatch({
                    action: 'view_room_alias',
                    room_alias: self.starting_room_alias
                });
                delete self.starting_room_alias;
            } else {
                if (!self.state.currentRoom) {
                    var firstRoom = null;
                    if (cli.getRooms() && cli.getRooms().length) {
                        firstRoom = RoomListSorter.mostRecentActivityFirst(
                            cli.getRooms()
                        )[0].roomId;
                        self.setState({ready: true, currentRoom: firstRoom, page_type: self.PageTypes.RoomView});
                    } else {
                        self.setState({ready: true, page_type: self.PageTypes.RoomDirectory});
                    }
                } else {
                    self.setState({ready: true, page_type: self.PageTypes.RoomView});
                }

                // we notifyNewScreen now because now the room will actually be displayed,
                // and (mostly) now we can get the correct alias.
                var presentedId = self.state.currentRoom;
                var room = MatrixClientPeg.get().getRoom(self.state.currentRoom);
                if (room) {
                    var theAlias = MatrixTools.getCanonicalAliasForRoom(room);
                    if (theAlias) presentedId = theAlias;
                }
                self.notifyNewScreen('room/'+presentedId);
                dis.dispatch({action: 'focus_composer'});
            }
        });
        cli.on('Call.incoming', function(call) {
            dis.dispatch({
                action: 'incoming_call',
                call: call
            });
        });
        Notifier.start();
        Presence.start();
        cli.startClient();
    },

    onKeyDown: function(ev) {
        if (ev.altKey) {
            if (ev.ctrlKey && ev.keyCode > 48 && ev.keyCode < 58) {
                dis.dispatch({
                    action: 'view_indexed_room',
                    roomIndex: ev.keyCode - 49,
                });
                ev.stopPropagation();
                ev.preventDefault();
                return;
            }
            switch (ev.keyCode) {
                case 38:
                    dis.dispatch({action: 'view_prev_room'});
                    ev.stopPropagation();
                    ev.preventDefault();
                    break;
                case 40:
                    dis.dispatch({action: 'view_next_room'});
                    ev.stopPropagation();
                    ev.preventDefault();
                    break;
            }
        }
    },

    onFocus: function(ev) {
        dis.dispatch({action: 'focus_composer'});
    },

    showScreen: function(screen, params) {
        if (screen == 'register') {
            dis.dispatch({
                action: 'start_registration',
                params: params
            });
        } else if (screen == 'login') {
            dis.dispatch({
                action: 'start_login',
                params: params
            });
        } else if (screen.indexOf('room/') == 0) {
            var roomString = screen.split('/')[1];
            if (roomString[0] == '#') {
                if (this.state.logged_in) {
                    dis.dispatch({
                        action: 'view_room_alias',
                        room_alias: roomString
                    });
                } else {
                    // Okay, we'll take you here soon...
                    this.starting_room_alias = roomString;
                    // ...but you're still going to have to log in.
                    this.notifyNewScreen('login');
                }
            } else {
                dis.dispatch({
                    action: 'view_room',
                    room_id: roomString
                });
            }
        }
    },

    notifyNewScreen: function(screen) {
        if (this.props.onNewScreen) {
            this.props.onNewScreen(screen);
        }
    }
};
<|endoftext|>


<commit_before>db.createCollection('creatorData');
db.createCollection('itemDataValues');
db.createCollection('syncDownloadCache');
<commit_msg>Add searchItems collection to Mongo schema<commit_after>db.createCollection('creatorData');
db.createCollection('itemDataValues');
db.createCollection('syncDownloadCache');
db.createCollection('searchItems');
<|endoftext|>


<commit_before>Key = function(key, x, y, w, h) {
  this.key = key;
  this.x = x;
  this.y = y;
  this.w = w ? w : MIN_KEY_SIZE;
  this.h = h ? h : MIN_KEY_SIZE;

  this.keyboardx = x;
  this.keyboardy = y;
  this.mousex;
  this.mousey;

  this.pressed = false;
  this.disabled = false;
  this.onKeyboard = true;
  this.moveInterval;

  var getKeyWidth = function(chars) {
    add = 0;

    switch(chars) {
      case 'Backspace': add = 72; break;
      case 'Tab': add = 26; break;
      case '|\\': add = 46; break;
      case 'CapsLk': add = 46; break;
      case 'Enter': add = 64; break;
      case 'Shift': add = 74; break;
      case 'Ctrl': add = 18; break;
      case 'Meta': add = 18; break;
      case 'Alt': add = 18; break;
      case ' ': add = 172; break;
      default: break;
    }

    return MIN_KEY_SIZE + add;
  };
  this.w = getKeyWidth(key);

  return this;
}
Key.prototype.detectMouseOver = function(event, isKeyboard) {
  var prefix = isKeyboard ? 'keyboard' : '';
  if (event.offsetX < this[prefix + 'x']) {
    return false;
  }
  else if (event.offsetX > (this[prefix + 'x'] + this.w)) {
    return false;
  }
  else if (event.offsetY < this[prefix + 'y']) {
    return false;
  }
  else if (event.offsetY > (this[prefix + 'y'] + this.h)) {
    return false;
  }
  return true;
}
Key.prototype.updateMousePos = function(event) {
  this.mousex = event.offsetX;
  this.mousey = event.offsetY;
};
Key.prototype.grab = function(event) {
  this.updateMousePos(event);
  this.onKeyboard = false;
  this.moveInterval = setInterval(function() {
    var diffx = this.mousex - this.x - (this.w / 2);
    var diffy = this.mousey - this.y - (this.h / 2);
    this.x += (diffx / 4);
    this.y += (diffy / 4);
  }.bind(this), KEY_MOVE_DELAY);
};
Key.prototype.release = function(event) {
  clearInterval(this.moveInterval);
  if (this.detectMouseOver(event, true)) {
    this.x = this.keyboardx;
    this.y = this.keyboardy;
    this.onKeyboard = true;
  }
  else {
    this.moveInterval = setInterval(function() {
      if (this.y + this.w >= 600) {
        clearInterval(this.moveInterval);
        this.y = 600 - this.h;
        return;
      }
      this.y += 4;
    }.bind(this), KEY_MOVE_DELAY);
  }
};
Key.prototype.render = function(context) {
  context.fillStyle = this.pressed ? KEY_LIGHT_BORDER_COLOR : KEY_DARK_BORDER_COLOR;
  context.fillRect(this.x, this.y, this.w, this.h);

  context.fillStyle = this.pressed ? KEY_DARK_BORDER_COLOR : KEY_LIGHT_BORDER_COLOR;
  context.beginPath();
  context.moveTo(this.x, this.y);
  context.lineTo(this.x + this.w, this.y);
  context.lineTo(this.x + this.w - KEY_LINE_WIDTH, this.y + KEY_LINE_WIDTH);
  context.lineTo(this.x + KEY_LINE_WIDTH, this.y + this.h - KEY_LINE_WIDTH);
  context.lineTo(this.x, this.y + this.h);
  context.closePath();
  context.fill();

  context.fillStyle = KEY_COLOR;
  context.fillRect(this.x + KEY_LINE_WIDTH, this.y + KEY_LINE_WIDTH, this.w - (2 * KEY_LINE_WIDTH), this.h - (2 * KEY_LINE_WIDTH));

  context.fillStyle = KEY_TEXT_COLOR;
  if (this.key.length == 2) {
    this.key.split('').forEach(function(char, index) {
      context.fillText(char, this.x + (MIN_KEY_SIZE / 4), this.y + ((index + 1) * KEY_TEXT_SIZE));
      context.strokeText(char, this.x + (MIN_KEY_SIZE / 4), this.y + ((index + 1) * KEY_TEXT_SIZE));
    }, this);
  }
  else {
    context.fillText(this.key, this.x + (MIN_KEY_SIZE / 4), this.y + (MIN_KEY_SIZE / 2));
    context.strokeText(this.key, this.x + (MIN_KEY_SIZE / 4), this.y + (MIN_KEY_SIZE / 2));
  }
};
<commit_msg>Add Key functions to toggle pressed prop<commit_after>Key = function(key, x, y, w, h) {
  this.key = key;
  this.x = x;
  this.y = y;
  this.w = w ? w : MIN_KEY_SIZE;
  this.h = h ? h : MIN_KEY_SIZE;

  this.keyboardx = x;
  this.keyboardy = y;
  this.mousex;
  this.mousey;

  this.pressed = false;
  this.disabled = false;
  this.onKeyboard = true;
  this.moveInterval;

  var getKeyWidth = function(chars) {
    add = 0;

    switch(chars) {
      case 'Backspace': add = 72; break;
      case 'Tab': add = 26; break;
      case '|\\': add = 46; break;
      case 'CapsLk': add = 46; break;
      case 'Enter': add = 64; break;
      case 'Shift': add = 74; break;
      case 'Ctrl': add = 18; break;
      case 'Meta': add = 18; break;
      case 'Alt': add = 18; break;
      case ' ': add = 172; break;
      default: break;
    }

    return MIN_KEY_SIZE + add;
  };
  this.w = getKeyWidth(key);

  return this;
}
Key.prototype.activate = function() {
  if (this.disabled === false) {
    this.pressed = true;
  }
};
Key.prototype.deactivate = function() {
  this.pressed = false;
}
Key.prototype.detectMouseOver = function(event, isKeyboard) {
  var prefix = isKeyboard ? 'keyboard' : '';
  if (event.offsetX < this[prefix + 'x']) {
    return false;
  }
  else if (event.offsetX > (this[prefix + 'x'] + this.w)) {
    return false;
  }
  else if (event.offsetY < this[prefix + 'y']) {
    return false;
  }
  else if (event.offsetY > (this[prefix + 'y'] + this.h)) {
    return false;
  }
  return true;
}
Key.prototype.updateMousePos = function(event) {
  this.mousex = event.offsetX;
  this.mousey = event.offsetY;
};
Key.prototype.grab = function(event) {
  this.updateMousePos(event);
  this.onKeyboard = false;
  this.moveInterval = setInterval(function() {
    var diffx = this.mousex - this.x - (this.w / 2);
    var diffy = this.mousey - this.y - (this.h / 2);
    this.x += (diffx / 4);
    this.y += (diffy / 4);
  }.bind(this), KEY_MOVE_DELAY);
};
Key.prototype.release = function(event) {
  clearInterval(this.moveInterval);
  if (this.detectMouseOver(event, true)) {
    this.x = this.keyboardx;
    this.y = this.keyboardy;
    this.onKeyboard = true;
  }
  else {
    this.moveInterval = setInterval(function() {
      if (this.y + this.w >= 600) {
        clearInterval(this.moveInterval);
        this.y = 600 - this.h;
        return;
      }
      this.y += 4;
    }.bind(this), KEY_MOVE_DELAY);
  }
};
Key.prototype.render = function(context) {
  context.fillStyle = this.pressed ? KEY_LIGHT_BORDER_COLOR : KEY_DARK_BORDER_COLOR;
  context.fillRect(this.x, this.y, this.w, this.h);

  context.fillStyle = this.pressed ? KEY_DARK_BORDER_COLOR : KEY_LIGHT_BORDER_COLOR;
  context.beginPath();
  context.moveTo(this.x, this.y);
  context.lineTo(this.x + this.w, this.y);
  context.lineTo(this.x + this.w - KEY_LINE_WIDTH, this.y + KEY_LINE_WIDTH);
  context.lineTo(this.x + KEY_LINE_WIDTH, this.y + this.h - KEY_LINE_WIDTH);
  context.lineTo(this.x, this.y + this.h);
  context.closePath();
  context.fill();

  context.fillStyle = KEY_COLOR;
  context.fillRect(this.x + KEY_LINE_WIDTH, this.y + KEY_LINE_WIDTH, this.w - (2 * KEY_LINE_WIDTH), this.h - (2 * KEY_LINE_WIDTH));

  context.fillStyle = KEY_TEXT_COLOR;
  if (this.key.length == 2) {
    this.key.split('').forEach(function(char, index) {
      context.fillText(char, this.x + (MIN_KEY_SIZE / 4), this.y + ((index + 1) * KEY_TEXT_SIZE));
      context.strokeText(char, this.x + (MIN_KEY_SIZE / 4), this.y + ((index + 1) * KEY_TEXT_SIZE));
    }, this);
  }
  else {
    context.fillText(this.key, this.x + (MIN_KEY_SIZE / 4), this.y + (MIN_KEY_SIZE / 2));
    context.strokeText(this.key, this.x + (MIN_KEY_SIZE / 4), this.y + (MIN_KEY_SIZE / 2));
  }
};
<|endoftext|>


<commit_before>import _ from 'lodash';
import {
  isTwoDimensional,
  isTooBig,
} from './utilities';
import {
  enhance,
} from '../../lib/helpers';
import cached from '../fields/cached';
import markdown from '../fields/markdown';
import Artist from '../artist';
import Image from '../image';
import Fair from '../fair';
import Sale from '../sale';
import PartnerShow from '../partner_show';
import Partner from '../partner';
import Related from './related';
import Highlight from './highlight';
import Tabs from './tabs';
import Dimensions from '../dimensions';
import EditionSet from '../edition_set';
import gravity from '../../lib/loaders/gravity';
import positron from '../../lib/loaders/positron';
import {
  GraphQLObjectType,
  GraphQLBoolean,
  GraphQLString,
  GraphQLNonNull,
  GraphQLList,
  GraphQLInt,
} from 'graphql';

const ArtworkType = new GraphQLObjectType({
  name: 'Artwork',
  fields: () => {
    return {
      cached,
      id: {
        type: GraphQLString,
      },
      _id: {
        type: GraphQLString,
      },
      to_s: {
        type: GraphQLString,
        resolve: ({ artist, title, date, partner }) => {
          return _.compact([
            (artist && artist.name),
            (title && `‘${title}’`),
            date,
            (partner && partner.name),
          ]).join(', ');
        },
      },
      href: {
        type: GraphQLString,
        resolve: ({ id }) => `/artwork/${id}`,
      },
      title: {
        type: GraphQLString,
      },
      category: {
        type: GraphQLString,
      },
      medium: {
        type: GraphQLString,
      },
      date: {
        type: GraphQLString,
      },
      image_rights: {
        type: GraphQLString,
      },
      series: {
        type: GraphQLString,
      },
      manufacturer: {
        type: GraphQLString,
      },
      website: {
        type: GraphQLString,
      },
      partner: {
        type: Partner.type,
        resolve: ({ partner }) => gravity(`partner/${partner.id}`),
      },
      can_share_image: {
        type: GraphQLBoolean,
        deprecationReason: 'Favor `is_`-prefixed boolean attributes',
      },
      is_shareable: {
        type: GraphQLBoolean,
        resolve: ({ can_share_image }) => can_share_image,
      },
      is_hangable: {
        type: GraphQLBoolean,
        resolve: (artwork) => {
          return (
            !_.includes(artwork.category, 'sculpture', 'installation', 'design') &&
            isTwoDimensional(artwork) &&
            !isTooBig(artwork)
          );
        },
      },
      is_contactable: {
        type: GraphQLBoolean,
        description: 'Are we able to display a contact form on artwork pages?',
        resolve: (artwork) => {
          return gravity('related/sales', { size: 1, active: true, artwork: [artwork.id] })
            .then(sales => {
              return (
                artwork.forsale &&
                !_.isEmpty(artwork.partner) &&
                !artwork.acquireable &&
                !sales.length
              );
            });
        },
      },
      is_in_auction: {
        type: GraphQLBoolean,
        description: 'Is this artwork part of an auction?',
        resolve: ({ id }) => {
          return gravity(`related/sales`, { size: 1, active: true, artwork: [id] })
            .then(sales => _.some(sales, 'is_auction'));
        },
      },
      is_for_sale: {
        type: GraphQLBoolean,
        resolve: ({ forsale }) => forsale,
      },
      is_unique: {
        type: GraphQLBoolean,
        resolve: ({ unique }) => unique,
      },
      is_sold: {
        type: GraphQLBoolean,
        resolve: ({ sold }) => sold,
      },
      is_ecommerce: {
        type: GraphQLBoolean,
        resolve: ({ ecommerce }) => ecommerce,
      },
      is_comparable_with_auction_results: {
        type: GraphQLBoolean,
        resolve: ({ comparables_count, category }) => {
          return (
            comparables_count > 0 &&
            category !== 'Architecture'
          );
        },
      },
      sale_message: {
        type: GraphQLString,
        resolve: ({ availability, price_hidden, price, sale_message }) => {
          if (availability === 'for sale' && price_hidden) return 'Contact For Price';
          if (sale_message !== 'Sold') return price || sale_message;
        },
      },
      artist: {
        type: Artist.type,
        resolve: ({ artist }) => gravity(`artist/${artist.id}`).catch(() => null),
      },
      contact_label: {
        type: GraphQLString,
        resolve: ({ partner }) => {
          return (partner.type === 'Gallery') ? 'Gallery' : 'Seller';
        },
      },
      cultural_maker: {
        type: GraphQLString,
      },
      artists: {
        type: new GraphQLList(Artist.type),
        resolve: ({ artists }) => {
          return Promise.all(
            artists.map(artist => gravity(`/artist/${artist.id}`))
          ).catch(() => null);
        },
      },
      dimensions: Dimensions,
      image: {
        type: Image.type,
        resolve: ({ images }) => {
          return Image.resolve(_.find(images, { is_default: true }) || _.first(images));
        },
      },
      images: {
        type: new GraphQLList(Image.type),
        args: {
          size: {
            type: GraphQLInt,
          },
        },
        resolve: ({ images }, { size }) => {
          return Image.resolve(size ? _.take(images, size) : images);
        },
      },
      related: {
        type: Related,
        description: 'Returns the associated Fair or Sale',
        resolve: ({ id }) => {
          const options = { artwork: [id], active: true, size: 1 };
          return Promise.all([
            gravity('related/fairs', options),
            gravity('related/sales', options),
          ]).then(([fairs, sales]) => {
            const relatedFairs = enhance(fairs, { related_type: 'Fair' });
            const relatedSales = enhance(sales, { related_type: 'Sale' });
            return _.first(_.take(relatedFairs.concat(relatedSales)));
          });
        },
      },
      highlights: {
        type: new GraphQLList(Highlight),
        description: 'Returns the highlighted shows and articles',
        resolve: ({ id, _id }) => {
          return Promise.all([
            gravity('related/shows', { artwork: [id], active: true, size: 1 }),
            positron('articles', { artwork_id: _id, published: true, limit: 1 })
              .then(articles => articles.results),
          ]).then(([shows, articles]) => {
            const highlightedShows = enhance(shows, { highlight_type: 'Show' });
            const highlightedArticles = enhance(articles, { highlight_type: 'Article' });
            return highlightedShows.concat(highlightedArticles);
          });
        },
      },
      shows: {
        type: new GraphQLList(PartnerShow.type),
        args: {
          size: {
            type: GraphQLInt,
            defaultValue: 1,
          },
          active: {
            type: GraphQLBoolean,
            defaultValue: true,
          },
        },
        resolve: ({ id }, options) => {
          return gravity('related/shows', _.defaults(options, { artwork: [id] }));
        },
      },
      sale: {
        type: Sale.type,
        resolve: ({ id }) => {
          return gravity('related/sales', { artwork: [id], active: true, size: 1 })
            .then(sales => _.first(sales));
        },
      },
      fair: {
        type: Fair.type,
        resolve: ({ id }) => {
          return gravity('related/fairs', { artwork: [id], active: true, size: 1 })
            .then(fairs => _.first(fairs));
        },
      },
      edition_of: {
        type: GraphQLString,
        resolve: ({ unique, edition_sets }) => {
          if (unique) return 'Unique';
          if (edition_sets && edition_sets.length === 1) {
            return _.first(edition_sets).editions;
          }
        },
      },
      edition_sets: {
        type: new GraphQLList(EditionSet.type),
        resolve: ({ edition_sets }) => {
          return _.filter(edition_sets, { acquireable: true });
        },
      },
      description: markdown('blurb'),
      provenance: markdown(),
      exhibition_history: markdown(),
      signature: markdown(),
      additional_information: markdown(),
      bibliography: markdown('literature'),
      tabs: Tabs,
    };
  },
});

const Artwork = {
  type: ArtworkType,
  description: 'An Artwork',
  args: {
    id: {
      type: new GraphQLNonNull(GraphQLString),
      description: 'The slug or ID of the Artwork',
    },
  },
  resolve: (root, { id }) => gravity(`artwork/${id}`),
};

export default Artwork;
<commit_msg>Return an empty Array rather than `null`<commit_after>import _ from 'lodash';
import {
  isTwoDimensional,
  isTooBig,
} from './utilities';
import {
  enhance,
} from '../../lib/helpers';
import cached from '../fields/cached';
import markdown from '../fields/markdown';
import Artist from '../artist';
import Image from '../image';
import Fair from '../fair';
import Sale from '../sale';
import PartnerShow from '../partner_show';
import Partner from '../partner';
import Related from './related';
import Highlight from './highlight';
import Tabs from './tabs';
import Dimensions from '../dimensions';
import EditionSet from '../edition_set';
import gravity from '../../lib/loaders/gravity';
import positron from '../../lib/loaders/positron';
import {
  GraphQLObjectType,
  GraphQLBoolean,
  GraphQLString,
  GraphQLNonNull,
  GraphQLList,
  GraphQLInt,
} from 'graphql';

const ArtworkType = new GraphQLObjectType({
  name: 'Artwork',
  fields: () => {
    return {
      cached,
      id: {
        type: GraphQLString,
      },
      _id: {
        type: GraphQLString,
      },
      to_s: {
        type: GraphQLString,
        resolve: ({ artist, title, date, partner }) => {
          return _.compact([
            (artist && artist.name),
            (title && `‘${title}’`),
            date,
            (partner && partner.name),
          ]).join(', ');
        },
      },
      href: {
        type: GraphQLString,
        resolve: ({ id }) => `/artwork/${id}`,
      },
      title: {
        type: GraphQLString,
      },
      category: {
        type: GraphQLString,
      },
      medium: {
        type: GraphQLString,
      },
      date: {
        type: GraphQLString,
      },
      image_rights: {
        type: GraphQLString,
      },
      series: {
        type: GraphQLString,
      },
      manufacturer: {
        type: GraphQLString,
      },
      website: {
        type: GraphQLString,
      },
      partner: {
        type: Partner.type,
        resolve: ({ partner }) => gravity(`partner/${partner.id}`),
      },
      can_share_image: {
        type: GraphQLBoolean,
        deprecationReason: 'Favor `is_`-prefixed boolean attributes',
      },
      is_shareable: {
        type: GraphQLBoolean,
        resolve: ({ can_share_image }) => can_share_image,
      },
      is_hangable: {
        type: GraphQLBoolean,
        resolve: (artwork) => {
          return (
            !_.includes(artwork.category, 'sculpture', 'installation', 'design') &&
            isTwoDimensional(artwork) &&
            !isTooBig(artwork)
          );
        },
      },
      is_contactable: {
        type: GraphQLBoolean,
        description: 'Are we able to display a contact form on artwork pages?',
        resolve: (artwork) => {
          return gravity('related/sales', { size: 1, active: true, artwork: [artwork.id] })
            .then(sales => {
              return (
                artwork.forsale &&
                !_.isEmpty(artwork.partner) &&
                !artwork.acquireable &&
                !sales.length
              );
            });
        },
      },
      is_in_auction: {
        type: GraphQLBoolean,
        description: 'Is this artwork part of an auction?',
        resolve: ({ id }) => {
          return gravity(`related/sales`, { size: 1, active: true, artwork: [id] })
            .then(sales => _.some(sales, 'is_auction'));
        },
      },
      is_for_sale: {
        type: GraphQLBoolean,
        resolve: ({ forsale }) => forsale,
      },
      is_unique: {
        type: GraphQLBoolean,
        resolve: ({ unique }) => unique,
      },
      is_sold: {
        type: GraphQLBoolean,
        resolve: ({ sold }) => sold,
      },
      is_ecommerce: {
        type: GraphQLBoolean,
        resolve: ({ ecommerce }) => ecommerce,
      },
      is_comparable_with_auction_results: {
        type: GraphQLBoolean,
        resolve: ({ comparables_count, category }) => {
          return (
            comparables_count > 0 &&
            category !== 'Architecture'
          );
        },
      },
      sale_message: {
        type: GraphQLString,
        resolve: ({ availability, price_hidden, price, sale_message }) => {
          if (availability === 'for sale' && price_hidden) return 'Contact For Price';
          if (sale_message !== 'Sold') return price || sale_message;
        },
      },
      artist: {
        type: Artist.type,
        resolve: ({ artist }) => gravity(`artist/${artist.id}`).catch(() => null),
      },
      contact_label: {
        type: GraphQLString,
        resolve: ({ partner }) => {
          return (partner.type === 'Gallery') ? 'Gallery' : 'Seller';
        },
      },
      cultural_maker: {
        type: GraphQLString,
      },
      artists: {
        type: new GraphQLList(Artist.type),
        resolve: ({ artists }) => {
          return Promise.all(
            artists.map(artist => gravity(`/artist/${artist.id}`))
          ).catch(() => []);
        },
      },
      dimensions: Dimensions,
      image: {
        type: Image.type,
        resolve: ({ images }) => {
          return Image.resolve(_.find(images, { is_default: true }) || _.first(images));
        },
      },
      images: {
        type: new GraphQLList(Image.type),
        args: {
          size: {
            type: GraphQLInt,
          },
        },
        resolve: ({ images }, { size }) => {
          return Image.resolve(size ? _.take(images, size) : images);
        },
      },
      related: {
        type: Related,
        description: 'Returns the associated Fair or Sale',
        resolve: ({ id }) => {
          const options = { artwork: [id], active: true, size: 1 };
          return Promise.all([
            gravity('related/fairs', options),
            gravity('related/sales', options),
          ]).then(([fairs, sales]) => {
            const relatedFairs = enhance(fairs, { related_type: 'Fair' });
            const relatedSales = enhance(sales, { related_type: 'Sale' });
            return _.first(_.take(relatedFairs.concat(relatedSales)));
          });
        },
      },
      highlights: {
        type: new GraphQLList(Highlight),
        description: 'Returns the highlighted shows and articles',
        resolve: ({ id, _id }) => {
          return Promise.all([
            gravity('related/shows', { artwork: [id], active: true, size: 1 }),
            positron('articles', { artwork_id: _id, published: true, limit: 1 })
              .then(articles => articles.results),
          ]).then(([shows, articles]) => {
            const highlightedShows = enhance(shows, { highlight_type: 'Show' });
            const highlightedArticles = enhance(articles, { highlight_type: 'Article' });
            return highlightedShows.concat(highlightedArticles);
          });
        },
      },
      shows: {
        type: new GraphQLList(PartnerShow.type),
        args: {
          size: {
            type: GraphQLInt,
            defaultValue: 1,
          },
          active: {
            type: GraphQLBoolean,
            defaultValue: true,
          },
        },
        resolve: ({ id }, options) => {
          return gravity('related/shows', _.defaults(options, { artwork: [id] }));
        },
      },
      sale: {
        type: Sale.type,
        resolve: ({ id }) => {
          return gravity('related/sales', { artwork: [id], active: true, size: 1 })
            .then(sales => _.first(sales));
        },
      },
      fair: {
        type: Fair.type,
        resolve: ({ id }) => {
          return gravity('related/fairs', { artwork: [id], active: true, size: 1 })
            .then(fairs => _.first(fairs));
        },
      },
      edition_of: {
        type: GraphQLString,
        resolve: ({ unique, edition_sets }) => {
          if (unique) return 'Unique';
          if (edition_sets && edition_sets.length === 1) {
            return _.first(edition_sets).editions;
          }
        },
      },
      edition_sets: {
        type: new GraphQLList(EditionSet.type),
        resolve: ({ edition_sets }) => {
          return _.filter(edition_sets, { acquireable: true });
        },
      },
      description: markdown('blurb'),
      provenance: markdown(),
      exhibition_history: markdown(),
      signature: markdown(),
      additional_information: markdown(),
      bibliography: markdown('literature'),
      tabs: Tabs,
    };
  },
});

const Artwork = {
  type: ArtworkType,
  description: 'An Artwork',
  args: {
    id: {
      type: new GraphQLNonNull(GraphQLString),
      description: 'The slug or ID of the Artwork',
    },
  },
  resolve: (root, { id }) => gravity(`artwork/${id}`),
};

export default Artwork;
<|endoftext|>


<commit_before>var _ = require("underscore");

var MAX_RESULTS = 100;

Parse.Cloud.define("readPosts", function(request, response) {
	console.log("readPosts: params=" + JSON.stringify(request.params));
	var inProfile = request.params.inProfile;
	var user = new Parse.User();
  	user.id = request.params.user;
	var searchResults = [];
	var promises = [];
	function getQuery(className) {
		return new Parse.Query(Parse.Object.extend(className));
	}

	// get the current users's posts
	function queryPost1() {
		var query = getQuery("Post");
		query.equalTo("createdBy", user).equalTo("type", "post").include("createdBy");
		return query.find();
	}

	// get posts for users the current user is following
	function queryPost2() {
		var query = getQuery("Follow");
		query.equalTo("from", user).exists("to").notEqualTo("to", user).include("to");
		return query.find().then(function(results) {
			try {
				var users = _.filter(results, function(a) { return typeof(a) != "undefined" }).map(function(a) { return a.get("to")})
				var query = getQuery("Post");
				query.equalTo("type", "post").containedIn("createdBy", users).include("createdBy");
				return query.find();
			}
			catch (e) {
				console.log(e);
			}
		});
	}
	//get the albums and groups posted by users the current user is following
	function queryPost2a() {
		var userQuery = getQuery("Follow");
		userQuery.equalTo("type", "user").equalTo("from", user).include("to");
		return userQuery.find().then(function(results) {
			try {
				var postingUsers = _.filter(results, function(a) { return typeof(a.get("to")) != "undefined"} ).map(function(b) { return b.get("to")});
				var followQuery = getQuery("Follow");
				followQuery.notEqualTo("type", "user").containedIn("from", postingUsers)
				followQuery.include("toAlbumGroup").include("toPost").include("toPost.createdBy").include("toAlbumGroup.createdBy");
				return followQuery.find();
			}
			catch (e) {
				console.log(e);
			}
		});
	}

	// get the posts blocked by this user
	function queryBlocks() {
		var blockQuery = getQuery("Block");
		blockQuery.equalTo("fromUser", user).exists("toPost").include("toPost");
		return blockQuery.find();
	}

	// get the albums/groups that the current user has posted
	function queryPost3() {
		var query = getQuery("Follow");
		query.include("toAlbumGroup").include("toPost").include("toPost.createdBy").include("toAlbumGroup.createdBy");
		query.notEqualTo("type", "user").equalTo("from", user).equalTo("to", user);
		return query.find();
	}
	promises.push(queryPost1());
	if (!inProfile) {
		// get posts for users the current user is following
		promises.push(queryPost2());
		//get the albums and groups posted by users the current user is following
		promises.push(queryPost2a());
		// get the albums/groups that the current user has posted
		promises.push(queryPost3());
	}
	queryBlocks().then(function(blockList) {
		Parse.Promise.when(promises).then(function(results) {
			var finalResults = [];
			try {
				_.each(results, function accum(r) { finalResults = finalResults.concat(r) });

				console.log("********** " + JSON.stringify(blockList));

				finalResults = _.filter(finalResults, function(post) { return _.where(blockList, {toPost: post }).length == 0 } );
				finalResults = _.sortBy(_.uniq(finalResults, function (a) { return a.id }), function(a) { return a.get("fromRollAt") || a.get("createdAt") }).reverse();
			}
			catch (e) {
				console.log(e);
			}
			if (finalResults.length > MAX_RESULTS)
				finalResults.length = MAX_RESULTS;
			response.success(finalResults);
		});
	});
});
<commit_msg>Fixed error handling in getSkin<commit_after>var _ = require("underscore");

var MAX_RESULTS = 100;

Parse.Cloud.define("readPosts", function(request, response) {
	console.log("readPosts: params=" + JSON.stringify(request.params));
	var inProfile = request.params.inProfile;
	var user = new Parse.User();
  	user.id = request.params.user;
	var searchResults = [];
	var promises = [];
	function getQuery(className) {
		return new Parse.Query(Parse.Object.extend(className));
	}

	// get the current users's posts
	function queryPost1() {
		var query = getQuery("Post");
		query.equalTo("createdBy", user).equalTo("type", "post").include("createdBy");
		return query.find();
	}

	// get posts for users the current user is following
	function queryPost2() {
		var query = getQuery("Follow");
		query.equalTo("from", user).exists("to").notEqualTo("to", user).include("to");
		return query.find().then(function(results) {
			try {
				var users = _.filter(results, function(a) { return typeof(a) != "undefined" }).map(function(a) { return a.get("to")})
				var query = getQuery("Post");
				query.equalTo("type", "post").containedIn("createdBy", users).include("createdBy");
				return query.find();
			}
			catch (e) {
				console.log(e);
			}
		});
	}
	//get the albums and groups posted by users the current user is following
	function queryPost2a() {
		var userQuery = getQuery("Follow");
		userQuery.equalTo("type", "user").equalTo("from", user).include("to");
		return userQuery.find().then(function(results) {
			try {
				var postingUsers = _.filter(results, function(a) { return typeof(a.get("to")) != "undefined"} ).map(function(b) { return b.get("to")});
				var followQuery = getQuery("Follow");
				followQuery.notEqualTo("type", "user").containedIn("from", postingUsers)
				followQuery.include("toAlbumGroup").include("toPost").include("toPost.createdBy").include("toAlbumGroup.createdBy");
				return followQuery.find();
			}
			catch (e) {
				console.log(e);
			}
		});
	}

	// get the posts blocked by this user
	function queryBlocks() {
		var blockQuery = getQuery("Block");
		blockQuery.equalTo("fromUser", user).exists("toPost").include("toPost");
		return blockQuery.find();
	}

	// get the albums/groups that the current user has posted
	function queryPost3() {
		var query = getQuery("Follow");
		query.include("toAlbumGroup").include("toPost").include("toPost.createdBy").include("toAlbumGroup.createdBy");
		query.notEqualTo("type", "user").equalTo("from", user).equalTo("to", user);
		return query.find();
	}
	promises.push(queryPost1());
	if (!inProfile) {
		// get posts for users the current user is following
		promises.push(queryPost2());
		//get the albums and groups posted by users the current user is following
		promises.push(queryPost2a());
		// get the albums/groups that the current user has posted
		promises.push(queryPost3());
	}
	queryBlocks().then(function(blockList) {
		Parse.Promise.when(promises).then(function(results) {
			var finalResults = [];
			try {
				_.each(results, function accum(r) { finalResults = finalResults.concat(r) });

				console.log("********** " + JSON.stringify(blockList));

				finalResults = _.filter(finalResults, function(post) { return _.filter(blockList, function (i) { return i.toPost.id == post.id }).length == 0 } );
				finalResults = _.sortBy(_.uniq(finalResults, function (a) { return a.id }), function(a) { return a.get("fromRollAt") || a.get("createdAt") }).reverse();
			}
			catch (e) {
				console.log(e);
			}
			if (finalResults.length > MAX_RESULTS)
				finalResults.length = MAX_RESULTS;
			response.success(finalResults);
		});
	});
});
<|endoftext|>


<commit_before>'use strict'
var router = require('express').Router();
const Promise = require("bluebird");
const path = require('path');
const fs = require('fs');

let readFile_prom = Promise.promisify(require("fs").readFile);
let here = path.join(__dirname, './')

router.get('/myheroes', function (req, res) {
    readFile_prom(here+'data.json') //, 'utf-8'
        .then(function(data){
            let content = data.toString('utf-8');
            let array = JSON.parse(content)
            res.json(array)
        })
        .catch((err) => {
            console.error(err.stack)
            res.status(500).send('Something broke')
        })
});

router.get('/myheroes/:id', function (req, res) {
    readFile_prom(here+'data.json') //, 'utf-8'
        .then(function(data){
            console.log(req.params.id);
            let numid = Number(req.params.id)
            let content = data.toString('utf-8');
            let array = JSON.parse(content)
            let query = array.find(function(obj){
                return obj.id === numid;
            })
            console.log(query);
            res.json(query)
        });
});

router.post('/myheroes', function (req, res) {
    readFile_prom(here+'data.json')
        .then(function(data){
            let newobj = {}
            let content = data.toString('utf-8');
            let array = JSON.parse(content)
            let sortRay = array.sort(function(a,b){return a.id-b.id;})
            let lastid = sortRay[sortRay.length - 1].id
            let newid = lastid + 1;
            let check = array.find(obj => {
                return obj.id === newid;
            })
            console.log(check);
            if(check === undefined){
                newobj.id = newid
                newobj.name = req.body.name
                console.log(newobj);
                array.push(newobj);
                let storeRay = JSON.stringify(array)
                fs.writeFileSync(here+'/data.json', storeRay, 'utf8', (err) => {
                    if (err) throw err;
                    console.log("data appended to file");
                });
                res.json(newobj)
            } else {
                console.log('that id already exists');
            }
        });
});

router.put('/myheroes/:id', function (req, res) {
    readFile_prom(here+'data.json')
        .then(function(data){
            console.log(req.params.id);
            let numid = Number(req.params.id)
            let content = data.toString('utf-8');
            let array = JSON.parse(content)
            let query = array.find(function(obj){
                return obj.id === numid;
            })
            console.log(query);
            console.log(req.body);
            let dex = array.indexOf(query)
            console.log('dex: ',dex);
            array.splice(dex, 1, req.body);
            console.log(array);
            let storeRay = JSON.stringify(array)
            fs.writeFileSync(here+'/data.json', storeRay, 'utf8', (err) => {
                if (err) throw err;
                console.log("data appended to file");
            });
            res.json(query)
        });
});

router.delete('/myheroes/:id', function (req, res) {
    readFile_prom(here+'data.json')
        .then(function(data){
            console.log(req.params.id);
            let numid = Number(req.params.id)
            let content = data.toString('utf-8');
            let array = JSON.parse(content)
            let query = array.find(function(obj){
                return obj.id === numid;
            })
            console.log(query);
            let dex = array.indexOf(query)
            console.log(dex);
            array.splice(dex, 1);
            console.log(array);
            let storeRay = JSON.stringify(array)
            fs.writeFileSync(here+'/data.json', storeRay, 'utf8', (err) => {
                if (err) throw err;
                console.log("data appended to file");
            });
            res.json(query)
        });
});

module.exports = router;
<commit_msg>express API put endpoint - bring response into writeFile callback. Build out conditional error handling<commit_after>'use strict'
var router = require('express').Router();
const Promise = require("bluebird");
const path = require('path');
const fs = require('fs');

let readFile_prom = Promise.promisify(require("fs").readFile);
let here = path.join(__dirname, './')

router.get('/myheroes', function (req, res) {
    readFile_prom(here+'data.json') //, 'utf-8'
        .then(function(data){
            let content = data.toString('utf-8');
            let array = JSON.parse(content)
            res.json(array)
        })
        .catch((err) => {
            console.error(err.stack)
            res.status(500).send('Something broke')
        })
});

router.get('/myheroes/:id', function (req, res) {
    readFile_prom(here+'data.json') //, 'utf-8'
        .then(function(data){
            console.log(req.params.id);
            let numid = Number(req.params.id)
            let content = data.toString('utf-8');
            let array = JSON.parse(content)
            let query = array.find(function(obj){
                return obj.id === numid;
            })
            console.log(query);
            res.json(query)
        });
});

router.post('/myheroes', function (req, res) {
    readFile_prom(here+'data.json')
        .then(function(data){
            let newobj = {}
            let content = data.toString('utf-8');
            let array = JSON.parse(content)
            let sortRay = array.sort(function(a,b){return a.id-b.id;})
            let lastid = sortRay[sortRay.length - 1].id
            let newid = lastid + 1;
            let check = array.find(obj => {
                return obj.id === newid;
            })
            console.log(check);
            if(check === undefined){
                newobj.id = newid
                newobj.name = req.body.name
                console.log(newobj);
                array.push(newobj);
                let storeRay = JSON.stringify(array)
                fs.writeFileSync(here+'/data.json', storeRay, 'utf8', (err) => {
                    if (err) throw err;
                    console.log("data appended to file");
                });
                res.json(newobj)
            } else {
                console.log('that id already exists');
            }
        });
});

router.put('/myheroes/:id', function (req, res) {
    readFile_prom(here+'data.json')
        .then(function(data){
            console.log(req.params.id);
            let numid = Number(req.params.id)
            let content = data.toString('utf-8');
            let array = JSON.parse(content)
            let query = array.find(function(obj){
                return obj.id === numid;
            })
            console.log(query);
            console.log(req.body);
            let dex = array.indexOf(query)
            console.log('dex: ',dex);
            array.splice(dex, 1, req.body);
            console.log(array);
            let storeRay = JSON.stringify(array)
            fs.writeFileSync(here+'/data.json', storeRay, 'utf8', (err) => {
                if (err) {
                    throw err;
                } else {
                    console.log("data appended to file");
                    res.json(query)
                }
            });
        });
});

router.delete('/myheroes/:id', function (req, res) {
    readFile_prom(here+'data.json')
        .then(function(data){
            console.log(req.params.id);
            let numid = Number(req.params.id)
            let content = data.toString('utf-8');
            let array = JSON.parse(content)
            let query = array.find(function(obj){
                return obj.id === numid;
            })
            console.log(query);
            let dex = array.indexOf(query)
            console.log(dex);
            array.splice(dex, 1);
            console.log(array);
            let storeRay = JSON.stringify(array)
            fs.writeFileSync(here+'/data.json', storeRay, 'utf8', (err) => {
                if (err) throw err;
                console.log("data appended to file");
            });
            res.json(query)
        });
});

module.exports = router;
<|endoftext|>