<commit_before>/******************************************
 *               TxtFX Bot                *
 *         Created by Evan Straw          *
 * Applies various Unicode alphabet and   *
 * pseudoalphabet effects to text         *
 * inputted via Telegram.                 *
 *                                        *
 * This code is under the MIT License     *
 * (see LICENSE)                          *
 *******************************************/

//require the colors library for colorful output text
var colors = require("colors");
//require logutil.js
var logutil = require("./logutil.js");
//require the log function (see logutils.js)
var log = logutil.log;
var exit = logutil.exit;
var levels = logutil.levels;
log("Program start!",levels.info);
log("Importing libraries...",levels.info);
var TelegramBot = require("node-telegram-bot-api");

//constant to hold the usage message (will be displayed if the user gets one of the arguments wrong)
//The arguments required for the program right now are:
// 1. The node command
// 2. The name of the program ("txtfxbot.js")
// 3. The key for the Telegram Bot API
const usage = "node txtfxbot.js <Telegram Bot API key>"

//object that holds the alphabet mappings.
//all the printing ASCII characters (ASCII codes 32-126) are mapped by code to the Unicode character equivalent.
//  for example: in the "circled" pseudoalphabet, character code 65 ('A') is mapped to 'Ⓐ'
//also contains some extra info about the alphabet
//structure:
//alphabetMap
//|-rtl: whether or not the text should be reversed. Unsure at this point whether to use an RTL character or just print the text in reverse order. Probably will go with the latter, RTLs tend to be annoying to some users
//|-alphabet: the actual alphabet mapping
//  |-character code
//    |- alphabet equivalent
const alphabetMap = {
	normalASCII: {rtl: false, alphabet:{32:' ', 33:'!', 34:'"', 35:'#', 36:'$', 37:'%', 38:'&', 39:"'", 40:'(', 41:')', 42:'*', 43:'+', 44:',', 45:'-', 46:'.', 47:'/', 48:'0', 49:'1', 50:'2', 51:'3', 52:'4', 53:'5', 54:'6', 55:'7', 56:'8', 57:'9', 58:':', 59:';', 60:'<', 61:'=', 62:'>', 63:'?', 64:'@', 65:'A', 66:'B', 67:'C', 68:'D', 69:'E', 70:'F', 71:'G', 72:'H', 73:'I', 74:'J', 75:'K', 76:'L', 77:'M', 78:'N', 79:'O', 80:'P', 81:'Q', 82:'R', 83:'S', 84:'T', 85:'U', 86:'V', 87:'W', 88:'X', 89:'Y', 90:'Z', 91:'[', 92:'\\', 93:']', 94:'^', 95:'_', 96:'`', 97:'a', 98:'b', 99:'c', 100:'d', 101:'e', 102:'f', 103:'g', 104:'h', 105:'i', 106:'j', 107:'k', 108:'l', 109:'m', 110:'n', 111:'o', 112:'p', 113:'q', 114:'r', 115:'s', 116:'t', 117:'u', 118:'v', 119:'w', 120:'x', 121:'y', 122:'z', 123:'{', 124:'|', 125:'}', 126:'~'}},
	circled: {rtl: false, alphabet:{32:' ', 33:'!', 34:'\"', 35:'#', 36:'$', 37:'%', 38:'&', 39:'\'', 40:'(', 41:')', 42:'⊛', 43:'⊕', 44:',', 45:'⊖', 46:'⨀', 47:'⊘', 48:'0', 49:'①', 50:'②', 51:'③', 52:'④', 53:'⑤', 54:'⑥', 55:'⑦', 56:'⑧', 57:'⑨', 58:':', 59:';', 60:'⧀', 61:'⊜', 62:'⧁', 63:'?', 64:'@', 65:'Ⓐ', 66:'Ⓑ', 67:'Ⓒ', 68:'Ⓓ', 69:'Ⓔ', 70:'Ⓕ', 71:'Ⓖ', 72:'Ⓗ', 73:'Ⓘ', 74:'Ⓙ', 75:'Ⓚ', 76:'Ⓛ', 77:'Ⓜ', 78:'Ⓝ', 79:'Ⓞ', 80:'Ⓟ', 81:'Ⓠ', 82:'Ⓡ', 83:'Ⓢ', 84:'Ⓣ', 85:'Ⓤ', 86:'Ⓥ', 87:'Ⓦ', 88:'Ⓧ', 89:'Ⓨ', 90:'Ⓩ', 91:'[', 92:'⦸', 93:']', 94:'^', 95:'_', 96:'`', 97:'ⓐ', 98:'ⓑ', 99:'ⓒ', 100:'ⓓ', 101:'ⓔ', 102:'ⓕ', 103:'ⓖ', 104:'ⓗ', 105:'ⓘ', 106:'ⓙ', 107:'ⓚ', 108:'ⓛ', 109:'ⓜ', 110:'ⓝ', 111:'ⓞ', 112:'ⓟ', 113:'ⓠ', 114:'ⓡ', 115:'ⓢ', 116:'ⓣ', 117:'ⓤ', 118:'ⓥ', 119:'ⓦ', 120:'ⓧ', 121:'ⓨ', 122:'ⓩ', 123:'{', 124:'⦶', 125:'}', 126:'~'}},
	fullwidth: {rtl: false, alphabet:{32:' ', 33:'！', 34:'\"', 35:'＃', 36:'＄', 37:'％', 38:'＆', 39:'＇', 40:'（', 41:'）', 42:'＊', 43:'＋', 44:'，', 45:'－', 46:'．', 47:'／', 48:'０', 49:'１', 50:'２', 51:'３', 52:'４', 53:'５', 54:'６', 55:'７', 56:'８', 57:'９', 58:'：', 59:'；', 60:'<', 61:'＝', 62:'>', 63:'？', 64:'＠', 65:'Ａ', 66:'Ｂ', 67:'Ｃ', 68:'Ｄ', 69:'Ｅ', 70:'Ｆ', 71:'Ｇ', 72:'Ｈ', 73:'Ｉ', 74:'Ｊ', 75:'Ｋ', 76:'Ｌ', 77:'Ｍ', 78:'Ｎ', 79:'Ｏ', 80:'Ｐ', 81:'Ｑ', 82:'Ｒ', 83:'Ｓ', 84:'Ｔ', 85:'Ｕ', 86:'Ｖ', 87:'Ｗ', 88:'Ｘ', 89:'Ｙ', 90:'Ｚ', 91:'[', 92:'\\', 93:']', 94:'^', 95:'_', 96:'`', 97:'ａ', 98:'ｂ', 99:'ｃ', 100:'ｄ', 101:'ｅ', 102:'ｆ', 103:'ｇ', 104:'ｈ', 105:'ｉ', 106:'ｊ', 107:'ｋ', 108:'ｌ', 109:'ｍ', 110:'ｎ', 111:'ｏ', 112:'ｐ', 113:'ｑ', 114:'ｒ', 115:'ｓ', 116:'ｔ', 117:'ｕ', 118:'ｖ', 119:'ｗ', 120:'ｘ', 121:'ｙ', 122:'ｚ', 123:'{', 124:'|', 125:'}', 126:'~'}},
    //will add more later, just have these for now
}

checkArguments();

//Check the command line arguments
//returns true if all required arguments are present (NOTE: doesn't actually check if they're valid)
//if some are missing, the program will exit
function checkArguments(){
	var args = process.argv
	if(args.length < 3)
	{
		log("Missing arguments!",levels.err);
		log("Usage: "+usage,levels.err);
		exit(1)
	}
	return true;
}

function startTelegram(){

}<commit_msg>Continued work on main program body<commit_after>/******************************************
 *               TxtFX Bot                *
 *         Created by Evan Straw          *
 * Applies various Unicode alphabet and   *
 * pseudoalphabet effects to text         *
 * inputted via Telegram.                 *
 *                                        *
 * This code is under the MIT License     *
 * (see LICENSE)                          *
 *******************************************/

//require the colors library for colorful output text
var colors = require("colors");
//require logutil.js
var logutil = require("./logutil.js");
//require the log function (see logutils.js)
var log = logutil.log;
var exit = logutil.exit;
var levels = logutil.levels;
log("Program start!",levels.info);
log("Importing libraries...",levels.info);
var TelegramBot = require("node-telegram-bot-api");

//Start the actual program
//check command line arguments
checkArguments();
//variable to hold the API key
var key = process.argv[2];
//start telegram functions (tests key)
log("Starting Telegram Bot...",levels.info);
startTelegram();

//variable to hold the bot instance once it is created
var bot = {};
//variable to hold the bot information
var me = {};

//constant to hold the usage message (will be displayed if the user gets one of the arguments wrong)
//The arguments required for the program right now are:
// 1. The node command
// 2. The name of the program ("txtfxbot.js")
// 3. The key for the Telegram Bot API
const usage = "node txtfxbot.js <Telegram Bot API key>"

//object that holds the alphabet mappings.
//all the printing ASCII characters (ASCII codes 32-126) are mapped by code to the Unicode character equivalent.
//  for example: in the "circled" pseudoalphabet, character code 65 ('A') is mapped to 'Ⓐ'
//also contains some extra info about the alphabet
//structure:
//alphabetMap
//|-rtl: whether or not the text should be reversed. Unsure at this point whether to use an RTL character or just print the text in reverse order. Probably will go with the latter, RTLs tend to be annoying to some users
//|-alphabet: the actual alphabet mapping
//  |-character code
//    |- alphabet equivalent
const alphabetMap = {
	normalASCII: {rtl: false, alphabet:{32:' ', 33:'!', 34:'"', 35:'#', 36:'$', 37:'%', 38:'&', 39:"'", 40:'(', 41:')', 42:'*', 43:'+', 44:',', 45:'-', 46:'.', 47:'/', 48:'0', 49:'1', 50:'2', 51:'3', 52:'4', 53:'5', 54:'6', 55:'7', 56:'8', 57:'9', 58:':', 59:';', 60:'<', 61:'=', 62:'>', 63:'?', 64:'@', 65:'A', 66:'B', 67:'C', 68:'D', 69:'E', 70:'F', 71:'G', 72:'H', 73:'I', 74:'J', 75:'K', 76:'L', 77:'M', 78:'N', 79:'O', 80:'P', 81:'Q', 82:'R', 83:'S', 84:'T', 85:'U', 86:'V', 87:'W', 88:'X', 89:'Y', 90:'Z', 91:'[', 92:'\\', 93:']', 94:'^', 95:'_', 96:'`', 97:'a', 98:'b', 99:'c', 100:'d', 101:'e', 102:'f', 103:'g', 104:'h', 105:'i', 106:'j', 107:'k', 108:'l', 109:'m', 110:'n', 111:'o', 112:'p', 113:'q', 114:'r', 115:'s', 116:'t', 117:'u', 118:'v', 119:'w', 120:'x', 121:'y', 122:'z', 123:'{', 124:'|', 125:'}', 126:'~'}},
	circled: {rtl: false, alphabet:{32:' ', 33:'!', 34:'\"', 35:'#', 36:'$', 37:'%', 38:'&', 39:'\'', 40:'(', 41:')', 42:'⊛', 43:'⊕', 44:',', 45:'⊖', 46:'⨀', 47:'⊘', 48:'0', 49:'①', 50:'②', 51:'③', 52:'④', 53:'⑤', 54:'⑥', 55:'⑦', 56:'⑧', 57:'⑨', 58:':', 59:';', 60:'⧀', 61:'⊜', 62:'⧁', 63:'?', 64:'@', 65:'Ⓐ', 66:'Ⓑ', 67:'Ⓒ', 68:'Ⓓ', 69:'Ⓔ', 70:'Ⓕ', 71:'Ⓖ', 72:'Ⓗ', 73:'Ⓘ', 74:'Ⓙ', 75:'Ⓚ', 76:'Ⓛ', 77:'Ⓜ', 78:'Ⓝ', 79:'Ⓞ', 80:'Ⓟ', 81:'Ⓠ', 82:'Ⓡ', 83:'Ⓢ', 84:'Ⓣ', 85:'Ⓤ', 86:'Ⓥ', 87:'Ⓦ', 88:'Ⓧ', 89:'Ⓨ', 90:'Ⓩ', 91:'[', 92:'⦸', 93:']', 94:'^', 95:'_', 96:'`', 97:'ⓐ', 98:'ⓑ', 99:'ⓒ', 100:'ⓓ', 101:'ⓔ', 102:'ⓕ', 103:'ⓖ', 104:'ⓗ', 105:'ⓘ', 106:'ⓙ', 107:'ⓚ', 108:'ⓛ', 109:'ⓜ', 110:'ⓝ', 111:'ⓞ', 112:'ⓟ', 113:'ⓠ', 114:'ⓡ', 115:'ⓢ', 116:'ⓣ', 117:'ⓤ', 118:'ⓥ', 119:'ⓦ', 120:'ⓧ', 121:'ⓨ', 122:'ⓩ', 123:'{', 124:'⦶', 125:'}', 126:'~'}},
	fullwidth: {rtl: false, alphabet:{32:' ', 33:'！', 34:'\"', 35:'＃', 36:'＄', 37:'％', 38:'＆', 39:'＇', 40:'（', 41:'）', 42:'＊', 43:'＋', 44:'，', 45:'－', 46:'．', 47:'／', 48:'０', 49:'１', 50:'２', 51:'３', 52:'４', 53:'５', 54:'６', 55:'７', 56:'８', 57:'９', 58:'：', 59:'；', 60:'<', 61:'＝', 62:'>', 63:'？', 64:'＠', 65:'Ａ', 66:'Ｂ', 67:'Ｃ', 68:'Ｄ', 69:'Ｅ', 70:'Ｆ', 71:'Ｇ', 72:'Ｈ', 73:'Ｉ', 74:'Ｊ', 75:'Ｋ', 76:'Ｌ', 77:'Ｍ', 78:'Ｎ', 79:'Ｏ', 80:'Ｐ', 81:'Ｑ', 82:'Ｒ', 83:'Ｓ', 84:'Ｔ', 85:'Ｕ', 86:'Ｖ', 87:'Ｗ', 88:'Ｘ', 89:'Ｙ', 90:'Ｚ', 91:'[', 92:'\\', 93:']', 94:'^', 95:'_', 96:'`', 97:'ａ', 98:'ｂ', 99:'ｃ', 100:'ｄ', 101:'ｅ', 102:'ｆ', 103:'ｇ', 104:'ｈ', 105:'ｉ', 106:'ｊ', 107:'ｋ', 108:'ｌ', 109:'ｍ', 110:'ｎ', 111:'ｏ', 112:'ｐ', 113:'ｑ', 114:'ｒ', 115:'ｓ', 116:'ｔ', 117:'ｕ', 118:'ｖ', 119:'ｗ', 120:'ｘ', 121:'ｙ', 122:'ｚ', 123:'{', 124:'|', 125:'}', 126:'~'}},
    //will add more later, just have these for now
}

//Check the command line arguments
//returns true if all required arguments are present (NOTE: doesn't actually check if they're valid)
//if some are missing, the program will exit
function checkArguments(){
	var args = process.argv
	if(args.length < 3)
	{
		log("Missing arguments!",levels.err);
		log("Usage: "+usage,levels.err);
		exit(1)
	}
	return true;
}

function startTelegram(){
  bot = new TelegramBot(key+"a");//,{polling:true});
  me = bot.getMe();
  log("Telegram Bot successfully started!",levels.info);
}<|endoftext|>


<commit_before>odoo.define('web.field_registry', function (require) {
"use strict";

var Registry = require('web.Registry');

return new Registry();
});

odoo.define('web._field_registry', function(require) {
"use strict";

var AbstractField = require('web.AbstractField');
var basic_fields = require('web.basic_fields');
var relational_fields = require('web.relational_fields');
var registry = require('web.field_registry');
var special_fields = require('web.special_fields');

// Basic fields
registry
    .add('abstract', AbstractField)
    .add('input', basic_fields.InputField)
    .add('integer', basic_fields.FieldInteger)
    .add('boolean', basic_fields.FieldBoolean)
    .add('date', basic_fields.FieldDate)
    .add('datetime', basic_fields.FieldDateTime)
    .add('domain', basic_fields.FieldDomain)
    .add('text', basic_fields.FieldText)
    .add('html', basic_fields.FieldText)
    .add('float', basic_fields.FieldFloat)
    .add('char', basic_fields.FieldChar)
    .add('link_button', basic_fields.LinkButton)
    .add('handle', basic_fields.HandleWidget)
    .add('email', basic_fields.FieldEmail)
    .add('phone', basic_fields.FieldPhone)
    .add('url', basic_fields.UrlWidget)
    .add('CopyClipboardText', basic_fields.TextCopyClipboard)
    .add('CopyClipboardChar', basic_fields.CharCopyClipboard)
    .add('image', basic_fields.FieldBinaryImage)
    .add('signature', basic_fields.FieldBinarySignature)
    .add('binary', basic_fields.FieldBinaryFile)
    .add('pdf_viewer', basic_fields.FieldPdfViewer)
    .add('monetary', basic_fields.FieldMonetary)
    .add('percentage', basic_fields.FieldPercentage)
    .add('priority', basic_fields.PriorityWidget)
    .add('attachment_image', basic_fields.AttachmentImage)
    .add('label_selection', basic_fields.LabelSelection)
    .add('state_selection', basic_fields.StateSelectionWidget)
    .add('kanban_state_selection', basic_fields.StateSelectionWidget)
    .add('boolean_favorite', basic_fields.FavoriteWidget)
    .add('boolean_button', basic_fields.FieldBooleanButton)
    .add('boolean_toggle', basic_fields.BooleanToggle)
    .add('statinfo', basic_fields.StatInfo)
    .add('percentpie', basic_fields.FieldPercentPie)
    .add('float_time', basic_fields.FieldFloatTime)
    .add('float_factor', basic_fields.FieldFloatFactor)
    .add('float_toggle', basic_fields.FieldFloatToggle)
    .add('progressbar', basic_fields.FieldProgressBar)
    .add('toggle_button', basic_fields.FieldToggleBoolean)
    .add('dashboard_graph', basic_fields.JournalDashboardGraph)
    .add('ace', basic_fields.AceEditor);

// Relational fields
registry
    .add('selection', relational_fields.FieldSelection)
    .add('radio', relational_fields.FieldRadio)
    .add('selection_badge', relational_fields.FieldSelectionBadge)
    .add('many2one', relational_fields.FieldMany2One)
    .add('many2one_barcode', relational_fields.FieldMany2One)
    .add('list.many2one', relational_fields.ListFieldMany2One)
    .add('kanban.many2one', relational_fields.KanbanFieldMany2One)
    .add('many2many', relational_fields.FieldMany2Many)
    .add('many2many_binary', relational_fields.FieldMany2ManyBinaryMultiFiles)
    .add('many2many_tags', relational_fields.FieldMany2ManyTags)
    .add('form.many2many_tags', relational_fields.FormFieldMany2ManyTags)
    .add('kanban.many2many_tags', relational_fields.KanbanFieldMany2ManyTags)
    .add('many2many_checkboxes', relational_fields.FieldMany2ManyCheckBoxes)
    .add('one2many', relational_fields.FieldOne2Many)
    .add('statusbar', relational_fields.FieldStatus)
    .add('reference', relational_fields.FieldReference)
    .add('one2many_list', relational_fields.FieldOne2Many);

// Special fields
registry
    .add('timezone_mismatch', special_fields.FieldTimezoneMismatch)
    .add('report_layout', special_fields.FieldReportLayout);
});
<commit_msg>[FIX] web: remove duplicated entry in field_registry<commit_after>odoo.define('web.field_registry', function (require) {
"use strict";

var Registry = require('web.Registry');

return new Registry();
});

odoo.define('web._field_registry', function(require) {
"use strict";

var AbstractField = require('web.AbstractField');
var basic_fields = require('web.basic_fields');
var relational_fields = require('web.relational_fields');
var registry = require('web.field_registry');
var special_fields = require('web.special_fields');

// Basic fields
registry
    .add('abstract', AbstractField)
    .add('input', basic_fields.InputField)
    .add('integer', basic_fields.FieldInteger)
    .add('boolean', basic_fields.FieldBoolean)
    .add('date', basic_fields.FieldDate)
    .add('datetime', basic_fields.FieldDateTime)
    .add('domain', basic_fields.FieldDomain)
    .add('text', basic_fields.FieldText)
    .add('html', basic_fields.FieldText)
    .add('float', basic_fields.FieldFloat)
    .add('char', basic_fields.FieldChar)
    .add('link_button', basic_fields.LinkButton)
    .add('handle', basic_fields.HandleWidget)
    .add('email', basic_fields.FieldEmail)
    .add('phone', basic_fields.FieldPhone)
    .add('url', basic_fields.UrlWidget)
    .add('CopyClipboardText', basic_fields.TextCopyClipboard)
    .add('CopyClipboardChar', basic_fields.CharCopyClipboard)
    .add('image', basic_fields.FieldBinaryImage)
    .add('binary', basic_fields.FieldBinaryFile)
    .add('pdf_viewer', basic_fields.FieldPdfViewer)
    .add('monetary', basic_fields.FieldMonetary)
    .add('percentage', basic_fields.FieldPercentage)
    .add('priority', basic_fields.PriorityWidget)
    .add('attachment_image', basic_fields.AttachmentImage)
    .add('label_selection', basic_fields.LabelSelection)
    .add('state_selection', basic_fields.StateSelectionWidget)
    .add('kanban_state_selection', basic_fields.StateSelectionWidget)
    .add('boolean_favorite', basic_fields.FavoriteWidget)
    .add('boolean_button', basic_fields.FieldBooleanButton)
    .add('boolean_toggle', basic_fields.BooleanToggle)
    .add('statinfo', basic_fields.StatInfo)
    .add('percentpie', basic_fields.FieldPercentPie)
    .add('float_time', basic_fields.FieldFloatTime)
    .add('float_factor', basic_fields.FieldFloatFactor)
    .add('float_toggle', basic_fields.FieldFloatToggle)
    .add('progressbar', basic_fields.FieldProgressBar)
    .add('toggle_button', basic_fields.FieldToggleBoolean)
    .add('dashboard_graph', basic_fields.JournalDashboardGraph)
    .add('ace', basic_fields.AceEditor);

// Relational fields
registry
    .add('selection', relational_fields.FieldSelection)
    .add('radio', relational_fields.FieldRadio)
    .add('selection_badge', relational_fields.FieldSelectionBadge)
    .add('many2one', relational_fields.FieldMany2One)
    .add('many2one_barcode', relational_fields.FieldMany2One)
    .add('list.many2one', relational_fields.ListFieldMany2One)
    .add('kanban.many2one', relational_fields.KanbanFieldMany2One)
    .add('many2many', relational_fields.FieldMany2Many)
    .add('many2many_binary', relational_fields.FieldMany2ManyBinaryMultiFiles)
    .add('many2many_tags', relational_fields.FieldMany2ManyTags)
    .add('form.many2many_tags', relational_fields.FormFieldMany2ManyTags)
    .add('kanban.many2many_tags', relational_fields.KanbanFieldMany2ManyTags)
    .add('many2many_checkboxes', relational_fields.FieldMany2ManyCheckBoxes)
    .add('one2many', relational_fields.FieldOne2Many)
    .add('statusbar', relational_fields.FieldStatus)
    .add('reference', relational_fields.FieldReference)
    .add('one2many_list', relational_fields.FieldOne2Many);

// Special fields
registry
    .add('timezone_mismatch', special_fields.FieldTimezoneMismatch)
    .add('report_layout', special_fields.FieldReportLayout);
});
<|endoftext|>


<commit_before>require('fileapi');

var backbone = require('backbone');
var backboneBase = require('backbone-base');
var getUri = require('get-uri');
var Goodtables = require('goodtables');
var jsonEditor = require('json-editor');
var jtsInfer = require('jts-infer');
var highlight = require('highlight-redux');
var UploadView = require('./upload');
var registry = require('./registry');
var _ = require('underscore');
var $ = require('jquery');

// Upload data file and populate .resource array with item
DataUploadView = backbone.BaseView.extend({
  events: {
    // Set up and append .resources row
    'change [data-id=input]': function(E) {
      FileAPI.readAsText(FileAPI.getFiles(E.currentTarget)[0], (function (EV) {
        if(EV.type === 'load') {
          getUri(['data', EV.target.type, 'utf-8'].join(':') + ',' + EV.result, (function (E, R) {
            if(E) throw E;

            jtsInfer(R, (function(E, S, SR) {
              if(E) throw E;

              this.options.form.getEditor('root.resources').addRow({
                name: EV.target.name,
                path: EV.target.name,
                schema: S
              });

              // Save data source
              _.last(this.options.form.getEditor('root.resources').rows).dataSource = EV.result;
            }).bind(this));
          }).bind(this));
        } else if( EV.type ==='progress' ) {
          this.setProgress(EV.loaded/EV.total * 100);
        } else {
          this.setError('File upload failed');
        }

        this.$(E.currentTarget).val('');
      }).bind(this));
    },

    'click [data-id=upload-data-file]': function() { this.$('[data-id=input]').trigger('click'); }
  },

  render: function() {
    this.$el
      .append('<input data-id="input" type="file" accept="text/csv" style="display: none;">')

      .append(
        $(this.options.form.theme.getButton('Upload data file', '', 'Upload data file'))
          .attr('data-id', 'upload-data-file')
      );

    return this;
  },

  setError: function() { return this; },
  setProgress: function() { return this; }
});

module.exports = {
  DescriptorEditView: backbone.BaseView.extend({
    activate: function(state) {
      backbone.BaseView.prototype.activate.call(this, state);
      this.layout.upload.activate(state);
      return this;
    },

    events: {
      'click #validate-resources': function() {
        var goodTables = new Goodtables({method: 'post'});

        // Navigate to valifation results just once during series of API calls
        var navigateToResults = _.once(function(id) { window.ROUTER.navigate('/validation-results/' + id, {trigger: true}); });

        window.APP.layout.validationResultList.reset(new backbone.Collection());

        _.each(this.layout.form.getEditor('root.resources').rows, function(R) {
          // Goodtables schema format {fields: [{name:'colname'...},...]}
          // Example https://raw.githubusercontent.com/okfn/goodtables/master/examples/test_schema.json
          goodTables.run(R.dataSource, JSON.stringify({fields: _.map(R.schema.properties, function(V, K) {
              return _.extend(V, {name: K}) })}
          )).then(
            function(M) {
              // Validation completed
              window.APP.layout.validationResultList.collection
                .add(
                  M.isValid()
                    ? [{resource_id: R.key, result_message: 'Validation Success'}]
                    : M.getValidationErrors().map(function(E) { return _.extend(E, {resource_id: R.key}) })
                );

              // Navigate between resources in validation results
              window.APP.layout.validationResultList.layout.tabs.add(new backbone.Model({
                title: R.getValue().path,

                // .key is a unique property among all resources rows
                url: '/validation-results/' + R.key
              }));

              navigateToResults(R.key);
            }
          );
        });
      }
    },

    initialize: function(options) {
      highlight.configure({useBR: true});
      return backbone.BaseView.prototype.initialize.call(this, options);
    },

    render: function() {
      this.layout.upload = new UploadView({el: window.APP.$('#upload-data-package'), parent: this});
      this.layout.registryList = new registry.ListView({el: window.APP.$('#registry-list'), container: '[data-id=list-container]', parent: this});
      return this;
    },

    // Utility method to remove empty values from object recursive
    compactObject: function(data) {
      _.each(data, function(v, k) {
        if(_.isEmpty(v)) {
          delete data[k];
        } else if(_.isArray(v) || _.isObject(v)) {
          v = this.compactObject(v);

          if(_.isArray(v))
            v = _.compact(v);

          if(_.isEmpty(v))
            delete data[k];
          else data[k] = v;
        }
      }, this);

      return data;
    },

    getFilledValues: function() { return this.compactObject(this.layout.form.getValue()); },
    getValue: function () { return this.layout.form.getValue(); },
    hasChanges: function() { return Boolean(this.changed); },

    reset: function(schema) {
      var formData;

      // Clean up previous state
      if(this.layout.form) {
        formData = this.getFilledValues();
        this.layout.form.destroy();
        this.layout.uploadData.undelegateEvents().remove();
      }

      this.layout.form = new JSONEditor(this.$('[data-id=form-container]').get(0), {
        schema: schema,
        theme: 'bootstrap3'
      });

      this.layout.uploadData = (new DataUploadView({
        el: this.layout.form.theme.getHeaderButtonHolder(),
        form: this.layout.form,
        parent: this
      })).render();

      this.layout.form.on('ready', (function() {
        // There is no any good way to bind events to custom button or even add cutsom button
        $(this.layout.form.getEditor('root.resources').container)
          .children('h3').append(this.layout.uploadData.el);

        // Detecting changes
        this.changed = false;

        // After `ready` event fired, editor fire `change` event regarding to the initial changes
        this.layout.form.on('change', _.after(2, (function() {
          this.changed = true;
          window.APP.layout.download.reset(this.layout.form.getValue()).activate();
          this.showResult();
        }).bind(this)));

        // If on the previous form was entered values try to apply it to new form
        if(formData) {
          this.layout.form.setValue(_.extend({}, this.layout.form.getValue(formData), formData));

          // Expand editors if it have value
          _.each(this.$('[data-schemapath][data-schemapath!=root]:has(.json-editor-btn-collapse)'), function(E) {
              if(_.isEmpty(this.layout.form.getEditor($(E).data('schemapath')).getValue()))
                $(E).find('.json-editor-btn-collapse').click();
          }, this);
        } else
          // Collapse all
          this.$('.row .json-editor-btn-collapse').click();

      }).bind(this));
    },

    showResult: function() {
      $('#json-code').html(highlight.fixMarkup(
        highlight.highlight('json', JSON.stringify(this.layout.form.getValue(), undefined, 2)).value
      ));

      return this;
    }
  })
};
<commit_msg>Work with GoodTables grouped reports (#45)<commit_after>require('fileapi');

var backbone = require('backbone');
var backboneBase = require('backbone-base');
var getUri = require('get-uri');
var Goodtables = require('goodtables');
var jsonEditor = require('json-editor');
var jtsInfer = require('jts-infer');
var highlight = require('highlight-redux');
var UploadView = require('./upload');
var registry = require('./registry');
var _ = require('underscore');
var $ = require('jquery');

// Upload data file and populate .resource array with item
DataUploadView = backbone.BaseView.extend({
  events: {
    // Set up and append .resources row
    'change [data-id=input]': function(E) {
      FileAPI.readAsText(FileAPI.getFiles(E.currentTarget)[0], (function (EV) {
        if(EV.type === 'load') {
          getUri(['data', EV.target.type, 'utf-8'].join(':') + ',' + EV.result, (function (E, R) {
            if(E) throw E;

            jtsInfer(R, (function(E, S, SR) {
              if(E) throw E;

              this.options.form.getEditor('root.resources').addRow({
                name: EV.target.name,
                path: EV.target.name,
                schema: S
              });

              // Save data source
              _.last(this.options.form.getEditor('root.resources').rows).dataSource = EV.result;
            }).bind(this));
          }).bind(this));
        } else if( EV.type ==='progress' ) {
          this.setProgress(EV.loaded/EV.total * 100);
        } else {
          this.setError('File upload failed');
        }

        this.$(E.currentTarget).val('');
      }).bind(this));
    },

    'click [data-id=upload-data-file]': function() { this.$('[data-id=input]').trigger('click'); }
  },

  render: function() {
    this.$el
      .append('<input data-id="input" type="file" accept="text/csv" style="display: none;">')

      .append(
        $(this.options.form.theme.getButton('Upload data file', '', 'Upload data file'))
          .attr('data-id', 'upload-data-file')
      );

    return this;
  },

  setError: function() { return this; },
  setProgress: function() { return this; }
});

module.exports = {
  DescriptorEditView: backbone.BaseView.extend({
    activate: function(state) {
      backbone.BaseView.prototype.activate.call(this, state);
      this.layout.upload.activate(state);
      return this;
    },

    events: {
      'click #validate-resources': function() {
        var goodTables = new Goodtables({method: 'post', report_type: 'grouped'});

        // Navigate to valifation results just once during series of API calls
        var navigateToResults = _.once(function(id) { window.ROUTER.navigate('/validation-results/' + id, {trigger: true}); });

        window.APP.layout.validationResultList.reset(new backbone.Collection());

        _.each(this.layout.form.getEditor('root.resources').rows, function(R) {
          // Goodtables schema format {fields: [{name:'colname'...},...]}
          // Example https://raw.githubusercontent.com/okfn/goodtables/master/examples/test_schema.json
          goodTables.run(R.dataSource, JSON.stringify({fields: _.map(R.schema.properties, function(V, K) {
              return _.extend(V, {name: K}) })}
          )).then(
            function(M) {
              // Validation completed
              window.APP.layout.validationResultList.collection
                .add(
                  M.isValid()
                    ? [{resource_id: R.key, result_message: 'Validation Success'}]
                    : M.getValidationErrors().map(function(E) { return _.extend(E, {resource_id: R.key}) })
                );

              // Navigate between resources in validation results
              window.APP.layout.validationResultList.layout.tabs.add(new backbone.Model({
                title: R.getValue().path,

                // .key is a unique property among all resources rows
                url: '/validation-results/' + R.key
              }));

              navigateToResults(R.key);
            }
          );
        });
      }
    },

    initialize: function(options) {
      highlight.configure({useBR: true});
      return backbone.BaseView.prototype.initialize.call(this, options);
    },

    render: function() {
      this.layout.upload = new UploadView({el: window.APP.$('#upload-data-package'), parent: this});
      this.layout.registryList = new registry.ListView({el: window.APP.$('#registry-list'), container: '[data-id=list-container]', parent: this});
      return this;
    },

    // Utility method to remove empty values from object recursive
    compactObject: function(data) {
      _.each(data, function(v, k) {
        if(_.isEmpty(v)) {
          delete data[k];
        } else if(_.isArray(v) || _.isObject(v)) {
          v = this.compactObject(v);

          if(_.isArray(v))
            v = _.compact(v);

          if(_.isEmpty(v))
            delete data[k];
          else data[k] = v;
        }
      }, this);

      return data;
    },

    getFilledValues: function() { return this.compactObject(this.layout.form.getValue()); },
    getValue: function () { return this.layout.form.getValue(); },
    hasChanges: function() { return Boolean(this.changed); },

    reset: function(schema) {
      var formData;

      // Clean up previous state
      if(this.layout.form) {
        formData = this.getFilledValues();
        this.layout.form.destroy();
        this.layout.uploadData.undelegateEvents().remove();
      }

      this.layout.form = new JSONEditor(this.$('[data-id=form-container]').get(0), {
        schema: schema,
        theme: 'bootstrap3'
      });

      this.layout.uploadData = (new DataUploadView({
        el: this.layout.form.theme.getHeaderButtonHolder(),
        form: this.layout.form,
        parent: this
      })).render();

      this.layout.form.on('ready', (function() {
        // There is no any good way to bind events to custom button or even add cutsom button
        $(this.layout.form.getEditor('root.resources').container)
          .children('h3').append(this.layout.uploadData.el);

        // Detecting changes
        this.changed = false;

        // After `ready` event fired, editor fire `change` event regarding to the initial changes
        this.layout.form.on('change', _.after(2, (function() {
          this.changed = true;
          window.APP.layout.download.reset(this.layout.form.getValue()).activate();
          this.showResult();
        }).bind(this)));

        // If on the previous form was entered values try to apply it to new form
        if(formData) {
          this.layout.form.setValue(_.extend({}, this.layout.form.getValue(formData), formData));

          // Expand editors if it have value
          _.each(this.$('[data-schemapath][data-schemapath!=root]:has(.json-editor-btn-collapse)'), function(E) {
              if(_.isEmpty(this.layout.form.getEditor($(E).data('schemapath')).getValue()))
                $(E).find('.json-editor-btn-collapse').click();
          }, this);
        } else
          // Collapse all
          this.$('.row .json-editor-btn-collapse').click();

      }).bind(this));
    },

    showResult: function() {
      $('#json-code').html(highlight.fixMarkup(
        highlight.highlight('json', JSON.stringify(this.layout.form.getValue(), undefined, 2)).value
      ));

      return this;
    }
  })
};
<|endoftext|>


<commit_before>var Util = require('util'),
    _ = require('underscore'),
    RSVP = require('rsvp'),
    restify = require('restify');

var domain = "https://{s}.unfuddle.com",
    version = 'v1';

function Unfuddle(subdomain, user, password) {
    this.cache = { projects: [], tickets: [] };
    this.client = restify.createJsonClient({
        url: domain.replace('{s}', subdomain)
    });
    this.client.basicAuth(user, password);
}

module.exports = Unfuddle;

Unfuddle.prototype.ticket = function (project_id, number) {
    var promise = new RSVP.Promise(),
        ticket = this.checkCache('tickets', function (t) {
            return t.number === number && t.project_id === project_id;
        });

    if (ticket) {
        promise.resolve(ticket);
    }
    else {
        var cache = this.cache,
            path = Util.format('/api/%s/projects/%d/tickets/by_number/%d', version, project_id, number);

        this.client.get(path, function (err, req, res, obj) {
            if (err) {
                var message = "Ticket: %d, not found in project: %d";
                promise.reject(this.error(err, Util.format(message, number, project_id)));
            }

            cache.tickets.push(obj);
            promise.resolve(obj);
        }.bind(this));
    }

    return promise;
};

Unfuddle.prototype.projects = function () {
    var cache = this.cache,
        promise = new RSVP.Promise();

    if (cache.projects.length) {
        promise.resolve(cache.projects);
    }
    else {
        this.client.get(Util.format('/api/%s/projects', version), function (err, req, res, obj) {
            if (err) {
                promise.reject(this.error(err, "Unable to get list of projects"));
            }
            cache.projects = obj;
            promise.resolve(obj);
        }.bind(this));
    }

    return promise;
};

Unfuddle.prototype.projectById = function (id) {
    var promise = new RSVP.Promise(),
        project = this.checkCache('projects', function (p) { return p.id === id; });

    if (project) {
        promise.resolve(project);
    }
    else {
        var cache = this.cache,
            path = Util.format('/api/%s/projects/%d', version, id);

        this.client.get(path, function (err, req, res, obj) {
            if (err) {
                var message = "Project: %d, not found.";
                promise.reject(this.error(err, Util.format(message, id)));
            }
            cache.projects.push(obj);
            promise.resolve(obj);
        }.bind(this));
    }

    return promise;
};

Unfuddle.prototype.projectByShortName = function (name) {
    var promise = new RSVP.Promise(),
        project = this.checkCache('projects', function (p) { return p.short_name === name; });

    if (project) {
        promise.resolve(project);
    }
    else {
        var cache = this.cache,
            path = Util.format('/api/%s/projects/by_short_name/%s', version, name);

        this.client.get(path, function (err, req, res, obj) {
            if (err) {
                var message = "Project: %s, not found.";
                promise.reject(this.error(err, Util.format(message, name)));
            }
            cache.projects.push(obj);
            promise.resolve(obj);
        }.bind(this));
    }

    return promise;
};

Unfuddle.prototype.checkCache = function (bin, condition) {
    var cache = this.cache;
    if (bin in cache && cache[bin].length) {
        return _.find(cache[bin], condition);
    }
};

Unfuddle.prototype.error = function (err, message) {
    if ('statusCode' in err) {
        if (err.statusCode === 404) {
            err = new restify.ResourceNotFoundError(message || "");
        }
    }
    return err;
};
<commit_msg>better handling of access denied<commit_after>var Util = require('util'),
    _ = require('underscore'),
    RSVP = require('rsvp'),
    restify = require('restify');

var domain = "https://{s}.unfuddle.com",
    version = 'v1';

function Unfuddle(subdomain, user, password) {
    this.cache = { projects: [], tickets: [] };
    this.client = restify.createJsonClient({
        url: domain.replace('{s}', subdomain)
    });
    this.client.basicAuth(user, password);
}

module.exports = Unfuddle;

Unfuddle.prototype.ticket = function (project_id, number) {
    var promise = new RSVP.Promise(),
        ticket = this.checkCache('tickets', function (t) {
            return t.number === number && t.project_id === project_id;
        });

    if (ticket) {
        promise.resolve(ticket);
    }
    else {
        var cache = this.cache,
            path = Util.format('/api/%s/projects/%d/tickets/by_number/%d', version, project_id, number);

        this.client.get(path, function (err, req, res, obj) {
            if (err) {
                var message = "Ticket: %d, not found in project: %d";
                promise.reject(this.error(err, Util.format(message, number, project_id)));
            }

            cache.tickets.push(obj);
            promise.resolve(obj);
        }.bind(this));
    }

    return promise;
};

Unfuddle.prototype.projects = function () {
    var cache = this.cache,
        promise = new RSVP.Promise();

    if (cache.projects.length) {
        promise.resolve(cache.projects);
    }
    else {
        this.client.get(Util.format('/api/%s/projects', version), function (err, req, res, obj) {
            if (err) {
                promise.reject(this.error(err, "Unable to get list of projects"));
            }
            cache.projects = obj;
            promise.resolve(obj);
        }.bind(this));
    }

    return promise;
};

Unfuddle.prototype.projectById = function (id) {
    var promise = new RSVP.Promise(),
        project = this.checkCache('projects', function (p) { return p.id === id; });

    if (project) {
        promise.resolve(project);
        return promise;
    }

    var cache = this.cache,
        path = Util.format('/api/%s/projects/%d', version, id);

    this.client.get(path, function (err, req, res, obj) {
        if (err) {
            var message = Util.format("Couldn't load project: %s.", id);
            return promise.reject(this.error(err, message));
        }
        cache.projects.push(obj);
        return promise.resolve(obj);
    }.bind(this));

    return promise;
};

Unfuddle.prototype.projectByShortName = function (name) {
    var promise = new RSVP.Promise(),
        project = this.checkCache('projects', function (p) { return p.short_name === name; });

    if (project) {
        promise.resolve(project);
        return promise;
    }

    var cache = this.cache,
        path = Util.format('/api/%s/projects/by_short_name/%s', version, name);

    this.client.get(path, function (err, req, res, obj) {
        if (err) {
            var message = Util.format("Couldn't load project: %s.", name);
            return promise.reject(this.error(err, message));
        }
        cache.projects.push(obj);
        return promise.resolve(obj);
    }.bind(this));

    return promise;
};

Unfuddle.prototype.checkCache = function (bin, condition) {
    var cache = this.cache;
    if (bin in cache && cache[bin].length) {
        return _.find(cache[bin], condition);
    }
};

Unfuddle.prototype.error = function (err, message, status_code) {
    if ('statusCode' in err) status_code = err.statusCode;

    message = message || "";

    if (status_code) {
        switch (+status_code) {
            case 404:
            return new restify.ResourceNotFoundError(message);
            case 409:
            return new restify.NotAuthorizedError(message);
        }
    }
    return err;
};
<|endoftext|>


<commit_before>var assert = require('assert');
var fork = require('child_process').fork;
var expect = require('chai').expect;
var http = require('http');
var request = require('request').defaults({baseUrl:"http://localhost:8080/"});;
var child

before(function(done) {
    child = fork('./server',['--sim']);
    setTimeout(function(){done();},1900);
});

beforeEach(function() {

});

describe('Angularjs', function() {
  describe('main', function() {
	  it('get the front page', function(done) {

		request('/', function (error, response, body) {
		  if (!error && response.statusCode == 200) {
		    console.log(body);
		    done();
		  }
		  else {
		   assert(0);
		   done();
		  }
		});
	  });

    it('get the app list', function(done) {
	 request("/list", function(error, response, body) {
		  if (!error && response.statusCode == 200) {
		    console.log(body);
		    done();
		  }
		  else {
		   assert(0);
		   done();
		  }
		});
    });
  });
});

describe('Angularjs', function() {
  describe('fpga', function() {
    it('always true', function() {
	assert(1)
    });
  });
});

describe('Angularjs', function() {
  describe('db', function() {
    it('add doc', function(done) {
	 request.post({
	headers: {"Connection": "close"},
    url: '/db/add/test',
    method: 'POST',
    json:true,
    body: {a:1,b:2}
}, function(error, response, body) {
		  if (!error && response.statusCode == 200) {
		    console.log(body);
		    done();
		  }
		  else {
		   assert(0);
		   done();
		  }
		});
    });
    it('verfiy doc', function(done) {
	 request("/db/list/test", function(error, response, body) {
		  if (!error && response.statusCode == 200) {
		    console.log(body);
		    var data = JSON.parse(body)
		    assert.equal(data[0].a ,1);
		    assert.equal(data[0].b ,2);
		    done();
		  }
		  else {
		   assert(0);
		   done();
		  }
		});
    });
    it('remove doc', function(done) {
	 request.del("/db/remove/test", function(error, response, body) {
		  if (!error && response.statusCode == 200) {
		    console.log(body);
		    done();
		  }
		  else {
		   assert(0);
		   done();
		  }
		});
    });
  });
});

afterEach(function() {

});

after(function() {
    child.kill('SIGHUP');
});
<commit_msg>add test case<commit_after>var assert = require('assert');
var fork = require('child_process').fork;
var expect = require('chai').expect;
var http = require('http');
var request = require('request').defaults({baseUrl:"http://localhost:8080/"});;
var child

before(function(done) {
    child = fork('./server',['--sim']);
    setTimeout(function(){done();},1900);
});

beforeEach(function() {

});

describe('Angularjs', function() {
  describe('main', function() {
	  it('get the front page', function(done) {

		request('/', function (error, response, body) {
		  if (!error && response.statusCode == 200) {
		    console.log(body);
		    done();
		  }
		  else {
		   assert(0);
		   done();
		  }
		});
	  });

    it('get the app list', function(done) {
	 request("/list", function(error, response, body) {
		  if (!error && response.statusCode == 200) {
		    console.log(body);
		    done();
		  }
		  else {
		   assert(0);
		   done();
		  }
		});
    });
    it('get the main app', function(done) {
	 request("/get/main.js", function(error, response, body) {
		  if (!error && response.statusCode == 200) {
		    console.log(body);
		  }
		  else {
		   assert(0);

		  }
	   	  done();
		});
    });
  it('get the main app', function(done) {
	 request.post(headers: {"Connection": "close"},
    url: '/load',
    method: 'POST',
    json:true,
    body: {filename:"main.js"}function(error, response, body) {
		  if (!error && response.statusCode == 200) {
		    console.log(body);
		  }
		  else {
		   assert(0);

		  }
	   	  done();
		});
    });

  });
});

describe('Angularjs', function() {
  describe('fpga', function() {
    it('always true', function() {
	assert(1)
    });
  });
});

describe('Angularjs', function() {
  describe('db', function() {
    it('add doc', function(done) {
	 request.post({
	headers: {"Connection": "close"},
    url: '/db/add/test',
    method: 'POST',
    json:true,
    body: {a:1,b:2}
}, function(error, response, body) {
		  if (!error && response.statusCode == 200) {
		    console.log(body);
		    done();
		  }
		  else {
		   assert(0);
		   done();
		  }
		});
    });
    it('verfiy doc', function(done) {
	 request("/db/list/test", function(error, response, body) {
		  if (!error && response.statusCode == 200) {
		    console.log(body);
		    var data = JSON.parse(body)
		    assert.equal(data[0].a ,1);
		    assert.equal(data[0].b ,2);
		    done();
		  }
		  else {
		   assert(0);
		   done();
		  }
		});
    });
    it('remove doc', function(done) {
	 request.del("/db/remove/test", function(error, response, body) {
		  if (!error && response.statusCode == 200) {
		    console.log(body);
		    done();
		  }
		  else {
		   assert(0);
		   done();
		  }
		});
    });
  });
});

afterEach(function() {

});

after(function() {
    child.kill('SIGHUP');
});
<|endoftext|>


<commit_before>module.exports = function sum(arr1, arr2) {
    const calc_shape = require('../lib/calc_shape');
    const arrange = require('../lib/arrange');
    const form_arr = require('../lib/form_arr');
    const flatten = require('../lib/flatten');
    let summ,
        ta1 = [],
        ta2 = [],
        t1, t2, s1, s2;
    if (!arr2) {
        t1 = form_arr(flatten(arr1));
        s1 = calc_shape(arr1);
        if (s1.length > 1) {
            summ = [];
            let s = 0;
            for (let i = 0; i <= t1.length; i++) {
                if ((i % s1[s1.length - 1]) === 0 && i !== 0) {
                    summ.push(s);
                    s = 0;
                }
                s += t1[i];
            }
            return summ;
        } else {
            summ = 0;
            for (let i = 0; i < t1.length; i++) {
                summ += t1[i];
            }
            return summ;
        }
    } else {
        t1 = form_arr(flatten(arr1));
        t2 = form_arr(flatten(arr2));
        s1 = calc_shape(arr1);
        s2 = calc_shape(arr2);
        if (s1.toString() === s2.toString()) {
            summ = [];
            for (let i = 0; i < t1.length; i++) {
                summ[i] = t1[i] + t2[i];
            }
            let si = s1.length > 1 ? s1.slice(s1.length - 2) : s1;
            return arrange(si, summ);
        } else {
            throw new Error("Uneven Size");
        }
    }
}<commit_msg>silly slice fix<commit_after>module.exports = function sum(arr1, arr2) {
    const calc_shape = require('../lib/calc_shape');
    const arrange = require('../lib/arrange');
    const form_arr = require('../lib/form_arr');
    const flatten = require('../lib/flatten');
    let summ, t1, t2, s1, s2;
    if (!arr2) {
        t1 = form_arr(flatten(arr1));
        s1 = calc_shape(arr1);
        if (s1.length > 1) {
            summ = [];
            let s = 0;
            for (let i = 0; i <= t1.length; i++) {
                if ((i % s1[s1.length - 1]) === 0 && i !== 0) {
                    summ.push(s);
                    s = 0;
                }
                s += t1[i];
            }
            return summ;
        } else {
            summ = 0;
            for (let i = 0; i < t1.length; i++) {
                summ += t1[i];
            }
            return summ;
        }
    } else {
        t1 = form_arr(flatten(arr1));
        t2 = form_arr(flatten(arr2));
        s1 = calc_shape(arr1);
        s2 = calc_shape(arr2);
        if (s1.toString() === s2.toString()) {
            summ = [];
            for (let i = 0; i < t1.length; i++) {
                summ[i] = t1[i] + t2[i];
            }
            return arrange(s1, summ);
        } else if (s1.length > 1 && s2.length === 1) {
            for (let i = 0; i < t1.length; i++) {
                t1[i] += t2;
            }
            return arrange(s1, t1);
        } else {
            throw new Error("Uneven Size");
        }
    }
}<|endoftext|>


<commit_before>/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */
/* Vector handling functions                                          (c) Chris Veness 2011-2019  */
/*                                                                                MIT Licence  */
/* www.movable-type.co.uk/scripts/geodesy-library.html#vector3d                                   */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */

/**
 * Library of 3-d vector manipulation routines.
 *
 * @module vector3d
 */

/* Vector3d - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

/**
 * Functions for manipulating generic 3-d vectors.
 *
 * Functions return vectors as return results, so that operations can be chained.
 *
 * @example
 *   const v = v1.cross(v2).dot(v3) // ≡ v1×v2⋅v3
 */
class Vector3d {

    /**
     * Creates a 3-d vector.
     *
     * @param {number} x - X component of vector.
     * @param {number} y - Y component of vector.
     * @param {number} z - Z component of vector.
     *
     * @example
     *   import Vector3d from '/js/geodesy/vector3d.js';
     *   const v = new Vector3d(0.267, 0.535, 0.802);
     */
    constructor(x, y, z) {
        if (isNaN(x) || isNaN(x) || isNaN(x)) throw new TypeError(`invalid vector [${x},${y},${z}]`);

        this.x = Number(x);
        this.y = Number(y);
        this.z = Number(z);
    }

    /**
     * Length (magnitude or norm) of ‘this’ vector.
     *
     * @returns {number} Magnitude of this vector.
     */
    get length() {
        return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
    }

    /**
     * Adds supplied vector to ‘this’ vector.
     *
     * @param   {Vector3d} v - Vector to be added to this vector.
     * @returns {Vector3d} Vector representing sum of this and v.
     */
    plus(v) {
        if (!(v instanceof Vector3d)) throw new TypeError('v is not Vector3d object');

        return new Vector3d(this.x + v.x, this.y + v.y, this.z + v.z);
    }

    /**
     * Subtracts supplied vector from ‘this’ vector.
     *
     * @param   {Vector3d} v - Vector to be subtracted from this vector.
     * @returns {Vector3d} Vector representing difference between this and v.
     */
    minus(v) {
        if (!(v instanceof Vector3d)) throw new TypeError('v is not Vector3d object');

        return new Vector3d(this.x - v.x, this.y - v.y, this.z - v.z);
    }

    /**
     * Multiplies ‘this’ vector by a scalar value.
     *
     * @param   {number}   x - Factor to multiply this vector by.
     * @returns {Vector3d} Vector scaled by x.
     */
    times(x) {
        if (isNaN(x)) throw new TypeError(`invalid scalar value ‘${x}’`);

        return new Vector3d(this.x * x, this.y * x, this.z * x);
    }

    /**
     * Divides ‘this’ vector by a scalar value.
     *
     * @param   {number}   x - Factor to divide this vector by.
     * @returns {Vector3d} Vector divided by x.
     */
    dividedBy(x) {
        if (isNaN(x)) throw new TypeError(`invalid scalar value ‘${x}’`);

        return new Vector3d(this.x / x, this.y / x, this.z / x);
    }

    /**
     * Multiplies ‘this’ vector by the supplied vector using dot (scalar) product.
     *
     * @param   {Vector3d} v - Vector to be dotted with this vector.
     * @returns {number}   Dot product of ‘this’ and v.
     */
    dot(v) {
        if (!(v instanceof Vector3d)) throw new TypeError('v is not Vector3d object');

        return this.x * v.x + this.y * v.y + this.z * v.z;
    }

    /**
     * Multiplies ‘this’ vector by the supplied vector using cross (vector) product.
     *
     * @param   {Vector3d} v - Vector to be crossed with this vector.
     * @returns {Vector3d} Cross product of ‘this’ and v.
     */
    cross(v) {
        if (!(v instanceof Vector3d)) throw new TypeError('v is not Vector3d object');

        const x = this.y * v.z - this.z * v.y;
        const y = this.z * v.x - this.x * v.z;
        const z = this.x * v.y - this.y * v.x;

        return new Vector3d(x, y, z);
    }

    /**
     * Negates a vector to point in the opposite direction.
     *
     * @returns {Vector3d} Negated vector.
     */
    negate() {
        return new Vector3d(-this.x, -this.y, -this.z);
    }

    /**
     * Normalizes a vector to its unit vector
     * – if the vector is already unit or is zero magnitude, this is a no-op.
     *
     * @returns {Vector3d} Normalised version of this vector.
     */
    unit() {
        const norm = this.length;
        if (norm == 1) return this;
        if (norm == 0) return this;

        const x = this.x / norm;
        const y = this.y / norm;
        const z = this.z / norm;

        return new Vector3d(x, y, z);
    }

    /**
     * Calculates the angle between ‘this’ vector and supplied vector atan2(|p₁×p₂|, p₁·p₂) (or if
     * (extra-planar) ‘n’ supplied then atan2(n·p₁×p₂, p₁·p₂).
     *
     * @param   {Vector3d} v - Vector whose angle is to be determined from ‘this’ vector.
     * @param   {Vector3d} [n] - Plane normal: if supplied, angle is signed +ve if this->v is
     *                     clockwise looking along n, -ve in opposite direction.
     * @returns {number}   Angle (in radians) between this vector and supplied vector (in range 0..π
     *                     if n not supplied, range -π..+π if n supplied).
     */
    angleTo(v, n=undefined) {
        if (!(v instanceof Vector3d)) throw new TypeError('v is not Vector3d object');
        if (!(n instanceof Vector3d || n == undefined)) throw new TypeError('n is not Vector3d object');

        // q.v. stackoverflow.com/questions/14066933#answer-16544330, but n·p₁×p₂ is numerically
        // ill-conditioned, so just calculate sign to apply to |p₁×p₂|

        // if n·p₁×p₂ is -ve, negate |p₁×p₂|
        const sign = n==undefined || this.cross(v).dot(n)>=0 ? 1 : -1;

        const sinθ = this.cross(v).length * sign;
        const cosθ = this.dot(v);

        return Math.atan2(sinθ, cosθ);
    }

    /**
     * Rotates ‘this’ point around an axis by a specified angle.
     *
     * @param   {Vector3d} axis - The axis being rotated around.
     * @param   {number}   angle - The angle of rotation (in degrees).
     * @returns {Vector3d} The rotated point.
     */
    rotateAround(axis, angle) {
        if (!(axis instanceof Vector3d)) throw new TypeError('axis is not Vector3d object');

        const θ = angle.toRadians();

        // en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle
        // en.wikipedia.org/wiki/Quaternions_and_spatial_rotation#Quaternion-derived_rotation_matrix
        const p = this.unit();
        const a = axis.unit();

        const s = Math.sin(θ);
        const c = Math.cos(θ);
        const t = 1-c;
        const x = a.x, y = a.y, z = a.z;

        const r = [ // rotation matrix for rotation about supplied axis
            [ t*x*x + c,   t*x*y - s*z, t*x*z + s*y ],
            [ t*x*y + s*z, t*y*y + c,   t*y*z - s*x ],
            [ t*x*z - s*y, t*y*z + s*x, t*z*z + c   ],
        ];

        // multiply r × p
        const rp = [
            r[0][0]*p.x + r[0][1]*p.y + r[0][2]*p.z,
            r[1][0]*p.x + r[1][1]*p.y + r[1][2]*p.z,
            r[2][0]*p.x + r[2][1]*p.y + r[2][2]*p.z,
        ];
        const p2 = new Vector3d(rp[0], rp[1], rp[2]);

        return p2;
        // qv en.wikipedia.org/wiki/Rodrigues'_rotation_formula...
    }

    /**
     * String representation of vector.
     *
     * @param   {number} [dp=3] - Number of decimal places to be used.
     * @returns {string} Vector represented as [x,y,z].
     */
    toString(dp=3) {
        return `[${this.x.toFixed(dp)},${this.y.toFixed(dp)},${this.z.toFixed(dp)}]`;
    }

}

// Extend Number object with methods to convert between degrees & radians
Number.prototype.toRadians = function() { return this * Math.PI / 180; };
Number.prototype.toDegrees = function() { return this * 180 / Math.PI; };

/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */

export default Vector3d;
<commit_msg>Typo fixed<commit_after>/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */
/* Vector handling functions                                          (c) Chris Veness 2011-2019  */
/*                                                                                MIT Licence  */
/* www.movable-type.co.uk/scripts/geodesy-library.html#vector3d                                   */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */

/**
 * Library of 3-d vector manipulation routines.
 *
 * @module vector3d
 */

/* Vector3d - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

/**
 * Functions for manipulating generic 3-d vectors.
 *
 * Functions return vectors as return results, so that operations can be chained.
 *
 * @example
 *   const v = v1.cross(v2).dot(v3) // ≡ v1×v2⋅v3
 */
class Vector3d {

    /**
     * Creates a 3-d vector.
     *
     * @param {number} x - X component of vector.
     * @param {number} y - Y component of vector.
     * @param {number} z - Z component of vector.
     *
     * @example
     *   import Vector3d from '/js/geodesy/vector3d.js';
     *   const v = new Vector3d(0.267, 0.535, 0.802);
     */
    constructor(x, y, z) {
        if (isNaN(x) || isNaN(y) || isNaN(z)) throw new TypeError(`invalid vector [${x},${y},${z}]`);

        this.x = Number(x);
        this.y = Number(y);
        this.z = Number(z);
    }

    /**
     * Length (magnitude or norm) of ‘this’ vector.
     *
     * @returns {number} Magnitude of this vector.
     */
    get length() {
        return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
    }

    /**
     * Adds supplied vector to ‘this’ vector.
     *
     * @param   {Vector3d} v - Vector to be added to this vector.
     * @returns {Vector3d} Vector representing sum of this and v.
     */
    plus(v) {
        if (!(v instanceof Vector3d)) throw new TypeError('v is not Vector3d object');

        return new Vector3d(this.x + v.x, this.y + v.y, this.z + v.z);
    }

    /**
     * Subtracts supplied vector from ‘this’ vector.
     *
     * @param   {Vector3d} v - Vector to be subtracted from this vector.
     * @returns {Vector3d} Vector representing difference between this and v.
     */
    minus(v) {
        if (!(v instanceof Vector3d)) throw new TypeError('v is not Vector3d object');

        return new Vector3d(this.x - v.x, this.y - v.y, this.z - v.z);
    }

    /**
     * Multiplies ‘this’ vector by a scalar value.
     *
     * @param   {number}   x - Factor to multiply this vector by.
     * @returns {Vector3d} Vector scaled by x.
     */
    times(x) {
        if (isNaN(x)) throw new TypeError(`invalid scalar value ‘${x}’`);

        return new Vector3d(this.x * x, this.y * x, this.z * x);
    }

    /**
     * Divides ‘this’ vector by a scalar value.
     *
     * @param   {number}   x - Factor to divide this vector by.
     * @returns {Vector3d} Vector divided by x.
     */
    dividedBy(x) {
        if (isNaN(x)) throw new TypeError(`invalid scalar value ‘${x}’`);

        return new Vector3d(this.x / x, this.y / x, this.z / x);
    }

    /**
     * Multiplies ‘this’ vector by the supplied vector using dot (scalar) product.
     *
     * @param   {Vector3d} v - Vector to be dotted with this vector.
     * @returns {number}   Dot product of ‘this’ and v.
     */
    dot(v) {
        if (!(v instanceof Vector3d)) throw new TypeError('v is not Vector3d object');

        return this.x * v.x + this.y * v.y + this.z * v.z;
    }

    /**
     * Multiplies ‘this’ vector by the supplied vector using cross (vector) product.
     *
     * @param   {Vector3d} v - Vector to be crossed with this vector.
     * @returns {Vector3d} Cross product of ‘this’ and v.
     */
    cross(v) {
        if (!(v instanceof Vector3d)) throw new TypeError('v is not Vector3d object');

        const x = this.y * v.z - this.z * v.y;
        const y = this.z * v.x - this.x * v.z;
        const z = this.x * v.y - this.y * v.x;

        return new Vector3d(x, y, z);
    }

    /**
     * Negates a vector to point in the opposite direction.
     *
     * @returns {Vector3d} Negated vector.
     */
    negate() {
        return new Vector3d(-this.x, -this.y, -this.z);
    }

    /**
     * Normalizes a vector to its unit vector
     * – if the vector is already unit or is zero magnitude, this is a no-op.
     *
     * @returns {Vector3d} Normalised version of this vector.
     */
    unit() {
        const norm = this.length;
        if (norm == 1) return this;
        if (norm == 0) return this;

        const x = this.x / norm;
        const y = this.y / norm;
        const z = this.z / norm;

        return new Vector3d(x, y, z);
    }

    /**
     * Calculates the angle between ‘this’ vector and supplied vector atan2(|p₁×p₂|, p₁·p₂) (or if
     * (extra-planar) ‘n’ supplied then atan2(n·p₁×p₂, p₁·p₂).
     *
     * @param   {Vector3d} v - Vector whose angle is to be determined from ‘this’ vector.
     * @param   {Vector3d} [n] - Plane normal: if supplied, angle is signed +ve if this->v is
     *                     clockwise looking along n, -ve in opposite direction.
     * @returns {number}   Angle (in radians) between this vector and supplied vector (in range 0..π
     *                     if n not supplied, range -π..+π if n supplied).
     */
    angleTo(v, n=undefined) {
        if (!(v instanceof Vector3d)) throw new TypeError('v is not Vector3d object');
        if (!(n instanceof Vector3d || n == undefined)) throw new TypeError('n is not Vector3d object');

        // q.v. stackoverflow.com/questions/14066933#answer-16544330, but n·p₁×p₂ is numerically
        // ill-conditioned, so just calculate sign to apply to |p₁×p₂|

        // if n·p₁×p₂ is -ve, negate |p₁×p₂|
        const sign = n==undefined || this.cross(v).dot(n)>=0 ? 1 : -1;

        const sinθ = this.cross(v).length * sign;
        const cosθ = this.dot(v);

        return Math.atan2(sinθ, cosθ);
    }

    /**
     * Rotates ‘this’ point around an axis by a specified angle.
     *
     * @param   {Vector3d} axis - The axis being rotated around.
     * @param   {number}   angle - The angle of rotation (in degrees).
     * @returns {Vector3d} The rotated point.
     */
    rotateAround(axis, angle) {
        if (!(axis instanceof Vector3d)) throw new TypeError('axis is not Vector3d object');

        const θ = angle.toRadians();

        // en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle
        // en.wikipedia.org/wiki/Quaternions_and_spatial_rotation#Quaternion-derived_rotation_matrix
        const p = this.unit();
        const a = axis.unit();

        const s = Math.sin(θ);
        const c = Math.cos(θ);
        const t = 1-c;
        const x = a.x, y = a.y, z = a.z;

        const r = [ // rotation matrix for rotation about supplied axis
            [ t*x*x + c,   t*x*y - s*z, t*x*z + s*y ],
            [ t*x*y + s*z, t*y*y + c,   t*y*z - s*x ],
            [ t*x*z - s*y, t*y*z + s*x, t*z*z + c   ],
        ];

        // multiply r × p
        const rp = [
            r[0][0]*p.x + r[0][1]*p.y + r[0][2]*p.z,
            r[1][0]*p.x + r[1][1]*p.y + r[1][2]*p.z,
            r[2][0]*p.x + r[2][1]*p.y + r[2][2]*p.z,
        ];
        const p2 = new Vector3d(rp[0], rp[1], rp[2]);

        return p2;
        // qv en.wikipedia.org/wiki/Rodrigues'_rotation_formula...
    }

    /**
     * String representation of vector.
     *
     * @param   {number} [dp=3] - Number of decimal places to be used.
     * @returns {string} Vector represented as [x,y,z].
     */
    toString(dp=3) {
        return `[${this.x.toFixed(dp)},${this.y.toFixed(dp)},${this.z.toFixed(dp)}]`;
    }

}

// Extend Number object with methods to convert between degrees & radians
Number.prototype.toRadians = function() { return this * Math.PI / 180; };
Number.prototype.toDegrees = function() { return this * 180 / Math.PI; };

/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */

export default Vector3d;
<|endoftext|>


<commit_before>/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */
/*  Vector handling functions                                         (c) Chris Veness 2011-2014  */
/*                                                                                */
/*  These are generic 3-d vector manipulation routines.                                           */
/*                                                                                */
/*  In a geodesy context, these may be used to represent:                                         */
/*   - n-vector representing a normal to point on Earth's surface                                 */
/*   - earth-centered, earth fixed vector (= n-vector for spherical model)                        */
/*   - great circle normal to vector                                                              */
/*   - motion vector on Earth's surface                                                           */
/*   - etc                                                                                */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */
'use strict';

/**
 * Creates a 3-d vector.
 *
 * The vector may be normalised, or use x/y/z values for eg height relative to the sphere or
 * ellipsoid, distance from earth centre, etc.
 *
 * @classdesc Tools for manipulating 3-d vectors, to support various latitude/longitude functions.
 *
 * @constructor
 * @param {number} x - X component of vector.
 * @param {number} y - Y component of vector.
 * @param {number} z - Z component of vector.
 */
function Vector3d(x, y, z) {
    // allow instantiation without 'new'
    if (!(this instanceof Vector3d)) return new Vector3d(x, y, z);

    this.x = Number(x);
    this.y = Number(y);
    this.z = Number(z);
}

/**
 * Adds supplied vector to ‘this’ vector.
 *
 * @param   {Vector3d} v - Vector to be added to this vector.
 * @returns {Vector3d} Vector representing sum of this and v.
 */
Vector3d.prototype.plus = function(v) {
    return new Vector3d(this.x + v.x, this.y + v.y, this.z + v.z);
}

/**
 * Subtracts supplied vector from ‘this’ vector.
 *
 * @param   {Vector3d} v - Vector to be subtracted from this vector.
 * @returns {Vector3d} Vector representing difference between this and v.
 */
Vector3d.prototype.minus = function(v) {
    return new Vector3d(this.x - v.x, this.y - v.y, this.z - v.z);
}

/**
 * Multiplies ‘this’ vector by a scalar value.
 *
 * @param   {number}   x - Factor to multiply this vector by.
 * @returns {Vector3d} Vector scaled by x.
 */
Vector3d.prototype.times = function(x) {
    x = Number(x);
    //console.log(this.toString(), x, (new Vector3d(this.x * x, this.y * x, this.z * x)).toString());
    return new Vector3d(this.x * x, this.y * x, this.z * x);
}

/**
 * Divides ‘this’ vector by a scalar value.
 *
 * @param   {number}   x - Factor to divide this vector by.
 * @returns {Vector3d} Vector divided by x.
 */
Vector3d.prototype.dividedBy = function(x) {
    x = Number(x);
    return new Vector3d(this.x / x, this.y / x, this.z / x);
}

/**
 * Multiplies ‘this’ vector by the supplied vector using dot (scalar) product.
 *
 * @param   {Vector3d} v - Vector to be dotted with this vector.
 * @returns {number} Dot product of ‘this’ and v.
 */
Vector3d.prototype.dot = function(v) {
    return this.x*v.x + this.y*v.y + this.z*v.z;
}

/**
 * Multiplies ‘this’ vector by the supplied vector using cross (vector) product.
 *
 * @param   {Vector3d} v - Vector to be crossed with this vector.
 * @returns {Vector3d} Cross product of ‘this’ and v.
 */
Vector3d.prototype.cross = function(v) {
    var x = this.y*v.z - this.z*v.y;
    var y = this.z*v.x - this.x*v.z;
    var z = this.x*v.y - this.y*v.x;

    return new Vector3d(x, y, z);
}

/**
 * Negates a vector to point in the opposite direction
 *
 * @returns {Vector3d} Negated vector.
 */
Vector3d.prototype.negate = function() {
    return new Vector3d(-this.x, -this.y, -this.z);
}

/**
 * Length (magnitude or norm) of ‘this’ vector
 *
 * @returns {number} Magnitude of this vector.
 */
Vector3d.prototype.length = function() {
    return Math.sqrt(this.x*this.x + this.y*this.y + this.z*this.z);
}

/**
 * Normalizes a vector to its unit vector
 * – if the vector is already unit or is zero magnitude, this is a no-op.
 *
 * @returns {Vector3d} Normalised version of this vector.
 */
Vector3d.prototype.unit = function() {
    var norm = this.length();
    if (norm == 1) return this;
    if (norm == 0) return this;

    var x = this.x/norm;
    var y = this.y/norm;
    var z = this.z/norm;

    return new Vector3d(x, y, z);
}

/**
 * Calculates the angle between ‘this’ vector and supplied vector.
 *
 * @param   {Vector3d} v
 * @returns {number} Angle (in signed radians) between this vector and supplied vector.
 */
Vector3d.prototype.angleTo = function(v) {
    var sinθ = this.cross(v).length();
    var cosθ = this.dot(v);

    return Math.atan2(sinθ, cosθ);
}

/**
 * Rotates ‘this’ point around an axis by a specified angle.
 *
 * @param   {Vector3d} axis - The axis being rotated around.
 * @param   {number}   theta - The angle of rotation (in radians).
 * @returns {Vector3d} The rotated point.
 */
Vector3d.prototype.rotateAround = function(axis, theta) {
    // en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle
    // en.wikipedia.org/wiki/Quaternions_and_spatial_rotation#Quaternion-derived_rotation_matrix
    var p1 = this.unit();
    var p = [ p1.x, p1.y, p1.z ]; // the point being rotated
    var a = axis.unit();          // the axis being rotated around
    var s = Math.sin(theta);
    var c = Math.cos(theta);
    // quaternion-derived rotation matrix
    var q = [ [ a.x*a.x*(1-c) + c,     a.x*a.y*(1-c) - a.z*s, a.x*a.z*(1-c) + a.y*s],
        [ a.y*a.x*(1-c) + a.z*s, a.y*a.y*(1-c) + c,     a.y*a.z*(1-c) - a.x*s],
        [ a.z*a.x*(1-c) - a.y*s, a.z*a.y*(1-c) + a.x*s, a.z*a.z*(1-c) + c    ] ];
    // multiply q × p
    var qp = [0, 0, 0];
    for (var i=0; i<3; i++) {
        for (var j=0; j<3; j++) {
            qp[i] += q[i][j] * p[j];
        }
    }
    var p2 = new Vector3d(qp[0], qp[1], qp[2]);
    return p2;
    // qv en.wikipedia.org/wiki/Rodrigues'_rotation_formula...
}

/**
 * String representation of vector.
 *
 * @param   {number} [precision=3] - Number of decimal places to be used.
 * @returns {string} Vector represented as [x,y,z].
 */
Vector3d.prototype.toString = function(precision) {
    if (typeof precision == 'undefined') precision = 3;

    var p = Number(precision);

    var str = '[' + this.x.toFixed(p) + ',' + this.y.toFixed(p) + ',' + this.z.toFixed(p) + ']';

    return str;
}

/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */
if (!window.console) window.console = { log: function() {} };
<commit_msg>Make angleTo signed if reference point supplied<commit_after>/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */
/*  Vector handling functions                                         (c) Chris Veness 2011-2014  */
/*                                                                                */
/*  These are generic 3-d vector manipulation routines.                                           */
/*                                                                                */
/*  In a geodesy context, these may be used to represent:                                         */
/*   - n-vector representing a normal to point on Earth's surface                                 */
/*   - earth-centered, earth fixed vector (= n-vector for spherical model)                        */
/*   - great circle normal to vector                                                              */
/*   - motion vector on Earth's surface                                                           */
/*   - etc                                                                                */
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */
'use strict';

/**
 * Creates a 3-d vector.
 *
 * The vector may be normalised, or use x/y/z values for eg height relative to the sphere or
 * ellipsoid, distance from earth centre, etc.
 *
 * @classdesc Tools for manipulating 3-d vectors, to support various latitude/longitude functions.
 *
 * @constructor
 * @param {number} x - X component of vector.
 * @param {number} y - Y component of vector.
 * @param {number} z - Z component of vector.
 */
function Vector3d(x, y, z) {
    // allow instantiation without 'new'
    if (!(this instanceof Vector3d)) return new Vector3d(x, y, z);

    this.x = Number(x);
    this.y = Number(y);
    this.z = Number(z);
}

/**
 * Adds supplied vector to ‘this’ vector.
 *
 * @param   {Vector3d} v - Vector to be added to this vector.
 * @returns {Vector3d} Vector representing sum of this and v.
 */
Vector3d.prototype.plus = function(v) {
    return new Vector3d(this.x + v.x, this.y + v.y, this.z + v.z);
}

/**
 * Subtracts supplied vector from ‘this’ vector.
 *
 * @param   {Vector3d} v - Vector to be subtracted from this vector.
 * @returns {Vector3d} Vector representing difference between this and v.
 */
Vector3d.prototype.minus = function(v) {
    return new Vector3d(this.x - v.x, this.y - v.y, this.z - v.z);
}

/**
 * Multiplies ‘this’ vector by a scalar value.
 *
 * @param   {number}   x - Factor to multiply this vector by.
 * @returns {Vector3d} Vector scaled by x.
 */
Vector3d.prototype.times = function(x) {
    x = Number(x);
    //console.log(this.toString(), x, (new Vector3d(this.x * x, this.y * x, this.z * x)).toString());
    return new Vector3d(this.x * x, this.y * x, this.z * x);
}

/**
 * Divides ‘this’ vector by a scalar value.
 *
 * @param   {number}   x - Factor to divide this vector by.
 * @returns {Vector3d} Vector divided by x.
 */
Vector3d.prototype.dividedBy = function(x) {
    x = Number(x);
    return new Vector3d(this.x / x, this.y / x, this.z / x);
}

/**
 * Multiplies ‘this’ vector by the supplied vector using dot (scalar) product.
 *
 * @param   {Vector3d} v - Vector to be dotted with this vector.
 * @returns {number} Dot product of ‘this’ and v.
 */
Vector3d.prototype.dot = function(v) {
    return this.x*v.x + this.y*v.y + this.z*v.z;
}

/**
 * Multiplies ‘this’ vector by the supplied vector using cross (vector) product.
 *
 * @param   {Vector3d} v - Vector to be crossed with this vector.
 * @returns {Vector3d} Cross product of ‘this’ and v.
 */
Vector3d.prototype.cross = function(v) {
    var x = this.y*v.z - this.z*v.y;
    var y = this.z*v.x - this.x*v.z;
    var z = this.x*v.y - this.y*v.x;

    return new Vector3d(x, y, z);
}

/**
 * Negates a vector to point in the opposite direction
 *
 * @returns {Vector3d} Negated vector.
 */
Vector3d.prototype.negate = function() {
    return new Vector3d(-this.x, -this.y, -this.z);
}

/**
 * Length (magnitude or norm) of ‘this’ vector
 *
 * @returns {number} Magnitude of this vector.
 */
Vector3d.prototype.length = function() {
    return Math.sqrt(this.x*this.x + this.y*this.y + this.z*this.z);
}

/**
 * Normalizes a vector to its unit vector
 * – if the vector is already unit or is zero magnitude, this is a no-op.
 *
 * @returns {Vector3d} Normalised version of this vector.
 */
Vector3d.prototype.unit = function() {
    var norm = this.length();
    if (norm == 1) return this;
    if (norm == 0) return this;

    var x = this.x/norm;
    var y = this.y/norm;
    var z = this.z/norm;

    return new Vector3d(x, y, z);
}

/**
 * Calculates the angle between ‘this’ vector and supplied vector.
 *
 * @param   {Vector3d} v
 * @param   {Vector3d} [vSign] - If supplied, angle is signed +ve if clockwise looking along vSign,
 *     -ve in opposite direction (otherwise unsigned angle).
 * @returns {number} Angle (in radians) between this vector and supplied vector.
 */
Vector3d.prototype.angleTo = function(v, vSign) {
    var sinθ = this.cross(v).length();
    var cosθ = this.dot(v);

    if (typeof vSign != 'undefined') {
        // use vSign as reference to get sign of sinθ
        sinθ = this.cross(v).dot(vSign)<0 ? -sinθ : sinθ;
    }

    return Math.atan2(sinθ, cosθ);
}

/**
 * Rotates ‘this’ point around an axis by a specified angle.
 *
 * @param   {Vector3d} axis - The axis being rotated around.
 * @param   {number}   theta - The angle of rotation (in radians).
 * @returns {Vector3d} The rotated point.
 */
Vector3d.prototype.rotateAround = function(axis, theta) {
    // en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle
    // en.wikipedia.org/wiki/Quaternions_and_spatial_rotation#Quaternion-derived_rotation_matrix
    var p1 = this.unit();
    var p = [ p1.x, p1.y, p1.z ]; // the point being rotated
    var a = axis.unit();          // the axis being rotated around
    var s = Math.sin(theta);
    var c = Math.cos(theta);
    // quaternion-derived rotation matrix
    var q = [ [ a.x*a.x*(1-c) + c,     a.x*a.y*(1-c) - a.z*s, a.x*a.z*(1-c) + a.y*s],
        [ a.y*a.x*(1-c) + a.z*s, a.y*a.y*(1-c) + c,     a.y*a.z*(1-c) - a.x*s],
        [ a.z*a.x*(1-c) - a.y*s, a.z*a.y*(1-c) + a.x*s, a.z*a.z*(1-c) + c    ] ];
    // multiply q × p
    var qp = [0, 0, 0];
    for (var i=0; i<3; i++) {
        for (var j=0; j<3; j++) {
            qp[i] += q[i][j] * p[j];
        }
    }
    var p2 = new Vector3d(qp[0], qp[1], qp[2]);
    return p2;
    // qv en.wikipedia.org/wiki/Rodrigues'_rotation_formula...
}

/**
 * String representation of vector.
 *
 * @param   {number} [precision=3] - Number of decimal places to be used.
 * @returns {string} Vector represented as [x,y,z].
 */
Vector3d.prototype.toString = function(precision) {
    if (typeof precision == 'undefined') precision = 3;

    var p = Number(precision);

    var str = '[' + this.x.toFixed(p) + ',' + this.y.toFixed(p) + ',' + this.z.toFixed(p) + ']';

    return str;
}

/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */
if (!window.console) window.console = { log: function() {} };
<|endoftext|>


<commit_before>'use strict';

module.exports = function(verb) {
  verb.invoke('verb-generate-readme');

  verb.helper('tag', function(str) {
    return '{%= ' + str;
  });

  verb.helper('nickname', function(name) {
    return name.slice('helper-'.length);
  });

  verb.task('default', ['readme']);
};
<commit_msg>use `.extendWith` in verbfile<commit_after>'use strict';

module.exports = function(verb) {
  verb.extendWith('verb-generate-readme');

  verb.helper('tag', function(str) {
    return '{%= ' + str;
  });

  verb.helper('nickname', function(name) {
    return name.slice('helper-'.length);
  });

  verb.task('default', ['readme']);
};
<|endoftext|>


<commit_before>var jest = require('jest')
    ,models = require('../../models')
    ,common = require('./../common')
    ,async = require('async')
    ,getUserChosenDiscussions = require('../../deliver/routes/elections/fbimage').getUserChosenDiscussions
    ,_ = require('underscore');

var UserChosenDiscussionsResource = module.exports =  jest.Resource.extend({

    init:function () {
        this._super();
        this.allowed_methods = ['get'];
        this.update_fields = {
            user_id:null
        };
    },

    get_object:getUserChosenDiscussions
});
<commit_msg>same bug try #2<commit_after>var jest = require('jest')
    ,models = require('../../models')
    ,common = require('./../common')
    ,async = require('async')
    ,getUserChosenDiscussions = require('../../deliver/routes/elections/fbimage').getUserChosenDiscussions
    ,_ = require('underscore');

var UserChosenDiscussionsResource = module.exports =  jest.Resource.extend({

    init:function () {
        this._super();
        this.allowed_methods = ['get'];
        this.update_fields = {
            user_id:null
        };
        this.fields = {
            title: null,
            tooltip:null,
//        text_field:{type:mongoose_types.Html},
//        text_field_preview:{type:mongoose_types.Html},
            image_field: null,
            image_field_preview: null,
            subject_id: null,
            subject_name: null,
            system_message: null,
            creation_date: null,
            creator_id: null,
            first_name: null,
            last_name:null,
            text_field_preview: null,//2-3 lines of the vision_text
            text_field: null,
            vision_text_history: null,
            num_of_approved_change_suggestions: null,
            is_hot_object: null,
            is_cycle: null,
            tags: null,
            //users that connected somehow to discussion for my uru
            users: null,

            //followers for my uru
            followers: null,
            view_counter: null,
            followers_count: null,
            is_visible: null,
            is_published: null,
            grade: null,
            evaluate_counter: null,
            grade_sum: null,
            post_counter: null
        }
    },

    get_object:getUserChosenDiscussions
});
<|endoftext|>


<commit_before>// function that reloads the DOM for
// MathJax (http://www.mathjax.org/docs/1.1/typeset.html)
function reloadDOM() {
    MathJax.Hub.Queue(["Typeset", MathJax.Hub]);
}

function updateAnnotationPreview(){
    var updatedAnnotation = document.getElementById("new_annotation_content").value;

    var previewParagraph = document.getElementById("annotation_preview");
    var title = document.getElementById("annotation_preview_title");

    var firstIndex = updatedAnnotation.indexOf("$$");
    var secondIndex = updatedAnnotation.indexOf("$$", firstIndex + 1);

    if(firstIndex != -1 && secondIndex != -1 && firstIndex != secondIndex){
        title.show();
        previewParagraph.show();
        previewParagraph.innerHTML = updatedAnnotation;

        // typeset the preview
        MathJax.Hub.Queue(["Typeset", MathJax.Hub, previewParagraph]);
    }else{
        title.hide();
        previewParagraph.hide()
    }
}<commit_msg>Add timeout to preview rendering<commit_after>// function that reloads the DOM for
// MathJax (http://www.mathjax.org/docs/1.1/typeset.html)
function reloadDOM() {
    MathJax.Hub.Queue(["Typeset", MathJax.Hub]);
}

var timeout;
function updateAnnotationPreview(){
    var updatedAnnotation = document.getElementById("new_annotation_content").value;

    var previewParagraph = document.getElementById("annotation_preview");
    var title = document.getElementById("annotation_preview_title");

    var firstIndex = updatedAnnotation.indexOf("$$");
    var secondIndex = updatedAnnotation.indexOf("$$", firstIndex + 1);

    if(firstIndex != -1 && secondIndex != -1 && firstIndex != secondIndex){
        title.show();
        previewParagraph.show();
        previewParagraph.innerHTML = updatedAnnotation;

        if(timeout){
            clearTimeout(timeout)
            timeout = null
        }

        // typeset the preview
        timeout = setTimeout(function() {
            MathJax.Hub.Queue(["Typeset", MathJax.Hub, previewParagraph]);
            clearTimeout(timeout)
        }, 3000);

    }else{
        title.hide();
        previewParagraph.hide()
    }
}<|endoftext|>


<commit_before>(function () {

  function getEvent (event) {
    if (typeof event.originalEvent !== 'undefined') {
      return event.originalEvent;
    } else {
      return event;
    }
  }

  angular.module('ngPlayer', [])
  .factory('Player', ['$timeout', function ($timeout) {
    var nowPlayingItem, playing = false;
    var audioElement = angular.element('<audio></audio>')[0];
    var Player = {};

    function nowPlaying() {
      return nowPlayingItem;
    }

    function loadFile(file) {
      nowPlayingItem = (file || nowPlayingItem);
      if (audioElement.src != nowPlayingItem) {
        audioElement.src = nowPlayingItem;
      }
    }

    function play(file) {
      loadFile(file);
      audioElement.play();
      scheduleUpdate();
    }

    function stop () {
      audioElement.pause();
      nowPlayingItem = null;
      audioElement.src = null;
      audioElement.currentTime = 0;
      audioElement.duration = 0;
      Player.time = 0;
      Player.duration = 0;
    }

    function pause () {
      audioElement.pause();
    }

    function paused () {
      return audioElement.paused;
    }

    function ended () {
      return audioElement.ended;
    }

    function updateTimecodes () {
      Player.time = audioElement.currentTime;
      Player.duration = audioElement.duration;
    }

    function rewind () {
      seekTo(0);
    }

    function seekTo (position) {
      if (audioElement.duration) {
        audioElement.currentTime = position;
        $timeout(updateTimecodes, 0);
      } else {
        $timeout(function(){seekTo(position)}, 100);
      }
    }

    function scheduleUpdate () {
      updateTimecodes();
      if (!paused() && !ended()) $timeout(scheduleUpdate, 100);
    };

    Player.time = 0;
    Player.duration = 0;
    Player.pause = pause;
    Player.paused = paused;
    Player.nowPlaying = nowPlaying;
    Player.rewind = rewind;
    Player.play = play;
    Player.stop = stop;
    Player.seekTo = seekTo;

    return Player;
  }])
  .filter('timeCode', function () {
    function pad(number) {
      if (number < 10) {
        return "0" + number;
      }
      return number;
    }

    return function (data, options) {
      if (isNaN(data)) {
        return "00:00.0";
      }
      var date = new Date(data*1000);
      return [date.getUTCHours(), pad(date.getMinutes()), pad(date.getUTCSeconds())].join(':') + '.' + parseInt(date.getUTCMilliseconds()/100);
    }
  })
  .directive("verticalScrubber", ["Player", '$timeout', function (Player, $timeout) {
    return {
      restrict: 'C',
      link: function(scope, el, attr) {
        scope.player = Player;
        var mouseIsDown = false;

        var barEl = angular.element("

");
        scope.$watch('player.time', function (time) {
          barEl.css('height', time * 100 / Player.duration + "%");
        });
        el.bind('mousedown', function mouseIsDown (e) {
          e = getEvent(e);

          var element = this;
          var $this = angular.element(this);
          var $window = angular.element(window);
          var $body = angular.element(window.document.getElementsByTagName('body'));

          $body.addClass('scrubbing');
          var timeoutComplete = true;

          function markTimeoutComplete() {
            timeoutComplete = true;
          }

          function mouseIsMoving (e) {
            e = getEvent(e);
            var relativePosition = e.y - element.offsetTop;
            if (relativePosition >= 0) {
              var percentage = (relativePosition / element.offsetHeight);
              if (timeoutComplete) {
                timeoutComplete = false
                $timeout(function () { Player.seekTo((percentage * Player.duration)) }, 10).then(markTimeoutComplete, markTimeoutComplete);
              }
            }
          }

          $window.bind('mousemove', mouseIsMoving);

          function unbindAll () {
            $window.unbind('mouseup', unbindAll);
            $window.unbind('mousemove', mouseIsMoving);
            $body.removeClass('scrubbing');
          }

          $window.bind('mouseup', unbindAll);

          mouseIsMoving(e);
        });
        el.append(barEl);
      }
    }
  }])
  .directive("scrubber", ["Player", function (Player) {
    return {
      restrict: 'C',
      link: function (scope, el, attrs) {
        el.bind('click', function (e) {
          e = getEvent(e);
          var relativePosition = e.x - this.offsetLeft;
          var percentage = (relativePosition / this.offsetWidth);
          Player.seekTo(percentage * Player.duration);
        });
      }
    }
  }])
  .directive("transcript", ['Player','$parse', function (Player, $parse) {
    return {
      restrict: 'C',
      replace: true,
      template: '
' +
                  '
' +
                    '
' +
                      '	' +
                      '{{text.startTime}}	' +
                      '–	' +
                      '{{text.endTime}}	' +
                      '{{text.text}}
	' +
                      ''+
                        '	' +
                      '<input ng-model="editableTranscript" ng-show="editorEnabled">	' +
                      '' +
                        '' +
                          '' +
                        '' +
                          '	' +
                    '
' +
                  '
' +
                '
',
      link: function (scope, el, attrs) {
        var lastSecond = -1;

        scope.transcriptStart = 0;
        scope.transcript = $parse(attrs.transcriptText)(scope);
        scope.transcriptRows = {};
        scope.canEdit = $parse(attrs.transcriptEditable)(scope);

        angular.forEach(scope.transcript, function(row, index) {
          scope.transcriptRows[row.startTime] = index;
        });

        scope.seekTo = function(time) {
          scope.$emit('transcriptSeek', time);
        }

        //edit transcripts
        scope.editorEnabled = false;

        scope.enableEditor = function() {
          this.editorEnabled = true;
          this.editableTranscript = this.text.text;
        };

        scope.disableEditor = function() {
          this.editorEnabled = false;
        };

        if (scope.transcript && scope.transcript.length > 0) {
          scope.$watch('player.time', function (time) {
            var second = parseInt(time, 10);
            var height = angular.element(".file-transcript table tr")[0].scrollHeight;
            if (second != lastSecond) {
              if (second in scope.transcriptRows) {
                var index = scope.transcriptRows[second];

                if (index != undefined) {
                  el[0].scrollTop = Math.max((index - 1), 0) * height;
                  scope.transcriptStart = second;
                }
              }
              lastSecond = second;
            }
          });
        }

      }
    }
  }]);
})();<commit_msg>only show editing on transcript when there is an id - data has been converted<commit_after>(function () {

  function getEvent (event) {
    if (typeof event.originalEvent !== 'undefined') {
      return event.originalEvent;
    } else {
      return event;
    }
  }

  angular.module('ngPlayer', [])
  .factory('Player', ['$timeout', function ($timeout) {
    var nowPlayingItem, playing = false;
    var audioElement = angular.element('<audio></audio>')[0];
    var Player = {};

    function nowPlaying() {
      return nowPlayingItem;
    }

    function loadFile(file) {
      nowPlayingItem = (file || nowPlayingItem);
      if (audioElement.src != nowPlayingItem) {
        audioElement.src = nowPlayingItem;
      }
    }

    function play(file) {
      loadFile(file);
      audioElement.play();
      scheduleUpdate();
    }

    function stop () {
      audioElement.pause();
      nowPlayingItem = null;
      audioElement.src = null;
      audioElement.currentTime = 0;
      audioElement.duration = 0;
      Player.time = 0;
      Player.duration = 0;
    }

    function pause () {
      audioElement.pause();
    }

    function paused () {
      return audioElement.paused;
    }

    function ended () {
      return audioElement.ended;
    }

    function updateTimecodes () {
      Player.time = audioElement.currentTime;
      Player.duration = audioElement.duration;
    }

    function rewind () {
      seekTo(0);
    }

    function seekTo (position) {
      if (audioElement.duration) {
        audioElement.currentTime = position;
        $timeout(updateTimecodes, 0);
      } else {
        $timeout(function(){seekTo(position)}, 100);
      }
    }

    function scheduleUpdate () {
      updateTimecodes();
      if (!paused() && !ended()) $timeout(scheduleUpdate, 100);
    };

    Player.time = 0;
    Player.duration = 0;
    Player.pause = pause;
    Player.paused = paused;
    Player.nowPlaying = nowPlaying;
    Player.rewind = rewind;
    Player.play = play;
    Player.stop = stop;
    Player.seekTo = seekTo;

    return Player;
  }])
  .filter('timeCode', function () {
    function pad(number) {
      if (number < 10) {
        return "0" + number;
      }
      return number;
    }

    return function (data, options) {
      if (isNaN(data)) {
        return "00:00.0";
      }
      var date = new Date(data*1000);
      return [date.getUTCHours(), pad(date.getMinutes()), pad(date.getUTCSeconds())].join(':') + '.' + parseInt(date.getUTCMilliseconds()/100);
    }
  })
  .directive("verticalScrubber", ["Player", '$timeout', function (Player, $timeout) {
    return {
      restrict: 'C',
      link: function(scope, el, attr) {
        scope.player = Player;
        var mouseIsDown = false;

        var barEl = angular.element("

");
        scope.$watch('player.time', function (time) {
          barEl.css('height', time * 100 / Player.duration + "%");
        });
        el.bind('mousedown', function mouseIsDown (e) {
          e = getEvent(e);

          var element = this;
          var $this = angular.element(this);
          var $window = angular.element(window);
          var $body = angular.element(window.document.getElementsByTagName('body'));

          $body.addClass('scrubbing');
          var timeoutComplete = true;

          function markTimeoutComplete() {
            timeoutComplete = true;
          }

          function mouseIsMoving (e) {
            e = getEvent(e);
            var relativePosition = e.y - element.offsetTop;
            if (relativePosition >= 0) {
              var percentage = (relativePosition / element.offsetHeight);
              if (timeoutComplete) {
                timeoutComplete = false
                $timeout(function () { Player.seekTo((percentage * Player.duration)) }, 10).then(markTimeoutComplete, markTimeoutComplete);
              }
            }
          }

          $window.bind('mousemove', mouseIsMoving);

          function unbindAll () {
            $window.unbind('mouseup', unbindAll);
            $window.unbind('mousemove', mouseIsMoving);
            $body.removeClass('scrubbing');
          }

          $window.bind('mouseup', unbindAll);

          mouseIsMoving(e);
        });
        el.append(barEl);
      }
    }
  }])
  .directive("scrubber", ["Player", function (Player) {
    return {
      restrict: 'C',
      link: function (scope, el, attrs) {
        el.bind('click', function (e) {
          e = getEvent(e);
          var relativePosition = e.x - this.offsetLeft;
          var percentage = (relativePosition / this.offsetWidth);
          Player.seekTo(percentage * Player.duration);
        });
      }
    }
  }])
  .directive("transcript", ['Player','$parse', function (Player, $parse) {
    return {
      restrict: 'C',
      replace: true,
      template: '
' +
                  '
' +
                    '
' +
                      '	' +
                      '{{text.startTime}}	' +
                      '–	' +
                      '{{text.endTime}}	' +
                      '{{text.text}}
	' +
                      ''+
                        '	' +
                      '<input ng-model="editableTranscript" ng-show="editorEnabled">	' +
                      '' +
                        '' +
                          '' +
                        '' +
                          '	' +
                    '
' +
                  '
' +
                '
',
      link: function (scope, el, attrs) {
        var lastSecond = -1;

        scope.transcriptStart = 0;
        scope.transcript = $parse(attrs.transcriptText)(scope);
        scope.transcriptRows = {};
        scope.canEdit = $parse(attrs.transcriptEditable)(scope);

        angular.forEach(scope.transcript, function(row, index) {
          scope.transcriptRows[row.startTime] = index;
        });

        scope.seekTo = function(time) {
          scope.$emit('transcriptSeek', time);
        }

        //edit transcripts
        scope.editorEnabled = false;

        scope.canShowEditor = function() {
          return (!this.editorEnabled && scope.canEdit && (parseInt(this.text.id, 10) > 0));
        };

        scope.enableEditor = function() {
          this.editorEnabled = true;
          this.editableTranscript = this.text.text;
        };

        scope.disableEditor = function() {
          this.editorEnabled = false;
        };

        if (scope.transcript && scope.transcript.length > 0) {
          scope.$watch('player.time', function (time) {
            var second = parseInt(time, 10);
            var height = angular.element(".file-transcript table tr")[0].scrollHeight;
            if (second != lastSecond) {
              if (second in scope.transcriptRows) {
                var index = scope.transcriptRows[second];

                if (index != undefined) {
                  el[0].scrollTop = Math.max((index - 1), 0) * height;
                  scope.transcriptStart = second;
                }
              }
              lastSecond = second;
            }
          });
        }

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