<commit_before>const fs = require('fs');
const path = require('path');
const { expect } = require('chai');
require('../../fixtures/namespace');

const ContainerBuilder = Jymfony.Component.DependencyInjection.ContainerBuilder;
const ContainerInterface = Jymfony.Component.DependencyInjection.ContainerInterface;
const ServiceClosureArgument = Jymfony.Component.DependencyInjection.Argument.ServiceClosureArgument;
const Definition = Jymfony.Component.DependencyInjection.Definition;
const JsDumper = Jymfony.Component.DependencyInjection.Dumper.JsDumper;
const Fixtures = Jymfony.Component.DependencyInjection.Fixtures;
const ParameterBag = Jymfony.Component.DependencyInjection.ParameterBag.ParameterBag;
const Reference = Jymfony.Component.DependencyInjection.Reference;
const ServiceLocator = Jymfony.Component.DependencyInjection.ServiceLocator;
const Variable = Jymfony.Component.DependencyInjection.Variable;
const fixturesPath = path.join(__dirname, '..', '..', 'fixtures');

describe('[DependencyInjection] JsDumper', function () {
    it('dump', () => {
        const container = new ContainerBuilder();
        container.compile();

        const dumper = new JsDumper(container);
        expect(dumper.dump({ build_time: 1536621245 })).to.be.deep.equal({
            'ContainerkHWy2bx/ProjectContainer.js': fs.readFileSync(path.join(fixturesPath, 'js', 'services1.js')).toString(),
            'ProjectContainer.js': `
// This file has been auto-generated by the Jymfony Dependency Injection Component for internal use.
const ContainerkHWy2bx = require('./ContainerkHWy2bx/ProjectContainer.js');

module.exports = new ContainerkHWy2bx({
    'container.build_hash': 'kHWy2bx',
    'container.build_id': '1285839777',
    'container.build_time': 1536621245,
});

`,
        });
        expect(dumper.dump({ class_name: 'DumpedContainer', base_class: 'AbstractContainer' })['ContainerEexe5Ot/DumpedContainer.js'])
            .to.be.equal(fs.readFileSync(path.join(fixturesPath, 'js', 'services1-1.js')).toString());
    });

    it('dump optimization string', () => {
        const definition = new Definition();
        definition.setClass('Object');
        definition.setPublic(true);
        definition.addArgument({
            'only dot': '.',
            'concatenation as value': '+""+',
            'concatenation from the start value': '""+',
            '.': 'dot as a key',
            '+""+': 'concatenation as a key',
            '""+': 'concatenation from the start key',
            'optimize concatenation': 'string1%some_string%string2',
            'optimize concatenation with empty string': 'string1%empty_value%string2',
            'optimize concatenation from the start': '%empty_value%start',
            'optimize concatenation at the end': 'end%empty_value%',
        });

        const container = new ContainerBuilder();
        container.setResourceTracking(false);
        container.setDefinition('test', definition);
        container.setParameter('empty_value', '');
        container.setParameter('some_string', '-');
        container.compile();

        const dumper = new JsDumper(container);
        expect(dumper.dump({ build_time: 1536621245 })['ContainerDw9sVw7/ProjectContainer.js'])
            .to.be.equal(fs.readFileSync(path.join(fixturesPath, 'js', 'services10.js')).toString());
    });

    const tests = function * () {
        yield {'foo': new Definition('Object')};
        yield {'foo': new Reference('foo')};
        yield {'foo': new Variable('foo')};
    };
    let count = 0;

    for (const t of tests()) {
        it('should throw if invalid parameters are passed #'+count++, () => {
            const container = new ContainerBuilder(new ParameterBag(t));
            container.compile();

            const dumper = new JsDumper(container);
            expect(() => dumper.dump()).to.throw(InvalidArgumentException);
        });
    }

    it('should add parameters', () => {
        const container = require(path.join(fixturesPath, 'containers', 'container8.js'));
        container.compile();

        const dumper = new JsDumper(container);
        expect(dumper.dump({ build_time: 1536621245 })['ContainerbFqdJN6/ProjectContainer.js'])
            .to.be.equal(fs.readFileSync(path.join(fixturesPath, 'js', 'services8.js')).toString());
    });

    it('should add services', () => {
        const container = require(path.join(fixturesPath, 'containers', 'container9.js'));
        container.compile();

        const dumper = new JsDumper(container);
        expect(dumper.dump({ build_time: 1536621245 })['ContainerahGASul/ProjectContainer.js'])
            .to.be.equal(fs.readFileSync(path.join(fixturesPath, 'js', 'services9.js')).toString());
    });

    it('should handle env parameters', () => {
        const container = require(path.join(fixturesPath, 'containers', 'container-env.js'));
        container.compile();

        const dumper = new JsDumper(container);
        expect(dumper.dump({ build_time: 1536621245 })['Container15Bk9yA/ProjectContainer.js'])
            .to.be.equal(fs.readFileSync(path.join(fixturesPath, 'js', 'services-env.js')).toString());
    });

    it('should handle factories inclusion', () => {
        const container = require(path.join(fixturesPath, 'containers', 'container14.js'));
        container.compile();

        const dumper = new JsDumper(container);
        expect(dumper.dump({ build_time: 1536621245 })['ContainerHk8K7Jr/ProjectContainer.js'])
            .to.be.equal(fs.readFileSync(path.join(fixturesPath, 'js', 'services14.js')).toString());
    });

    it('should handle module inclusion', () => {
        const container = require(path.join(fixturesPath, 'containers', 'container15.js'));
        container.compile();

        const dumper = new JsDumper(container);
        expect(dumper.dump({ build_time: 1536621245 })['Containerhr7szKm/ProjectContainer.js'])
            .to.be.equal(fs.readFileSync(path.join(fixturesPath, 'js', 'services15.js')).toString());
    });

    it('should handle service locators', () => {
        const container = new ContainerBuilder();
        let nil;

        container.register('foo_service', ServiceLocator)
            .setPublic(true)
            .addArgument({
                'bar': new ServiceClosureArgument(new Reference('bar_service')),
                'baz': new ServiceClosureArgument(new Reference('baz_service', 'stdClass')),
                'nil': nil = new ServiceClosureArgument(new Reference('nil')),
            })
        ;

        // No method calls
        container.register('translator.loader_1', 'stdClass').setPublic(true);
        container.register('translator.loader_1_locator', ServiceLocator)
            .setPublic(false)
            .addArgument({
                'translator.loader_1': new ServiceClosureArgument(new Reference('translator.loader_1')),
            });
        container.register('translator_1', Fixtures.StubbedTranslator)
            .setPublic(true)
            .addArgument(new Reference('translator.loader_1_locator'));

        // One method calls
        container.register('translator.loader_2', 'stdClass').setPublic(true);
        container.register('translator.loader_2_locator', ServiceLocator)
            .setPublic(false)
            .addArgument({
                'translator.loader_2': new ServiceClosureArgument(new Reference('translator.loader_2')),
            });

        container.register('translator_2', Fixtures.StubbedTranslator)
            .setPublic(true)
            .addArgument(new Reference('translator.loader_2_locator'))
            .addMethodCall('addResource', [ 'db', new Reference('translator.loader_2'), 'nl' ]);

        // Two method calls
        container.register('translator.loader_3', 'stdClass').setPublic(true);
        container.register('translator.loader_3_locator', ServiceLocator)
            .setPublic(false)
            .addArgument({
                'translator.loader_3': new ServiceClosureArgument(new Reference('translator.loader_3')),
            });
        container.register('translator_3', Fixtures.StubbedTranslator)
            .setPublic(true)
            .addArgument(new Reference('translator.loader_3_locator'))
            .addMethodCall('addResource', [ 'db', new Reference('translator.loader_3'), 'nl' ])
            .addMethodCall('addResource', [ 'db', new Reference('translator.loader_3'), 'en' ]);

        nil.values = [ undefined ];
        container.register('bar_service', 'stdClass').setArguments([ new Reference('baz_service') ]).setPublic(true);
        container.register('baz_service', 'stdClass').setPublic(false);
        container.compile();

        const dumper = new JsDumper(container);

        expect(dumper.dump({ build_time: 1536621245 })['Containerkoj5E9d/ProjectContainer.js'])
            .to.be.equal(fs.readFileSync(path.join(fixturesPath, 'js', 'services-locator.js')).toString());
    });

    it('should handle service subscriber', () => {
        const container = new ContainerBuilder();
        container.register('foo_service', Fixtures.TestServiceSubscriber)
            .setPublic(true)
            .addArgument(new Reference(ContainerInterface))
            .addTag('container.service_subscriber')
        ;

        container.register(Fixtures.TestServiceSubscriber, Fixtures.TestServiceSubscriber).setPublic(true);
        container.register(Fixtures.CustomDefinition, Fixtures.CustomDefinition).setPublic(false);
        container.compile();

        const dumper = new JsDumper(container);

        expect(dumper.dump({ build_time: 1536621245 })['ContainereemDUTS/ProjectContainer.js'])
            .to.be.equal(fs.readFileSync(path.join(fixturesPath, 'js', 'services-subscriber.js')).toString());
    });

    it('should throw if service argument is a function', () => {
        const container = new ContainerBuilder();
        container.register('foo', 'Bar.Foo')
            .setPublic(true)
            .addArgument(function () { });
        container.compile();

        const dumper = new JsDumper(container);
        expect(() => dumper.dump()).to.throw(/Unable to dump a service container if a parameter is a function/);
    });

    it('should throw if service argument is a class', () => {
        const container = new ContainerBuilder();
        container.register('foo', 'Bar.Foo')
            .setPublic(true)
            .addArgument(Jymfony.Component.DependencyInjection.Container);
        container.compile();

        const dumper = new JsDumper(container);
        expect(() => dumper.dump()).to.throw(/Unable to dump a service container if a parameter is a function/);
    });

    it('should load inject and parameter annotations', () => {
        const container = require(path.join(fixturesPath, 'containers', 'annotated-container.js'));
        container.compile();

        const dumper = new JsDumper(container);
        expect(dumper.dump({ build_time: 1536621245 })['Container9d159V4/ProjectContainer.js'])
            .to.be.equal(fs.readFileSync(path.join(fixturesPath, 'js', 'annotated-services.js')).toString());
    });
});
<commit_msg>[Autoloader] normalize path when selectively clear cache<commit_after>const fs = require('fs');
const path = require('path');
const { expect } = require('chai');
require('../../fixtures/namespace');

const ContainerBuilder = Jymfony.Component.DependencyInjection.ContainerBuilder;
const ContainerInterface = Jymfony.Component.DependencyInjection.ContainerInterface;
const ServiceClosureArgument = Jymfony.Component.DependencyInjection.Argument.ServiceClosureArgument;
const Definition = Jymfony.Component.DependencyInjection.Definition;
const JsDumper = Jymfony.Component.DependencyInjection.Dumper.JsDumper;
const Fixtures = Jymfony.Component.DependencyInjection.Fixtures;
const ParameterBag = Jymfony.Component.DependencyInjection.ParameterBag.ParameterBag;
const Reference = Jymfony.Component.DependencyInjection.Reference;
const ServiceLocator = Jymfony.Component.DependencyInjection.ServiceLocator;
const Variable = Jymfony.Component.DependencyInjection.Variable;
const fixturesPath = path.join(__dirname, '..', '..', 'fixtures');

describe('[DependencyInjection] JsDumper', function () {
    it('dump', () => {
        const container = new ContainerBuilder();
        container.compile();

        const dumper = new JsDumper(container);
        expect(dumper.dump({ build_time: 1536621245 })).to.be.deep.equal({
            'ContainerkHWy2bx/ProjectContainer.js': fs.readFileSync(path.join(fixturesPath, 'js', 'services1.js')).toString(),
            'ProjectContainer.js': `
// This file has been auto-generated by the Jymfony Dependency Injection Component for internal use.
const ContainerkHWy2bx = require('./ContainerkHWy2bx/ProjectContainer.js');

module.exports = new ContainerkHWy2bx({
    'container.build_hash': 'kHWy2bx',
    'container.build_id': '1285839777',
    'container.build_time': 1536621245,
});

`,
        });
        expect(dumper.dump({ class_name: 'DumpedContainer', base_class: 'AbstractContainer' })['ContainerEexe5Ot/DumpedContainer.js'])
            .to.be.equal(fs.readFileSync(path.join(fixturesPath, 'js', 'services1-1.js')).toString());
    });

    it('dump optimization string', () => {
        const definition = new Definition();
        definition.setClass('Object');
        definition.setPublic(true);
        definition.addArgument({
            'only dot': '.',
            'concatenation as value': '+""+',
            'concatenation from the start value': '""+',
            '.': 'dot as a key',
            '+""+': 'concatenation as a key',
            '""+': 'concatenation from the start key',
            'optimize concatenation': 'string1%some_string%string2',
            'optimize concatenation with empty string': 'string1%empty_value%string2',
            'optimize concatenation from the start': '%empty_value%start',
            'optimize concatenation at the end': 'end%empty_value%',
        });

        const container = new ContainerBuilder();
        container.setResourceTracking(false);
        container.setDefinition('test', definition);
        container.setParameter('empty_value', '');
        container.setParameter('some_string', '-');
        container.compile();

        const dumper = new JsDumper(container);
        expect(dumper.dump({ build_time: 1536621245 })['ContainerDw9sVw7/ProjectContainer.js'])
            .to.be.equal(fs.readFileSync(path.join(fixturesPath, 'js', 'services10.js')).toString());
    });

    const tests = function * () {
        yield {'foo': new Definition('Object')};
        yield {'foo': new Reference('foo')};
        yield {'foo': new Variable('foo')};
    };
    let count = 0;

    for (const t of tests()) {
        it('should throw if invalid parameters are passed #'+count++, () => {
            const container = new ContainerBuilder(new ParameterBag(t));
            container.compile();

            const dumper = new JsDumper(container);
            expect(() => dumper.dump()).to.throw(InvalidArgumentException);
        });
    }

    it('should add parameters', () => {
        const container = require(path.join(fixturesPath, 'containers', 'container8.js'));
        container.compile();

        const dumper = new JsDumper(container);
        expect(dumper.dump({ build_time: 1536621245 })['ContainerbFqdJN6/ProjectContainer.js'])
            .to.be.equal(fs.readFileSync(path.join(fixturesPath, 'js', 'services8.js')).toString());
    });

    it('should add services', () => {
        const container = require(path.join(fixturesPath, 'containers', 'container9.js'));
        container.compile();

        const dumper = new JsDumper(container);
        expect(dumper.dump({ build_time: 1536621245 })['ContainerahGASul/ProjectContainer.js'])
            .to.be.equal(fs.readFileSync(path.join(fixturesPath, 'js', 'services9.js')).toString());
    });

    it('should handle env parameters', () => {
        const container = require(path.join(fixturesPath, 'containers', 'container-env.js'));
        container.compile();

        const dumper = new JsDumper(container);
        expect(dumper.dump({ build_time: 1536621245 })['Container15Bk9yA/ProjectContainer.js'])
            .to.be.equal(fs.readFileSync(path.join(fixturesPath, 'js', 'services-env.js')).toString());
    });

    it('should handle factories inclusion', () => {
        const container = require(path.join(fixturesPath, 'containers', 'container14.js'));
        container.compile();

        const dumper = new JsDumper(container);
        expect(dumper.dump({ build_time: 1536621245 })['ContainerHk8K7Jr/ProjectContainer.js'])
            .to.be.equal(fs.readFileSync(path.join(fixturesPath, 'js', 'services14.js')).toString());
    });

    it('should handle module inclusion', () => {
        const container = require(path.join(fixturesPath, 'containers', 'container15.js'));
        container.compile();

        const dumper = new JsDumper(container);
        expect(dumper.dump({ build_time: 1536621245 })['Containerhr7szKm/ProjectContainer.js'])
            .to.be.equal(fs.readFileSync(path.join(fixturesPath, 'js', 'services15.js')).toString());
    });

    it('should handle service locators', () => {
        const container = new ContainerBuilder();
        let nil;

        container.register('foo_service', ServiceLocator)
            .setPublic(true)
            .addArgument({
                'bar': new ServiceClosureArgument(new Reference('bar_service')),
                'baz': new ServiceClosureArgument(new Reference('baz_service', 'stdClass')),
                'nil': nil = new ServiceClosureArgument(new Reference('nil')),
            })
        ;

        // No method calls
        container.register('translator.loader_1', 'stdClass').setPublic(true);
        container.register('translator.loader_1_locator', ServiceLocator)
            .setPublic(false)
            .addArgument({
                'translator.loader_1': new ServiceClosureArgument(new Reference('translator.loader_1')),
            });
        container.register('translator_1', Fixtures.StubbedTranslator)
            .setPublic(true)
            .addArgument(new Reference('translator.loader_1_locator'));

        // One method calls
        container.register('translator.loader_2', 'stdClass').setPublic(true);
        container.register('translator.loader_2_locator', ServiceLocator)
            .setPublic(false)
            .addArgument({
                'translator.loader_2': new ServiceClosureArgument(new Reference('translator.loader_2')),
            });

        container.register('translator_2', Fixtures.StubbedTranslator)
            .setPublic(true)
            .addArgument(new Reference('translator.loader_2_locator'))
            .addMethodCall('addResource', [ 'db', new Reference('translator.loader_2'), 'nl' ]);

        // Two method calls
        container.register('translator.loader_3', 'stdClass').setPublic(true);
        container.register('translator.loader_3_locator', ServiceLocator)
            .setPublic(false)
            .addArgument({
                'translator.loader_3': new ServiceClosureArgument(new Reference('translator.loader_3')),
            });
        container.register('translator_3', Fixtures.StubbedTranslator)
            .setPublic(true)
            .addArgument(new Reference('translator.loader_3_locator'))
            .addMethodCall('addResource', [ 'db', new Reference('translator.loader_3'), 'nl' ])
            .addMethodCall('addResource', [ 'db', new Reference('translator.loader_3'), 'en' ]);

        nil.values = [ undefined ];
        container.register('bar_service', 'stdClass').setArguments([ new Reference('baz_service') ]).setPublic(true);
        container.register('baz_service', 'stdClass').setPublic(false);
        container.compile();

        const dumper = new JsDumper(container);

        expect(dumper.dump({ build_time: 1536621245 })['Containerkoj5E9d/ProjectContainer.js'])
            .to.be.equal(fs.readFileSync(path.join(fixturesPath, 'js', 'services-locator.js')).toString());
    });

    it('should handle service subscriber', () => {
        const container = new ContainerBuilder();
        container.register('foo_service', Fixtures.TestServiceSubscriber)
            .setPublic(true)
            .addArgument(new Reference(ContainerInterface))
            .addTag('container.service_subscriber')
        ;

        container.register(Fixtures.TestServiceSubscriber, Fixtures.TestServiceSubscriber).setPublic(true);
        container.register(Fixtures.CustomDefinition, Fixtures.CustomDefinition).setPublic(false);
        container.compile();

        const dumper = new JsDumper(container);

        expect(dumper.dump({ build_time: 1536621245 })['ContainereemDUTS/ProjectContainer.js'])
            .to.be.equal(fs.readFileSync(path.join(fixturesPath, 'js', 'services-subscriber.js')).toString());
    });

    it('should throw if service argument is a function', () => {
        const container = new ContainerBuilder();
        container.register('foo', 'Bar.Foo')
            .setPublic(true)
            .addArgument(function () { });
        container.compile();

        const dumper = new JsDumper(container);
        expect(() => dumper.dump()).to.throw(/Unable to dump a service container if a parameter is a function/);
    });

    it('should throw if service argument is a class', () => {
        const container = new ContainerBuilder();
        container.register('foo', 'Bar.Foo')
            .setPublic(true)
            .addArgument(Jymfony.Component.DependencyInjection.Container);
        container.compile();

        const dumper = new JsDumper(container);
        expect(() => dumper.dump()).to.throw(/Unable to dump a service container if a parameter is a function/);
    });

    it('should load inject and parameter annotations', __jymfony.Platform.hasPublicFieldSupport() ? () => {
        const container = require(path.join(fixturesPath, 'containers', 'annotated-container.js'));
        container.compile();

        const dumper = new JsDumper(container);
        expect(dumper.dump({ build_time: 1536621245 })['Container9d159V4/ProjectContainer.js'])
            .to.be.equal(fs.readFileSync(path.join(fixturesPath, 'js', 'annotated-services.js')).toString());
    } : undefined);
});
<|endoftext|>


<commit_before>import Ember from 'ember'
const {Application} = Ember
import config from './config/environment'
import Resolver from './resolver'
import loadInitializers from 'ember-load-initializers'

let App

Ember.MODEL_FACTORY_INJECTIONS = true

App = Application.extend({
  modulePrefix: config.modulePrefix,
  podModulePrefix: config.podModulePrefix,
  Resolver
})

loadInitializers(App, config.modulePrefix)

export default App
<commit_msg>Separate imports in dummy/app/app.js<commit_after>import Ember from 'ember'
const {Application} = Ember
import loadInitializers from 'ember-load-initializers'

import config from './config/environment'
import Resolver from './resolver'

let App

Ember.MODEL_FACTORY_INJECTIONS = true

App = Application.extend({
  modulePrefix: config.modulePrefix,
  podModulePrefix: config.podModulePrefix,
  Resolver
})

loadInitializers(App, config.modulePrefix)

export default App
<|endoftext|>


<commit_before>var editor;

$(document).ready(function() {

  // 构造上中右三个面板
  $('body').layout({
    resizerDblClickToggle: false,
    resizable: false,
    slidable: false,
    togglerLength_open: '100%',
    togglerLength_closed: '100%',
    north: {
      size: '1px', // 只是占位，真实大小由内容决定
      togglerTip_open: 'Hide Toolbar',
      togglerTip_closed: 'Show Toolbar'
    },
    east: {
      size: '50%',
      togglerTip_open: 'Hide Preview',
      togglerTip_closed: 'Show Preview',
      onresize: function() {
        editor.session.setUseWrapMode(false); // ACE的wrap貌似有问题，这里手动触发一下。
        editor.session.setUseWrapMode(true);
      }
    }
  });

  // 左侧编辑器
  editor = ace.edit("editor");
  editor.$blockScrolling = Infinity;
  editor.renderer.setShowPrintMargin(false);
  editor.session.setMode("ace/mode/markdown");
  editor.session.setUseWrapMode(true);
  editor.setFontSize('14px');
  editor.focus();

  // 编辑器的一些拓展方法
  editor.selection.smartRange = function() {
    var range = editor.selection.getRange();
    if(!range.isEmpty()) {
      return range; // 用户手动选中了一些文字，直接用这个
    }
    // 没有选中任何东西
    var _range = range; // 备份原始range
    range = editor.selection.getWordRange(range.start.row, range.start.column); // 当前单词的range
    if(editor.session.getTextRange(range).trim().length == 0) { // 选中的东西是空或者全空白
      range = _range; // 还使用原始的range
    }
    return range;
  };

  // 设置marked
  var renderer = new marked.Renderer();
  renderer.listitem = function(text) {
    if(!/^\[[ x]\]\s/.test(text)) {
      return marked.Renderer.prototype.listitem(text);
    }
    // 任务列表
    var checkbox = $('<input type="checkbox" class="taskbox" disabled="disabled"/>');
    if(/^\[x\]\s/.test(text)) { // 完成的任务列表
      checkbox.attr('checked', true);
    }
    return $(marked.Renderer.prototype.listitem(text.substring(4))).addClass('none-style').prepend(checkbox)[0].outerHTML;
  }
  marked.setOptions({
    renderer: renderer,
    gfm: true,
    tables: true,
    breaks: true,
    pedantic: false,
    sanitize: false,
    smartLists: true,
    smartypants: true
  });

  // 实时监听用户的编辑
  // todo: 改成underscore debounce方法来减少执行次数、提升性能？
  editor.session.on('change', function() {
    $('.markdown-body').html(marked(editor.session.getValue())); // 实时预览
    $('pre').addClass('prettyprint').addClass('linenums');
    prettyPrint(); // 语法高亮
  });

  // h1 - h6 heading
  $('.heading-icon').click(function() {
    var level = $(this).data('level');
    var p = editor.getCursorPosition();
    p.column += level + 1; // 光标位置会产生偏移
    editor.navigateLineStart();
    editor.insert('#'.repeat(level) + ' ');
    editor.moveCursorToPosition(p); // 恢复光标位置
    editor.focus();
  });

  // styling icons
  $('.styling-icon').click(function() {
    var modifier = $(this).data('modifier');
    var range = editor.selection.smartRange();
    var p = editor.getCursorPosition();
    p.column += modifier.length; // 光标位置会产生偏移
    editor.session.replace(range, modifier + editor.session.getTextRange(range) + modifier);
    editor.moveCursorToPosition(p); // 恢复光标位置
    editor.selection.clearSelection(); // 不知为何上一个语句会选中一部分文字
    editor.focus();
  });

  //

  $('#horizontal-rule').click(function() {
    var p = editor.getCursorPosition();
    if(p.column == 0) { // 光标在行首
      editor.selection.clearSelection();
      editor.insert('\n---\n');
    } else {
      editor.navigateLineEnd();
      editor.insert('\n\n---\n');
    }
    editor.focus();
  });

  // list icons
  $('.list-icon').click(function() {
    var prefix = $(this).data('prefix');
    var p = editor.getCursorPosition();
    p.column += prefix.length; // 光标位置会产生偏移
    var range = editor.selection.getRange();
    for(var i = range.start.row + 1; i < range.end.row + 2; i++) {
      editor.gotoLine(i);
      editor.insert(prefix);
    }
    editor.moveCursorToPosition(p); // 恢复光标位置
    editor.focus();
  });

  // link icon
  $('#link-icon').click(function() {
    var range = editor.selection.smartRange();
    var text = editor.session.getTextRange(range);
    if(text.trim().length == 0) {
      text = 'link description';
    }
    editor.session.replace(range, '[' + text +'](http://example.com/ "optional title")');
    editor.focus();
  });

  // image icon
  $('#image-icon').click(function() {
    editor.insert('![image description](http://example.com/example.png)');
    editor.focus();
  });

});
<commit_msg>Get image action correct<commit_after>var editor;

$(document).ready(function() {

  // 构造上中右三个面板
  $('body').layout({
    resizerDblClickToggle: false,
    resizable: false,
    slidable: false,
    togglerLength_open: '100%',
    togglerLength_closed: '100%',
    north: {
      size: '1px', // 只是占位，真实大小由内容决定
      togglerTip_open: 'Hide Toolbar',
      togglerTip_closed: 'Show Toolbar'
    },
    east: {
      size: '50%',
      togglerTip_open: 'Hide Preview',
      togglerTip_closed: 'Show Preview',
      onresize: function() {
        editor.session.setUseWrapMode(false); // ACE的wrap貌似有问题，这里手动触发一下。
        editor.session.setUseWrapMode(true);
      }
    }
  });

  // 左侧编辑器
  editor = ace.edit("editor");
  editor.$blockScrolling = Infinity;
  editor.renderer.setShowPrintMargin(false);
  editor.session.setMode("ace/mode/markdown");
  editor.session.setUseWrapMode(true);
  editor.setFontSize('14px');
  editor.focus();

  // 编辑器的一些拓展方法
  editor.selection.smartRange = function() {
    var range = editor.selection.getRange();
    if(!range.isEmpty()) {
      return range; // 用户手动选中了一些文字，直接用这个
    }
    // 没有选中任何东西
    var _range = range; // 备份原始range
    range = editor.selection.getWordRange(range.start.row, range.start.column); // 当前单词的range
    if(editor.session.getTextRange(range).trim().length == 0) { // 选中的东西是空或者全空白
      range = _range; // 还使用原始的range
    }
    return range;
  };

  // 设置marked
  var renderer = new marked.Renderer();
  renderer.listitem = function(text) {
    if(!/^\[[ x]\]\s/.test(text)) {
      return marked.Renderer.prototype.listitem(text);
    }
    // 任务列表
    var checkbox = $('<input type="checkbox" class="taskbox" disabled="disabled"/>');
    if(/^\[x\]\s/.test(text)) { // 完成的任务列表
      checkbox.attr('checked', true);
    }
    return $(marked.Renderer.prototype.listitem(text.substring(4))).addClass('none-style').prepend(checkbox)[0].outerHTML;
  }
  marked.setOptions({
    renderer: renderer,
    gfm: true,
    tables: true,
    breaks: true,
    pedantic: false,
    sanitize: false,
    smartLists: true,
    smartypants: true
  });

  // 实时监听用户的编辑
  // todo: 改成underscore debounce方法来减少执行次数、提升性能？
  editor.session.on('change', function() {
    $('.markdown-body').html(marked(editor.session.getValue())); // 实时预览
    $('pre').addClass('prettyprint').addClass('linenums');
    prettyPrint(); // 语法高亮
  });

  // h1 - h6 heading
  $('.heading-icon').click(function() {
    var level = $(this).data('level');
    var p = editor.getCursorPosition();
    p.column += level + 1; // 光标位置会产生偏移
    editor.navigateLineStart();
    editor.insert('#'.repeat(level) + ' ');
    editor.moveCursorToPosition(p); // 恢复光标位置
    editor.focus();
  });

  // styling icons
  $('.styling-icon').click(function() {
    var modifier = $(this).data('modifier');
    var range = editor.selection.smartRange();
    var p = editor.getCursorPosition();
    p.column += modifier.length; // 光标位置会产生偏移
    editor.session.replace(range, modifier + editor.session.getTextRange(range) + modifier);
    editor.moveCursorToPosition(p); // 恢复光标位置
    editor.selection.clearSelection(); // 不知为何上一个语句会选中一部分文字
    editor.focus();
  });

  //

  $('#horizontal-rule').click(function() {
    var p = editor.getCursorPosition();
    if(p.column == 0) { // 光标在行首
      editor.selection.clearSelection();
      editor.insert('\n---\n');
    } else {
      editor.navigateLineEnd();
      editor.insert('\n\n---\n');
    }
    editor.focus();
  });

  // list icons
  $('.list-icon').click(function() {
    var prefix = $(this).data('prefix');
    var p = editor.getCursorPosition();
    p.column += prefix.length; // 光标位置会产生偏移
    var range = editor.selection.getRange();
    for(var i = range.start.row + 1; i < range.end.row + 2; i++) {
      editor.gotoLine(i);
      editor.insert(prefix);
    }
    editor.moveCursorToPosition(p); // 恢复光标位置
    editor.focus();
  });

  // link icon
  $('#link-icon').click(function() {
    var range = editor.selection.smartRange();
    var text = editor.session.getTextRange(range);
    if(text.trim().length == 0) {
      text = 'link description';
    }
    editor.session.replace(range, '[' + text +'](http://example.com/ "optional title")');
    editor.focus();
  });

  // image icon
  $('#image-icon').click(function() {
    var range = editor.selection.getRange();
    var text = editor.session.getTextRange(range).trim();
    if(text.length == 0) {
      text = 'image description';
    }
    editor.session.replace(range, '![' + text + '](http://example.com/example.png)');
    editor.focus();
  });

});
<|endoftext|>


<commit_before>$(document).ready(function () {
    $("#progress").show();
    $.ajax("/entity/list", {
        data: "",
        contentType: 'application/json',
        type: 'GET',
        success: function (data) {
            if (data.code === 200) {
                jQuery.each(data.entities, function (index, value) {
                    var innerhtml = '';
                    innerhtml += "
";
                    innerhtml += "view_list";
                    innerhtml += "" + value + "";
                    innerhtml += "
";
                    innerhtml += "
";
                    innerhtml += "

option	value

";
                    innerhtml += "
";
                    innerhtml += "
";
                    innerhtml += "
";
                    innerhtml += "
";
                    innerhtml += "
";
                    innerhtml += "delete";
                    innerhtml += "info";
                    innerhtml += "
";
                    innerhtml += "
";
                    $("#info").append(innerhtml);

                    var handler = function () {
                        $('#' + value + ' > div.details').show();
                        $("#progress").show();
                        $.ajax("/entity/details?entityname=" + value, {
                            data: "",
                            contentType: 'application/json',
                            type: 'GET',
                            success: function (data) {
                                if (data.code === 200) {
                                    var innerinnerhtml = '';
                                    jQuery.each(data.details, function (detailsindex, detailsvalue) {
                                        innerinnerhtml += "
";
                                        innerinnerhtml += "";
                                        innerinnerhtml += detailsindex;
                                        innerinnerhtml += "	";
                                        innerinnerhtml += "";
                                        innerinnerhtml += detailsvalue;
                                        innerinnerhtml += "	";
                                        innerinnerhtml += "
";
                                    });

                                    $('#' + value + ' > div > table > tbody').html(innerinnerhtml);
                                    $('#' + value + ' > div.collapsible-header').unbind("click", handler);
                                    $("#progress").hide()
                                } else {
                                    $("#progress").hide()
                                    showAlert("Error in request: " + data.message);
                                }
                            }
                        });
                    };

                    $('#' + value + ' > div > a.btndelete').bind("click", function(){showAlert("Not implemented yet.")});
                    $('#' + value + ' > div > a.btninfo').bind("click", handler);

                    $('.collapsible').collapsible({
                        accordion: false
                    });
                });

            } else {
                showAlert("Error in request: " + data.message);
            }
            $("#progress").hide();
        }
        ,
        error: function () {
            $("#progress").hide()
            showAlert("Unspecified error in request.");
        }
    });
});<commit_msg>made overview a bit nicer<commit_after>$(document).ready(function () {
    $("#progress").show();
    $.ajax("/entity/list", {
        data: "",
        contentType: 'application/json',
        type: 'GET',
        success: function (data) {
            if (data.code === 200) {
                jQuery.each(data.entities, function (index, value) {
                    var innerhtml = '';
                    innerhtml += "
";
                    innerhtml += "" + value + "";
                    innerhtml += "
";
                    innerhtml += "delete";
                    innerhtml += "info";
                    innerhtml += "
";
                    innerhtml += "
";
                    innerhtml += "
";
                    innerhtml += "
";
                    innerhtml += "
";
                    innerhtml += "
";
                    innerhtml += "
";
                    innerhtml += "
";
                    $("#info").append(innerhtml);

                    var dropHandler = function(){
                        $("#progress").show();
                        $.ajax("/entity/drop?entityname=" + value, {
                            data: "",
                            contentType: 'application/json',
                            type: 'GET',
                            success: function (data) {
                                if (data.code === 200) {
                                    $("#" + value).hide();
                                    showAlert("Entity dropped");
                                    $("#progress").hide();
                                } else {
                                    $("#progress").hide();
                                    showAlert("Error in request: " + data.message);
                                }
                            }
                        });
                    }

                    var infoHandler = function () {
                        $('#' + value + ' > div.details').show();
                        $("#progress").show();
                        $.ajax("/entity/details?entityname=" + value, {
                            data: "",
                            contentType: 'application/json',
                            type: 'GET',
                            success: function (data) {
                                if (data.code === 200) {
                                    var innerinnerhtml = '';
                                    jQuery.each(data.details, function (detailsindex, detailsvalue) {
                                        innerinnerhtml += "
";
                                        innerinnerhtml += "";
                                        innerinnerhtml += detailsindex;
                                        innerinnerhtml += "	";
                                        innerinnerhtml += "";
                                        innerinnerhtml += detailsvalue;
                                        innerinnerhtml += "	";
                                        innerinnerhtml += "
";
                                    });

                                    $('#' + value + ' > div > table > tbody').html(innerinnerhtml);
                                    $('#' + value + ' > div.collapsible-header').unbind("click", infoHandler);
                                    $("#progress").hide()
                                } else {
                                    $("#progress").hide()
                                    showAlert("Error in request: " + data.message);
                                }
                            }
                        });
                    };

                    $('#' + value + ' > div > a.btndelete').bind("click", dropHandler);
                    $('#' + value + ' > div > a.btninfo').bind("click", infoHandler);
                });

            } else {
                showAlert("Error in request: " + data.message);
            }
            $("#progress").hide();
        }
        ,
        error: function () {
            $("#progress").hide()
            showAlert("Unspecified error in request.");
        }
    });
});<|endoftext|>


<commit_before>Subs = {}, remoteString = "DUMMY";

remote = DDP.connect('https://atmospherejs.com');

Packages = new Meteor.Collection('packages', {connection: remote});
Counts = new Meteor.Collection('counts', {connection: remote});

var keyLevels = [10, 25, 50, 100, 250, 500, 1000, 2500, 5000, 10000, 25000];
var heartbeatOutstanding = false
var localHost = (Meteor.absoluteUrl() === 'http://localhost:3000/');

function subFunc() {
	var subHolder = [], intervalHandle, subNum;
	var localIds = PackageTracker.find({}, {fields: {_id: true}}).map(function(doc) {return doc._id});
	Packages.find({_id: {$nin: localIds}}).forEach(function(doc) {
		var thisPackage = PackageTracker.findOne({name: doc.metadata.name});
		if (!thisPackage) {
			PackageTracker.insert({name: doc.metadata.name, description: doc.metadata.description, git: doc.metadata.git, installCount: 0});
			var tweetString = ("New Package: " + doc.metadata.name + ', ' + doc.metadata.description).slice(0,140);
			console.log(tweetString);
			if (!localHost) twitterSendTweet(tweetString);
		}
	});

	PackageTracker.find({}).forEach(function(doc) {
		var thisSub = remote.subscribe('packageInstalls', doc.name);
		subHolder.push({name: doc.name, sub: thisSub});
	});

	subNum = subHolder.length;
	console.log("Waiting for subscriptions on " + subNum.toString() + " packages");

	intervalHandle = Meteor.setInterval(function() {
		var thisPackage, oldPackage, thisCount, count = 0;
		for (var i = 0; i < subHolder.length; i++) {
			thisPackage = subHolder[i];
			if (thisPackage && thisPackage.sub.ready()) {
				thisCount = Counts.findOne({_id: 'package-installs-' + thisPackage.name}),
				oldPackage = PackageTracker.findOne({name: thisPackage.name});
				checkBounds(oldPackage, thisCount.count);
				console.log("Updating install count for " + thisPackage.name + " to " + (thisCount ? thisCount.count : 0).toString());
				PackageTracker.update({name: thisPackage.name}, {$set: {installCount: thisCount ? thisCount.count: 0}});
				thisPackage.sub.stop();
				subHolder[i] = null;
			}
			else if (thisPackage) count += 1;
		}
		if (!count) {
			console.log("Clearing Interval Job");
			Meteor.clearInterval(intervalHandle);
		}
		console.log("Still " + count.toString() + " packages left to check...");
	}, 5000);

};

function checkBounds(package, newCount) {
	if (!newCount || package.installCount === newCount) return false;
	else {
		keyLevels.forEach(function(level) {
			if (package.installCount < level && newCount >= level) {
				var tweetString = "Package '" + package.name + "' has reached " + level.toString() + " downloads! https://atmospherejs.com/package/" + package.name;
				console.log(tweetString);
				if (!localHost) twitterSendTweet(tweetString);
			}
		})
	}
}

Meteor.startup(function() {

	twitterCredentials = SecureData.findOne({name: "twitterCredentials"});
	remoteString = SecureData.findOne({name: 'remoteString'}) ? SecureData.findOne({name: 'remoteString'}).value : "DUMMY";

	Subs.packages = remote.subscribe('search', '*', 10000);

	if (!Meteor.settings.noUpdate) Meteor.setInterval(subFunc, 300000);

});

Meteor.methods({
	subFunc: function() {
		subFunc();
		return true;
	},
	showCounts: function() {
		return Counts.find().count();
	}
})<commit_msg>posts only start at 50 downloads<commit_after>Subs = {}, remoteString = "DUMMY";

remote = DDP.connect('https://atmospherejs.com');

Packages = new Meteor.Collection('packages', {connection: remote});
Counts = new Meteor.Collection('counts', {connection: remote});

var keyLevels = [50, 100, 250, 500, 1000, 2500, 5000, 10000, 25000];
var heartbeatOutstanding = false
var localHost = (Meteor.absoluteUrl() === 'http://localhost:3000/');

function subFunc() {
	var subHolder = [], intervalHandle, subNum;
	var localIds = PackageTracker.find({}, {fields: {_id: true}}).map(function(doc) {return doc._id});
	Packages.find({_id: {$nin: localIds}}).forEach(function(doc) {
		var thisPackage = PackageTracker.findOne({name: doc.metadata.name});
		if (!thisPackage) {
			PackageTracker.insert({name: doc.metadata.name, description: doc.metadata.description, git: doc.metadata.git, installCount: 0});
			var tweetString = ("New Package: " + doc.metadata.name + ', ' + doc.metadata.description).slice(0,140);
			console.log(tweetString);
			if (!localHost) twitterSendTweet(tweetString);
		}
	});

	PackageTracker.find({}).forEach(function(doc) {
		var thisSub = remote.subscribe('packageInstalls', doc.name);
		subHolder.push({name: doc.name, sub: thisSub});
	});

	subNum = subHolder.length;
	console.log("Waiting for subscriptions on " + subNum.toString() + " packages");

	intervalHandle = Meteor.setInterval(function() {
		var thisPackage, oldPackage, thisCount, count = 0;
		for (var i = 0; i < subHolder.length; i++) {
			thisPackage = subHolder[i];
			if (thisPackage && thisPackage.sub.ready()) {
				thisCount = Counts.findOne({_id: 'package-installs-' + thisPackage.name}),
				oldPackage = PackageTracker.findOne({name: thisPackage.name});
				checkBounds(oldPackage, thisCount.count);
				console.log("Updating install count for " + thisPackage.name + " to " + (thisCount ? thisCount.count : 0).toString());
				PackageTracker.update({name: thisPackage.name}, {$set: {installCount: thisCount ? thisCount.count: 0}});
				thisPackage.sub.stop();
				subHolder[i] = null;
			}
			else if (thisPackage) count += 1;
		}
		if (!count) {
			console.log("Clearing Interval Job");
			Meteor.clearInterval(intervalHandle);
		}
		console.log("Still " + count.toString() + " packages left to check...");
	}, 5000);

};

function checkBounds(package, newCount) {
	if (!newCount || package.installCount === newCount) return false;
	else {
		keyLevels.forEach(function(level) {
			if (package.installCount < level && newCount >= level) {
				var tweetString = "Package '" + package.name + "' has reached " + level.toString() + " downloads! https://atmospherejs.com/package/" + package.name;
				console.log(tweetString);
				if (!localHost) twitterSendTweet(tweetString);
			}
		})
	}
}

Meteor.startup(function() {

	twitterCredentials = SecureData.findOne({name: "twitterCredentials"});
	remoteString = SecureData.findOne({name: 'remoteString'}) ? SecureData.findOne({name: 'remoteString'}).value : "DUMMY";

	Subs.packages = remote.subscribe('search', '*', 10000);

	if (!Meteor.settings.noUpdate) Meteor.setInterval(subFunc, 300000);

});

Meteor.methods({
	subFunc: function() {
		subFunc();
		return true;
	},
	showCounts: function() {
		return Counts.find().count();
	}
})<|endoftext|>


<commit_before>var organizationSettings = {
    //The url that points to team city
    teamCityUrl: 'https://ci.travcorpservices.com',

    //Only show builds for branches that satisfy the predicate
    branchFilter: function(branch) {
        return (
            (branch.buildType.projectName != "Tour Itinerary Portal"
                || [
                    "aws-uat :: Create stack",
                    "aws-uat :: Deploy",
                    "aws-uat :: Delete stack"
                ].indexOf(branch.buildType.name) == -1) // Ignore TIP UAT, as the peering VPS infrastructure has not been set up
            && (branch.buildType.projectName != "Single Sign On"
                || [
                    "Run BDD tests on develop branch"
                ].indexOf(branch.buildType.name) == -1) // Ignore SSO E2E tests, as they are not reliable. Fix and unignore!
			&& (branch.buildType.projectName != "iTROPICS :: Nightly Integration Tests"
			|| [
				"Nightly Integration Tests"
			].indexOf(branch.buildType.name) == -1) // Ignore iTropics Nightly Integration tests until the AWS Deploy Dev environment is created properly
            && (branch.buildType.projectName != "iTROPICS"
                || [
                    "AWS Deploy QA",
					"AWS Deploy Dev"
                ].indexOf(branch.buildType.name) == -1) // Ignore iTropics QA and Dev deployment, as the environment is not ready.
            && (
                !branch.name /* No branch name is there for builds with no VCS roots at all, or when 'Branch specification' is left empty (e.g. when not using feature branches at all)*/
                || [
                    "<default>"/*This branch name is used for the default builds, when there are multiple VCS roots with different branches (e.g. source and config files are in different repos) */,
                    "master",
                    "refs/heads/master" /* Long Git 'refs/...' names are used when 'Branch specification' doesn't have a '*' and paretheses are also not being used to mark the 'Logical branch name' - see https://confluence.jetbrains.com/display/TCD9/Working+with+Feature+Branches#WorkingwithFeatureBranches-Logicalbranchname */,
                    "develop",
                    "refs/heads/develop"
                ].indexOf(branch.name) > -1
            )
        );
    },
};

var DefaultSettings = {
    //The main branch to show the master build status on the right hand panel on the screen. Leave empty to show the first failed one.
    mainBranch: '',

    //Proxy to handle the cross domain ajax request.
    // This will need to be hosted on the relevant server e.g. proxy-node.js on Node.js or proxy-aspnet.ashx on IIS
    // You could write your own proxy just so long as it is hosted form the same domain as the rest of the app
    proxy: '',

    // If your TeamCity is set up for guest access, you can just use it. Otherwise, the moment that tc-radiate sends first request to TC, TC will
    // ask the user for basic http credentials. Your browser may even offer you to save them.
    useTeamCityGuest: false,

    //How often to refresh the whole page in order to update the application (to get all the latest changes without having to come to the monitor and refresh).
    // Set to [0/undefined/null] to disable just this. Use enableAutoUpdate to disable this and any data updates.
    appUpdateIntervalMs: 1 /*hr*/ * 60 * 60 * 1000,

    //How often to call the TeamCity webservices and update the data on the screen
    dataUpdateIntervalMs: 30/*sec*/ * 1000,

    //How often to refresh the build image;
    buildImageIntervalMs: 15/*min*/ * 60 * 60 * 1000,

    //use this to stop the screen from updating automatically at all (disables both appUpdateIntervalMs and dataUpdateIntervalMs). You will need to manually refresh the page to get new data.
    enableAutoUpdate: true,

};

var Settings = _.clone(DefaultSettings);

var queryString = Utils.getObjectFromQueryString();
Settings.teamCityUrl = queryString.teamCityUrl || organizationSettings.teamCityUrl;

//Allow the settings to be overridden by querystring parameters
//(url parameters are currently only treated as strings)
_.defaults(Settings, queryString);

if (!queryString.teamCityUrl)
    history.replaceState(null, '', '?' + 'teamCityUrl=' + Settings.teamCityUrl + (location.search ? '&' + location.search.substr(1) : '')); // Put the TeamCity url to the querystring - a cheap way of advertising to savvy users that they can connect to a different instance, and that they can have each tab connected to a different one

if (Settings.teamCityUrl === organizationSettings.teamCityUrl) {
    _.defaults(Settings, organizationSettings);
}

var authType = Settings.useTeamCityGuest ? 'guestAuth' : 'httpAuth';

//----------------------
// TEAM CITY URLS
//----------------------

Settings.teamCityBaseUrl = Settings.proxy + Settings.teamCityUrl;
Settings.restApiBaseUrl = Settings.teamCityBaseUrl + '/' + authType + '/app/rest/9.1';

//The url for the list of build types (used for mapping the build id (e.g. bt11) to the name (e.g. Website Tests)
Settings.buildTypesUrl = Settings.restApiBaseUrl + '/buildTypes';

function getBuildStatusUrlForBranch(branchName) {
    return Settings.restApiBaseUrl + '/builds/branch:' + branchName + ',running:any,canceled:any';
}

function getBuildStatusUrlForBuildId(buildId) {
    return Settings.restApiBaseUrl + '/builds/id:' + buildId;
}

function getAppStorageKey(storageKey) {
    return Settings.teamCityUrl + '#' + storageKey; // Add the URL we're working against, so that it doesn't mix setting when this monitor is open from a local .html file (at least in Chrome, files in the same folder share their localStorage space).
}
<commit_msg>Removed booking engine deploy dev job from the build monitor as this is still being worked on<commit_after>var organizationSettings = {
    //The url that points to team city
    teamCityUrl: 'https://ci.travcorpservices.com',

    //Only show builds for branches that satisfy the predicate
    branchFilter: function(branch) {
        return (
            (branch.buildType.projectName != "Tour Itinerary Portal"
                || [
                    "aws-uat :: Create stack",
                    "aws-uat :: Deploy",
                    "aws-uat :: Delete stack"
                ].indexOf(branch.buildType.name) == -1) // Ignore TIP UAT, as the peering VPS infrastructure has not been set up
            && (branch.buildType.projectName != "Single Sign On"
                || [
                    "Run BDD tests on develop branch"
                ].indexOf(branch.buildType.name) == -1) // Ignore SSO E2E tests, as they are not reliable. Fix and unignore!
			&& (branch.buildType.projectName != "iTROPICS :: Nightly Integration Tests"
			|| [
				"Nightly Integration Tests"
			].indexOf(branch.buildType.name) == -1) // Ignore iTropics Nightly Integration tests until the AWS Deploy Dev environment is created properly
            && (branch.buildType.projectName != "iTROPICS"
                || [
                    "AWS Deploy QA",
					"AWS Deploy Dev",
                    "Booking Engine Deploy Dev"
                ].indexOf(branch.buildType.name) == -1) // Ignore iTropics QA and Dev deployment, as the environment is not ready.
            && (
                !branch.name /* No branch name is there for builds with no VCS roots at all, or when 'Branch specification' is left empty (e.g. when not using feature branches at all)*/
                || [
                    "<default>"/*This branch name is used for the default builds, when there are multiple VCS roots with different branches (e.g. source and config files are in different repos) */,
                    "master",
                    "refs/heads/master" /* Long Git 'refs/...' names are used when 'Branch specification' doesn't have a '*' and paretheses are also not being used to mark the 'Logical branch name' - see https://confluence.jetbrains.com/display/TCD9/Working+with+Feature+Branches#WorkingwithFeatureBranches-Logicalbranchname */,
                    "develop",
                    "refs/heads/develop"
                ].indexOf(branch.name) > -1
            )
        );
    },
};

var DefaultSettings = {
    //The main branch to show the master build status on the right hand panel on the screen. Leave empty to show the first failed one.
    mainBranch: '',

    //Proxy to handle the cross domain ajax request.
    // This will need to be hosted on the relevant server e.g. proxy-node.js on Node.js or proxy-aspnet.ashx on IIS
    // You could write your own proxy just so long as it is hosted form the same domain as the rest of the app
    proxy: '',

    // If your TeamCity is set up for guest access, you can just use it. Otherwise, the moment that tc-radiate sends first request to TC, TC will
    // ask the user for basic http credentials. Your browser may even offer you to save them.
    useTeamCityGuest: false,

    //How often to refresh the whole page in order to update the application (to get all the latest changes without having to come to the monitor and refresh).
    // Set to [0/undefined/null] to disable just this. Use enableAutoUpdate to disable this and any data updates.
    appUpdateIntervalMs: 1 /*hr*/ * 60 * 60 * 1000,

    //How often to call the TeamCity webservices and update the data on the screen
    dataUpdateIntervalMs: 30/*sec*/ * 1000,

    //How often to refresh the build image;
    buildImageIntervalMs: 15/*min*/ * 60 * 60 * 1000,

    //use this to stop the screen from updating automatically at all (disables both appUpdateIntervalMs and dataUpdateIntervalMs). You will need to manually refresh the page to get new data.
    enableAutoUpdate: true,

};

var Settings = _.clone(DefaultSettings);

var queryString = Utils.getObjectFromQueryString();
Settings.teamCityUrl = queryString.teamCityUrl || organizationSettings.teamCityUrl;

//Allow the settings to be overridden by querystring parameters
//(url parameters are currently only treated as strings)
_.defaults(Settings, queryString);

if (!queryString.teamCityUrl)
    history.replaceState(null, '', '?' + 'teamCityUrl=' + Settings.teamCityUrl + (location.search ? '&' + location.search.substr(1) : '')); // Put the TeamCity url to the querystring - a cheap way of advertising to savvy users that they can connect to a different instance, and that they can have each tab connected to a different one

if (Settings.teamCityUrl === organizationSettings.teamCityUrl) {
    _.defaults(Settings, organizationSettings);
}

var authType = Settings.useTeamCityGuest ? 'guestAuth' : 'httpAuth';

//----------------------
// TEAM CITY URLS
//----------------------

Settings.teamCityBaseUrl = Settings.proxy + Settings.teamCityUrl;
Settings.restApiBaseUrl = Settings.teamCityBaseUrl + '/' + authType + '/app/rest/9.1';

//The url for the list of build types (used for mapping the build id (e.g. bt11) to the name (e.g. Website Tests)
Settings.buildTypesUrl = Settings.restApiBaseUrl + '/buildTypes';

function getBuildStatusUrlForBranch(branchName) {
    return Settings.restApiBaseUrl + '/builds/branch:' + branchName + ',running:any,canceled:any';
}

function getBuildStatusUrlForBuildId(buildId) {
    return Settings.restApiBaseUrl + '/builds/id:' + buildId;
}

function getAppStorageKey(storageKey) {
    return Settings.teamCityUrl + '#' + storageKey; // Add the URL we're working against, so that it doesn't mix setting when this monitor is open from a local .html file (at least in Chrome, files in the same folder share their localStorage space).
}
<|endoftext|>


<commit_before>
$(document).ready(function() {

	$.getJSON('/backend/complex/' + complex['complex_accession'], function(data) {

	  	var complex_table = create_complex_table(data);

		if(data != null && data["graph"]["nodes"].length > 1) {

		    var graph = create_cytoscape_vis("cy", layout, graph_style, data["graph"], null, true, "complex");
		    create_cy_download_button(graph, "cy_download", complex['complex_accession'] + '_complex_graph')

		}
		else {
                    hide_section("diagram");
                }

		if (data != null && data["network_graph"]["nodes"].length > 1) {

		    var graph2 = create_cytoscape_vis("cy2", layout, graph_style, data["network_graph"], null, true, "complex_network");
		    create_cy_download_button(graph2, "cy2_download", complex['complex_accession'] + '_complex_network_graph')
		}
		else {
		    hide_section("network");
		}
	});

});

function create_complex_table(data) {
    var evidence = data['subunit'];
    var datatable = [];
    var subunits = {};
    for (var i = 0; i < evidence.length; i++) {
	datatable.push(complex_subunit_data_to_table(evidence[i]));
	subunits[evidence[i]["display_name"]] = true;
    }

    set_up_header(
		  "complex_table",
		  datatable.length,
		  "entry",
		  "entries",
		  Object.keys(subunits).length,
		  "subunit",
		  "subunits"
		  );

    var options = {};
    options["bPaginate"] = false;
    options["bDestroy"] = true;
    options["aoColumns"] = [
			  null,
			  null,
			  null
			  ];
  options["aaData"] = datatable;
  options["oLanguage"] = {
      sEmptyTable: "No subunits for this complex???."
  };

  return create_table("complex_table", options);

}

var graph_style = cytoscape.stylesheet()
    .selector('node')
    .css({
	    'content': 'data(name)',
	    'font-family': 'helvetica',
	    'font-size': 14,
	    'text-outline-width': 3,
	    'text-outline-color': '#888',
	    'text-valign': 'center',
	    'color': '#fff',
	    'width': 30,
	    'height': 30,
	    'border-color': '#fff'
        })
    .selector("node[type='small-molecule']")
    .css({
	    'text-outline-color': "#338AFF",
	})
    .selector("node[type='Gene']")
    .css({
            'text-outline-color': "#FF8933",
        })
    .selector("node[type='Go']")
    .css({
            'text-outline-color': "#A133FF",
        })
    .selector("node[type='Complex']")
    .css({
            'text-outline-color': "#33FFD4",
        })
    .selector('edge')
    .css({
	    'width': 2
        })
    .selector("node[sub_type='FOCUS']")
    .css({
	    'background-color': "#FF3391",
	    'text-outline-color': '#fff',
	    'color': '#fff'
        })
    .selector("edge[class_type = 'complex_go']")
    .css({
            'line-color': "#7233FF"
        })
    .selector("edge[class_type = 'complex_gene']")
    .css({
            'line-color': "#74FF33"
        })
    .selector("edge[class_type = 'complex']")
    .css({
	    'line-color': "#74FF33"
        });

var layout = {
    "name": "arbor",
    "liveUpdate": true,
    "ungrabifyWhileSimulating": true,
    "nodeMass":function(data) {
	if(data.sub_type == 'FOCUS') {
	    return 10;
	}
	else {
	    return 1;
	}
    }
};
<commit_msg>in progress<commit_after>
$(document).ready(function() {

	$.getJSON('/backend/complex/' + complex['complex_accession'], function(data) {

	  	var complex_table = create_complex_table(data);

		if(data != null && data["graph"]["nodes"].length > 1) {

		    var graph = create_cytoscape_vis("cy", layout, graph_style, data["graph"], null, true, "complex");
		    create_cy_download_button(graph, "cy_download", complex['complex_accession'] + '_subunit_graph')

		}
		else {
                    hide_section("diagram");
                }

		if (data != null && data["network_graph"]["nodes"].length > 1) {

		    var graph2 = create_cytoscape_vis("cy2", layout, graph_style, data["network_graph"], null, true, "complex_network");
		    create_cy_download_button(graph2, "cy2_download", complex['complex_accession'] + '_complex_network_graph')
		}
		else {
		    hide_section("network");
		}
	});

});

function create_complex_table(data) {
    var evidence = data['subunit'];
    var datatable = [];
    var subunits = {};
    for (var i = 0; i < evidence.length; i++) {
	datatable.push(complex_subunit_data_to_table(evidence[i]));
	subunits[evidence[i]["display_name"]] = true;
    }

    set_up_header(
		  "complex_table",
		  datatable.length,
		  "entry",
		  "entries",
		  Object.keys(subunits).length,
		  "subunit",
		  "subunits"
		  );

    var options = {};
    options["bPaginate"] = false;
    options["bDestroy"] = true;
    options["aoColumns"] = [
			  null,
			  null,
			  null
			  ];
  options["aaData"] = datatable;
  options["oLanguage"] = {
      sEmptyTable: "No subunits for this complex???."
  };

  return create_table("complex_table", options);

}

var graph_style = cytoscape.stylesheet()
    .selector('node')
    .css({
	    'content': 'data(name)',
	    'font-family': 'helvetica',
	    'font-size': 14,
	    'text-outline-width': 3,
	    'text-outline-color': '#888',
	    'text-valign': 'center',
	    'color': '#fff',
	    'width': 30,
	    'height': 30,
	    'border-color': '#fff'
        })
    .selector("node[type='small-molecule']")
    .css({
	    'text-outline-color': "#338AFF",
	})
    .selector("node[type='Gene']")
    .css({
            'text-outline-color': "#FF8933",
        })
    .selector("node[type='Go']")
    .css({
            'text-outline-color': "#A133FF",
        })
    .selector("node[type='Complex']")
    .css({
            'text-outline-color': "#33FFD4",
        })
    .selector('edge')
    .css({
	    'width': 2
        })
    .selector("node[sub_type='FOCUS']")
    .css({
	    'background-color': "#FF3391",
	    'text-outline-color': '#fff',
	    'color': '#fff'
        })
    .selector("edge[class_type = 'complex_go']")
    .css({
            'line-color': "#7233FF"
        })
    .selector("edge[class_type = 'complex_gene']")
    .css({
            'line-color': "#74FF33"
        })
    .selector("edge[class_type = 'complex']")
    .css({
	    'line-color': "#74FF33"
        });

var layout = {
    "name": "arbor",
    "liveUpdate": true,
    "ungrabifyWhileSimulating": true,
    "nodeMass":function(data) {
	if(data.sub_type == 'FOCUS') {
	    return 10;
	}
	else {
	    return 1;
	}
    }
};
<|endoftext|>


<commit_before>angular.module('StackWho')

  .controller('AppController', ['$scope', '$http', '$location', 'config', function($scope, $http, $location, config) {

    'use strict';

    var paramsToCommand = function(params){
      var command = '';

      if (params.cmd){
        command += params.cmd;
        return command;
      }

      if (params.location){
        command += 'location: ' + params.location
      }

      if(params.answers){
        command += ' answers: ' + params.answers;
      }

      return command;
    };

    $scope.searchString = paramsToCommand($location.search());
    $scope.searchStringTags = '';
    $scope.displayUsers = [];

    $scope.createQueryLink = function(){
      var cmd = $scope.searchString.replace(/\s/g, '%20');
      return encodeURIComponent('http://stackwho.herokuapp.com/#/?cmd=' + cmd);
    };

    var server = config.backendEndpoint + '/users';

    var safeApply = function (fn) {
      ($scope.$$phase || $scope.$root.$$phase) ? fn() : $scope.$apply(fn);
    };

    var queryBackend = function(){

      var searchParams = {
        searchString: $scope.searchString
      };

      var observable = Rx.Observable.fromDeferred(
        $http({
          url: server,
          method: 'GET',
          params: searchParams
      }))
      .select(function(response){
        return response.data.users;
      });

      safeApply();

      return observable;
    };

    //This might look scary at first glance.
    //However this code deals with
    //1. throttleing user input to not hammer our API on every keystroke
    //2. not requesting data that is already there
    //3. not getting out of order results
    Rx.Observable
    .fromScope($scope, 'searchString')
    .where(function(term){
      return term && term.length > 0;
    })
    .throttle(400)
    .distinctUntilChanged()
    .doAction(function(){
      $scope.displayUsers = [];
      $scope.loading = true;
    })
    .select(queryBackend)
    .switchLatest()
    .subscribe(function(data){
      safeApply(function(){
        $scope.loading = false;
        $scope.displayUsers = data;
      });
    });

  }]);

<commit_msg>fix(AppController): remove unneeded safeApply call<commit_after>angular.module('StackWho')

  .controller('AppController', ['$scope', '$http', '$location', 'config', function($scope, $http, $location, config) {

    'use strict';

    var paramsToCommand = function(params){
      var command = '';

      if (params.cmd){
        command += params.cmd;
        return command;
      }

      if (params.location){
        command += 'location: ' + params.location
      }

      if(params.answers){
        command += ' answers: ' + params.answers;
      }

      return command;
    };

    $scope.searchString = paramsToCommand($location.search());
    $scope.searchStringTags = '';
    $scope.displayUsers = [];

    $scope.createQueryLink = function(){
      var cmd = $scope.searchString.replace(/\s/g, '%20');
      return encodeURIComponent('http://stackwho.herokuapp.com/#/?cmd=' + cmd);
    };

    var server = config.backendEndpoint + '/users';

    var safeApply = function (fn) {
      ($scope.$$phase || $scope.$root.$$phase) ? fn() : $scope.$apply(fn);
    };

    var queryBackend = function(){

      var searchParams = {
        searchString: $scope.searchString
      };

      var observable = Rx.Observable.fromDeferred(
        $http({
          url: server,
          method: 'GET',
          params: searchParams
      }))
      .select(function(response){
        return response.data.users;
      });

      return observable;
    };

    //This might look scary at first glance.
    //However this code deals with
    //1. throttleing user input to not hammer our API on every keystroke
    //2. not requesting data that is already there
    //3. not getting out of order results
    Rx.Observable
    .fromScope($scope, 'searchString')
    .where(function(term){
      return term && term.length > 0;
    })
    .throttle(400)
    .distinctUntilChanged()
    .doAction(function(){
      $scope.displayUsers = [];
      $scope.loading = true;
    })
    .select(queryBackend)
    .switchLatest()
    .subscribe(function(data){
      safeApply(function(){
        $scope.loading = false;
        $scope.displayUsers = data;
      });
    });

  }]);

<|endoftext|>


<commit_before>'use strict';

var version = exports;

var fs = require('fs');
var node_path = require('path');

version.run = function(options, callback) {
  var root = options.root;
  var package_json = node_path.join(root, 'package.json');
  var logger = this.logger;

  fs.readFile(package_json, function(err, content) {
    if (err) {
      return callback({
        code: 'EREADPKG',
        message: 'fails to read "' + package_json + '", err: ' + err.stack,
        data: {
          file: package_json,
          error: err
        }
      });
    }

    var pkg;

    try {
      pkg = JSON.parse(content.toString());

    } catch (e) {
      return callback({
        code: 'EPARSEJSON',
        message: 'fails to parse package.json, path "' + package_json + '"',
        data: {
          file: package_json,
          error: e
        }
      });
    }

    var version = pkg.version;

    if (!version) {
      return callback({
        code: 'ENOVERSION',
        message: 'No version found in package.json, "' + package_json + '"',
        data: {
          file: package_json
        }
      });
    }

    logger.info(version);

    callback(null);
  });
};<commit_msg>use package-version to get version; #21<commit_after>'use strict';

var version = exports;

var fs = require('fs');
var node_path = require('path');
var package_version = require('package-version');

version.run = function(options, callback) {
  var logger = this.logger;
  package_version(options.root, function (err, v) {
    if (err) {
      return callback(err);
    }

    logger.info(v);
    callback(null);
  });
};<|endoftext|>


<commit_before>import FEATURE_TOGGLE from '../../src/feature-toggle';

export default class Particle {

    constructor(settings) {
        this.x = settings.x || 0;
        this.y = settings.y || 0;
        this.vx = (Math.cos(settings.direction) * settings.speed) || 0;
        this.vy = (Math.sin(settings.direction) * settings.speed) || 0;
        this.gravity = settings.gravity || 0;
        this.mass = settings.mass || 1;
        this.radius = settings.radius || settings.mass * 0.87;
        this.friction = settings.friction || 1;
        this.springs = [];
        this.gravitations = [];

        this.shape = settings.shape || "circle";
        this.mapperRegions = settings.mapperRegions || {};
        this.color = settings.color || "#000000";
        this.points = settings.points || [];
        this.boxBounce = settings.boxBounce || false;
    }

    /*
     *  Updates the state of the particle
     */
    update() {
        this.handleSprings();
        this.handleGravitations();
        this.vy += this.gravity;
        this.vx *= this.friction;
        this.vy *= this.friction;
        this.x += this.vx;
        this.y += this.vy;

        if (this.boxBounce) {
          this.checkBorders(this.boxBounce.w, this.boxBounce.h);
        }
    }

    /*
     *  Gets the length of the velocity vector, which equals to the hypotenuse
     */
    getSpeed() {
        return Math.sqrt(this.vx * this.vx + this.vy * this.vy);
    }

    /*
     *  Using the actual Velocity vector's angle, sets a new length for it
     */
    setSpeed(speed) {
        let heading = this.getHeading();
        this.vx = Math.cos(heading) * speed;
        this.vy = Math.sin(heading) * speed;
    }

    /*
     *  Gets the angle direction of the velocity vector
     */
    getHeading() {
        return Math.atan2(this.vy, this.vx);
    }

    /*
     *  Changes the Velocity vector's angle and recalculate coordinates
     */
    setHeading(heading) {
        let speed = this.getSpeed();
        this.vx = Math.cos(heading) * speed;
        this.vy = Math.sin(heading) * speed;
    }

    /*
     *  Sums to the Velocity vector x and y values
     */
    accelerate(x, y) {
        this.vx += x;
        this.vy += y;
    }

    /*
    *  Bounce if the particle hits the box (i.e. screen) borders
    */
    checkBorders(width, height) {
      if (this.x + this.radius >= width) {
        this.x = width - this.radius;
        this.vx *=  -1;
      } else if (this.x - this.radius <= 0) {
        this.x = this.radius;
        this.vx *= -1;
      }

      if (this.y + this.radius >= height) {
        this.y = height - this.radius;
        this.vy *=  -1;
      } else if (this.y - this.radius <= 0) {
        this.y = this.radius;
        this.vy *= -1;
      }
    }

    /*
     *  Calculates the angle between this particle and 'p2'
     */
    angleTo(p2) {
        return Math.atan2(p2.y - this.y, p2.x - this.x);
    }

    /*
     *  Calculates the distance to a given particle
     */
    distanceTo(p) {
        let dx = p.x - this.x;
        let dy = p.y - this.y;
        return Math.sqrt(dx * dx + dy * dy);
    }

    /*
     *  Calculates and applies a gravitation vector to a given particle
     */
    gravitateTo(p) {
        let dx = p.x - this.x;
        let dy = p.y - this.y;
        let distSQ = (dx * dx) + (dy * dy);
        let dist = Math.sqrt(distSQ);
        let force = (p.mass) / distSQ; // Force = mass / square of the distance
        /*
        cos * hypotenuse = opposite side || cos = opposite side / hypotenuse
        sin * hypotenuse = adjacent side || sin = adjacent side / hypotenuse

        That being said, we can optimize this:
        let angle = this.angleTo(p);
        let ax = Math.cos(angle) * force;
        let ay = Math.sin(angle) * force;

        And save three trigo functions
        */
        let ax = (dx / dist) * force;
        let ay = (dy / dist) * force;

        this.vx += ax;
        this.vy += ay;
    }

    /*
     *  Registers a particle to gravitate to
     */
    addGravitation(p) {
        this.removeGravitation(p);
        this.gravitations.push(p);
    }

    /*
     *  Unregisters a gravitation particle
     */
    removeGravitation(p) {
        let length = this.gravitations.length;
        for (let i=0; i<length; i++){
            if (this.gravitations[i] === p) {
                this.gravitations.slice(i, 1);
                return true;
            }
        }
    }

    /*
     *  Gravitates to each registered gravitation particle
     */
    handleGravitations() {
        let length = this.gravitations.length;
        for (let i=0; i<length; i++){
            this.gravitateTo(this.gravitations[i]);
        }
    }

    /*
     *  Calculates and applies a spring vector to a given point
     */
    springTo(point, k, length) {
        let dx = point.x - this.x;
        let dy = point.y - this.y;
        let distance = Math.sqrt(dx * dx + dy * dy);
        let force = (distance - length || 0) * k;
        // Instead of getting cos / sin of angle, divide sides by hypotenuse
        this.vx += (dx / distance) * force;
        this.vy += (dy / distance) * force;
    }

    /*
     *  Registers a new spring point
     */
    addSpring(point, k, length) {
        this.removeSpring(point);
        this.springs.push({
            point: point,
            k: k,
            length: length || 0
        });
    }

    /*
     *  Unregisters a spring point
     */
    removeSpring(point) {
        let length = this.springs.length;
        for (let i=0; i<length; i++){
            if (this.springs[i].point === point) {
                this.springs.splice(i, 1);
                return;
            }
        }
    }

    /*
     *  Springs to each registered spring point
     */
    handleSprings() {
        let length = this.springs.length;
        for (let i=0; i<length; i++){
            let spring = this.springs[i];
            this.springTo(spring.point, spring.k, spring.length);
        }
    }
}
<commit_msg>decouple Particle.js from Collisioner Project: removing unnecessary code<commit_after>import FEATURE_TOGGLE from '../../src/feature-toggle';

export default class Particle {

  /*
   *   Pass 'boxBounce' as { w: <with>, h: <height> } to make particle bounce inside a box
   *
   **/
    constructor(settings) {
        this.x = settings.x || 0;
        this.y = settings.y || 0;
        this.vx = (Math.cos(settings.direction) * settings.speed) || 0;
        this.vy = (Math.sin(settings.direction) * settings.speed) || 0;
        this.gravity = settings.gravity || 0;
        this.mass = settings.mass || 1;
        this.radius = settings.radius || settings.mass * 0.87;
        this.friction = settings.friction || 1;
        this.springs = [];
        this.gravitations = [];

        this.color = settings.color || "#000000";
        this.boxBounce = settings.boxBounce || false;
    }

    /*
     *  Updates the state of the particle
     */
    update() {
        this.handleSprings();
        this.handleGravitations();
        this.vy += this.gravity;
        this.vx *= this.friction;
        this.vy *= this.friction;
        this.x += this.vx;
        this.y += this.vy;

        if (this.boxBounce) {
          this.checkBorders(this.boxBounce.w, this.boxBounce.h);
        }
    }

    /*
     *  Gets the length of the velocity vector, which equals to the hypotenuse
     */
    getSpeed() {
        return Math.sqrt(this.vx * this.vx + this.vy * this.vy);
    }

    /*
     *  Using the actual Velocity vector's angle, sets a new length for it
     */
    setSpeed(speed) {
        let heading = this.getHeading();
        this.vx = Math.cos(heading) * speed;
        this.vy = Math.sin(heading) * speed;
    }

    /*
     *  Gets the angle direction of the velocity vector
     */
    getHeading() {
        return Math.atan2(this.vy, this.vx);
    }

    /*
     *  Changes the Velocity vector's angle and recalculate coordinates
     */
    setHeading(heading) {
        let speed = this.getSpeed();
        this.vx = Math.cos(heading) * speed;
        this.vy = Math.sin(heading) * speed;
    }

    /*
     *  Sums to the Velocity vector x and y values
     */
    accelerate(x, y) {
        this.vx += x;
        this.vy += y;
    }

    /*
    *  Bounce if the particle hits the box (i.e. screen) borders
    */
    checkBorders(width, height) {
      if (this.x + this.radius >= width) {
        this.x = width - this.radius;
        this.vx *=  -1;
      } else if (this.x - this.radius <= 0) {
        this.x = this.radius;
        this.vx *= -1;
      }

      if (this.y + this.radius >= height) {
        this.y = height - this.radius;
        this.vy *=  -1;
      } else if (this.y - this.radius <= 0) {
        this.y = this.radius;
        this.vy *= -1;
      }
    }

    /*
     *  Calculates the angle between this particle and 'p2'
     */
    angleTo(p2) {
        return Math.atan2(p2.y - this.y, p2.x - this.x);
    }

    /*
     *  Calculates the distance to a given particle
     */
    distanceTo(p) {
        let dx = p.x - this.x;
        let dy = p.y - this.y;
        return Math.sqrt(dx * dx + dy * dy);
    }

    /*
     *  Calculates and applies a gravitation vector to a given particle
     */
    gravitateTo(p) {
        let dx = p.x - this.x;
        let dy = p.y - this.y;
        let distSQ = (dx * dx) + (dy * dy);
        let dist = Math.sqrt(distSQ);
        let force = (p.mass) / distSQ; // Force = mass / square of the distance
        /*
        cos * hypotenuse = opposite side || cos = opposite side / hypotenuse
        sin * hypotenuse = adjacent side || sin = adjacent side / hypotenuse

        That being said, we can optimize this:
        let angle = this.angleTo(p);
        let ax = Math.cos(angle) * force;
        let ay = Math.sin(angle) * force;

        And save three trigo functions
        */
        let ax = (dx / dist) * force;
        let ay = (dy / dist) * force;

        this.vx += ax;
        this.vy += ay;
    }

    /*
     *  Registers a particle to gravitate to
     */
    addGravitation(p) {
        this.removeGravitation(p);
        this.gravitations.push(p);
    }

    /*
     *  Unregisters a gravitation particle
     */
    removeGravitation(p) {
        let length = this.gravitations.length;
        for (let i=0; i<length; i++){
            if (this.gravitations[i] === p) {
                this.gravitations.slice(i, 1);
                return true;
            }
        }
    }

    /*
     *  Gravitates to each registered gravitation particle
     */
    handleGravitations() {
        let length = this.gravitations.length;
        for (let i=0; i<length; i++){
            this.gravitateTo(this.gravitations[i]);
        }
    }

    /*
     *  Calculates and applies a spring vector to a given point
     */
    springTo(point, k, length) {
        let dx = point.x - this.x;
        let dy = point.y - this.y;
        let distance = Math.sqrt(dx * dx + dy * dy);
        let force = (distance - length || 0) * k;
        // Instead of getting cos / sin of angle, divide sides by hypotenuse
        this.vx += (dx / distance) * force;
        this.vy += (dy / distance) * force;
    }

    /*
     *  Registers a new spring point
     */
    addSpring(point, k, length) {
        this.removeSpring(point);
        this.springs.push({
            point: point,
            k: k,
            length: length || 0
        });
    }

    /*
     *  Unregisters a spring point
     */
    removeSpring(point) {
        let length = this.springs.length;
        for (let i=0; i<length; i++){
            if (this.springs[i].point === point) {
                this.springs.splice(i, 1);
                return;
            }
        }
    }

    /*
     *  Springs to each registered spring point
     */
    handleSprings() {
        let length = this.springs.length;
        for (let i=0; i<length; i++){
            let spring = this.springs[i];
            this.springTo(spring.point, spring.k, spring.length);
        }
    }
}
<|endoftext|>