<commit_before>"use strict";

var errors = require('../../server/errors.js')
  , exec = require('child_process').exec
  , path = require('path')
  , fs = require('fs')
  , ADB = require('./adb.js')
  , helpers = require('../../helpers.js')
  , getTempPath = helpers.getTempPath
  , _ = require('underscore')
  , logger = require('../../server/logger.js').get('appium')
  , deviceCommon = require('../common.js')
  , status = require("../../server/status.js")
  , helperJarPath = path.resolve(__dirname, 'helpers')
  , async = require('async')
  , androidController = require('./android-controller.js')
  , androidCommon = require('./android-common.js')
  , UiAutomator = require('./uiautomator.js')
  , UnknownError = errors.UnknownError;

var Android = function(opts) {
  this.initialize(opts);
};

Android.prototype.initialize = function(opts) {
  this.compressXml = opts.compressXml;
  this.skipUninstall = opts.fastReset;
  this.rest = opts.rest;
  this.webSocket = opts.webSocket;
  opts.systemPort = opts.systemPort || 4724;
  opts.devicePort = opts.devicePort || 4724;
  this.opts = opts;
  this.apkPath = opts.apkPath;
  this.udid = opts.udid;
  this.appPackage = opts.appPackage;
  this.appActivity = opts.appActivity;
  this.appWaitActivity = opts.appWaitActivity || opts.appActivity;
  this.avdName = opts.avdName || null;
  this.appDeviceReadyTimeout = opts.appDeviceReadyTimeout;
  this.verbose = opts.verbose;
  this.queue = [];
  this.progress = 0;
  this.implicitWaitMs = 0;
  this.shuttingDown = false;
  this.adb = null;
  this.uiautomator = null;
  this.swipeStepsPerSec = 28;
  this.asyncWaitMs = 0;
  this.remote = null;
  this.curWindowHandle = null;
  this.didLaunch = false;
  this.launchCb = function() {};
  this.uiautomatorExitCb = function() {};
  this.capabilities = {
    platform: 'LINUX'
    , browserName: 'Android'
    , version: '4.1'
    , webStorageEnabled: false
    , takesScreenshot: true
    , javascriptEnabled: true
    , databaseEnabled: false
  };
};

Android.prototype.start = function(cb, onDie) {
  this.launchCb = cb;
  this.uiautomatorExitCb = onDie;

  if (this.adb === null) {
    // Pass Android opts and Android ref to adb.
    logger.info("Starting android appium");
    this.adb = new ADB(this.opts);
    this.uiautomator = new UiAutomator(this.adb, this.opts);
    this.uiautomator.setExitHandler(this.onUiautomatorExit.bind(this));

    logger.debug("Using fast reset? " + this.opts.fastReset);

    async.series([
      this.prepareDevice.bind(this),
      this.pushStrings.bind(this),
      this.requestXmlCompression.bind(this),
      this.uninstallApp.bind(this),
      this.installApp.bind(this),
      this.forwardPort.bind(this),
      this.pushAppium.bind(this),
      this.pushUnlock.bind(this),
      this.uiautomator.start.bind(this.uiautomator),
      this.wakeUp.bind(this),
      this.unlockScreen.bind(this),
      this.startApp.bind(this)
    ], function(err) {
      if (err) {
        this.shutdown(function() {
          this.launchCb(err);
        }.bind(this));
      } else {
        this.launchCb();
      }
    }.bind(this));
  } else {
    logger.error("Tried to start ADB when we already have one running!");
  }
};

Android.prototype.onLaunch = function(err) {
  var readyToGo = function() {
    this.didLaunch = true;
    this.launchCb();
  }.bind(this);

  var giveUp = function(err) {
    this.shutdown(function() {
      this.launchCb(err);
    }.bind(this));
  }.bind(this);

  if (err) {
    if (this.checkShouldRelaunch(err)) {
      logger.error(err);
      logger.error("Above error isn't fatal, maybe relaunching adb will help....");
      this.adb.waitForDevice(function(err) {
        if (err) return giveUp(err);
        readyToGo();
      });
    } else {
      giveUp(err);
    }
  } else {
    readyToGo();
  }
};

Android.prototype.onUiautomatorExit = function() {
  var respondToClient = function() {
    this.cleanup();
    if (!this.didLaunch) {
      var msg = "UiAutomator quit before it successfully launched";
      logger.error(msg);
      this.launchCb(new Error(msg));
      return;
    } else if (typeof this.cbForCurrentCmd === "function") {
      var error = new UnknownError("UiAutomator died while responding to " +
                                    "command, please check appium logs!");
      this.cbForCurrentCmd(error, null);
    }
    // make sure appium.js knows we crashed so it can clean up
    this.uiautomatorExitCb();
  }.bind(this);

  if (this.adb) {
    logger.info("Attempting to uninstall app");
    this.uninstallApp(function() {
      this.shuttingDown = false;
      respondToClient();
    }.bind(this));
  } else {
    logger.info("We're in uiautomator's exit callback but adb is gone already");
    respondToClient();
  }
};

Android.prototype.checkShouldRelaunch = function(launchErr) {
  if (launchErr.message === null || typeof launchErr.message === 'undefined') {
    logger.error("We're checking if we should relaunch based on something " +
                 "which isn't an error object. Check the codez!");
    return false;
  }
  var msg = launchErr.message.toString();
  var relaunchOn = [
    'Could not find a connected Android device'
    , 'Device did not become ready'
  ];
  var relaunch = false;
  _.each(relaunchOn, function(relaunchMsg) {
    relaunch = relaunch || msg.indexOf(relaunchMsg) !== -1;
  });
  return relaunch;
};

Android.prototype.pushStrings = function(cb) {
  var remotePath = '/data/local/tmp';
  var stringsJson = 'strings.json';
  if (!fs.existsSync(this.apkPath)) {
    // apk doesn't exist locally so remove old strings.json
    logger.debug("Apk doesn't exist. Removing old strings.json");
    this.adb.rimraf(remotePath + '/' + stringsJson, function(err) {
      if (err) return cb(new Error("Could not remove old strings"));
      cb();
    });
  } else {
    var stringsFromApkJarPath = path.resolve(helperJarPath,
        'strings_from_apk.jar');
    var outputPath = path.resolve(getTempPath(), this.appPackage);
    var makeStrings = ['java -jar "', stringsFromApkJarPath,
                       '" "', this.apkPath, '" "', outputPath, '"'].join('');
    logger.debug(makeStrings);
    exec(makeStrings, { maxBuffer: 524288 }, function(err, stdout, stderr) {
      if (err) {
        logger.debug(stderr);
        return cb(new Error("Could not make strings from apk"));
      }
      var jsonFile = path.resolve(outputPath, stringsJson);
      this.adb.push(jsonFile, remotePath, function(err) {
        if (err) return cb(new Error("Could not push strings.json"));
        cb();
      });
    }.bind(this));
  }
};

Android.prototype.pushAppium = function(cb) {
  logger.debug("Pushing appium bootstrap to device...");
  var binPath = path.resolve(__dirname, "..", "..", "..", "build",
      "android_bootstrap", "AppiumBootstrap.jar");
  fs.stat(binPath, function(err) {
    if (err) {
      cb(new Error("Could not find AppiumBootstrap.jar; please run " +
                   "'grunt buildAndroidBootstrap'"));
    } else {
      this.adb.push(binPath, this.remoteTempPath(), cb);
    }
  }.bind(this));
};

Android.prototype.startApp = function(cb) {
  this.adb.startApp(this.appPackage, this.appActivity, this.appWaitActivity,
      cb);
};

Android.prototype.requestXmlCompression = function(cb) {
  if (this.compressXml) {
    this.proxy(["enableCompressedLayoutHeirarchy"], cb);
  } else {
    cb();
  }
};

Android.prototype.uninstallApp = function(cb) {
  var next = function() {
    this.adb.uninstallApk(this.appPackage, function(err) {
      if (err) return cb(err);
      cb(null);
    }.bind(this));
  }.bind(this);

  if (this.skipUninstall) {
    logger.debug("Not uninstalling app since server not started with " +
               "--full-reset");
    cb();
  } else {
    next();
  }
};

Android.prototype.stop = function(cb) {
  this.shuttingDown = true;
  if (this.adb) {
    this.adb.goToHome(function() {
      this.shutdown(cb);
    }.bind(this));
  } else {
    this.shutdown(cb);
  }
};

Android.prototype.cleanup = function() {
  logger.info("Cleaning up android objects");
  this.queue = [];
  this.progress = 0;
  this.adb = null;
  this.uiautomator = null;
};

Android.prototype.shutdown = function(cb) {
  var next = function() {
    if (this.uiautomator) {
      this.uiautomator.shutdown(function() {
        this.cleanup();
        cb();
      }.bind(this));
    } else {
      this.cleanup();
      cb();
    }
  }.bind(this);

  if (this.adb) {
    this.adb.stopLogcat(function() {
      next();
    }.bind(this));
  } else {
    next();
  }
};

Android.prototype.proxy = deviceCommon.proxy;
Android.prototype.respond = deviceCommon.respond;

Android.prototype.push = function(elem) {
  this.queue.push(elem);

  var next = function() {
    if (this.queue.length <= 0) {
      return;
    }

    if (this.queue[0] === null) {
      this.queue.shift();
      return;
    }

    // Always send the command.
    if (this.progress > 0) {
      this.progress = 0;
    }

    var target = this.queue.shift()
      , action = target[0][0]
      , params = typeof target[0][1] === "undefined" ? {} : target[0][1]
      , cb = target[1];

    this.cbForCurrentCmd = cb;

    this.progress++;

    if (this.adb && !this.shuttingDown) {
      this.uiautomator.sendAction(action, params, function(response) {
        this.cbForCurrentCmd = null;
        if (typeof cb === 'function') {
          this.respond(response, cb);
        }

        // maybe there's moar work to do
        this.progress--;
        next();
      }.bind(this));
    } else {
      this.cbForCurrentCmd = null;
      var msg = "Tried to send command to non-existent Android device, " +
                 "maybe it shut down?";
      if (this.shuttingDown) {
        msg = "We're in the middle of shutting down the Android device, " +
              "so your request won't be executed. Sorry!";
      }

      this.respond({
        status: status.codes.UnknownError.code
        , value: msg
      }, cb);
      this.progress--;
      next();
    }
  }.bind(this);

  next();
};

Android.prototype.wakeUp = function(cb) {
  // requires an appium bootstrap connection loaded
  logger.debug("Waking up device if it's not alive");
  this.proxy(["wake", {}], cb);
};

Android.prototype.waitForActivityToStop = function(cb) {
  this.adb.waitForNotActivity(this.appPackage, this.appWaitActivity, cb);
};

Android.prototype.waitForCondition = deviceCommon.waitForCondition;

Android.prototype = _.extend(Android.prototype, androidController);
Android.prototype = _.extend(Android.prototype, androidCommon);

module.exports = function(opts) {
  return new Android(opts);
};

module.exports.Android = Android;
<commit_msg>(Android) Don't uninstall the app when --no-reset is used.<commit_after>"use strict";

var errors = require('../../server/errors.js')
  , exec = require('child_process').exec
  , path = require('path')
  , fs = require('fs')
  , ADB = require('./adb.js')
  , helpers = require('../../helpers.js')
  , getTempPath = helpers.getTempPath
  , _ = require('underscore')
  , logger = require('../../server/logger.js').get('appium')
  , deviceCommon = require('../common.js')
  , status = require("../../server/status.js")
  , helperJarPath = path.resolve(__dirname, 'helpers')
  , async = require('async')
  , androidController = require('./android-controller.js')
  , androidCommon = require('./android-common.js')
  , UiAutomator = require('./uiautomator.js')
  , UnknownError = errors.UnknownError;

var Android = function(opts) {
  this.initialize(opts);
};

Android.prototype.initialize = function(opts) {
  this.compressXml = opts.compressXml;
  this.skipUninstall = opts.fastReset || !opts.reset;
  this.rest = opts.rest;
  this.webSocket = opts.webSocket;
  opts.systemPort = opts.systemPort || 4724;
  opts.devicePort = opts.devicePort || 4724;
  this.opts = opts;
  this.apkPath = opts.apkPath;
  this.udid = opts.udid;
  this.appPackage = opts.appPackage;
  this.appActivity = opts.appActivity;
  this.appWaitActivity = opts.appWaitActivity || opts.appActivity;
  this.avdName = opts.avdName || null;
  this.appDeviceReadyTimeout = opts.appDeviceReadyTimeout;
  this.verbose = opts.verbose;
  this.queue = [];
  this.progress = 0;
  this.implicitWaitMs = 0;
  this.shuttingDown = false;
  this.adb = null;
  this.uiautomator = null;
  this.swipeStepsPerSec = 28;
  this.asyncWaitMs = 0;
  this.remote = null;
  this.curWindowHandle = null;
  this.didLaunch = false;
  this.launchCb = function() {};
  this.uiautomatorExitCb = function() {};
  this.capabilities = {
    platform: 'LINUX'
    , browserName: 'Android'
    , version: '4.1'
    , webStorageEnabled: false
    , takesScreenshot: true
    , javascriptEnabled: true
    , databaseEnabled: false
  };
};

Android.prototype.start = function(cb, onDie) {
  this.launchCb = cb;
  this.uiautomatorExitCb = onDie;

  if (this.adb === null) {
    // Pass Android opts and Android ref to adb.
    logger.info("Starting android appium");
    this.adb = new ADB(this.opts);
    this.uiautomator = new UiAutomator(this.adb, this.opts);
    this.uiautomator.setExitHandler(this.onUiautomatorExit.bind(this));

    logger.debug("Using fast reset? " + this.opts.fastReset);

    async.series([
      this.prepareDevice.bind(this),
      this.pushStrings.bind(this),
      this.requestXmlCompression.bind(this),
      this.uninstallApp.bind(this),
      this.installApp.bind(this),
      this.forwardPort.bind(this),
      this.pushAppium.bind(this),
      this.pushUnlock.bind(this),
      this.uiautomator.start.bind(this.uiautomator),
      this.wakeUp.bind(this),
      this.unlockScreen.bind(this),
      this.startApp.bind(this)
    ], function(err) {
      if (err) {
        this.shutdown(function() {
          this.launchCb(err);
        }.bind(this));
      } else {
        this.launchCb();
      }
    }.bind(this));
  } else {
    logger.error("Tried to start ADB when we already have one running!");
  }
};

Android.prototype.onLaunch = function(err) {
  var readyToGo = function() {
    this.didLaunch = true;
    this.launchCb();
  }.bind(this);

  var giveUp = function(err) {
    this.shutdown(function() {
      this.launchCb(err);
    }.bind(this));
  }.bind(this);

  if (err) {
    if (this.checkShouldRelaunch(err)) {
      logger.error(err);
      logger.error("Above error isn't fatal, maybe relaunching adb will help....");
      this.adb.waitForDevice(function(err) {
        if (err) return giveUp(err);
        readyToGo();
      });
    } else {
      giveUp(err);
    }
  } else {
    readyToGo();
  }
};

Android.prototype.onUiautomatorExit = function() {
  var respondToClient = function() {
    this.cleanup();
    if (!this.didLaunch) {
      var msg = "UiAutomator quit before it successfully launched";
      logger.error(msg);
      this.launchCb(new Error(msg));
      return;
    } else if (typeof this.cbForCurrentCmd === "function") {
      var error = new UnknownError("UiAutomator died while responding to " +
                                    "command, please check appium logs!");
      this.cbForCurrentCmd(error, null);
    }
    // make sure appium.js knows we crashed so it can clean up
    this.uiautomatorExitCb();
  }.bind(this);

  if (this.adb) {
    logger.info("Attempting to uninstall app");
    this.uninstallApp(function() {
      this.shuttingDown = false;
      respondToClient();
    }.bind(this));
  } else {
    logger.info("We're in uiautomator's exit callback but adb is gone already");
    respondToClient();
  }
};

Android.prototype.checkShouldRelaunch = function(launchErr) {
  if (launchErr.message === null || typeof launchErr.message === 'undefined') {
    logger.error("We're checking if we should relaunch based on something " +
                 "which isn't an error object. Check the codez!");
    return false;
  }
  var msg = launchErr.message.toString();
  var relaunchOn = [
    'Could not find a connected Android device'
    , 'Device did not become ready'
  ];
  var relaunch = false;
  _.each(relaunchOn, function(relaunchMsg) {
    relaunch = relaunch || msg.indexOf(relaunchMsg) !== -1;
  });
  return relaunch;
};

Android.prototype.pushStrings = function(cb) {
  var remotePath = '/data/local/tmp';
  var stringsJson = 'strings.json';
  if (!fs.existsSync(this.apkPath)) {
    // apk doesn't exist locally so remove old strings.json
    logger.debug("Apk doesn't exist. Removing old strings.json");
    this.adb.rimraf(remotePath + '/' + stringsJson, function(err) {
      if (err) return cb(new Error("Could not remove old strings"));
      cb();
    });
  } else {
    var stringsFromApkJarPath = path.resolve(helperJarPath,
        'strings_from_apk.jar');
    var outputPath = path.resolve(getTempPath(), this.appPackage);
    var makeStrings = ['java -jar "', stringsFromApkJarPath,
                       '" "', this.apkPath, '" "', outputPath, '"'].join('');
    logger.debug(makeStrings);
    exec(makeStrings, { maxBuffer: 524288 }, function(err, stdout, stderr) {
      if (err) {
        logger.debug(stderr);
        return cb(new Error("Could not make strings from apk"));
      }
      var jsonFile = path.resolve(outputPath, stringsJson);
      this.adb.push(jsonFile, remotePath, function(err) {
        if (err) return cb(new Error("Could not push strings.json"));
        cb();
      });
    }.bind(this));
  }
};

Android.prototype.pushAppium = function(cb) {
  logger.debug("Pushing appium bootstrap to device...");
  var binPath = path.resolve(__dirname, "..", "..", "..", "build",
      "android_bootstrap", "AppiumBootstrap.jar");
  fs.stat(binPath, function(err) {
    if (err) {
      cb(new Error("Could not find AppiumBootstrap.jar; please run " +
                   "'grunt buildAndroidBootstrap'"));
    } else {
      this.adb.push(binPath, this.remoteTempPath(), cb);
    }
  }.bind(this));
};

Android.prototype.startApp = function(cb) {
  this.adb.startApp(this.appPackage, this.appActivity, this.appWaitActivity,
      cb);
};

Android.prototype.requestXmlCompression = function(cb) {
  if (this.compressXml) {
    this.proxy(["enableCompressedLayoutHeirarchy"], cb);
  } else {
    cb();
  }
};

Android.prototype.uninstallApp = function(cb) {
  var next = function() {
    this.adb.uninstallApk(this.appPackage, function(err) {
      if (err) return cb(err);
      cb(null);
    }.bind(this));
  }.bind(this);

  if (this.skipUninstall) {
    logger.debug("Not uninstalling app since server not started with " +
               "--full-reset");
    cb();
  } else {
    next();
  }
};

Android.prototype.stop = function(cb) {
  this.shuttingDown = true;
  if (this.adb) {
    this.adb.goToHome(function() {
      this.shutdown(cb);
    }.bind(this));
  } else {
    this.shutdown(cb);
  }
};

Android.prototype.cleanup = function() {
  logger.info("Cleaning up android objects");
  this.queue = [];
  this.progress = 0;
  this.adb = null;
  this.uiautomator = null;
};

Android.prototype.shutdown = function(cb) {
  var next = function() {
    if (this.uiautomator) {
      this.uiautomator.shutdown(function() {
        this.cleanup();
        cb();
      }.bind(this));
    } else {
      this.cleanup();
      cb();
    }
  }.bind(this);

  if (this.adb) {
    this.adb.stopLogcat(function() {
      next();
    }.bind(this));
  } else {
    next();
  }
};

Android.prototype.proxy = deviceCommon.proxy;
Android.prototype.respond = deviceCommon.respond;

Android.prototype.push = function(elem) {
  this.queue.push(elem);

  var next = function() {
    if (this.queue.length <= 0) {
      return;
    }

    if (this.queue[0] === null) {
      this.queue.shift();
      return;
    }

    // Always send the command.
    if (this.progress > 0) {
      this.progress = 0;
    }

    var target = this.queue.shift()
      , action = target[0][0]
      , params = typeof target[0][1] === "undefined" ? {} : target[0][1]
      , cb = target[1];

    this.cbForCurrentCmd = cb;

    this.progress++;

    if (this.adb && !this.shuttingDown) {
      this.uiautomator.sendAction(action, params, function(response) {
        this.cbForCurrentCmd = null;
        if (typeof cb === 'function') {
          this.respond(response, cb);
        }

        // maybe there's moar work to do
        this.progress--;
        next();
      }.bind(this));
    } else {
      this.cbForCurrentCmd = null;
      var msg = "Tried to send command to non-existent Android device, " +
                 "maybe it shut down?";
      if (this.shuttingDown) {
        msg = "We're in the middle of shutting down the Android device, " +
              "so your request won't be executed. Sorry!";
      }

      this.respond({
        status: status.codes.UnknownError.code
        , value: msg
      }, cb);
      this.progress--;
      next();
    }
  }.bind(this);

  next();
};

Android.prototype.wakeUp = function(cb) {
  // requires an appium bootstrap connection loaded
  logger.debug("Waking up device if it's not alive");
  this.proxy(["wake", {}], cb);
};

Android.prototype.waitForActivityToStop = function(cb) {
  this.adb.waitForNotActivity(this.appPackage, this.appWaitActivity, cb);
};

Android.prototype.waitForCondition = deviceCommon.waitForCondition;

Android.prototype = _.extend(Android.prototype, androidController);
Android.prototype = _.extend(Android.prototype, androidCommon);

module.exports = function(opts) {
  return new Android(opts);
};

module.exports.Android = Android;
<|endoftext|>


<commit_before>(function($){

  $(".layout__slot:nth-child(1)").attr("id","calendar-list");
  $(".layout__slot:nth-child(2)").attr("id","app-list");
  $(".layout__slot:nth-child(3)").attr("id","activity-list");
  $(".layout__slot:nth-child(4)").attr("id","tweets-list");
  $(".layout__slot:nth-child(4)").attr("id","tweets-list");

  var appList = $("app-list")

  appList.prependTo(appList.parent())
  appList.removeClass();

})(jQuery)
<commit_msg>Update page-manipulation.js<commit_after>(function($){

  $(".layout__slot:nth-child(1)").attr("id","calendar-list");
  $(".layout__slot:nth-child(2)").attr("id","app-list");
  $(".layout__slot:nth-child(3)").attr("id","activity-list");
  $(".layout__slot:nth-child(4)").attr("id","tweets-list");
  $(".layout__slot:nth-child(4)").attr("id","tweets-list");

  var appList = $("#app-list")

  appList.prependTo(appList.parent())
  appList.removeClass();

})(jQuery)
<|endoftext|>


<commit_before>// ─────────────────────────────────────────────────────────────────────────────
// import
// ─────────────────────────────────────────────────────────────────────────────

import React, { PureComponent } from 'react';
import { graphql } from 'gatsby';
import { shape } from 'prop-types';

import { RootContainer, SEOContainer, HeroContainer } from '~containers';
import { Main, Section, Table, Link, Button, Modal, H2, P } from '~components';
import { metaTypes } from '~utils';

// ─────────────────────────────────────────────────────────────────────────────
// query
// ─────────────────────────────────────────────────────────────────────────────

export const query = graphql`
  {
    page: labJson(meta: { permalink: { eq: "/lab/czerman/" } }) {
      meta {
        title
        description
        permalink
        ogImage {
          ...OgImageFragment
        }
      }
      dictionary {
        id
        czech {
          grammar
          ipa
        }
        german {
          grammar
          ipa
        }
      }
    }
  }
`;

// ─────────────────────────────────────────────────────────────────────────────
// component
// ─────────────────────────────────────────────────────────────────────────────

export default class CzermanPage extends PureComponent {
  static propTypes = {
    data: shape({
      page: shape({
        ...metaTypes,
      }).isRequired,
    }).isRequired,
  };

  state = {
    openTermId:    '',
    isOpenAll:     false,
    isModalOpen:   false,
    isCardFlipped: false,
  };

  handleOpenTerm = (openTermId) => {
    this.setState({ isOpenAll: false, openTermId });
  };

  handleOpenAll = () => {
    this.setState(state => ({ isOpenAll: !state.isOpenAll }));
  };

  handleNextTerm = () => {
    this.setState((state) => {
      const currentIndex = this.props.data.page.dictionary.findIndex(
        term => term.id === state.openTermId,
      );
      return {
        isModalOpen:   true,
        isCardFlipped: false,
        openTermId:
          currentIndex === this.props.data.page.dictionary.length - 1
            ? this.props.data.page.dictionary[0].id
            : this.props.data.page.dictionary[currentIndex + 1].id,
      };
    });
  };

  handleModal = () => {
    this.setState(state => ({
      isModalOpen: !state.isModalOpen,
    }));
  };

  handleFlipCard = () => {
    this.setState(state => ({
      isCardFlipped: !state.isCardFlipped,
    }));
  };

  renderModal = () => {
    const modalTerm = this.props.data.page.dictionary.find(term => term.id === this.state.openTermId)
      || this.props.data.page.dictionary[0];
    return (
      <Modal
        innerKey={modalTerm.id}
        isOpen={this.state.isModalOpen}
        innerPadding="4rem 4rem 2rem 4rem"
        innerMinWidth="15vw"
        onClickBackground={this.handleModal}
        onClickClose={this.handleModal}
        onClickEscape={this.handleModal}
      >

Czech

{modalTerm.czech.grammar}

          Czech{' '}
          <Link to="https://en.wikipedia.org/wiki/Help:IPA/Czech">
            IPA
          </Link>

{modalTerm.czech.ipa}

German equivalent

{this.state.isCardFlipped ? modalTerm.german.grammar : '...'}

          German{' '}
          <Link to="https://en.wikipedia.org/wiki/Help:IPA/German">
            IPA
          </Link>

{this.state.isCardFlipped ? modalTerm.german.ipa : '...'}

        <Button
          onClick={this.state.isCardFlipped ? this.handleNextTerm : this.handleFlipCard}
          margin="4rem 0 0 0"
          width="100%"
        >
          {this.state.isCardFlipped ? 'Next' : 'Reveal'}
        </Button>
      </Modal>
    );
  };

  renderTable = () => (

Czech

            Czech{' '}
            <Link to="https://en.wikipedia.org/wiki/Help:IPA/Czech">
              IPA
            </Link>

German equivalent

            German{' '}
            <Link to="https://en.wikipedia.org/wiki/Help:IPA/German">
              IPA
            </Link>

        {this.props.data.page.dictionary.map(term => (

 this.handleOpenTerm(this.state.openTermId !== term.id ? term.id : '')}
          >

{term.czech.grammar}

{term.czech.ipa}

            {this.state.openTermId === term.id || this.state.isOpenAll ? (

{term.german.grammar}

            ) : (

                Reveal

            )}
            {this.state.openTermId === term.id || this.state.isOpenAll ? (

{term.german.ipa}

            ) : null}

        ))}

  );

  render() {
    return (
      <RootContainer>
        <SEOContainer meta={this.props.data.page.meta} />

          <HeroContainer title={this.props.data.page.meta.description} />

            <Button onClick={this.handleNextTerm}>Start practice</Button>
            {this.renderModal()}

            {this.renderTable()}
            <Button onClick={this.handleOpenAll}>
              {this.state.isOpenAll ? 'Hide' : 'Reveal'} all
            </Button>

      </RootContainer>
    );
  }
}
<commit_msg>update czerman page to function<commit_after>// ─────────────────────────────────────────────────────────────────────────────
// import
// ─────────────────────────────────────────────────────────────────────────────

import React, { useState } from 'react';
import { graphql } from 'gatsby';
import { shape } from 'prop-types';

import { RootContainer, SEOContainer, HeroContainer } from '~containers';
import { Main, Section, Table, Link, Button, Modal, H2, P } from '~components';
import { metaTypes } from '~utils';

// ─────────────────────────────────────────────────────────────────────────────
// query
// ─────────────────────────────────────────────────────────────────────────────

export const query = graphql`
  {
    page: labJson(meta: { permalink: { eq: "/lab/czerman/" } }) {
      meta {
        title
        description
        permalink
        ogImage {
          ...OgImageFragment
        }
      }
      dictionary {
        id
        czech {
          grammar
          ipa
        }
        german {
          grammar
          ipa
        }
      }
    }
  }
`;

// ─────────────────────────────────────────────────────────────────────────────
// component
// ─────────────────────────────────────────────────────────────────────────────

export default function CzermanPage(props) {
  const [state, setState] = useState({
    openTermId:    '',
    isOpenAll:     false,
    isModalOpen:   false,
    isCardFlipped: false,
  });

  const handleOpenTerm = (openTermId) => {
    setState({
      ...state,
      isOpenAll: false,
      openTermId,
    });
  };

  const handleOpenAll = () => {
    setState(prevState => ({ ...prevState, isOpenAll: !prevState.isOpenAll }));
  };

  const handleNextTerm = () => {
    setState((prevState) => {
      const currentIndex = props.data.page.dictionary.findIndex(
        term => term.id === prevState.openTermId,
      );
      return {
        ...prevState,
        isModalOpen:   true,
        isCardFlipped: false,
        openTermId:
          currentIndex === props.data.page.dictionary.length - 1
            ? props.data.page.dictionary[0].id
            : props.data.page.dictionary[currentIndex + 1].id,
      };
    });
  };

  const handleModal = () => {
    setState(prevState => ({
      ...prevState,
      isModalOpen: !prevState.isModalOpen,
    }));
  };

  const handleFlipCard = () => {
    setState(prevState => ({
      ...prevState,
      isCardFlipped: !prevState.isCardFlipped,
    }));
  };

  const renderModal = () => {
    const modalTerm = props.data.page.dictionary.find(term => term.id === state.openTermId)
      || props.data.page.dictionary[0];
    return (
      <Modal
        innerKey={modalTerm.id}
        isOpen={state.isModalOpen}
        innerPadding="4rem 4rem 2rem 4rem"
        innerMinWidth="15vw"
        onClickBackground={handleModal}
        onClickClose={handleModal}
        onClickEscape={handleModal}
      >

Czech

{modalTerm.czech.grammar}

          Czech <Link to="https://en.wikipedia.org/wiki/Help:IPA/Czech">IPA</Link>

{modalTerm.czech.ipa}

German equivalent

{state.isCardFlipped ? modalTerm.german.grammar : '...'}

          German <Link to="https://en.wikipedia.org/wiki/Help:IPA/German">IPA</Link>

{state.isCardFlipped ? modalTerm.german.ipa : '...'}

        <Button
          onClick={state.isCardFlipped ? handleNextTerm : handleFlipCard}
          margin="4rem 0 0 0"
          width="100%"
        >
          {state.isCardFlipped ? 'Next' : 'Reveal'}
        </Button>
      </Modal>
    );
  };

  const renderTable = () => (

Czech

            Czech <Link to="https://en.wikipedia.org/wiki/Help:IPA/Czech">IPA</Link>

German equivalent

            German <Link to="https://en.wikipedia.org/wiki/Help:IPA/German">IPA</Link>

        {props.data.page.dictionary.map(term => (

 handleOpenTerm(state.openTermId !== term.id ? term.id : '')}
          >

{term.czech.grammar}

{term.czech.ipa}

            {state.openTermId === term.id || state.isOpenAll ? (

{term.german.grammar}

            ) : (

                Reveal

            )}
            {state.openTermId === term.id || state.isOpenAll ? (

{term.german.ipa}

            ) : null}

        ))}

  );

  return (
    <RootContainer>
      <SEOContainer meta={props.data.page.meta} />

        <HeroContainer title={props.data.page.meta.description} />

          <Button onClick={handleNextTerm}>Start practice</Button>
          {renderModal()}

          {renderTable()}
          <Button onClick={handleOpenAll}>
            {state.isOpenAll ? 'Hide' : 'Reveal'} all
          </Button>

    </RootContainer>
  );
}

CzermanPage.propTypes = {
  data: shape({
    page: shape({
      ...metaTypes,
    }).isRequired,
  }).isRequired,
};
<|endoftext|>


<commit_before>// Copyright 2012 Google Inc. All Rights Reserved.

/**
 * @fileoverview Functions for dynamically loading scripts without blocking.
 * By nesting multiple calls in callback parameters, execution order of
 * the scripts can be preserved as well.
 *
 * Single script example:
 * spf.net.scripts.load(url, function() {
 *   doSomethingAfterOneScriptIsLoaded();
 * });
 *
 * Multiple script example, preserving execution order of the scripts:
 * spf.net.scripts.load(url1, function() {
 *   spf.net.scripts.load(url2, function() {
 *     doSomethingAfterTwoScriptsAreLoadedInOrder();
 *   });
 * });
 *
 * @author nicksay@google.com (Alex Nicksay)
 */

goog.provide('spf.net.scripts');

goog.require('spf.dom.dataset');
goog.require('spf.pubsub');
goog.require('spf.string');

/**
 * Evaluates a script text by dynamically creating an element and appending it
 * to the document.  A callback can be specified to execute once the script
 * has been loaded.
 *
 * @param {string} text The text of the script.
 * @param {Function=} opt_callback Callback function to execute when the
 *     script is loaded.
 */
spf.net.scripts.eval = function(text, opt_callback) {
  if (window.execScript) {
    window.execScript(text, 'JavaScript');
  } else {
    var scriptEl = document.createElement('script');
    scriptEl.appendChild(document.createTextNode(text));
    // Place the scripts in the head instead of the body to avoid errors when
    // called from the head in the first place.
    var head = document.getElementsByTagName('head')[0];
    // Use insertBefore instead of appendChild to avoid errors with loading
    // multiple scripts at once in IE.
    head.insertBefore(scriptEl, head.firstChild);
  }
  if (opt_callback) {
    opt_callback();
  }
};

/**
 * Loads a script URL by dynamically creating an element and appending it to
 * the document.  A callback can be specified to execute once the script
 * has been loaded.  Subsequent calls to load the same URL will not
 * reload the script.
 *
 * @param {string} url Url of the script.
 * @param {Function=} opt_callback Callback function to execute when the
 *     script is loaded.
 * @return {Element} The dynamically created script element.
 */
spf.net.scripts.load = function(url, opt_callback) {
  var id = spf.net.scripts.ID_PREFIX + spf.string.hashCode(url);
  var scriptEl = document.getElementById(id);
  var isLoaded = scriptEl && spf.dom.dataset.get(scriptEl, 'loaded');
  var isLoading = scriptEl && !isLoaded;
  // If the script is already loaded, execute the callback(s) immediately.
  if (isLoaded) {
    if (opt_callback) {
      opt_callback();
    }
    return scriptEl;
  }
  // Register the callback.
  if (opt_callback) {
    spf.pubsub.subscribe(id, opt_callback);
  }
  // If the script is currently loading, wait.
  if (isLoading) {
    return scriptEl;
  }
  // Otherwise, the script needs to be loaded.
  // Lexical closures allow this trickiness with the "el" variable.
  var el = spf.net.scripts.load_(url, id, function() {
    if (!spf.dom.dataset.get(el, 'loaded')) {
      spf.dom.dataset.set(el, 'loaded', 'true');
      spf.pubsub.publish(id);
      spf.pubsub.clear(id);
    }
  });
  return el;
};

/**
 * See {@link #load}.
 *
 * @param {string} url Url of the script.
 * @param {string} id Id of the script element.
 * @param {Function} fn Callback for when the script has loaded.
 * @return {Element} The dynamically created script element.
 * @private
 */
spf.net.scripts.load_ = function(url, id, fn) {
  var scriptEl = document.createElement('script');
  scriptEl.id = id;
  // Safari/Chrome and Firefox support the onload event for scripts.
  scriptEl.onload = fn;
  // IE supports the onreadystatechange event; have it call the onload
  // handler when appropriate.
  scriptEl.onreadystatechange = function() {
    switch (scriptEl.readyState) {
      case 'loaded':
      case 'complete':
        scriptEl.onload();
    }
  };
  // Set the onload and onreadystatechange handlers before setting the src
  // to avoid potential IE bug where handlers are not called.
  scriptEl.src = url;
  // Place the scripts in the head instead of the body to avoid errors when
  // called from the head in the first place.
  var head = document.getElementsByTagName('head')[0];
  // Use insertBefore instead of appendChild to avoid errors with loading
  // multiple scripts at once in IE.
  head.insertBefore(scriptEl, head.firstChild);
  return scriptEl;
};

/**
 * "Unloads" a script URL by finding a previously created element and
 * removing it from the document.  This will allow a URL to be loaded again
 * if needed.  Calling unload will stop execution of a pending callback, but
 * will not stop loading a pending script.
 *
 * @param {string} url Url of the script.
 */
spf.net.scripts.unload = function(url) {
  var id = spf.net.scripts.ID_PREFIX + spf.string.hashCode(url);
  var scriptEl = document.getElementById(id);
  if (scriptEl) {
    spf.pubsub.clear(id);
    scriptEl.parentNode.removeChild(scriptEl);
  }
};

/**
 * Parses scripts from an HTML string and executes them in the current
 * document.
 *
 * @param {string} html The complete HTML content to use as a source for
 *     updates.
 * @param {Function=} opt_callback Callback function to execute after
 *     all scripts are loaded.
 */
spf.net.scripts.execute = function(html, opt_callback) {
  if (!html) {
    return;
  }
  var queue = [];
  // Extract the scripts.
  html = html.replace(spf.net.scripts.SCRIPT_TAG_REGEXP,
      function(fullMatch, attr, text) {
        var url = attr.match(spf.net.scripts.SRC_ATTR_REGEXP);
          if (url) {
            queue.push([url[1], true]);
          } else {
            queue.push([text, false]);
          }
        return '';
      });
  // Load or evaluate the scripts in order.
  var getNextScript = function() {
    if (queue.length > 0) {
      var pair = queue.shift();
      var script = pair[0];
      var isUrl = pair[1];
      if (isUrl) {
        spf.net.scripts.load(script, getNextScript);
      } else {
        spf.net.scripts.eval(script, getNextScript);
      }
    } else {
      if (opt_callback) {
        opt_callback();
      }
    }
  };
  getNextScript();
};

/**
 * @type {string} The ID prefix for dynamically created script elements.
 * @const
 */
spf.net.scripts.ID_PREFIX = 'js-';

/**
 * Regular expression used to locate script tags in a string.
 * See {@link #execute}.
 *
 * @type {RegExp}
 * @const
 */
spf.net.scripts.SCRIPT_TAG_REGEXP =
    /\x3cscript([\s\S]*?)\x3e([\s\S]*?)\x3c\/script\x3e/ig;

/**
 * Regular expression used to locate src attributes in a string.
 * See {@link #execute}.
 *
 * @type {RegExp}
 * @const
 */
spf.net.scripts.SRC_ATTR_REGEXP = /src="([\S]+)"/;
<commit_msg>SPF: Fix minor error.<commit_after>// Copyright 2012 Google Inc. All Rights Reserved.

/**
 * @fileoverview Functions for dynamically loading scripts without blocking.
 * By nesting multiple calls in callback parameters, execution order of
 * the scripts can be preserved as well.
 *
 * Single script example:
 * spf.net.scripts.load(url, function() {
 *   doSomethingAfterOneScriptIsLoaded();
 * });
 *
 * Multiple script example, preserving execution order of the scripts:
 * spf.net.scripts.load(url1, function() {
 *   spf.net.scripts.load(url2, function() {
 *     doSomethingAfterTwoScriptsAreLoadedInOrder();
 *   });
 * });
 *
 * @author nicksay@google.com (Alex Nicksay)
 */

goog.provide('spf.net.scripts');

goog.require('spf.dom.dataset');
goog.require('spf.pubsub');
goog.require('spf.string');

/**
 * Evaluates a script text by dynamically creating an element and appending it
 * to the document.  A callback can be specified to execute once the script
 * has been loaded.
 *
 * @param {string} text The text of the script.
 * @param {Function=} opt_callback Callback function to execute when the
 *     script is loaded.
 */
spf.net.scripts.eval = function(text, opt_callback) {
  if (window.execScript) {
    window.execScript(text, 'JavaScript');
  } else {
    var scriptEl = document.createElement('script');
    scriptEl.appendChild(document.createTextNode(text));
    // Place the scripts in the head instead of the body to avoid errors when
    // called from the head in the first place.
    var head = document.getElementsByTagName('head')[0];
    // Use insertBefore instead of appendChild to avoid errors with loading
    // multiple scripts at once in IE.
    head.insertBefore(scriptEl, head.firstChild);
  }
  if (opt_callback) {
    opt_callback();
  }
};

/**
 * Loads a script URL by dynamically creating an element and appending it to
 * the document.  A callback can be specified to execute once the script
 * has been loaded.  Subsequent calls to load the same URL will not
 * reload the script.
 *
 * @param {string} url Url of the script.
 * @param {Function=} opt_callback Callback function to execute when the
 *     script is loaded.
 * @return {Element} The dynamically created script element.
 */
spf.net.scripts.load = function(url, opt_callback) {
  var id = spf.net.scripts.ID_PREFIX + spf.string.hashCode(url);
  var scriptEl = document.getElementById(id);
  var isLoaded = scriptEl && spf.dom.dataset.get(scriptEl, 'loaded');
  var isLoading = scriptEl && !isLoaded;
  // If the script is already loaded, execute the callback(s) immediately.
  if (isLoaded) {
    if (opt_callback) {
      opt_callback();
    }
    return scriptEl;
  }
  // Register the callback.
  if (opt_callback) {
    spf.pubsub.subscribe(id, opt_callback);
  }
  // If the script is currently loading, wait.
  if (isLoading) {
    return scriptEl;
  }
  // Otherwise, the script needs to be loaded.
  // Lexical closures allow this trickiness with the "el" variable.
  var el = spf.net.scripts.load_(url, id, function() {
    if (!spf.dom.dataset.get(el, 'loaded')) {
      spf.dom.dataset.set(el, 'loaded', 'true');
      spf.pubsub.publish(id);
      spf.pubsub.clear(id);
    }
  });
  return el;
};

/**
 * See {@link #load}.
 *
 * @param {string} url Url of the script.
 * @param {string} id Id of the script element.
 * @param {Function} fn Callback for when the script has loaded.
 * @return {Element} The dynamically created script element.
 * @private
 */
spf.net.scripts.load_ = function(url, id, fn) {
  var scriptEl = document.createElement('script');
  scriptEl.id = id;
  // Safari/Chrome and Firefox support the onload event for scripts.
  scriptEl.onload = fn;
  // IE supports the onreadystatechange event; have it call the onload
  // handler when appropriate.
  scriptEl.onreadystatechange = function() {
    switch (scriptEl.readyState) {
      case 'loaded':
      case 'complete':
        scriptEl.onload(null);
    }
  };
  // Set the onload and onreadystatechange handlers before setting the src
  // to avoid potential IE bug where handlers are not called.
  scriptEl.src = url;
  // Place the scripts in the head instead of the body to avoid errors when
  // called from the head in the first place.
  var head = document.getElementsByTagName('head')[0];
  // Use insertBefore instead of appendChild to avoid errors with loading
  // multiple scripts at once in IE.
  head.insertBefore(scriptEl, head.firstChild);
  return scriptEl;
};

/**
 * "Unloads" a script URL by finding a previously created element and
 * removing it from the document.  This will allow a URL to be loaded again
 * if needed.  Calling unload will stop execution of a pending callback, but
 * will not stop loading a pending script.
 *
 * @param {string} url Url of the script.
 */
spf.net.scripts.unload = function(url) {
  var id = spf.net.scripts.ID_PREFIX + spf.string.hashCode(url);
  var scriptEl = document.getElementById(id);
  if (scriptEl) {
    spf.pubsub.clear(id);
    scriptEl.parentNode.removeChild(scriptEl);
  }
};

/**
 * Parses scripts from an HTML string and executes them in the current
 * document.
 *
 * @param {string} html The complete HTML content to use as a source for
 *     updates.
 * @param {Function=} opt_callback Callback function to execute after
 *     all scripts are loaded.
 */
spf.net.scripts.execute = function(html, opt_callback) {
  if (!html) {
    return;
  }
  var queue = [];
  // Extract the scripts.
  html = html.replace(spf.net.scripts.SCRIPT_TAG_REGEXP,
      function(fullMatch, attr, text) {
        var url = attr.match(spf.net.scripts.SRC_ATTR_REGEXP);
          if (url) {
            queue.push([url[1], true]);
          } else {
            queue.push([text, false]);
          }
        return '';
      });
  // Load or evaluate the scripts in order.
  var getNextScript = function() {
    if (queue.length > 0) {
      var pair = queue.shift();
      var script = pair[0];
      var isUrl = pair[1];
      if (isUrl) {
        spf.net.scripts.load(script, getNextScript);
      } else {
        spf.net.scripts.eval(script, getNextScript);
      }
    } else {
      if (opt_callback) {
        opt_callback();
      }
    }
  };
  getNextScript();
};

/**
 * @type {string} The ID prefix for dynamically created script elements.
 * @const
 */
spf.net.scripts.ID_PREFIX = 'js-';

/**
 * Regular expression used to locate script tags in a string.
 * See {@link #execute}.
 *
 * @type {RegExp}
 * @const
 */
spf.net.scripts.SCRIPT_TAG_REGEXP =
    /\x3cscript([\s\S]*?)\x3e([\s\S]*?)\x3c\/script\x3e/ig;

/**
 * Regular expression used to locate src attributes in a string.
 * See {@link #execute}.
 *
 * @type {RegExp}
 * @const
 */
spf.net.scripts.SRC_ATTR_REGEXP = /src="([\S]+)"/;
<|endoftext|>


<commit_before>goog.provide('og.layer.WMS');

goog.require('og.inheritance');
goog.require('og.layer.XYZ');

/**
 * Used to display WMS services as tile layers on the globe.
 * @class
 * @extends {og.layer.XYZ}
 * //TODO: WMS version, format, and custom srs cpecification.
 * @param {string} name - Layer name.
 * @param {Object} options - Options:
 * @param {number} [options.opacity=1.0] - Layer opacity.
 * @param {Array.<number,number,number>} [options.transparentColor=[-1,-1,-1]] - RGB color that defines transparent color.
 * @param {number} [options.minZoom=0] - Minimal visibility zoom level.
 * @param {number} [options.maxZoom=0] - Maximal visibility zoom level.
 * @param {string} [options.attribution] - Layer attribution that displayed in the attribution area on the screen.
 * @param {boolean} [options.isBaseLayer=false] - Base layer flag.
 * @param {boolean} [options.visibility=true] - Layer visibility.
 * @param {string} options.url - WMS url source.
 * @param {number} [options.width=256] - Tile width.
 * @param {number} [options.height=256] - Tile height.
 * @param {string} options.layers - WMS layers string.
 * @param {string} [options.version="1.1.1"] - WMS version.
 * @example:
 * new og.layer.WMS("USA States", {
 *     isBaseLayer: false,
 *     url: "http://openglobus.org/geoserver/",
 *     layers: "topp:states",
 *     opacity: 0.5,
 *     zIndex: 50,
 *     attribution: 'USA states - geoserver WMS example',
 *     transparentColor: [1.0, 1.0, 1.0],
 *     version: "1.1.1",
 *     visibility: false }
 * );
 *
 * @fires og.layer.XYZ#load
 * @fires og.layer.XYZ#loadend
 */
og.layer.WMS = function (name, options) {
    og.inheritance.base(this, name, options);

    if (!options.extent) {
        this.setExtent(new og.Extent(new og.LonLat(-180.0, -90), new og.LonLat(180.0, 90)));
    }

    /**
     * WMS layers string.
     * @public
     * @type {string}
     */
    this.layers = options.layers;

    /**
     * WMS tile width.
     * @public
     * @type {number}
     */
    this.imageWidth = options.imageWidth || 256;

    /**
     * WMS tile height.
     * @public
     * @type {number}
     */
    this.imageHeight = options.imageHeight || 256;

    this.setVersion(options.version);
}

og.inheritance.extend(og.layer.WMS, og.layer.XYZ);

/**
 * Creates WMS layer {@link og.layer.WMS} instance.
 * @function
 * @param {string} name - Layer name.
 * @param {Object} options - Options.
 * @return {og.layer.WMS}
 */
og.layer.wms = function (name, options) {
    return new og.layer.WMS(name, options);
};

/**
 * Start to load tile material.
 * @public
 * @virtual
 * @param {og.planetSegment.Material} mateial
 */
og.layer.WMS.prototype.loadMaterial = function (material) {
    var seg = material.segment;
    if (!material.isLoading) {
        if (this._planet.layersActivity) {
            material.isReady = false;
            material.isLoading = true;
            if (og.layer.XYZ.__requestsCounter >= og.layer.XYZ.MAX_REQUESTS && this.counter) {
                this.pendingsQueue.push(material);
            } else {
                this._exec(material);
            }
        }
    }
};

/**
 * Creates query url.
 * @protected
 * @virtual
 * @param {og.planetSegment.Segment}
 */
og.layer.WMS.prototype._createUrl = function (segment) {
    return this.url + "wms?" + "LAYERS=" + this.layers +
            "&FORMAT=image/jpeg&SERVICE=WMS&VERSION=" + this._version + "&REQUEST=GetMap" +
            "&SRS=" + segment._projection.code +
            "&BBOX=" + this._getBbox(segment) +
            "&WIDTH=" + this.imageWidth +
            "&HEIGHT=" + this.imageHeight;
};

og.layer.WMS.prototype.setVersion = function (version) {
    if (version) {
        this._version = version;
    } else {
        this._version = "1.1.1";
    }

    if (this._version === "1.1.1") {
        this._getBbox = this._getBbox111;
    } else if (version === "1.3.0") {
        this._getBbox = this._getBbox130;
    }
};

/**
 * @private
 * @return {string}
 */
og.layer.WMS.prototype._getBbox111 = function (segment) {
    return segment._extent.getWest() + "," + segment._extent.getSouth() + "," + segment._extent.getEast() + "," + segment._extent.getNorth();
};

/**
 * @private
 * @return {string}
 */
og.layer.WMS.prototype._getBbox130 = function (segment) {
    return segment._extent.getSouth() + "," + segment._extent.getWest() + "," + segment._extent.getNorth() + "," + segment._extent.getEast();
};

/**
 * @protected
 */
og.layer.WMS.prototype._correctFullExtent = function () {
    var e = this._extent,
        em = this._extentMerc;
    var ENLARGE_MERCATOR_LON = og.mercator.POLE + 50000;
    var ENLARGE_MERCATOR_LAT = og.mercator.POLE + 50000;
    if (e.northEast.lat === 90.0) {
        em.northEast.lat = ENLARGE_MERCATOR_LAT;
    }
    if (e.northEast.lon === 180.0) {
        em.northEast.lon = ENLARGE_MERCATOR_LON;
    }
    if (e.southWest.lat === -90.0) {
        em.southWest.lat = -ENLARGE_MERCATOR_LAT;
    }
    if (e.southWest.lon === -180.0) {
        em.southWest.lon = -ENLARGE_MERCATOR_LON;
    }
};<commit_msg>WMS default version 1.1.1<commit_after>goog.provide('og.layer.WMS');

goog.require('og.inheritance');
goog.require('og.layer.XYZ');

/**
 * Used to display WMS services as tile layers on the globe.
 * @class
 * @extends {og.layer.XYZ}
 * //TODO: WMS version, format, and custom srs cpecification.
 * @param {string} name - Layer name.
 * @param {Object} options - Options:
 * @param {number} [options.opacity=1.0] - Layer opacity.
 * @param {Array.<number,number,number>} [options.transparentColor=[-1,-1,-1]] - RGB color that defines transparent color.
 * @param {number} [options.minZoom=0] - Minimal visibility zoom level.
 * @param {number} [options.maxZoom=0] - Maximal visibility zoom level.
 * @param {string} [options.attribution] - Layer attribution that displayed in the attribution area on the screen.
 * @param {boolean} [options.isBaseLayer=false] - Base layer flag.
 * @param {boolean} [options.visibility=true] - Layer visibility.
 * @param {string} options.url - WMS url source.
 * @param {number} [options.width=256] - Tile width.
 * @param {number} [options.height=256] - Tile height.
 * @param {string} options.layers - WMS layers string.
 * @param {string} [options.version="1.1.1"] - WMS version.
 * @example:
 * new og.layer.WMS("USA States", {
 *     isBaseLayer: false,
 *     url: "http://openglobus.org/geoserver/",
 *     layers: "topp:states",
 *     opacity: 0.5,
 *     zIndex: 50,
 *     attribution: 'USA states - geoserver WMS example',
 *     transparentColor: [1.0, 1.0, 1.0],
 *     version: "1.1.1",
 *     visibility: false }
 * );
 *
 * @fires og.layer.XYZ#load
 * @fires og.layer.XYZ#loadend
 */
og.layer.WMS = function (name, options) {
    og.inheritance.base(this, name, options);

    if (!options.extent) {
        this.setExtent(new og.Extent(new og.LonLat(-180.0, -90), new og.LonLat(180.0, 90)));
    }

    /**
     * WMS layers string.
     * @public
     * @type {string}
     */
    this.layers = options.layers;

    /**
     * WMS tile width.
     * @public
     * @type {number}
     */
    this.imageWidth = options.imageWidth || 256;

    /**
     * WMS tile height.
     * @public
     * @type {number}
     */
    this.imageHeight = options.imageHeight || 256;

    this.setVersion(options.version);
}

og.inheritance.extend(og.layer.WMS, og.layer.XYZ);

/**
 * Creates WMS layer {@link og.layer.WMS} instance.
 * @function
 * @param {string} name - Layer name.
 * @param {Object} options - Options.
 * @return {og.layer.WMS}
 */
og.layer.wms = function (name, options) {
    return new og.layer.WMS(name, options);
};

/**
 * Start to load tile material.
 * @public
 * @virtual
 * @param {og.planetSegment.Material} mateial
 */
og.layer.WMS.prototype.loadMaterial = function (material) {
    var seg = material.segment;
    if (!material.isLoading) {
        if (this._planet.layersActivity) {
            material.isReady = false;
            material.isLoading = true;
            if (og.layer.XYZ.__requestsCounter >= og.layer.XYZ.MAX_REQUESTS && this.counter) {
                this.pendingsQueue.push(material);
            } else {
                this._exec(material);
            }
        }
    }
};

/**
 * Creates query url.
 * @protected
 * @virtual
 * @param {og.planetSegment.Segment}
 */
og.layer.WMS.prototype._createUrl = function (segment) {
    return this.url + "wms?" + "LAYERS=" + this.layers +
            "&FORMAT=image/jpeg&SERVICE=WMS&VERSION=" + this._version + "&REQUEST=GetMap" +
            "&SRS=" + segment._projection.code +
            "&BBOX=" + this._getBbox(segment) +
            "&WIDTH=" + this.imageWidth +
            "&HEIGHT=" + this.imageHeight;
};

og.layer.WMS.prototype.setVersion = function (version) {
    if (version) {
        this._version = version;
    } else {
        this._version = "1.1.1";
    }

    if (this._version === "1.1.1") {
        this._getBbox = this._getBbox111;
    } else if (version === "1.3.0") {
        this._getBbox = this._getBbox130;
    } else {
        this._getBbox = this._getBbox111;
    }
};

/**
 * @private
 * @return {string}
 */
og.layer.WMS.prototype._getBbox111 = function (segment) {
    return segment._extent.getWest() + "," + segment._extent.getSouth() + "," + segment._extent.getEast() + "," + segment._extent.getNorth();
};

/**
 * @private
 * @return {string}
 */
og.layer.WMS.prototype._getBbox130 = function (segment) {
    return segment._extent.getSouth() + "," + segment._extent.getWest() + "," + segment._extent.getNorth() + "," + segment._extent.getEast();
};

/**
 * @protected
 */
og.layer.WMS.prototype._correctFullExtent = function () {
    var e = this._extent,
        em = this._extentMerc;
    var ENLARGE_MERCATOR_LON = og.mercator.POLE + 50000;
    var ENLARGE_MERCATOR_LAT = og.mercator.POLE + 50000;
    if (e.northEast.lat === 90.0) {
        em.northEast.lat = ENLARGE_MERCATOR_LAT;
    }
    if (e.northEast.lon === 180.0) {
        em.northEast.lon = ENLARGE_MERCATOR_LON;
    }
    if (e.southWest.lat === -90.0) {
        em.southWest.lat = -ENLARGE_MERCATOR_LAT;
    }
    if (e.southWest.lon === -180.0) {
        em.southWest.lon = -ENLARGE_MERCATOR_LON;
    }
};<|endoftext|>


<commit_before>var   path                 = require('path')
 ,    chalk                = require('chalk')
 ,    print                = console.log
 ,    clayConfigFactory    = require('./clay-config-generator')
 ,    exec                 = require('child-process-promise').exec
 ,    clayTestDataFactory  = require('./clay-test-data-generator')
 ,    clayNodePckgFactory  = require('./clay-node-package-generator')
,     fs                   = require('fs-extra-promise');

module.exports = function(serviceName, templateName) {
  const dir                          = path.resolve(process.cwd(), `${this.credentials.username}-${serviceName}`)
   ,    clayDir                      = path.resolve(__dirname, '..')
   ,    packagePath                  = path.resolve(dir, 'package.json')
   ,    clayConfigPath               = path.resolve(dir, 'clay-config.json')
   ,    testDataPath                 = path.resolve(dir, 'test-data.json')
   ,    NO_SERVICE_NAME_ERR_MSG      = chalk.white("You need a name for your service. Use:\n\n")+chalk.red("clay new <serviceName>\n")+chalk.white("\nReplace serviceName with the name of your service and do not include the angle brackets.")
   ,    INVALID_SERVICE_NAME_ERR_MSG = chalk.white("You must enter a valid name for the service. Only use lower case letters, numbers, dashes or an underscore.")
   ,    DIR_EXISTS_ERR_MSG           = chalk.white(`Looks like a directory already exists with the name of your service. Please delete this directory:`) +chalk.red(`\n\n${dir}`)+chalk.white(` \n\nand try again.`)
   ,    CREATING_SERVICE_MSG         = chalk.white('Creating your service, one moment:\n')
   ,    SERVICE_EXISTS_ERR_MSG       = chalk.white(`Couldn't create service: `)+chalk.red(`${serviceName}\n`)+chalk.white(`Service already exists in your account`)
   ,    DOCS_LINK                    = 'https://www.clay.run/docs'
   ,    SERVICE_NOT_CREATED          = chalk.white("Service was not created. Contact support@tryclay.com") + chalk.white(`\nCleaning up any files or directories that were created`)

  var clayConfigJson;
  var testDataJson;
  var packageJson;
  var commandFile;
  var templateMessages;

  // Error checking must have a valid name and no directory with that name in folder

  if(!serviceName) {
    print(NO_SERVICE_NAME_ERR_MSG)
    return
  }

  if(!/^[-0-9_a-z~]+$/.test(serviceName)) {
    print(INVALID_SERVICE_NAME_ERR_MSG)
    return
  }

  if(!fs.existsSync(dir)) fs.mkdirSync(dir)
  else {
    print(DIR_EXISTS_ERR_MSG);
    return
  }

  switch(templateName.template) {
    case 'alexa':
      clayConfigJson  = clayConfigFactory.alexaTemplate(serviceName, 'alexa');
      testDataJson = clayTestDataFactory.alexaTemplate();
      packageJson = clayNodePckgFactory.alexaTemplate(clayConfigJson, this.credentials.username);
      commandFile = path.resolve(clayDir,'templates/clay-alexa-template.js')
      templateMessages = require('../templates/clay-alexa-node-text.js');
      break;
    default:
      clayConfigJson  = clayConfigFactory.defaultTemplate(serviceName, 'microservice');
      testDataJson = clayTestDataFactory.defaultTemplate();
      packageJson = clayNodePckgFactory.defaultTemplate(clayConfigJson, this.credentials.username);
      commandFile = path.resolve(clayDir,'templates/clay-node-template.js')
      templateMessages = require('../templates/clay-microservices-node-text.js');
      break;
  }

  // Copy files that come with the package as the template
  print(CREATING_SERVICE_MSG);

  fs.copyAsync(commandFile, path.resolve(dir, `index.js`))
  .then(() => {
    return fs.writeFileAsync(clayConfigPath, JSON.stringify(clayConfigJson, null, 2));
  })
  .then(() => {
    return fs.writeFileAsync(testDataPath, JSON.stringify(testDataJson, null, 2));
  })
  .then(() => {
   return fs.writeFileAsync(packagePath, JSON.stringify(packageJson, null, 2));
  })
  .then(() => {
    return fs.mkdirAsync(path.resolve(dir, 'node_modules'));
  })
  .then(() => {
    return exec('npm install', {cwd: dir})
  })
  .then((result) => {
    // Set the directory to act on as the new service directory
    return this.deploy({mode: 'POST', dir: dir})
  })
  .then((deployResponse) => {
    var urlForService = `${this.apis.servicePage}/${this.credentials.username}/${serviceName}`
    print(templateMessages.serviceCreated(urlForService, dir, DOCS_LINK+'/tutorial'));
  })
  .catch((err) => {
    if(process.env.CLAY_DEV) console.log(err);
    if(err && !err.statusCode) print(SERVICE_NOT_CREATED)
    else if(err.statusCode == 409) print(SERVICE_EXISTS_ERR_MSG)
    else if(err.statusCode == 500) print(SERVICE_NOT_CREATED)
    fs.removeSync(dir);
  })
}
<commit_msg>don't use the username to create a new service directory<commit_after>var   path                 = require('path')
 ,    chalk                = require('chalk')
 ,    print                = console.log
 ,    clayConfigFactory    = require('./clay-config-generator')
 ,    exec                 = require('child-process-promise').exec
 ,    clayTestDataFactory  = require('./clay-test-data-generator')
 ,    clayNodePckgFactory  = require('./clay-node-package-generator')
,     fs                   = require('fs-extra-promise');

module.exports = function(serviceName, templateName) {
  const dir                          = path.resolve(process.cwd(), `${serviceName}`)
   ,    clayDir                      = path.resolve(__dirname, '..')
   ,    packagePath                  = path.resolve(dir, 'package.json')
   ,    clayConfigPath               = path.resolve(dir, 'clay-config.json')
   ,    testDataPath                 = path.resolve(dir, 'test-data.json')
   ,    NO_SERVICE_NAME_ERR_MSG      = chalk.white("You need a name for your service. Use:\n\n")+chalk.red("clay new <serviceName>\n")+chalk.white("\nReplace serviceName with the name of your service and do not include the angle brackets.")
   ,    INVALID_SERVICE_NAME_ERR_MSG = chalk.white("You must enter a valid name for the service. Only use lower case letters, numbers, dashes or an underscore.")
   ,    DIR_EXISTS_ERR_MSG           = chalk.white(`Looks like a directory already exists with the name of your service. Please delete this directory:`) +chalk.red(`\n\n${dir}`)+chalk.white(` \n\nand try again.`)
   ,    CREATING_SERVICE_MSG         = chalk.white('Creating your service, one moment:\n')
   ,    SERVICE_EXISTS_ERR_MSG       = chalk.white(`Couldn't create service: `)+chalk.red(`${serviceName}\n`)+chalk.white(`Service already exists in your account`)
   ,    DOCS_LINK                    = 'https://www.clay.run/docs'
   ,    SERVICE_NOT_CREATED          = chalk.white("Service was not created. Contact support@tryclay.com") + chalk.white(`\nCleaning up any files or directories that were created`)

  var clayConfigJson;
  var testDataJson;
  var packageJson;
  var commandFile;
  var templateMessages;

  // Error checking must have a valid name and no directory with that name in folder

  if(!serviceName) {
    print(NO_SERVICE_NAME_ERR_MSG)
    return
  }

  if(!/^[-0-9_a-z~]+$/.test(serviceName)) {
    print(INVALID_SERVICE_NAME_ERR_MSG)
    return
  }

  if(!fs.existsSync(dir)) fs.mkdirSync(dir)
  else {
    print(DIR_EXISTS_ERR_MSG);
    return
  }

  switch(templateName.template) {
    case 'alexa':
      clayConfigJson  = clayConfigFactory.alexaTemplate(serviceName, 'alexa');
      testDataJson = clayTestDataFactory.alexaTemplate();
      packageJson = clayNodePckgFactory.alexaTemplate(clayConfigJson, this.credentials.username);
      commandFile = path.resolve(clayDir,'templates/clay-alexa-template.js')
      templateMessages = require('../templates/clay-alexa-node-text.js');
      break;
    default:
      clayConfigJson  = clayConfigFactory.defaultTemplate(serviceName, 'microservice');
      testDataJson = clayTestDataFactory.defaultTemplate();
      packageJson = clayNodePckgFactory.defaultTemplate(clayConfigJson, this.credentials.username);
      commandFile = path.resolve(clayDir,'templates/clay-node-template.js')
      templateMessages = require('../templates/clay-microservices-node-text.js');
      break;
  }

  // Copy files that come with the package as the template
  print(CREATING_SERVICE_MSG);

  fs.copyAsync(commandFile, path.resolve(dir, `index.js`))
  .then(() => {
    return fs.writeFileAsync(clayConfigPath, JSON.stringify(clayConfigJson, null, 2));
  })
  .then(() => {
    return fs.writeFileAsync(testDataPath, JSON.stringify(testDataJson, null, 2));
  })
  .then(() => {
   return fs.writeFileAsync(packagePath, JSON.stringify(packageJson, null, 2));
  })
  .then(() => {
    return fs.mkdirAsync(path.resolve(dir, 'node_modules'));
  })
  .then(() => {
    return exec('npm install', {cwd: dir})
  })
  .then((result) => {
    // Set the directory to act on as the new service directory
    return this.deploy({mode: 'POST', dir: dir})
  })
  .then((deployResponse) => {
    var urlForService = `${this.apis.servicePage}/${this.credentials.username}/${serviceName}`
    print(templateMessages.serviceCreated(urlForService, dir, DOCS_LINK+'/tutorial'));
  })
  .catch((err) => {
    if(process.env.CLAY_DEV) console.log(err);
    if(err && !err.statusCode) print(SERVICE_NOT_CREATED)
    else if(err.statusCode == 409) print(SERVICE_EXISTS_ERR_MSG)
    else if(err.statusCode == 500) print(SERVICE_NOT_CREATED)
    fs.removeSync(dir);
  })
}
<|endoftext|>


<commit_before>define(function (require, exports, module) {
    "use strict";

    module.exports = {
        root: true,
        it: true
    };
});
<commit_msg>Update strings.js<commit_after>define(function (require, exports, module) {
    "use strict";

    module.exports = {
        root: true,
        it: true,
        de: true
    };
});
<|endoftext|>


<commit_before>/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
function sendTextUp(whatTriggered,whichTable) {
    var text = document.getElementById(whatTriggered.id).innerHTML;
    document.getElementById(whichTable+"Input").value = text;

}

function init() {
    initStartTable();
    initEndTable();
}

function initStartTable(){
   var myArray    = new Array();
    myArray[0] = "joe"
    myArray[1] = "jon";
    myArray[2] = "33";
    myArray[3] = "coco";
    myArray[4] = "ralph";
    myArray[5] = "sal";
    myArray[6] = "114";
    myArray[7] = "arnold5";

    var myTable= "
";
        myTable+="
";
        myTable+="
";
        myTable+="Name	";
        myTable+="

";

    for (var i=0; i<myArray.length; i++) {
        myTable+="
"+myArray[i];
        myTable+="
";
  }
   myTable+="

";
   document.getElementById('startTable').innerHTML = myTable;
}
function initEndTable(){
   var myArray    = new Array();
    myArray[0] = "joe"
    myArray[1] = "jon";
    myArray[2] = "3aifewf09233";
    myArray[3] = "coco";
    myArray[4] = "ralph";
    myArray[5] = "sal";
    myArray[6] = "awefijaowiejfo";
    myArray[7] = "arnold5";

    var myTable= "
";
        myTable+="
";
        myTable+="
";
        myTable+="Name	";
        myTable+="

";

    for (var i=0; i<myArray.length; i++) {
        myTable+="
"+myArray[i];
        myTable+="
";
  }
   myTable+="

";

   document.getElementById('endTable').innerHTML = myTable;
}
onload = init;<commit_msg>one little apostrophe thing ' screwed the entire method from not working<commit_after>/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
function sendTextUp(whatTriggered,whichTable) {
    var text = document.getElementById(whatTriggered.id).innerHTML;
    document.getElementById(whichTable+"Input").value = text;

}

function init() {
    initStartTable();
    initEndTable();
}

function initStartTable(){
   var myArray    = new Array();
    myArray[0] = "joe"
    myArray[1] = "jon";
    myArray[2] = "33";
    myArray[3] = "coco";
    myArray[4] = "ralph";
    myArray[5] = "sal";
    myArray[6] = "114";
    myArray[7] = "arnold5";

    var myTable= "
";
        myTable+="
";
        myTable+="
";
        myTable+="Name	";
        myTable+="

";

    for (var i=0; i<myArray.length; i++) {
        myTable+="
"+myArray[i];
        myTable+="
";
  }
   myTable+="

";
   document.getElementById('startTable').innerHTML = myTable;
}
function initEndTable(){
   var myArray    = new Array();
    myArray[0] = "joe"
    myArray[1] = "jon";
    myArray[2] = "3aifewf09233";
    myArray[3] = "coco";
    myArray[4] = "ralph";
    myArray[5] = "sal";
    myArray[6] = "awefijaowiejfo";
    myArray[7] = "arnold5";

    var myTable= "
";
        myTable+="
";
        myTable+="
";
        myTable+="Name	";
        myTable+="

";

    for (var i=0; i<myArray.length; i++) {
        myTable+="
"+myArray[i];
        myTable+="
";
  }
   myTable+="

";

   document.getElementById('endTable').innerHTML = myTable;
}
onload = init;<|endoftext|>


<commit_before>import BaseLfo from '../core/BaseLfo';
import complexArray from 'jsfft/lib/complex_array';
import initWindow from '../utils/windows';
import jsfft from 'jsfft';
import parameters from 'parameters';

const sqrt = Math.sqrt;

const isPowerOfTwo = function(number) {
  while ((number % 2 === 0) && number > 1)
    number = number / 2;

  return number === 1;
}

const definitions = {
  fftSize: {
    type: 'integer',
    default: 1024,
    metas: { kind: 'static' },
  },
  windowName: {
    type: 'enum',
    list: [ 'hann', 'hanning', 'hamming', 'blackman', 'blackmanharris', 'sine', 'rectangle'],
    default: 'hann',
    metas: { kind: 'static' },
  },
  outType: {
    type: 'enum',
    list: ['magnitude', 'power'],
    default: 'magnitude',
  }
}

/**
 *
 *
 *
 */
class FFT extends BaseLfo {
  constructor(options) {
    super();

    this.params = parameters(definitions, options);

    this.windowSize = null;

    if (!isPowerOfTwo(this.params.get('fftSize')))
      throw new Error('fftSize must be a power of two');
  }

  processStreamParams(prevStreamParams) {
    this.prepareStreamParams(prevStreamParams);
    // set the output frame size
    const inFrameSize = prevStreamParams.frameSize;
    const fftSize = this.params.get('fftSize');
    const outType = this.params.get('outType');
    const windowName = this.params.get('windowName');

    this.streamParams.frameSize = fftSize / 2 + 1;
    this.streamParams.frameType = 'vector';
    this.streamParams.description = ['fft bins'];
    // size of the window to apply on the input frame
    this.windowSize = (inFrameSize < fftSize) ? inFrameSize : fftSize;

    // references to populate in the window functions (cf. `initWindow`)
    this.normalizeCoefs = { linear: 0, power: 0 };
    this.window = new Float32Array(this.windowSize);

    initWindow(
      windowName, // name of the window
      this.window, // buffer populated with the window signal
      this.windowSize, // size of the window
      this.normalizeCoefs // object populated with the normalization coefs
    );

    const { linear, power } = this.normalizeCoefs;
    this.windowScale = (outType === 'magnitude') ? linear : power;
    this.complexFrame = new complexArray.ComplexArray(fftSize);
    this.windowedFrame = new Float32Array(fftSize);

    this.propagateStreamParams();
  }

  inputSignal(signal) {
    const windowSize = this.windowSize;
    const frameSize = this.streamParams.frameSize;
    const fftSize = this.params.get('fftSize');
    const outData = this.frame.data;

    // apply window on the input signal
    // @todo - test the `windowScale` factor
    for (let i = 0; i < windowSize; i++)
      this.windowedFrame[i] = signal[i] * this.window[i] * this.windowScale;

    // if windowedFrame is bigger than input signal, fill with zeros
    if (windowSize < fftSize)
      this.windowedFrame.fill(0, windowSize);

    // FFT - reuse the same buffer for fft calculations
    this.complexFrame.map((value, i) => {
      value.real = this.windowedFrame[i];
      value.imag = 0;
    });

    const complexSpectrum = this.complexFrame.FFT();
    const scale = 1 / fftSize;

    // DC index
    const realDc = complexSpectrum.real[0];
    const imagDc = complexSpectrum.imag[0];
    outData[0] = (realDc * realDc + imagDc * imagDc) * scale;

    // Nquyst index
    const realNy = complexSpectrum.real[fftSize / 2];
    const imagNy = complexSpectrum.imag[fftSize / 2];
    outData[fftSize / 2] = (realNy * realNy + imagNy * imagNy) * scale;

    // power spectrum
    for (let i = 1, j = fftSize - 1; i < fftSize / 2; i++, j--) {
      const real = complexSpectrum.real[i] + complexSpectrum.real[j];
      const imag = complexSpectrum.imag[i] - complexSpectrum.imag[j];

      outData[i] = (real * real + imag * imag) * scale;
    }

    // magnitude spectrum
    if (this.params.get('outType') === 'magnitude') {
      for (let i = 0; i < frameSize; i++)
        outData[i] = sqrt(outData[i]);
    }

    return outData;
  }

  /**
   * the first call of this method can be quite long (~4ms),
   * subsequent ones are faster (~0.5ms) for fftSize = 1024
   * If this comes from the FFT memory allocation, maybe make a dummy call of
   * `this.complexFrame.FFT` in `initialize` ?
   */
  processSignal(frame) {
    this.inputSignal(frame.data);
  }
}

export default FFT;
<commit_msg>changed FFT and fixed magnitude and power computation<commit_after>import BaseLfo from '../core/BaseLfo';
import initWindow from '../utils/windows';
import parameters from 'parameters';

// https://code.soundsoftware.ac.uk/projects/js-dsp-test/repository/entry/fft/nayuki-obj/fft.js
/*
 * Free FFT and convolution (JavaScript)
 *
 * Copyright (c) 2014 Project Nayuki
 * http://www.nayuki.io/page/free-small-fft-in-multiple-languages
 *
 * (MIT License)
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 * - The above copyright notice and this permission notice shall be included in
 *   all copies or substantial portions of the Software.
 * - The Software is provided "as is", without warranty of any kind, express or
 *   implied, including but not limited to the warranties of merchantability,
 *   fitness for a particular purpose and noninfringement. In no event shall the
 *   authors or copyright holders be liable for any claim, damages or other
 *   liability, whether in an action of contract, tort or otherwise, arising from,
 *   out of or in connection with the Software or the use or other dealings in the
 *   Software.
 *
 * Slightly restructured by Chris Cannam, cannam@all-day-breakfast.com
 *
 * @private
 */
/*
 * Construct an object for calculating the discrete Fourier transform (DFT) of
 * size n, where n is a power of 2.
 *
 * @private
 */
function FFTNayuki(n) {

  this.n = n;
  this.levels = -1;

  for (var i = 0; i < 32; i++) {
    if (1 << i == n) {
      this.levels = i;  // Equal to log2(n)
    }
  }

  if (this.levels == -1) {
    throw "Length is not a power of 2";
  }

  this.cosTable = new Array(n / 2);
  this.sinTable = new Array(n / 2);

  for (var i = 0; i < n / 2; i++) {
    this.cosTable[i] = Math.cos(2 * Math.PI * i / n);
    this.sinTable[i] = Math.sin(2 * Math.PI * i / n);
  }

  /*
   * Computes the discrete Fourier transform (DFT) of the given complex vector,
   * storing the result back into the vector.
   * The vector's length must be equal to the size n that was passed to the
   * object constructor, and this must be a power of 2. Uses the Cooley-Tukey
   * decimation-in-time radix-2 algorithm.
   *
   * @private
   */
  this.forward = function(real, imag) {
    var n = this.n;

    // Bit-reversed addressing permutation
    for (var i = 0; i < n; i++) {
      var j = reverseBits(i, this.levels);

      if (j > i) {
        var temp = real[i];
        real[i] = real[j];
        real[j] = temp;
        temp = imag[i];
        imag[i] = imag[j];
        imag[j] = temp;
      }
    }

    // Cooley-Tukey decimation-in-time radix-2 FFT
    for (var size = 2; size <= n; size *= 2) {
      var halfsize = size / 2;
      var tablestep = n / size;

      for (var i = 0; i < n; i += size) {
        for (var j = i, k = 0; j < i + halfsize; j++, k += tablestep) {
          var tpre =  real[j+halfsize] * this.cosTable[k] +
                      imag[j+halfsize] * this.sinTable[k];
          var tpim = -real[j+halfsize] * this.sinTable[k] +
                      imag[j+halfsize] * this.cosTable[k];
          real[j + halfsize] = real[j] - tpre;
          imag[j + halfsize] = imag[j] - tpim;
          real[j] += tpre;
          imag[j] += tpim;
        }
      }
    }

    // Returns the integer whose value is the reverse of the lowest 'bits'
    // bits of the integer 'x'.
    function reverseBits(x, bits) {
      var y = 0;

      for (var i = 0; i < bits; i++) {
        y = (y << 1) | (x & 1);
        x >>>= 1;
      }

      return y;
    }
  }

  /*
   * Computes the inverse discrete Fourier transform (IDFT) of the given complex
   * vector, storing the result back into the vector.
   * The vector's length must be equal to the size n that was passed to the
   * object constructor, and this must be a power of 2. This is a wrapper
   * function. This transform does not perform scaling, so the inverse is not
   * a true inverse.
   *
   * @private
   */
  this.inverse = function(real, imag) {
    forward(imag, real);
  }
}

const sqrt = Math.sqrt;

const isPowerOfTwo = function(number) {
  while ((number % 2 === 0) && number > 1)
    number = number / 2;

  return number === 1;
}

const definitions = {
  size: {
    type: 'integer',
    default: 1024,
    metas: { kind: 'static' },
  },
  window: {
    type: 'enum',
    list: ['none', 'hann', 'hanning', 'hamming', 'blackman', 'blackmanharris', 'sine', 'rectangle'],
    default: 'none',
    metas: { kind: 'static' },
  },
  mode: {
    type: 'enum',
    list: ['magnitude', 'power'], // add complex output
    default: 'magnitude',
  },
  norm: {
    type: 'enum',
    default: 'auto',
    list: ['auto', 'none', 'linear', 'power'],
  },
}

/**
 * Perfom a Fast Fourier Transform on the incomming signal.
 * This node is based on the [FFT implementation by Nayuki](https://code.soundsoftware.ac.uk/projects/js-dsp-test/repository/entry/fft/nayuki-obj/fft.js)
 *
 * @memberof module:operator
 *
 * @param {Object} options - Override default parameters.
 * @param {Number} [options.size=1024] - Size of the fft, should be a power of
 *  2. If the the frame size of the incomming signal is lower than this value,
 *  it is zero padded to match the fft size.
 * @param {String} [options.window='none'] - Name of the window applied on the
 *  incomming signal. Available windows are: 'none', 'hann', 'hanning',
 *  'hamming', 'blackman', 'blackmanharris', 'sine', 'rectangle'.
 * @param {String} [options.mode='magnitude'] - Type of the output (`magnitude`
 *  or `power`)
 * @param {String} [options.norm='auto'] - Type of normalization applied on the
 *  output. Possible values are 'auto', 'none', 'linear', 'power'. When set to
 *  `auto`, a `linear` normalization is applied on the magnitude spectrum, while
 *  a `power` normalizetion is applied on the power spectrum.
 *
 * @example
 * // assuming an `audioBuffer` exists
 * const source = new AudioInBuffer({ audioBuffer });
 *
 * const slicer = new Slicer({
 *   frameSize: 256,
 * });
 *
 * const fft = new FFT({
 *   mode: 'power',
 *   window: 'hann',
 *   norm: 'power',
 *   size: 256,
 * });
 *
 * source.connect(slicer);
 * slicer.connect(fft);
 * source.start();
 *
 * // > outputs 129 bins containing the values of the power spectrum (including
 * // > DC and Nyuist frequencies).
 *
 * @todo - check if 'rectangle' and 'none' windows are not redondant.
 * @todo - check default values for all params.
 */
class FFT extends BaseLfo {
  constructor(options) {
    super();

    this.params = parameters(definitions, options);

    this.windowSize = null;
    this.normalizeCoefs = null;
    this.window = null;
    this.real = null;
    this.imag = null;
    this.fft = null;

    if (!isPowerOfTwo(this.params.get('size')))
      throw new Error('fftSize must be a power of two');
  }

  /** @private */
  processStreamParams(prevStreamParams) {
    this.prepareStreamParams(prevStreamParams);
    // set the output frame size
    const inFrameSize = prevStreamParams.frameSize;
    const fftSize = this.params.get('size');
    const mode = this.params.get('mode');
    const norm = this.params.get('norm');
    const windowName = this.params.get('window');

    this.streamParams.frameSize = fftSize / 2 + 1;
    this.streamParams.frameType = 'vector';
    this.streamParams.description = [];
    // size of the window to apply on the input frame
    this.windowSize = (inFrameSize < fftSize) ? inFrameSize : fftSize;

    // references to populate in the window functions (cf. `initWindow`)
    this.normalizeCoefs = { linear: 0, power: 0 };
    this.window = new Float32Array(this.windowSize);

    if (windowName !== 'none') {
      initWindow(
        windowName, // name of the window
        this.window, // buffer populated with the window signal
        this.windowSize, // size of the window
        this.normalizeCoefs // object populated with the normalization coefs
      );
    } else {
      this.window.fill(1);
    }

    const { linear, power } = this.normalizeCoefs;

    switch (norm) {
      case 'none':
        this.windowNorm = 1;
        break;

      case 'linear':
        this.windowNorm = linear;
        break;

      case 'power':
        this.windowNorm = power;
        break;

      case 'auto':
        if (mode === 'magnitude')
          this.windowNorm = linear;
        else if (mode === 'power')
          this.windowNorm = power;
        else
          this.windowNorm = 1;

        break;
    }

    this.real = new Float32Array(fftSize);
    this.imag = new Float32Array(fftSize);
    this.fft = new FFTNayuki(fftSize);

    this.propagateStreamParams();
  }

  /** @private */
  inputSignal(signal) {
    const mode = this.params.get('mode');
    const windowSize = this.windowSize;
    const frameSize = this.streamParams.frameSize;
    const fftSize = this.params.get('size');
    const outData = this.frame.data;

    // apply window on the input signal and reset imag buffer
    for (let i = 0; i < windowSize; i++) {
      this.real[i] = signal[i] * this.window[i] * this.windowNorm;
      this.imag[i] = 0;
    }

    // if real is bigger than input signal, fill with zeros
    for (let i = windowSize; i < fftSize; i++) {
      this.real[i] = 0;
      this.imag[i] = 0;
    }

    this.fft.forward(this.real, this.imag);

    if (mode === 'magnitude') {
      const norm = 1 / fftSize;

      // DC index
      const realDc = this.real[0];
      const imagDc = this.imag[0];
      outData[0] = sqrt(realDc * realDc + imagDc * imagDc) * norm;

      // Nquyst index
      const realNy = this.real[fftSize / 2];
      const imagNy = this.imag[fftSize / 2];
      outData[fftSize / 2] = sqrt(realNy * realNy + imagNy * imagNy) * norm;

      // power spectrum
      for (let i = 1, j = fftSize - 1; i < fftSize / 2; i++, j--) {
        const real = 0.5 * (this.real[i] + this.real[j]);
        const imag = 0.5 * (this.imag[i] - this.imag[j]);

        outData[i] = 2 * sqrt(real * real + imag * imag) * norm;
      }

    } else if (mode === 'power') {
      const norm = 1 / (fftSize * fftSize);

      // DC index
      const realDc = this.real[0];
      const imagDc = this.imag[0];
      outData[0] = (realDc * realDc + imagDc * imagDc) * norm;

      // Nquyst index
      const realNy = this.real[fftSize / 2];
      const imagNy = this.imag[fftSize / 2];
      outData[fftSize / 2] = (realNy * realNy + imagNy * imagNy) * norm;

      // power spectrum
      for (let i = 1, j = fftSize - 1; i < fftSize / 2; i++, j--) {
        const real = 0.5 * (this.real[i] + this.real[j]);
        const imag = 0.5 * (this.imag[i] - this.imag[j]);

        outData[i] = 4 * (real * real + imag * imag) * norm;
      }
    }

    return outData;
  }

  /** @private */
  processSignal(frame) {
    this.inputSignal(frame.data);
  }
}

export default FFT;
<|endoftext|>