<commit_before>/**
 * Copyright (c) 2015-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule NativeModules
 * @flow
 */
'use strict';

const BatchedBridge = require('BatchedBridge');

const defineLazyObjectProperty = require('defineLazyObjectProperty');
const invariant = require('fbjs/lib/invariant');

type ModuleConfig = [
  string, /* name */
  ?Object, /* constants */
  Array<string>, /* functions */
  Array<number>, /* promise method IDs */
  Array<number>, /* sync method IDs */
];

export type MethodType = 'async' | 'promise' | 'sync';

function genModule(config: ?ModuleConfig, moduleID: number): ?{name: string, module?: Object} {
  if (!config) {
    return null;
  }

  const [moduleName, constants, methods, promiseMethods, syncMethods] = config;
  invariant(!moduleName.startsWith('RCT') && !moduleName.startsWith('RK'),
    'Module name prefixes should\'ve been stripped by the native side ' +
    'but wasn\'t for ' + moduleName);

  if (!constants && !methods) {
    // Module contents will be filled in lazily later
    return { name: moduleName };
  }

  const module = {};
  methods && methods.forEach((methodName, methodID) => {
    const isPromise = promiseMethods && arrayContains(promiseMethods, methodID);
    const isSync = syncMethods && arrayContains(syncMethods, methodID);
    invariant(!isPromise || !isSync, 'Cannot have a method that is both async and a sync hook');
    const methodType = isPromise ? 'promise' : isSync ? 'sync' : 'async';
    module[methodName] = genMethod(moduleID, methodID, methodType);
  });
  Object.assign(module, constants);

  if (__DEV__) {
    BatchedBridge.createDebugLookup(moduleID, moduleName, methods);
  }

  return { name: moduleName, module };
}

// export this method as a global so we can call it from native
global.__fbGenNativeModule = genModule;

function loadModule(name: string, moduleID: number): ?Object {
  invariant(global.nativeRequireModuleConfig,
    'Can\'t lazily create module without nativeRequireModuleConfig');
  const config = global.nativeRequireModuleConfig(name);
  const info = genModule(config, moduleID);
  return info && info.module;
}

function genMethod(moduleID: number, methodID: number, type: MethodType) {
  let fn = null;
  if (type === 'promise') {
    fn = function(...args: Array<any>) {
      return new Promise((resolve, reject) => {
        BatchedBridge.enqueueNativeCall(moduleID, methodID, args,
          (data) => resolve(data),
          (errorData) => reject(createErrorFromErrorData(errorData)));
      });
    };
  } else if (type === 'sync') {
    fn = function(...args: Array<any>) {
      return global.nativeCallSyncHook(moduleID, methodID, args);
    };
  } else {
    fn = function(...args: Array<any>) {
      const lastArg = args.length > 0 ? args[args.length - 1] : null;
      const secondLastArg = args.length > 1 ? args[args.length - 2] : null;
      const hasSuccessCallback = typeof lastArg === 'function';
      const hasErrorCallback = typeof secondLastArg === 'function';
      hasErrorCallback && invariant(
        hasSuccessCallback,
        'Cannot have a non-function arg after a function arg.'
      );
      const onSuccess = hasSuccessCallback ? lastArg : null;
      const onFail = hasErrorCallback ? secondLastArg : null;
      const callbackCount = hasSuccessCallback + hasErrorCallback;
      args = args.slice(0, args.length - callbackCount);
      BatchedBridge.enqueueNativeCall(moduleID, methodID, args, onFail, onSuccess);
    };
  }
  fn.type = type;
  return fn;
}

function arrayContains<T>(array: Array<T>, value: T): boolean {
  return array.indexOf(value) !== -1;
}

function createErrorFromErrorData(errorData: {message: string}): Error {
  const {
    message,
    ...extraErrorInfo
  } = errorData;
  const error = new Error(message);
  (error:any).framesToPop = 1;
  return Object.assign(error, extraErrorInfo);
}

let NativeModules : {[moduleName: string]: Object} = {};
if (global.nativeModuleProxy) {
  NativeModules = global.nativeModuleProxy;
} else {
  const bridgeConfig = global.__fbBatchedBridgeConfig;
  invariant(bridgeConfig, '__fbBatchedBridgeConfig is not set, cannot invoke native modules');

  (bridgeConfig.remoteModuleConfig || []).forEach((config: ModuleConfig, moduleID: number) => {
    // Initially this config will only contain the module name when running in JSC. The actual
    // configuration of the module will be lazily loaded.
    const info = genModule(config, moduleID);
    if (!info) {
      return;
    }

    if (info.module) {
      NativeModules[info.name] = info.module;
    }
    // If there's no module config, define a lazy getter
    else {
      defineLazyObjectProperty(NativeModules, info.name, {
        get: () => loadModule(info.name, moduleID)
      });
    }
  });
}

module.exports = NativeModules;
<commit_msg>Fix crash when overriding native modules on RCTJSCExecutor<commit_after>/**
 * Copyright (c) 2015-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule NativeModules
 * @flow
 */
'use strict';

const BatchedBridge = require('BatchedBridge');

const invariant = require('fbjs/lib/invariant');

type ModuleConfig = [
  string, /* name */
  ?Object, /* constants */
  Array<string>, /* functions */
  Array<number>, /* promise method IDs */
  Array<number>, /* sync method IDs */
];

export type MethodType = 'async' | 'promise' | 'sync';

function genModule(config: ?ModuleConfig, moduleID: number): ?{name: string, module?: Object} {
  if (!config) {
    return null;
  }

  const [moduleName, constants, methods, promiseMethods, syncMethods] = config;
  invariant(!moduleName.startsWith('RCT') && !moduleName.startsWith('RK'),
    'Module name prefixes should\'ve been stripped by the native side ' +
    'but wasn\'t for ' + moduleName);

  if (!constants && !methods) {
    // Module contents will be filled in lazily later
    return { name: moduleName };
  }

  const module = {};
  methods && methods.forEach((methodName, methodID) => {
    const isPromise = promiseMethods && arrayContains(promiseMethods, methodID);
    const isSync = syncMethods && arrayContains(syncMethods, methodID);
    invariant(!isPromise || !isSync, 'Cannot have a method that is both async and a sync hook');
    const methodType = isPromise ? 'promise' : isSync ? 'sync' : 'async';
    module[methodName] = genMethod(moduleID, methodID, methodType);
  });
  Object.assign(module, constants);

  if (__DEV__) {
    BatchedBridge.createDebugLookup(moduleID, moduleName, methods);
  }

  return { name: moduleName, module };
}

// export this method as a global so we can call it from native
global.__fbGenNativeModule = genModule;

function loadModule(name: string, moduleID: number): ?Object {
  invariant(global.nativeRequireModuleConfig,
    'Can\'t lazily create module without nativeRequireModuleConfig');
  const config = global.nativeRequireModuleConfig(name);
  const info = genModule(config, moduleID);
  return info && info.module;
}

function genMethod(moduleID: number, methodID: number, type: MethodType) {
  let fn = null;
  if (type === 'promise') {
    fn = function(...args: Array<any>) {
      return new Promise((resolve, reject) => {
        BatchedBridge.enqueueNativeCall(moduleID, methodID, args,
          (data) => resolve(data),
          (errorData) => reject(createErrorFromErrorData(errorData)));
      });
    };
  } else if (type === 'sync') {
    fn = function(...args: Array<any>) {
      return global.nativeCallSyncHook(moduleID, methodID, args);
    };
  } else {
    fn = function(...args: Array<any>) {
      const lastArg = args.length > 0 ? args[args.length - 1] : null;
      const secondLastArg = args.length > 1 ? args[args.length - 2] : null;
      const hasSuccessCallback = typeof lastArg === 'function';
      const hasErrorCallback = typeof secondLastArg === 'function';
      hasErrorCallback && invariant(
        hasSuccessCallback,
        'Cannot have a non-function arg after a function arg.'
      );
      const onSuccess = hasSuccessCallback ? lastArg : null;
      const onFail = hasErrorCallback ? secondLastArg : null;
      const callbackCount = hasSuccessCallback + hasErrorCallback;
      args = args.slice(0, args.length - callbackCount);
      BatchedBridge.enqueueNativeCall(moduleID, methodID, args, onFail, onSuccess);
    };
  }
  fn.type = type;
  return fn;
}

function arrayContains<T>(array: Array<T>, value: T): boolean {
  return array.indexOf(value) !== -1;
}

function createErrorFromErrorData(errorData: {message: string}): Error {
  const {
    message,
    ...extraErrorInfo
  } = errorData;
  const error = new Error(message);
  (error:any).framesToPop = 1;
  return Object.assign(error, extraErrorInfo);
}

let NativeModules : {[moduleName: string]: Object} = {};
if (global.nativeModuleProxy) {
  NativeModules = global.nativeModuleProxy;
} else {
  const bridgeConfig = global.__fbBatchedBridgeConfig;
  invariant(bridgeConfig, '__fbBatchedBridgeConfig is not set, cannot invoke native modules');

  const defineLazyObjectProperty = require('defineLazyObjectProperty');
  (bridgeConfig.remoteModuleConfig || []).forEach((config: ModuleConfig, moduleID: number) => {
    // Initially this config will only contain the module name when running in JSC. The actual
    // configuration of the module will be lazily loaded.
    const info = genModule(config, moduleID);
    if (!info) {
      return;
    }

    if (info.module) {
      NativeModules[info.name] = info.module;
    }
    // If there's no module config, define a lazy getter
    else {
      defineLazyObjectProperty(NativeModules, info.name, {
        get: () => loadModule(info.name, moduleID)
      });
    }
  });
}

module.exports = NativeModules;
<|endoftext|>


<commit_before>// Copyright (c) 2015 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

'use strict';

/* HOWDO:
 *
 * Step 1: is there any failures to care about?
 *     $ node test/streaming_bisect.js
 *     ...
 *     # Isolated 4 failures
 *     # - head 31KiB + 965B body 64KiB
 *     # - head 431KiB + 1001B body 64KiB
 *     # - head 423KiB + 1023B body 128KiB
 *     # - head 437KiB + 17B body 512KiB
 *     ...
 *
 * Step 2: get detail on the first failure
 *     $ node test/streaming_bisect.js --trace --first
 *     ...
 *     # Failure #1: head 31KiB + 966B body 64KiB
 *     # Last good at: head 31KiB + 965B body 64KiB
 *     ... much detail ...
 *
 * Step 3: analyze the difference between good and bad
 *     $ NODE_DEBUG=tchannel,tchannel_dump node test/streaming_bisect.js \
 *         --repro --head '31KiB + 965B' --body '64KiB' --timeout 1000 2>&1 \
 *         | ./test/streaming_bisect_relabel.sh \
 *         >good
 *
 *     $ NODE_DEBUG=tchannel,tchannel_dump node test/streaming_bisect.js \
 *         --repro --head '31KiB + 966B' --body 64KiB --timeout 1000 2>&1 \
 *         | ./test/streaming_bisect_relabel.sh \
 *         >bad
 *
 *     $ diff -y good bad
 *     # or any other diff viewer
 */

var async = require('async');
var PassThrough = require('readable-stream').PassThrough;
var test = require('tape');
var util = require('util');
var allocCluster = require('./lib/alloc-cluster.js');
var EndpointHandler = require('../endpoint-handler');
var CountStream = require('./lib/count_stream');
var TestIsolateSearch = require('./lib/test_isolate_search');
var base2 = require('./lib/base2');
var extend = require('xtend');

var argv = {
    first: false,
    trace: false,
    instrument: 0
};

if (require.main === module) {
    argv = require('minimist')(process.argv.slice(2), {
        boolean: {
            first: true,
            trace: true,
        },
        default: argv
    });
}

if (argv.repro) {
    var hSize = base2.parse(argv.head);
    var bSize = base2.parse(argv.body);
    if (isNaN(hSize)) die('invalid hSize');
    if (isNaN(bSize)) die('invalid hSize');
    var state = {
        hSize: hSize,
        bSize: bSize,
        timeout: argv.timeout
    };
    test.only('repro ' + describe(state), function t(assert) {
        var search = TestStreamSearch();
        var spec = search.makeSpec(state);
        search.test(spec, assert);
    });
}

test('bisection test', function t(assert) {
    var sizeLimit = null;

    if (argv.sizeLimit) {
        sizeLimit = base2.parse(argv.sizeLimit);
        if (isNaN(sizeLimit)) die('invalid sizeLimit');
    }

    var search = TestStreamSearch({
        stopOnFirstFailure: argv.first,
        traceDetails: argv.trace,
        sizeLimit: sizeLimit || 128 * base2.Ki,
        timeout: argv.timeout
    }).instrument(argv.instrument);

    var firstStop = {};

    async.series([

        {
            withHeaderOnly: true,
            withBodyOnly: true,
            withBoth: true,
            basis: [0, 1],
            mul: []
        },

        {
            withHeaderOnly: true,
            withBodyOnly: true,
            withBoth: true,
            basis: [2]
        },

        {
            withHeaderOnly: true,
            withBodyOnly: true,
            withBoth: true,
            basis: [3]
        },

        {
            // TODO: basis length >= 2 && withBoth causes non-deterministic
            // timeout failures (even with setting maxTries > 1); however none
            // of these failures are ever reproducible...
            // basis: [2, 3, 5, 7, 11, 13],
            withHeaderOnly: true,
            withBodyOnly: true,
            withBoth: false,
            basis: [2, 3]
        }

    ].map(function eachOptions(options) {
        return function runThunk(next) {
            search.run(assert, options, function(err, run) {
                if (!err && argv.first && run.fail) {
                    next(firstStop);
                } else {
                    next(err);
                }
            });
        };
    }), function done(err) {
        if (err && err !== firstStop) assert.ifError(err, 'no final error');
        assert.end();
    });
});

function TestStreamSearch(options) {
    if (!(this instanceof TestStreamSearch)) {
        return new TestStreamSearch(options);
    }
    var self = this;
    TestIsolateSearch.call(self, options);
}
util.inherits(TestStreamSearch, TestIsolateSearch);

TestStreamSearch.prototype.willFailLike = function willFailLike(a, b) {
    if (like(a, b)) return true;
    for (var i = 0; i < b.trace.length; i++) {
        var res = b.trace[i];
        if (res.fail && like(a, res.state)) return true;
    }
    return false;
    function like(a, b) {
        if (a.test.hSize !== b.test.hSize) return false;
        if (a.test.bSize < b.test.bSize) return false;
        return true;
    }
};

TestStreamSearch.prototype.describeState = function describeState(state) {
    return describe(state.test);
};

TestStreamSearch.prototype.describeNoFailure = function describeNoFailure(assert) {
    var self = this;
    assert.pass('found no failure under ' + prettyBytes(self.options.sizeLimit));
};

TestStreamSearch.prototype.init = function init() {
    var self = this;
    self.expand(function(_emit) {
        var base = {hSize: 0, bSize: 0, timeout: self.options.timeout};
        self.options.basis.forEach(function each(n) {
            if (self.options.withHeaderOnly) emit({hSize: n});
            if (self.options.withBodyOnly) emit({bSize: n});
            if (self.options.withBoth) emit({hSize: n, bSize: n});
        });
        function emit(overlay) {
            _emit(self.makeSpec(extend(base, overlay)));
        }
    });
};

TestStreamSearch.prototype.test = function test(state, assert) {
    var options = state.test;
    var name = describe(options);
    var cluster = allocCluster({
        numPeers: 2
    });
    cluster.ready(function clusterReady() {
        for (var i = 0; i < cluster.hosts.length; i++) {
            assert.comment(util.format(
                'cluster host %s: %s',
                i + 1, cluster.hosts[i]));
        }

        var one = cluster.channels[0];
        var two = cluster.channels[1];
        one.handler = echoHandler();
        assert.timeoutAfter(options.timeout || 100);
        assert.once('end', cluster.destroy);
        streamingTest({
            name: name,
            channel: two,
            opts: {host: cluster.hosts[0]},
            op: 'foo',
            headStream: CountStream({limit: options.hSize}),
            bodyStream: CountStream({limit: options.bSize})
        }, assert, function streamingTestDone() {
            cluster.assertCleanState(assert, {
                channels: [{
                    peers: [{
                        connections: [
                            {direction: 'in', inReqs: 0, outReqs: 0}
                        ]
                    }]
                }, {
                    peers: [{
                        connections: [
                            {direction: 'out', inReqs: 0, outReqs: 0}
                        ]
                    }]
                }]
            });
            cluster.destroy(assert.end);
        });
    });
};

TestStreamSearch.prototype.explore = function explore(spec, _emit) {
    var self = this;
    var good = spec.good.test;
    (self.options.mul || self.options.basis).forEach(function each(n) {
        if (n < 2) return;
        var hSize = n * good.hSize;
        var bSize = n * good.bSize;
        if (hSize <= self.options.sizeLimit) emit({hSize: hSize});
        if (bSize <= self.options.sizeLimit) emit({bSize: bSize});
    });
    function emit(overlay) {
        _emit(spec.makeTest(extend(good, overlay)));
    }
};

TestStreamSearch.prototype.isolate = function isolate(spec, _emit) {
    var good = spec.good && spec.good.test || {hSize: 0, bSize: 0};
    var bad = spec.bad.test;
    if (bad.hSize - good.hSize > 1) emit({hSize: mid(good.hSize, bad.hSize)});
    if (good.bSize < bad.bSize) emit({bSize: mid(good.bSize, bad.bSize)});
    function emit(overlay) {
        _emit(spec.makeTest(extend(good, overlay)));
    }
    function mid(a, b) {
        return a + Math.floor(b / 2 - a / 2);
    }
};

function streamingTest(testCase, assert, callback) {
    if (!callback) callback = assert.end;

    var reqHeadStream;
    if (typeof testCase.headStream === 'function') {
        reqHeadStream = testCase.headStream();
    } else {
        reqHeadStream = testCase.headStream;
    }

    var reqBodyStream;
    if (typeof testCase.bodyStream === 'function') {
        reqBodyStream = testCase.bodyStream();
    } else {
        reqBodyStream = testCase.bodyStream;
    }

    var resHeadStream = PassThrough();
    var resBodyStream = PassThrough();

    var req = testCase.channel.request(extend({
        streamed: true
    }, testCase.opts));
    req.arg1.end(testCase.op);
    reqHeadStream.pipe(resHeadStream);
    reqHeadStream.pipe(req.arg2);
    req.arg2.once('finish', function onArg2Finished() {
        reqBodyStream.pipe(resBodyStream);
        reqBodyStream.pipe(req.arg3);
    });

    onResult.canStream = true;
    req.hookupCallback(onResult);

    function onResult(err, req, res) {
        assert.ifError(err, testCase.name + ': no result error');
        if (err) {
            callback();
            return;
        }
        if (res.streamed) {
            async.series([
                verifyStream('arg2', res.arg2, resHeadStream),
                verifyStream('arg3', res.arg3, resBodyStream),
            ], callback);
        } else {
            verifyStreamChunk('arg2', 0, res.arg2, resHeadStream);
            verifyDrained('arg2', resHeadStream);
            verifyStreamChunk('arg3', 0, res.arg3, resBodyStream);
            verifyDrained('arg3', resBodyStream);
            callback();
        }
    }

    function verifyStreamChunk(name, offset, gotChunk, expected) {
        var expectedChunk = expected.read(gotChunk.length) || Buffer(0);
        assert.deepEqual(gotChunk, expectedChunk, util.format(
            '%s: expected chunk %s bytes @%s',
            name,
            prettyBytes(gotChunk.length),
            '0x' + offset.toString(16))
        );
        return offset + gotChunk.length;
    }

    function verifyDrained(name, expected) {
        var remain = expected.read();
        assert.equal(remain, null, name + ': got all expected data (bytes)');
        assert.equal(remain && remain.length || 0, 0, name + ': got all expected data (length)');
    }

    function verifyStream(name, got, expected) {
        return function verifyStreamThunk(streamDone) {
            var offset = 0;
            got.on('data', onData);
            got.on('error', finish);
            got.on('end', finish);

            function onData(gotChunk) {
                offset = verifyStreamChunk(name, offset, gotChunk, expected);
            }

            function finish(err) {
                assert.ifError(err, name + ': no error');
                if (!err) verifyDrained(name, expected);
                streamDone();
            }
        };
    }
}

function describe(params) {
    return util.format('head %s body %s',
        prettyBytes(params.hSize),
        prettyBytes(params.bSize));
}

function echoHandler() {
    var handler = EndpointHandler();
    function foo(req, buildRes) {
        var res = buildRes({streamed: req.streamed});
        if (req.streamed) {
            res.setOk(true);
            req.arg2.on('data', function onArg2Data(chunk) {
                res.arg2.write(chunk);
            });
            req.arg2.on('end', function onArg2End() {
                res.arg2.end();
            });
            req.arg3.on('data', function onArg3Data(chunk) {
                res.arg3.write(chunk);
            });
            req.arg3.on('end', function onArg3End() {
                res.arg3.end();
            });
        } else {
            res.sendOk(req.arg2, req.arg3);
        }
    }
    foo.canStream = true;
    handler.register('foo', foo);
    return handler;
}

function die() {
    console.error.apply(console, arguments);
    process.exit(1);
}

function prettyBytes(n) {
    return base2.pretty(n, 'B');
}
<commit_msg>test/streaming_bisect: drop duplicate cluster destroy<commit_after>// Copyright (c) 2015 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

'use strict';

/* HOWDO:
 *
 * Step 1: is there any failures to care about?
 *     $ node test/streaming_bisect.js
 *     ...
 *     # Isolated 4 failures
 *     # - head 31KiB + 965B body 64KiB
 *     # - head 431KiB + 1001B body 64KiB
 *     # - head 423KiB + 1023B body 128KiB
 *     # - head 437KiB + 17B body 512KiB
 *     ...
 *
 * Step 2: get detail on the first failure
 *     $ node test/streaming_bisect.js --trace --first
 *     ...
 *     # Failure #1: head 31KiB + 966B body 64KiB
 *     # Last good at: head 31KiB + 965B body 64KiB
 *     ... much detail ...
 *
 * Step 3: analyze the difference between good and bad
 *     $ NODE_DEBUG=tchannel,tchannel_dump node test/streaming_bisect.js \
 *         --repro --head '31KiB + 965B' --body '64KiB' --timeout 1000 2>&1 \
 *         | ./test/streaming_bisect_relabel.sh \
 *         >good
 *
 *     $ NODE_DEBUG=tchannel,tchannel_dump node test/streaming_bisect.js \
 *         --repro --head '31KiB + 966B' --body 64KiB --timeout 1000 2>&1 \
 *         | ./test/streaming_bisect_relabel.sh \
 *         >bad
 *
 *     $ diff -y good bad
 *     # or any other diff viewer
 */

var async = require('async');
var PassThrough = require('readable-stream').PassThrough;
var test = require('tape');
var util = require('util');
var allocCluster = require('./lib/alloc-cluster.js');
var EndpointHandler = require('../endpoint-handler');
var CountStream = require('./lib/count_stream');
var TestIsolateSearch = require('./lib/test_isolate_search');
var base2 = require('./lib/base2');
var extend = require('xtend');

var argv = {
    first: false,
    trace: false,
    instrument: 0
};

if (require.main === module) {
    argv = require('minimist')(process.argv.slice(2), {
        boolean: {
            first: true,
            trace: true,
        },
        default: argv
    });
}

if (argv.repro) {
    var hSize = base2.parse(argv.head);
    var bSize = base2.parse(argv.body);
    if (isNaN(hSize)) die('invalid hSize');
    if (isNaN(bSize)) die('invalid hSize');
    var state = {
        hSize: hSize,
        bSize: bSize,
        timeout: argv.timeout
    };
    test.only('repro ' + describe(state), function t(assert) {
        var search = TestStreamSearch();
        var spec = search.makeSpec(state);
        search.test(spec, assert);
    });
}

test('bisection test', function t(assert) {
    var sizeLimit = null;

    if (argv.sizeLimit) {
        sizeLimit = base2.parse(argv.sizeLimit);
        if (isNaN(sizeLimit)) die('invalid sizeLimit');
    }

    var search = TestStreamSearch({
        stopOnFirstFailure: argv.first,
        traceDetails: argv.trace,
        sizeLimit: sizeLimit || 128 * base2.Ki,
        timeout: argv.timeout
    }).instrument(argv.instrument);

    var firstStop = {};

    async.series([

        {
            withHeaderOnly: true,
            withBodyOnly: true,
            withBoth: true,
            basis: [0, 1],
            mul: []
        },

        {
            withHeaderOnly: true,
            withBodyOnly: true,
            withBoth: true,
            basis: [2]
        },

        {
            withHeaderOnly: true,
            withBodyOnly: true,
            withBoth: true,
            basis: [3]
        },

        {
            // TODO: basis length >= 2 && withBoth causes non-deterministic
            // timeout failures (even with setting maxTries > 1); however none
            // of these failures are ever reproducible...
            // basis: [2, 3, 5, 7, 11, 13],
            withHeaderOnly: true,
            withBodyOnly: true,
            withBoth: false,
            basis: [2, 3]
        }

    ].map(function eachOptions(options) {
        return function runThunk(next) {
            search.run(assert, options, function(err, run) {
                if (!err && argv.first && run.fail) {
                    next(firstStop);
                } else {
                    next(err);
                }
            });
        };
    }), function done(err) {
        if (err && err !== firstStop) assert.ifError(err, 'no final error');
        assert.end();
    });
});

function TestStreamSearch(options) {
    if (!(this instanceof TestStreamSearch)) {
        return new TestStreamSearch(options);
    }
    var self = this;
    TestIsolateSearch.call(self, options);
}
util.inherits(TestStreamSearch, TestIsolateSearch);

TestStreamSearch.prototype.willFailLike = function willFailLike(a, b) {
    if (like(a, b)) return true;
    for (var i = 0; i < b.trace.length; i++) {
        var res = b.trace[i];
        if (res.fail && like(a, res.state)) return true;
    }
    return false;
    function like(a, b) {
        if (a.test.hSize !== b.test.hSize) return false;
        if (a.test.bSize < b.test.bSize) return false;
        return true;
    }
};

TestStreamSearch.prototype.describeState = function describeState(state) {
    return describe(state.test);
};

TestStreamSearch.prototype.describeNoFailure = function describeNoFailure(assert) {
    var self = this;
    assert.pass('found no failure under ' + prettyBytes(self.options.sizeLimit));
};

TestStreamSearch.prototype.init = function init() {
    var self = this;
    self.expand(function(_emit) {
        var base = {hSize: 0, bSize: 0, timeout: self.options.timeout};
        self.options.basis.forEach(function each(n) {
            if (self.options.withHeaderOnly) emit({hSize: n});
            if (self.options.withBodyOnly) emit({bSize: n});
            if (self.options.withBoth) emit({hSize: n, bSize: n});
        });
        function emit(overlay) {
            _emit(self.makeSpec(extend(base, overlay)));
        }
    });
};

TestStreamSearch.prototype.test = function test(state, assert) {
    var options = state.test;
    var name = describe(options);
    var cluster = allocCluster({
        numPeers: 2
    });
    cluster.ready(function clusterReady() {
        for (var i = 0; i < cluster.hosts.length; i++) {
            assert.comment(util.format(
                'cluster host %s: %s',
                i + 1, cluster.hosts[i]));
        }

        var one = cluster.channels[0];
        var two = cluster.channels[1];
        one.handler = echoHandler();
        assert.timeoutAfter(options.timeout || 100);
        streamingTest({
            name: name,
            channel: two,
            opts: {host: cluster.hosts[0]},
            op: 'foo',
            headStream: CountStream({limit: options.hSize}),
            bodyStream: CountStream({limit: options.bSize})
        }, assert, function streamingTestDone() {
            cluster.assertCleanState(assert, {
                channels: [{
                    peers: [{
                        connections: [
                            {direction: 'in', inReqs: 0, outReqs: 0}
                        ]
                    }]
                }, {
                    peers: [{
                        connections: [
                            {direction: 'out', inReqs: 0, outReqs: 0}
                        ]
                    }]
                }]
            });
            cluster.destroy(assert.end);
        });
    });
};

TestStreamSearch.prototype.explore = function explore(spec, _emit) {
    var self = this;
    var good = spec.good.test;
    (self.options.mul || self.options.basis).forEach(function each(n) {
        if (n < 2) return;
        var hSize = n * good.hSize;
        var bSize = n * good.bSize;
        if (hSize <= self.options.sizeLimit) emit({hSize: hSize});
        if (bSize <= self.options.sizeLimit) emit({bSize: bSize});
    });
    function emit(overlay) {
        _emit(spec.makeTest(extend(good, overlay)));
    }
};

TestStreamSearch.prototype.isolate = function isolate(spec, _emit) {
    var good = spec.good && spec.good.test || {hSize: 0, bSize: 0};
    var bad = spec.bad.test;
    if (bad.hSize - good.hSize > 1) emit({hSize: mid(good.hSize, bad.hSize)});
    if (good.bSize < bad.bSize) emit({bSize: mid(good.bSize, bad.bSize)});
    function emit(overlay) {
        _emit(spec.makeTest(extend(good, overlay)));
    }
    function mid(a, b) {
        return a + Math.floor(b / 2 - a / 2);
    }
};

function streamingTest(testCase, assert, callback) {
    if (!callback) callback = assert.end;

    var reqHeadStream;
    if (typeof testCase.headStream === 'function') {
        reqHeadStream = testCase.headStream();
    } else {
        reqHeadStream = testCase.headStream;
    }

    var reqBodyStream;
    if (typeof testCase.bodyStream === 'function') {
        reqBodyStream = testCase.bodyStream();
    } else {
        reqBodyStream = testCase.bodyStream;
    }

    var resHeadStream = PassThrough();
    var resBodyStream = PassThrough();

    var req = testCase.channel.request(extend({
        streamed: true
    }, testCase.opts));
    req.arg1.end(testCase.op);
    reqHeadStream.pipe(resHeadStream);
    reqHeadStream.pipe(req.arg2);
    req.arg2.once('finish', function onArg2Finished() {
        reqBodyStream.pipe(resBodyStream);
        reqBodyStream.pipe(req.arg3);
    });

    onResult.canStream = true;
    req.hookupCallback(onResult);

    function onResult(err, req, res) {
        assert.ifError(err, testCase.name + ': no result error');
        if (err) {
            callback();
            return;
        }
        if (res.streamed) {
            async.series([
                verifyStream('arg2', res.arg2, resHeadStream),
                verifyStream('arg3', res.arg3, resBodyStream),
            ], callback);
        } else {
            verifyStreamChunk('arg2', 0, res.arg2, resHeadStream);
            verifyDrained('arg2', resHeadStream);
            verifyStreamChunk('arg3', 0, res.arg3, resBodyStream);
            verifyDrained('arg3', resBodyStream);
            callback();
        }
    }

    function verifyStreamChunk(name, offset, gotChunk, expected) {
        var expectedChunk = expected.read(gotChunk.length) || Buffer(0);
        assert.deepEqual(gotChunk, expectedChunk, util.format(
            '%s: expected chunk %s bytes @%s',
            name,
            prettyBytes(gotChunk.length),
            '0x' + offset.toString(16))
        );
        return offset + gotChunk.length;
    }

    function verifyDrained(name, expected) {
        var remain = expected.read();
        assert.equal(remain, null, name + ': got all expected data (bytes)');
        assert.equal(remain && remain.length || 0, 0, name + ': got all expected data (length)');
    }

    function verifyStream(name, got, expected) {
        return function verifyStreamThunk(streamDone) {
            var offset = 0;
            got.on('data', onData);
            got.on('error', finish);
            got.on('end', finish);

            function onData(gotChunk) {
                offset = verifyStreamChunk(name, offset, gotChunk, expected);
            }

            function finish(err) {
                assert.ifError(err, name + ': no error');
                if (!err) verifyDrained(name, expected);
                streamDone();
            }
        };
    }
}

function describe(params) {
    return util.format('head %s body %s',
        prettyBytes(params.hSize),
        prettyBytes(params.bSize));
}

function echoHandler() {
    var handler = EndpointHandler();
    function foo(req, buildRes) {
        var res = buildRes({streamed: req.streamed});
        if (req.streamed) {
            res.setOk(true);
            req.arg2.on('data', function onArg2Data(chunk) {
                res.arg2.write(chunk);
            });
            req.arg2.on('end', function onArg2End() {
                res.arg2.end();
            });
            req.arg3.on('data', function onArg3Data(chunk) {
                res.arg3.write(chunk);
            });
            req.arg3.on('end', function onArg3End() {
                res.arg3.end();
            });
        } else {
            res.sendOk(req.arg2, req.arg3);
        }
    }
    foo.canStream = true;
    handler.register('foo', foo);
    return handler;
}

function die() {
    console.error.apply(console, arguments);
    process.exit(1);
}

function prettyBytes(n) {
    return base2.pretty(n, 'B');
}
<|endoftext|>


<commit_before>/*global QUnit:false, module:false, test:false, asyncTest:false, expect:false*/
/*global start:false, stop:false ok:false, equal:false, notEqual:false, deepEqual:false*/
/*global notDeepEqual:false, strictEqual:false, notStrictEqual:false, raises:false*/
(function($) {
  var testSetup = {
    testStart: function(data) {
      $slides = $('#slides');
      $slides.superslides({
        play: true
      });
    },
    init: function() {
      QUnit.testStart = testSetup.testStart;
    }
  };

  $(document).ready(testSetup.init);

  $(function() {
    var addSlide = function($slides) {
      $li = $slides.find('li').first();
      $clone = $li.clone();
      $li.after($clone);
    };

    test('Initialize and store object in data attribute', function() {
      ok($slides.data('superslides'));
    });

    test('update()', function() {
      addSlide($slides);
      equal($slides.superslides('current'), 0, 'current == 0');
      equal($slides.superslides('next'), 1, 'next == 1');
      equal($slides.superslides('prev'), 1, 'prev == 1');
    });

    module('API', {
      setup: function() {
        $slides.superslides('stop');
      },
      teardown: function() {
      }
    });
    test('.size()', function() {
      size = $slides.superslides('size');
      equal(size, 1, 'should be 1');
    });

    test('.start()', function() {
      $slides.superslides('start');
      ok($slides.data('superslides').play_id);
    });

    test('.stop()', function() {
      ok(!$slides.data('superslides').play_id);
    });

    test('.destroy()', function() {
      $slides.superslides('destroy');
      ok(!$slides.data('superslides'));
    });

    test('.current', function() {
      equal($slides.superslides('current'), 0, 'current == 0');
    });

    test('.prev', function() {
      equal($slides.superslides('prev'), 0, 'prev == 0');
    });

    test('.next', function() {
      equal($slides.superslides('next'), 0, 'next == 0');
    });

    module('Events');
    test('slides.updated', function() {
      expect(1);
      $slides.on('slides.updated', function(e) {
        ok('true');
      });

      addSlide($slides);
    });

    test('slides.init', function() {
      expect(1);
      $slides.on('slides.init', function(e) {
        ok('true');
      });
      $slides.superslides('destroy');
      $slides.superslides();
    });
  });

}(jQuery));
<commit_msg>Fix globals<commit_after>/*global QUnit:false, module:false, test:false, asyncTest:false, expect:false*/
/*global start:false, stop:false ok:false, equal:false, notEqual:false, deepEqual:false*/
/*global notDeepEqual:false, strictEqual:false, notStrictEqual:false, raises:false*/
(function($) {
  var testSetup = {
    testStart: function(data) {
      $slides = $('#slides');
      $slides.superslides({
        play: true
      });
    },
    init: function() {
      QUnit.testStart = testSetup.testStart;
    }
  };

  $(document).ready(testSetup.init);

  $(function() {
    var addSlide = function($slides) {
      var $li = $slides.find('li').first();
      var $clone = $li.clone();
      $li.after($clone);
    };

    test('Initialize and store object in data attribute', function() {
      ok($slides.data('superslides'));
    });

    test('update()', function() {
      addSlide($slides);
      equal($slides.superslides('current'), 0, 'current == 0');
      equal($slides.superslides('next'), 1, 'next == 1');
      equal($slides.superslides('prev'), 1, 'prev == 1');
    });

    module('API', {
      setup: function() {
        $slides.superslides('stop');
      },
      teardown: function() {
      }
    });
    test('.size()', function() {
      var size = $slides.superslides('size');
      equal(size, 1, 'should be 1');
    });

    test('.start()', function() {
      $slides.superslides('start');
      ok($slides.data('superslides').play_id);
    });

    test('.stop()', function() {
      ok(!$slides.data('superslides').play_id);
    });

    test('.destroy()', function() {
      $slides.superslides('destroy');
      ok(!$slides.data('superslides'));
    });

    test('.current', function() {
      equal($slides.superslides('current'), 0, 'current == 0');
    });

    test('.prev', function() {
      equal($slides.superslides('prev'), 0, 'prev == 0');
    });

    test('.next', function() {
      equal($slides.superslides('next'), 0, 'next == 0');
    });

    module('Events');
    test('slides.updated', function() {
      expect(1);
      $slides.on('slides.updated', function(e) {
        ok('true');
      });

      addSlide($slides);
    });

    test('slides.init', function() {
      expect(1);
      $slides.on('slides.init', function(e) {
        ok('true');
      });
      $slides.superslides('destroy');
      $slides.superslides();
    });
  });

}(jQuery));
<|endoftext|>


<commit_before>describe('ax5.util.filter TEST', function () {
    /* ax5.util.filter */
    //example 01
    var array = [5, 4, 3, 2, 1];
    it('ax5.util.filter([5,4,3,2,1],function(){return this%2;})', function () {
        var result = ax5.util.filter(array, function () {
            return this % 2;
        });

        _.isEqual(result, [5, 3, 1]).should.equal(true);
    });

    //example 02
    var list = [
        {isdel: 1, name: "ax5-1"},
        {name: "ax5-2"},
        {isdel: 1, name: "ax5-3"},
        {name: "ax5-4"},
        {name: "ax5-5"}
    ];

    it('ax5.util.filter([{isdel : 1 , name : "ax5-1"},{name : "ax5-2"},{isdel : 1 , name : "ax5-3"},{name : "ax5-4"},{name : "ax5-5"}] , function(){return (this.isdel !=1)})', function () {
        var result = ax5.util.filter(list, function () {
            return (this.isdel != 1);
        });

        _.isEqual(result, [{name: "ax5-2"}, {name: "ax5-4"}, {name: "ax5-5"}]).should.equal(true);
    });

    //example03
    var filObject = {
        a: 1,
        s: "string",
        oa: {pickup: true, name: "AXISJ"},
        os: {pickup: true, name: "AX5"}
    };

    it('ax5.util.filter( {a : 1, s : "string", oa : {pickup:true, name:"AXISJ"}, os : {pickup:true, name:"AX5"}}, function(){return this.pickup;})', function () {
        var result = ax5.util.filter(filObject, function () {
            return this.pickup;
        });
        should(result).be.deepEqual([{"pickup": true, "name": "AXISJ"}, {"pickup": true, "name": "AX5"}]);
    });

    /* end ax5.util.filter */
});

describe('ax5.util.search TEST', function () {
    /*ax5.util.search */
    //example01
    var a = ["A", "X", "5"];

    it('ax5.util.search(["A" , "X" , "5"], function(){return this == "X"})', function () {
        var idx = ax5.util.search(a, function () {
            return this == "X";
        });

        _.isEqual(a[idx], "X").should.equal(true);
    });

    //example02
    var a = ["A", "X", "5"];

    it('["A" , "X" ,"5"][ax5.util.search(["A" , "X" ,"5"] , function(idx){return idx == 2;})]', function () {
        var result = a[ax5.util.search(a, function (idx) {
            return idx == 2;
        })
            ];

        _.isEqual(result, "5").should.equal(true);
    });

    //example03
    var b = {a: "AX5-0", x: "AX5-1", 5: "AX5-2"};

    it('{a:"AX5-0" , x:"AX5-1" , 5:"AX5-2"}[ax5.util.search(b , function(k){return k == "x"})]', function () {
        var result = b[ax5.util.search(b, function (k) {
            return k == "x";
        })];

        _.isEqual(result, "AX5-1").should.equal(true);
    });
    /*end ax5.util.search */
});

describe('ax5.util.map TEST', function () {
    /*ax5.util.map*/
    //Usage 01
    var map_a = [1, 2, 3, 4, 5];

    it('[1,2,3,4,5] = ax5.util.map([1,2,3,4,5] , function(){return {id : this}})', function () {
        map_a = ax5.util.map(map_a, function () {
            return {id: this}
        });

        _.isEqual(map_a, [{"id": 1}, {"id": 2}, {"id": 3}, {"id": 4}, {"id": 5}]).should.equal(true);
    });

    //Usage 02
    it('ax5.util.map({a: 1, b: 2}, function (k, v) {return {id: k, value: v};})', function () {

        _.isEqual(ax5.util.map({a: 1, b: 2}, function (k, v) {
            return {id: k, value: v};
        }), [{"id": "a", "value": 1}, {"id": "b", "value": 2}]).should.equal(true);
    });
    /*end ax5.util.map*/
});

describe('ax5.util.merge TEST', function () {
    /*ax5.util.merge*/
    it('ax5.util.merge([1,2,3],[7,8,9])', function () {
        _.isEqual(ax5.util.merge([1, 2, 3], [7, 8, 9]), [1, 2, 3, 7, 8, 9]).should.equal(true);
    });
    /*end ax5.util.merge*/
});

describe('ax5.util.reduce TEST', function () {
    /*ax5.util.reduce*/
    //Example01
    it('ax5.util.reduce([5,4,3,2,1]) , function(p , n){return p*n;}', function () {
        should.deepEqual(ax5.util.reduce([5, 4, 3, 2, 1], function (p, n) {
            return p * n;
        }), 120);
    });
    //Example02
    it('ax5.util.reduce({a:1,b:2} , function(p,n){ return parseInt(p || 0) + parseInt(n);})', function () {
        should.deepEqual(ax5.util.reduce({a: 1, b: 2}, function (p, n) {
            return parseInt(p || 0) + parseInt(n);
        }), 3);
    });
    /*end ax5.util.reduce*/
});

describe('ax5.util.reduceRight TEST', function () {
    /*ax5.util.reduceRight*/
    it('ax5.util.reduceRight([5,4,3,2,1] , function(p,n){return p-n;})', function () {
        should.deepEqual(ax5.util.reduceRight([5, 4, 3, 2, 1], function (p, n) {
            return p - n;
        }), -13);
    });
    /*end ax5.util.reduceRight*/
});

describe('ax5.util.sum TEST', function () {
    /*ax.util.Sum */
    //Usage 01
    it('ax5.util.sum([{name: "122", value: 9},{name: "122", value: 10},{name: "123", value: 11}] , function(){if(this.name == "122"){return this.value;}})', function () {
        var arr = [
            {name: "122", value: 9},
            {name: "122", value: 10},
            {name: "123", value: 11}
        ];

        var rs = ax5.util.sum(arr, function () {
            if (this.name == "122") {
                return this.value;
            }
        });

        should.deepEqual(rs, 19);
    });

    //Usage 02
    it('ax5.util.sum([{name: "122", value: 9},{name: "122", value: 10},{name: "123", value: 11}] , 10 , function(){return this.value;})', function () {
        var arr = [
            {name: "122", value: 9},
            {name: "122", value: 10},
            {name: "123", value: 11}
        ];

        var test = ax5.util.sum(arr, 10, function () {
            return this.value;
        });

        should.deepEqual(test, 40);
    });
    /*end ax.util.Sum */
});

describe('ax5.util.avg TEST', function () {
    /* ax.util.avg */
    it('ax5.util.avg(arr , function(){return this.value;})', function () {
        var arr = [
            {name: "122", value: 9},
            {name: "122", value: 10},
            {name: "123", value: 11}
        ];

        var rs = ax5.util.avg(arr, function () {
            return this.value;
        });

        should.deepEqual(rs, 10);
    });
    /* end ax.util.avg */
});

describe('ax5.util.first TEST', function () {
    /* ax.util.first */
    //Example 01
    it('ax5.util.first(["ax5", "axisj"])', function () {
        var _arr = ["ax5", "axisj"];
        var str = ax5.util.first(_arr);

        should.deepEqual(str, "ax5");
    });

    //Example 02
    //confirm 필요 (ax5.util.toJson을 넣으면 에러)
    it('ax5.util.first({k: "ax5", z: "axisj"})', function () {
        var _obj = {k: "ax5", z: "axisj"};

        should.deepEqual(ax5.util.first(_obj), {"k": "ax5"});
    });
    /* end ax.util.first */
});

describe('ax5.util.first TEST', function () {
    /* ax5.util.last */
    //Example01
    it('ax5.util.last(["ax5", "axisj"])', function () {
        var _arr = ["ax5", "axisj"];

        should.deepEqual(ax5.util.last(_arr), "axisj");
    });

    //Example 02
    //confirm 필요 (ax5.util.toJson을 넣으면 에러)
    it('ax5.util.last({k: "ax5", z: "axisj"})', function () {
        var _obj = {k: "ax5", z: "axisj"};

        should.deepEqual(ax5.util.last(_obj), {"z": "axisj"});
    });
    /* end ax5.util.last */
});

/* ax5.util.deepCopy */

/* end ax5.util.deepCopy */
<commit_msg>update test code<commit_after>describe('ax5.util.each TEST', function () {
    /* ax5.util.filter */
    //example 01
    it('ax5.util.each [object]', function () {
        var obj = {a: 1, b: 2, c: 3, d: 4, e: 5};
        var result = 0;
        ax5.util.each(obj, function (i, o) {
            result += o;
        });
        _.isEqual(result, 15).should.equal(true);
    });
});

describe('ax5.util.filter TEST', function () {
    /* ax5.util.filter */
    //example 01
    var array = [5, 4, 3, 2, 1];
    it('ax5.util.filter([5,4,3,2,1],function(){return this%2;})', function () {
        var result = ax5.util.filter(array, function () {
            return this % 2;
        });

        _.isEqual(result, [5, 3, 1]).should.equal(true);
    });

    //example 02
    var list = [
        {isdel: 1, name: "ax5-1"},
        {name: "ax5-2"},
        {isdel: 1, name: "ax5-3"},
        {name: "ax5-4"},
        {name: "ax5-5"}
    ];

    it('ax5.util.filter([{isdel : 1 , name : "ax5-1"},{name : "ax5-2"},{isdel : 1 , name : "ax5-3"},{name : "ax5-4"},{name : "ax5-5"}] , function(){return (this.isdel !=1)})', function () {
        var result = ax5.util.filter(list, function () {
            return (this.isdel != 1);
        });

        _.isEqual(result, [{name: "ax5-2"}, {name: "ax5-4"}, {name: "ax5-5"}]).should.equal(true);
    });

    //example03
    var filObject = {
        a: 1,
        s: "string",
        oa: {pickup: true, name: "AXISJ"},
        os: {pickup: true, name: "AX5"}
    };

    it('ax5.util.filter( {a : 1, s : "string", oa : {pickup:true, name:"AXISJ"}, os : {pickup:true, name:"AX5"}}, function(){return this.pickup;})', function () {
        var result = ax5.util.filter(filObject, function () {
            return this.pickup;
        });
        should(result).be.deepEqual([{"pickup": true, "name": "AXISJ"}, {"pickup": true, "name": "AX5"}]);
    });

    /* end ax5.util.filter */
});

describe('ax5.util.search TEST', function () {
    /*ax5.util.search */
    //example01
    var a = ["A", "X", "5"];

    it('ax5.util.search(["A" , "X" , "5"], function(){return this == "X"})', function () {
        var idx = ax5.util.search(a, function () {
            return this == "X";
        });

        _.isEqual(a[idx], "X").should.equal(true);
    });

    //example02
    var a = ["A", "X", "5"];

    it('["A" , "X" ,"5"][ax5.util.search(["A" , "X" ,"5"] , function(idx){return idx == 2;})]', function () {
        var result = a[ax5.util.search(a, function (idx) {
            return idx == 2;
        })
            ];

        _.isEqual(result, "5").should.equal(true);
    });

    //example03
    var b = {a: "AX5-0", x: "AX5-1", 5: "AX5-2"};

    it('{a:"AX5-0" , x:"AX5-1" , 5:"AX5-2"}[ax5.util.search(b , function(k){return k == "x"})]', function () {
        var result = b[ax5.util.search(b, function (k) {
            return k == "x";
        })];

        _.isEqual(result, "AX5-1").should.equal(true);
    });
    /*end ax5.util.search */
});

describe('ax5.util.map TEST', function () {
    /*ax5.util.map*/
    //Usage 01
    var map_a = [1, 2, 3, 4, 5];

    it('[1,2,3,4,5] = ax5.util.map([1,2,3,4,5] , function(){return {id : this}})', function () {
        map_a = ax5.util.map(map_a, function () {
            return {id: this}
        });

        _.isEqual(map_a, [{"id": 1}, {"id": 2}, {"id": 3}, {"id": 4}, {"id": 5}]).should.equal(true);
    });

    //Usage 02
    it('ax5.util.map({a: 1, b: 2}, function (k, v) {return {id: k, value: v};})', function () {

        _.isEqual(ax5.util.map({a: 1, b: 2}, function (k, v) {
            return {id: k, value: v};
        }), [{"id": "a", "value": 1}, {"id": "b", "value": 2}]).should.equal(true);
    });
    /*end ax5.util.map*/
});

describe('ax5.util.merge TEST', function () {
    /*ax5.util.merge*/
    it('ax5.util.merge([1,2,3],[7,8,9])', function () {
        _.isEqual(ax5.util.merge([1, 2, 3], [7, 8, 9]), [1, 2, 3, 7, 8, 9]).should.equal(true);
    });
    /*end ax5.util.merge*/
});

describe('ax5.util.reduce TEST', function () {
    /*ax5.util.reduce*/
    //Example01
    it('ax5.util.reduce([5,4,3,2,1]) , function(p , n){return p*n;}', function () {
        should.deepEqual(ax5.util.reduce([5, 4, 3, 2, 1], function (p, n) {
            return p * n;
        }), 120);
    });
    //Example02
    it('ax5.util.reduce({a:1,b:2} , function(p,n){ return parseInt(p || 0) + parseInt(n);})', function () {
        should.deepEqual(ax5.util.reduce({a: 1, b: 2}, function (p, n) {
            return parseInt(p || 0) + parseInt(n);
        }), 3);
    });
    /*end ax5.util.reduce*/
});

describe('ax5.util.reduceRight TEST', function () {
    /*ax5.util.reduceRight*/
    it('ax5.util.reduceRight([5,4,3,2,1] , function(p,n){return p-n;})', function () {
        should.deepEqual(ax5.util.reduceRight([5, 4, 3, 2, 1], function (p, n) {
            return p - n;
        }), -13);
    });
    /*end ax5.util.reduceRight*/
});

describe('ax5.util.sum TEST', function () {
    /*ax.util.Sum */
    //Usage 01
    it('ax5.util.sum([{name: "122", value: 9},{name: "122", value: 10},{name: "123", value: 11}] , function(){if(this.name == "122"){return this.value;}})', function () {
        var arr = [
            {name: "122", value: 9},
            {name: "122", value: 10},
            {name: "123", value: 11}
        ];

        var rs = ax5.util.sum(arr, function () {
            if (this.name == "122") {
                return this.value;
            }
        });

        should.deepEqual(rs, 19);
    });

    //Usage 02
    it('ax5.util.sum([{name: "122", value: 9},{name: "122", value: 10},{name: "123", value: 11}] , 10 , function(){return this.value;})', function () {
        var arr = [
            {name: "122", value: 9},
            {name: "122", value: 10},
            {name: "123", value: 11}
        ];

        var test = ax5.util.sum(arr, 10, function () {
            return this.value;
        });

        should.deepEqual(test, 40);
    });
    /*end ax.util.Sum */
});

describe('ax5.util.avg TEST', function () {
    /* ax.util.avg */
    it('ax5.util.avg(arr , function(){return this.value;})', function () {
        var arr = [
            {name: "122", value: 9},
            {name: "122", value: 10},
            {name: "123", value: 11}
        ];

        var rs = ax5.util.avg(arr, function () {
            return this.value;
        });

        should.deepEqual(rs, 10);
    });
    /* end ax.util.avg */
});

describe('ax5.util.first TEST', function () {
    /* ax.util.first */
    //Example 01
    it('ax5.util.first(["ax5", "axisj"])', function () {
        var _arr = ["ax5", "axisj"];
        var str = ax5.util.first(_arr);

        should.deepEqual(str, "ax5");
    });

    //Example 02
    //confirm 필요 (ax5.util.toJson을 넣으면 에러)
    it('ax5.util.first({k: "ax5", z: "axisj"})', function () {
        var _obj = {k: "ax5", z: "axisj"};

        should.deepEqual(ax5.util.first(_obj), {"k": "ax5"});
    });
    /* end ax.util.first */
});

describe('ax5.util.first TEST', function () {
    /* ax5.util.last */
    //Example01
    it('ax5.util.last(["ax5", "axisj"])', function () {
        var _arr = ["ax5", "axisj"];

        should.deepEqual(ax5.util.last(_arr), "axisj");
    });

    //Example 02
    //confirm 필요 (ax5.util.toJson을 넣으면 에러)
    it('ax5.util.last({k: "ax5", z: "axisj"})', function () {
        var _obj = {k: "ax5", z: "axisj"};

        should.deepEqual(ax5.util.last(_obj), {"z": "axisj"});
    });
    /* end ax5.util.last */
});

/* ax5.util.deepCopy */

/* end ax5.util.deepCopy */
<|endoftext|>


<commit_before>const assert = require('assert')
const should = require('chai').should
should()

const KrakenTime = require('../lib/index').Time

describe('Kraken Connectivity', function () {
  describe('Kraken Time connectivity', function() {
    it('should send valid time', function() {
      const allowedTimeDiscrepancy = 3600 // An hour
      const localUnixTimeStamp = Math.floor(new Date() / 1000)
      const referenceTimestamp = localUnixTimeStamp - allowedTimeDiscrepancy
      const krakenTime = new KrakenTime()

      return krakenTime.getUnixTime()
        .then((unixTime) => {
          console.log(unixTime)
          unixTime.should.be.greaterThan(referenceTimestamp)
        }).catch(() => {
          throw new Error('it failed to respond with unix timestamp')
        })
    })
  })
})<commit_msg>removed unecessary code from test<commit_after>const should = require('chai').should
const KrakenTime = require('../lib/index').Time

should()

describe('Kraken Connectivity', function () {
  describe('Kraken Time connectivity', function() {
    it('should send valid time', function() {
      const allowedTimeDiscrepancy = 3600 // An hour
      const localUnixTimeStamp = Math.floor(new Date() / 1000)
      const referenceTimestamp = localUnixTimeStamp - allowedTimeDiscrepancy
      const krakenTime = new KrakenTime()

      return krakenTime.getUnixTime()
        .then((unixTime) => {
          unixTime
            .should.be.greaterThan(referenceTimestamp)
        }).catch(() => {
          throw new Error('it failed to respond with unix timestamp')
        })
    })
  })
})<|endoftext|>


<commit_before>import React from 'react'
import Tile from './tile'
import TileSizeSelector from './TileSizeSelector'

var MainMenu = React.createClass({

  onTabSelect(key) {
    this.props.navigate(key);
  },

  render() {

    var navigate = this.props.navigate;
    var selected = this.props.selected;

    var items = [ "Users", "Roles", "Permissions", "History" ];

    var tabs = items.map(function(item, index) {

      var onClick = function(e) {
        e.preventDefault();
        navigate(item.toLowerCase());
      }

      var active = selected == item.toLowerCase() ? "active" : "";

      return (

          {item}

      );

    });

    return (

        {tabs}
        <TileSizeSelector className="pull-right" />

    );
  }

});

export default MainMenu
<commit_msg>mainMenu: make stateless<commit_after>import React from 'react'
import Tile from './tile'
import TileSizeSelector from './TileSizeSelector'

var MainMenu = ({ navigate, selected }) => {

  const items = [ "Users", "Roles", "Permissions", "History" ];

  const tabs = items.map(function(item, index) {

    var onClick = function(e) {
      e.preventDefault();
      navigate(item.toLowerCase());
    }

    var active = selected == item.toLowerCase() ? "active" : "";

    return (

        {item}

    );

  });

  return (

      {tabs}
      <TileSizeSelector className="pull-right" />

  );
}

export default MainMenu
<|endoftext|>


<commit_before>/* jshint -W097 */
/* jshint strict:false */
/* jslint node: true */
/* jshint expr: true */
var expect = require('chai').expect;
var fs        = require('fs');

describe('Test package.json and io-package.json', function() {
    it('Test package files', function (done) {
        console.log();

        var fileContentIOPackage = fs.readFileSync(__dirname + '/../io-package.json', 'utf8');
        var ioPackage = JSON.parse(fileContentIOPackage);

        var fileContentNPMPackage = fs.readFileSync(__dirname + '/../package.json', 'utf8');
        var npmPackage = JSON.parse(fileContentNPMPackage);

        expect(ioPackage).to.be.an('object');
        expect(npmPackage).to.be.an('object');

        expect(ioPackage.common.version, 'ERROR: Version number in io-package.json needs to exist').to.exist;
        expect(npmPackage.version, 'ERROR: Version number in package.json needs to exist').to.exist;

        expect(ioPackage.common.version, 'ERROR: Version numbers in package.json and io-package.json needs to match').to.be.equal(npmPackage.version);

        if (!ioPackage.common.news || !ioPackage.common.news[ioPackage.common.version]) {
            console.log('WARNING: No news entry for current version exists in io-package.json, no rollback in Admin possible!');
            console.log();
        }

        expect(npmPackage.author, 'ERROR: Author in package.json needs to exist').to.exist;
        expect(ioPackage.common.authors, 'ERROR: Authors in io-package.json needs to exist').to.exist;

        if (ioPackage.common.name.indexOf('template') !== 0) {
            if (Array.isArray(ioPackage.common.authors)) {
                expect(ioPackage.common.authors.length, 'ERROR: Author in io-package.json needs to be set').to.not.be.equal(0);
                if (ioPackage.common.authors.length === 1) {
                    expect(ioPackage.common.authors[0], 'ERROR: Author in io-package.json needs to be a real name').to.not.be.equal('my Name <my@email.com>');
                }
            }
            else {
                expect(ioPackage.common.authors, 'ERROR: Author in io-package.json needs to be a real name').to.not.be.equal('my Name <my@email.com>');
            }
        }
        else {
            console.log('WARNING: Testing for set authors field in io-package skipped because template adapter');
            console.log();
        }
        expect(fs.existsSync(__dirname + '/../README.md'), 'ERROR: README.md needs to exist! Please create one with description, detail information and changelog. English is mandatory.').to.be.true;
        if (!ioPackage.common.titleLang || typeof ioPackage.common.titleLang !== 'object') {
            console.log('WARNING: titleLang is not existing in io-package.json. Please add');
            console.log();
        }
        if (
            ioPackage.common.title.indexOf('iobroker') !== -1 ||
            ioPackage.common.title.indexOf('ioBroker') !== -1 ||
            ioPackage.common.title.indexOf('adapter') !== -1 ||
            ioPackage.common.title.indexOf('Adapter') !== -1
        ) {
            console.log('WARNING: title contains Adapter or ioBroker. It is clear anyway, that it is adapter for ioBroker.');
            console.log();
        }

        if (ioPackage.common.name.indexOf('vis-') !== 0) {
            if (!ioPackage.common.materialize || !fs.existsSync(__dirname + '/../admin/index_m.html') || !fs.existsSync(__dirname + '/../gulpfile.js')) {
                console.log('WARNING: Admin3 support is missing! Please add it');
                console.log();
            }
            if (ioPackage.common.materialize) {
                expect(fs.existsSync(__dirname + '/../admin/index_m.html'), 'Admin3 support is enabled in io-package.json, but index_m.html is missing!').to.be.true;
            }
        }

        var licenseFileExists = fs.existsSync(__dirname + '/../LICENSE');
        var fileContentReadme = fs.readFileSync(__dirname + '/../README.md', 'utf8');
        if (fileContentReadme.indexOf('## Changelog') === -1) {
            console.log('Warning: The README.md should have a section ## Changelog');
            console.log();
        }
        expect((licenseFileExists || fileContentReadme.indexOf('## License') !== -1), 'A LICENSE must exist as LICENSE file or as part of the README.md').to.be.true;
        if (!licenseFileExists) {
            console.log('Warning: The License should also exist as LICENSE file');
            console.log();
        }
        if (fileContentReadme.indexOf('## License') === -1) {
            console.log('Warning: The README.md should also have a section ## License to be shown in Admin3');
            console.log();
        }
        done();
    });
});
<commit_msg>(bluefox) fix tests<commit_after>/* jshint -W097 */
/* jshint strict:false */
/* jslint node: true */
/* jshint expr: true */
'use strict';

const expect = require('chai').expect;
const fs     = require('fs');

describe('Test package.json and io-package.json', () => {
    it('Test package files', done => {
        console.log();

        const fileContentIOPackage = fs.readFileSync(__dirname + '/../io-package.json', 'utf8');
        const ioPackage = JSON.parse(fileContentIOPackage);

        const fileContentNPMPackage = fs.readFileSync(__dirname + '/../package.json', 'utf8');
        const npmPackage = JSON.parse(fileContentNPMPackage);

        expect(ioPackage).to.be.an('object');
        expect(npmPackage).to.be.an('object');

        expect(ioPackage.common.version, 'ERROR: Version number in io-package.json needs to exist').to.exist;
        expect(npmPackage.version, 'ERROR: Version number in package.json needs to exist').to.exist;

        expect(ioPackage.common.version, 'ERROR: Version numbers in package.json and io-package.json needs to match').to.be.equal(npmPackage.version);

        if (!ioPackage.common.news || !ioPackage.common.news[ioPackage.common.version]) {
            console.log('WARNING: No news entry for current version exists in io-package.json, no rollback in Admin possible!');
            console.log();
        }

        expect(npmPackage.author, 'ERROR: Author in package.json needs to exist').to.exist;
        expect(ioPackage.common.authors, 'ERROR: Authors in io-package.json needs to exist').to.exist;

        if (ioPackage.common.name.indexOf('template') !== 0) {
            if (Array.isArray(ioPackage.common.authors)) {
                expect(ioPackage.common.authors.length, 'ERROR: Author in io-package.json needs to be set').to.not.be.equal(0);
                if (ioPackage.common.authors.length === 1) {
                    expect(ioPackage.common.authors[0], 'ERROR: Author in io-package.json needs to be a real name').to.not.be.equal('my Name <my@email.com>');
                }
            }
            else {
                expect(ioPackage.common.authors, 'ERROR: Author in io-package.json needs to be a real name').to.not.be.equal('my Name <my@email.com>');
            }
        }
        else {
            console.log('WARNING: Testing for set authors field in io-package skipped because template adapter');
            console.log();
        }
        expect(fs.existsSync(__dirname + '/../README.md'), 'ERROR: README.md needs to exist! Please create one with description, detail information and changelog. English is mandatory.').to.be.true;
        if (!ioPackage.common.titleLang || typeof ioPackage.common.titleLang !== 'object') {
            console.log('WARNING: titleLang is not existing in io-package.json. Please add');
            console.log();
        }
        if (
            ioPackage.common.title.indexOf('iobroker') !== -1 ||
            ioPackage.common.title.indexOf('ioBroker') !== -1 ||
            ioPackage.common.title.indexOf('adapter') !== -1 ||
            ioPackage.common.title.indexOf('Adapter') !== -1
        ) {
            console.log('WARNING: title contains Adapter or ioBroker. It is clear anyway, that it is adapter for ioBroker.');
            console.log();
        }

        if (!ioPackage.common.controller && !ioPackage.common.onlyWWW && !ioPackage.common.noConfig) {
            if (!ioPackage.common.materialize || !fs.existsSync(__dirname + '/../admin/index_m.html') || !fs.existsSync(__dirname + '/../gulpfile.js')) {
                console.log('WARNING: Admin3 support is missing! Please add it');
                console.log();
            }
            if (ioPackage.common.materialize) {
                expect(fs.existsSync(__dirname + '/../admin/index_m.html'), 'Admin3 support is enabled in io-package.json, but index_m.html is missing!').to.be.true;
            }
        }

        var licenseFileExists = fs.existsSync(__dirname + '/../LICENSE');
        var fileContentReadme = fs.readFileSync(__dirname + '/../README.md', 'utf8');
        if (fileContentReadme.indexOf('## Changelog') === -1) {
            console.log('Warning: The README.md should have a section ## Changelog');
            console.log();
        }
        expect((licenseFileExists || fileContentReadme.indexOf('## License') !== -1), 'A LICENSE must exist as LICENSE file or as part of the README.md').to.be.true;
        if (!licenseFileExists) {
            console.log('Warning: The License should also exist as LICENSE file');
            console.log();
        }
        if (fileContentReadme.indexOf('## License') === -1) {
            console.log('Warning: The README.md should also have a section ## License to be shown in Admin3');
            console.log();
        }
        done();
    });
});
<|endoftext|>


<commit_before>define([
  'angular',
  'app',
  'lodash',
  'jquery',
],
function (angular, app, _) {
  'use strict';

  angular
    .module('grafana.controllers')
    .controller('SelectDropdownCtrl', function($q) {
      var vm = this;

      vm.show = function() {
        vm.oldVariableText = vm.variable.current.text;
        vm.highlightIndex = -1;

        var currentValues = vm.variable.current.value;
        if (_.isString(currentValues)) {
          currentValues  = [currentValues];
        }

        vm.options = _.map(vm.variable.options, function(option) {
          if (_.indexOf(currentValues, option.value) >= 0) { option.selected = true; }
          return option;
        });

        _.sortBy(vm.options, 'text');

        vm.selectedValues = _.filter(vm.options, {selected: true});

        vm.tags = _.map(vm.variable.tags, function(value) {
          return { text: value, selected: false };
        });

        vm.search = {query: '', options: vm.options};
        vm.dropdownVisible = true;
      };

      vm.updateLinkText = function() {
        var current = vm.variable.current;
        var currentValues = current.value;

        if (_.isArray(currentValues) && current.tags.length) {
          // filer out values that are in selected tags
          currentValues = _.filter(currentValues, function(test) {
            for (var i = 0; i < current.tags.length; i++) {
              if (_.indexOf(current.tags[i].values, test) !== -1) {
                return false;
              }
            }
            return true;
          });
          // convert values to text
          var currentTexts = _.map(currentValues, function(value) {
            for (var i = 0; i < vm.variable.options.length; i++) {
              var option = vm.variable.options[i];
              if (option.value === value) {
                return option.text;
              }
            }
            return value;
          });
          // join texts
          vm.linkText = currentTexts.join(' + ');
          if (vm.linkText.length > 0) {
            vm.linkText += ' + ';
          }
        } else {
          vm.linkText = vm.variable.current.text;
        }
      };

      vm.clearSelections = function() {
        _.each(vm.options, function(option) {
          option.selected = false;
        });

        vm.selectionsChanged(false);
      };

      vm.selectTag = function(tag) {
        tag.selected = !tag.selected;
        var tagValuesPromise;
        if (!tag.values) {
          tagValuesPromise = vm.getValuesForTag({tagKey: tag.text});
        } else {
          tagValuesPromise = $q.when(tag.values);
        }

        tagValuesPromise.then(function(values) {
          tag.values = values;
          tag.valuesText = values.join(' + ');
          _.each(vm.options, function(option) {
            if (_.indexOf(tag.values, option.value) !== -1) {
              option.selected = tag.selected;
            }
          });

          vm.selectionsChanged(false);
        });
      };

      vm.keyDown = function (evt) {
        if (evt.keyCode === 27) {
          vm.hide();
        }
        if (evt.keyCode === 40) {
          vm.moveHighlight(1);
        }
        if (evt.keyCode === 38) {
          vm.moveHighlight(-1);
        }
        if (evt.keyCode === 13) {
          vm.optionSelected(vm.search.options[vm.highlightIndex], {}, true, false);
        }
        if (evt.keyCode === 32) {
          vm.optionSelected(vm.search.options[vm.highlightIndex], {}, false, false);
        }
      };

      vm.moveHighlight = function(direction) {
        vm.highlightIndex = (vm.highlightIndex + direction) % vm.search.options.length;
      };

      vm.selectValue = function(option, event, commitChange, excludeOthers) {
        if (!option) { return; }

        option.selected = !option.selected;

        commitChange = commitChange || false;
        excludeOthers = excludeOthers || false;

        var setAllExceptCurrentTo = function(newValue) {
          _.each(vm.options, function(other) {
            if (option !== other) { other.selected = newValue; }
          });
        };

        // commit action (enter key), should not deselect it
        if (commitChange) {
          option.selected = true;
        }

        if (option.text === 'All' || excludeOthers) {
          setAllExceptCurrentTo(false);
          commitChange = true;
        }
        else if (!vm.variable.multi) {
          setAllExceptCurrentTo(false);
          commitChange = true;
        } else if (event.ctrlKey || event.metaKey || event.shiftKey) {
          commitChange = true;
          setAllExceptCurrentTo(false);
        }

        vm.selectionsChanged(commitChange);
      };

      vm.selectionsChanged = function(commitChange) {
        vm.selectedValues = _.filter(vm.options, {selected: true});

        if (vm.selectedValues.length > 1 && vm.selectedValues.length !== vm.options.length) {
          if (vm.selectedValues[0].text === 'All') {
            vm.selectedValues[0].selected = false;
            vm.selectedValues = vm.selectedValues.slice(1, vm.selectedValues.length);
          }
        }

        // validate selected tags
        _.each(vm.tags, function(tag) {
          if (tag.selected)  {
            _.each(tag.values, function(value) {
              if (!_.findWhere(vm.selectedValues, {value: value})) {
                tag.selected = false;
              }
            });
          }
        });

        vm.selectedTags = _.filter(vm.tags, {selected: true});
        vm.variable.current.value = _.pluck(vm.selectedValues, 'value');
        vm.variable.current.text = _.pluck(vm.selectedValues, 'text').join(' + ');
        vm.variable.current.tags = vm.selectedTags;

        // only single value
        if (vm.selectedValues.length === 1) {
          vm.variable.current.value = vm.selectedValues[0].value;
        }

        if (commitChange) {
          vm.commitChanges();
        }
      };

      vm.commitChanges = function() {
        // make sure one option is selected
        if (vm.selectedValues.length === 0) {
          vm.options[0].selected = true;
          vm.selectionsChanged(false);
        }

        vm.dropdownVisible = false;
        vm.updateLinkText();

        if (vm.variable.current.text !== vm.oldVariableText) {
          vm.onUpdated();
        }
      };

      vm.queryChanged = function() {
        vm.highlightIndex = -1;
        vm.search.options = _.filter(vm.options, function(option) {
          return option.text.toLowerCase().indexOf(vm.search.query.toLowerCase()) !== -1;
        });
      };

      vm.init = function() {
        vm.selectedTags = vm.variable.current.tags || [];
        vm.updateLinkText();
      };

    });

    angular
    .module('grafana.directives')
    .directive('variableValueSelect', function($compile, $window, $timeout) {

      return {
        scope: { variable: "=", onUpdated: "&", getValuesForTag: "&" },
        templateUrl: 'app/features/dashboard/partials/variableValueSelect.html',
        controller: 'SelectDropdownCtrl',
        controllerAs: 'vm',
        bindToController: true,
        link: function(scope, elem) {
          var bodyEl = angular.element($window.document.body);
          var linkEl = elem.find('.variable-value-link');
          var inputEl = elem.find('input');

          function openDropdown() {
            inputEl.css('width', Math.max(linkEl.width(), 30) + 'px');

            inputEl.show();
            linkEl.hide();

            inputEl.focus();
            $timeout(function() { bodyEl.on('click', bodyOnClick); }, 0, false);
          }

          function switchToLink() {
            inputEl.hide();
            linkEl.show();
            bodyEl.off('click', bodyOnClick);
          }

          function bodyOnClick (e) {
            if (elem.has(e.target).length === 0) {
              scope.$apply(function() {
                scope.vm.commitChanges();
              });
            }
          }

          scope.$watch('vm.dropdownVisible', function(newValue) {
            if (newValue) {
              openDropdown();
            } else {
              switchToLink();
            }
          });

          scope.vm.init();
        },
      };
    });

});
<commit_msg>Fixed intendation<commit_after>define([
  'angular',
  'app',
  'lodash',
  'jquery',
],
function (angular, app, _) {
  'use strict';

  angular
    .module('grafana.controllers')
    .controller('SelectDropdownCtrl', function($q) {
      var vm = this;

      vm.show = function() {
        vm.oldVariableText = vm.variable.current.text;
        vm.highlightIndex = -1;

        var currentValues = vm.variable.current.value;
        if (_.isString(currentValues)) {
          currentValues  = [currentValues];
        }

        vm.options = _.map(vm.variable.options, function(option) {
          if (_.indexOf(currentValues, option.value) >= 0) { option.selected = true; }
          return option;
        });

        _.sortBy(vm.options, 'text');

        vm.selectedValues = _.filter(vm.options, {selected: true});

        vm.tags = _.map(vm.variable.tags, function(value) {
          return { text: value, selected: false };
        });

        vm.search = {query: '', options: vm.options};
        vm.dropdownVisible = true;
      };

      vm.updateLinkText = function() {
        var current = vm.variable.current;
        var currentValues = current.value;

        if (_.isArray(currentValues) && current.tags.length) {
          // filer out values that are in selected tags
          currentValues = _.filter(currentValues, function(test) {
            for (var i = 0; i < current.tags.length; i++) {
              if (_.indexOf(current.tags[i].values, test) !== -1) {
                return false;
              }
            }
            return true;
          });
          // convert values to text
          var currentTexts = _.map(currentValues, function(value) {
            for (var i = 0; i < vm.variable.options.length; i++) {
              var option = vm.variable.options[i];
              if (option.value === value) {
                return option.text;
              }
            }
            return value;
          });
          // join texts
          vm.linkText = currentTexts.join(' + ');
          if (vm.linkText.length > 0) {
            vm.linkText += ' + ';
          }
        } else {
          vm.linkText = vm.variable.current.text;
        }
      };

      vm.clearSelections = function() {
        _.each(vm.options, function(option) {
          option.selected = false;
        });

        vm.selectionsChanged(false);
      };

      vm.selectTag = function(tag) {
        tag.selected = !tag.selected;
        var tagValuesPromise;
        if (!tag.values) {
          tagValuesPromise = vm.getValuesForTag({tagKey: tag.text});
        } else {
          tagValuesPromise = $q.when(tag.values);
        }

        tagValuesPromise.then(function(values) {
          tag.values = values;
          tag.valuesText = values.join(' + ');
          _.each(vm.options, function(option) {
            if (_.indexOf(tag.values, option.value) !== -1) {
              option.selected = tag.selected;
            }
          });

          vm.selectionsChanged(false);
        });
      };

      vm.keyDown = function (evt) {
        if (evt.keyCode === 27) {
          vm.hide();
        }
        if (evt.keyCode === 40) {
          vm.moveHighlight(1);
        }
        if (evt.keyCode === 38) {
          vm.moveHighlight(-1);
        }
        if (evt.keyCode === 13) {
          vm.optionSelected(vm.search.options[vm.highlightIndex], {}, true, false);
        }
        if (evt.keyCode === 32) {
          vm.optionSelected(vm.search.options[vm.highlightIndex], {}, false, false);
        }
      };

      vm.moveHighlight = function(direction) {
        vm.highlightIndex = (vm.highlightIndex + direction) % vm.search.options.length;
      };

      vm.selectValue = function(option, event, commitChange, excludeOthers) {
        if (!option) { return; }

        option.selected = !option.selected;

        commitChange = commitChange || false;
        excludeOthers = excludeOthers || false;

        var setAllExceptCurrentTo = function(newValue) {
          _.each(vm.options, function(other) {
            if (option !== other) { other.selected = newValue; }
          });
        };

        // commit action (enter key), should not deselect it
        if (commitChange) {
          option.selected = true;
        }

        if (option.text === 'All' || excludeOthers) {
          setAllExceptCurrentTo(false);
          commitChange = true;
        }
        else if (!vm.variable.multi) {
          setAllExceptCurrentTo(false);
          commitChange = true;
        } else if (event.ctrlKey || event.metaKey || event.shiftKey) {
          commitChange = true;
          setAllExceptCurrentTo(false);
        }

        vm.selectionsChanged(commitChange);
      };

      vm.selectionsChanged = function(commitChange) {
        vm.selectedValues = _.filter(vm.options, {selected: true});

        if (vm.selectedValues.length > 1 && vm.selectedValues.length !== vm.options.length) {
          if (vm.selectedValues[0].text === 'All') {
            vm.selectedValues[0].selected = false;
            vm.selectedValues = vm.selectedValues.slice(1, vm.selectedValues.length);
          }
        }

        // validate selected tags
        _.each(vm.tags, function(tag) {
          if (tag.selected)  {
            _.each(tag.values, function(value) {
              if (!_.findWhere(vm.selectedValues, {value: value})) {
                tag.selected = false;
              }
            });
          }
        });

        vm.selectedTags = _.filter(vm.tags, {selected: true});
        vm.variable.current.value = _.pluck(vm.selectedValues, 'value');
        vm.variable.current.text = _.pluck(vm.selectedValues, 'text').join(' + ');
        vm.variable.current.tags = vm.selectedTags;

        // only single value
        if (vm.selectedValues.length === 1) {
          vm.variable.current.value = vm.selectedValues[0].value;
        }

        if (commitChange) {
          vm.commitChanges();
        }
      };

      vm.commitChanges = function() {
        // make sure one option is selected
        if (vm.selectedValues.length === 0) {
          vm.options[0].selected = true;
          vm.selectionsChanged(false);
        }

        vm.dropdownVisible = false;
        vm.updateLinkText();

        if (vm.variable.current.text !== vm.oldVariableText) {
          vm.onUpdated();
        }
      };

      vm.queryChanged = function() {
        vm.highlightIndex = -1;
        vm.search.options = _.filter(vm.options, function(option) {
          return option.text.toLowerCase().indexOf(vm.search.query.toLowerCase()) !== -1;
        });
      };

      vm.init = function() {
        vm.selectedTags = vm.variable.current.tags || [];
        vm.updateLinkText();
      };

    });

  angular
    .module('grafana.directives')
    .directive('variableValueSelect', function($compile, $window, $timeout) {

      return {
        scope: { variable: "=", onUpdated: "&", getValuesForTag: "&" },
        templateUrl: 'app/features/dashboard/partials/variableValueSelect.html',
        controller: 'SelectDropdownCtrl',
        controllerAs: 'vm',
        bindToController: true,
        link: function(scope, elem) {
          var bodyEl = angular.element($window.document.body);
          var linkEl = elem.find('.variable-value-link');
          var inputEl = elem.find('input');

          function openDropdown() {
            inputEl.css('width', Math.max(linkEl.width(), 30) + 'px');

            inputEl.show();
            linkEl.hide();

            inputEl.focus();
            $timeout(function() { bodyEl.on('click', bodyOnClick); }, 0, false);
          }

          function switchToLink() {
            inputEl.hide();
            linkEl.show();
            bodyEl.off('click', bodyOnClick);
          }

          function bodyOnClick (e) {
            if (elem.has(e.target).length === 0) {
              scope.$apply(function() {
                scope.vm.commitChanges();
              });
            }
          }

          scope.$watch('vm.dropdownVisible', function(newValue) {
            if (newValue) {
              openDropdown();
            } else {
              switchToLink();
            }
          });

          scope.vm.init();
        },
      };
    });

});
<|endoftext|>


<commit_before>angular.module('mage').factory('Observation', ['$resource', function($resource) {

  var ObservationId = $resource('/api/events/:eventId/observations/id/', {
    eventId: '@eventId'
  }, {
    createId: {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      }
    }
  });

  var Observation = $resource('/api/events/:eventId/observations/:id', {
    id: '@id',
    eventId: '@eventId'
  }, {
    update: {
      method: 'PUT',
      url: '/api/events/:eventId/observations/id/:id',
      headers: {
        'Content-Type': 'application/json'
      }
    },
    get: {
      method: 'GET'
    }
  });

  Observation.prototype.$save = function(params, success, error) {
    if (this.id) {
      this.$update(params, success, error);
    } else {
      var self = this;
      var onSuccess = function(observation) {
        self.id = observation.id;
        self.$update(params, success, error);
      };

      new ObservationId({eventId: this.eventId}).$createId({}, onSuccess, error);
    }
  };

  return Observation;
}])
.factory('ObservationFavorite', ['$resource', function($resource) {

  var ObservationFavorite = $resource('/api/events/:eventId/observations/:observationId/favorite', {
    id: '@id',
    observationId: '@observationId',
    eventId: '@eventId'
  },{
    save: {
      method: 'PUT',
      headers: {
        'Content-Type': 'application/json'
      }
    }
  });

  return ObservationFavorite;
}])
.factory('ObservationImportant', ['$resource', function($resource) {

  var ObservationImportant = $resource('/api/events/:eventId/observations/:observationId/important', {
    id: '@id',
    observationId: '@observationId',
    eventId: '@eventId'
  },{
    save: {
      method: 'PUT',
      headers: {
        'Content-Type': 'application/json'
      }
    }
  });

  return ObservationImportant;
}])
.factory('ObservationState', ['$resource', function($resource) {

  var ObservationState = $resource('/api/events/:eventId/observations/:observationId/states/:id', {
    id: '@id',
    observationId: '@observationId',
    eventId: '@eventId'
  },{
    save: {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      }
    },
    get: {
      method: 'GET',
      headers: {
        'Content-Type': 'application/json'
      }
    }
  });

  return ObservationState;
}])
.factory('ObservationAttachment', ['$resource', function($resource) {
  var ObservationAttachment = $resource('/api/events/:eventId/observations/:observationId/attachments/:id', {

  }, {
    get: {
      method: 'GET'
    }
  });

  return ObservationAttachment;
}]);
<commit_msg>Update observation resource to conform to new api<commit_after>angular.module('mage').factory('Observation', ['$resource', function($resource) {

  var ObservationId = $resource('/api/events/:eventId/observations/id/', {
    eventId: '@eventId'
  }, {
    createId: {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      }
    }
  });

  var Observation = $resource('/api/events/:eventId/observations/:id', {
    id: '@id',
    eventId: '@eventId'
  }, {
    update: {
      method: 'PUT',
      url: '/api/events/:eventId/observations/:id',
      headers: {
        'Content-Type': 'application/json'
      }
    },
    get: {
      method: 'GET'
    }
  });

  Observation.prototype.$save = function(params, success, error) {
    if (this.id) {
      this.$update(params, success, error);
    } else {
      var self = this;
      var onSuccess = function(observation) {
        self.id = observation.id;
        self.$update(params, success, error);
      };

      new ObservationId({eventId: this.eventId}).$createId({}, onSuccess, error);
    }
  };

  return Observation;
}])
.factory('ObservationFavorite', ['$resource', function($resource) {

  var ObservationFavorite = $resource('/api/events/:eventId/observations/:observationId/favorite', {
    id: '@id',
    observationId: '@observationId',
    eventId: '@eventId'
  },{
    save: {
      method: 'PUT',
      headers: {
        'Content-Type': 'application/json'
      }
    }
  });

  return ObservationFavorite;
}])
.factory('ObservationImportant', ['$resource', function($resource) {

  var ObservationImportant = $resource('/api/events/:eventId/observations/:observationId/important', {
    id: '@id',
    observationId: '@observationId',
    eventId: '@eventId'
  },{
    save: {
      method: 'PUT',
      headers: {
        'Content-Type': 'application/json'
      }
    }
  });

  return ObservationImportant;
}])
.factory('ObservationState', ['$resource', function($resource) {

  var ObservationState = $resource('/api/events/:eventId/observations/:observationId/states/:id', {
    id: '@id',
    observationId: '@observationId',
    eventId: '@eventId'
  },{
    save: {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      }
    },
    get: {
      method: 'GET',
      headers: {
        'Content-Type': 'application/json'
      }
    }
  });

  return ObservationState;
}])
.factory('ObservationAttachment', ['$resource', function($resource) {
  var ObservationAttachment = $resource('/api/events/:eventId/observations/:observationId/attachments/:id', {

  }, {
    get: {
      method: 'GET'
    }
  });

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


<commit_before>define([
  'angular',
  'jquery',
],
function(angular, $) {
  "use strict";

  var module = angular.module('grafana.services');

  module.service('dashboardKeybindings', function($rootScope, keyboardManager, $modal, $q) {

    this.shortcuts = function(scope) {

      scope.$on('$destroy', function() {
        keyboardManager.unbindAll();
      });

      var helpModalScope = null;
      keyboardManager.bind('shift+?', function() {
        if (helpModalScope) { return; }

        helpModalScope = $rootScope.$new();
        var helpModal = $modal({
          template: './app/partials/help_modal.html',
          persist: false,
          show: false,
          scope: helpModalScope,
          keyboard: false
        });

        helpModalScope.$on('$destroy', function() { helpModalScope = null; });
        $q.when(helpModal).then(function(modalEl) { modalEl.modal('show'); });

      }, { inputDisabled: true });

      keyboardManager.bind('ctrl+f', function() {
        scope.appEvent('show-dash-search');
      }, { inputDisabled: true });

      keyboardManager.bind('ctrl+o', function() {
        var current = scope.dashboard.sharedCrosshair;
        scope.dashboard.sharedCrosshair = !current;
        scope.broadcastRefresh();
      }, { inputDisabled: true });

      keyboardManager.bind('ctrl+l', function() {
        scope.$broadcast('toggle-all-legends');
      }, { inputDisabled: true });

      keyboardManager.bind('ctrl+h', function() {
        var current = scope.dashboard.hideControls;
        scope.dashboard.hideControls = !current;
      }, { inputDisabled: true });

      keyboardManager.bind('ctrl+s', function(evt) {
        scope.appEvent('save-dashboard', evt);
      }, { inputDisabled: true });

      keyboardManager.bind('ctrl+r', function() {
        scope.broadcastRefresh();
      }, { inputDisabled: true });

      keyboardManager.bind('ctrl+z', function(evt) {
        scope.appEvent('zoom-out', evt);
      }, { inputDisabled: true });

      keyboardManager.bind('esc', function() {
        var popups = $('.popover.in');
        if (popups.length > 0) {
          return;
        }
        // close modals
        var modalData = $(".modal").data();
        if (modalData && modalData.$scope && modalData.$scope.dismiss) {
          modalData.$scope.dismiss();
        }

        scope.appEvent('hide-dash-editor');

        scope.exitFullscreen();
      }, { inputDisabled: true });
    };
  });
});
<commit_msg>Removed unused keybinding, ctrl+l, Fixes #1962<commit_after>define([
  'angular',
  'jquery',
],
function(angular, $) {
  "use strict";

  var module = angular.module('grafana.services');

  module.service('dashboardKeybindings', function($rootScope, keyboardManager, $modal, $q) {

    this.shortcuts = function(scope) {

      scope.$on('$destroy', function() {
        keyboardManager.unbindAll();
      });

      var helpModalScope = null;
      keyboardManager.bind('shift+?', function() {
        if (helpModalScope) { return; }

        helpModalScope = $rootScope.$new();
        var helpModal = $modal({
          template: './app/partials/help_modal.html',
          persist: false,
          show: false,
          scope: helpModalScope,
          keyboard: false
        });

        helpModalScope.$on('$destroy', function() { helpModalScope = null; });
        $q.when(helpModal).then(function(modalEl) { modalEl.modal('show'); });

      }, { inputDisabled: true });

      keyboardManager.bind('ctrl+f', function() {
        scope.appEvent('show-dash-search');
      }, { inputDisabled: true });

      keyboardManager.bind('ctrl+o', function() {
        var current = scope.dashboard.sharedCrosshair;
        scope.dashboard.sharedCrosshair = !current;
        scope.broadcastRefresh();
      }, { inputDisabled: true });

      keyboardManager.bind('ctrl+h', function() {
        var current = scope.dashboard.hideControls;
        scope.dashboard.hideControls = !current;
      }, { inputDisabled: true });

      keyboardManager.bind('ctrl+s', function(evt) {
        scope.appEvent('save-dashboard', evt);
      }, { inputDisabled: true });

      keyboardManager.bind('ctrl+r', function() {
        scope.broadcastRefresh();
      }, { inputDisabled: true });

      keyboardManager.bind('ctrl+z', function(evt) {
        scope.appEvent('zoom-out', evt);
      }, { inputDisabled: true });

      keyboardManager.bind('esc', function() {
        var popups = $('.popover.in');
        if (popups.length > 0) {
          return;
        }
        // close modals
        var modalData = $(".modal").data();
        if (modalData && modalData.$scope && modalData.$scope.dismiss) {
          modalData.$scope.dismiss();
        }

        scope.appEvent('hide-dash-editor');

        scope.exitFullscreen();
      }, { inputDisabled: true });
    };
  });
});
<|endoftext|>