<commit_before>export var chondricPage = ["$compile", "$injector", function($compile, $injector) {
    var $animate;
    if ($injector.has("$animate")) {
        $animate = $injector.get("$animate");
    }

    return {
        scope: true,
        controller: "page.pageCtrl",
        link: function(scope, element, attrs) {

            // clean up the generated html a little
            element.removeAttr("ng-repeat");
            element.removeAttr("chondric-page");

            //            console.log("viewport directive");
            var page = scope.page; // = scope.$eval(attrs.chondricPage);
            if (!page) {
                element.html("
Page not found
");
                return;
            }
            element.addClass("chondric-page");

            if (page.cssClass) element.addClass(page.cssClass);
            if (page.options.cssClass) element.addClass(page.options.cssClass);

            var isBlockPage = false;
            if (!scope.$parent.blockUsed && page.isBlockPage) {
                scope.blockUsed = true;
                element.addClass("block");
                isBlockPage = true;
            }

            var template = page.template || "Template not set";

            if (page.requiredTask) {
                template = "
" + page.preloadContent + "

" + template + "
";

                scope.$watch("loadStatus.allTasks", function(tasks) {
                    if (!tasks) return;
                    scope.currentTask = null;
                    for (var i = 0; i < tasks.length; i++) {
                        var task = tasks[i];
                        if (task.active || task.error) {
                            scope.currentTask = task;
                            break;
                        }
                        if (task.key == page.requiredTask) {
                            scope.currentTask = task;
                            break;
                        }
                    }
                }, true);

            }

            if (isBlockPage) {
                // the page-content element includes any necessary padding to avoid nav elements
                // set the background on page-content rather than chondric-page so that it scrolls.
                // todo: don't add this if the template already includes a page-content element
                // custom nav components may need to be outside the scrolling area.
                template = "
" + template + "
";

                if (page.fixedTemplate) {
                    template = "

" + page.fixedTemplate + "
" + template + "
";
                } else {
                    element.addClass("scrollcontainer");
                }

                // add any popups etc here
                // modal overlay will be active if the route is not complete
                // but need to distinguish between popups and accordion sections.
                // modals div is much like subsections but applies when isSection is false.
                template += "

";
            }
            element.html(template);
            $compile(element.contents())(scope);

            element.attr("route", page.route);

            var isActive = false;
            scope.$watch("route", function(newRoute) {

                // todo: handle popup section of route

                // route is now "/main/page;/popup/first;/popup/second;/popup/current"

                if (!newRoute) return;

                var splitRoute = newRoute.split(";");
                // just ignore popups for now
                var mainRoute = splitRoute[0];

                var tc = scope.transition && scope.transition.type;

                if (!isActive && mainRoute == page.route || mainRoute.indexOf(page.route + "/") === 0) {
                    // set active for main page and parent sections
                    isActive = true;
                    if ($animate) {
                        element.addClass(tc);
                        $animate.addClass(element, "active").then(function() {
                            element.removeClass(tc);
                        });
                    } else {
                        element.addClass("active");
                    }
                } else if (isActive && mainRoute != page.route && mainRoute.indexOf(page.route + "/") !== 0) {
                    // deactivate others, only applying change if page was previously active
                    isActive = false;
                    if ($animate) {
                        element.addClass(tc);

                        $animate.removeClass(element, "active").then(function() {
                            element.removeClass(tc);
                        });
                    } else {
                        element.removeClass("active");
                    }
                } else if (scope.activePopups[scope.activePopups.length - 1] && scope.activePopups[scope.activePopups.length - 1] == page.route) {
                    element.removeClass("prev-popup");
                    element.addClass("active-popup");
                } else if (scope.activePopups[scope.activePopups.length - 2] && scope.activePopups[scope.activePopups.length - 2] == page.route) {
                    element.removeClass("active-popup");
                    element.addClass("prev-popup");
                } else {
                    element.removeClass("active-popup");
                    element.removeClass("prev-popup");
                }

            });
        }
    };
}];
<commit_msg>remove dead code<commit_after>export var chondricPage = ["$compile", "$injector", function($compile, $injector) {
    var $animate;
    if ($injector.has("$animate")) {
        $animate = $injector.get("$animate");
    }

    return {
        scope: true,
        controller: "page.pageCtrl",
        link: function(scope, element, attrs) {

            // clean up the generated html a little
            element.removeAttr("ng-repeat");
            element.removeAttr("chondric-page");

            //            console.log("viewport directive");
            var page = scope.page; // = scope.$eval(attrs.chondricPage);
            if (!page) {
                element.html("
Page not found
");
                return;
            }
            element.addClass("chondric-page");

            if (page.cssClass) element.addClass(page.cssClass);
            if (page.options.cssClass) element.addClass(page.options.cssClass);

            var isBlockPage = false;
            if (!scope.$parent.blockUsed && page.isBlockPage) {
                scope.blockUsed = true;
                element.addClass("block");
                isBlockPage = true;
            }

            var template = page.template || "Template not set";

            if (page.requiredTask) {
                template = "
" + page.preloadContent + "

" + template + "
";

                scope.$watch("loadStatus.allTasks", function(tasks) {
                    if (!tasks) return;
                    scope.currentTask = null;
                    for (var i = 0; i < tasks.length; i++) {
                        var task = tasks[i];
                        if (task.active || task.error) {
                            scope.currentTask = task;
                            break;
                        }
                        if (task.key == page.requiredTask) {
                            scope.currentTask = task;
                            break;
                        }
                    }
                }, true);

            }

            if (isBlockPage) {
                // the page-content element includes any necessary padding to avoid nav elements
                // set the background on page-content rather than chondric-page so that it scrolls.
                // todo: don't add this if the template already includes a page-content element
                // custom nav components may need to be outside the scrolling area.
                template = "
" + template + "
";

                if (page.fixedTemplate) {
                    template = "

" + page.fixedTemplate + "
" + template + "
";
                } else {
                    element.addClass("scrollcontainer");
                }

                // add any popups etc here
                // modal overlay will be active if the route is not complete
                // but need to distinguish between popups and accordion sections.
                // modals div is much like subsections but applies when isSection is false.
                template += "

";
            }
            element.html(template);
            $compile(element.contents())(scope);

            element.attr("route", page.route);

            var isActive = false;
            scope.$watch("route", function(newRoute) {

                // todo: handle popup section of route

                // route is now "/main/page;/popup/first;/popup/second;/popup/current"

                if (!newRoute) return;

                var splitRoute = newRoute.split(";");
                // just ignore popups for now
                var mainRoute = splitRoute[0];

                var tc = scope.transition && scope.transition.type;

                if (!isActive && mainRoute == page.route || mainRoute.indexOf(page.route + "/") === 0) {
                    // set active for main page and parent sections
                    isActive = true;
                    element.addClass(tc);
                    $animate.addClass(element, "active").then(function() {
                        element.removeClass(tc);
                    });
                } else if (isActive && mainRoute != page.route && mainRoute.indexOf(page.route + "/") !== 0) {
                    // deactivate others, only applying change if page was previously active
                    isActive = false;
                    element.addClass(tc);
                    $animate.removeClass(element, "active").then(function() {
                        element.removeClass(tc);
                    });
                } else if (scope.activePopups[scope.activePopups.length - 1] && scope.activePopups[scope.activePopups.length - 1] == page.route) {
                    element.removeClass("prev-popup");
                    element.addClass("active-popup");
                } else if (scope.activePopups[scope.activePopups.length - 2] && scope.activePopups[scope.activePopups.length - 2] == page.route) {
                    element.removeClass("active-popup");
                    element.addClass("prev-popup");
                } else {
                    element.removeClass("active-popup");
                    element.removeClass("prev-popup");
                }

            });
        }
    };
}];
<|endoftext|>


<commit_before>E.on('init', function() {

    var led = new Pin(2); // pin 2 is the onboard LED on my boards, it may be different pin on yours.
    var toggle = true;

    setInterval(function() {
        toggle = !toggle;
        digitalWrite(led, toggle);
    }, 1000);

});
<commit_msg>updated pin assignment<commit_after>E.on('init', function() {

    var led = NodeMCU.D4;  // onboard LED on NodeMCU board
    var toggle = true;

    setInterval(function() {
        toggle = !toggle;
        digitalWrite(led, toggle);
    }, 1000);

});
<|endoftext|>


<commit_before>const promisify = require('util').promisify;
const KubernetesClient = require('kubernetes-client');
const sleep = require("es7-sleep");
const R = require('ramda');
const sha1 = require('sha1');
const crypto = require('crypto');
const { logger } = require('@lagoon/commons/src/local-logging');
const { getOpenShiftInfoForProject, addOrUpdateEnvironment, getEnvironmentByName, addDeployment } = require('@lagoon/commons/src/api');

const { sendToLagoonLogs, initSendToLagoonLogs } = require('@lagoon/commons/src/logs');
const { consumeTasks, initSendToLagoonTasks, createTaskMonitor } = require('@lagoon/commons/src/tasks');

initSendToLagoonLogs();
initSendToLagoonTasks();

const CI = process.env.CI || "false"
const lagoonGitSafeBranch = process.env.LAGOON_GIT_SAFE_BRANCH || "master"
const lagoonVersion = process.env.LAGOON_VERSION
const overwriteKubectlBuildDeployDindImage = process.env.OVERWRITE_KUBECTL_BUILD_DEPLOY_DIND_IMAGE
const lagoonEnvironmentType = process.env.LAGOON_ENVIRONMENT_TYPE || "development"
const jwtSecret = process.env.JWTSECRET || "super-secret-string"

const messageConsumer = async msg => {
  const {
    projectName,
    branchName,
    sha,
    type,
    headBranchName,
    headSha,
    baseBranchName,
    baseSha,
    pullrequestTitle,
    promoteSourceEnvironment,
  } = JSON.parse(msg.content.toString())

  logger.verbose(`Received DeployKubernetes task for project: ${projectName}, branch: ${branchName}, sha: ${sha}`);

  const result = await getOpenShiftInfoForProject(projectName);
  const projectOpenShift = result.project

  const ocsafety = string => string.toLocaleLowerCase().replace(/[^0-9a-z-]/g,'-')

  try {
    var safeBranchName = ocsafety(branchName)
    var safeProjectName = ocsafety(projectName)

    var overlength = 58 - safeProjectName.length;
    if ( safeBranchName.length > overlength ) {
      var hash = sha1(safeBranchName).substring(0,4)

      safeBranchName = safeBranchName.substring(0, overlength-5)
      safeBranchName = safeBranchName.concat('-' + hash)
    }

    var environmentType = branchName === projectOpenShift.productionEnvironment ? 'production' : 'development';
    var gitSha = sha
    var projectId = projectOpenShift.id
    var openshiftConsole = projectOpenShift.openshift.consoleUrl.replace(/\/$/, "");
    var openshiftToken = projectOpenShift.openshift.token || ""
    var openshiftProject = projectOpenShift.openshiftProjectPattern ? projectOpenShift.openshiftProjectPattern.replace('${branch}',safeBranchName).replace('${project}', safeProjectName) : `${safeProjectName}-${safeBranchName}`
    var openshiftName = projectOpenShift.openshift.name
    var openshiftProjectUser = projectOpenShift.openshift.projectUser || ""
    var deployPrivateKey = projectOpenShift.privateKey
    var gitUrl = projectOpenShift.gitUrl
    var subfolder = projectOpenShift.subfolder || ""
    var routerPattern = projectOpenShift.openshift.routerPattern ? projectOpenShift.openshift.routerPattern.replace('${branch}',safeBranchName).replace('${project}', safeProjectName) : ""
    var prHeadBranchName = headBranchName || ""
    var prHeadSha = headSha || ""
    var prBaseBranchName = baseBranchName || ""
    var prBaseSha = baseSha || ""
    var prPullrequestTitle = pullrequestTitle || ""
    var graphqlEnvironmentType = environmentType.toUpperCase()
    var graphqlGitType = type.toUpperCase()
    var openshiftPromoteSourceProject = promoteSourceEnvironment ? `${safeProjectName}-${ocsafety(promoteSourceEnvironment)}` : ""
    // A secret which is the same across all Environments of this Lagoon Project
    var projectSecret = crypto.createHash('sha256').update(`${projectName}-${jwtSecret}`).digest('hex');
  } catch(error) {
    logger.error(`Error while loading information for project ${projectName}`)
    logger.error(error)
    throw(error)
  }

  // Deciding which git REF we would like deployed
  switch (type) {
    case "branch":
      // if we have a sha given, we use that, if not we fall back to the branch (which needs be prefixed by `origin/`
      var gitRef = gitSha ? gitSha : `origin/${branchName}`
      var deployBaseRef = branchName
      var deployHeadRef = null
      var deployTitle = null
      break;

    case "pullrequest":
      var gitRef = gitSha
      var deployBaseRef = prBaseBranchName
      var deployHeadRef = prHeadBranchName
      var deployTitle = prPullrequestTitle
      break;

    case "promote":
      var gitRef = `origin/${promoteSourceEnvironment}`
      var deployBaseRef = promoteSourceEnvironment
      var deployHeadRef = null
      var deployTitle = null
      break;
  }

  // Generates a jobconfig object
  const generateJobConfig = (buildName, secret, type, environment = {}) => {

    let buildImage = {}
    // During CI we want to use the OpenShift Registry for our build Image and use the OpenShift registry for the base Images
    if (CI == "true") {
      buildImage = "oc-build-deploy-dind:latest"
    } else if (overwriteKubectlBuildDeployDindImage) {
      // allow to overwrite the image we use via OVERWRITE_OC_BUILD_DEPLOY_DIND_IMAGE env variable
      buildImage = overwriteKubectlBuildDeployDindImage
    } else if (lagoonEnvironmentType == 'production') {
      // we are a production environment, use the amazeeio/ image with our current lagoon version
      buildImage = `amazeeio/oc-build-deploy-dind:${lagoonVersion}`
    } else {
      // we are a development enviornment, use the amazeeiolagoon image with the same branch name
      buildImage = `amazeeiolagoon/oc-build-deploy-dind:${lagoonGitSafeBranch}`
    }

    let jobconfig = {
      "apiVersion": "batch/v1",
      "kind": "Job",
      "metadata": {
          "creationTimestamp": null,
          "name": buildName,
      },
      "spec": {
        "backoffLimit": 0,
        "template": {
          "spec": {
            "restartPolicy": "Never",
            "volumes": [
              {
                name: secret,
                secret: {
                  secretName: secret,
                  defaultMode: 420
                }
              },
              {
                name: "lagoon-sshkey",
                secret: {
                  secretName: "lagoon-sshkey",
                  defaultMode: 420
                }
              }
            ],
            "containers": [
              {
                "name": "lagoon-build",
                "image": buildImage,
                "imagePullPolicy": "IfNotPresent",
                "env": [
                  {
                      "name": "TYPE",
                      "value": type
                  },
                  {
                      "name": "SOURCE_REPOSITORY",
                      "value": gitUrl
                  },
                  {
                      "name": "GIT_REF",
                      "value": gitRef
                  },
                  {
                      "name": "SUBFOLDER",
                      "value": subfolder
                  },
                  {
                      "name": "SAFE_BRANCH",
                      "value": safeBranchName
                  },
                  {
                      "name": "BRANCH",
                      "value": branchName
                  },
                  {
                      "name": "SAFE_PROJECT",
                      "value": safeProjectName
                  },
                  {
                      "name": "PROJECT",
                      "value": projectName
                  },
                  {
                      "name": "ROUTER_URL",
                      "value": routerPattern
                  },
                  {
                      "name": "ENVIRONMENT_TYPE",
                      "value": environmentType
                  },
                  {
                      "name": "OPENSHIFT_NAME",
                      "value": openshiftName
                  },
                  {
                      "name": "PROJECT_SECRET",
                      "value": projectSecret
                  }
                ],
                "volumeMounts": [
                  {
                    name: secret,
                    readOnly: true,
                    mountPath: "/var/run/secrets/lagoon/deployer"
                  },
                  {
                    name: "lagoon-sshkey",
                    readOnly: true,
                    mountPath: "/var/run/secrets/lagoon/ssh"
                  }
                ]
              }
            ]
          }
        }
      }
    }
    if (CI == "true") {
      jobconfig.spec.template.spec.containers[0].env.push({"name": "CI","value": CI})
    }
    if (type == "pullrequest") {
      jobconfig.spec.template.spec.containers[0].env.push({"name": "PR_HEAD_BRANCH","value": prHeadBranchName})
      jobconfig.spec.template.spec.containers[0].env.push({"name": "PR_HEAD_SHA","value": prHeadSha})
      jobconfig.spec.template.spec.containers[0].env.push({"name": "PR_BASE_BRANCH","value": prBaseBranchName})
      jobconfig.spec.template.spec.containers[0].env.push({"name": "PR_BASE_SHA","value": prBaseSha})
      jobconfig.spec.template.spec.containers[0].env.push({"name": "PR_TITLE","value": prPullrequestTitle})
    }
    if (type == "promote") {
      jobconfig.spec.template.spec.containers[0].env.push({"name": "PROMOTION_SOURCE_ENVIRONMENT","value": promoteSourceEnvironment})
      jobconfig.spec.template.spec.containers[0].env.push({"name": "PROMOTION_SOURCE_NAMESPACE","value": openshiftPromoteSourceProject})
    }
    if (!R.isEmpty(projectOpenShift.envVariables)) {
      jobconfig.spec.template.spec.containers[0].env.push({"name": "LAGOON_PROJECT_VARIABLES", "value": JSON.stringify(projectOpenShift.envVariables)})
    }
    if (!R.isEmpty(environment.envVariables)) {
      jobconfig.spec.template.spec.containers[0].env.push({"name": "LAGOON_ENVIRONMENT_VARIABLES", "value": JSON.stringify(environment.envVariables)})
    }
    return jobconfig
  }

  // Kubernetes API Object - needed as some API calls are done to the Kubernetes API part of OpenShift and
  // the OpenShift API does not support them.
  const kubernetes = new KubernetesClient.Core({
    url: openshiftConsole,
    insecureSkipTlsVerify: true,
    auth: {
      bearer: openshiftToken
    },
  });

  // Kubernetes API Object - needed as some API calls are done to the Kubernetes API part of OpenShift and
  // the OpenShift API does not support them.
  const kubernetesApi = new KubernetesClient.Api({
    url: openshiftConsole,
    insecureSkipTlsVerify: true,
    auth: {
      bearer: openshiftToken
    },
  });

  // kubernetes-client does not know about the OpenShift Resources, let's teach it.
  kubernetes.ns.addResource('rolebindings');

  // // If we should promote, first check if the source project does exist
  // if (type == "promote") {
  //   try {
  //     const promotionSourceProjectsGet = promisify(openshift.projects(openshiftPromoteSourceProject).get)
  //     await promotionSourceProjectsGet()
  //     logger.info(`${openshiftProject}: Promotion Source Project ${openshiftPromoteSourceProject} exists, continuing`)
  //   } catch (err) {
  //     const error = `${openshiftProject}: Promotion Source Project ${openshiftPromoteSourceProject} does not exists, ${err}`
  //     logger.error(error)
  //     throw new Error(error)
  //   }
  // }

  // Create a new Namespace if it does not exist
  let namespaceStatus = {}
  try {
    const namespacePost = promisify(kubernetes.namespace.post)
    namespaceStatus = await namespacePost({ body: {"apiVersion":"v1","kind":"Namespace","metadata":{"name":openshiftProject}} })
    logger.info(`${openshiftProject}: Namespace ${openshiftProject} created`)
  } catch (err) {
    console.log(err.code)
    // an already existing namespace  throws an error, we check if it's a 409, means it does already exist, so we ignore that error.
    if (err.code == 409) {
      logger.info(`${openshiftProject}: Namespace ${openshiftProject} already exists`)
    } else {
      logger.error(err)
      throw new Error
    }
  }

  // Update GraphQL API with information about this environment
  let environment;
  try {
    environment = await addOrUpdateEnvironment(branchName, projectId, graphqlGitType, deployBaseRef, graphqlEnvironmentType, openshiftProject, deployHeadRef, deployTitle)
    logger.info(`${openshiftProject}: Created/Updated Environment in API`)
  } catch (err) {
    logger.error(err)
    throw new Error
  }

  // Create ServiceAccount if it does not exist yet.
  try {
    logger.info(`${openshiftProject}: Check if ServiceAccount lagoon-deployer already exists`)
    const serviceaccountsGet = promisify(kubernetes.ns(openshiftProject).serviceaccounts('lagoon-deployer').get)
    projectStatus = await serviceaccountsGet()
    logger.info(`${openshiftProject}: ServiceAccount lagoon-deployer already exists, continuing`)
  } catch (err) {
    if (err.code == 404) {
      logger.info(`${openshiftProject}: ServiceAccount lagoon-deployer does not exists, creating`)
      const serviceaccountsPost = promisify(kubernetes.ns(openshiftProject).serviceaccounts.post)
      await serviceaccountsPost({ body: {"kind":"ServiceAccount","apiVersion":"v1","metadata":{"name":"lagoon-deployer"} }})
      await sleep(2000); // sleep a bit after creating the ServiceAccount for Kubernetes to create all the secrets
      const serviceaccountsRolebindingsBody = {"kind":"RoleBinding","apiVersion":"rbac.authorization.k8s.io/v1","metadata":{"name":"lagoon-deployer-admin","namespace":openshiftProject},"roleRef":{"name":"admin","kind":"ClusterRole","apiGroup":"rbac.authorization.k8s.io"},"subjects":[{"name":"lagoon-deployer","kind":"ServiceAccount","namespace":openshiftProject}]};
      const serviceaccountsRolebindingsPost = promisify(kubernetesApi.group(serviceaccountsRolebindingsBody).ns(openshiftProject).rolebindings.post)
      await serviceaccountsRolebindingsPost({ body: serviceaccountsRolebindingsBody })
    } else {
      logger.error(err)
      throw new Error
    }
  }

  // // Give the ServiceAccount access to the Promotion Source Project, it needs two roles: 'view' and 'system:image-puller'
  // if (type == "promote") {
  //   try {
  //     const promotionSourcRolebindingsGet = promisify(openshift.ns(openshiftPromoteSourceProject).rolebindings(`${openshiftProject}-lagoon-deployer-view`).get)
  //     await promotionSourcRolebindingsGet()
  //     logger.info(`${openshiftProject}: RoleBinding ${openshiftProject}-lagoon-deployer-view in ${openshiftPromoteSourceProject} does already exist, continuing`)
  //   } catch (err) {
  //     if (err.code == 404) {
  //       logger.info(`${openshiftProject}: RoleBinding ${openshiftProject}-lagoon-deployer-view in ${openshiftPromoteSourceProject} does not exists, creating`)
  //       const promotionSourceRolebindingsPost = promisify(openshift.ns(openshiftPromoteSourceProject).rolebindings.post)
  //       await promotionSourceRolebindingsPost({ body: {"kind":"RoleBinding","apiVersion":"v1","metadata":{"name":`${openshiftProject}-lagoon-deployer-view`,"namespace":openshiftPromoteSourceProject},"roleRef":{"name":"view"},"subjects":[{"name":"lagoon-deployer","kind":"ServiceAccount","namespace":openshiftProject}]}})
  //     } else {
  //       logger.error(err)
  //       throw new Error
  //     }
  //   }
  //   try {
  //     const promotionSourceRolebindingsGet = promisify(openshift.ns(openshiftPromoteSourceProject).rolebindings(`${openshiftProject}-lagoon-deployer-image-puller`).get)
  //     await promotionSourceRolebindingsGet()
  //     logger.info(`${openshiftProject}: RoleBinding ${openshiftProject}-lagoon-deployer-image-puller in ${openshiftPromoteSourceProject} does already exist, continuing`)
  //   } catch (err) {
  //     if (err.code == 404) {
  //       logger.info(`${openshiftProject}: RoleBinding ${openshiftProject}-lagoon-deployer-image-puller in ${openshiftPromoteSourceProject} does not exists, creating`)
  //       const promotionSourceRolebindingsPost = promisify(openshift.ns(openshiftPromoteSourceProject).rolebindings.post)
  //       await promotionSourceRolebindingsPost({ body: {"kind":"RoleBinding","apiVersion":"v1","metadata":{"name":`${openshiftProject}-lagoon-deployer-image-puller`,"namespace":openshiftPromoteSourceProject},"roleRef":{"name":"system:image-puller"},"subjects":[{"name":"lagoon-deployer","kind":"ServiceAccount","namespace":openshiftProject}]}})
  //     } else {
  //       logger.error(err)
  //       throw new Error
  //     }
  //   }
  // }

  // Create SSH Key Secret if not exist yet, if it does update it.
  let sshKey = {}
  const sshKeyBase64 = new Buffer(deployPrivateKey.replace(/\\n/g, "\n")).toString('base64')
  try {
    logger.info(`${openshiftProject}: Check if secret lagoon-sshkey exists`)
    const secretsGet = promisify(kubernetes.ns(openshiftProject).secrets('lagoon-sshkey').get)
    sshKey = await secretsGet()
    logger.info(`${openshiftProject}: Secret lagoon-sshkey already exists, updating`)
    const secretsPut = promisify(kubernetes.ns(openshiftProject).secrets('lagoon-sshkey').put)
    await secretsPut({ body: {"apiVersion":"v1","kind":"Secret","metadata":{"name":"lagoon-sshkey", "resourceVersion": sshKey.metadata.resourceVersion },"type":"kubernetes.io/ssh-auth","data":{"ssh-privatekey":sshKeyBase64}}})
  } catch (err) {
    if (err.code == 404) {
      logger.info(`${openshiftProject}: Secret lagoon-sshkey does not exists, creating`)
      const secretsPost = promisify(kubernetes.ns(openshiftProject).secrets.post)
      await secretsPost({ body: {"apiVersion":"v1","kind":"Secret","metadata":{"name":"lagoon-sshkey"},"type":"kubernetes.io/ssh-auth","data":{"ssh-privatekey":sshKeyBase64}}})
    } else {
      logger.error(err)
      throw new Error
    }
  }

  // Load the Token Secret Name for our created ServiceAccount
  const serviceaccountsGet = promisify(kubernetes.ns(openshiftProject).serviceaccounts("lagoon-deployer").get)
  serviceaccount = await serviceaccountsGet()
  // a ServiceAccount can have multiple secrets, we are interested in one that has starts with 'lagoon-deployer-token'
  let serviceaccountTokenSecret = '';
  for (var key in serviceaccount.secrets) {
    if(/^lagoon-deployer-token/.test(serviceaccount.secrets[key].name)) {
      serviceaccountTokenSecret = serviceaccount.secrets[key].name
      break;
    }
  }
  if (serviceaccountTokenSecret == '') {
    throw new Error(`${openshiftProject}: Could not find token secret for ServiceAccount lagoon-deployer`)
  }

  // Create Job
  let job = {};
  try {
    // @TODO: generate names with incremential numbers from the previous build number
    const buildName = `lagoon-build-${Math.random().toString(36).substring(7)}`;
    const jobConfig = generateJobConfig(buildName, serviceaccountTokenSecret, type, environment.addOrUpdateEnvironment)
    const jobPost = promisify(kubernetesApi.group(jobConfig).ns(openshiftProject).jobs.post)
    job = await jobPost({ body: jobConfig })
    logger.info(`${openshiftProject}: Created job`)
  } catch (err) {
    logger.error(err)
    throw new Error
  }

  const jobName = job.metadata.name

  try {
    const convertDateFormat = R.init;
    const apiEnvironment = await getEnvironmentByName(branchName, projectId);
    await addDeployment(jobName, "RUNNING", convertDateFormat(job.metadata.creationTimestamp), apiEnvironment.environmentByName.id, job.metadata.uid);
  } catch (error) {
    logger.error(`Could not save deployment for project ${projectId}, job ${jobName}. Message: ${error}`);
  }

  logger.verbose(`${openshiftProject}: Running build: ${jobName}`)

  const monitorPayload = {
    buildName: jobName,
    projectName: projectName,
    openshiftProject: openshiftProject,
    branchName: branchName,
    sha: sha
  }

  const taskMonitorLogs = await createTaskMonitor('builddeploy-kubernetes', monitorPayload)

  let logMessage = ''
  if (gitSha) {
    logMessage = `\`${branchName}\` (${buildName})`
  } else {
    logMessage = `\`${branchName}\``
  }

  sendToLagoonLogs('start', projectName, "", "task:builddeploy-kubernetes:start", {},
    `*[${projectName}]* ${logMessage}`
  )

}

const deathHandler = async (msg, lastError) => {
  const {
    projectName,
    branchName,
    sha
  } = JSON.parse(msg.content.toString())

  let logMessage = ''
  if (sha) {
    logMessage = `\`${branchName}\` (${sha.substring(0, 7)})`
  } else {
    logMessage = `\`${branchName}\``
  }

  sendToLagoonLogs('error', projectName, "", "task:builddeploy-kubernetes:error",  {},
`*[${projectName}]* ${logMessage} ERROR:
\`\`\`
${lastError}
\`\`\``
  )

}

const retryHandler = async (msg, error, retryCount, retryExpirationSecs) => {
  const {
    projectName,
    branchName,
    sha
  } = JSON.parse(msg.content.toString())

  let logMessage = ''
  if (sha) {
    logMessage = `\`${branchName}\` (${sha.substring(0, 7)})`
  } else {
    logMessage = `\`${branchName}\``
  }

  sendToLagoonLogs('warn', projectName, "", "task:builddeploy-kubernetes:retry", {error: error.message, msg: JSON.parse(msg.content.toString()), retryCount: retryCount},
`*[${projectName}]* ${logMessage} ERROR:
\`\`\`
${error}
\`\`\`
Retrying deployment in ${retryExpirationSecs} secs`
  )
}
consumeTasks('builddeploy-kubernetes', messageConsumer, retryHandler, deathHandler)
<commit_msg>Make kubernetesdeployqueue actually work and only run one build at a time<commit_after>const promisify = require('util').promisify;
const KubernetesClient = require('kubernetes-client');
const sleep = require('es7-sleep');
const R = require('ramda');
const sha1 = require('sha1');
const crypto = require('crypto');
const { logger } = require('@lagoon/commons/src/local-logging');
const {
  getOpenShiftInfoForProject,
  addOrUpdateEnvironment,
  getEnvironmentByName,
  updateDeployment
} = require('@lagoon/commons/src/api');

const {
  sendToLagoonLogs,
  initSendToLagoonLogs
} = require('@lagoon/commons/src/logs');
const {
  consumeTaskMonitor,
  initSendToLagoonTasks,
  createTaskMonitor
} = require('@lagoon/commons/src/tasks');

initSendToLagoonLogs();
initSendToLagoonTasks();

const messageConsumer = async msg => {
  const {
    buildName,
    projectName,
    openshiftProject,
    branchName,
    sha,
    jobConfig,
    deployment
  } = JSON.parse(msg.content.toString());

  logger.verbose(
    `Received QueueDeployKubernetes task for project: ${projectName}, branch: ${branchName}, sha: ${sha}, build: ${buildName}`
  );

  const result = await getOpenShiftInfoForProject(projectName);
  const projectOpenShift = result.project;

  const ocsafety = string =>
    string.toLocaleLowerCase().replace(/[^0-9a-z-]/g, '-');

  try {
    var openshiftConsole = projectOpenShift.openshift.consoleUrl.replace(
      /\/$/,
      ''
    );
    var openshiftToken = projectOpenShift.openshift.token || '';
    var gitSha = sha;
  } catch (error) {
    logger.error(`Error while loading information for project ${projectName}`);
    logger.error(error);
    throw error;
  }

  // Kubernetes API Object - needed as some API calls are done to the Kubernetes API part of OpenShift and
  // the OpenShift API does not support them.
  const kubernetesApi = new KubernetesClient.Api({
    url: openshiftConsole,
    insecureSkipTlsVerify: true,
    auth: {
      bearer: openshiftToken
    }
  });

  const kubernetesBatchApi = new KubernetesClient.Batch({
    url: openshiftConsole,
    insecureSkipTlsVerify: true,
    auth: {
      bearer: openshiftToken
    }
  });

  // Check for currently active builds
  let activeBuilds;
  try {
    const jobsGet = promisify(
      kubernetesBatchApi.namespaces(openshiftProject).jobs.get
    );
    namespaceJobs = await jobsGet();

    activeBuilds = R.pipe(
      R.propOr([], 'items'),
      R.filter(R.pathSatisfies(R.lt(0), ['status', 'active'])),
    )(namespaceJobs);
  } catch (err) {
    logger.error(
      `${openshiftProject}: Unexpected error loading jobs, unable to build ${buildName}: ${err}`
    );
    return;
  }

  // If there are current builds running, delay this one
  if (!R.isEmpty(activeBuilds)) {
    logger.info(`Delaying build of ${buildName} due to ${activeBuilds.length} pending builds`);
    throw new Error('requeue');
  }

  // Load job, if not exists create
  let jobInfo;
  try {
    const jobsGet = promisify(
      kubernetesBatchApi.namespaces(openshiftProject).jobs(buildName).get
    );
    jobInfo = await jobsGet();
    logger.info(`${openshiftProject}: Build ${buildName} already exists`);
  } catch (err) {
    if (err.code == 404) {
      const jobPost = promisify(
        kubernetesApi.group(jobConfig).ns(openshiftProject).jobs.post
      );
      jobInfo = await jobPost({ body: jobConfig });
      logger.info(`${openshiftProject}: Created build ${buildName}`);
    } else {
      logger.error(
        `${openshiftProject}: Unexpected error loading job, unable to build ${buildName}: ${err}`
      );
      return;
    }
  }

  const jobName = jobInfo.metadata.name;

  // Update the deployment with the job id
  try {
    await updateDeployment(deployment.id, {
      status: 'PENDING',
      remoteId: jobInfo.metadata.uid
    });
  } catch (error) {
    logger.error(
      `Could not update deployment ${projectName} ${buildName}. Message: ${error}`
    );
  }

  const monitorPayload = {
    buildName: jobName,
    projectName,
    openshiftProject,
    branchName,
    sha
  };

  const taskMonitorLogs = await createTaskMonitor(
    'builddeploy-kubernetes',
    monitorPayload
  );

  let logMessage = '';
  if (gitSha) {
    logMessage = `\`${branchName}\` (${buildName})`;
  } else {
    logMessage = `\`${branchName}\``;
  }

  sendToLagoonLogs(
    'start',
    projectName,
    '',
    'task:builddeploy-kubernetes:start',
    {},
    `*[${projectName}]* ${logMessage}`
  );
};

const deathHandler = async (msg, lastError) => {
  const {
    buildName,
    projectName,
    openshiftProject,
    branchName,
    sha,
    jobConfig
  } = JSON.parse(msg.content.toString());

  let logMessage = '';
  if (sha) {
    logMessage = `\`${branchName}\` (${sha.substring(0, 7)})`;
  } else {
    logMessage = `\`${branchName}\``;
  }

  const task = 'task:builddeploy-kubernetes:error';
  const errorMsg = `*[${projectName}]* ${logMessage} Build \`${buildName}\` ERROR: \`\`\` ${lastError} \`\`\``;
  sendToLagoonLogs('error', projectName, '', task, {}, errorMsg);
};

consumeTaskMonitor('queuedeploy-kubernetes', messageConsumer, deathHandler);
<|endoftext|>


<commit_before>google.load("visualization", "1", {packages:["corechart"]});
google.setOnLoadCallback(drawChart);
function drawChart() {
    var labels = overview_data['experiment_types'];
    labels.unshift('Mutant Type');
    var all_data = [labels];
    //Prepare Data
    for(var j=0; j < overview_data['mutant_types'].length; j++) {
        var mutant = overview_data['mutant_types'][j];
        var new_row = overview_data['mutant_to_count'][mutant];
        new_row.unshift(mutant);
        all_data.push(new_row);
    };

    var title;
    var hAxis;
    if(class_type == 'PHENOTYPE') {
        title = 'Genes by mutant type and experiment type';
        hAxis = '# of Genes';
    }
    else if(class_type == 'LOCUS') {
        title = 'Phenotypes by mutant type and experiment type';
        hAxis = '# of Phenotypes';
    }
    var data = google.visualization.arrayToDataTable(all_data);
    var options = {
        'legend': {'position': 'top', title: 'Experiment Type'},
        'title': title,
        'vAxis': {title: 'Mutant Type'},
        'hAxis': {title: hAxis},
        'chartArea': {left:110,top:50,width:"60%",height:"75%"},
        'dataOpacity':.75,
        'colors': ["#7FBF7B", "#AF8DC3", "#1F78B4"],
        'backgroundColor': 'transparent'
    };

    var chart = new google.visualization.BarChart(document.getElementById('mutant_experiment_chart'));
    chart.draw(data, options);

    //Strain Chart
    var strain_all_data = [['Strain', 'Phenotypes']];
    //Prepare Data
    for(var j=0; j < overview_data['strain_list'].length; j++) {
        var strain = overview_data['strain_list'][j];
        var new_row = [strain, overview_data['strain_to_count'][strain]];
        strain_all_data.push(new_row);
    };

    var strain_data = google.visualization.arrayToDataTable(strain_all_data);
    var strain_options = {
        'legend': {'position': 'none'},
        'title': 'Phenotypes in different strain backgrounds',
        'vAxis': {title: hAxis},
        'hAxis': {title: 'Strain'},
        'dataOpacity':.75,
        'colors': ["#1F78B4"],
        'chartArea': {left:50,top:50,width:"80%",height:"50%"},
        'backgroundColor': 'transparent'
    };

    var strain_chart = new google.visualization.ColumnChart(document.getElementById('strain_chart'));
    strain_chart.draw(strain_data, strain_options);
}<commit_msg>Fixed title on phenotype graphs.<commit_after>google.load("visualization", "1", {packages:["corechart"]});
google.setOnLoadCallback(drawChart);
function drawChart() {
    var labels = overview_data['experiment_types'];
    labels.unshift('Mutant Type');
    var all_data = [labels];
    //Prepare Data
    for(var j=0; j < overview_data['mutant_types'].length; j++) {
        var mutant = overview_data['mutant_types'][j];
        var new_row = overview_data['mutant_to_count'][mutant];
        new_row.unshift(mutant);
        all_data.push(new_row);
    };

    var label;
    var title;
    var hAxis;
    if(class_type == 'PHENOTYPE') {
        label = 'Genes';
    }
    else if(class_type == 'LOCUS') {
        label = 'Phenotypes';
    }
    var data = google.visualization.arrayToDataTable(all_data);
    var options = {
        'legend': {'position': 'top', title: 'Experiment Type'},
        'title': label + ' by mutant type and experiment type',
        'vAxis': {title: 'Mutant Type'},
        'hAxis': {title: '# of ' + label},
        'chartArea': {left:110,top:50,width:"60%",height:"75%"},
        'dataOpacity':.75,
        'colors': ["#7FBF7B", "#AF8DC3", "#1F78B4"],
        'backgroundColor': 'transparent'
    };

    var chart = new google.visualization.BarChart(document.getElementById('mutant_experiment_chart'));
    chart.draw(data, options);

    //Strain Chart
    var strain_all_data = [['Strain', label]];
    //Prepare Data
    for(var j=0; j < overview_data['strain_list'].length; j++) {
        var strain = overview_data['strain_list'][j];
        var new_row = [strain, overview_data['strain_to_count'][strain]];
        strain_all_data.push(new_row);
    };

    var strain_data = google.visualization.arrayToDataTable(strain_all_data);
    var strain_options = {
        'legend': {'position': 'none'},
        'title': label + ' in different strain backgrounds',
        'vAxis': {title: '# of ' + label},
        'hAxis': {title: 'Strain'},
        'dataOpacity':.75,
        'colors': ["#1F78B4"],
        'chartArea': {left:50,top:50,width:"80%",height:"50%"},
        'backgroundColor': 'transparent'
    };

    var strain_chart = new google.visualization.ColumnChart(document.getElementById('strain_chart'));
    strain_chart.draw(strain_data, strain_options);
}<|endoftext|>


<commit_before>import path from 'path'
import webpack from 'webpack'
import autoprefixer from 'autoprefixer'
import HtmlWebpackPlugin from 'html-webpack-plugin'

module.exports = {
  resolveLoader: {
    moduleDirectories: ['node_modules']
  },

  output: {
    path: path.join(__dirname, 'build'),
    filename: '[name].js',
    publicPath: '/',
  },

  resolve: {
    fallback: path.join(__dirname, 'node_modules'),
    extensions: ['', '.css', '.scss', '.js', '.jsx', '.json'],
    alias: {
      'app': path.join(__dirname, 'app')
    }
  },

  resolveLoader: {
    fallback: path.join(__dirname, 'node_modules')
  },

  module: {
    loaders: [
      { test: /\.css$/, loaders: ['style', 'css'] },
      { test: /\.scss$/, loaders: ['style', 'css', 'postcss-loader', 'sass'] },
      { test: /\.json$/, loaders: ['json-loader'] },
      {
        test: /\.jsx?$/,
        loader: 'babel-loader',
        exclude: /node_modules/,
        query: { presets: ['es2015', 'react', 'stage-2'] }
      }
    ]
  },

  postcss: [autoprefixer({ browsers: ['last 2 version'] })],

  devtool: 'eval',
  debug: true,
  entry: {
    app: [
      'webpack-dev-server/client?http://0.0.0.0:9000',
      'webpack/hot/only-dev-server',
      './app/bootstrap'
    ]
  },

  plugins: [
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NoErrorsPlugin(),
    new webpack.DefinePlugin({
      ENVIRONMENT: '\'development\'',
      REACT_VERSION: '\'0.14\'',
    }),
    new HtmlWebpackPlugin({
      template: 'app/index.html'
    })
  ],

  devServer: {
    contentBase: './build',
    port: 9000,
    host: '0.0.0.0',
    noInfo: true,
    hot: true,
    inline: true,
    historyApiFallback: true,
  }
}
<commit_msg>Clean up example app webpack config<commit_after>import path from 'path'
import webpack from 'webpack'
import autoprefixer from 'autoprefixer'
import HtmlWebpackPlugin from 'html-webpack-plugin'

module.exports = {
  resolveLoader: {
    moduleDirectories: ['node_modules'],
    fallback: path.join(__dirname, 'node_modules'),
  },

  output: {
    path: path.join(__dirname, 'build'),
    filename: '[name].js',
    publicPath: '/',
  },

  resolve: {
    fallback: path.join(__dirname, 'node_modules'),
    extensions: ['', '.css', '.scss', '.js', '.jsx', '.json'],
    alias: {
      'app': path.join(__dirname, 'app')
    }
  },

  module: {
    loaders: [
      {test: /\.css$/, loaders: ['style', 'css']},
      {test: /\.scss$/, loaders: ['style', 'css', 'postcss-loader', 'sass']},
      {test: /\.json$/, loaders: ['json-loader']},
      {
        test: /\.jsx?$/,
        loader: 'babel-loader',
        exclude: /node_modules/,
        query: {presets: ['es2015', 'react', 'stage-2']}
      }
    ]
  },

  postcss: [autoprefixer({browsers: ['last 2 version']})],

  devtool: 'eval',
  debug: true,
  entry: {
    app: [
      'webpack-dev-server/client?http://0.0.0.0:9000',
      'webpack/hot/only-dev-server',
      './app/bootstrap'
    ]
  },

  plugins: [
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NoErrorsPlugin(),
    new webpack.DefinePlugin({
      ENVIRONMENT: '\'development\'',
      REACT_VERSION: '\'0.14\'',
    }),
    new HtmlWebpackPlugin({
      template: 'app/index.html'
    })
  ],

  devServer: {
    contentBase: './build',
    port: 9000,
    host: '0.0.0.0',
    noInfo: true,
    hot: true,
    inline: true,
    historyApiFallback: true,
  }
}
<|endoftext|>


<commit_before>module("changes", {
  setup : function () {
    this.name = 'idb://test_suite_db';
  }
});

asyncTest("All changes", function () {
  initTestDB(this.name, function(err, db) {
    db.post({test:"somestuff"}, function (err, info) {
      db.changes({
        onChange: function (change) {
          ok(change.seq);
          start();
        },
        error: function() {
          ok(false);
          start();
        }
      });
    });
  });
});

asyncTest("Changes doc", function () {
  initTestDB(this.name, function(err, db) {
    db.post({test:"somestuff"}, function (err, info) {
      db.changes({
        onChange: function (change) {
          ok(change.doc);
          equal(change.doc._id, change.id);
          ok(!change.doc._junk, 'Do not expose junk');
          equal(change.doc._rev, change.changes[change.changes.length - 1].rev);
          start();
        },
        error: function() {
          ok(false);
          start();
        }
      });
    });
  });
});

asyncTest("Continuous changes", function() {
  initTestDB(this.name, function(err, db) {
    var count = 0;
    var changes = db.changes({
      onChange: function(change) { count += 1; },
      continuous: true
    });
    db.post({test:"adoc"}, function(err, info) {
      setTimeout(function() {
        equal(count, 1);
        changes.cancel();
        start();
      }, 50);
    });
  });
});

asyncTest("Cancel changes", function() {
  initTestDB(this.name, function(err, db) {
    var count = 0;
    var changes = db.changes({
      onChange: function(change) { count += 1; },
      continuous: true
    });
    db.post({test:"adoc"}, function(err, info) {
      changes.cancel();
      db.post({test:"another doc"}, function(err, info) {
        setTimeout(function() {
          equal(count, 1);
          start();
        }, 50);
      });
    });
  });
});

asyncTest("Changes filter", function() {

  var docs1 = [
    {_id: "0", integer: 0},
    {_id: "1", integer: 1},
    {_id: "2", integer: 2},
    {_id: "3", integer: 3}
  ];

  var docs2 = [
    {_id: "4", integer: 4},
    {_id: "5", integer: 5},
    {_id: "6", integer: 6},
    {_id: "7", integer: 7}
  ];

  initTestDB(this.name, function(err, db) {
    var count = 0;
    db.bulkDocs({docs: docs1}, function(err, info) {
      var changes = db.changes({
        filter: function(doc) { return doc.integer % 2 === 0; },
        onChange: function(change) {
          count += 1;
        },
        continuous: true
      });
      db.bulkDocs({docs: docs2}, function(err, info) {
        setTimeout(function() {
          equal(count, 4);
          changes.cancel();
          start();
        }, 100);
      });
    });
  });
});
<commit_msg>Run changes suite over idb + http backends<commit_after>['idb-1', 'http-1'].map(function(adapter) {

  module("changes: " + adapter, {
    setup : function () {
      this.name = generateAdapterUrl(adapter);
    }
  });

  asyncTest("All changes", function () {
    initTestDB(this.name, function(err, db) {
      db.post({test:"somestuff"}, function (err, info) {
        db.changes({
          onChange: function (change) {
            ok(change.seq);
            start();
          },
          error: function() {
            ok(false);
            start();
          }
        });
      });
    });
  });

  asyncTest("Changes doc", function () {
    initTestDB(this.name, function(err, db) {
      db.post({test:"somestuff"}, function (err, info) {
        db.changes({
          include_docs: true,
          onChange: function (change) {
            ok(change.doc);
            equal(change.doc._id, change.id);
            ok(!change.doc._junk, 'Do not expose junk');
            equal(change.doc._rev, change.changes[change.changes.length - 1].rev);
            start();
          },
          error: function() {
            ok(false);
            start();
          }
        });
      });
    });
  });

  asyncTest("Continuous changes", function() {
    initTestDB(this.name, function(err, db) {
      var count = 0;
      var changes = db.changes({
        onChange: function(change) { count += 1; },
        continuous: true
      });
      db.post({test:"adoc"}, function(err, info) {
        setTimeout(function() {
          equal(count, 1);
          changes.cancel();
          start();
        }, 50);
      });
    });
  });

  asyncTest("Cancel changes", function() {
    initTestDB(this.name, function(err, db) {
      var count = 0;
      var changes = db.changes({
        onChange: function(change) {
          count += 1;
          if (count === 1) {
            changes.cancel();
            db.post({test:"another doc"}, function(err, info) {
              setTimeout(function() {
                equal(count, 1);
                start();
              }, 200);
            });
          }
        },
        continuous: true
      });
      db.post({test:"adoc"}, function() {});
    });
  });

  asyncTest("Changes filter", function() {

    var docs1 = [
      {_id: "0", integer: 0},
      {_id: "1", integer: 1},
      {_id: "2", integer: 2},
      {_id: "3", integer: 3}
    ];

    var docs2 = [
      {_id: "4", integer: 4},
      {_id: "5", integer: 5},
      {_id: "6", integer: 6},
      {_id: "7", integer: 7}
    ];

    initTestDB(this.name, function(err, db) {
      var count = 0;
      db.bulkDocs({docs: docs1}, function(err, info) {
        var changes = db.changes({
          filter: function(doc) { return doc.integer % 2 === 0; },
          onChange: function(change) {
            count += 1;
          },
          continuous: true
        });
        db.bulkDocs({docs: docs2}, function(err, info) {
          setTimeout(function() {
            equal(count, 4);
            changes.cancel();
            start();
          }, 100);
        });
      });
    });
  });

});<|endoftext|>


<commit_before>APP.applicationController = (function () {
    'use strict';

    var fastClick;

    function offlineWarning() {
        alert("This feature is only available online.");
    }

    function pageNotFound() {
        alert("That page you were looking for cannot be found.");
    }

    function showHome() {
        $("#body").html(APP.templates.home());

        // Load up the last cached copy of the news
        APP.articlesController.showArticleList();

        $('#refreshButton').click(function () {

            // If the user is offline, don't bother trying to synchronize
            if (navigator && navigator.onLine === false) {
                offlineWarning();
            } else {
                APP.articlesController.synchronizeWithServer(function failureCallback() {
                    alert("This feature is not available offline");
                });
            }
        });
    }

    function showArticle(id) {
        $("#body").html(APP.templates.articleLoading());
        APP.articlesController.showArticle(id);
    }

    function route(page) {
        if (page) {
            page = page.replace(new RegExp('^' + APP_ROOT), '');
        } else {
            page = '';
        }
        if (page.length > 0) {
            if (parseInt(page, 10) > 0) {
                showArticle(parseInt(page, 10));
            } else {
                pageNotFound();
                page = APP_ROOT + 'error';
            }
        } else {
            showHome();
        }
        window.history.pushState(null, null, APP_ROOT + page);
    }

    function initialize(resources, contentAlreadyLoaded) {

        // Listen to the URL link clicks
        $(document).on('click', 'a', function (event) {
            event.stopPropagation();
            event.preventDefault();
            route(this.getAttribute('href'));
        });

        // Set up FastClick
        fastClick = new FastClick(document.body);

        // Initalise appcache
        APP.appcache.start();

        // If we don't have resources, stop because this
        // means the data in the dom has been freshly
        // loaded from the server.
        if (contentAlreadyLoaded) {
            return;
        }

        // Inject CSS Into the DOM
        $("head").append("<style>" + resources.css + "</style>");

        // Create app elements
        $("body").append(APP.templates.application());

        // Remove our loading splash screen
        $("#loading").remove();

        route();
    }

    // This is to our webapp what main() is to C, $(document).ready is to jQuery, etc
    function start(resources, storeResources, contentAlreadyLoaded) {

        // As a bare minimum we need History API to
        // run the advanced features of this app
        if (!historyAPI()) return;

        window.addEventListener("popstate", function(e) {
            route(location.pathname);
        });

        // When indexedDB available, use it!
        APP.indexedDB.start(function indexedDBSuccess() {
            APP.database = APP.indexedDB;
            initialize(resources, contentAlreadyLoaded);

            // When indexedDB is not available, fallback to trying websql
        }, function indexedDBFailure() {
            APP.webSQL.start(function webSQLSuccess() {
                APP.database = APP.webSQL;
                initialize(resources, contentAlreadyLoaded);

            // When webSQL not available, fall back to using the network
            }, function webSQLFailure() {
                APP.network.start(function networkSuccess() {
                    APP.database = APP.network;
                    initialize(resources, contentAlreadyLoaded);
                });
            });
        });

        if (storeResources && window['localStorage']) {
            localStorage.resources = JSON.stringify(resources);
        }
    }

    function startFromServer() {

        // As a bare minimum we need History API to
        // run the advanced features of this app
        if (!historyAPI()) return;
        $.ajax('api/resources/', {
            dataType: 'json',
            success: function (data) {
                start(data, true, true);
            }
        });
    }

    // Detection of history API, 'borrowed' from Modernizr
    function historyAPI() {
        var ua = navigator.userAgent;

        // We only want Android 2, stock browser, and not Chrome which identifies
        // itself as 'Mobile Safari' as well
        if (ua.indexOf('Android 2') !== -1 &&
            ua.indexOf('Mobile Safari') !== -1 &&
                ua.indexOf('Chrome') === -1) {
            return false;
        }

        // Return the regular check
        if (window.history && 'pushState' in history) {
            return true;
        }
    }

    return {
        start: start,
        startFromServer: startFromServer,
        route: route
    };
}());
<commit_msg>Improvements to the way private browsing works on iOS but still a bit strange...<commit_after>APP.applicationController = (function () {
    'use strict';

    var fastClick,
        iOSPrivateBrowsing;

    function offlineWarning() {
        alert("This feature is only available online.");
    }

    function pageNotFound() {
        alert("That page you were looking for cannot be found.");
    }

    function showHome() {
        $("#body").html(APP.templates.home());

        // Load up the last cached copy of the news
        APP.articlesController.showArticleList();

        $('#refreshButton').click(function () {

            // If the user is offline, don't bother trying to synchronize
            if (navigator && navigator.onLine === false) {
                offlineWarning();
            } else {
                APP.articlesController.synchronizeWithServer(function failureCallback() {
                    alert("This feature is not available offline");
                });
            }
        });
    }

    function showArticle(id) {
        $("#body").html(APP.templates.articleLoading());
        APP.articlesController.showArticle(id);
    }

    function route(page) {
        if (page) {
            page = page.replace(new RegExp('^' + APP_ROOT), '');
        } else {
            page = '';
        }
        if (page.length > 0) {
            if (parseInt(page, 10) > 0) {
                showArticle(parseInt(page, 10));
            } else {
                pageNotFound();
                page = APP_ROOT + 'error';
            }
        } else {
            showHome();
        }
        window.history.pushState(null, null, APP_ROOT + page);
    }

    function initialize(resources, contentAlreadyLoaded) {

        // Listen to the URL link clicks
        $(document).on('click', 'a', function (event) {
            event.stopPropagation();
            event.preventDefault();
            route(this.getAttribute('href'));
        });

        // Set up FastClick
        fastClick = new FastClick(document.body);

        // Initalise appcache if app not in private browsing mode
        if (!iOSPrivateBrowsing) {
	        APP.appcache.start(iOSPrivateBrowsing);
        }

        // If we don't have resources, stop because this
        // means the data in the dom has been freshly
        // loaded from the server.
        if (contentAlreadyLoaded) {
            return;
        }

        // Inject CSS Into the DOM
        $("head").append("<style>" + resources.css + "</style>");

        // Create app elements
        $("body").append(APP.templates.application());

        // Remove our loading splash screen
        $("#loading").remove();

        route();
    }

    // This is to our webapp what main() is to C, $(document).ready is to jQuery, etc
    function start(resources, storeResources, contentAlreadyLoaded) {

        // Try to detect whether iOS private browsing mode is enabled
        try {
            localStorage.test = '';
            localStorage.removeItem('item');
        } catch (exception) {
            if (exception.code === 22) {
                iOSPrivateBrowsing = true;
            }
        }

        if (iOSPrivateBrowsing) {
            return APP.network.start(function networkSuccess() {
                APP.database = APP.network;
                initialize(resources);
            });
        }

        // As a bare minimum we need History API to
        // run the advanced features of this app
        if (!historyAPI()) return;

        window.addEventListener("popstate", function(e) {
            route(location.pathname);
        });

        // When indexedDB available, use it!
        APP.indexedDB.start(function indexedDBSuccess() {
            APP.database = APP.indexedDB;
            initialize(resources, contentAlreadyLoaded);

            // When indexedDB is not available, fallback to trying websql
        }, function indexedDBFailure() {
            APP.webSQL.start(function webSQLSuccess() {
                APP.database = APP.webSQL;
                initialize(resources, contentAlreadyLoaded);

            // When webSQL not available, fall back to using the network
            }, function webSQLFailure() {
                APP.network.start(function networkSuccess() {
                    APP.database = APP.network;
                    initialize(resources, contentAlreadyLoaded);
                });
            });
        });

        if (storeResources && window['localStorage']) {
            localStorage.resources = JSON.stringify(resources);
        }
    }

    function startFromServer() {

        // As a bare minimum we need History API to
        // run the advanced features of this app
        if (!historyAPI()) return;
        $.ajax('api/resources/', {
            dataType: 'json',
            success: function (data) {
                start(data, true, true);
            }
        });
    }

    // Detection of history API, 'borrowed' from Modernizr
    function historyAPI() {
        var ua = navigator.userAgent;

        // We only want Android 2, stock browser, and not Chrome which identifies
        // itself as 'Mobile Safari' as well
        if (ua.indexOf('Android 2') !== -1 &&
            ua.indexOf('Mobile Safari') !== -1 &&
                ua.indexOf('Chrome') === -1) {
            return false;
        }

        // Return the regular check
        if (window.history && 'pushState' in history) {
            return true;
        }
    }

    return {
        start: start,
        startFromServer: startFromServer,
        route: route
    };
}());
<|endoftext|>


<commit_before>var Crafty = require('../core/core.js');

//
// Define some variables required for webgl
var fs = require('fs');
var IMAGE_VERTEX_SHADER = fs.readFileSync(__dirname + '/shaders/sprite.vert', 'utf8');
var IMAGE_FRAGMENT_SHADER = fs.readFileSync(__dirname + '/shaders/sprite.frag', 'utf8');
var IMAGE_ATTRIBUTE_LIST = [
    {name:"aPosition", width: 2},
    {name:"aOrientation", width: 3},
    {name:"aLayer", width:2},
    {name:"aTextureCoord",  width: 2}
];

/**@
 * #Image
 * @category Graphics
 * Draw an image with or without repeating (tiling).
 */
Crafty.c("Image", {
    _repeat: "repeat",
    ready: false,

    init: function () {
        this.bind("Draw", this._drawImage);
    },

    remove: function() {
        this.unbind("Draw", this._drawImage);
        // Unregister webgl entities
        if (this.program) {
            this.program.unregisterEntity(this);
        }
    },

    /**@
     * #.image
     * @comp Image
     * @trigger Invalidate - when the image is loaded
     * @sign public this .image(String url[, String repeat])
     * @param url - URL of the image
     * @param repeat - If the image should be repeated to fill the entity.  This follows CSS syntax: (`"no-repeat", "repeat", "repeat-x", "repeat-y"`), but defaults to `no-repeat`.
     *
     * Draw the specified image.
     *
     * @note The default value of repeat is `no-repeat`, which is different than the standard CSS default
     *
     * If the width and height are `0` and repeat is set to `no-repeat` the width and
     * height will automatically assume that of the image. This is an
     * easy way to create an image without needing sprites.
     *
     * If set to `no-repeat` and given dimensions larger than that of the image,
     * the exact appearance will depend on what renderer (WebGL, DOM, or Canvas) is used.
     *
     * @example
     * Will default to no-repeat. Entity width and height will be set to the images width and height
     * ~~~
     * var ent = Crafty.e("2D, DOM, Image").image("myimage.png");
     * ~~~
     * Create a repeating background.
     * ~~~
     * var bg = Crafty.e("2D, DOM, Image")
     *              .attr({w: Crafty.viewport.width, h: Crafty.viewport.height})
     *              .image("bg.png", "repeat");
     * ~~~
     *
     * @see Crafty.sprite
     */
    image: function (url, repeat) {
        this.__image = url;
        this._repeat = repeat || "no-repeat";

        this.img = Crafty.asset(url);
        if (!this.img) {
            this.img = new Image();
            Crafty.asset(url, this.img);
            this.img.src = url;
            var self = this;

            this.img.onload = function () {
                self._onImageLoad();
            };
        } else {
            this._onImageLoad();
        }

        this.trigger("Invalidate");

        return this;
    },

    _onImageLoad: function(){

        if (this.has("Canvas")) {
            this._pattern = this._drawContext.createPattern(this.img, this._repeat);
        } else if (this.has("WebGL")) {
            this._establishShader("image:" + this.__image, IMAGE_FRAGMENT_SHADER, IMAGE_VERTEX_SHADER, IMAGE_ATTRIBUTE_LIST);
            this.program.setTexture( this.webgl.makeTexture(this.__image, this.img, (this._repeat!=="no-repeat")));
        }

        if (this._repeat === "no-repeat") {
            this.w = this.w || this.img.width;
            this.h = this.h || this.img.height;
        }

        this.ready = true;
        this.trigger("Invalidate");
    },

    _drawImage: function(e){
        if (e.type === "canvas") {
            //skip if no image
            if (!this.ready || !this._pattern) return;

            var context = e.ctx;

            context.fillStyle = this._pattern;

            context.save();
            context.translate(e.pos._x, e.pos._y);
            context.fillRect(0, 0, e.pos._w, e.pos._h);
            context.restore();
        } else if (e.type === "DOM") {
            if (this.__image) {
              e.style.backgroundImage = "url(" + this.__image + ")";
              e.style.backgroundRepeat = this._repeat;
            }
        } else if (e.type === "webgl") {
            var pos = e.pos;
            // Write texture coordinates
            e.program.writeVector("aTextureCoord",
                0, 0,
                0, pos._h,
                pos._w, 0,
                pos._w, pos._h
            );
        }

    }
});<commit_msg>Remove unregistering from WebGL<commit_after>var Crafty = require('../core/core.js');

//
// Define some variables required for webgl
var fs = require('fs');
var IMAGE_VERTEX_SHADER = fs.readFileSync(__dirname + '/shaders/sprite.vert', 'utf8');
var IMAGE_FRAGMENT_SHADER = fs.readFileSync(__dirname + '/shaders/sprite.frag', 'utf8');
var IMAGE_ATTRIBUTE_LIST = [
    {name:"aPosition", width: 2},
    {name:"aOrientation", width: 3},
    {name:"aLayer", width:2},
    {name:"aTextureCoord",  width: 2}
];

/**@
 * #Image
 * @category Graphics
 * Draw an image with or without repeating (tiling).
 */
Crafty.c("Image", {
    _repeat: "repeat",
    ready: false,

    init: function () {
        this.bind("Draw", this._drawImage);
    },

    remove: function() {
        this.unbind("Draw", this._drawImage);
    },

    /**@
     * #.image
     * @comp Image
     * @trigger Invalidate - when the image is loaded
     * @sign public this .image(String url[, String repeat])
     * @param url - URL of the image
     * @param repeat - If the image should be repeated to fill the entity.  This follows CSS syntax: (`"no-repeat", "repeat", "repeat-x", "repeat-y"`), but defaults to `no-repeat`.
     *
     * Draw the specified image.
     *
     * @note The default value of repeat is `no-repeat`, which is different than the standard CSS default
     *
     * If the width and height are `0` and repeat is set to `no-repeat` the width and
     * height will automatically assume that of the image. This is an
     * easy way to create an image without needing sprites.
     *
     * If set to `no-repeat` and given dimensions larger than that of the image,
     * the exact appearance will depend on what renderer (WebGL, DOM, or Canvas) is used.
     *
     * @example
     * Will default to no-repeat. Entity width and height will be set to the images width and height
     * ~~~
     * var ent = Crafty.e("2D, DOM, Image").image("myimage.png");
     * ~~~
     * Create a repeating background.
     * ~~~
     * var bg = Crafty.e("2D, DOM, Image")
     *              .attr({w: Crafty.viewport.width, h: Crafty.viewport.height})
     *              .image("bg.png", "repeat");
     * ~~~
     *
     * @see Crafty.sprite
     */
    image: function (url, repeat) {
        this.__image = url;
        this._repeat = repeat || "no-repeat";

        this.img = Crafty.asset(url);
        if (!this.img) {
            this.img = new Image();
            Crafty.asset(url, this.img);
            this.img.src = url;
            var self = this;

            this.img.onload = function () {
                self._onImageLoad();
            };
        } else {
            this._onImageLoad();
        }

        this.trigger("Invalidate");

        return this;
    },

    _onImageLoad: function(){

        if (this.has("Canvas")) {
            this._pattern = this._drawContext.createPattern(this.img, this._repeat);
        } else if (this.has("WebGL")) {
            this._establishShader("image:" + this.__image, IMAGE_FRAGMENT_SHADER, IMAGE_VERTEX_SHADER, IMAGE_ATTRIBUTE_LIST);
            this.program.setTexture( this.webgl.makeTexture(this.__image, this.img, (this._repeat!=="no-repeat")));
        }

        if (this._repeat === "no-repeat") {
            this.w = this.w || this.img.width;
            this.h = this.h || this.img.height;
        }

        this.ready = true;
        this.trigger("Invalidate");
    },

    _drawImage: function(e){
        if (e.type === "canvas") {
            //skip if no image
            if (!this.ready || !this._pattern) return;

            var context = e.ctx;

            context.fillStyle = this._pattern;

            context.save();
            context.translate(e.pos._x, e.pos._y);
            context.fillRect(0, 0, e.pos._w, e.pos._h);
            context.restore();
        } else if (e.type === "DOM") {
            if (this.__image) {
              e.style.backgroundImage = "url(" + this.__image + ")";
              e.style.backgroundRepeat = this._repeat;
            }
        } else if (e.type === "webgl") {
            var pos = e.pos;
            // Write texture coordinates
            e.program.writeVector("aTextureCoord",
                0, 0,
                0, pos._h,
                pos._w, 0,
                pos._w, pos._h
            );
        }

    }
});
<|endoftext|>


<commit_before>// @flow

//
// INTEL CONFIDENTIAL
//
// Copyright 2013-2016 Intel Corporation All Rights Reserved.
//
// The source code contained or described herein and all documents related
// to the source code ("Material") are owned by Intel Corporation or its
// suppliers or licensors. Title to the Material remains with Intel Corporation
// or its suppliers and licensors. The Material contains trade secrets and
// proprietary and confidential information of Intel or its suppliers and
// licensors. The Material is protected by worldwide copyright and trade secret
// laws and treaty provisions. No part of the Material may be used, copied,
// reproduced, modified, published, uploaded, posted, transmitted, distributed,
// or disclosed in any way without Intel's prior express written permission.
//
// No license under any patent, copyright, trade secret or other intellectual
// property right is granted to or conferred upon you by disclosure or delivery
// of the Materials, either expressly, by implication, inducement, estoppel or
// otherwise. Any license under such intellectual property rights must be
// express and approved by Intel in writing.

import {memoize} from 'intel-fp';

export default function (createDate) {
  'ngInject';

  return memoize(createDate);
}
<commit_msg>- Added type to top level of to-date-filter.js<commit_after>// @flow

//
// INTEL CONFIDENTIAL
//
// Copyright 2013-2016 Intel Corporation All Rights Reserved.
//
// The source code contained or described herein and all documents related
// to the source code ("Material") are owned by Intel Corporation or its
// suppliers or licensors. Title to the Material remains with Intel Corporation
// or its suppliers and licensors. The Material contains trade secrets and
// proprietary and confidential information of Intel or its suppliers and
// licensors. The Material is protected by worldwide copyright and trade secret
// laws and treaty provisions. No part of the Material may be used, copied,
// reproduced, modified, published, uploaded, posted, transmitted, distributed,
// or disclosed in any way without Intel's prior express written permission.
//
// No license under any patent, copyright, trade secret or other intellectual
// property right is granted to or conferred upon you by disclosure or delivery
// of the Materials, either expressly, by implication, inducement, estoppel or
// otherwise. Any license under such intellectual property rights must be
// express and approved by Intel in writing.

import {memoize} from 'intel-fp';

export default function (createDate:(milliseconds:Number) => Date) {
  'ngInject';

  return memoize(createDate);
}
<|endoftext|>


<commit_before>var ac = this.AudioContext ? new AudioContext() : new webkitAudioContext();
ac.createGain();
var nextBeat = 0;
var totalBeats =  0;
var nextBeatM = 0;
var nextBeatTime = ac.currentTime;
setInterval(function(){
  //ac time is more accurate than setInterval, look ahead 100 ms to schedule notes
  while (nextBeatTime < ac.currentTime + .1){
    //on every nth beat, spin the larger circle and apply notes
    if (!(totalBeats % ratioM)){
      //spin larger wheel
      svgM
        .transition().duration(getBPM()*8*1000).ease('linear')
          .attr('transform', 'rotate(' + (-(.5 + nextBeatM)/numBeatsM*360 - 90) + ')');

      //extract update information
      var updateArray = pitches.map(function(d){ return false; });
      beatsM.filter(function(d, i){ return i === nextBeatM; })
        .selectAll('path')
          .each(function(d, i){
            updateArray[i] = d.on;
            //TODO flash color
            d3.select(this)
                .style('fill', d.on ? 'blue' : 'white')
              .transition().duration(3000)
                .call(colorNote);
          });

      //apply updates to slow circle
      beats.filter(function(d, i){ return i == (Math.ceil(numBeats/2) + totalBeats) % numBeats; })
        .selectAll('path')
          .each(function(d, i){
            if (updateArray[i]){
              d.on = +!d.on;
              d3.select(this)
                  .style('fill', d.on ? 'green' : 'red')
                .transition().duration(2000)
                  .call(colorNote);
            }
          })

      nextBeatM = (((nextBeatM - 1) % numBeatsM) + numBeatsM) % numBeatsM;
    }

    //grab the active beat column
    beats.filter(function(d, i){ return i == totalBeats % numBeats; })
      .selectAll('path')
        .each(function(d){
          //if the note is selected, play pitch at scheduled nextBeat
          if (d.on){
            var o = osc(d.pitch, d.on);
            o.osc.start(nextBeatTime);
            o.osc.stop(nextBeatTime + getDuration())
          }
          //highlight and unhighlight selected column
          //visually exact timing doesn't matter as much
          //easier to hear something off by a few ms
          var selection = d3.select(this).style('stroke', 'blue')
          //use timeout instead of transition so mouseovers transitions don't cancel)
          setTimeout(function(){
            selection.style('stroke', 'lightgrey');
          }, getBPM()*1000)
        });

    svg
      .transition().duration(getBPM()*1000).ease('linear')
        .attr('transform', 'rotate(' + (-totalBeats%numBeats/numBeats*360 - 180) + ')');

    //update time and index of nextBeat
    nextBeatTime += getBPM();
    nextBeat = (nextBeat + 1) % numBeats;
    totalBeats++;
  }
}, 25)

//add sliders to the page
var sliders = d3.select('#synthSliders').selectAll('input')
    .data(['Pitch', 'BPM', 'Duration']).enter()
  .append('div')
    .style({display: 'inline-block', 'margin-left': '89.5px', 'text-align': 'center'})

sliders.append('p').text(f());

sliders.append('p').append('input')
    .attr({type: 'range', min: '0', max: '1', step: '0.0001', value: '.5'})
    .attr('id', f())
    .style('width', '127px');

//use inverse log scales for finer control over high and low values
function getPitch(){
  var scale = d3.scale.log().base(2).domain([.1, 10]);
  return scale.invert((d3.select('#Pitch').node().valueAsNumber));
}
function getBPM(){
  var scale = d3.scale.log().base(2).domain([40, 1200]);
  var rv = 60/scale.invert((d3.select('#BPM').node().valueAsNumber));
  return rv;
}
function getDuration(){
  var scale = d3.scale.log().base(2).domain([.05, 1]);
  return scale.invert((d3.select('#Duration').node().valueAsNumber));
}

//generate oscillator
function osc(pitch, waveform){
  oscillator = ac.createOscillator(),
  oscillator.type = waveform;
  oscillator.frequency.value = pitch*getPitch();
  gainNode = ac.createGain();
  oscillator.connect(gainNode);
  gainNode.connect(ac.destination);
  gainNode.gain.value = .2;
  return {osc: oscillator, gain: gainNode};
};<commit_msg>pause working<commit_after>var ac = this.AudioContext ? new AudioContext() : new webkitAudioContext();
ac.createGain();
var nextBeat = 0;
var totalBeats =  0;
var nextBeatM = 0;
var nextBeatTime = ac.currentTime;
setInterval(function(){
  //ac time is more accurate than setInterval, look ahead 100 ms to schedule notes
  while (nextBeatTime < ac.currentTime + .1  && !isPaused){
    //on every nth beat, spin the larger circle and apply notes
    if (!(totalBeats % ratioM)){
      //spin larger wheel
      svgM
        .transition().duration(getBPM()*8*1000).ease('linear')
          .attr('transform', 'rotate(' + (-(.5 + nextBeatM)/numBeatsM*360 - 90) + ')');

      //extract update information
      var updateArray = pitches.map(function(d){ return false; });
      beatsM.filter(function(d, i){ return i === nextBeatM; })
        .selectAll('path')
          .each(function(d, i){
            updateArray[i] = d.on;
            //TODO flash color
            d3.select(this)
                .style('fill', d.on ? 'blue' : 'white')
              .transition().duration(3000)
                .call(colorNote);
          });

      //apply updates to slow circle
      beats.filter(function(d, i){ return i == (Math.ceil(numBeats/2) + totalBeats) % numBeats; })
        .selectAll('path')
          .each(function(d, i){
            if (updateArray[i]){
              d.on = +!d.on;
              d3.select(this)
                  .style('fill', d.on ? 'green' : 'red')
                .transition().duration(2000)
                  .call(colorNote);
            }
          })

      nextBeatM = (((nextBeatM - 1) % numBeatsM) + numBeatsM) % numBeatsM;
    }

    //grab the active beat column
    beats.filter(function(d, i){ return i == totalBeats % numBeats; })
      .selectAll('path')
        .each(function(d){
          //if the note is selected, play pitch at scheduled nextBeat
          if (d.on){
            var o = osc(d.pitch, d.on);
            o.osc.start(nextBeatTime);
            o.osc.stop(nextBeatTime + getDuration())
          }
          //highlight and unhighlight selected column
          //visually exact timing doesn't matter as much
          //easier to hear something off by a few ms
          var selection = d3.select(this).style('stroke', 'blue')
          //use timeout instead of transition so mouseovers transitions don't cancel)
          setTimeout(function(){
            selection.style('stroke', 'lightgrey');
          }, getBPM()*1000)
        });

    svg
      .transition().duration(getBPM()*1000).ease('linear')
        .attr('transform', 'rotate(' + (-totalBeats%numBeats/numBeats*360 - 180) + ')');

    //update time and index of nextBeat
    nextBeatTime += getBPM();
    nextBeat = (nextBeat + 1) % numBeats;
    totalBeats++;
  }
}, 25);

var isPaused = false;
var pauseStart = 0;
var totalPause = 0;
function togglePause(){
  isPaused = !isPaused;
  if (isPaused){
    pauseStart = ac.currentTime;
  } else {
    totalPause += ac.currentTime - pauseStart;
    nextBeatTime += ac.currentTime - pauseStart;
  }

}

//add sliders to the page
var sliders = d3.select('#synthSliders').selectAll('input')
    .data(['Pitch', 'BPM', 'Duration']).enter()
  .append('div')
    .style({display: 'inline-block', 'margin-left': '89.5px', 'text-align': 'center'})

sliders.append('p').text(f());

sliders.append('p').append('input')
    .attr({type: 'range', min: '0', max: '1', step: '0.0001', value: '.5'})
    .attr('id', f())
    .style('width', '127px');

//use inverse log scales for finer control over high and low values
function getPitch(){
  var scale = d3.scale.log().base(2).domain([.1, 10]);
  return scale.invert((d3.select('#Pitch').node().valueAsNumber));
}
function getBPM(){
  var scale = d3.scale.log().base(2).domain([40, 1200]);
  var rv = 60/scale.invert((d3.select('#BPM').node().valueAsNumber));
  return rv;
}
function getDuration(){
  var scale = d3.scale.log().base(2).domain([.05, 1]);
  return scale.invert((d3.select('#Duration').node().valueAsNumber));
}

//generate oscillator
function osc(pitch, waveform){
  oscillator = ac.createOscillator(),
  oscillator.type = waveform;
  oscillator.frequency.value = pitch*getPitch();
  gainNode = ac.createGain();
  oscillator.connect(gainNode);
  gainNode.connect(ac.destination);
  gainNode.gain.value = .2;
  return {osc: oscillator, gain: gainNode};
};<|endoftext|>


<commit_before>(function() {
    const active_ids = [];
    const reading_speed = 55;

    const addon_name = browser.runtime.getManifest().name;
    const icon_url = browser.extension.getURL("/icons/main_64.png");

    // Display a notification
    // Close existing message if a message with the same identifier already exists
    // The notification is closed after a variable delay.
    function notify(id, message){
        // Do not display the same message twice by using a active_id
        browser.notifications.create(id,
        {
            type: "basic",
            iconUrl: icon_url,
            title: addon_name,
            message: message
        });

        // Add active_id to active_ids, so we can clear it later
        active_ids.push(id);

        setTimeout(function()
        {
            // Clear the first (oldest) notification
            browser.notifications.clear(active_ids.shift());
        }, message.length * reading_speed);
    }

    define({ notify: notify });
})();
<commit_msg>review formatting and documentation comments for notifications module<commit_after>(function()
{
    const active_ids    = [];
    const reading_speed = 55;  // in ms per character

    const addon_name = browser.runtime.getManifest().name;
    const icon_url   = browser.extension.getURL("/icons/main_64.png");

    // Displays a notification message with given identifier. If an earlier notification with same
    // identifier exists, it is discarded. Notifications last a variable duration based on the
    // length of their message text.
    function notify(id, message)
    {
        // This discards any active notifications with the same identifier.
        browser.notifications.create(id,
        {
            type:    "basic",
            iconUrl: icon_url,
            title:   addon_name,
            message: message
        });

        active_ids.push(id);
        setTimeout(function()
        {
            // Clear the first (oldest) notification
            browser.notifications.clear(active_ids.shift());
        }, message.length * reading_speed);
    }

    define({ notify: notify });
})();
<|endoftext|>


<commit_before>(function (factory) {
  if (typeof define === 'function' && define.amd) {
    define(['jquery'], factory);
  } else if (typeof exports === 'object') {
    // Node / CommonJS
    factory(require('jquery'));
  } else {
    factory(jQuery);
  }
})(function ($) {

  'use strict';

  var console = window.console || { log: function () {} };

  function CropAvatar($element) {
    this.$container = $element;

    this.$avatarView = this.$container.find('.avatar-view');
    this.$avatar = this.$avatarView.find('img');
    this.$avatarModal = this.$container.find('#avatar-modal');
    this.$loading = this.$container.find('.loading');

    this.$avatarForm = this.$avatarModal.find('.avatar-form');
    this.$avatarUpload = this.$avatarForm.find('.avatar-upload');
    this.$avatarSrc = this.$avatarForm.find('.avatar-src');
    this.$avatarData = this.$avatarForm.find('.avatar-data');
    this.$avatarInput = this.$avatarForm.find('.avatar-input');
    this.$avatarSave = this.$avatarForm.find('.avatar-save');
    this.$avatarBtns = this.$avatarForm.find('.avatar-btns');

    this.$avatarWrapper = this.$avatarModal.find('.avatar-wrapper');
    this.$avatarPreview = this.$avatarModal.find('.avatar-preview');

    this.init();
    console.log(this);
  }

  CropAvatar.prototype = {
    constructor: CropAvatar,

    support: {
      fileList: !!$('<input type="file">').prop('files'),
      blobURLs: !!window.URL && URL.createObjectURL,
      formData: !!window.FormData
    },

    init: function () {
      this.support.datauri = this.support.fileList && this.support.blobURLs;

      if (!this.support.formData) {
        this.initIframe();
      }

      this.initTooltip();
      this.initModal();
      this.addListener();
    },

    addListener: function () {
      this.$avatarView.on('click', $.proxy(this.click, this));
      this.$avatarInput.on('change', $.proxy(this.change, this));
      this.$avatarForm.on('submit', $.proxy(this.submit, this));
      this.$avatarBtns.on('click', $.proxy(this.rotate, this));
    },

    initTooltip: function () {
      this.$avatarView.tooltip({
        placement: 'bottom'
      });
    },

    initModal: function () {
      this.$avatarModal.modal({
        show: false
      });
    },

    initPreview: function () {
      var url = this.$avatar.attr('src');

      this.$avatarPreview.empty().html('');
    },

    initIframe: function () {
      var target = 'upload-iframe-' + (new Date()).getTime(),
          $iframe = $('').attr({
            name: target,
            src: ''
          }),
          _this = this;

      // Ready ifrmae
      $iframe.one('load', function () {

        // respond response
        $iframe.on('load', function () {
          var data;

          try {
            data = $(this).contents().find('body').text();
          } catch (e) {
            console.log(e.message);
          }

          if (data) {
            try {
              data = $.parseJSON(data);
            } catch (e) {
              console.log(e.message);
            }

            _this.submitDone(data);
          } else {
            _this.submitFail('Image upload failed!');
          }

          _this.submitEnd();

        });
      });

      this.$iframe = $iframe;
      this.$avatarForm.attr('target', target).after($iframe.hide());
    },

    click: function () {
      this.$avatarModal.modal('show');
      this.initPreview();
    },

    change: function () {
      var files,
          file;

      if (this.support.datauri) {
        files = this.$avatarInput.prop('files');

        if (files.length > 0) {
          file = files[0];

          if (this.isImageFile(file)) {
            if (this.url) {
              URL.revokeObjectURL(this.url); // Revoke the old one
            }

            this.url = URL.createObjectURL(file);
            this.startCropper();
          }
        }
      } else {
        file = this.$avatarInput.val();

        if (this.isImageFile(file)) {
          this.syncUpload();
        }
      }
    },

    submit: function () {
      if (!this.$avatarSrc.val() && !this.$avatarInput.val()) {
        return false;
      }

      if (this.support.formData) {
        this.ajaxUpload();
        return false;
      }
    },

    rotate: function (e) {
      var data;

      if (this.active) {
        data = $(e.target).data();

        if (data.method) {
          this.$img.cropper(data.method, data.option);
        }
      }
    },

    isImageFile: function (file) {
      if (file.type) {
        return /^image\/\w+$/.test(file.type);
      } else {
        return /\.(jpg|jpeg|png|gif)$/.test(file);
      }
    },

    startCropper: function () {
      var _this = this;

      if (this.active) {
        this.$img.cropper('replace', this.url);
      } else {
        this.$img = $('');
        this.$avatarWrapper.empty().html(this.$img);
        this.$img.cropper({
          aspectRatio: 1,
          preview: this.$avatarPreview.selector,
          strict: false,
          crop: function (data) {
            var json = [
                  '{"x":' + data.x,
                  '"y":' + data.y,
                  '"height":' + data.height,
                  '"width":' + data.width,
                  '"rotate":' + data.rotate + '}'
                ].join();

            _this.$avatarData.val(json);
          }
        });

        this.active = true;
      }
    },

    stopCropper: function () {
      if (this.active) {
        this.$img.cropper('destroy');
        this.$img.remove();
        this.active = false;
      }
    },

    ajaxUpload: function () {
      var url = this.$avatarForm.attr('action'),
          data = new FormData(this.$avatarForm[0]),
          _this = this;

      $.ajax(url, {
        type: 'post',
        data: data,
        dataType: 'json',
        processData: false,
        contentType: false,

        beforeSend: function () {
          _this.submitStart();
        },

        success: function (data) {
          _this.submitDone(data);
        },

        error: function (XMLHttpRequest, textStatus, errorThrown) {
          _this.submitFail(textStatus || errorThrown);
        },

        complete: function () {
          _this.submitEnd();
        }
      });
    },

    syncUpload: function () {
      this.$avatarSave.click();
    },

    submitStart: function () {
      this.$loading.fadeIn();
    },

    submitDone: function (data) {
      console.log(data);

      if ($.isPlainObject(data) && data.state === 200) {
        if (data.result) {
          this.url = data.result;

          if (this.support.datauri || this.uploaded) {
            this.uploaded = false;
            this.cropDone();
          } else {
            this.uploaded = true;
            this.$avatarSrc.val(this.url);
            this.startCropper();
          }

          this.$avatarInput.val('');
        } else if (data.message) {
          this.alert(data.message);
        }
      } else {
        this.alert('Failed to response');
      }
    },

    submitFail: function (msg) {
      this.alert(msg);
    },

    submitEnd: function () {
      this.$loading.fadeOut();
    },

    cropDone: function () {
      this.$avatarForm.get(0).reset();
      this.$avatar.attr('src', this.url);
      this.stopCropper();
      this.$avatarModal.modal('hide');
    },

    alert: function (msg) {
      var $alert = [
            '
',
              '<button type="button" class="close" data-dismiss="alert">×</button>',
              msg,
            '
'
          ].join('');

      this.$avatarUpload.after($alert);
    }
  };

  $(function () {
    return new CropAvatar($('#crop-avatar'));
  });

});
<commit_msg>Fix #363<commit_after>(function (factory) {
  if (typeof define === 'function' && define.amd) {
    define(['jquery'], factory);
  } else if (typeof exports === 'object') {
    // Node / CommonJS
    factory(require('jquery'));
  } else {
    factory(jQuery);
  }
})(function ($) {

  'use strict';

  var console = window.console || { log: function () {} };

  function CropAvatar($element) {
    this.$container = $element;

    this.$avatarView = this.$container.find('.avatar-view');
    this.$avatar = this.$avatarView.find('img');
    this.$avatarModal = this.$container.find('#avatar-modal');
    this.$loading = this.$container.find('.loading');

    this.$avatarForm = this.$avatarModal.find('.avatar-form');
    this.$avatarUpload = this.$avatarForm.find('.avatar-upload');
    this.$avatarSrc = this.$avatarForm.find('.avatar-src');
    this.$avatarData = this.$avatarForm.find('.avatar-data');
    this.$avatarInput = this.$avatarForm.find('.avatar-input');
    this.$avatarSave = this.$avatarForm.find('.avatar-save');
    this.$avatarBtns = this.$avatarForm.find('.avatar-btns');

    this.$avatarWrapper = this.$avatarModal.find('.avatar-wrapper');
    this.$avatarPreview = this.$avatarModal.find('.avatar-preview');

    this.init();
  }

  CropAvatar.prototype = {
    constructor: CropAvatar,

    support: {
      fileList: !!$('<input type="file">').prop('files'),
      blobURLs: !!window.URL && URL.createObjectURL,
      formData: !!window.FormData
    },

    init: function () {
      this.support.datauri = this.support.fileList && this.support.blobURLs;

      if (!this.support.formData) {
        this.initIframe();
      }

      this.initTooltip();
      this.initModal();
      this.addListener();
    },

    addListener: function () {
      this.$avatarView.on('click', $.proxy(this.click, this));
      this.$avatarInput.on('change', $.proxy(this.change, this));
      this.$avatarForm.on('submit', $.proxy(this.submit, this));
      this.$avatarBtns.on('click', $.proxy(this.rotate, this));
    },

    initTooltip: function () {
      this.$avatarView.tooltip({
        placement: 'bottom'
      });
    },

    initModal: function () {
      this.$avatarModal.modal({
        show: false
      });
    },

    initPreview: function () {
      var url = this.$avatar.attr('src');

      this.$avatarPreview.html('');
    },

    initIframe: function () {
      var target = 'upload-iframe-' + (new Date()).getTime(),
          $iframe = $('').attr({
            name: target,
            src: ''
          }),
          _this = this;

      // Ready ifrmae
      $iframe.one('load', function () {

        // respond response
        $iframe.on('load', function () {
          var data;

          try {
            data = $(this).contents().find('body').text();
          } catch (e) {
            console.log(e.message);
          }

          if (data) {
            try {
              data = $.parseJSON(data);
            } catch (e) {
              console.log(e.message);
            }

            _this.submitDone(data);
          } else {
            _this.submitFail('Image upload failed!');
          }

          _this.submitEnd();

        });
      });

      this.$iframe = $iframe;
      this.$avatarForm.attr('target', target).after($iframe.hide());
    },

    click: function () {
      this.$avatarModal.modal('show');
      this.initPreview();
    },

    change: function () {
      var files,
          file;

      if (this.support.datauri) {
        files = this.$avatarInput.prop('files');

        if (files.length > 0) {
          file = files[0];

          if (this.isImageFile(file)) {
            if (this.url) {
              URL.revokeObjectURL(this.url); // Revoke the old one
            }

            this.url = URL.createObjectURL(file);
            this.startCropper();
          }
        }
      } else {
        file = this.$avatarInput.val();

        if (this.isImageFile(file)) {
          this.syncUpload();
        }
      }
    },

    submit: function () {
      if (!this.$avatarSrc.val() && !this.$avatarInput.val()) {
        return false;
      }

      if (this.support.formData) {
        this.ajaxUpload();
        return false;
      }
    },

    rotate: function (e) {
      var data;

      if (this.active) {
        data = $(e.target).data();

        if (data.method) {
          this.$img.cropper(data.method, data.option);
        }
      }
    },

    isImageFile: function (file) {
      if (file.type) {
        return /^image\/\w+$/.test(file.type);
      } else {
        return /\.(jpg|jpeg|png|gif)$/.test(file);
      }
    },

    startCropper: function () {
      var _this = this;

      if (this.active) {
        this.$img.cropper('replace', this.url);
      } else {
        this.$img = $('');
        this.$avatarWrapper.empty().html(this.$img);
        this.$img.cropper({
          aspectRatio: 1,
          preview: this.$avatarPreview.selector,
          strict: false,
          crop: function (data) {
            var json = [
                  '{"x":' + data.x,
                  '"y":' + data.y,
                  '"height":' + data.height,
                  '"width":' + data.width,
                  '"rotate":' + data.rotate + '}'
                ].join();

            _this.$avatarData.val(json);
          }
        });

        this.active = true;
      }

      this.$avatarModal.one('hidden.bs.modal', function () {
        _this.$avatarPreview.empty();
        _this.stopCropper();
      });
    },

    stopCropper: function () {
      if (this.active) {
        this.$img.cropper('destroy');
        this.$img.remove();
        this.active = false;
      }
    },

    ajaxUpload: function () {
      var url = this.$avatarForm.attr('action'),
          data = new FormData(this.$avatarForm[0]),
          _this = this;

      $.ajax(url, {
        type: 'post',
        data: data,
        dataType: 'json',
        processData: false,
        contentType: false,

        beforeSend: function () {
          _this.submitStart();
        },

        success: function (data) {
          _this.submitDone(data);
        },

        error: function (XMLHttpRequest, textStatus, errorThrown) {
          _this.submitFail(textStatus || errorThrown);
        },

        complete: function () {
          _this.submitEnd();
        }
      });
    },

    syncUpload: function () {
      this.$avatarSave.click();
    },

    submitStart: function () {
      this.$loading.fadeIn();
    },

    submitDone: function (data) {
      console.log(data);

      if ($.isPlainObject(data) && data.state === 200) {
        if (data.result) {
          this.url = data.result;

          if (this.support.datauri || this.uploaded) {
            this.uploaded = false;
            this.cropDone();
          } else {
            this.uploaded = true;
            this.$avatarSrc.val(this.url);
            this.startCropper();
          }

          this.$avatarInput.val('');
        } else if (data.message) {
          this.alert(data.message);
        }
      } else {
        this.alert('Failed to response');
      }
    },

    submitFail: function (msg) {
      this.alert(msg);
    },

    submitEnd: function () {
      this.$loading.fadeOut();
    },

    cropDone: function () {
      this.$avatarForm.get(0).reset();
      this.$avatar.attr('src', this.url);
      this.stopCropper();
      this.$avatarModal.modal('hide');
    },

    alert: function (msg) {
      var $alert = [
            '
',
              '<button type="button" class="close" data-dismiss="alert">×</button>',
              msg,
            '
'
          ].join('');

      this.$avatarUpload.after($alert);
    }
  };

  $(function () {
    return new CropAvatar($('#crop-avatar'));
  });

});
<|endoftext|>