<commit_before>// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

const path = require('path');
const glob = require('glob');
const fs = require('fs');

// false by default
const DEBUG_ENABLED = !!process.env['DEBUG'];
const COVERAGE_ENABLED = !!process.env['COVERAGE'];

// true by default
const TEXT_COVERAGE_ENABLED = COVERAGE_ENABLED && !process.env['NO_TEXT_COVERAGE'];

const GEN_DIRECTORY = path.join(__dirname, '..', '..');
const ROOT_DIRECTORY = path.join(GEN_DIRECTORY, '..', '..', '..');
const browsers = DEBUG_ENABLED ? ['Chrome'] : ['ChromeHeadless'];

const coverageReporters = COVERAGE_ENABLED ? ['coverage'] : [];
const coveragePreprocessors = COVERAGE_ENABLED ? ['coverage'] : [];
const commonIstanbulReporters = [{type: 'html'}, {type: 'json-summary'}];
const istanbulReportOutputs =
    TEXT_COVERAGE_ENABLED ? [{type: 'text'}, ...commonIstanbulReporters] : commonIstanbulReporters;

const UNIT_TESTS_ROOT_FOLDER = path.join(ROOT_DIRECTORY, 'test', 'unittests');
const UNIT_TESTS_FOLDERS = [
  path.join(UNIT_TESTS_ROOT_FOLDER, 'front_end'),
  path.join(UNIT_TESTS_ROOT_FOLDER, 'inspector_overlay'),
];
const TEST_SOURCES = UNIT_TESTS_FOLDERS.map(folder => path.join(folder, '**/*.ts'));

// To make sure that any leftover JavaScript files (e.g. that were outputs from now-removed tests)
// aren't incorrectly included, we glob for the TypeScript files instead and use that
// to instruct Mocha to run the output JavaScript file.
const TEST_FILES =
    TEST_SOURCES
        .map(source => {
          return glob.sync(source).map(fileName => {
            const jsFile = fileName.replace(/\.ts$/, '.js');
            const generatedJsFile = path.join(__dirname, path.relative(UNIT_TESTS_ROOT_FOLDER, jsFile));
            if (!fs.existsSync(generatedJsFile)) {
              throw new Error(`Test file ${fileName} is not included in a BUILD.gn and therefore will not be run.`);
            }

            return generatedJsFile;
          });
        })
        .flat();

const TEST_FILES_SOURCE_MAPS = TEST_FILES.map(fileName => `${fileName}.map`);

module.exports = function(config) {
  const options = {
    basePath: ROOT_DIRECTORY,

    files: [
      ...TEST_FILES.map(pattern => ({pattern, type: 'module'})),
      ...TEST_FILES_SOURCE_MAPS.map(pattern => ({pattern, served: true, included: false})),
      ...TEST_SOURCES.map(source => ({pattern: source, served: true, included: false})),
      {pattern: path.join(GEN_DIRECTORY, 'front_end/Images/*.{svg,png}'), served: true, included: false},
      {pattern: path.join(GEN_DIRECTORY, 'front_end/**/*.css'), served: true, included: false},
      {pattern: path.join(GEN_DIRECTORY, 'front_end/**/*.js'), served: true, included: false},
      {pattern: path.join(GEN_DIRECTORY, 'front_end/**/*.js.map'), served: true, included: false},
      {pattern: path.join(GEN_DIRECTORY, 'front_end/**/*.mjs'), served: true, included: false},
      {pattern: path.join(GEN_DIRECTORY, 'front_end/**/*.mjs.map'), served: true, included: false},
      {pattern: path.join(ROOT_DIRECTORY, 'front_end/**/*.ts'), served: true, included: false},
      {pattern: path.join(ROOT_DIRECTORY, 'inspector_overlay/**/*.ts'), served: true, included: false},
      {pattern: path.join(GEN_DIRECTORY, 'inspector_overlay/**/*.js'), served: true, included: false},
      {pattern: path.join(GEN_DIRECTORY, 'inspector_overlay/**/*.js.map'), served: true, included: false},
    ],

    reporters: [
      'dots',
      ...coverageReporters,
    ],

    browsers,

    frameworks: ['mocha', 'chai'],

    client: {
      /*
       * Passed through to the client via __karma__ because test_setup.ts
       * preloads some CSS files and it needs to know the target directory to do
       * so.
       */
      targetDir: path.relative(process.cwd(), GEN_DIRECTORY),
    },

    plugins: [
      require('karma-chrome-launcher'),
      require('karma-mocha'),
      require('karma-chai'),
      require('karma-sourcemap-loader'),
      require('karma-coverage'),
    ],

    preprocessors: {
      '**/*.{js,mjs}': ['sourcemap'],
      [path.join(GEN_DIRECTORY, 'front_end/**/*.{js,mjs}')]: [...coveragePreprocessors],
    },

    proxies: {'/Images': 'front_end/Images'},

    coverageReporter: {
      dir: 'karma-coverage',
      reporters: istanbulReportOutputs,
    },

    singleRun: !DEBUG_ENABLED,
  };

  config.set(options);
};
<commit_msg>Remove unnecessary file pattern in karma.conf.js<commit_after>// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

const path = require('path');
const glob = require('glob');
const fs = require('fs');

// false by default
const DEBUG_ENABLED = !!process.env['DEBUG'];
const COVERAGE_ENABLED = !!process.env['COVERAGE'];

// true by default
const TEXT_COVERAGE_ENABLED = COVERAGE_ENABLED && !process.env['NO_TEXT_COVERAGE'];

const GEN_DIRECTORY = path.join(__dirname, '..', '..');
const ROOT_DIRECTORY = path.join(GEN_DIRECTORY, '..', '..', '..');
const browsers = DEBUG_ENABLED ? ['Chrome'] : ['ChromeHeadless'];

const coverageReporters = COVERAGE_ENABLED ? ['coverage'] : [];
const coveragePreprocessors = COVERAGE_ENABLED ? ['coverage'] : [];
const commonIstanbulReporters = [{type: 'html'}, {type: 'json-summary'}];
const istanbulReportOutputs =
    TEXT_COVERAGE_ENABLED ? [{type: 'text'}, ...commonIstanbulReporters] : commonIstanbulReporters;

const UNIT_TESTS_ROOT_FOLDER = path.join(ROOT_DIRECTORY, 'test', 'unittests');
const UNIT_TESTS_FOLDERS = [
  path.join(UNIT_TESTS_ROOT_FOLDER, 'front_end'),
  path.join(UNIT_TESTS_ROOT_FOLDER, 'inspector_overlay'),
];
const TEST_SOURCES = UNIT_TESTS_FOLDERS.map(folder => path.join(folder, '**/*.ts'));

// To make sure that any leftover JavaScript files (e.g. that were outputs from now-removed tests)
// aren't incorrectly included, we glob for the TypeScript files instead and use that
// to instruct Mocha to run the output JavaScript file.
const TEST_FILES =
    TEST_SOURCES
        .map(source => {
          return glob.sync(source).map(fileName => {
            const jsFile = fileName.replace(/\.ts$/, '.js');
            const generatedJsFile = path.join(__dirname, path.relative(UNIT_TESTS_ROOT_FOLDER, jsFile));
            if (!fs.existsSync(generatedJsFile)) {
              throw new Error(`Test file ${fileName} is not included in a BUILD.gn and therefore will not be run.`);
            }

            return generatedJsFile;
          });
        })
        .flat();

const TEST_FILES_SOURCE_MAPS = TEST_FILES.map(fileName => `${fileName}.map`);

module.exports = function(config) {
  const options = {
    basePath: ROOT_DIRECTORY,

    files: [
      ...TEST_FILES.map(pattern => ({pattern, type: 'module'})),
      ...TEST_FILES_SOURCE_MAPS.map(pattern => ({pattern, served: true, included: false})),
      ...TEST_SOURCES.map(source => ({pattern: source, served: true, included: false})),
      {pattern: path.join(GEN_DIRECTORY, 'front_end/Images/*.{svg,png}'), served: true, included: false},
      {pattern: path.join(GEN_DIRECTORY, 'front_end/**/*.css'), served: true, included: false},
      {pattern: path.join(GEN_DIRECTORY, 'front_end/**/*.js'), served: true, included: false},
      {pattern: path.join(GEN_DIRECTORY, 'front_end/**/*.js.map'), served: true, included: false},
      {pattern: path.join(GEN_DIRECTORY, 'front_end/**/*.mjs'), served: true, included: false},
      {pattern: path.join(GEN_DIRECTORY, 'front_end/**/*.mjs.map'), served: true, included: false},
      {pattern: path.join(ROOT_DIRECTORY, 'front_end/**/*.ts'), served: true, included: false},
      {pattern: path.join(GEN_DIRECTORY, 'inspector_overlay/**/*.js'), served: true, included: false},
      {pattern: path.join(GEN_DIRECTORY, 'inspector_overlay/**/*.js.map'), served: true, included: false},
    ],

    reporters: [
      'dots',
      ...coverageReporters,
    ],

    browsers,

    frameworks: ['mocha', 'chai'],

    client: {
      /*
       * Passed through to the client via __karma__ because test_setup.ts
       * preloads some CSS files and it needs to know the target directory to do
       * so.
       */
      targetDir: path.relative(process.cwd(), GEN_DIRECTORY),
    },

    plugins: [
      require('karma-chrome-launcher'),
      require('karma-mocha'),
      require('karma-chai'),
      require('karma-sourcemap-loader'),
      require('karma-coverage'),
    ],

    preprocessors: {
      '**/*.{js,mjs}': ['sourcemap'],
      [path.join(GEN_DIRECTORY, 'front_end/**/*.{js,mjs}')]: [...coveragePreprocessors],
    },

    proxies: {'/Images': 'front_end/Images'},

    coverageReporter: {
      dir: 'karma-coverage',
      reporters: istanbulReportOutputs,
    },

    singleRun: !DEBUG_ENABLED,
  };

  config.set(options);
};
<|endoftext|>


<commit_before>QUnit.test('class_name', function (assert) {
    assert.equal(DEMO.class_name('prefix', '1<2>=0 cat dog!'), 'prefix_1lt2gt-0-cat-dog-');
});

QUnit.test('row_html', function (assert) {
    assert.equal(DEMO.row_html({
        "id": "MU589117",
        "type": "single base substitution",
        "chromosome": "10",
        "start": 38654432,
        "end": 38654432,
        "mutation": "A>G"
    })[0].outerHTML,
            '
'
            + 'MU589117	A>G	single base substitution	'
            + '10	38654432	38654432
');
});

QUnit.test('table_html', function (assert) {
    assert.equal(DEMO.table_html([{
        "id": "MU589117",
        "type": "single base substitution",
        "chromosome": "10",
        "start": 38654432,
        "end": 38654432,
        "mutation": "A>G"
    }])[0].outerHTML,
            '

'
            + '
'
            + 'MU589117	A>G	single base substitution	'
            + '10	38654432	38654432
'
            + '

');
});

QUnit.test('controls_html', function (assert) {
    assert.equal(DEMO.controls_html('x',['a','b'],'y',['1','2'])[0].outerHTML,
            '

'
            + '
	a	b

1

2
'
            + '

');
});
<commit_msg>tests passing again.<commit_after>QUnit.test('class_name', function (assert) {
    assert.equal(DEMO.class_name('prefix', '1<2>=0 cat dog!'), 'prefix_1lt2gt-0-cat-dog-');
});

QUnit.test('row_html', function (assert) {
    assert.equal(DEMO.row_html({
        "id": "MU589117",
        "type": "single base substitution",
        "chromosome": "10",
        "start": 38654432,
        "end": 38654432,
        "mutation": "A>G"
    })[0].outerHTML,
            '
'
            + 'MU589117	A>G	single base substitution	'
            + '10	38654432	38654432
');
});

QUnit.test('table_html', function (assert) {
    assert.equal(DEMO.table_html([{
        "id": "MU589117",
        "type": "single base substitution",
        "chromosome": "10",
        "start": 38654432,
        "end": 38654432,
        "mutation": "A>G"
    }])[0].outerHTML,
            '

'
            + '
id	mutation	type	chromosome	start	end

MU589117	A>G	single base substitution	10	38654432	38654432
'
            + '

');
});

QUnit.test('controls_html', function (assert) {
    DEMO.type_chromosome_matrix = {'a': {}, 'b': {}};
    assert.equal(DEMO.controls_html('x',['a','b'],'y',['1','2'])[0].outerHTML,
            '

'
            + '
	a	b

1

2
'
            + '

');
});
<|endoftext|>


<commit_before>"use strict";

var path = require('path');
var es = require('event-stream');
var constants = require('../../lib/constants');
var network = require('../../lib/network');
var dtos = require('../../lib/streams/dtos');
var logger = require('../../lib/logger')('webmin');

let WebSocketServer = require('ws').Server;

module.exports = function(dbConf, overConf, interfaces, httpLogs) {

  var webminCtrl = require('../../controllers/webmin.controller')(dbConf, overConf);

  var fullPath = path.join(__dirname, '../../../ui/package/public');

  return network.createServersAndListen('uCoin web admin', interfaces, httpLogs, fullPath, (app, httpMethods) => {

    httpMethods.httpGET(  '/webmin/summary',                   webminCtrl.summary, dtos.AdminSummary);
    httpMethods.httpPOST(  '/webmin/key/preview',               webminCtrl.previewPubkey, dtos.PreviewPubkey);
    httpMethods.httpGET(  '/webmin/server/http/start',         webminCtrl.startHTTP, dtos.Boolean);
    httpMethods.httpGET(  '/webmin/server/http/stop',          webminCtrl.stopHTTP,  dtos.Boolean);
    httpMethods.httpGET(  '/webmin/server/preview_next',       webminCtrl.previewNext,  dtos.Block);
    httpMethods.httpPOST( '/webmin/server/send_conf',          webminCtrl.sendConf, dtos.Identity);
    httpMethods.httpPOST( '/webmin/server/net_conf',           webminCtrl.applyNetworkConf, dtos.Boolean);
    httpMethods.httpPOST( '/webmin/server/key_conf',           webminCtrl.applyNewKeyConf, dtos.Boolean);
    httpMethods.httpPOST( '/webmin/server/start_sync',         webminCtrl.startSync, dtos.Boolean);
    httpMethods.httpGET(  '/webmin/server/auto_conf_network',  webminCtrl.autoConfNetwork, dtos.Boolean);
    httpMethods.httpGET(  '/webmin/server/services/start_all', webminCtrl.startAllServices, dtos.Boolean);
    httpMethods.httpGET(  '/webmin/server/services/stop_all',  webminCtrl.stopAllServices, dtos.Boolean);
    httpMethods.httpGET(  '/webmin/server/reset/data',         webminCtrl.resetData, dtos.Boolean);
    httpMethods.httpGET(  '/webmin/network/interfaces',        webminCtrl.listInterfaces, dtos.NetworkInterfaces);
  }, (httpServer) => {

    // Socket for synchronization events
    let wssEvents = new WebSocketServer({
      server: httpServer,
      path: '/webmin/ws'
    });

    let lastLogs = [];
    wssEvents.on('connection', function connection(ws) {

      ws.on('message', () => {
        wssEvents.broadcast(JSON.stringify({
          type: 'log',
          value: lastLogs
        }));
      });

      wssEvents.broadcast(JSON.stringify({
        type: 'log',
        value: lastLogs
      }));

      // The callback which write each new log message to websocket
      logger.addCallbackLogs((level, msg) => {
        lastLogs.splice(0, Math.max(0, lastLogs.length - constants.WEBMIN_LOGS_CACHE + 1));
        lastLogs.push({
          level: level,
          msg: msg
        });
        wssEvents.broadcast(JSON.stringify({
          type: 'log',
          value: [{
            level: level,
            msg: msg
          }]
        }));
      });
    });

    wssEvents.broadcast = (data) => wssEvents.clients.forEach((client) => client.send(data));

    // Forward blocks & peers
    webminCtrl
      .pipe(es.mapSync(function(data) {
        // Broadcast block
        if (data.download !== undefined) {
          wssEvents.broadcast(JSON.stringify({
            type: 'download',
            value: data.download
          }));
        }
        if (data.applied !== undefined) {
          wssEvents.broadcast(JSON.stringify({
            type: 'applied',
            value: data.applied
          }));
        }
        if (data.sync !== undefined) {
          wssEvents.broadcast(JSON.stringify({
            type: 'sync',
            value: data.sync
          }));
        }
        if (data.started !== undefined) {
          wssEvents.broadcast(JSON.stringify({
            type: 'started',
            value: data.started
          }));
        }
        if (data.stopped !== undefined) {
          wssEvents.broadcast(JSON.stringify({
            type: 'stopped',
            value: data.stopped
          }));
        }
      }));
  });
};
<commit_msg>Fix: websocket error made the app crash<commit_after>"use strict";

var path = require('path');
var es = require('event-stream');
var constants = require('../../lib/constants');
var network = require('../../lib/network');
var dtos = require('../../lib/streams/dtos');
var logger = require('../../lib/logger')('webmin');

let WebSocketServer = require('ws').Server;

module.exports = function(dbConf, overConf, interfaces, httpLogs) {

  var webminCtrl = require('../../controllers/webmin.controller')(dbConf, overConf);

  var fullPath = path.join(__dirname, '../../../ui/package/public');

  return network.createServersAndListen('uCoin web admin', interfaces, httpLogs, fullPath, (app, httpMethods) => {

    httpMethods.httpGET(  '/webmin/summary',                   webminCtrl.summary, dtos.AdminSummary);
    httpMethods.httpPOST(  '/webmin/key/preview',               webminCtrl.previewPubkey, dtos.PreviewPubkey);
    httpMethods.httpGET(  '/webmin/server/http/start',         webminCtrl.startHTTP, dtos.Boolean);
    httpMethods.httpGET(  '/webmin/server/http/stop',          webminCtrl.stopHTTP,  dtos.Boolean);
    httpMethods.httpGET(  '/webmin/server/preview_next',       webminCtrl.previewNext,  dtos.Block);
    httpMethods.httpPOST( '/webmin/server/send_conf',          webminCtrl.sendConf, dtos.Identity);
    httpMethods.httpPOST( '/webmin/server/net_conf',           webminCtrl.applyNetworkConf, dtos.Boolean);
    httpMethods.httpPOST( '/webmin/server/key_conf',           webminCtrl.applyNewKeyConf, dtos.Boolean);
    httpMethods.httpPOST( '/webmin/server/start_sync',         webminCtrl.startSync, dtos.Boolean);
    httpMethods.httpGET(  '/webmin/server/auto_conf_network',  webminCtrl.autoConfNetwork, dtos.Boolean);
    httpMethods.httpGET(  '/webmin/server/services/start_all', webminCtrl.startAllServices, dtos.Boolean);
    httpMethods.httpGET(  '/webmin/server/services/stop_all',  webminCtrl.stopAllServices, dtos.Boolean);
    httpMethods.httpGET(  '/webmin/server/reset/data',         webminCtrl.resetData, dtos.Boolean);
    httpMethods.httpGET(  '/webmin/network/interfaces',        webminCtrl.listInterfaces, dtos.NetworkInterfaces);
  }, (httpServer) => {

    // Socket for synchronization events
    let wssEvents = new WebSocketServer({
      server: httpServer,
      path: '/webmin/ws'
    });

    let lastLogs = [];
    wssEvents.on('connection', function connection(ws) {

      ws.on('message', () => {
        wssEvents.broadcast(JSON.stringify({
          type: 'log',
          value: lastLogs
        }));
      });

      wssEvents.broadcast(JSON.stringify({
        type: 'log',
        value: lastLogs
      }));

      // The callback which write each new log message to websocket
      logger.addCallbackLogs((level, msg) => {
        lastLogs.splice(0, Math.max(0, lastLogs.length - constants.WEBMIN_LOGS_CACHE + 1));
        lastLogs.push({
          level: level,
          msg: msg
        });
        wssEvents.broadcast(JSON.stringify({
          type: 'log',
          value: [{
            level: level,
            msg: msg
          }]
        }));
      });
    });

    wssEvents.broadcast = (data) => wssEvents.clients.forEach((client) => {
      try {
        client.send(data);
      } catch (e) {
        console.log(e);
      }
    });

    // Forward blocks & peers
    webminCtrl
      .pipe(es.mapSync(function(data) {
        // Broadcast block
        if (data.download !== undefined) {
          wssEvents.broadcast(JSON.stringify({
            type: 'download',
            value: data.download
          }));
        }
        if (data.applied !== undefined) {
          wssEvents.broadcast(JSON.stringify({
            type: 'applied',
            value: data.applied
          }));
        }
        if (data.sync !== undefined) {
          wssEvents.broadcast(JSON.stringify({
            type: 'sync',
            value: data.sync
          }));
        }
        if (data.started !== undefined) {
          wssEvents.broadcast(JSON.stringify({
            type: 'started',
            value: data.started
          }));
        }
        if (data.stopped !== undefined) {
          wssEvents.broadcast(JSON.stringify({
            type: 'stopped',
            value: data.stopped
          }));
        }
      }));
  });
};
<|endoftext|>


<commit_before>define(['logger', 'tracker', 'underscore', 'jquery', 'backbone', 'spin', 'voc', 'userParams',
        'utils/InputValidation',
        'text!templates/toolbar/activity_stream.tpl', 'text!templates/toolbar/components/selected_user.tpl',
        'view/sss/ActivityView', 'view/sss/EntityRecommendationView',
        'data/sss/ActivityData', 'data/EntityData',
        'utils/SearchHelper', 'utils/SystemMessages'], function(Logger, tracker, _, $, Backbone, Spinner, Voc, userParams, InputValidation, ActivityStreamTemplate, SelectedUserTemplate, ActivityView, EntityRecommendationView, ActivityData, EntityData, SearchHelper, SystemMessages){
    return Backbone.View.extend({
        events: {
            'change input[name="showInToolbar[]"]' : 'filterStream',
            'click .activityStreamRefresh' : 'fetchRefreshActivityStream'
        },
        LOG: Logger.get('ActivityStreamToolbarView'),
        initialize: function() {
            this.streamSelector = '.stream';
            this.streamResultSetSelector = '.stream .resultSet';
            this.activityResultViews = [];
            this.recommendationsResultViews = [];

            this.fetchActivityStream();
        },
        render: function() {
            var that = this,
                notifications = _.template(ActivityStreamTemplate);
            this.$el.html(notifications);

            this.addAjaxLoader(this.$el.find(this.streamSelector));
        },
        addAjaxLoader: function(element) {
            if ( !this.spinner ) {
                this.spinner = new Spinner({
                    radius : 5,
                    length : 5,
                    width : 2
                });
            }
            var wrapper = document.createElement('div');
            wrapper.className = 'ajaxLoader';
            element.prepend(wrapper);
            this.spinner.spin(wrapper);
        },
        removeAjaxLoader: function(element) {
            this.spinner.stop();
            element.find('.ajaxLoader').remove();
        },
        fetchActivities: function() {
            var that = this,
                data = {
                types : [
'removeCategories',
'addEntityToLearnEpVersion',
'changeEntityForLearnEpVersionEntity',
'moveLearnEpVersionEntity',
'removeLearnEpVersionEntity',
'addCircleToLearnEpVersion',
'changeLearnEpVersionCircleLabel',
'moveLearnEpVersionCircle',
'removeLearnEpVersionCircle',
'shareLearnEpWithUser',
'copyLearnEpForUsers',
'addEntityToLearnEpCircle',
'removeEntityFromLearnEpCircle',
'removeLearnEpVersionCircleWithEntitites',
'changeLearnEpVersionCircleDescription'
                ],
                includeOnlyLastActivities : true,
                startTime: this.activitiesFetchTime ? this.activitiesFetchTime : null
            },
            promise = ActivityData.getActivities(data),
            defer = $.Deferred();

            promise.done(function(activities, passThrough) {
                that.activitiesFetchTime = passThrough['queryTime'];
                defer.resolve(activities, passThrough);
            }).fail(function(f) {
                defer.resolve([], { 'queryTime' : null });
            });

            return defer.promise();
        },
        fetchRecommendations: function() {
            var data = {
                    forUser : userParams.user,
                    maxResources : 20,
                    typesToRecommOnly : ['evernoteResource', 'evernoteNote', 'evernoteNotebook']
                },
                promise = EntityData.getRecommResources(data),
                defer = $.Deferred();

            promise.done(function(entities) {
                defer.resolve(entities);
            }).fail(function(f) {
                defer.resolve([]);
            });

            return defer.promise();
        },
        fetchActivityStream: function() {
            var that = this,
                activitiesPromise = this.fetchActivities(),
                recommendationsPromise = this.fetchRecommendations();

            // Even one failure will prevent it from working, but all the wrapper
            // methods return their own promise object and resolve with empty
            // data even on case of reject
            $.when(activitiesPromise, recommendationsPromise)
                .done(function(activitiesData, recommendations) {
                    var activities = activitiesData[0];
                    that.LOG.debug('fetchActivityStream', activities, recommendations);

                    // Deal with activities
                    if ( !_.isEmpty(that.activityResultViews) ) {
                        _.each(that.activityResultViews, function(view) {
                            view.remove();
                        });
                        that.activityResultViews = [];
                    }
                    _.each(activities, function(activity) {
                        var view = new ActivityView({
                            model : activity
                        });
                        that.activityResultViews.push(view);
                    });

                    // Deal with recommendations
                    if ( !_.isEmpty(that.recommendationsResultViews) ) {
                        _.each(that.recommendationsResultViews, function(view) {
                            view.remove();
                        });
                        that.recommendationsResultViews = [];
                    }
                    _.each(recommendations, function(recommendation) {
                        var view = new EntityRecommendationView({
                            model : recommendation
                        });
                        that.recommendationsResultViews.push(view);
                    });

                    that.displayActivityStream();
                    that.removeAjaxLoader(that.$el.find(that.streamSelector));
                }).fail(function() {
                    that.LOG.debug('fetchActivityStream Failed');
                    that.removeAjaxLoader(that.$el.find(that.streamSelector));
                });
        },
        fetchRefreshActivityStream: function(e) {
            var that = this,
                currentTarget = $(e.currentTarget),
                activitiesPromise = this.fetchActivities();

            currentTarget.prop('disabled', true);

            this.addAjaxLoader(this.$el.find(this.streamSelector));

            $.when(activitiesPromise)
                .done(function(activitiesData) {
                    var activities = activitiesData[0];
                    that.LOG.debug('fetchRefreshActivityStream', activities);

                    // Remove extsting views
                    // Deal with activities
                    if ( !_.isEmpty(that.activityResultViews) ) {
                        _.each(that.activityResultViews, function(view) {
                            view.remove();
                        });
                    }

                    // Deal with recommendations
                    if ( !_.isEmpty(that.recommendationsResultViews) ) {
                        _.each(that.recommendationsResultViews, function(view) {
                            view.remove();
                        });
                    }

                    // Deal with activities
                    _.each(activities, function(activity) {
                        // TODO Check if already present, just in case
                        var view = new ActivityView({
                            model : activity
                        });

                        if ( !that.$el.find('#showActivities').is(':checked') ) {
                            view.$el.hide();
                        }

                        that.activityResultViews.push(view);
                    });

                    that.displayActivityStream();

                    currentTarget.prop('disabled', false);
                    that.removeAjaxLoader(that.$el.find(that.streamSelector));
                }).fail(function() {
                    currentTarget.prop('disabled', false);
                    that.removeAjaxLoader(that.$el.find(that.streamSelector));
                });
        },
        displayActivityStream: function() {
            var resultSet = this.$el.find(this.streamResultSetSelector);
                combined = this.activityResultViews.concat(this.recommendationsResultViews);

            var sortedViews = _.sortBy(combined, function(view) {
                // Get reverse sort order
                return view.model.get(Voc.creationTime) * -1;
            });

            _.each(sortedViews, function(view) {
                resultSet.append(view.render().$el);
            });
        },
        _showHideStreamViews: function(views, doShow) {
           if ( views.length > 0 ) {
               _.each(views, function(view) {
                   if ( doShow ) {
                       view.$el.show();
                   } else {
                       view.$el.hide();
                   }
               });
           }
        },
        filterStream: function(e) {
            this.LOG.debug('FilterStream', e);
            var currentTarget = $(e.currentTarget),
                value = currentTarget.val(),
                isChecked = currentTarget.is(':checked'),
                views = [];

            this.$el.find('input[name="showInToolbar[]"]').prop('disabled', true);

            switch (value) {
                case 'activities':
                    views = this.activityResultViews;
                    break;
                case 'recommendations':
                    views = this.recommendationsResultViews;
                    break;
            }

            this._showHideStreamViews(views, isChecked);
            this.$el.find('input[name="showInToolbar[]"]').prop('disabled', false);

            if ( isChecked ) {
                tracker.info(tracker.SETFILTER, tracker.NOTIFICATIONTAB, null, value);
            } else {
                tracker.info(tracker.REMOVEFILTER, tracker.NOTIFICATIONTAB, null, value);
            }
        }
    });
});
<commit_msg>LL-1300 #comment Uncommented removeCategories activity.<commit_after>define(['logger', 'tracker', 'underscore', 'jquery', 'backbone', 'spin', 'voc', 'userParams',
        'utils/InputValidation',
        'text!templates/toolbar/activity_stream.tpl', 'text!templates/toolbar/components/selected_user.tpl',
        'view/sss/ActivityView', 'view/sss/EntityRecommendationView',
        'data/sss/ActivityData', 'data/EntityData',
        'utils/SearchHelper', 'utils/SystemMessages'], function(Logger, tracker, _, $, Backbone, Spinner, Voc, userParams, InputValidation, ActivityStreamTemplate, SelectedUserTemplate, ActivityView, EntityRecommendationView, ActivityData, EntityData, SearchHelper, SystemMessages){
    return Backbone.View.extend({
        events: {
            'change input[name="showInToolbar[]"]' : 'filterStream',
            'click .activityStreamRefresh' : 'fetchRefreshActivityStream'
        },
        LOG: Logger.get('ActivityStreamToolbarView'),
        initialize: function() {
            this.streamSelector = '.stream';
            this.streamResultSetSelector = '.stream .resultSet';
            this.activityResultViews = [];
            this.recommendationsResultViews = [];

            this.fetchActivityStream();
        },
        render: function() {
            var that = this,
                notifications = _.template(ActivityStreamTemplate);
            this.$el.html(notifications);

            this.addAjaxLoader(this.$el.find(this.streamSelector));
        },
        addAjaxLoader: function(element) {
            if ( !this.spinner ) {
                this.spinner = new Spinner({
                    radius : 5,
                    length : 5,
                    width : 2
                });
            }
            var wrapper = document.createElement('div');
            wrapper.className = 'ajaxLoader';
            element.prepend(wrapper);
            this.spinner.spin(wrapper);
        },
        removeAjaxLoader: function(element) {
            this.spinner.stop();
            element.find('.ajaxLoader').remove();
        },
        fetchActivities: function() {
            var that = this,
                data = {
                types : [
//'removeCategories',
'addEntityToLearnEpVersion',
'changeEntityForLearnEpVersionEntity',
'moveLearnEpVersionEntity',
'removeLearnEpVersionEntity',
'addCircleToLearnEpVersion',
'changeLearnEpVersionCircleLabel',
'moveLearnEpVersionCircle',
'removeLearnEpVersionCircle',
'shareLearnEpWithUser',
'copyLearnEpForUsers',
'addEntityToLearnEpCircle',
'removeEntityFromLearnEpCircle',
'removeLearnEpVersionCircleWithEntitites',
'changeLearnEpVersionCircleDescription'
                ],
                includeOnlyLastActivities : true,
                startTime: this.activitiesFetchTime ? this.activitiesFetchTime : null
            },
            promise = ActivityData.getActivities(data),
            defer = $.Deferred();

            promise.done(function(activities, passThrough) {
                that.activitiesFetchTime = passThrough['queryTime'];
                defer.resolve(activities, passThrough);
            }).fail(function(f) {
                defer.resolve([], { 'queryTime' : null });
            });

            return defer.promise();
        },
        fetchRecommendations: function() {
            var data = {
                    forUser : userParams.user,
                    maxResources : 20,
                    typesToRecommOnly : ['evernoteResource', 'evernoteNote', 'evernoteNotebook']
                },
                promise = EntityData.getRecommResources(data),
                defer = $.Deferred();

            promise.done(function(entities) {
                defer.resolve(entities);
            }).fail(function(f) {
                defer.resolve([]);
            });

            return defer.promise();
        },
        fetchActivityStream: function() {
            var that = this,
                activitiesPromise = this.fetchActivities(),
                recommendationsPromise = this.fetchRecommendations();

            // Even one failure will prevent it from working, but all the wrapper
            // methods return their own promise object and resolve with empty
            // data even on case of reject
            $.when(activitiesPromise, recommendationsPromise)
                .done(function(activitiesData, recommendations) {
                    var activities = activitiesData[0];
                    that.LOG.debug('fetchActivityStream', activities, recommendations);

                    // Deal with activities
                    if ( !_.isEmpty(that.activityResultViews) ) {
                        _.each(that.activityResultViews, function(view) {
                            view.remove();
                        });
                        that.activityResultViews = [];
                    }
                    _.each(activities, function(activity) {
                        var view = new ActivityView({
                            model : activity
                        });
                        that.activityResultViews.push(view);
                    });

                    // Deal with recommendations
                    if ( !_.isEmpty(that.recommendationsResultViews) ) {
                        _.each(that.recommendationsResultViews, function(view) {
                            view.remove();
                        });
                        that.recommendationsResultViews = [];
                    }
                    _.each(recommendations, function(recommendation) {
                        var view = new EntityRecommendationView({
                            model : recommendation
                        });
                        that.recommendationsResultViews.push(view);
                    });

                    that.displayActivityStream();
                    that.removeAjaxLoader(that.$el.find(that.streamSelector));
                }).fail(function() {
                    that.LOG.debug('fetchActivityStream Failed');
                    that.removeAjaxLoader(that.$el.find(that.streamSelector));
                });
        },
        fetchRefreshActivityStream: function(e) {
            var that = this,
                currentTarget = $(e.currentTarget),
                activitiesPromise = this.fetchActivities();

            currentTarget.prop('disabled', true);

            this.addAjaxLoader(this.$el.find(this.streamSelector));

            $.when(activitiesPromise)
                .done(function(activitiesData) {
                    var activities = activitiesData[0];
                    that.LOG.debug('fetchRefreshActivityStream', activities);

                    // Remove extsting views
                    // Deal with activities
                    if ( !_.isEmpty(that.activityResultViews) ) {
                        _.each(that.activityResultViews, function(view) {
                            view.remove();
                        });
                    }

                    // Deal with recommendations
                    if ( !_.isEmpty(that.recommendationsResultViews) ) {
                        _.each(that.recommendationsResultViews, function(view) {
                            view.remove();
                        });
                    }

                    // Deal with activities
                    _.each(activities, function(activity) {
                        // TODO Check if already present, just in case
                        var view = new ActivityView({
                            model : activity
                        });

                        if ( !that.$el.find('#showActivities').is(':checked') ) {
                            view.$el.hide();
                        }

                        that.activityResultViews.push(view);
                    });

                    that.displayActivityStream();

                    currentTarget.prop('disabled', false);
                    that.removeAjaxLoader(that.$el.find(that.streamSelector));
                }).fail(function() {
                    currentTarget.prop('disabled', false);
                    that.removeAjaxLoader(that.$el.find(that.streamSelector));
                });
        },
        displayActivityStream: function() {
            var resultSet = this.$el.find(this.streamResultSetSelector);
                combined = this.activityResultViews.concat(this.recommendationsResultViews);

            var sortedViews = _.sortBy(combined, function(view) {
                // Get reverse sort order
                return view.model.get(Voc.creationTime) * -1;
            });

            _.each(sortedViews, function(view) {
                resultSet.append(view.render().$el);
            });
        },
        _showHideStreamViews: function(views, doShow) {
           if ( views.length > 0 ) {
               _.each(views, function(view) {
                   if ( doShow ) {
                       view.$el.show();
                   } else {
                       view.$el.hide();
                   }
               });
           }
        },
        filterStream: function(e) {
            this.LOG.debug('FilterStream', e);
            var currentTarget = $(e.currentTarget),
                value = currentTarget.val(),
                isChecked = currentTarget.is(':checked'),
                views = [];

            this.$el.find('input[name="showInToolbar[]"]').prop('disabled', true);

            switch (value) {
                case 'activities':
                    views = this.activityResultViews;
                    break;
                case 'recommendations':
                    views = this.recommendationsResultViews;
                    break;
            }

            this._showHideStreamViews(views, isChecked);
            this.$el.find('input[name="showInToolbar[]"]').prop('disabled', false);

            if ( isChecked ) {
                tracker.info(tracker.SETFILTER, tracker.NOTIFICATIONTAB, null, value);
            } else {
                tracker.info(tracker.REMOVEFILTER, tracker.NOTIFICATIONTAB, null, value);
            }
        }
    });
});
<|endoftext|>


<commit_before>class Pen {
  constructor() {
    this.name = "pen";
    this.drawing = false;
    this.currentPath = null;
    this.prevPoint = null;
  }

  startPath(x, y) {
    let path = dom.svg("path", {
      d: `M${x},${y}`,
      stroke: currentColor,
      "stroke-width": currentStrokeWidth,
      "stroke-linejoin": "round",
      "stroke-linecap": "round",
      fill: "none"
    });
    this.currentPath = currentFrame().appendChild(path);
    // console.log('currentPath: %o', this.currentPath);
    file.onChange();
  }

  appendToPath(x, y) {
    this.currentPath.setAttribute(
      "d",
      this.currentPath.getAttribute("d") + ` L${x},${y}`
    );
  }

  start(evt) {
    saveMatrix();
    let { x, y, err } = getXY(evt);
    if (err) {
      return;
    }
    this.firstPoint = { x, y };
    this.prevPoint = { x, y };
    this.startPath(x, y);
    this.drawing = true;
  }

  move(evt) {
    if (!this.drawing) return;
    let { x, y, wx, wy, err } = getXY(evt);
    if (err) {
      return;
    }
    if (collideCircle({ x, y }, 1, this.prevPoint, 1)) {
      // too close to previous point to both drawing
      return;
    }
    this.prevPoint = { x, y };
    if (inBounds(wx, wy)) {
      this.appendToPath(x, y);
    }
  }

  stop(evt) {
    if (!this.drawing) return;
    let { x, y, wx, wy, err } = getXY(evt);
    if (err) {
      return;
    }
    let path = this.currentPath;
    let parent = currentFrame();
    if (this.currentPath) {
      if (inBounds(wx, wy) && this.sx === x && this.sy === y) {
        this.appendToPath(x, y);
      }
      //dom.simplifyPath(currentPath);
      this.currentPath = null;
    }
    this.drawing = false;
    currentMatrix = null;
    undo.pushFrameUndo(
      "Draw",
      () => path.remove(),
      () => parent.appendChild(path)
    );
  }

  cancel() {
    this.currentPath.remove();
    this.currentPath = null;
    currentMatrix = null;
  }
}

class Move {
  constructor() {
    this.name = "move";
    this.dragging = false;
    this.px = 0;
    this.py = 0;
  }

  start(evt) {
    saveMatrix();
    let { x, y, err } = getXY(evt);
    if (err) {
      return;
    }
    this.px = x;
    this.py = y;
    this.dragging = true;
    this.origTransform = currentFrame().getAttribute("transform") || "";
  }

  move(evt) {
    if (!this.dragging) {
      return;
    }
    let { x, y, err } = getXY(evt);
    if (err) {
      return;
    }
    let dx = x - this.px;
    let dy = y - this.py;
    currentFrame().setAttribute(
      "transform",
      `${this.origTransform} translate(${dx} ${dy})`
    );
  }

  stop(evt) {
    if (!this.dragging) {
      return;
    }
    this.px = 9;
    this.py = 0;
    this.dragging = false;
    let oldTransform = this.origTransform;
    this.origTransform = "";
    currentMatrix = null;
    let curr = currentFrame();
    let newTransform = curr.getAttribute("transform");
    undo.pushFrameUndo(
      "Move",
      () => curr.setAttribute("transform", oldTransform),
      () => curr.setAttribute("transform", newTransform)
    );
  }

  cancel() {
    currentFrame().setAttribute("transform", this.origTransform);
    this.dragging = false;
    this.origTransform = false;
    currentMatrix = null;
  }
}

function dist(dx, dy) {
  return Math.sqrt(dx * dx + dy * dy);
}

class Rotate {
  constructor() {
    this.name = "rotate";
    this.dragging = false;
    this.px = 0;
    this.py = 0;
    this.originalAngle = null;
  }

  start(evt) {
    saveMatrix();
    let { x, y, err } = getXY(evt);
    if (err) {
      return;
    }
    this.px = x;
    this.py = y;
    this.dragging = true;
    this.origTransform = currentFrame().getAttribute("transform") || "";
  }

  move(evt) {
    if (!this.dragging) {
      return;
    }
    let { x, y, err } = getXY(evt);
    if (err) {
      return;
    }
    let px = this.px;
    let py = this.py;
    let dx = x - px;
    let dy = y - py;
    if (dist(dx, dy) < 20) {
      return;
    } // don't pick starting angle until we've moved a little from the starting point
    if (this.originalAngle !== null) {
      let transform = this.origTransform;
      let angle = degrees(Math.atan2(dy, dx)) - this.originalAngle;
      currentFrame().setAttribute(
        "transform",
        `${transform} rotate(${angle} ${px} ${py})`
      );
    } else {
      this.originalAngle = degrees(Math.atan2(dy, dx));
    }
  }

  stop(evt) {
    if (!this.dragging) {
      return;
    }
    this.px = 9;
    this.py = 0;
    this.dragging = false;
    let oldTransform = this.origTransform;
    this.origTransform = "";
    this.originalAngle = null;
    currentMatrix = null;
    let curr = currentFrame();
    let newTransform = curr.getAttribute("transform");
    undo.pushFrameUndo(
      "Rotate",
      () => curr.setAttribute("transform", oldTransform),
      () => curr.setAttribute("transform", newTransform)
    );
  }

  cancel(evt) {
    currentFrame().setAttribute("transform", this.origTransform);
    this.dragging = false;
    this.origTransform = false;
    currentMatrix = null;
  }
}

class ZoomIn {
  constructor() {
    this.name = "zoomin";
  }

  start(evt) {
    saveMatrix();
    let { x, y, err } = getXY(evt);
    if (err) {
      return;
    }
    let curr = currentFrame();
    let oldTransform = curr.getAttribute("transform") || "";
    let newTransform = `${oldTransform} translate(${x} ${y}) scale(${ZOOMIN}) translate(-${x}, -${y})`;
    currentFrame().setAttribute("transform", newTransform);
    currentMatrix = null;
    undo.pushFrameUndo(
      "Zoom In",
      () => curr.setAttribute("transform", oldTransform),
      () => curr.setAttribute("transform", newTransform)
    );
  }

  move(evt) {
    // do nothing
  }

  stop(evt) {
    // do nothing
  }

  cancel(evt) {
    // do nothing
  }
}

class ZoomOut {
  constructor() {
    this.name = "zoomout";
  }

  start(evt) {
    saveMatrix();
    let { x, y, err } = getXY(evt);
    if (err) {
      return;
    }
    let curr = currentFrame();
    let oldTransform = curr.getAttribute("transform") || "";
    let newTransform = `${oldTransform} translate(${x} ${y}) scale(${ZOOMOUT}) translate(-${x}, -${y})`;
    currentFrame().setAttribute("transform", newTransform);
    currentMatrix = null;
    undo.pushFrameUndo(
      "Zoom Out",
      () => curr.setAttribute("transform", oldTransform),
      () => curr.setAttribute("transform", newTransform)
    );
  }

  move(evt) {
    // do nothing
  }

  stop(evt) {
    // do nothing
  }

  cancel(evt) {
    // do nothing
  }
}

class Eraser {
  constructor() {
    this.name = "eraser";
  }

  start(evt) {
    let { x, y, wx, wy, err } = getXY(evt);
    if (err) {
      return;
    }
    this.prevPoint = {x,y};
    if (inBounds(wx,wy)){
      erasePaths({x,y});
    }

  }

  move(evt) {
    if (!this.drawing) return;
    let { x, y, wx, wy, err } = getXY(evt);
    if (err) {
      return;
    }
    // if (collideCircle({ x, y }, 1, this.prevPoint, 1)) {
    //   // too close to previous point to both erasing
    //   return;
    // }
    if (inBounds(wx,wy)){
      erasePaths({x,y});
    }
  }

  stop(evt) {
    this.prevPoint = null;
  }

  cancel() {
    this.prevPoint = null;
  }
}

// UTILITIES

function pointsFromPath(path) {
  let coords = path
    .getAttribute("d")
    .split(/[ ,LM]+/)
    .map(Number);
  // First one is empty
  let points = [];
  while (coords.length) {
    points.push((points.shift(), points.shift()));
  }
  return points;
}

function pointsToPath(points){
  let first = points.shift();
  let rest = points.map(pt => `L${pt.x},${pt.y}`);
  rest.unshift(`M${first.x},${first.y}`);
  return rest.join(' ');
}

// Because points are actually circles (due to penWidth / eraserWidth) this is a basic circl collision algorithm
function collideCircle(p1, r1, p2, r2) {
  return (
    Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2) < Math.pow(r1 + r2, 2)
  );
}

function collideBox(r1, r2) {
  if (r1.x + r1.width < r2.x) {
    return false;
  }
  if (r1.y + r1.height < r2.y) {
    return false;
  }
  if (r1.x > r2.y + r2.width) {
    return false;
  }
  if (r1.y > r2.y + r2.height) {
    return false;
  }
  return true;
}

function inBounds(x, y) {
  return !(x < 0 || x > WIDTH || y < 0 || y > HEIGHT);
}

function saveMatrix() {
  let matrix = currentFrame().getCTM();
  if (matrix instanceof SVGMatrix) {
    matrix = new DOMMatrix([
      matrix.a,
      matrix.b,
      matrix.c,
      matrix.d,
      matrix.e,
      matrix.f
    ]);
  }
  currentMatrix = matrix.inverse();
}

function getXY(evt) {
  if (evt.button) {
    // left button is 0, for touch events button will be undefined
    return { x: 0, y: 0, err: true };
  }
  if (evt.touches && evt.touches.length > 1) {
    // don't interfere with multi-touch
    return { x: 0, y: 0, err: true };
  }
  if (evt.cancelable) {
    evt.preventDefault();
  }

  const rect = this.canvas.getBoundingClientRect();
  const position = (evt.changedTouches && evt.changedTouches[0]) || evt;
  let x = position.offsetX;
  let y = position.offsetY;

  if (typeof x === "undefined") {
    x = position.clientX - rect.left;
  }
  if (typeof y === "undefined") {
    y = position.clientY - rect.top;
  }
  // if the frame has been translated, rotated, or scaled, we need to map the point to the current matrix
  let { x: tx, y: ty } = transformPoint(x, y);
  return { x: tx, y: ty, wx: x, wy: y, err: false };
}

function transformPoint(x, y) {
  let frame = currentFrame();
  if (frame.transform.baseVal.length === 0) {
    return { x, y };
  }
  return currentMatrix.transformPoint(new DOMPoint(x, y));
}

function drawBoundingBox(bbox, color){
  let r = dom.svg('rect', bbox);
  r.setAttribute('fill', 'none');
  r.setAttribute('stroke', color || '#00F');
  currentFrame().appendChild(r);
}

function erasePaths(point){
  currentFrame().querySelectorAll('rect').forEach(r => r.remove());
  let paths = collidePaths(point, Array.from(currentFrame().querySelector("path")));
  console.log(`${paths.length} matching paths`);
  // paths.forEach(drawBoundingBox);
  paths.forEach(path => erasePath(point, path));

}

function erasePath(pt1, path){
  let r1 = currentEraserWidth;
  let r2 = Number(path.getAttribute('stroke-width'))
  path.setAttribute('d', pointsToPath(pointsFromPath(path).filter(pt2 => collideCircle(pt1, r1, pt2, r2))));
}

function collidePaths(point, paths) {
  // quck check to try to eliminate paths that don't intersect
  let d = currentEraserWidth / 2;
  let eraserBox = {
    x: point.x - d,
    y: point.y - d,
    width: currentEraserWidth,
    height: currentEraserWidth
  };
  drawBoundingBox(eraserBox, '#F00');
  return paths.filter(path =>
    collideBox(eraserBox, path.getBBox({ stroke: true }))
  );
}
<commit_msg>🏝🌯 Checkpoint ./js/tools.js:739936/259<commit_after>class Pen {
  constructor() {
    this.name = "pen";
    this.drawing = false;
    this.currentPath = null;
    this.prevPoint = null;
  }

  startPath(x, y) {
    let path = dom.svg("path", {
      d: `M${x},${y}`,
      stroke: currentColor,
      "stroke-width": currentStrokeWidth,
      "stroke-linejoin": "round",
      "stroke-linecap": "round",
      fill: "none"
    });
    this.currentPath = currentFrame().appendChild(path);
    // console.log('currentPath: %o', this.currentPath);
    file.onChange();
  }

  appendToPath(x, y) {
    this.currentPath.setAttribute(
      "d",
      this.currentPath.getAttribute("d") + ` L${x},${y}`
    );
  }

  start(evt) {
    saveMatrix();
    let { x, y, err } = getXY(evt);
    if (err) {
      return;
    }
    this.firstPoint = { x, y };
    this.prevPoint = { x, y };
    this.startPath(x, y);
    this.drawing = true;
  }

  move(evt) {
    if (!this.drawing) return;
    let { x, y, wx, wy, err } = getXY(evt);
    if (err) {
      return;
    }
    if (collideCircle({ x, y }, 1, this.prevPoint, 1)) {
      // too close to previous point to both drawing
      return;
    }
    this.prevPoint = { x, y };
    if (inBounds(wx, wy)) {
      this.appendToPath(x, y);
    }
  }

  stop(evt) {
    if (!this.drawing) return;
    let { x, y, wx, wy, err } = getXY(evt);
    if (err) {
      return;
    }
    let path = this.currentPath;
    let parent = currentFrame();
    if (this.currentPath) {
      if (inBounds(wx, wy) && this.sx === x && this.sy === y) {
        this.appendToPath(x, y);
      }
      //dom.simplifyPath(currentPath);
      this.currentPath = null;
    }
    this.drawing = false;
    currentMatrix = null;
    undo.pushFrameUndo(
      "Draw",
      () => path.remove(),
      () => parent.appendChild(path)
    );
  }

  cancel() {
    this.currentPath.remove();
    this.currentPath = null;
    currentMatrix = null;
  }
}

class Move {
  constructor() {
    this.name = "move";
    this.dragging = false;
    this.px = 0;
    this.py = 0;
  }

  start(evt) {
    saveMatrix();
    let { x, y, err } = getXY(evt);
    if (err) {
      return;
    }
    this.px = x;
    this.py = y;
    this.dragging = true;
    this.origTransform = currentFrame().getAttribute("transform") || "";
  }

  move(evt) {
    if (!this.dragging) {
      return;
    }
    let { x, y, err } = getXY(evt);
    if (err) {
      return;
    }
    let dx = x - this.px;
    let dy = y - this.py;
    currentFrame().setAttribute(
      "transform",
      `${this.origTransform} translate(${dx} ${dy})`
    );
  }

  stop(evt) {
    if (!this.dragging) {
      return;
    }
    this.px = 9;
    this.py = 0;
    this.dragging = false;
    let oldTransform = this.origTransform;
    this.origTransform = "";
    currentMatrix = null;
    let curr = currentFrame();
    let newTransform = curr.getAttribute("transform");
    undo.pushFrameUndo(
      "Move",
      () => curr.setAttribute("transform", oldTransform),
      () => curr.setAttribute("transform", newTransform)
    );
  }

  cancel() {
    currentFrame().setAttribute("transform", this.origTransform);
    this.dragging = false;
    this.origTransform = false;
    currentMatrix = null;
  }
}

function dist(dx, dy) {
  return Math.sqrt(dx * dx + dy * dy);
}

class Rotate {
  constructor() {
    this.name = "rotate";
    this.dragging = false;
    this.px = 0;
    this.py = 0;
    this.originalAngle = null;
  }

  start(evt) {
    saveMatrix();
    let { x, y, err } = getXY(evt);
    if (err) {
      return;
    }
    this.px = x;
    this.py = y;
    this.dragging = true;
    this.origTransform = currentFrame().getAttribute("transform") || "";
  }

  move(evt) {
    if (!this.dragging) {
      return;
    }
    let { x, y, err } = getXY(evt);
    if (err) {
      return;
    }
    let px = this.px;
    let py = this.py;
    let dx = x - px;
    let dy = y - py;
    if (dist(dx, dy) < 20) {
      return;
    } // don't pick starting angle until we've moved a little from the starting point
    if (this.originalAngle !== null) {
      let transform = this.origTransform;
      let angle = degrees(Math.atan2(dy, dx)) - this.originalAngle;
      currentFrame().setAttribute(
        "transform",
        `${transform} rotate(${angle} ${px} ${py})`
      );
    } else {
      this.originalAngle = degrees(Math.atan2(dy, dx));
    }
  }

  stop(evt) {
    if (!this.dragging) {
      return;
    }
    this.px = 9;
    this.py = 0;
    this.dragging = false;
    let oldTransform = this.origTransform;
    this.origTransform = "";
    this.originalAngle = null;
    currentMatrix = null;
    let curr = currentFrame();
    let newTransform = curr.getAttribute("transform");
    undo.pushFrameUndo(
      "Rotate",
      () => curr.setAttribute("transform", oldTransform),
      () => curr.setAttribute("transform", newTransform)
    );
  }

  cancel(evt) {
    currentFrame().setAttribute("transform", this.origTransform);
    this.dragging = false;
    this.origTransform = false;
    currentMatrix = null;
  }
}

class ZoomIn {
  constructor() {
    this.name = "zoomin";
  }

  start(evt) {
    saveMatrix();
    let { x, y, err } = getXY(evt);
    if (err) {
      return;
    }
    let curr = currentFrame();
    let oldTransform = curr.getAttribute("transform") || "";
    let newTransform = `${oldTransform} translate(${x} ${y}) scale(${ZOOMIN}) translate(-${x}, -${y})`;
    currentFrame().setAttribute("transform", newTransform);
    currentMatrix = null;
    undo.pushFrameUndo(
      "Zoom In",
      () => curr.setAttribute("transform", oldTransform),
      () => curr.setAttribute("transform", newTransform)
    );
  }

  move(evt) {
    // do nothing
  }

  stop(evt) {
    // do nothing
  }

  cancel(evt) {
    // do nothing
  }
}

class ZoomOut {
  constructor() {
    this.name = "zoomout";
  }

  start(evt) {
    saveMatrix();
    let { x, y, err } = getXY(evt);
    if (err) {
      return;
    }
    let curr = currentFrame();
    let oldTransform = curr.getAttribute("transform") || "";
    let newTransform = `${oldTransform} translate(${x} ${y}) scale(${ZOOMOUT}) translate(-${x}, -${y})`;
    currentFrame().setAttribute("transform", newTransform);
    currentMatrix = null;
    undo.pushFrameUndo(
      "Zoom Out",
      () => curr.setAttribute("transform", oldTransform),
      () => curr.setAttribute("transform", newTransform)
    );
  }

  move(evt) {
    // do nothing
  }

  stop(evt) {
    // do nothing
  }

  cancel(evt) {
    // do nothing
  }
}

class Eraser {
  constructor() {
    this.name = "eraser";
  }

  start(evt) {
    let { x, y, wx, wy, err } = getXY(evt);
    if (err) {
      console.error('Houston, we have a problem');
      return;
    }
    this.prevPoint = {x,y};
    this.isErasing = true;
    if (inBounds(wx,wy)){
      erasePaths({x,y});
    }

  }

  move(evt) {
    if (!this.isErasing){
      return;
    }
    let { x, y, wx, wy, err } = getXY(evt);
    if (err) {
      return;
    }
    if (collideCircle({ x, y }, 1, this.prevPoint, 1)) {
      // too close to previous point to both erasing
      return;
    }
    this.prevPoint = {x,y};
    if (inBounds(wx,wy)){
      erasePaths({x,y});
    }
  }

  stop(evt) {
    this.isErasing = false;
    this.prevPoint = null;
  }

  cancel() {
    this.isErasing = false;
    this.prevPoint = null;
  }
}

// UTILITIES

function pointsFromPath(path) {
  let coords = path
    .getAttribute("d")
    .split(/[ ,LM]+/)
    .map(Number);
  // First one is empty
  let points = [];
  while (coords.length) {
    points.push((points.shift(), points.shift()));
  }
  return points;
}

function pointsToPath(points){
  let first = points.shift();
  let rest = points.map(pt => `L${pt.x},${pt.y}`);
  rest.unshift(`M${first.x},${first.y}`);
  return rest.join(' ');
}

// Because points are actually circles (due to penWidth / eraserWidth) this is a basic circl collision algorithm
function collideCircle(p1, r1, p2, r2) {
  return (
    Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2) < Math.pow(r1 + r2, 2)
  );
}

function collideBox(r1, r2) {
  if (r1.x + r1.width < r2.x) {
    return false;
  }
  if (r1.y + r1.height < r2.y) {
    return false;
  }
  if (r1.x > r2.y + r2.width) {
    return false;
  }
  if (r1.y > r2.y + r2.height) {
    return false;
  }
  return true;
}

function inBounds(x, y) {
  return !(x < 0 || x > WIDTH || y < 0 || y > HEIGHT);
}

function saveMatrix() {
  let matrix = currentFrame().getCTM();
  if (matrix instanceof SVGMatrix) {
    matrix = new DOMMatrix([
      matrix.a,
      matrix.b,
      matrix.c,
      matrix.d,
      matrix.e,
      matrix.f
    ]);
  }
  currentMatrix = matrix.inverse();
}

function getXY(evt) {
  if (evt.button) {
    // left button is 0, for touch events button will be undefined
    return { x: 0, y: 0, err: true };
  }
  if (evt.touches && evt.touches.length > 1) {
    // don't interfere with multi-touch
    return { x: 0, y: 0, err: true };
  }
  if (evt.cancelable) {
    evt.preventDefault();
  }

  const rect = this.canvas.getBoundingClientRect();
  const position = (evt.changedTouches && evt.changedTouches[0]) || evt;
  let x = position.offsetX;
  let y = position.offsetY;

  if (typeof x === "undefined") {
    x = position.clientX - rect.left;
  }
  if (typeof y === "undefined") {
    y = position.clientY - rect.top;
  }
  // if the frame has been translated, rotated, or scaled, we need to map the point to the current matrix
  let { x: tx, y: ty } = transformPoint(x, y);
  return { x: tx, y: ty, wx: x, wy: y, err: false };
}

function transformPoint(x, y) {
  let frame = currentFrame();
  if (frame.transform.baseVal.length === 0) {
    return { x, y };
  }
  return currentMatrix.transformPoint(new DOMPoint(x, y));
}

function drawBoundingBox(bbox, color){
  let r = dom.svg('rect', bbox);
  r.setAttribute('fill', 'none');
  r.setAttribute('stroke', color || '#00F');
  currentFrame().appendChild(r);
}

function erasePaths(point){
  currentFrame().querySelectorAll('rect').forEach(r => r.remove());
  let paths = collidePaths(point, Array.from(currentFrame().querySelector("path")));
  console.log(`${paths.length} matching paths`);
  // paths.forEach(drawBoundingBox);
  paths.forEach(path => erasePath(point, path));

}

function erasePath(pt1, path){
  let r1 = currentEraserWidth;
  let r2 = Number(path.getAttribute('stroke-width'))
  path.setAttribute('d', pointsToPath(pointsFromPath(path).filter(pt2 => collideCircle(pt1, r1, pt2, r2))));
}

function collidePaths(point, paths) {
  // quck check to try to eliminate paths that don't intersect
  let d = currentEraserWidth / 2;
  let eraserBox = {
    x: point.x - d,
    y: point.y - d,
    width: currentEraserWidth,
    height: currentEraserWidth
  };
  drawBoundingBox(eraserBox, '#F00');
  return paths.filter(path =>
    collideBox(eraserBox, path.getBBox({ stroke: true }))
  );
}
<|endoftext|>


<commit_before>//---------------------------------------------------------------------------------
//- datastore
//---------------------------------------------------------------------------------
'use strict;'
var datastore = require('node-persist');
var log = console.log;

datastore.initSync({
  dir: '../../../../datastore',
  stringify: JSON.stringify,
  parse: JSON.parse,
  encoding: 'utf8',
  logging: false, // can also be custom logging function
  continuous: true,
  interval: false
});

var milis = 0;
exports.createId = function() {
  milis = new Date().getTime();
  return (milis += 1).toString();
};

exports.clear = function() {
  datastore.clear();
};

exports.save = function(obj) {
  datastore.setItem(obj.id, obj);
  datastore.getItem(obj.id);
}

exports.get = function(id) {
  return datastore.getItem(id);
}

exports.getAll = function() {
  var objs = [];
  datastore.values(function(vals) {
    objs = vals;
  });
  return objs;
}

exports.remove = function(id) {
  return datastore.removeItem(id);
}
<commit_msg>renamed datastore.js to db.js<commit_after><|endoftext|>


<commit_before>//rocketLabGyro.js
//extensão do gyro

//VARIÁVEIS GLOBAIS-------------------------------------------------------------
var canvas;
var ctx;
var animation;

//FOGUETUINHO-------------------------------------------------------------------
var rocket = function(sizeX, sizeY, sizeZ){

    //classe que rotaciona pontos 3d internamente, um tipo de "herança"
    //feita na força da gambiarra
    var Model3DManager = function(points){

        return{
            rotateX : function (theta){
                //funçao que rotaciona todos os pontos em torno do eixo X;

                var cos = Math.cos(theta);
                var sin = Math.sin(theta);

                for (var i=0; i<points.length; i++){
                    nodeY = points[i][1];
                    nodeZ = points[i][2];

                    points[i][1] = (cos*nodeY) - (sin*nodeZ);
                    points[i][2] = (cos*nodeZ) + (sin*nodeY);
                }
            },

            rotateY : function(theta){
                //funçao que rotaciona todos os pontos em torno do eixo Y;

                var cos = Math.cos(theta);
                var sin = Math.sin(theta);

                for (var i=0; i<points.length; i++){
                    nodeX = points[i][0];
                    nodeZ = points[i][2];

                    points[i][0] = (cos*nodeX) - (sin*nodeZ);
                    points[i][2] = (cos*nodeZ) + (sin*nodeX);
                }
            },

            rotateZ : function(theta){
                //funçao que rotaciona todos os pontos em torno do eixo Z;

                var cos = Math.cos(theta);
                var sin = Math.sin(theta);

                for (var i=0; i<points.length; i++){
                    nodeX = points[i][0];
                    nodeY = points[i][1];

                    points[i][0] = (cos*nodeX) - (sin*nodeY);
                    points[i][1] = (cos*nodeY) + (sin*nodeX);
                }
            }
        }
    }

    //corpo do boitatá
    var rocketBody = function(sizeXZ, sizeY){

        //MÁGICA. NÃO TOQUE. NÃO OLHE. NÃO TENTE ENTENDER

        var points = [ ];
        var rotate = new Model3DManager(points);
        var pl = 16; //numero de poligonos

        //fazer um cilindro com pontos (lembrando que y cresce de cima para
        //baixo)
        for(var i=0; i<(pl/2)+1; i++){
            points.push([sizeXZ, -sizeY, sizeXZ]);
            points.push([sizeXZ, sizeY, sizeXZ]);
            rotate.rotateY((6.283/pl)*2, points);
        }
        //ponto para ser o bico da coifa do foguete
        points.push([0, sizeY*1.45, 0]);

        return {
            rotateX : function(theta){
                rotate.rotateX(theta);
            },
            rotateY : function(theta){
                rotate.rotateY(theta);
            },
            rotateZ : function(theta){
                rotate.rotateZ(theta);
            },
            draw : function(){
                //desenha o cilindro de cor laranja (transparente).

                var fov = 750;

                //desenha todos os retangulos
                for (var i=0; i<pl-1; i=i+2){
                    ctx.fillStyle = '#cc8d06'; //fov/(fov+points[i][2]);
                    ctx.beginPath();
                    ctx.moveTo(points[i][0]*fov/(fov+points[i][2]), points[i][1]*fov/(fov+points[i][2]));
                    ctx.lineTo(points[i+1][0]*fov/(fov+points[i+1][2]), points[i+1][1]*fov/(fov+points[i+1][2]));
                    ctx.lineTo(points[i+3][0]*fov/(fov+points[i+3][2]), points[i+3][1]*fov/(fov+points[i+3][2]));
                    ctx.lineTo(points[i+2][0]*fov/(fov+points[i+2][2]), points[i+2][1]*fov/(fov+points[i+2][2]));
                    ctx.closePath();
                    ctx.fill();
                }
                for(var i=0; i<pl-1; i=i+2){ //coifa
                    ctx.fillStyle = '#000000';
                    ctx.beginPath();
                    ctx.moveTo(points[i+1][0]*fov/(fov+points[i+1][2]), points[i+1][1]*fov/(fov+points[i+1][2]));
                    ctx.lineTo(points[points.length-1][0]*fov/(fov+points[points.length-1][2]), points[points.length-1][1]*fov/(fov+points[points.length-1][2]));
                    ctx.lineTo(points[i+3][0]*fov/(fov+points[i+3][2]), points[i+3][1]*fov/(fov+points[i+3][2]));
                    ctx.closePath();
                    ctx.fill();
                }
            }
        }
    }

    var rocketFins = function(sizeXZ, sizeY){

        var points = [ ];
        var rotate = new Model3DManager(points);
        var nOf = 4; //numero de empenas

        for(var i=0; i<nOf; i++){

            //sempre jogar 1 ponto a mais do que será plotado
            points.push([sizeXZ, -sizeY*0.65, sizeXZ]);
            points.push([sizeXZ, -sizeY*0.95, sizeXZ]);
            points.push([sizeXZ*3, -sizeY*0.9, sizeXZ*3]);
            points.push([sizeXZ*3, -sizeY*0.75, sizeXZ*3]);
            rotate.rotateY(6.283/nOf, points);
        }

        return {
            rotateX : function(theta){
                rotate.rotateX(theta);
            },
            rotateY : function(theta){
                rotate.rotateY(theta);
            },
            rotateZ : function(theta){
                rotate.rotateZ(theta);
            },
            draw : function(){

				//FOV
				var fov = 750;

                ctx.fillStyle = '#000000';

                for (var i=0; i<nOf; i++){
                    ctx.beginPath();
                    ctx.moveTo(points[i*nOf][0]*fov/(fov+points[i*nOf][2]), points[i*nOf][1]*fov/(fov+points[i*nOf][2]));
                    ctx.lineTo(points[(i*nOf)+1][0]*fov/(fov+points[(i*nOf)+1][2]), points[(i*nOf)+1][1]*fov/(fov+points[(i*nOf)+1][2]));
                    ctx.lineTo(points[(i*nOf)+2][0]*fov/(fov+points[(i*nOf)+2][2]), points[(i*nOf)+2][1]*fov/(fov+points[(i*nOf)+2][2]));
                    ctx.lineTo(points[(i*nOf)+3][0]*fov/(fov+points[(i*nOf)+3][2]), points[(i*nOf)+3][1]*fov/(fov+points[(i*nOf)+3][2]));
                    ctx.closePath();
                    ctx.stroke();
                    ctx.fill();
                }
            }
        }
    }

    //guardar o modelo
    var rocketModel = [
        new rocketBody(sizeX, sizeY),
        new rocketFins(sizeX, sizeY)
    ];

    return {
        draw : function(){
            for (var i=0; i<rocketModel.length; i++){
                rocketModel[i].draw(); //desenha cada componente
            }
        },
        rotate : function(xRad, yRad, zRad){
            //distribui a rotação para cada componente
            for (var i=0; i<rocketModel.length; i++){
                rocketModel[i].rotateX(xRad);
                rocketModel[i].rotateY(yRad);
                rocketModel[i].rotateZ(zRad);
            }
        }
    }
}

//CONTROLE DE ANIMAÇÃO DO GIROSCÓPIO--------------------------------------------
function gyro_rotate_animation(boitata, line){
	//função que gera a animação de rotação.
    ctx.clearRect(-ctx.canvas.width/2, -ctx.canvas.height/2, ctx.canvas.width, ctx.canvas.height);

    ctx.font = '20pt Calibri';
    ctx.fillStyle = 'black';
    ctx.fillText(line[0], -ctx.canvas.width/2 + 50, -ctx.canvas.height/2 + 50);
    ctx.fillText(line[1], -ctx.canvas.width/2 + 50, -ctx.canvas.height/2 + 100);
    ctx.fillText(line[2], -ctx.canvas.width/2 + 50, -ctx.canvas.height/2 + 150);

    boitata.rotate(line[0], line[1], line[2]);
    boitata.draw();
}

function gyro_noData_animation(boitata){
    ctx.clearRect(-ctx.canvas.width/2, -ctx.canvas.height/2, ctx.canvas.width, ctx.canvas.height);

    boitata.rotate(-0.005, -0.005, -0.005);
    boitata.draw();

    ctx.font = '60pt Calibri';
    ctx.textAlign = 'center';
    ctx.fillStyle = 'black';
    ctx.fillText('NO DATA FOUND', 0, 0);
}

//"MAIN" DO ANALISADOR GYRO-----------------------------------------------------
function setup_gyro(){
    delete canvas;
    canvas = document.getElementById("gyro_canvas");

    //configurando o canvas
	ctx = canvas.getContext("2d");
	ctx.canvas.width  = window.innerWidth;
    ctx.canvas.height = window.innerHeight;
    ctx.globalAlpha = 0.8;
    ctx.translate(ctx.canvas.width/2,ctx.canvas.height/2);

    //rotacionar pois o canvas é invertido e o boitata é criado de ponta
    //cabeça
    var boitata = new rocket(15, 225, 15);
    boitata.rotate(3.14159, 0, 0);

    clearInterval(animation);

    if (lines.length==0){

        animation = setInterval(function(){
            gyro_noData_animation(boitata);
        }, 10);
    }
    else {

        var i=0;

        (function Rotate_animation(){
            if (i!=lines.length) {
                gyro_rotate_animation(boitata, lines[i++]);
                animation = setTimeout(Rotate_animation, 50);
            }
            else {
                ctx.font = '60pt Calibri';
                ctx.textAlign = 'center';
                ctx.fillStyle = 'black';
                ctx.fillText('END OF INPUT', 0, 0);
            }
        })();
    }
}
<commit_msg>Mudança na animação sem data<commit_after>//rocketLabGyro.js
//extensão do gyro

//VARIÁVEIS GLOBAIS-------------------------------------------------------------
var canvas;
var ctx;
var animation;

//FOGUETUINHO-------------------------------------------------------------------
var rocket = function(sizeX, sizeY, sizeZ){

    //classe que rotaciona pontos 3d internamente, um tipo de "herança"
    //feita na força da gambiarra
    var Model3DManager = function(points){

        return{
            rotateX : function (theta){
                //funçao que rotaciona todos os pontos em torno do eixo X;

                var cos = Math.cos(theta);
                var sin = Math.sin(theta);

                for (var i=0; i<points.length; i++){
                    nodeY = points[i][1];
                    nodeZ = points[i][2];

                    points[i][1] = (cos*nodeY) - (sin*nodeZ);
                    points[i][2] = (cos*nodeZ) + (sin*nodeY);
                }
            },

            rotateY : function(theta){
                //funçao que rotaciona todos os pontos em torno do eixo Y;

                var cos = Math.cos(theta);
                var sin = Math.sin(theta);

                for (var i=0; i<points.length; i++){
                    nodeX = points[i][0];
                    nodeZ = points[i][2];

                    points[i][0] = (cos*nodeX) - (sin*nodeZ);
                    points[i][2] = (cos*nodeZ) + (sin*nodeX);
                }
            },

            rotateZ : function(theta){
                //funçao que rotaciona todos os pontos em torno do eixo Z;

                var cos = Math.cos(theta);
                var sin = Math.sin(theta);

                for (var i=0; i<points.length; i++){
                    nodeX = points[i][0];
                    nodeY = points[i][1];

                    points[i][0] = (cos*nodeX) - (sin*nodeY);
                    points[i][1] = (cos*nodeY) + (sin*nodeX);
                }
            }
        }
    }

    //corpo do boitatá
    var rocketBody = function(sizeXZ, sizeY){

        //MÁGICA. NÃO TOQUE. NÃO OLHE. NÃO TENTE ENTENDER

        var points = [ ];
        var rotate = new Model3DManager(points);
        var pl = 16; //numero de poligonos

        //fazer um cilindro com pontos (lembrando que y cresce de cima para
        //baixo)
        for(var i=0; i<(pl/2)+1; i++){
            points.push([sizeXZ, -sizeY, sizeXZ]);
            points.push([sizeXZ, sizeY, sizeXZ]);
            rotate.rotateY((6.283/pl)*2, points);
        }
        //ponto para ser o bico da coifa do foguete
        points.push([0, sizeY*1.45, 0]);

        return {
            rotateX : function(theta){
                rotate.rotateX(theta);
            },
            rotateY : function(theta){
                rotate.rotateY(theta);
            },
            rotateZ : function(theta){
                rotate.rotateZ(theta);
            },
            draw : function(){
                //desenha o cilindro de cor laranja (transparente).

                var fov = 750;

                //desenha todos os retangulos
                for (var i=0; i<pl-1; i=i+2){
                    ctx.fillStyle = '#cc8d06'; //fov/(fov+points[i][2]);
                    ctx.beginPath();
                    ctx.moveTo(points[i][0]*fov/(fov+points[i][2]), points[i][1]*fov/(fov+points[i][2]));
                    ctx.lineTo(points[i+1][0]*fov/(fov+points[i+1][2]), points[i+1][1]*fov/(fov+points[i+1][2]));
                    ctx.lineTo(points[i+3][0]*fov/(fov+points[i+3][2]), points[i+3][1]*fov/(fov+points[i+3][2]));
                    ctx.lineTo(points[i+2][0]*fov/(fov+points[i+2][2]), points[i+2][1]*fov/(fov+points[i+2][2]));
                    ctx.closePath();
                    ctx.fill();
                }
                for(var i=0; i<pl-1; i=i+2){ //coifa
                    ctx.fillStyle = '#000000';
                    ctx.beginPath();
                    ctx.moveTo(points[i+1][0]*fov/(fov+points[i+1][2]), points[i+1][1]*fov/(fov+points[i+1][2]));
                    ctx.lineTo(points[points.length-1][0]*fov/(fov+points[points.length-1][2]), points[points.length-1][1]*fov/(fov+points[points.length-1][2]));
                    ctx.lineTo(points[i+3][0]*fov/(fov+points[i+3][2]), points[i+3][1]*fov/(fov+points[i+3][2]));
                    ctx.closePath();
                    ctx.fill();
                }
            }
        }
    }

    var rocketFins = function(sizeXZ, sizeY){

        var points = [ ];
        var rotate = new Model3DManager(points);
        var nOf = 4; //numero de empenas

        for(var i=0; i<nOf; i++){

            //sempre jogar 1 ponto a mais do que será plotado
            points.push([sizeXZ, -sizeY*0.65, sizeXZ]);
            points.push([sizeXZ, -sizeY*0.95, sizeXZ]);
            points.push([sizeXZ*3, -sizeY*0.9, sizeXZ*3]);
            points.push([sizeXZ*3, -sizeY*0.75, sizeXZ*3]);
            rotate.rotateY(6.283/nOf, points);
        }

        return {
            rotateX : function(theta){
                rotate.rotateX(theta);
            },
            rotateY : function(theta){
                rotate.rotateY(theta);
            },
            rotateZ : function(theta){
                rotate.rotateZ(theta);
            },
            draw : function(){

				//FOV
				var fov = 750;

                ctx.fillStyle = '#000000';

                for (var i=0; i<nOf; i++){
                    ctx.beginPath();
                    ctx.moveTo(points[i*nOf][0]*fov/(fov+points[i*nOf][2]), points[i*nOf][1]*fov/(fov+points[i*nOf][2]));
                    ctx.lineTo(points[(i*nOf)+1][0]*fov/(fov+points[(i*nOf)+1][2]), points[(i*nOf)+1][1]*fov/(fov+points[(i*nOf)+1][2]));
                    ctx.lineTo(points[(i*nOf)+2][0]*fov/(fov+points[(i*nOf)+2][2]), points[(i*nOf)+2][1]*fov/(fov+points[(i*nOf)+2][2]));
                    ctx.lineTo(points[(i*nOf)+3][0]*fov/(fov+points[(i*nOf)+3][2]), points[(i*nOf)+3][1]*fov/(fov+points[(i*nOf)+3][2]));
                    ctx.closePath();
                    ctx.stroke();
                    ctx.fill();
                }
            }
        }
    }

    //guardar o modelo
    var rocketModel = [
        new rocketBody(sizeX, sizeY),
        new rocketFins(sizeX, sizeY)
    ];

    return {
        draw : function(){
            for (var i=0; i<rocketModel.length; i++){
                rocketModel[i].draw(); //desenha cada componente
            }
        },
        rotate : function(xRad, yRad, zRad){
            //distribui a rotação para cada componente
            for (var i=0; i<rocketModel.length; i++){
                rocketModel[i].rotateX(xRad);
                rocketModel[i].rotateY(yRad);
                rocketModel[i].rotateZ(zRad);
            }
        }
    }
}

//CONTROLE DE ANIMAÇÃO DO GIROSCÓPIO--------------------------------------------
function gyro_rotate_animation(boitata, line){
	//função que gera a animação de rotação.
    ctx.clearRect(-ctx.canvas.width/2, -ctx.canvas.height/2, ctx.canvas.width, ctx.canvas.height);

    ctx.font = '20pt Calibri';
    ctx.fillStyle = 'black';
    ctx.fillText(line[0], -ctx.canvas.width/2 + 50, -ctx.canvas.height/2 + 50);
    ctx.fillText(line[1], -ctx.canvas.width/2 + 50, -ctx.canvas.height/2 + 100);
    ctx.fillText(line[2], -ctx.canvas.width/2 + 50, -ctx.canvas.height/2 + 150);

    boitata.rotate(line[0], line[1], line[2]);
    boitata.draw();
}

function gyro_noData_animation(boitata){
    ctx.clearRect(-ctx.canvas.width/2, -ctx.canvas.height/2, ctx.canvas.width, ctx.canvas.height);

    boitata.rotate(0, 0.005, -0.000);
    boitata.draw();

    ctx.font = '60pt Calibri';
    ctx.textAlign = 'center';
    ctx.fillStyle = 'black';
    ctx.fillText('NO DATA FOUND', 0, 0);
}

//"MAIN" DO ANALISADOR GYRO-----------------------------------------------------
function setup_gyro(){
    delete canvas;
    canvas = document.getElementById("gyro_canvas");

    //configurando o canvas
	ctx = canvas.getContext("2d");
	ctx.canvas.width  = window.innerWidth;
    ctx.canvas.height = window.innerHeight;
    ctx.globalAlpha = 0.8;
    ctx.translate(ctx.canvas.width/2,ctx.canvas.height/2);

    //rotacionar pois o canvas é invertido e o boitata é criado de ponta
    //cabeça
    var boitata = new rocket(15, 225, 15);
    boitata.rotate(3.14159, 0, 0);

    clearInterval(animation);

    if (lines.length==0){
        boitata.rotate(1.2, 0, 0);
        animation = setInterval(function(){
            gyro_noData_animation(boitata);
        }, 10);
    }
    else {

        var i=0;

        (function Rotate_animation(){
            if (i!=lines.length) {
                gyro_rotate_animation(boitata, lines[i++]);
                animation = setTimeout(Rotate_animation, 50);
            }
            else {
                ctx.font = '60pt Calibri';
                ctx.textAlign = 'center';
                ctx.fillStyle = 'black';
                ctx.fillText('END OF INPUT', 0, 0);
            }
        })();
    }
}
<|endoftext|>