<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */

import React from "react";
import { bindActionCreators, combineReducers } from "redux";
import ReactDOM from "react-dom";
const { Provider } = require("react-redux");

import {
  getValue,
  isFirefoxPanel,
  isDevelopment,
  isTesting
} from "devtools-config";
import { startSourceMapWorker, stopSourceMapWorker } from "devtools-source-map";
import { startSearchWorker, stopSearchWorker } from "../workers/search";

import {
  startPrettyPrintWorker,
  stopPrettyPrintWorker
} from "../workers/pretty-print";
import { startParserWorker, stopParserWorker } from "../workers/parser";
import configureStore from "../actions/utils/create-store";
import reducers from "../reducers";
import * as selectors from "../selectors";
import App from "../components/App";
import { prefs } from "./prefs";

function renderPanel(component, store) {
  const root = document.createElement("div");
  root.className = "launchpad-root theme-body";
  root.style.setProperty("flex", 1);
  const mount = document.querySelector("#mount");
  mount.appendChild(root);

  ReactDOM.render(
    React.createElement(Provider, { store }, React.createElement(component)),
    root
  );
}

export function bootstrapStore(client, { services, toolboxActions }) {
  const createStore = configureStore({
    log: isTesting() || getValue("logging.actions"),
    timing: isDevelopment(),
    makeThunkArgs: (args, state) => {
      return { ...args, client, ...services, ...toolboxActions };
    }
  });

  const store = createStore(combineReducers(reducers));
  store.subscribe(() => updatePrefs(store.getState()));

  const actions = bindActionCreators(
    require("../actions").default,
    store.dispatch
  );

  return { store, actions, selectors };
}

export function bootstrapWorkers() {
  if (!isFirefoxPanel()) {
    // When used in Firefox, the toolbox manages the source map worker.
    startSourceMapWorker(getValue("workers.sourceMapURL"));
  }
  startPrettyPrintWorker(getValue("workers.prettyPrintURL"));
  startParserWorker(getValue("workers.parserURL"));
  startSearchWorker(getValue("workers.searchURL"));
}

export function teardownWorkers() {
  if (!isFirefoxPanel()) {
    // When used in Firefox, the toolbox manages the source map worker.
    stopSourceMapWorker();
  }
  stopPrettyPrintWorker();
  stopParserWorker();
  stopSearchWorker();
}

export function bootstrapApp(store) {
  if (isFirefoxPanel()) {
    renderPanel(App, store);
  } else {
    const { renderRoot } = require("devtools-launchpad");
    renderRoot(React, ReactDOM, App, store);
  }
}

function updatePrefs(state) {
  const pendingBreakpoints = selectors.getPendingBreakpoints(state);

  if (prefs.pendingBreakpoints !== pendingBreakpoints) {
    prefs.pendingBreakpoints = pendingBreakpoints;
  }
}
<commit_msg>add flow header to src/utils/bootstrap.js (#5873)<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */

// @flow

import React from "react";
import { bindActionCreators, combineReducers } from "redux";
import ReactDOM from "react-dom";
const { Provider } = require("react-redux");

import {
  getValue,
  isFirefoxPanel,
  isDevelopment,
  isTesting
} from "devtools-config";
import { startSourceMapWorker, stopSourceMapWorker } from "devtools-source-map";
import { startSearchWorker, stopSearchWorker } from "../workers/search";

import {
  startPrettyPrintWorker,
  stopPrettyPrintWorker
} from "../workers/pretty-print";
import { startParserWorker, stopParserWorker } from "../workers/parser";
import configureStore from "../actions/utils/create-store";
import reducers from "../reducers";
import * as selectors from "../selectors";
import App from "../components/App";
import { prefs } from "./prefs";

function renderPanel(component, store) {
  const root = document.createElement("div");
  root.className = "launchpad-root theme-body";
  root.style.setProperty("flex", "1");
  const mount = document.querySelector("#mount");
  if (!mount) {
    return;
  }
  mount.appendChild(root);

  ReactDOM.render(
    React.createElement(Provider, { store }, React.createElement(component)),
    root
  );
}

export function bootstrapStore(client: any, { services, toolboxActions }: any) {
  const createStore = configureStore({
    log: isTesting() || getValue("logging.actions"),
    timing: isDevelopment(),
    makeThunkArgs: (args, state) => {
      return { ...args, client, ...services, ...toolboxActions };
    }
  });

  const store = createStore(combineReducers(reducers));
  store.subscribe(() => updatePrefs(store.getState()));

  const actions = bindActionCreators(
    require("../actions").default,
    store.dispatch
  );

  return { store, actions, selectors };
}

export function bootstrapWorkers() {
  if (!isFirefoxPanel()) {
    // When used in Firefox, the toolbox manages the source map worker.
    startSourceMapWorker(getValue("workers.sourceMapURL"));
  }
  startPrettyPrintWorker(getValue("workers.prettyPrintURL"));
  startParserWorker(getValue("workers.parserURL"));
  startSearchWorker(getValue("workers.searchURL"));
}

export function teardownWorkers() {
  if (!isFirefoxPanel()) {
    // When used in Firefox, the toolbox manages the source map worker.
    stopSourceMapWorker();
  }
  stopPrettyPrintWorker();
  stopParserWorker();
  stopSearchWorker();
}

export function bootstrapApp(store: any) {
  if (isFirefoxPanel()) {
    renderPanel(App, store);
  } else {
    const { renderRoot } = require("devtools-launchpad");
    renderRoot(React, ReactDOM, App, store);
  }
}

function updatePrefs(state: any) {
  const pendingBreakpoints = selectors.getPendingBreakpoints(state);

  if (prefs.pendingBreakpoints !== pendingBreakpoints) {
    prefs.pendingBreakpoints = pendingBreakpoints;
  }
}
<|endoftext|>


<commit_before>
// failures - test failures

var test = require('tap').test
  , fs = require('fs')
  , pickup = require('../')

test('null', function (t) {
  var transformer = pickup()
  t.throws(function () { transformer.write(null) })
  t.notok(transformer.read(), 'should be null')
  t.end()
})

test('crap', function (t) {
  var transformer = pickup()
  t.throws(function () { transformer.write('crap') })
  t.notok(transformer.read(), 'should be null')
  t.end()
})

test('empty string', function (t) {
  var transformer = pickup()
  transformer.write('')
  t.notok(transformer.read(), 'should be null')
  t.end()
})

test('empty xml', function (t) {
  var transformer = pickup()
  transformer.write('<xml></xml>')
  transformer.end()
  t.notok(transformer.read(), 'should be null')
  t.end()
})
<commit_msg>Improve tests<commit_after>
// failures - test failures

var test = require('tap').test
  , fs = require('fs')
  , pickup = require('../')

test('null', function (t) {
  t.throws(function () { pickup().write(null) })
  t.end()
})

test('crap', function (t) {
  t.throws(function () { pickup().write('crap') })
  t.end()
})

test('empty string', function (t) {
  var p = pickup()
  p.write('')
  t.end()
  p.on('readable', function () {
    t.equals(p.read(), null)
    t.end()
  })
})

test('empty xml', function (t) {
  var p = pickup()
  p.write('<xml></xml>')
  p.end()
  p.on('readable', function () {
    t.equals(p.read(), null)
    t.end()
  })
})
<|endoftext|>


<commit_before>const fs = require('fs');

class WeightedQuickUnion {
  constructor() {
    this.numComponents = null;
    this.id = [];
    this.size = [];
  }

  initialize(filePath) {
    fs.readFile(filePath, 'utf-8', (err, data) => {
      if (err !== null) { console.log(err); }
      let parsedData  = data.split('\n');
      this.numComponents = Number(parsedData[0]);

      for (let i = 0; i < this.numComponents; i++) {
        // Set id of each object to itself
        this.id.push(i);
        // Instantiate the size of each component as 1
        this.size.push(1);
      }

      // Read the input and create dynamic connections
      for (let j = 1; j < parsedData.length - 1; j++) {
        let p = Number(parsedData[j].split(' ')[0]);
        let q = Number(parsedData[j].split(' ')[1]);

        if (!this.connected(p, q)) { // Ignore connected components
          this.union(p, q); // Combine unconnected components
          console.log(`Joined ${p} and ${q}`);
        }
      }

      console.log(`Number of components: ${this.count()}`);
    });
  }

  union(p, q) {
    // Put p and q into the same component
    let pRoot = this.root(p);
    let qRoot = this.root(q);

    if (pRoot !== qRoot) {
      // Give p and q the same root if they did not already have the same root
      if (this.size[pRoot] < this.size[qRoot]) {
        // Make the smaller root point to the larger one, and increase its size
        this.id[pRoot] = qRoot;
        this.size[pRoot] += this.size[qRoot];
      } else {
        this.id[qRoot] = pRoot;
        this.size[qRoot] += this.size[pRoot];
      }

      this.numComponents--;
    }
  }

  root(i) {
    // Chase parent pointers until the root is reached
    while (i !== this.id[i]) { i = this.id[i]; }
    return i;
  }

  connected(p, q) {
    // Check if p and q have the same root
    return this.root(p) === this.root(q);
  }

  count() {
    return this.numComponents;
  }
}

const wqu = new WeightedQuickUnion();
wqu.initialize('../../input/union-find/tinyUF.txt');
<commit_msg>Implement two-pass path compression<commit_after>const fs = require('fs');

class WeightedQuickUnion {
  constructor() {
    this.numComponents = null;
    this.id = [];
    this.size = [];
  }

  initialize(filePath) {
    fs.readFile(filePath, 'utf-8', (err, data) => {
      if (err !== null) { console.log(err); }
      let parsedData  = data.split('\n');
      this.numComponents = Number(parsedData[0]);

      for (let i = 0; i < this.numComponents; i++) {
        // Set id of each object to itself
        this.id.push(i);
        // Instantiate the size of each component as 1
        this.size.push(1);
      }

      // Read the input and create dynamic connections
      for (let j = 1; j < parsedData.length - 1; j++) {
        let p = Number(parsedData[j].split(' ')[0]);
        let q = Number(parsedData[j].split(' ')[1]);

        if (!this.connected(p, q)) { // Ignore connected components
          this.union(p, q); // Combine unconnected components
          console.log(`Joined ${p} and ${q}`);
        }
      }

      console.log(`Number of components: ${this.count()}`);
    });
  }

  union(p, q) {
    // Put p and q into the same component
    let pRoot = this.root(p);
    let qRoot = this.root(q);

    if (pRoot !== qRoot) {
      // Give p and q the same root if they did not already have the same root
      if (this.size[pRoot] < this.size[qRoot]) {
        // Make the smaller root point to the larger one, and increase its size
        this.id[pRoot] = qRoot;
        this.size[pRoot] += this.size[qRoot];
      } else {
        this.id[qRoot] = pRoot;
        this.size[qRoot] += this.size[pRoot];
      }

      this.numComponents--;
    }
  }

  root(i) {
    // Chase parent pointers until the root is reached
    while (i !== this.id[i]) {
      while (this.id[i] !== this.id[this.id[i]]) {
        // Two-pass implementation of path compression, pointing to the root
        this.id[i] = this.id[this.id[i]];
      }
      i = this.id[i];
    }

    return i;
  }

  connected(p, q) {
    // Check if p and q have the same root
    return this.root(p) === this.root(q);
  }

  count() {
    return this.numComponents;
  }
}

const wqu = new WeightedQuickUnion();
wqu.initialize('../../input/union-find/tinyUF.txt');
<|endoftext|>


<commit_before>/* eslint-env mocha */
/* eslint max-nested-callbacks: ["error", 8] */

'use strict'

const expect = require('chai').expect
const isNode = require('detect-node')
const fs = require('fs')
const concat = require('concat-stream')
const through = require('through2')
const streamEqual = require('stream-equal')
const path = require('path')
const loadFixture = require('aegir/fixtures')
const FactoryClient = require('./ipfs-factory/client')

let testfile
let testfileBig
let tfbPath
if (isNode) {
  tfbPath = path.join(__dirname, '/fixtures/15mb.random')
  testfileBig = fs.createReadStream(tfbPath, { bufferSize: 128 })
  testfile = loadFixture(__dirname, '/fixtures/testfile.txt')
} else {
  testfile = loadFixture(__dirname, 'fixtures/testfile.txt')
}

describe('.get', () => {
  let ipfs
  let fc

  before(function (done) {
    this.timeout(20 * 1000) // slow CI
    fc = new FactoryClient()
    fc.spawnNode((err, node) => {
      expect(err).to.not.exist
      ipfs = node
      done()
    })
  })

  after((done) => fc.dismantle(done))

  describe('Callback API', () => {
    it('add file for testing', (done) => {
      const expectedMultihash = 'Qma4hjFTnCasJ8PVp3mZbZK5g2vGDT4LByLJ7m8ciyRFZP'

      ipfs.files.add(testfile, (err, res) => {
        expect(err).to.not.exist

        expect(res).to.have.length(1)
        expect(res[0].hash).to.equal(expectedMultihash)
        expect(res[0].path).to.equal(expectedMultihash)
        done()
      })
    })

    it('get with no compression args', (done) => {
      ipfs.get('Qma4hjFTnCasJ8PVp3mZbZK5g2vGDT4LByLJ7m8ciyRFZP', (err, res) => {
        expect(err).to.not.exist

        // accumulate the files and their content
        var files = []

        res.pipe(through.obj((file, enc, next) => {
          file.content.pipe(concat((content) => {
            files.push({
              path: file.path,
              content: content
            })
            next()
          }))
        }, () => {
          expect(files).to.be.length(1)
          expect(files[0].content.toString()).to.contain(testfile.toString())
          done()
        }))
      })
    })

    it('get with archive true', (done) => {
      ipfs.get('Qma4hjFTnCasJ8PVp3mZbZK5g2vGDT4LByLJ7m8ciyRFZP', {
        archive: true
      }, (err, res) => {
        expect(err).to.not.exist

        // accumulate the files and their content
        var files = []

        res.pipe(through.obj((file, enc, next) => {
          file.content.pipe(concat((content) => {
            files.push({
              path: file.path,
              content: content
            })
            next()
          }))
        }, () => {
          expect(files).to.be.length(1)
          expect(files[0].content.toString()).to.contain(testfile.toString())
          done()
        }))
      })
    })

    it('get err with out of range compression level', (done) => {
      ipfs.get('Qma4hjFTnCasJ8PVp3mZbZK5g2vGDT4LByLJ7m8ciyRFZP', {
        compress: true,
        'compression-level': 10
      }, (err, res) => {
        expect(err).to.exist
        expect(err.toString()).to.equal('Error: Compression level must be between 1 and 9')
        done()
      })
    })

    it('get with compression level', (done) => {
      ipfs.get('Qma4hjFTnCasJ8PVp3mZbZK5g2vGDT4LByLJ7m8ciyRFZP', {
        compress: true,
        'compression-level': 1
      }, (err, res) => {
        expect(err).to.not.exist
        done()
      })
    })

    it('add a BIG file (for testing get)', (done) => {
      if (!isNode) { return done() }

      const bigFile = fs.readFileSync(tfbPath)
      const expectedMultihash = 'Qme79tX2bViL26vNjPsF3DP1R9rMKMvnPYJiKTTKPrXJjq'

      ipfs.files.add(bigFile, (err, res) => {
        expect(err).to.not.exist

        expect(res).to.have.length(1)
        expect(res[0].path).to.equal(expectedMultihash)
        expect(res[0].hash).to.equal(expectedMultihash)
        done()
      })
    })

    it('get BIG file', (done) => {
      if (!isNode) { return done() }

      ipfs.get('Qme79tX2bViL26vNjPsF3DP1R9rMKMvnPYJiKTTKPrXJjq', (err, files) => {
        expect(err).to.not.exist

        files.on('data', (file) => {
          // Do not blow out the memory of nodejs :)
          streamEqual(file.content, testfileBig, (err, equal) => {
            expect(err).to.not.exist
            expect(equal).to.be.true
            done()
          })
        })
      })
    })
  })

  describe('Promise API', () => {
    it('get', (done) => {
      ipfs.get('Qma4hjFTnCasJ8PVp3mZbZK5g2vGDT4LByLJ7m8ciyRFZP')
        .then((files) => {
          files.on('data', (file) => {
            let buf = ''
            file.content
              .on('error', (err) => expect(err).to.not.exist)
              .on('data', (data) => {
                buf += data.toString()
              })
              .on('end', () => {
                expect(buf).to.contain(testfile.toString())
                done()
              })
          })
        })
      .catch((err) => {
        expect(err).to.not.exist
      })
    })
  })
})
<commit_msg>test: confirm that loadFixtures does not require special pathing for browser<commit_after>/* eslint-env mocha */
/* eslint max-nested-callbacks: ["error", 8] */

'use strict'

const expect = require('chai').expect
const isNode = require('detect-node')
const fs = require('fs')
const concat = require('concat-stream')
const through = require('through2')
const streamEqual = require('stream-equal')
const path = require('path')
const loadFixture = require('aegir/fixtures')
const FactoryClient = require('./ipfs-factory/client')

const testfile = loadFixture(__dirname, '/fixtures/testfile.txt')
let testfileBig
let tfbPath

if (isNode) {
  tfbPath = path.join(__dirname, '/fixtures/15mb.random')
  testfileBig = fs.createReadStream(tfbPath, { bufferSize: 128 })
}

describe('.get', () => {
  let ipfs
  let fc

  before(function (done) {
    this.timeout(20 * 1000) // slow CI
    fc = new FactoryClient()
    fc.spawnNode((err, node) => {
      expect(err).to.not.exist
      ipfs = node
      done()
    })
  })

  after((done) => fc.dismantle(done))

  describe('Callback API', () => {
    it('add file for testing', (done) => {
      const expectedMultihash = 'Qma4hjFTnCasJ8PVp3mZbZK5g2vGDT4LByLJ7m8ciyRFZP'

      ipfs.files.add(testfile, (err, res) => {
        expect(err).to.not.exist

        expect(res).to.have.length(1)
        expect(res[0].hash).to.equal(expectedMultihash)
        expect(res[0].path).to.equal(expectedMultihash)
        done()
      })
    })

    it('get with no compression args', (done) => {
      ipfs.get('Qma4hjFTnCasJ8PVp3mZbZK5g2vGDT4LByLJ7m8ciyRFZP', (err, res) => {
        expect(err).to.not.exist

        // accumulate the files and their content
        var files = []

        res.pipe(through.obj((file, enc, next) => {
          file.content.pipe(concat((content) => {
            files.push({
              path: file.path,
              content: content
            })
            next()
          }))
        }, () => {
          expect(files).to.be.length(1)
          expect(files[0].content.toString()).to.contain(testfile.toString())
          done()
        }))
      })
    })

    it('get with archive true', (done) => {
      ipfs.get('Qma4hjFTnCasJ8PVp3mZbZK5g2vGDT4LByLJ7m8ciyRFZP', {
        archive: true
      }, (err, res) => {
        expect(err).to.not.exist

        // accumulate the files and their content
        var files = []

        res.pipe(through.obj((file, enc, next) => {
          file.content.pipe(concat((content) => {
            files.push({
              path: file.path,
              content: content
            })
            next()
          }))
        }, () => {
          expect(files).to.be.length(1)
          expect(files[0].content.toString()).to.contain(testfile.toString())
          done()
        }))
      })
    })

    it('get err with out of range compression level', (done) => {
      ipfs.get('Qma4hjFTnCasJ8PVp3mZbZK5g2vGDT4LByLJ7m8ciyRFZP', {
        compress: true,
        'compression-level': 10
      }, (err, res) => {
        expect(err).to.exist
        expect(err.toString()).to.equal('Error: Compression level must be between 1 and 9')
        done()
      })
    })

    it('get with compression level', (done) => {
      ipfs.get('Qma4hjFTnCasJ8PVp3mZbZK5g2vGDT4LByLJ7m8ciyRFZP', {
        compress: true,
        'compression-level': 1
      }, (err, res) => {
        expect(err).to.not.exist
        done()
      })
    })

    it('add a BIG file (for testing get)', (done) => {
      if (!isNode) { return done() }

      const bigFile = fs.readFileSync(tfbPath)
      const expectedMultihash = 'Qme79tX2bViL26vNjPsF3DP1R9rMKMvnPYJiKTTKPrXJjq'

      ipfs.files.add(bigFile, (err, res) => {
        expect(err).to.not.exist

        expect(res).to.have.length(1)
        expect(res[0].path).to.equal(expectedMultihash)
        expect(res[0].hash).to.equal(expectedMultihash)
        done()
      })
    })

    it('get BIG file', (done) => {
      if (!isNode) { return done() }

      ipfs.get('Qme79tX2bViL26vNjPsF3DP1R9rMKMvnPYJiKTTKPrXJjq', (err, files) => {
        expect(err).to.not.exist

        files.on('data', (file) => {
          // Do not blow out the memory of nodejs :)
          streamEqual(file.content, testfileBig, (err, equal) => {
            expect(err).to.not.exist
            expect(equal).to.be.true
            done()
          })
        })
      })
    })
  })

  describe('Promise API', () => {
    it('get', (done) => {
      ipfs.get('Qma4hjFTnCasJ8PVp3mZbZK5g2vGDT4LByLJ7m8ciyRFZP')
        .then((files) => {
          files.on('data', (file) => {
            let buf = ''
            file.content
              .on('error', (err) => expect(err).to.not.exist)
              .on('data', (data) => {
                buf += data.toString()
              })
              .on('end', () => {
                expect(buf).to.contain(testfile.toString())
                done()
              })
          })
        })
      .catch((err) => {
        expect(err).to.not.exist
      })
    })
  })
})
<|endoftext|>


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

import { graphql } from 'gatsby';

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

// separate due to being used in other fragments
// export const OgImageFragment = graphql`
//   fragment OgImageFragment on File {
//     childImageSharp {
//       resize(width: 1200, height: 630) {
//         src
//       }
//     }
//   }
// `;

export const fragments = graphql`
  fragment MetaFragment on frontmatter_2 {
    meta {
      permalink
      title
      description
      # ogImage {
      #   ...OgImageFragment
      # }
    }
  }

  fragment WorkPreviewFragment on Mdx {
    frontmatter {
      title
      meta {
        permalink
        tags
      }
    }
  }

  fragment LabPreviewFragment on Mdx {
    frontmatter {
      title
      tagline
      date
      meta {
        permalink
      }
    }
  }

  fragment BlogPreviewFragment on Mdx {
    timeToRead
    frontmatter {
      title
      permalink
      date(formatString: "MMMM D, YYYY")
    }
  }
`;
<commit_msg>update fragments<commit_after>// ─────────────────────────────────────────────────────────────────────────────
// import
// ─────────────────────────────────────────────────────────────────────────────

import { graphql } from 'gatsby';

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

// separate due to being used in other fragments
export const OgImageFragment = graphql`
  fragment OgImageFragment on File {
    childImageSharp {
      resize(width: 1200, height: 630) {
        src
      }
    }
  }
`;

export const fragments = graphql`
  fragment MetaFragment on MdxFrontmatter {
    meta {
      permalink
      title
      description
      ogImage {
        ...OgImageFragment
      }
    }
  }

  fragment WorkPreviewFragment on Mdx {
    frontmatter {
      title
      meta {
        permalink
        tags
      }
    }
  }

  fragment LabPreviewFragment on Mdx {
    frontmatter {
      title
      tagline
      date
      meta {
        permalink
      }
    }
  }

  fragment BlogPreviewFragment on Mdx {
    timeToRead
    frontmatter {
      title
      permalink
      date(formatString: "MMMM D, YYYY")
    }
  }
`;
<|endoftext|>


<commit_before>/* @flow strict-local */
import type { PmRecipientUser, Message, Outbox, User } from '../types';

// TODO types: this union is confusing
export const normalizeRecipients = (recipients: $ReadOnlyArray<{ email: string }> | string) =>
  !Array.isArray(recipients)
    ? recipients
    : recipients
        .map(s => s.email.trim())
        .filter(x => x.length > 0)
        .sort()
        .join(',');

export const normalizeRecipientsSansMe = (
  recipients: $ReadOnlyArray<{ email: string }>,
  ownEmail: string,
) =>
  recipients.length === 1
    ? recipients[0].email
    : normalizeRecipients(recipients.filter(r => r.email !== ownEmail));

/**
 * Returns a filtered array of recipients for a private message.
 * If the message is a self PM, returns an array containing a single
 * element - the current user. Otherwise, returns all recipients
 * except the current user.
 */
export const filteredRecipientsForPM = (
  message: Message | Outbox,
  ownUser: User,
): PmRecipientUser[] => {
  if (message.type !== 'private') {
    throw new Error('filteredRecipientsForPM: expected PM, got stream message');
  }
  const { display_recipient } = message;
  return display_recipient.length === 1
    ? display_recipient
    : display_recipient.filter(r => r.id !== ownUser.user_id);
};

export const getRecipientsIds = (recipients: PmRecipientUser[], ownEmail?: string): string =>
  recipients.length === 2
    ? recipients.filter(r => r.email !== ownEmail)[0].id.toString()
    : recipients
        .map(s => s.id)
        .sort((a, b) => a - b)
        .join(',');

export const isSameRecipient = (
  message1: Message | Outbox,
  message2: Message | Outbox,
): boolean => {
  if (message1 === undefined || message2 === undefined) {
    return false;
  }

  if (message1.type !== message2.type) {
    return false;
  }

  switch (message1.type) {
    case 'private':
      return (
        normalizeRecipients(message1.display_recipient).toLowerCase()
        === normalizeRecipients(message2.display_recipient).toLowerCase()
      );
    case 'stream':
      return (
        message1.display_recipient.toLowerCase() === message2.display_recipient.toLowerCase()
        && message1.subject.toLowerCase() === message2.subject.toLowerCase()
      );
    default:
      // Invariant
      return false;
  }
};
<commit_msg>recipient [nfc]: Factor out a small helper filterRecipients.<commit_after>/* @flow strict-local */
import type { PmRecipientUser, Message, Outbox, User } from '../types';

// Filter a list of PM recipients in the quirky way that we do.
//
// This is a module-private helper.  See caller for jsdoc.
const filterRecipients = (recipients: PmRecipientUser[], ownUserId: number): PmRecipientUser[] =>
  recipients.length === 1 ? recipients : recipients.filter(r => r.id !== ownUserId);

// TODO types: this union is confusing
export const normalizeRecipients = (recipients: $ReadOnlyArray<{ email: string }> | string) =>
  !Array.isArray(recipients)
    ? recipients
    : recipients
        .map(s => s.email.trim())
        .filter(x => x.length > 0)
        .sort()
        .join(',');

export const normalizeRecipientsSansMe = (
  recipients: $ReadOnlyArray<{ email: string }>,
  ownEmail: string,
) =>
  recipients.length === 1
    ? recipients[0].email
    : normalizeRecipients(recipients.filter(r => r.email !== ownEmail));

/**
 * Returns a filtered array of recipients for a private message.
 * If the message is a self PM, returns an array containing a single
 * element - the current user. Otherwise, returns all recipients
 * except the current user.
 */
export const filteredRecipientsForPM = (
  message: Message | Outbox,
  ownUser: User,
): PmRecipientUser[] => {
  if (message.type !== 'private') {
    throw new Error('filteredRecipientsForPM: expected PM, got stream message');
  }
  return filterRecipients(message.display_recipient, ownUser.user_id);
};

export const getRecipientsIds = (recipients: PmRecipientUser[], ownEmail?: string): string =>
  recipients.length === 2
    ? recipients.filter(r => r.email !== ownEmail)[0].id.toString()
    : recipients
        .map(s => s.id)
        .sort((a, b) => a - b)
        .join(',');

export const isSameRecipient = (
  message1: Message | Outbox,
  message2: Message | Outbox,
): boolean => {
  if (message1 === undefined || message2 === undefined) {
    return false;
  }

  if (message1.type !== message2.type) {
    return false;
  }

  switch (message1.type) {
    case 'private':
      return (
        normalizeRecipients(message1.display_recipient).toLowerCase()
        === normalizeRecipients(message2.display_recipient).toLowerCase()
      );
    case 'stream':
      return (
        message1.display_recipient.toLowerCase() === message2.display_recipient.toLowerCase()
        && message1.subject.toLowerCase() === message2.subject.toLowerCase()
      );
    default:
      // Invariant
      return false;
  }
};
<|endoftext|>


<commit_before>import gql from 'graphql-tag';

export default gql`
  mutation createChannelMutation($title: String!) {
    create_channel(input: { title: $title }) {
      channel {
        id: slug
        href
        title
      }
    }
  }
`;
<commit_msg>Make channel private by default<commit_after>import gql from 'graphql-tag';

export default gql`
  mutation createChannelMutation($title: String!, $visibility: ChannelVisibility = PRIVATE) {
    create_channel(input: { title: $title, visibility: $visibility }) {
      channel {
        id: slug
        href
        title
      }
    }
  }
`;
<|endoftext|>


<commit_before>'use strict'

const Joi = require('joi')
const RecordTypeA = require('./record_type_a')
const RecordTypeAAAA = require('./record_type_aaaa')
const RecordTypeCNAME = require('./record_type_cname')
const RecordTypeMX = require('./record_type_mx')
const RecordTypeNS = require('./record_type_ns')
const RecordTypeSOA = require('./record_type_soa')
const RecordTypeSRV = require('./record_type_srv')
const RecordTypeTXT = require('./record_type_txt')
const zoneName = require('./zone_name')

const schema = Joi.object().keys({
  name: zoneName.required(),
  records: Joi.array().items(
    RecordTypeA, RecordTypeAAAA, RecordTypeCNAME, RecordTypeMX, RecordTypeNS,
    RecordTypeSOA, RecordTypeSRV, RecordTypeTXT
  ),
  vendor: Joi.object()
})

module.exports = function (zone, config) {
  return new Promise((resolve, reject) => {
    const response = {
      errors: {}
    }

    Joi.validate(zone, schema, (err, value) => {
      response.valid = !err

      // Expose the error objects to the caller.
      if (err) {
        response.errors.zone = err
      }

      resolve(response)
    })
  })
}
<commit_msg>Allow IDs on zones<commit_after>'use strict'

const Joi = require('joi')
const RecordTypeA = require('./record_type_a')
const RecordTypeAAAA = require('./record_type_aaaa')
const RecordTypeCNAME = require('./record_type_cname')
const RecordTypeMX = require('./record_type_mx')
const RecordTypeNS = require('./record_type_ns')
const RecordTypeSOA = require('./record_type_soa')
const RecordTypeSRV = require('./record_type_srv')
const RecordTypeTXT = require('./record_type_txt')
const zoneName = require('./zone_name')

const schema = Joi.object().keys({
  // Implementation specific, any kind of ID is allowed.
  id: Joi.any(),
  name: zoneName.required(),
  records: Joi.array().items(
    RecordTypeA, RecordTypeAAAA, RecordTypeCNAME, RecordTypeMX, RecordTypeNS,
    RecordTypeSOA, RecordTypeSRV, RecordTypeTXT
  ),
  vendor: Joi.object()
})

module.exports = function (zone, config) {
  return new Promise((resolve, reject) => {
    const response = {
      errors: {}
    }

    Joi.validate(zone, schema, (err, value) => {
      response.valid = !err

      // Expose the error objects to the caller.
      if (err) {
        response.errors.zone = err
      }

      resolve(response)
    })
  })
}
<|endoftext|>


<commit_before>import fetch from './fetch.js'
import addCacheBustToQuery from './common/add-cache-bust-to-query.js'

export default function checkIfFileExists (url) {
  return fetch(
    addCacheBustToQuery(url),
    {
      method: 'HEAD',
      cache: 'reload'
    }
  ).then(function onSuccess(response){
    // response.ok provides boolean type information on request status
    // https://developer.mozilla.org/en-US/docs/Web/API/Response/ok
    return response.ok
  }, function onReject(){
    return false
  })
}<commit_msg>adds param check<commit_after>import fetch from './fetch.js'
import addCacheBustToQuery from './common/add-cache-bust-to-query.js'

export default function checkIfFileExists (url) {

  if (!url) return Promise.reject('Please provide file URL string as param.')

  return fetch( addCacheBustToQuery(url), {
    method: 'HEAD',
    cache: 'reload'
  }).then(function onSuccess (response) {
    // response.ok provides boolean type information on request status
    // https://developer.mozilla.org/en-US/docs/Web/API/Response/ok
    return response.ok
  }, function onReject () {
    return false
  })
}<|endoftext|>


<commit_before>/*! videojs-preroll - v0.0.0 - 2014-07-16
* Copyright (c) 2014 Dirk-jan; Licensed MIT */
(function(window, videojs) {
  'use strict';

  var defaults = {
    src : '',
    href : '',
    target: '_blank',
    allowSkip: true,
    skipTime: 5
  }, prerollPlugin;

  /**
   * Initialize the plugin.
   *
   * @param options
   *            (optional) {object} configuration for the plugin
   */
  prerollPlugin = function(options) {
    var settings = videojs.util.mergeOptions(defaults, options), player = this;
    player.on('contentupdate', function() {
      player.trigger('adsready');
    });
    player.preroll = {};
    player.on('readyforpreroll', function() {
      // No video? No ad.
      if (settings.src === ''){
        return;
      }

      // Initialize ad mode
      player.ads.startLinearAdMode();
      // Change player src to ad src
      player.src(settings.src);
      player.one('durationchange', function() {
        player.play();
      });

      // link overlay
      var blocker = document.createElement('a');
      blocker.className = 'preroll-blocker';
      blocker.href = settings.href || '#';
      blocker.target = settings.target || '_blank';
      blocker.onclick = function() {
        player.trigger('adclick');
      };
      player.preroll.blocker = blocker;
      player.el().insertBefore(blocker, player.controlBar.el());
      if (settings.allowSkip !== false){
        var skipButton = document.createElement('div');
        skipButton.className = 'preroll-skip-button';
        player.preroll.skipButton = skipButton;
        player.el().appendChild(skipButton);

        skipButton.onclick = function(e) {
          var Event = Event || window.Event;
          if((' ' + player.preroll.skipButton.className + ' ').indexOf(' enabled ') >= 0) {
            player.preroll.tearDown();
          }
          if(Event.prototype.stopPropagation !== undefined) {
            e.stopPropagation();
          } else {
            return false;
          }
        };
      }
      player.one('ended', player.preroll.exitPreroll);
      player.on('timeupdate', player.preroll.timeupdate);
    });
    player.preroll.exitPreroll = function() {
      player.preroll.skipButton.parentNode.removeChild(player.preroll.skipButton);
      player.preroll.blocker.parentNode.removeChild(player.preroll.blocker);
      player.off('timeupdate', player.preroll.timeupdate);
      player.off('ended', player.preroll.exitPreroll);
      player.ads.endLinearAdMode();
    };
    player.preroll.timeupdate = function(e) {
      player.loadingSpinner.el().style.display = 'none';
      var timeLeft = Math.ceil(settings.skipTime - player.currentTime());
      if(timeLeft > 0) {
        player.preroll.skipButton.innerHTML = 'Skip in ' + timeLeft + '...';
      } else {
        if((' ' + player.preroll.skipButton.className + ' ').indexOf(' enabled ') === -1){
          player.preroll.skipButton.className += ' enabled';
          player.preroll.skipButton.innerHTML = 'Skip';
        }
      }
    };
  };

  // register the plugin
  videojs.plugin('preroll', prerollPlugin);
})(window, window.videojs);
<commit_msg>Fixed copyright header<commit_after>/*! videojs-preroll - v0.1.0 - 2014-07-16
* Copyright (c) 2014 Sano Webdevelopment;
* Copyright (c) 2014 The Onion
* Licensed MIT */
(function(window, videojs) {
  'use strict';

  var defaults = {
    src : '',
    href : '',
    target: '_blank',
    allowSkip: true,
    skipTime: 5
  }, prerollPlugin;

  /**
   * Initialize the plugin.
   *
   * @param options
   *            (optional) {object} configuration for the plugin
   */
  prerollPlugin = function(options) {
    var settings = videojs.util.mergeOptions(defaults, options), player = this;
    player.on('contentupdate', function() {
      player.trigger('adsready');
    });
    player.preroll = {};
    player.on('readyforpreroll', function() {
      // No video? No ad.
      if (settings.src === ''){
        return;
      }

      // Initialize ad mode
      player.ads.startLinearAdMode();
      // Change player src to ad src
      player.src(settings.src);
      player.one('durationchange', function() {
        player.play();
      });

      // link overlay
      var blocker = document.createElement('a');
      blocker.className = 'preroll-blocker';
      blocker.href = settings.href || '#';
      blocker.target = settings.target || '_blank';
      blocker.onclick = function() {
        player.trigger('adclick');
      };
      player.preroll.blocker = blocker;
      player.el().insertBefore(blocker, player.controlBar.el());
      if (settings.allowSkip !== false){
        var skipButton = document.createElement('div');
        skipButton.className = 'preroll-skip-button';
        player.preroll.skipButton = skipButton;
        player.el().appendChild(skipButton);

        skipButton.onclick = function(e) {
          var Event = Event || window.Event;
          if((' ' + player.preroll.skipButton.className + ' ').indexOf(' enabled ') >= 0) {
            player.preroll.tearDown();
          }
          if(Event.prototype.stopPropagation !== undefined) {
            e.stopPropagation();
          } else {
            return false;
          }
        };
      }
      player.one('ended', player.preroll.exitPreroll);
      player.on('timeupdate', player.preroll.timeupdate);
    });
    player.preroll.exitPreroll = function() {
      player.preroll.skipButton.parentNode.removeChild(player.preroll.skipButton);
      player.preroll.blocker.parentNode.removeChild(player.preroll.blocker);
      player.off('timeupdate', player.preroll.timeupdate);
      player.off('ended', player.preroll.exitPreroll);
      player.ads.endLinearAdMode();
    };
    player.preroll.timeupdate = function(e) {
      player.loadingSpinner.el().style.display = 'none';
      var timeLeft = Math.ceil(settings.skipTime - player.currentTime());
      if(timeLeft > 0) {
        player.preroll.skipButton.innerHTML = 'Skip in ' + timeLeft + '...';
      } else {
        if((' ' + player.preroll.skipButton.className + ' ').indexOf(' enabled ') === -1){
          player.preroll.skipButton.className += ' enabled';
          player.preroll.skipButton.innerHTML = 'Skip';
        }
      }
    };
  };

  // register the plugin
  videojs.plugin('preroll', prerollPlugin);
})(window, window.videojs);
<|endoftext|>


<commit_before>import React from 'react'
import { Link } from 'react-router'

const AboutView = () => (

This is the about view!

    <Link to='/'>Back To Home View</Link>

)

export default AboutView
<commit_msg>refactor(AboutView): switch to component class<commit_after>import React from 'react'
import { Link } from 'react-router'

export class AboutView extends React.Component {
  render () {
    return (

This is the about view!

        <Link to='/'>Back To Home View</Link>

    )
  }
}

export default AboutView
<|endoftext|>


<commit_before>var expect = require('chai').expect,
    moment = require('moment'),
    sinon = require('sinon'),
    async = require('async'),
    _ = require('lodash'),
    testHelper = require('../helper'),
    jobModel = require('../../models/jobs');

describe('Jobs', function() {
  var dbs = [];
  var jobs;
  beforeEach(function(done) {
    async.times(2, testHelper.connectToDB, function(err, results) {
      dbs = results;
      jobs = require('../../lib/jobs')(dbs[0]);
      done(err);
    });
  });

  afterEach(function() {
    _.invoke(dbs, 'end');
  });

  function lockJob(db, jobId, callback) {
    db.query('begin', doLocks);
    function doLocks(err, result) {
      if (err) return done(err);
      // Note: In this test we use the job_snapshot id not the job_id as
      // that is how the locking is done in the query that grabs the next
      // job.
      // This only locks one row (not all the snapshots for the job). It
      // probably would be fine to lock on the job_id, but it is not
      // necessary as we should only ever have one snapshot of a given job
      // that is up for processing...
      db.query('select pg_try_advisory_xact_lock(id) from job_snapshots ' +
          'where job_id = $1 and processed IS NULL', [jobId], callback);
    }
  }

  describe('#create', function() {
    beforeEach(function(done) {
      dbs[1].query('delete from job_snapshots', done);
    });

    it('creates a job with given initial state, time ' +
      'to process in and payload, returning said job as well.',
      function(done) {
        var now = moment();
        var cb = function() {
          jobModel.getJobs(dbs[0], function(err, result) {
            if (err) return done(err);

            expect(result.length).to.equal(1);
            expect(result[0]).to.have.property('process_at');
            expect(moment(result[0].process_at).diff(now.add('seconds',
                100), 'seconds')).to.equal(0);
            expect(result[0].data).to.have.property('state', 'waiting');
            done();
          });
        };
        jobs.create({state: 'waiting', date: 'some'}, 100 * 1000, cb);
      });
  });

  /** Consume jobs waiting for service.
   * process(callback) calls the supplied callback on each job that is
   * awaiting service.
   * Callback must be of the form: callback(id, job, done).
   * When callback is finished providing service to the job, done should be
   * called with the updated job data, like so:
   * done(error, newJobData, msUntilNextProcessing);
   * If error is non-null then no updates will be made to the job.
   * If msUntilNextProcessing is null, then the job will not be serviced again.
   * See below for an example callback (jobIterator).
   */
  describe('#process', function() {
    var jobIterator = function(id, job, jobDone) {
      console.log('user job iterator');
      function error() {
        // We just always error for this test.
        return true;
      }

      console.log('user job iterator from tests:');
      console.log(job);
      if (error() && job.retriesRemaining > 0 ) {
        return jobDone(null, {
          state: 'pendingRetry',
          log: 'it failed!, retrying soon',
          retriesRemaining: --job.retriesRemaining
        }, 2);
      } else if (error()) {
        return jobDone(null, {
          state : 'permanentlyFailed',
          log: 'it failed and we are stopping here!',
          retriesRemaining: 0
        }, null);
      } else {
        return jobDone(null, {
          state : 'complete',
          log: 'it worked!',
          retriesRemaining: 0
        }, null);
      }
    };

    var maybeServiceJobCount, jobUpdatedCount;

    var maybeServiceJob = function() {
      maybeServiceJobCount++;
    };

    var jobUpdated = function() {
      jobUpdatedCount++;
    };

    beforeEach(function() {
      maybeServiceJobCount = 0;
      jobUpdatedCount = 0;

      jobs.eventEmitter.removeAllListeners();
      jobs.eventEmitter.on('jobUpdated', jobUpdated);
      jobs.eventEmitter.on('maybeServiceJob', maybeServiceJob);
    });

    afterEach(function() {
      jobs.stopProcessing();
    });

    it('re-schedules a job iff a non-null serviceNextIn property is provided',
          function(done) {
      // Set up jobs data
      jobModel.setJobs(dbs[0], [{
        data: {
          retriesRemaining: 3
        },
        process_at: moment().add('milliseconds', 1)
      }, {
        data: {
          retriesRemaining: 2
        },
        process_at: moment().add('milliseconds', 4)
      }, {
        data: {
          retriesRemaining: 2
        },
        process_at: moment().add('milliseconds', 5)
      }]);

      // Set up our condition
      jobs.eventEmitter.on('jobUpdated', function() {
        // Should need 10 iterations for all jobs to retried out of existence.
        // Each job will be provided service until no retries remaining, then
        // once more to figure out that we need to permanently fail it (and
        // hence not requeue.)
        // I.e. retries remaining for each job + no. jobs initially == 10
        if (jobUpdatedCount == 10) {
          jobModel.scheduledJobs(dbs[0], function(err, result) {
            expect(result.length, 'length of job queue').
              to.equal(0);
            done();
          });
        }
      });

      // Run the test
      jobs.process(jobIterator);
    });

    // Just binds test and prep together.
    describe('', function() {
      beforeEach(function(done) {
        // Set up some jobs.
        jobModel.setJobs(dbs[0], [{
          data: {
            retriesRemaining: 1,
            wee: 'wah'
          },
          process_at: moment().add('milliseconds', 1)
        }, {
          data: {
            retriesRemaining: 5,
            boo: 'hoo'
          },
          process_at: moment().add('milliseconds', 40000)
        }], done);
      });

      it('provides service to a job iff correct number of ms have elapsed.',
          function(done) {
        // Set up our condition.
        jobs.eventEmitter.on('maybeServiceJob', function() {
          // The condition below should hold by 10 attempts to process jobs...
          if (maybeServiceJobCount == 10) {
            // Only the first job should have got service, and only twice as it
            // only had one retry remaining.
            expect(jobUpdatedCount, 'number of times we serviced a job').
              to.equal(2);

            done();
          }
        });

        // Run the test.
        jobs.process(jobIterator);
      });
    });

    // Just binds test and setup together.
    describe('', function() {
      beforeEach(function(done) {
        jobModel.setJobs(dbs[0], [{
          job_id: 1,
          data: {
            retriesRemaining: 1
          },
          process_at: moment().add('milliseconds', 0)
        }, {
          data: {
            retriesRemaining: 5
          },
          process_at: moment().add('milliseconds', 0)
        }, {
          data: {
            retriesRemaining: 5
          },
          process_at: moment().add('milliseconds', 10000)
        }], lockFirstJob);

        function lockFirstJob() {
          lockJob(dbs[1], 1, done);
        }
      });

      it('provides service to a job iff job is not locked.',
          function(done) {

        // Set up our condition.
        jobs.eventEmitter.on('maybeServiceJob', function() {
          // The condition below should hold by 10 attempts to process jobs...
          if (maybeServiceJobCount == 10) {
            // Only the second job should have got service, six times.
            // This test also shows starvation does not occur, as the first
            // job should be considered for service first (but is locked).
            // Correct behaviour is to move on to the second.
            expect(jobUpdatedCount, 'number of times we serviced a job').
              to.equal(6);
            done();
          }
        });

        // Run the test.
        jobs.process(jobIterator);
      });
    });

    //bind setup and test together
    describe('', function() {
      beforeEach(function(done) {
        jobModel.setJobs(dbs[0], [{
          data: [],
          process_at: moment()
        }], done);
      });

      it('saves the newJobData in a job, appending it to the history of job data',
          function(done) {
        var iterator = function(id, job, cb) {
          return cb(null, {
            state: 'complete',
            name: "tim"
          }, null);
        };

        jobs.eventEmitter.on('processCommitted', function() {
          jobs.stopProcessing();
          jobModel.getJobs(dbs[1], function(err, result) {
            if (err) return done(err);
            expect(result).to.have.length(2);
            done();
          });
        });

        jobs.process(iterator);
      });
    });
  });
  describe('#processNow', function() {
    describe('', function() {
      beforeEach(function(done) {
        // Set up some jobs.
        jobModel.setJobs(dbs[1], [{
          job_id: 1,
          data: {
            retriesRemaining: 1
          },
          process_at: moment().add('milliseconds', 10000).toDate()
        }, {
          job_id: 2,
          data: {
            retriesRemaining: 5
          },
          process_at: moment().add('milliseconds', 40000).toDate()
        }], done);
      });

      it('immediately runs the callback on the requested job, updating it',
          function(done) {
        var iterator = function(err, job, cb) {
          return cb(null, job, 200);
        };

        // Set up condition
        var checkConditions =  function() {
          console.log('checkConditions');
          jobModel.getJobs(dbs[1], function(err, result) {
            if (err) return done(err);
            expect(result.length).to.equal(3);
            expect(result[2].data).to.have.property('retriesRemaining');
            done();
          });
        };

        // Run the test.
        jobs.processNow(1, iterator, checkConditions);
      });
    });

    describe('', function() {
      beforeEach(function(done) {
        // TODO: lock this job
        jobModel.setJobs(dbs[0], [{
          job_id: 1,
          data: {
            retriesRemaining: 1
          },
          process_at: moment().add('milliseconds', 10000).toDate()
        }], lockFirstJob);

        function lockFirstJob(err) {
          if (err) return done(err);
          console.log('lockFirstJob');
          lockJob(dbs[1], 1, done);
        }
      });

      it('waits until the lock is ceeded if process() has got hold of the job',
          function(done) {
        // We first obtain a lock on the job. Then we run processNow().
        // It should be waiting.  We then release our lock.  We then see that
        // it ran.

        var iterator = function(err, job, cb) {
          jobModel.getJobs(dbs[0], function(err, result) {
            if (err) return done(err);
            return cb(null, job, 200);
          });
        };

        var wasWaiting = false;

        jobs.eventEmitter.on('lockSought', function() {
          console.log('lockSought');
          // Yes, this is hacky.  We assume that the obtaining of the lock
          // will always take < 100ms.  I could mock out the dbs[0], but this would
          // then be less 'realistic'.  Open to suggestions on how to do this
          // better!
          setTimeout(shouldBeWaiting, 100);
        });

        function shouldBeWaiting() {
          wasWaiting = true;
          dbs[1].query('commit');
        }

        jobs.eventEmitter.on('lockObtained', function(err) {
          if (err) return done(err);
          console.log('lockObtained');
          expect(wasWaiting).to.equal(true);
          done();
        });

        // Run the test.
        jobs.processNow(1, iterator, done);
      });
    });
  });

  describe.skip('#getHistory', function() {
    it('gets the requested job history', function(done) {
      // Set up some jobs.
      jobModel.setJobs([{
        id: 1,
        jobData: [{
          retriesRemaining: 1
        }],
        processNext: moment().add('milliseconds', 10000).toDate()
      }, {
        id: 2,
        jobData: [{
          retriesRemaining: 7
        },
        { retriesRemaining: 6
        }],
        processNext: moment().add('milliseconds', 40000).toDate()
      }]);

      function cb(err, jobHistory) {
        expect(jobHistory).to.eql([{
          retriesRemaining: 7
        },
        {
          retriesRemaining: 6
        }]);
        done();
      }
      jobs.getHistory(2, cb);
    });
  });
});

// vim: set et sw=2 ts=2 colorcolumn=80:
<commit_msg>Fix up test designations a bit.<commit_after>var expect = require('chai').expect,
    moment = require('moment'),
    sinon = require('sinon'),
    async = require('async'),
    _ = require('lodash'),
    testHelper = require('../helper'),
    jobModel = require('../../models/jobs');

describe('Jobs', function() {
  var dbs = [];
  var jobs;
  beforeEach(function(done) {
    async.times(2, testHelper.connectToDB, function(err, results) {
      dbs = results;
      jobs = require('../../lib/jobs')(dbs[0]);
      done(err);
    });
  });

  afterEach(function() {
    _.invoke(dbs, 'end');
  });

  function lockJob(db, jobId, callback) {
    db.query('begin', doLocks);
    function doLocks(err, result) {
      if (err) return done(err);
      // Note: In this test we use the job_snapshot id not the job_id as
      // that is how the locking is done in the query that grabs the next
      // job.
      // This only locks one row (not all the snapshots for the job). It
      // probably would be fine to lock on the job_id, but it is not
      // necessary as we should only ever have one snapshot of a given job
      // that is up for processing...
      db.query('select pg_try_advisory_xact_lock(id) from job_snapshots ' +
          'where job_id = $1 and processed IS NULL', [jobId], callback);
    }
  }

  describe('#create', function() {
    beforeEach(function(done) {
      dbs[1].query('delete from job_snapshots', done);
    });

    it('creates a job with given initial state, time ' +
      'to process in and payload, returning said job as well.',
      function(done) {
        var now = moment();
        var cb = function() {
          jobModel.getJobs(dbs[0], function(err, result) {
            if (err) return done(err);

            expect(result.length).to.equal(1);
            expect(result[0]).to.have.property('process_at');
            expect(moment(result[0].process_at).diff(now.add('seconds',
                100), 'seconds')).to.equal(0);
            expect(result[0].data).to.have.property('state', 'waiting');
            done();
          });
        };
        jobs.create({state: 'waiting', date: 'some'}, 100 * 1000, cb);
      });
  });

  /** Consume jobs waiting for service.
   * process(callback) calls the supplied callback on each job that is
   * awaiting service.
   * Callback must be of the form: callback(id, job, done).
   * When callback is finished providing service to the job, done should be
   * called with the updated job data, like so:
   * done(error, newJobData, msUntilNextProcessing);
   * If error is non-null then no updates will be made to the job.
   * If msUntilNextProcessing is null, then the job will not be serviced again.
   * See below for an example callback (jobIterator).
   */
  describe('#process', function() {
    var jobIterator = function(id, job, jobDone) {
      console.log('user job iterator');
      function error() {
        // We just always error for this test.
        return true;
      }

      console.log('user job iterator from tests:');
      console.log(job);
      if (error() && job.retriesRemaining > 0 ) {
        return jobDone(null, {
          state: 'pendingRetry',
          log: 'it failed!, retrying soon',
          retriesRemaining: --job.retriesRemaining
        }, 2);
      } else if (error()) {
        return jobDone(null, {
          state : 'permanentlyFailed',
          log: 'it failed and we are stopping here!',
          retriesRemaining: 0
        }, null);
      } else {
        return jobDone(null, {
          state : 'complete',
          log: 'it worked!',
          retriesRemaining: 0
        }, null);
      }
    };

    var maybeServiceJobCount, jobUpdatedCount;

    var maybeServiceJob = function() {
      maybeServiceJobCount++;
    };

    var jobUpdated = function() {
      jobUpdatedCount++;
    };

    beforeEach(function() {
      maybeServiceJobCount = 0;
      jobUpdatedCount = 0;

      jobs.eventEmitter.removeAllListeners();
      jobs.eventEmitter.on('jobUpdated', jobUpdated);
      jobs.eventEmitter.on('maybeServiceJob', maybeServiceJob);
    });

    afterEach(function() {
      jobs.stopProcessing();
    });

    it('re-schedules a job iff a non-null serviceNextIn property is provided',
          function(done) {
      // Set up jobs data
      jobModel.setJobs(dbs[0], [{
        data: {
          retriesRemaining: 3
        },
        process_at: moment().add('milliseconds', 1)
      }, {
        data: {
          retriesRemaining: 2
        },
        process_at: moment().add('milliseconds', 4)
      }, {
        data: {
          retriesRemaining: 2
        },
        process_at: moment().add('milliseconds', 5)
      }]);

      // Set up our condition
      jobs.eventEmitter.on('jobUpdated', function() {
        // Should need 10 iterations for all jobs to retried out of existence.
        // Each job will be provided service until no retries remaining, then
        // once more to figure out that we need to permanently fail it (and
        // hence not requeue.)
        // I.e. retries remaining for each job + no. jobs initially == 10
        if (jobUpdatedCount == 10) {
          jobModel.scheduledJobs(dbs[0], function(err, result) {
            expect(result.length, 'length of job queue').
              to.equal(0);
            done();
          });
        }
      });

      // Run the test
      jobs.process(jobIterator);
    });

    // Just binds test and prep together.
    describe('with a delayed job', function() {
      beforeEach(function(done) {
        // Set up some jobs.
        jobModel.setJobs(dbs[0], [{
          data: {
            retriesRemaining: 1,
            wee: 'wah'
          },
          process_at: moment().add('milliseconds', 1)
        }, {
          data: {
            retriesRemaining: 5,
            boo: 'hoo'
          },
          process_at: moment().add('milliseconds', 40000)
        }], done);
      });

      it('provides service only when correct number of ms have elapsed.',
          function(done) {
        // Set up our condition.
        jobs.eventEmitter.on('maybeServiceJob', function() {
          // The condition below should hold by 10 attempts to process jobs...
          if (maybeServiceJobCount == 10) {
            // Only the first job should have got service, and only twice as it
            // only had one retry remaining.
            expect(jobUpdatedCount, 'number of times we serviced a job').
              to.equal(2);

            done();
          }
        });

        // Run the test.
        jobs.process(jobIterator);
      });
    });

    // Just binds test and setup together.
    describe('with a locked job', function() {
      beforeEach(function(done) {
        jobModel.setJobs(dbs[0], [{
          job_id: 1,
          data: {
            retriesRemaining: 1
          },
          process_at: moment().add('milliseconds', 0)
        }, {
          data: {
            retriesRemaining: 5
          },
          process_at: moment().add('milliseconds', 0)
        }, {
          data: {
            retriesRemaining: 5
          },
          process_at: moment().add('milliseconds', 10000)
        }], lockFirstJob);

        function lockFirstJob() {
          lockJob(dbs[1], 1, done);
        }
      });

      it('will not service it.',
          function(done) {

        // Set up our condition.
        jobs.eventEmitter.on('maybeServiceJob', function() {
          // The condition below should hold by 10 attempts to process jobs...
          if (maybeServiceJobCount == 10) {
            // Only the second job should have got service, six times.
            // This test also shows starvation does not occur, as the first
            // job should be considered for service first (but is locked).
            // Correct behaviour is to move on to the second.
            expect(jobUpdatedCount, 'number of times we serviced a job').
              to.equal(6);
            done();
          }
        });

        // Run the test.
        jobs.process(jobIterator);
      });
    });

    //bind setup and test together
    describe('when called on a job', function() {
      beforeEach(function(done) {
        jobModel.setJobs(dbs[0], [{
          data: [],
          process_at: moment()
        }], done);
      });

      it('saves the new job data given to the db, in a non-destructive way',
          function(done) {
        var iterator = function(id, job, cb) {
          return cb(null, {
            state: 'complete',
            name: "tim"
          }, null);
        };

        jobs.eventEmitter.on('processCommitted', function() {
          jobs.stopProcessing();
          jobModel.getJobs(dbs[1], function(err, result) {
            if (err) return done(err);
            expect(result).to.have.length(2);
            done();
          });
        });

        jobs.process(iterator);
      });
    });
  });
  describe('#processNow', function() {
    describe('when called on a not locked job', function() {
      beforeEach(function(done) {
        // Set up some jobs.
        jobModel.setJobs(dbs[1], [{
          job_id: 1,
          data: {
            retriesRemaining: 1
          },
          process_at: moment().add('milliseconds', 10000).toDate()
        }, {
          job_id: 2,
          data: {
            retriesRemaining: 5
          },
          process_at: moment().add('milliseconds', 40000).toDate()
        }], done);
      });

      it('immediately runs the callback on the requested job, updating it',
          function(done) {
        var iterator = function(err, job, cb) {
          return cb(null, job, 200);
        };

        // Set up condition
        var checkConditions =  function() {
          console.log('checkConditions');
          jobModel.getJobs(dbs[1], function(err, result) {
            if (err) return done(err);
            expect(result.length).to.equal(3);
            expect(result[2].data).to.have.property('retriesRemaining');
            done();
          });
        };

        // Run the test.
        jobs.processNow(1, iterator, checkConditions);
      });
    });

    describe('when called on a locked job', function() {
      beforeEach(function(done) {
        jobModel.setJobs(dbs[0], [{
          job_id: 1,
          data: {
            retriesRemaining: 1
          },
          process_at: moment().add('milliseconds', 10000).toDate()
        }], lockFirstJob);

        function lockFirstJob(err) {
          if (err) return done(err);
          console.log('lockFirstJob');
          lockJob(dbs[1], 1, done);
        }
      });

      it('waits until the lock is ceeded',
          function(done) {
        // We first obtain a lock on the job. Then we run processNow().
        // It should be waiting.  We then release our lock.  We then see that
        // it ran.

        var iterator = function(err, job, cb) {
          jobModel.getJobs(dbs[0], function(err, result) {
            if (err) return done(err);
            return cb(null, job, 200);
          });
        };

        var wasWaiting = false;

        jobs.eventEmitter.on('lockSought', function() {
          console.log('lockSought');
          // Yes, this is hacky.  We assume that the obtaining of the lock
          // will always take < 100ms.  I could mock out the dbs[0], but this would
          // then be less 'realistic'.  Open to suggestions on how to do this
          // better!
          setTimeout(shouldBeWaiting, 100);
        });

        function shouldBeWaiting() {
          wasWaiting = true;
          dbs[1].query('commit');
        }

        jobs.eventEmitter.on('lockObtained', function(err) {
          if (err) return done(err);
          console.log('lockObtained');
          expect(wasWaiting).to.equal(true);
          done();
        });

        // Run the test.
        jobs.processNow(1, iterator, done);
      });
    });
  });

  describe.skip('#getHistory', function() {
    it('gets the requested job history', function(done) {
      // Set up some jobs.
      jobModel.setJobs([{
        id: 1,
        jobData: [{
          retriesRemaining: 1
        }],
        processNext: moment().add('milliseconds', 10000).toDate()
      }, {
        id: 2,
        jobData: [{
          retriesRemaining: 7
        },
        { retriesRemaining: 6
        }],
        processNext: moment().add('milliseconds', 40000).toDate()
      }]);

      function cb(err, jobHistory) {
        expect(jobHistory).to.eql([{
          retriesRemaining: 7
        },
        {
          retriesRemaining: 6
        }]);
        done();
      }
      jobs.getHistory(2, cb);
    });
  });
});

// vim: set et sw=2 ts=2 colorcolumn=80:
<|endoftext|>


<commit_before>'use strict';

var fs = require('fs');
var browserify = require('browserify');
var babelify = require('babelify');

if (!fs.existsSync('./es5')) {
  fs.mkdirSync('./es5');
}

browserify({'debug': true})
  .transform(babelify)
  .require('./index.js', {'entry': true})
  .bundle()
  .on('error', function (err) { console.log('Error : ' + err.message); })
  .pipe(fs.createWriteStream('es5/index.js'));
<commit_msg>Remove browserify script.<commit_after><|endoftext|>


<commit_before>import { configure, addDecorator, addParameters } from '@storybook/angular';
import { withA11y } from '@storybook/addon-a11y';
import sparkTheme from "../../storybook-spark-theme";

const storyWrapper = templateFn => storyFn => {
  const story = storyFn();
  return {
    ...story,
    template: templateFn(story.template)
  };
};

addDecorator(
  storyWrapper(storyContent => `<div class="sprk-o-Box">${ storyContent }<div>`)
);

addDecorator(withA11y);

// Option defaults.
addParameters({
  options: {
    theme: sparkTheme,
  },
});

configure(require.context('../../spark', true, /\/angular\/.*\.stories\.(js|ts|tsx|mdx)$/), module);
<commit_msg>update code style<commit_after>import { configure, addDecorator, addParameters } from '@storybook/angular';
import { withA11y } from '@storybook/addon-a11y';
import sparkTheme from "../../storybook-spark-theme";

const storyWrapper = templateFn => storyFn => {
  const story = storyFn();
  return {
    ...story,
    template: templateFn(story.template)
  };
};

addDecorator(
  storyWrapper(storyContent => (
    `<div class="sprk-o-Box">${ storyContent }<div>`)
  )
);

addDecorator(withA11y);

// Option defaults.
addParameters({
  options: {
    theme: sparkTheme,
  },
});

configure(require.context('../../spark', true, /\/angular\/.*\.stories\.(js|ts|tsx|mdx)$/), module);
<|endoftext|>


<commit_before>/*
 * Name space
 */
var CBMONITOR = CBMONITOR || {};

/*
 * Tabs with clusters/metrics/events
 */
CBMONITOR.configureAccordion = function() {
    "use strict";

    $("#accordion").accordion({
        heightStyle: "fill"
    });
};

/*
 * Panel with buttons related to cluster management
 */
CBMONITOR.configureCPanel = function() {
    "use strict";

    $("input:button")
        .button()
        .css({
            fontSize: "77%",
            width: "23%"
        })
        .click(function() {
            switch(this.value) {
                case "Add cluster":
                    $("#dialog_new_cluster").dialog("open");
                    break;
                case "Add server":
                    $("#dialog_new_server").dialog("open");
                    break;
                case "Add bucket":
                    $("#dialog_new_bucket").dialog("open");
                    break;
                case "Edit":
                    //var selected_id = jstree.jstree("get_selected").attr("id");
                    //jstree.jstree("rename", selected_id);
                    break;
                case "Delete":
                    $("#dialog_delete").dialog("open");
                    break;
                default:
                    break;
            }
        });

    $("input:text")
        .button()
        .css({
            fontSize: "77%",
            textAlign: "left",
            cursor : "text"
        });
};

/*
 * Cluster tree
 */
CBMONITOR.configureCTree = function() {
    "use strict";

    var jstree = $("#tree"),
        renc = $("#renc"),
        delc = $("#delc"),
        adds = $("#adds");

    // Disable buttons
    renc.addClass("ui-state-disabled");
    delc.addClass("ui-state-disabled");
    adds.addClass("ui-state-disabled");

    // Create tree
    jstree.jstree({
        "themes" : {
            "theme" : "default",
            "icons" : false
        },
        "crrm": {
            "move": {
                "check_move": function (m) {
                    var p = this._get_parent(m.o);
                    if (!p) {
                        return false;
                    }
                    p = p === -1 ? this.get_container() : p;
                    if (p === m.np) {
                        return true;
                    }
                    return p[0] && m.np[0] && p[0] === m.np[0];
                }
            }
        },
        "dnd": {
            "drop_target": false,
            "drag_target": false
        },
        "plugins": ["themes", "json_data", "dnd", "ui", "crrm"],
        "json_data": {
            "ajax" : {
                "url" : "/cbmonitor/get_tree_data/"
            }
        }
    });

    // Expand all nodes
    jstree.on("loaded.jstree", function() {
        jstree.jstree("open_all");
    });

    // Define binding
    jstree.bind("select_node.jstree", function (event, data) {
        var cls = data.rslt.obj.attr("class").split(" ")[0];
        switch(cls) {
            case "cluster":
                delc.removeClass("ui-state-disabled");
                adds.addClass("ui-state-disabled");
                break;
            case "servers":
                adds.removeClass("ui-state-disabled");
                adds.prop("value", "Add server");
                break;
            case "server":
                delc.removeClass("ui-state-disabled");
                adds.addClass("ui-state-disabled");
                break;
            case "buckets":
                adds.removeClass("ui-state-disabled");
                adds.prop("value", "Add bucket");
                break;
            case "bucket":
                delc.removeClass("ui-state-disabled");
                adds.addClass("ui-state-disabled");
                break;
            default:
                break;
        }
    });
};

/*
 * Panel with radio buttons related to chart views
 */
CBMONITOR.configureChartPanel = function() {
    "use strict";

    $("#vpanel").buttonset();
    $(".vradio").click(function() {
        var views = $("#views");
        views.empty();
        switch(this.id) {
            case "view1":
                $("<div/>", {
                    "id": "first_view",
                    "class": "chart_view_single"
                }).appendTo(views);
                break;
            case "view2":
                $("<div/>", {
                    "id": "first_view",
                    "class": "chart_view_double"
                }).appendTo(views);
                $("<div/>", {
                    "id": "second_view_double",
                    "class": "chart_view_double"
                }).appendTo(views);
                break;
            case "view4":
                $("<div/>", {
                    "id": "first_view",
                    "class": "chart_view_quadruple"
                }).appendTo(views);
                $("<div/>", {
                    "id": "second_view",
                    "class": "chart_view_quadruple"
                }).appendTo(views);
                $("<div/>", {
                    "id": "third_view",
                    "class": "chart_view_quadruple"
                }).appendTo(views);
                $("<div/>", {
                    "id": "fourth_view",
                    "class": "chart_view_quadruple"
                }).appendTo(views);
                break;
            default:
                break;
        }
    });
    $("#rpanel").buttonset();
};

CBMONITOR.getMetricsAndEvents = function(type) {
    "use strict";

    var prefix = (type === "metric")? "met" : "evnt";
    $.ajax({
        url: "/cbmonitor/get_metrics_and_events/", dataType: "json",
        data: {
            "cluster": $("#" + prefix + "_cluster option:selected").val(),
            "server": $("#" + prefix + "_server option:selected").val(),
            "bucket": $("#" + prefix + "_bucket option:selected").val(),
            "type": type
        },
        success: function(metrics) {
            var ul = (type === "metric") ? $("#metrics_ul") : $("#events_ul");
            metrics.forEach(function(metric) {
                ul.empty();
                ul.append(
                    $("<li>").addClass("ui-state-default ui-corner-all").append(
                        metric
                    )
                );
            });
        }
    });
};

CBMONITOR.configureMEPanel = function() {
    "use strict";

    CBMONITOR.configureClusters("metric");
    CBMONITOR.configureClusters("event");
};

CBMONITOR.configureClusters = function(type) {
    "use strict";

    $.ajax({url: "/cbmonitor/get_clusters/", dataType: "json",
        success: function(clusters){
            var sel = (type === "metric") ? $("#met_cluster") : $("#evnt_cluster");
            sel.empty();
            clusters.forEach(function(cluster) {
                var o = new Option(cluster, cluster);
                sel.append(o);
            });
            sel.selectmenu({
                select: function(event, option) {
                    CBMONITOR.configureMEItems(option.value, type, "server");
                    CBMONITOR.configureMEItems(option.value, type, "bucket");
                }
            });
            CBMONITOR.configureMEItems(clusters[0], type, "server");
            CBMONITOR.configureMEItems(clusters[0], type, "bucket");
        }
    });
};

CBMONITOR.configureMEItems = function(cluster, type, item) {
    "use strict";

    $.ajax({url: "/cbmonitor/get_" + item + "s/", dataType: "json",
        data: {"cluster": cluster},
        success: function(items) {
            var sel = (type === "metric") ? $("#met_" + item) : $("#evnt_" + item);
            sel.empty();
            var o = new Option("None", "");
            sel.append(o);
            items.forEach(function(item) {
                var o = new Option(item, item);
                sel.append(o);
            });
            sel.selectmenu({
                select: function() {
                    CBMONITOR.getMetricsAndEvents(type);
                }
            });
            CBMONITOR.getMetricsAndEvents(type);
        }
    });
};

$(document).ready(function(){
    "use strict";

    CBMONITOR.configureMEPanel();
    CBMONITOR.configureAccordion();
    CBMONITOR.configureCPanel();
    CBMONITOR.configureCTree();
    CBMONITOR.addNewCluster();
    CBMONITOR.addNewServer();
    CBMONITOR.addNewBucket();
    CBMONITOR.deleteItem();
    CBMONITOR.configureChartPanel();
});<commit_msg>drag and drop metrics & events to chart views<commit_after>/*
 * Name space
 */
var CBMONITOR = CBMONITOR || {};

/*
 * Tabs with clusters/metrics/events
 */
CBMONITOR.configureAccordion = function() {
    "use strict";

    $("#accordion").accordion({
        heightStyle: "fill"
    });
};

/*
 * Panel with buttons related to cluster management
 */
CBMONITOR.configureCPanel = function() {
    "use strict";

    $("input:button")
        .button()
        .css({
            fontSize: "77%",
            width: "23%"
        })
        .click(function() {
            switch(this.value) {
                case "Add cluster":
                    $("#dialog_new_cluster").dialog("open");
                    break;
                case "Add server":
                    $("#dialog_new_server").dialog("open");
                    break;
                case "Add bucket":
                    $("#dialog_new_bucket").dialog("open");
                    break;
                case "Edit":
                    //var selected_id = jstree.jstree("get_selected").attr("id");
                    //jstree.jstree("rename", selected_id);
                    break;
                case "Delete":
                    $("#dialog_delete").dialog("open");
                    break;
                default:
                    break;
            }
        });

    $("input:text")
        .button()
        .css({
            fontSize: "77%",
            textAlign: "left",
            cursor : "text"
        });
};

/*
 * Cluster tree
 */
CBMONITOR.configureCTree = function() {
    "use strict";

    var jstree = $("#tree"),
        renc = $("#renc"),
        delc = $("#delc"),
        adds = $("#adds");

    // Disable buttons
    renc.addClass("ui-state-disabled");
    delc.addClass("ui-state-disabled");
    adds.addClass("ui-state-disabled");

    // Create tree
    jstree.jstree({
        "themes" : {
            "theme" : "default",
            "icons" : false
        },
        "crrm": {
            "move": {
                "check_move": function (m) {
                    var p = this._get_parent(m.o);
                    if (!p) {
                        return false;
                    }
                    p = p === -1 ? this.get_container() : p;
                    if (p === m.np) {
                        return true;
                    }
                    return p[0] && m.np[0] && p[0] === m.np[0];
                }
            }
        },
        "dnd": {
            "drop_target": false,
            "drag_target": false
        },
        "plugins": ["themes", "json_data", "dnd", "ui", "crrm"],
        "json_data": {
            "ajax" : {
                "url" : "/cbmonitor/get_tree_data/"
            }
        }
    });

    // Expand all nodes
    jstree.on("loaded.jstree", function() {
        jstree.jstree("open_all");
    });

    // Define binding
    jstree.bind("select_node.jstree", function (event, data) {
        var cls = data.rslt.obj.attr("class").split(" ")[0];
        switch(cls) {
            case "cluster":
                delc.removeClass("ui-state-disabled");
                adds.addClass("ui-state-disabled");
                break;
            case "servers":
                adds.removeClass("ui-state-disabled");
                adds.prop("value", "Add server");
                break;
            case "server":
                delc.removeClass("ui-state-disabled");
                adds.addClass("ui-state-disabled");
                break;
            case "buckets":
                adds.removeClass("ui-state-disabled");
                adds.prop("value", "Add bucket");
                break;
            case "bucket":
                delc.removeClass("ui-state-disabled");
                adds.addClass("ui-state-disabled");
                break;
            default:
                break;
        }
    });
};

/*
 * Panel with radio buttons related to chart views
 */
CBMONITOR.configureChartPanel = function() {
    "use strict";

    $("#vpanel").buttonset();
    $(".vradio").click(function() {
        var views = $("#views");
        views.empty();
        switch(this.id) {
            case "view1":
                $("<div/>", {
                    "id": "first_view",
                    "class": "chart_view_single"
                }).appendTo(views);
                break;
            case "view2":
                $("<div/>", {
                    "id": "first_view",
                    "class": "chart_view_double"
                }).appendTo(views);
                $("<div/>", {
                    "id": "second_view_double",
                    "class": "chart_view_double"
                }).appendTo(views);
                break;
            case "view4":
                $("<div/>", {
                    "id": "first_view",
                    "class": "chart_view_quadruple"
                }).appendTo(views);
                $("<div/>", {
                    "id": "second_view",
                    "class": "chart_view_quadruple"
                }).appendTo(views);
                $("<div/>", {
                    "id": "third_view",
                    "class": "chart_view_quadruple"
                }).appendTo(views);
                $("<div/>", {
                    "id": "fourth_view",
                    "class": "chart_view_quadruple"
                }).appendTo(views);
                break;
            default:
                break;
        }
        CBMONITOR.enableDroppable();
    });
    $("#rpanel").buttonset();
};

CBMONITOR.getMetricsAndEvents = function(type) {
    "use strict";

    var prefix = (type === "metric")? "met" : "evnt";
    $.ajax({
        url: "/cbmonitor/get_metrics_and_events/", dataType: "json",
        data: {
            "cluster": $("#" + prefix + "_cluster option:selected").val(),
            "server": $("#" + prefix + "_server option:selected").val(),
            "bucket": $("#" + prefix + "_bucket option:selected").val(),
            "type": type
        },
        success: function(metrics) {
            var ul = (type === "metric") ? "#metrics_ul" : "#events_ul";
            metrics.forEach(function(metric) {
                $(ul).empty();
                $(ul).append(
                    $("<li>").addClass("ui-state-default ui-corner-all").append(
                        metric
                    )
                );
            });
            $(ul + " li").draggable({
                "revert": "invalid",
                "appendTo": "#views",
                "helper": "clone"
            });
        }
    });
};

CBMONITOR.enableDroppable = function() {
    "use strict";

    $("#views div").droppable({
        activeClass: "ui-state-default",
        hoverClass: "ui-state-hover",
        drop: function(event, ui) {
            //$(this).attr("id") ui.draggable.text();
        }
    });
};

CBMONITOR.configureMEPanel = function() {
    "use strict";

    CBMONITOR.configureClusters("metric");
    CBMONITOR.configureClusters("event");
};

CBMONITOR.configureClusters = function(type) {
    "use strict";

    $.ajax({url: "/cbmonitor/get_clusters/", dataType: "json",
        success: function(clusters){
            var sel = (type === "metric") ? $("#met_cluster") : $("#evnt_cluster");
            sel.empty();
            clusters.forEach(function(cluster) {
                var o = new Option(cluster, cluster);
                sel.append(o);
            });
            sel.selectmenu({
                select: function(event, option) {
                    CBMONITOR.configureMEItems(option.value, type, "server");
                    CBMONITOR.configureMEItems(option.value, type, "bucket");
                }
            });
            CBMONITOR.configureMEItems(clusters[0], type, "server");
            CBMONITOR.configureMEItems(clusters[0], type, "bucket");
        }
    });
};

CBMONITOR.configureMEItems = function(cluster, type, item) {
    "use strict";

    $.ajax({url: "/cbmonitor/get_" + item + "s/", dataType: "json",
        data: {"cluster": cluster},
        success: function(items) {
            var sel = (type === "metric") ? $("#met_" + item) : $("#evnt_" + item);
            sel.empty();
            var o = new Option("None", "");
            sel.append(o);
            items.forEach(function(item) {
                var o = new Option(item, item);
                sel.append(o);
            });
            sel.selectmenu({
                select: function() {
                    CBMONITOR.getMetricsAndEvents(type);
                }
            });
            CBMONITOR.getMetricsAndEvents(type);
        }
    });
};

$(document).ready(function(){
    "use strict";

    CBMONITOR.configureMEPanel();
    CBMONITOR.configureAccordion();
    CBMONITOR.configureCPanel();
    CBMONITOR.configureCTree();
    CBMONITOR.addNewCluster();
    CBMONITOR.addNewServer();
    CBMONITOR.addNewBucket();
    CBMONITOR.deleteItem();
    CBMONITOR.configureChartPanel();
    CBMONITOR.enableDroppable();
});<|endoftext|>


<commit_before>/**
 * WP Dashboard Widgets Component Stories.
 *
 * Site Kit by Google, Copyright 2022 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * Internal dependencies
 */
import WPDashboardWidgets from './WPDashboardWidgets';
import WithRegistrySetup from '../../../../tests/js/WithRegistrySetup';
import {
	provideModules,
	provideSiteInfo,
	provideModuleRegistrations,
} from '../../../../tests/js/utils';
import { CORE_USER } from '../../googlesitekit/datastore/user/constants';
import { provideSearchConsoleMockReport } from '../../modules/search-console/util/data-mock';
import { provideAnalyticsMockReport } from '../../modules/analytics/util/data-mock';

const searchConsoleArgs = {
	startDate: '2021-08-18',
	endDate: '2021-10-12',
	dimensions: 'date',
};

const analyticsArgs = [
	{
		startDate: '2021-09-15',
		endDate: '2021-10-12',
		compareStartDate: '2021-08-18',
		compareEndDate: '2021-09-14',
		metrics: [
			{
				expression: 'ga:goalCompletionsAll',
				alias: 'Goal Completions',
			},
			'ga:bounceRate',
		],
	},
	{
		startDate: '2021-09-15',
		endDate: '2021-10-12',
		compareStartDate: '2021-08-18',
		compareEndDate: '2021-09-14',
		dimensions: 'ga:date',
		metrics: [
			{
				expression: 'ga:goalCompletionsAll',
				alias: 'Goal Completions',
			},
			'ga:bounceRate',
		],
	},
	{
		startDate: '2021-09-15',
		endDate: '2021-10-12',
		compareStartDate: '2021-08-18',
		compareEndDate: '2021-09-14',
		metrics: [
			{
				expression: 'ga:users',
				alias: 'Total Users',
			},
		],
		dimensions: [ 'ga:channelGrouping' ],
		dimensionFilters: { 'ga:channelGrouping': 'Organic Search' },
	},
	{
		startDate: '2021-09-15',
		endDate: '2021-10-12',
		compareStartDate: '2021-08-18',
		compareEndDate: '2021-09-14',
		metrics: [
			{
				expression: 'ga:users',
				alias: 'Total Users',
			},
		],
		dimensions: [ 'ga:date' ],
		dimensionFilters: { 'ga:channelGrouping': 'Organic Search' },
	},
	{
		dimensions: [ 'ga:date' ],
		metrics: [
			{
				expression: 'ga:users',
			},
		],
		startDate: '2021-09-15',
		endDate: '2021-10-12',
	},
];

const Template = ( { setupRegistry } ) => (
	<WithRegistrySetup func={ setupRegistry }>

					<WPDashboardWidgets />

	</WithRegistrySetup>
);

export const Ready = Template.bind( {} );
Ready.storyName = 'Ready';
Ready.args = {
	setupRegistry: ( registry ) => {
		for ( const options of analyticsArgs ) {
			provideAnalyticsMockReport( registry, options );
		}

		provideSearchConsoleMockReport( registry, searchConsoleArgs );
	},
};

export const ReadyWithActivateModuleCTA = Template.bind( {} );
ReadyWithActivateModuleCTA.storyName = 'Ready with Activate Module CTA';
ReadyWithActivateModuleCTA.args = {
	setupRegistry: ( registry ) => {
		provideModules( registry, [
			{
				active: false,
				connected: false,
				slug: 'analytics',
			},
		] );

		provideSearchConsoleMockReport( registry, searchConsoleArgs );
	},
};

export const ReadyWithActivateAnalyticsCTA = Template.bind( {} );
ReadyWithActivateAnalyticsCTA.storyName = 'Ready with Activate Analytics CTA';
ReadyWithActivateAnalyticsCTA.args = {
	setupRegistry: ( registry ) => {
		provideModules( registry, [
			{
				active: false,
				connected: false,
				slug: 'analytics',
			},
		] );

		provideSearchConsoleMockReport( registry, searchConsoleArgs );
	},
};
ReadyWithActivateAnalyticsCTA.parameters = {
	features: [ 'zeroDataStates' ],
};
ReadyWithActivateAnalyticsCTA.scenario = {
	label:
		'Views/WPDashboardApp/WPDashboardWidgets/ReadyWithActivateAnalyticsCTA',
	delay: 3000,
};

export const ReadyWithCompleteAnalyticsActivationCTA = Template.bind( {} );
ReadyWithCompleteAnalyticsActivationCTA.storyName =
	'Ready with Complete Analytics Activation CTA';
ReadyWithCompleteAnalyticsActivationCTA.args = {
	setupRegistry: ( registry ) => {
		provideModules( registry, [
			{
				active: true,
				connected: false,
				slug: 'analytics',
			},
		] );
		provideModuleRegistrations( registry );
		provideSearchConsoleMockReport( registry, searchConsoleArgs );
	},
};
ReadyWithCompleteAnalyticsActivationCTA.parameters = {
	features: [ 'zeroDataStates' ],
};

export default {
	title: 'Views/WPDashboardApp/WPDashboardWidgets',
	decorators: [
		( Story, { args } ) => {
			const setupRegistry = ( registry ) => {
				provideSiteInfo( registry );
				registry.dispatch( CORE_USER ).setReferenceDate( '2021-10-13' );
				registry.dispatch( CORE_USER ).receiveGetAuthentication( {
					needsReauthentication: false,
				} );

				// Call story-specific setup.
				args.setupRegistry( registry );
			};

			return (
				<WithRegistrySetup func={ setupRegistry }>
					<Story />
				</WithRegistrySetup>
			);
		},
	],
};
<commit_msg>Refactor and add ZDS stories for WPDashboard.<commit_after>/**
 * WP Dashboard Widgets Component Stories.
 *
 * Site Kit by Google, Copyright 2022 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * Internal dependencies
 */
import WPDashboardWidgets from './WPDashboardWidgets';
import WithRegistrySetup from '../../../../tests/js/WithRegistrySetup';
import {
	provideModules,
	provideSiteInfo,
	provideModuleRegistrations,
} from '../../../../tests/js/utils';
import { CORE_USER } from '../../googlesitekit/datastore/user/constants';
import {
	setupSearchConsoleAnalyticsMockReports,
	setupSearchConsoleMockReports,
	setupSearchConsoleAnalyticsZeroData,
	setupSearchConsoleGatheringData,
	setupAnalyticsGatheringData,
} from './common.stories';

const Template = ( { setupRegistry } ) => (
	<WithRegistrySetup func={ setupRegistry }>

					<WPDashboardWidgets />

	</WithRegistrySetup>
);

export const Ready = Template.bind( {} );
Ready.storyName = 'Ready';
Ready.args = {
	setupRegistry: setupSearchConsoleAnalyticsMockReports,
};
Ready.decorators = [
	( Story ) => {
		const setupRegistry = ( registry ) => {
			// Set up the search console and analytics modules stores but provide no data.
			provideModules( registry, [
				{
					slug: 'search-console',
					active: true,
					connected: true,
				},
				{
					slug: 'analytics',
					active: true,
					connected: true,
				},
			] );
		};

		return (
			<WithRegistrySetup func={ setupRegistry }>
				<Story />
			</WithRegistrySetup>
		);
	},
];

export const ReadyWithActivateModuleCTA = Template.bind( {} );
ReadyWithActivateModuleCTA.storyName = 'Ready with Activate Module CTA';
ReadyWithActivateModuleCTA.args = {
	setupRegistry: ( registry ) => {
		provideModules( registry, [
			{
				active: false,
				connected: false,
				slug: 'analytics',
			},
		] );

		setupSearchConsoleMockReports( registry );
	},
};

export const ReadyWithActivateAnalyticsCTA = Template.bind( {} );
ReadyWithActivateAnalyticsCTA.storyName = 'Ready with Activate Analytics CTA';
ReadyWithActivateAnalyticsCTA.args = {
	setupRegistry: ( registry ) => {
		provideModules( registry, [
			{
				active: false,
				connected: false,
				slug: 'analytics',
			},
		] );

		setupSearchConsoleMockReports( registry );
	},
};
ReadyWithActivateAnalyticsCTA.parameters = {
	features: [ 'zeroDataStates' ],
};
ReadyWithActivateAnalyticsCTA.scenario = {
	label:
		'Views/WPDashboardApp/WPDashboardWidgets/ReadyWithActivateAnalyticsCTA',
	delay: 3000,
};

export const ReadyWithCompleteAnalyticsActivationCTA = Template.bind( {} );
ReadyWithCompleteAnalyticsActivationCTA.storyName =
	'Ready with Complete Analytics Activation CTA';
ReadyWithCompleteAnalyticsActivationCTA.args = {
	setupRegistry: ( registry ) => {
		provideModules( registry, [
			{
				active: true,
				connected: false,
				slug: 'analytics',
			},
		] );
		provideModuleRegistrations( registry );
		setupSearchConsoleMockReports( registry );
	},
};
ReadyWithCompleteAnalyticsActivationCTA.parameters = {
	features: [ 'zeroDataStates' ],
};

export const GatheringData = Template.bind( {} );
GatheringData.storyName = 'Gathering Data';
GatheringData.args = {
	setupRegistry: ( registry ) => {
		provideModules( registry, [
			{
				slug: 'search-console',
				active: true,
				connected: true,
			},
			{
				slug: 'analytics',
				active: true,
				connected: true,
			},
		] );
		setupSearchConsoleGatheringData( registry );
		setupAnalyticsGatheringData( registry );
	},
};
GatheringData.parameters = {
	features: [ 'zeroDataStates' ],
};

export const ZeroData = Template.bind( {} );
ZeroData.storyName = 'Zero Data';
ZeroData.args = {
	setupRegistry: ( registry ) => {
		provideModules( registry, [
			{
				slug: 'search-console',
				active: true,
				connected: true,
			},
			{
				slug: 'analytics',
				active: true,
				connected: true,
			},
		] );
		setupSearchConsoleAnalyticsZeroData( registry );
	},
};
ZeroData.parameters = {
	features: [ 'zeroDataStates' ],
};

export default {
	title: 'Views/WPDashboardApp/WPDashboardWidgets',
	// Do not use common decorator so as to activate/connect analytics in only certain scenarios.
	decorators: [
		( Story, { args } ) => {
			const setupRegistry = ( registry ) => {
				provideSiteInfo( registry );
				registry.dispatch( CORE_USER ).receiveGetAuthentication( {
					needsReauthentication: false,
				} );

				// Call story-specific setup.
				if ( typeof args?.setupRegistry === 'function' ) {
					args.setupRegistry( registry );
				}
			};

			return (
				<WithRegistrySetup func={ setupRegistry }>
					<Story />
				</WithRegistrySetup>
			);
		},
	],
};
<|endoftext|>