<commit_before>import nextFrame from '../utils/next-frame';
import Ember from 'ember';

const {
  guidFor
  } = Ember;

export default class FrameQueue {

  constructor(options) {
    this.queueNames = options.queueNames;
    this.queues = {};
    this.items = [];
    this.queueNames.forEach((name)=> {
      this.queues[name] = [];
    });
  }

  schedule(queueName, context, method, ...args) {
    let queueItem = FrameQueue._createItem(queueName, context, method, args);
    this.items.push(queueItem);
    this.queues[queueName].push(queueItem);
    return guidFor(queueItem);
  }

  findByMethod(queueName, context, method) {
    return this.items.find((i) => {
      return i.queueName === queueName &&
        i.method === method &&
        i.context === context;
    });
  }

  findByGuid(guid) {
    return this.items.find((item) => {
      return guidFor(item) === guid;
    });
  }

  static _createItem(queueName, context, method, args) {
    return {
      context: context,
      method: method,
      args: args,
      queue: queueName
    };
  }

  scheduleOnce(queueName, context, method, ...args) {
    let item = this.findByMethod(queueName, method, context);
    if (item) {
      item.args = args;
    } else {
      item = FrameQueue._createItem(queueName, context, method, args);
    }
    return guidFor(item);
  }

  _remove(item) {
    this.items.splice(this.items.indexOf(item), 1);
    let queue = this.queues[item.queueNames];
    queue.splice(queue.indexOf(item), 1);
  }

  cancel(guid) {
    let item = this.findByGuid(guid);
    if (!item) {
      return false;
    }
    this._remove(item);
    return true;
  }

  static flushQueue(queue) {
    let work;
    while (work = queue.pop()) {
      work[1].apply(work[0], work[2]);
    }
  }

  render() {
    return nextFrame(this, function() {
      this.queueNames.forEach((name) => {
        FrameQueue.flushQueue(this.queues[name]);
      });
    });
  }

}
<commit_msg>cleaner syntax<commit_after>import nextFrame from '../utils/next-frame';
import Ember from 'ember';

const {
  guidFor
  } = Ember;

export default class FrameQueue {

  constructor(options) {
    this.queueNames = options.queueNames;
    this.queues = {};
    this.items = [];
    this.queueNames.forEach((name)=> {
      this.queues[name] = [];
    });
  }

  schedule(queueName, context, method, ...args) {
    let queueItem = FrameQueue._createItem(queueName, context, method, args);
    this.items.push(queueItem);
    this.queues[queueName].push(queueItem);
    return guidFor(queueItem);
  }

  findByMethod(queueName, context, method) {
    return this.items.find((i) => {
      return i.queueName === queueName &&
        i.method === method &&
        i.context === context;
    });
  }

  findByGuid(guid) {
    return this.items.find((item) => {
      return guidFor(item) === guid;
    });
  }

  static _createItem(queueName, context, method, args) {
    return {
      context,
      method,
      args,
      queueName
    };
  }

  scheduleOnce(queueName, context, method, ...args) {
    let item = this.findByMethod(queueName, method, context);
    if (item) {
      item.args = args;
    } else {
      item = FrameQueue._createItem(queueName, context, method, args);
    }
    return guidFor(item);
  }

  _remove(item) {
    this.items.splice(this.items.indexOf(item), 1);
    let queue = this.queues[item.queueName];
    queue.splice(queue.indexOf(item), 1);
  }

  cancel(guid) {
    let item = this.findByGuid(guid);
    if (!item) {
      return false;
    }
    this._remove(item);
    return true;
  }

  static flushQueue(queue) {
    let work;
    while (work = queue.pop()) {
      work[1].apply(work[0], work[2]);
    }
  }

  render() {
    return nextFrame(this, function() {
      this.queueNames.forEach((name) => {
        FrameQueue.flushQueue(this.queues[name]);
      });
    });
  }

}
<|endoftext|>


<commit_before>/*! Kernel CI Dashboard | Licensed under the GNU GPL v3 (or later) */
require([
    'jquery',
    'utils/init',
    'utils/base',
    'utils/error',
    'utils/request',
    'utils/table',
    'utils/urls',
    'charts/passpie',
    'charts/diffmatrix',
    'utils/date'
], function($, init, b, e, r, table, u, pie, matrix) {
    'use strict';
    var compareId = null,
        comparedTable,
        nonAvail,
        tableDom;

    document.getElementById('li-compare').setAttribute('class', 'active');

    nonAvail = '' +
        '';

    tableDom = '<"row"' +
        '<"col-xs-12 col-sm-12 col-md-12 col-lg-12"t>>';

    // Calculate total diff between the baseline and what is being compared
    // against.
    // Return a string with the total from the compared one and a diff number.
    function calculateTotalDiff(baseline, compared) {
        var totalDiff = 0,
            display;

        totalDiff = compared - baseline;
        if (totalDiff === 0) {
            display = compared + ' (±0)';
        } else if (totalDiff > 0) {
            display = compared + ' (+' + totalDiff + ')';
        } else {
            display = compared + ' (' + totalDiff + ')';
        }

        return display;
    }

    function setupCompareToTable(comparedData, baseline) {
        var columns;
        columns = [
            {
                data: 'job',
                title: 'Tree ‐ Branch',
                className: 'tree-column',
                render: function(data, type, object) {
                    var rend;
                    if (type === 'display') {
                        rend = '' + data;

                        if (object.git_branch !== null) {
                            rend += ' ‐ ' +
                                object.git_branch + '';
                        }
                        rend += '';
                    } else {
                        rend = data;
                        if (object.git_branch !== null) {
                            rend += ' ' + object.git_branch;
                        }
                    }
                    return rend;
                }
            },
            {
                data: 'kernel',
                title: 'Kernel',
                type: 'string',
                className: 'kernel-column',
                render: function(data, type) {
                    var rend = data;
                    if (type === 'display') {
                        rend = '' + data + '';
                    }
                    return rend;
                }
            },
            {
                data: 'git_commit',
                title: 'Commit',
                type: 'string',
                render: function(data, type, object) {
                    var rend = data,
                        cUrl;
                    if (type === 'display') {
                        cUrl = u.translateCommit(object.git_url, data);
                        rend = '';
                        if (cUrl[1] !== null) {
                            rend += '' + data + '';
                        } else {
                            rend += data;
                        }

                        rend += '';
                    }
                    return rend;
                }
            },
            {
                data: 'total_builds',
                title: 'Total Builds',
                className: 'pull-center',
                render: function(data, type) {
                    var rend = data;
                    if (type === 'display' || type === 'filter') {
                        rend = calculateTotalDiff(baseline.total_builds, data);
                    }
                    return rend;
                }
            },
            {
                data: 'created_on',
                title: 'Date',
                type: 'date',
                className: 'date-column pull-center',
                render: function(data, type) {
                    var created = new Date(data.$date);
                    if (type === 'display' || type === 'filter') {
                        created = created.toCustomISODate();
                    }
                    return created;
                }
            },
            {
                data: 'job',
                title: '',
                orderable: false,
                searchable: false,
                className: 'pull-center',
                render: function(data, type, object) {
                    var rend = '';
                    if (type === 'display') {
                        rend = '' +
                            '' +
                            '';
                    }
                    return rend;
                }
            }
        ];

        comparedTable
            .dom(tableDom)
            .data(comparedData)
            .columns(columns)
            .order([4, 'desc'])
            .noIdURL(true)
            .rowURLElements(['job', 'kernel'])
            .draw();
    }

    function setupBaselineData(baseline) {
        var baseCreatedOn,
            baseGitCommit,
            baseGitUrl,
            baseJob,
            baseKernel,
            baseTotalBuilds,
            translatedGitUrl;

        baseGitCommit = baseline.git_commit;
        baseGitUrl = baseline.git_url;
        baseTotalBuilds = baseline.total_builds;
        baseJob = baseline.job;
        baseKernel = baseline.kernel;

        translatedGitUrl = u.translateCommit(baseGitUrl, baseGitCommit);

        b.replaceById(
            'dd-tree',
            '' +
            '' + baseJob + '' +
            ' — ' +
            '' +
            '' +
            '' +
            ''
        );
        b.replaceById('dd-branch', baseline.git_branch);
        b.replaceById(
            'dd-kernel',
                '' +
                '' + baseKernel + '' +
                ' — ' +
                '' +
                '' + ''
        );

        if (translatedGitUrl[0] !== null) {
            b.replaceById(
                'dd-url',
                '' + baseGitUrl +
                ' '
            );
        } else {
            if (baseGitUrl !== null) {
                b.replaceById('dd-url', baseGitUrl);
            } else {
                b.replaceById('dd-url', nonAvail);
            }
        }

        if (translatedGitUrl[1] !== null) {
            b.replaceById(
                'dd-commit',
                '' + baseGitCommit +
                ' '
            );
        } else {
            if (baseGitCommit !== null) {
                b.replaceById('dd-commit', baseGitCommit);
            } else {
                b.replaceById('dd-commit', nonAvail);
            }
        }

        b.replaceById('dd-total', baseTotalBuilds);
        baseCreatedOn = new Date(baseline.created_on.$date);
        b.replaceById('dd-date', baseCreatedOn.toCustomISODate());
    }

    function getJobCompareFail() {
        b.replaceByClass('loading-content', nonAvail);
        b.replaceByClass(
            'no-data',
            '
' +
            'Error loading data.
'
        );
    }

    function getJobCompareDone(response) {
        var result = response.result,
            resLen = result.length,
            baseline,
            comparedData,
            matrixData,
            deltaResult;

        if (resLen > 0) {
            baseline = result[0].baseline;
            comparedData = result[0].compare_to;
            deltaResult = result[0].delta_result;

            b.replaceById(
                'body-title',
                'for «' + baseline.job +
                '» ‐ ' + baseline.kernel
            );

            setupBaselineData(baseline);
            setupCompareToTable(comparedData, baseline);

            pie.buildpie(
                'build-chart',
                [baseline.total_builds, baseline.build_counts],
                function(resp) {
                    return resp;
                }
            );

            if (deltaResult.length > 0) {
                matrixData = {
                    xdata: [baseline],
                    ydata: deltaResult
                };

                Array.prototype.push.apply(matrixData.xdata, comparedData);
                matrix.builds('builds-matrix', matrixData);
            } else {
                b.replaceById(
                    'builds-matrix',
                    '
' +
                    'No differences to show.
'
                );
            }
        } else {
            b.replaceByClass('loading-content', nonAvail);
            b.replaceByClass(
                'no-data',
                '
' +
                'No data available.
'
            );
        }
    }

    function getJobCompare() {
        var deferred;

        if (compareId !== null) {
            comparedTable = table({
                tableId: 'compared-against'
            });
            deferred = r.get('/_ajax/job/compare/' + compareId, {});
            $.when(deferred)
                .fail(e.error, getJobCompareFail)
                .done(getJobCompareDone);
        } else {
            b.replaceByClass('loading-content', nonAvail);
            b.replaceByClass(
                'no-data',
                '
' +
                'No data available.
'
            );
            e.customError(
                400, 'Missing job comparison ID value: please specify one.');
        }
    }

    if (document.getElementById('compare-id') !== null) {
        compareId = document.getElementById('compare-id').value;
    }

    getJobCompare();

    init.hotkeys();
    init.tooltip();
});
<commit_msg>Refactor job-compare view<commit_after>/*! Kernel CI Dashboard | Licensed under the GNU GPL v3 (or later) */
require([
    'jquery',
    'utils/init',
    'utils/error',
    'utils/request',
    'utils/table',
    'utils/urls',
    'charts/passpie',
    'charts/diffmatrix',
    'utils/html',
    'tables/job',
    'utils/date'
], function($, init, e, r, table, urls, pie, matrix, html, jobt) {
    'use strict';
    var gCompareId,
        gComparedTable;

    document.getElementById('li-compare').setAttribute('class', 'active');

    // Calculate total diff between the baseline and what is being compared
    // against.
    // Return a string with the total from the compared one and a diff number.
    function calculateTotalDiff(baseline, compared) {
        var display,
            totalDiff;

        totalDiff = compared - baseline;
        if (totalDiff === 0) {
            display = compared + ' (±0)';
        } else if (totalDiff > 0) {
            display = compared + ' (+' + totalDiff + ')';
        } else {
            display = compared + ' (' + totalDiff + ')';
        }

        return display;
    }

    function setupCompareToTable(comparedData, baseline) {
        var columns,
            dom;

        /**
         * Wrapper to provide the href.
        **/
        function _renderDetails(data, type, object) {
            return jobt.renderDetails(
                '/build/' + data + '/kernel/' + object.kernel + '/', type);
        }

        function _renderTotal(data, type) {
            var rendered;

            rendered = data;
            if (type === 'display' || type === 'filter') {
                rendered = calculateTotalDiff(baseline.total_builds, data);
            }
            return rendered;
        }

        function _renderCommit(data, type, object) {
            var aNode,
                rendered,
                textNode,
                tooltipNode,
                gitURL;

            rendered = data;
            if (type === 'display') {
                gitURL = urls.translateCommit(object.git_url, data);
                tooltipNode = html.tooltip();
                tooltipNode.setAttribute('title', data);

                if (gitURL[1] !== null) {
                    aNode = document.createElement('a');
                    aNode.setAttribute('href', gitURL[1]);

                    textNode = document.createTextNode(data);
                    aNode.appendChild(textNode);

                    tooltipNode.appendChild(aNode);
                } else {
                    textNode = document.createTextNode(data);
                    tooltipNode.appendChild(textNode);
                }

                rendered = tooltipNode.outerHTML;
                // Remove the nodes.
                textNode.remove();
                if (aNode) {
                    aNode.remove();
                }
                tooltipNode.remove();
            }

            return rendered;
        }

        dom = '<"row"' +
            '<"col-xs-12 col-sm-12 col-md-12 col-lg-12"t>>';

        columns = [
            {
                data: 'job',
                title: 'Tree',
                type: 'string',
                className: 'tree-column',
                render: jobt.renderTree
            },
            {
                data: 'git_branch',
                title: 'Branch',
                type: 'string',
                className: 'branch-column'
            },
            {
                data: 'kernel',
                title: 'Kernel',
                type: 'string',
                className: 'kernel-column',
                render: jobt.renderKernel
            },
            {
                data: 'git_commit',
                title: 'Commit',
                type: 'string',
                render: _renderCommit
            },
            {
                data: 'total_builds',
                title: 'Total Builds',
                type: 'string',
                className: 'pull-center',
                render: _renderTotal
            },
            {
                data: 'created_on',
                title: 'Date',
                type: 'date',
                className: 'date-column pull-center',
                render: jobt.renderDate
            },
            {
                data: 'job',
                title: '',
                type: 'string',
                orderable: false,
                searchable: false,
                className: 'pull-center',
                render: _renderDetails
            }
        ];

        gComparedTable
            .dom(dom)
            .data(comparedData)
            .columns(columns)
            .order([5, 'desc'])
            .noIdURL(true)
            .rowURLElements(['job', 'kernel'])
            .draw();
    }

    function setupBaselineData(baseline) {
        var aNode,
            baseGitCommit,
            baseGitUrl,
            baseJob,
            baseKernel,
            baseTotalBuilds,
            gitURLs,
            spanNode,
            tooltipNode;

        baseGitCommit = baseline.git_commit;
        baseGitUrl = baseline.git_url;
        baseTotalBuilds = parseInt(baseline.total_builds, 10);
        baseJob = baseline.job;
        baseKernel = baseline.kernel;

        gitURLs = urls.translateCommit(baseGitUrl, baseGitCommit);

        // Tree.
        spanNode = document.createElement('span');

        tooltipNode = html.tooltip();
        tooltipNode.setAttribute('title', 'Details for tree ' + baseJob);

        aNode = document.createElement('a');
        aNode.setAttribute('href', '/job/' + baseJob + '/');
        aNode.appendChild(document.createTextNode(baseJob));

        tooltipNode.appendChild(aNode);
        spanNode.appendChild(tooltipNode);

        tooltipNode = html.tooltip();
        tooltipNode.setAttribute(
            'title', 'Boot reports for tree ' + baseJob);

        aNode = document.createElement('a');
        aNode.setAttribute('href', '/boot/all/job/' + baseJob + '/');
        aNode.appendChild(html.boot());

        tooltipNode.appendChild(aNode);

        spanNode.insertAdjacentHTML('beforeend', ' — ');
        spanNode.appendChild(tooltipNode);

        html.replaceContent(document.getElementById('dd-tree'), spanNode);

        // Git branch.
        html.replaceContent(
            document.getElementById('dd-branch'),
            document.createTextNode(baseline.git_branch));

        // Kernel.
        spanNode = document.createElement('span');

        tooltipNode = html.tooltip();
        tooltipNode.setAttribute(
            'title',
            'Build details for ' + baseJob +
            ' ‐ ' + baseKernel
        );

        aNode = document.createElement('a');
        aNode.setAttribute(
            'href', '/build/' + baseJob + '/kernel/' + baseKernel + '/');
        aNode.appendChild(document.createTextNode(baseKernel));

        tooltipNode.appendChild(aNode);
        spanNode.appendChild(tooltipNode);

        tooltipNode = html.tooltip();
        tooltipNode.setAttribute(
            'title',
            'Boot reports for ' + baseJob +
            ' ‐ ' + baseKernel
        );

        aNode = document.createElement('a');
        aNode.setAttribute(
            'href',
            '/boot/all/job/' + baseJob + '/kernel/' + baseKernel + '/');
        aNode.appendChild(html.boot());

        tooltipNode.appendChild(aNode);
        spanNode.insertAdjacentHTML('beforeend', ' — ');
        spanNode.appendChild(tooltipNode);

        html.replaceContent(document.getElementById('dd-kernel'), spanNode);

        // Git URL/commit.
        if (gitURLs[0] !== null) {
            aNode = document.createElement('a');
            aNode.setAttribute('href', gitURLs[0]);
            aNode.appendChild(document.createTextNode(baseGitUrl));
            aNode.insertAdjacentHTML('beforeend', ' ');
            aNode.appendChild(html.external());

            html.replaceContent(
                document.getElementById('dd-url'), aNode);
        } else {
            if (baseGitUrl !== null) {
                html.replaceContent(
                    document.getElementById('dd-url'),
                    document.createTextNode(baseGitUrl));
            } else {
                html.replaceContent(
                    document.getElementById('dd-url'), html.nonavail());
            }
        }

        if (gitURLs[1] !== null) {
            aNode = document.createElement('a');
            aNode.setAttribute('href', gitURLs[1]);
            aNode.appendChild(document.createTextNode(baseGitCommit));
            aNode.insertAdjacentHTML('beforeend', ' ');
            aNode.appendChild(html.external());

            html.replaceContent(
                document.getElementById('dd-commit'), aNode);
        } else {
            if (baseGitCommit !== null) {
                html.replaceContent(
                    document.getElementById('dd-commit'),
                    document.createTextNode(baseGitCommit));
            } else {
                html.replaceContent(
                    document.getElementById('dd-commit'),
                    html.nonavail());
            }
        }

        html.replaceContent(
            document.getElementById('dd-total'),
            document.createTextNode(baseTotalBuilds));

        html.replaceContent(
            document.getElementById('dd-date'),
            html.time(baseline.created_on));
    }

    function getJobCompareFail() {
        html.replaceByClassNode('loading-content', html.nonavail().outerHTML);
        html.replaceContent(
            document.getElementById('summary-table-div'),
            html.errorDiv('Error loading data.'));
    }

    function getJobCompareDone(response) {
        var baseline,
            comparedData,
            deltaResult,
            matrixData,
            results,
            titleNode;

        results = response.result;
        if (results.length > 0) {
            baseline = results[0].baseline;
            comparedData = results[0].compare_to;
            deltaResult = results[0].delta_result;

            titleNode = document.getElementById('body-title');
            titleNode.insertAdjacentHTML(
                'beforeend',
                'for «' + baseline.job +
                '» ‐ ' + baseline.kernel
            );

            setupBaselineData(baseline);
            setupCompareToTable(comparedData, baseline);

            pie.buildpie(
                'build-chart',
                [baseline.total_builds, baseline.build_counts],
                function(resp) {
                    return resp;
                }
            );

            if (deltaResult.length > 0) {
                matrixData = {
                    xdata: [baseline],
                    ydata: deltaResult
                };

                Array.prototype.push.apply(matrixData.xdata, comparedData);
                matrix.builds('builds-matrix', matrixData);
            } else {
                html.replaceContent(
                    document.getElementById('builds-matrix'),
                    html.errorDiv('No differences to show.'));
            }
        } else {
            html.replaceByClassHTML(
                'loading-content', html.nonavail().outerHTML);
            html.replaceContent(
                document.getElementById('summary-table-div'),
                html.errorDiv('No data available.'));
            html.replaceContent(
                document.getElementById('builds-matrix'),
                html.errorDiv('No data available.'));
        }
    }

    function getJobCompare() {
        var deferred;

        if (gCompareId !== null) {
            gComparedTable = table({
                tableId: 'compared-against'
            });

            deferred = r.get('/_ajax/job/compare/' + gCompareId, {});
            $.when(deferred)
                .fail(e.error, getJobCompareFail)
                .done(getJobCompareDone);
        } else {
            html.replaceByClassHTML(
                'loading-content', html.nonavail().outerHTML);
            html.replaceContent(
                document.getElementById('summary-table-div'),
                html.errorDiv('Error loading data.'));
            html.replaceContent(
                document.getElementById('builds-matrix'),
                html.errorDiv('Error loading data.'));
            e.customError(
                400, 'Missing job comparison ID value: please specify one.');
        }
    }

    if (document.getElementById('compare-id') !== null) {
        gCompareId = document.getElementById('compare-id').value;
    }

    getJobCompare();

    init.hotkeys();
    init.tooltip();
});
<|endoftext|>


<commit_before>import React, { Component } from 'react'
import { StyleSheet } from 'react-native'
import TabBarNavigation from './tab-bar-navigation/TabBarNavigation'

import moment from 'moment'
import nbLocale  from 'moment/locale/nb'
import SplashScreen from 'react-native-splash-screen'

class App extends Component {

    componentDidMount() {
        SplashScreen.hide();
    }

    render () {
        moment.updateLocale('nb', nbLocale)
        return (
            <TabBarNavigation style={styles.container}/>
        )
    }
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
        justifyContent: 'center',
        alignItems: 'center',
        backgroundColor: '#F5FCFF'
    },
    welcome: {
        fontSize: 20,
        textAlign: 'center',
        margin: 10
    },
    instructions: {
        textAlign: 'center',
        color: '#333333',
        marginBottom: 5
    }
})

export default App
<commit_msg>fixed linter issues<commit_after>import React, { Component } from 'react'
import { StyleSheet } from 'react-native'
import TabBarNavigation from './tab-bar-navigation/TabBarNavigation'

import moment from 'moment'
import nbLocale  from 'moment/locale/nb'
import SplashScreen from 'react-native-splash-screen'

class App extends Component {

    componentDidMount() {
        SplashScreen.hide()
    }

    render () {
        moment.updateLocale('nb', nbLocale)
        return (
            <TabBarNavigation style={styles.container}/>
        )
    }
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
        justifyContent: 'center',
        alignItems: 'center',
        backgroundColor: '#F5FCFF'
    },
    welcome: {
        fontSize: 20,
        textAlign: 'center',
        margin: 10
    },
    instructions: {
        textAlign: 'center',
        color: '#333333',
        marginBottom: 5
    }
})

export default App
<|endoftext|>


<commit_before>const MetaTraderConfig = require('./metatrader.config');
const MetaTraderUI     = require('./metatrader.ui');
const Client           = require('../../../base/client');
const BinarySocket     = require('../../../base/socket');
const Validation       = require('../../../common/form_validation');
const localize         = require('../../../../_common/localize').localize;
const State            = require('../../../../_common/storage').State;
const toTitleCase      = require('../../../../_common/string_util').toTitleCase;

const MetaTrader = (() => {
    const mt_companies  = MetaTraderConfig.mt_companies;
    const accounts_info = MetaTraderConfig.accounts_info;
    const actions_info  = MetaTraderConfig.actions_info;
    const fields        = MetaTraderConfig.fields;

    const mt_company = {};

    const onLoad = () => {
        BinarySocket.wait('landing_company', 'get_account_status').then(() => {
            if (isEligible()) {
                MetaTraderUI.switchToMT5();
                getAllAccountsInfo();
                MetaTraderUI.init(submit);
            } else {
                MetaTraderUI.displayPageError(localize('Sorry, this feature is not available in your jurisdiction.'));
            }
        });
    };

    const isEligible = () => {
        let has_mt_company = false;
        Object.keys(mt_companies).forEach((company) => {
            mt_company[company] = State.getResponse(`landing_company.mt_${company}_company.shortcode`);
            if (mt_company[company]) {
                has_mt_company = true;
                addAccount(company);
            }
        });

        const is_ico_only = /ico_only/.test(State.getResponse('get_account_status.status'));

        return (!is_ico_only && has_mt_company);
    };

    const addAccount = (company) => {
        ['demo', 'real'].forEach((type) => {
            Object.keys(mt_companies[company]).forEach((acc_type) => {
                const company_info     = mt_companies[company][acc_type];
                const mt5_account_type = company_info.mt5_account_type;
                const title            = localize(`${toTitleCase(type)} ${company_info.title}`);
                const is_demo          = type === 'demo';

                accounts_info[`${type}_${mt_company[company]}${mt5_account_type ? `_${mt5_account_type}` : ''}`] = {
                    title,
                    is_demo,
                    mt5_account_type,
                    account_type: is_demo ? 'demo' : company,
                    max_leverage: company_info.max_leverage,
                    short_title : company_info.title,
                };
            });
        });
    };

    const getAllAccountsInfo = () => {
        BinarySocket.wait('mt5_login_list').then((response) => {
            // Ignore old accounts which are not linked to any group or has deprecated group
            const mt5_login_list = (response.mt5_login_list || []).filter(obj => (
                obj.group && Client.getMT5AccountType(obj.group) in accounts_info
            ));

            // Update account info
            mt5_login_list.forEach((obj) => {
                const acc_type = Client.getMT5AccountType(obj.group);
                accounts_info[acc_type].info = { login: obj.login };
                getAccountDetails(obj.login, acc_type);
            });

            Client.set('mt5_account', getDefaultAccount());

            // Update types with no account
            Object.keys(accounts_info)
                .filter(acc_type => !hasAccount(acc_type))
                .forEach((acc_type) => { MetaTraderUI.updateAccount(acc_type); });
        });
    };

    const getDefaultAccount = () => {
        let default_account = '';
        if (hasAccount(location.hash.substring(1))) {
            default_account = location.hash.substring(1);
            MetaTraderUI.removeUrlHash();
        } else if (hasAccount(Client.get('mt5_account'))) {
            default_account = Client.get('mt5_account');
        } else {
            default_account = Object.keys(accounts_info)
                .filter(acc_type => hasAccount(acc_type))
                .sort(acc_type => (accounts_info[acc_type].is_demo ? 1 : -1))[0] || ''; // real first
        }
        return default_account;
    };

    const hasAccount = acc_type => (accounts_info[acc_type] || {}).info;

    const getAccountDetails = (login, acc_type) => {
        BinarySocket.send({
            mt5_get_settings: 1,
            login,
        }).then((response) => {
            if (response.mt5_get_settings) {
                accounts_info[acc_type].info = response.mt5_get_settings;
                MetaTraderUI.updateAccount(acc_type);
            }
        });
    };

    const makeRequestObject = (acc_type, action) => {
        const req = {};

        Object.keys(fields[action]).forEach((field) => {
            const field_obj = fields[action][field];
            if (field_obj.request_field) {
                req[field_obj.request_field] = MetaTraderUI.$form().find(field_obj.id).val();
            }
        });

        // set main command
        req[`mt5_${action}`] = 1;

        // add additional fields
        $.extend(req, fields[action].additional_fields(acc_type));

        return req;
    };

    const submit = (e) => {
        e.preventDefault();
        const $btn_submit = $(e.target);
        const acc_type    = $btn_submit.attr('acc_type');
        const action      = $btn_submit.attr('action');
        MetaTraderUI.hideFormMessage(action);
        if (Validation.validate(`#frm_${action}`)) {
            MetaTraderUI.disableButton(action);
            // further validations before submit (password_check)
            MetaTraderUI.postValidate(acc_type, action).then((is_ok) => {
                if (!is_ok) {
                    MetaTraderUI.enableButton(action);
                    return;
                }

                const req = makeRequestObject(acc_type, action);
                BinarySocket.send(req).then((response) => {
                    if (response.error) {
                        MetaTraderUI.displayFormMessage(response.error.message, action);
                        MetaTraderUI.enableButton(action);
                    } else {
                        const login = actions_info[action].login ?
                            actions_info[action].login(response) : accounts_info[acc_type].info.login;
                        if (!accounts_info[acc_type].info) {
                            accounts_info[acc_type].info = { login };
                            MetaTraderUI.setAccountType(acc_type, true);
                        }
                        MetaTraderUI.loadAction(null, acc_type);
                        getAccountDetails(login, acc_type);
                        if (typeof actions_info[action].success_msg === 'function') {
                            MetaTraderUI.displayMainMessage(actions_info[action].success_msg(response));
                        }
                        if (typeof actions_info[action].onSuccess === 'function') {
                            actions_info[action].onSuccess(response, acc_type);
                        }
                    }
                    MetaTraderUI.enableButton(action);
                });
            });
        }
    };

    const onUnload = () => {
        MetaTraderUI.switchToMT5(false);
    };

    return {
        onLoad,
        onUnload,
        isEligible,
    };
})();

module.exports = MetaTrader;
<commit_msg>Update login list on new account creation<commit_after>const MetaTraderConfig = require('./metatrader.config');
const MetaTraderUI     = require('./metatrader.ui');
const Client           = require('../../../base/client');
const BinarySocket     = require('../../../base/socket');
const Validation       = require('../../../common/form_validation');
const localize         = require('../../../../_common/localize').localize;
const State            = require('../../../../_common/storage').State;
const toTitleCase      = require('../../../../_common/string_util').toTitleCase;

const MetaTrader = (() => {
    const mt_companies  = MetaTraderConfig.mt_companies;
    const accounts_info = MetaTraderConfig.accounts_info;
    const actions_info  = MetaTraderConfig.actions_info;
    const fields        = MetaTraderConfig.fields;

    const mt_company = {};

    const onLoad = () => {
        BinarySocket.wait('landing_company', 'get_account_status').then(() => {
            if (isEligible()) {
                MetaTraderUI.switchToMT5();
                getAllAccountsInfo();
                MetaTraderUI.init(submit);
            } else {
                MetaTraderUI.displayPageError(localize('Sorry, this feature is not available in your jurisdiction.'));
            }
        });
    };

    const isEligible = () => {
        let has_mt_company = false;
        Object.keys(mt_companies).forEach((company) => {
            mt_company[company] = State.getResponse(`landing_company.mt_${company}_company.shortcode`);
            if (mt_company[company]) {
                has_mt_company = true;
                addAccount(company);
            }
        });

        const is_ico_only = /ico_only/.test(State.getResponse('get_account_status.status'));

        return (!is_ico_only && has_mt_company);
    };

    const addAccount = (company) => {
        ['demo', 'real'].forEach((type) => {
            Object.keys(mt_companies[company]).forEach((acc_type) => {
                const company_info     = mt_companies[company][acc_type];
                const mt5_account_type = company_info.mt5_account_type;
                const title            = localize(`${toTitleCase(type)} ${company_info.title}`);
                const is_demo          = type === 'demo';

                accounts_info[`${type}_${mt_company[company]}${mt5_account_type ? `_${mt5_account_type}` : ''}`] = {
                    title,
                    is_demo,
                    mt5_account_type,
                    account_type: is_demo ? 'demo' : company,
                    max_leverage: company_info.max_leverage,
                    short_title : company_info.title,
                };
            });
        });
    };

    const getAllAccountsInfo = () => {
        BinarySocket.wait('mt5_login_list').then((response) => {
            // Ignore old accounts which are not linked to any group or has deprecated group
            const mt5_login_list = (response.mt5_login_list || []).filter(obj => (
                obj.group && Client.getMT5AccountType(obj.group) in accounts_info
            ));

            // Update account info
            mt5_login_list.forEach((obj) => {
                const acc_type = Client.getMT5AccountType(obj.group);
                accounts_info[acc_type].info = { login: obj.login };
                getAccountDetails(obj.login, acc_type);
            });

            Client.set('mt5_account', getDefaultAccount());

            // Update types with no account
            Object.keys(accounts_info)
                .filter(acc_type => !hasAccount(acc_type))
                .forEach((acc_type) => { MetaTraderUI.updateAccount(acc_type); });
        });
    };

    const getDefaultAccount = () => {
        let default_account = '';
        if (hasAccount(location.hash.substring(1))) {
            default_account = location.hash.substring(1);
            MetaTraderUI.removeUrlHash();
        } else if (hasAccount(Client.get('mt5_account'))) {
            default_account = Client.get('mt5_account');
        } else {
            default_account = Object.keys(accounts_info)
                .filter(acc_type => hasAccount(acc_type))
                .sort(acc_type => (accounts_info[acc_type].is_demo ? 1 : -1))[0] || ''; // real first
        }
        return default_account;
    };

    const hasAccount = acc_type => (accounts_info[acc_type] || {}).info;

    const getAccountDetails = (login, acc_type) => {
        BinarySocket.send({
            mt5_get_settings: 1,
            login,
        }).then((response) => {
            if (response.mt5_get_settings) {
                accounts_info[acc_type].info = response.mt5_get_settings;
                MetaTraderUI.updateAccount(acc_type);
            }
        });
    };

    const makeRequestObject = (acc_type, action) => {
        const req = {};

        Object.keys(fields[action]).forEach((field) => {
            const field_obj = fields[action][field];
            if (field_obj.request_field) {
                req[field_obj.request_field] = MetaTraderUI.$form().find(field_obj.id).val();
            }
        });

        // set main command
        req[`mt5_${action}`] = 1;

        // add additional fields
        $.extend(req, fields[action].additional_fields(acc_type));

        return req;
    };

    const submit = (e) => {
        e.preventDefault();
        const $btn_submit = $(e.target);
        const acc_type    = $btn_submit.attr('acc_type');
        const action      = $btn_submit.attr('action');
        MetaTraderUI.hideFormMessage(action);
        if (Validation.validate(`#frm_${action}`)) {
            MetaTraderUI.disableButton(action);
            // further validations before submit (password_check)
            MetaTraderUI.postValidate(acc_type, action).then((is_ok) => {
                if (!is_ok) {
                    MetaTraderUI.enableButton(action);
                    return;
                }

                const req = makeRequestObject(acc_type, action);
                BinarySocket.send(req).then((response) => {
                    if (response.error) {
                        MetaTraderUI.displayFormMessage(response.error.message, action);
                        MetaTraderUI.enableButton(action);
                    } else {
                        const login = actions_info[action].login ?
                            actions_info[action].login(response) : accounts_info[acc_type].info.login;
                        if (!accounts_info[acc_type].info) {
                            accounts_info[acc_type].info = { login };
                            MetaTraderUI.setAccountType(acc_type, true);
                            BinarySocket.send({ mt5_login_list: 1 });
                        }
                        MetaTraderUI.loadAction(null, acc_type);
                        getAccountDetails(login, acc_type);
                        if (typeof actions_info[action].success_msg === 'function') {
                            MetaTraderUI.displayMainMessage(actions_info[action].success_msg(response));
                        }
                        if (typeof actions_info[action].onSuccess === 'function') {
                            actions_info[action].onSuccess(response, acc_type);
                        }
                    }
                    MetaTraderUI.enableButton(action);
                });
            });
        }
    };

    const onUnload = () => {
        MetaTraderUI.switchToMT5(false);
    };

    return {
        onLoad,
        onUnload,
        isEligible,
    };
})();

module.exports = MetaTrader;
<|endoftext|>


<commit_before>import Immutable from 'immutable';
import React, { PureComponent, PropTypes } from 'react';
import { ListView, InteractionManager } from 'react-native';

import utils from './utils';

/**
 * A ListView capable of displaying {@link https://facebook.github.io/immutable-js/ Immutable} data
 * out of the box.
 */
class ImmutableListView extends PureComponent {

  static propTypes = {
    // Pass through any props that ListView would normally take.
    ...ListView.propTypes,

    // ImmutableListView handles creating the dataSource, so don't allow it to be passed in.
    dataSource: PropTypes.oneOf([undefined]),

    /**
     * The immutable data to be rendered in a ListView.
     */
    // eslint-disable-next-line consistent-return
    immutableData: (props, propName, componentName) => {
      // Note: It's not enough to simply validate PropTypes.instanceOf(Immutable.Iterable),
      // because different imports of Immutable.js across files have different class prototypes.
      if (!utils.isImmutableIterable(props[propName])) {
        return new Error(`Invalid prop ${propName} supplied to ${componentName}: Must be instance of Immutable.Iterable.`);
      }
    },

    /**
     * A function taking (prevSectionData, nextSectionData)
     * and returning true if the section header will change.
     */
    sectionHeaderHasChanged: PropTypes.func,

    /**
     * How many rows of data to display while waiting for interactions to finish (e.g. Navigation animations).
     * You can use this to improve the animation performance of longer lists when pushing new routes.
     *
     * @see https://facebook.github.io/react-native/docs/performance.html#slow-navigator-transitions
     */
    rowsDuringInteraction: PropTypes.number,

    /**
     * A function that returns some {@link PropTypes.element} to be rendered when there are no items in the list.
     */
    renderEmpty: PropTypes.func,
  };

  static defaultProps = {
    ...ListView.defaultProps,

    // The data contained in the section generally doesn't affect the header text, so return false.
    // eslint-disable-next-line no-unused-vars
    sectionHeaderHasChanged: (prevSectionData, nextSectionData) => false,
  };

  state = {
    dataSource: new ListView.DataSource({
      rowHasChanged: (prevRowData, nextRowData) => !Immutable.is(prevRowData, nextRowData),

      getRowData: (dataBlob, sectionID, rowID) => {
        const rowData = utils.getValueFromKey(sectionID, dataBlob);
        return utils.getValueFromKey(rowID, rowData);
      },

      sectionHeaderHasChanged: this.props.sectionHeaderHasChanged,

      getSectionHeaderData: (dataBlob, sectionID) => utils.getValueFromKey(sectionID, dataBlob),
    }),

    interactionOngoing: true,
  };

  componentWillMount() {
    this.canSetState = true;
    this.setStateFromPropsAfterInteraction(this.props);
  }

  componentWillReceiveProps(newProps) {
    this.setStateFromPropsAfterInteraction(newProps);
  }

  componentWillUnmount() {
    this.canSetState = false;
  }

  setStateFromPropsAfterInteraction(props) {
    // Always set state right away before the interaction.
    this.setStateFromProps(props, false);

    // If set, wait for animations etc. to complete before rendering the full list of data.
    if (props.rowsDuringInteraction >= 0) {
      InteractionManager.runAfterInteractions(() => {
        this.setStateFromProps(props, true);
      });
    }
  }

  setStateFromProps(props, interactionHasJustFinished) {
    // In some cases the component will have been unmounted before executing
    // InteractionManager.runAfterInteractions, causing a warning if we try to set state.
    if (!this.canSetState) return;

    const { dataSource, interactionOngoing } = this.state;
    const { immutableData, rowsDuringInteraction, renderSectionHeader } = props;

    const shouldDisplayPartialData = rowsDuringInteraction >= 0 && interactionOngoing && !interactionHasJustFinished;

    const displayData = (shouldDisplayPartialData
      ? immutableData.slice(0, rowsDuringInteraction)
      : immutableData);

    const updatedDataSource = (renderSectionHeader
      ? dataSource.cloneWithRowsAndSections(
          displayData, utils.getKeys(displayData), utils.getRowIdentities(displayData))
      : dataSource.cloneWithRows(
          displayData, utils.getKeys(displayData)));

    this.setState({
      dataSource: updatedDataSource,
      interactionOngoing: interactionHasJustFinished ? false : interactionOngoing,
    });
  }

  render() {
    const { dataSource } = this.state;
    const { immutableData, renderEmpty } = this.props;

    if (renderEmpty && (!immutableData || immutableData.isEmpty())) {
      return renderEmpty(this.props);
    }

    // Note: enableEmptySections is being used to mimic the default behavior of the upcoming version.
    return (
      <ListView
        dataSource={dataSource}
        enableEmptySections
        {...this.props}
      />
    );
  }

}

export default ImmutableListView;
<commit_msg>:rocket: Add ListView ref<commit_after>import Immutable from 'immutable';
import React, { PureComponent, PropTypes } from 'react';
import { ListView, InteractionManager } from 'react-native';

import utils from './utils';

/**
 * A ListView capable of displaying {@link https://facebook.github.io/immutable-js/ Immutable} data
 * out of the box.
 */
class ImmutableListView extends PureComponent {

  static propTypes = {
    // Pass through any props that ListView would normally take.
    ...ListView.propTypes,

    // ImmutableListView handles creating the dataSource, so don't allow it to be passed in.
    dataSource: PropTypes.oneOf([undefined]),

    /**
     * The immutable data to be rendered in a ListView.
     */
    // eslint-disable-next-line consistent-return
    immutableData: (props, propName, componentName) => {
      // Note: It's not enough to simply validate PropTypes.instanceOf(Immutable.Iterable),
      // because different imports of Immutable.js across files have different class prototypes.
      if (!utils.isImmutableIterable(props[propName])) {
        return new Error(`Invalid prop ${propName} supplied to ${componentName}: Must be instance of Immutable.Iterable.`);
      }
    },

    /**
     * A function taking (prevSectionData, nextSectionData)
     * and returning true if the section header will change.
     */
    sectionHeaderHasChanged: PropTypes.func,

    /**
     * How many rows of data to display while waiting for interactions to finish (e.g. Navigation animations).
     * You can use this to improve the animation performance of longer lists when pushing new routes.
     *
     * @see https://facebook.github.io/react-native/docs/performance.html#slow-navigator-transitions
     */
    rowsDuringInteraction: PropTypes.number,

    /**
     * A function that returns some {@link PropTypes.element} to be rendered when there are no items in the list.
     */
    renderEmpty: PropTypes.func,
  };

  static defaultProps = {
    ...ListView.defaultProps,

    // The data contained in the section generally doesn't affect the header text, so return false.
    // eslint-disable-next-line no-unused-vars
    sectionHeaderHasChanged: (prevSectionData, nextSectionData) => false,
  };

  state = {
    dataSource: new ListView.DataSource({
      rowHasChanged: (prevRowData, nextRowData) => !Immutable.is(prevRowData, nextRowData),

      getRowData: (dataBlob, sectionID, rowID) => {
        const rowData = utils.getValueFromKey(sectionID, dataBlob);
        return utils.getValueFromKey(rowID, rowData);
      },

      sectionHeaderHasChanged: this.props.sectionHeaderHasChanged,

      getSectionHeaderData: (dataBlob, sectionID) => utils.getValueFromKey(sectionID, dataBlob),
    }),

    interactionOngoing: true,
  };

  componentWillMount() {
    this.canSetState = true;
    this.setStateFromPropsAfterInteraction(this.props);
  }

  componentWillReceiveProps(newProps) {
    this.setStateFromPropsAfterInteraction(newProps);
  }

  componentWillUnmount() {
    this.canSetState = false;
  }

  setStateFromPropsAfterInteraction(props) {
    // Always set state right away before the interaction.
    this.setStateFromProps(props, false);

    // If set, wait for animations etc. to complete before rendering the full list of data.
    if (props.rowsDuringInteraction >= 0) {
      InteractionManager.runAfterInteractions(() => {
        this.setStateFromProps(props, true);
      });
    }
  }

  setStateFromProps(props, interactionHasJustFinished) {
    // In some cases the component will have been unmounted before executing
    // InteractionManager.runAfterInteractions, causing a warning if we try to set state.
    if (!this.canSetState) return;

    const { dataSource, interactionOngoing } = this.state;
    const { immutableData, rowsDuringInteraction, renderSectionHeader } = props;

    const shouldDisplayPartialData = rowsDuringInteraction >= 0 && interactionOngoing && !interactionHasJustFinished;

    const displayData = (shouldDisplayPartialData
      ? immutableData.slice(0, rowsDuringInteraction)
      : immutableData);

    const updatedDataSource = (renderSectionHeader
      ? dataSource.cloneWithRowsAndSections(
          displayData, utils.getKeys(displayData), utils.getRowIdentities(displayData))
      : dataSource.cloneWithRows(
          displayData, utils.getKeys(displayData)));

    this.setState({
      dataSource: updatedDataSource,
      interactionOngoing: interactionHasJustFinished ? false : interactionOngoing,
    });
  }

  render() {
    const { dataSource } = this.state;
    const { immutableData, renderEmpty } = this.props;

    if (renderEmpty && (!immutableData || immutableData.isEmpty())) {
      return renderEmpty(this.props);
    }

    // Note: enableEmptySections is being used to mimic the default behavior of the upcoming version.
    return (
      <ListView
        ref={(listView) => { this.listViewRef = listView; }}
        dataSource={dataSource}
        enableEmptySections
        {...this.props}
      />
    );
  }

}

export default ImmutableListView;
<|endoftext|>


<commit_before>(function($)
{
    var scrollElement = 'html, body';
    var active_input = '';

    // Settings
    var COMMENT_SCROLL_TOP_OFFSET = 40;
    var PREVIEW_SCROLL_TOP_OFFSET = 20;
    var DISABLE_COMMENT_SCROLL = false;

    $.fn.ready(function()
    {
        var commentform = $('form.js-comments-form');
        if( commentform.length > 0 )
        {
            // Detect last active input.
            // Submit if return is hit, or any button other then preview is hit.
            commentform.find(':input').focus(setActiveInput).mousedown(setActiveInput);
            commentform.submit(onCommentFormSubmit);
        }

        // Bind events for threaded comment reply
        if($.isFunction($.live))
        {
            $('.comment-reply-link').live('click', showThreadedReplyForm);
        }

        $('.comment-cancel-reply-link').click(cancelThreadedReplyForm);
        $('.js-comments-form').wrap('

');

        // Find the element to use for scrolling.
        // This code is much shorter then jQuery.scrollTo()
        $('html, body').each(function()
        {
            // See which tag updates the scrollTop attribute
            var $rootEl = $(this);
            var initScrollTop = $rootEl.attr('scrollTop');
            $rootEl.attr('scrollTop', initScrollTop + 1);
            if( $rootEl.attr('scrollTop') == initScrollTop + 1 )
            {
                scrollElement = this.nodeName.toLowerCase();
                $rootEl.attr('scrollTop', initScrollTop);  // Firefox 2 reset
                return false;
            }
        });

        // On load, scroll to proper comment.
        var hash = window.location.hash;
        if( hash.substring(0, 2) == "#c" )
        {
            var id = parseInt(hash.substring(2));
            if( ! isNaN(id))   // e.g. #comments in URL
                scrollToComment(id, 1000);
        }
    });

    function setActiveInput()
    {
        active_input = this.name;
    }

    function onCommentFormSubmit(event)
    {
        event.preventDefault();  // only after ajax call worked.
        var form = event.target;
        var preview = (active_input == 'preview');

        ajaxComment(form, {
            onsuccess: (preview ? null : onCommentPosted),
            preview: preview
        });
        return false;
    }

    function scrollToComment(id, speed)
    {
        if( DISABLE_COMMENT_SCROLL ) {
            return;
        }

        // Allow initialisation before scrolling.
        var $comment = $("#c" + id);
        if( $comment.length == 0 ) {
            if( window.console ) console.warn("scrollToComment() - #c" + id + " not found.");
            return;
        }

        if( window.on_scroll_to_comment && window.on_scroll_to_comment({comment: $comment}) === false )
            return;

        // Scroll to the comment.
        scrollToElement( $comment, speed, COMMENT_SCROLL_TOP_OFFSET );
    }

    function scrollToElement( $element, speed, offset )
    {
        if( DISABLE_COMMENT_SCROLL ) {
            return;
        }

        if( $element.length )
            $(scrollElement).animate( {scrollTop: $element.offset().top - (offset || 0) }, speed || 1000 );
    }

    function onCommentPosted( comment_id, is_moderated, $comment )
    {
        var $message_span;
        if( is_moderated )
            $message_span = $("#comment-moderated-message").fadeIn(200);
        else
            $message_span = $("#comment-added-message").fadeIn(200);

        setTimeout(function(){ scrollToComment(comment_id, 1000); }, 1000);
        setTimeout(function(){ $message_span.fadeOut(500) }, 4000);
    }

    function showThreadedReplyForm(event) {
        event.preventDefault();

        var $a = $(this);
        var comment_id = $a.data('comment-id');

        $('#id_parent').val(comment_id);
        $('.js-comments-form').insertAfter($a.closest('.comment-item'));
    };

    function cancelThreadedReplyForm(event) {
        if(event)
            event.preventDefault();

        cancelThreadedReplyFormHelper({})
    }

    function cancelThreadedReplyFormHelper(data) {
        var object_id = data['object_id'];
        var the_form = $('#comment-form-' + object_id);

        $('#id_comment').val('', the_form);
        $('#id_parent').val('', the_form);
        $('.js-comments-form', the_form).appendTo($('.js-comments-form-orig-position', the_form));
    }

    /*
      Based on django-ajaxcomments, BSD licensed.
      Copyright (c) 2009 Brandon Konkle and individual contributors.

      Updated to be more generic, more fancy, and usable with different templates.
     */
    var commentBusy = false;
    var previewAutoAdded = false;

    function ajaxComment(form, args)
    {
        var onsuccess = args.onsuccess;
        var preview = !!args.preview;

        $('div.comment-error').remove();
        if (commentBusy) {
            return false;
        }

        commentBusy = true;
        var $form = $(form);
        var comment = $form.serialize() + (preview ? '&preview=1' : '');
        var url = $form.attr('action') || './';
        var ajaxurl = $form.attr('data-ajax-action');

        // Add a wait animation
        if( ! preview )
            $('#comment-waiting').fadeIn(1000);

        // Use AJAX to post the comment.
        $.ajax({
            type: 'POST',
            url: ajaxurl || url,
            data: comment,
            dataType: 'json',
            success: function(data) {
                commentBusy = false;
                removeWaitAnimation();
                removeErrors();

                if (data.success) {
                    var $added;
                    if( preview )
                        $added = commentPreview(data);
                    else
                        $added = commentSuccess(data);

                    if( onsuccess )
                        args.onsuccess(data.comment_id, data.is_moderated, $added);
                }
                else {
                    commentFailure(data);
                }
            },
            error: function(data) {
                commentBusy = false;
                removeWaitAnimation();

                // Submit as non-ajax instead
                //$form.unbind('submit').submit();
            }
        });

        return false;
    }

    function commentSuccess(data)
    {
        var object_id = data['object_id'];
        var the_form = $('#comment-form-' + object_id);

        // Clean form
        $('form.js-comments-form textarea', the_form).last().val("");
        $('#id_comment', the_form).val('');
        cancelThreadedReplyFormHelper(data);  // in case threaded comments are used.

        // Show comment
        var had_preview = removePreview(data);
        var $new_comment = addComment(data);

        if( had_preview )
            // Avoid double jump when preview was removed. Instead refade to final comment.
            $new_comment.hide().fadeIn(600);
        else
            // Smooth introduction to the new comment.
            $new_comment.hide().show(600);

        return $new_comment;
    }

    function addComment(data)
    {
        // data contains the server-side response.
        var html = data['html']
        var parent_id = data['parent_id'];
        var object_id = data['object_id'];

        var $new_comment;
        if(parent_id)
        {
            var $parentLi = $("#c" + parseInt(parent_id)).parent('li.comment-wrapper');
            var $commentUl = $parentLi.children('ul');
            if( $commentUl.length == 0 )
                $commentUl = $parentLi.append('

').children('ul.comment-list-wrapper');
            $commentUl.append('
' + html + '
');
        }
        else
        {
            var $comments = getCommentsDiv(object_id);
            $comments.append(html).removeClass('empty');
        }

        return $("#c" + parseInt(data.comment_id));
    }

    function commentPreview(data)
    {
        var object_id = data['object_id'];
        var $previewarea = $("#comment-preview-area");
        if( $previewarea.length == 0 )
        {
            // If not explicitly added to the HTML, include a previewarea in the comments.
            // This should at least give the same markup.
            getCommentsDiv(object_id).append('

').addClass('has-preview');
            $previewarea = $("#comment-preview-area");
            previewAutoAdded = true;
        }

        var had_preview = $previewarea.hasClass('has-preview-loaded');
        $previewarea.html(data.html).addClass('has-preview-loaded');
        if( ! had_preview )
            $previewarea.hide().show(600);

        // Scroll to preview, but allow time to render it.
        setTimeout(function(){ scrollToElement( $previewarea, 500, PREVIEW_SCROLL_TOP_OFFSET ); }, 500);
    }

    function commentFailure(data)
    {
        // Show mew errors
        for (var field_name in data.errors) {
            if(field_name) {
                var $field = $('#id_' + field_name);

                // Twitter bootstrap style
                $field.after('' + data.errors[field_name] + '');
                $field.closest('.control-group').addClass('error');
            }
        }
    }

    function removeErrors()
    {
        $('form.js-comments-form .js-errors').remove();
        $('form.js-comments-form .control-group.error').removeClass('error');
    }

    function getCommentsDiv(object_id)
    {
        var $comments = $("#comments-" + object_id);
        if( $comments.length == 0 )
            alert("Internal error - unable to display comment.\n\nreason: container is missing in the page.");
        return $comments;
    }

    function removePreview(data)
    {
        var object_id = data['object_id'];
        var the_form = $('#comment-form-' + object_id);
        var the_list = $('#comments-' + object_id);

        var $previewarea = $("#comment-preview-area", the_list);
        var had_preview = $previewarea.hasClass('has-preview-loaded');

        if( previewAutoAdded )
            $previewarea.remove();  // make sure it's added at the end again later.
        else
            $previewarea.html('');

        // Update classes. allowing CSS to add/remove margins for example.
        $previewarea.removeClass('has-preview-loaded')
        $(the_list).removeClass('has-preview');

        return had_preview;
    }

    function removeWaitAnimation()
    {
        // Remove the wait animation and message
        $('#comment-waiting').hide().stop();
    }

})(window.jQuery);
<commit_msg>Support both old jQuery and new jQuery (.on vs .live)<commit_after>(function($)
{
    var scrollElement = 'html, body';
    var active_input = '';

    // Settings
    var COMMENT_SCROLL_TOP_OFFSET = 40;
    var PREVIEW_SCROLL_TOP_OFFSET = 20;
    var DISABLE_COMMENT_SCROLL = false;

    $.fn.ready(function()
    {
        var commentform = $('form.js-comments-form');
        if( commentform.length > 0 )
        {
            // Detect last active input.
            // Submit if return is hit, or any button other then preview is hit.
            commentform.find(':input').focus(setActiveInput).mousedown(setActiveInput);
            commentform.submit(onCommentFormSubmit);
        }

        // Bind events for threaded comment reply
        if($.fn.on) {
            // jQuery 1.7+
            $('body').on('click', '.comment-reply-link', showThreadedReplyForm);
        }
        else {
            $('.comment-reply-link').live('click', showThreadedReplyForm);
        }

        $('.comment-cancel-reply-link').click(cancelThreadedReplyForm);
        $('.js-comments-form').wrap('

');

        // Find the element to use for scrolling.
        // This code is much shorter then jQuery.scrollTo()
        $('html, body').each(function()
        {
            // See which tag updates the scrollTop attribute
            var $rootEl = $(this);
            var initScrollTop = $rootEl.attr('scrollTop');
            $rootEl.attr('scrollTop', initScrollTop + 1);
            if( $rootEl.attr('scrollTop') == initScrollTop + 1 )
            {
                scrollElement = this.nodeName.toLowerCase();
                $rootEl.attr('scrollTop', initScrollTop);  // Firefox 2 reset
                return false;
            }
        });

        // On load, scroll to proper comment.
        var hash = window.location.hash;
        if( hash.substring(0, 2) == "#c" )
        {
            var id = parseInt(hash.substring(2));
            if( ! isNaN(id))   // e.g. #comments in URL
                scrollToComment(id, 1000);
        }
    });

    function setActiveInput()
    {
        active_input = this.name;
    }

    function onCommentFormSubmit(event)
    {
        event.preventDefault();  // only after ajax call worked.
        var form = event.target;
        var preview = (active_input == 'preview');

        ajaxComment(form, {
            onsuccess: (preview ? null : onCommentPosted),
            preview: preview
        });
        return false;
    }

    function scrollToComment(id, speed)
    {
        if( DISABLE_COMMENT_SCROLL ) {
            return;
        }

        // Allow initialisation before scrolling.
        var $comment = $("#c" + id);
        if( $comment.length == 0 ) {
            if( window.console ) console.warn("scrollToComment() - #c" + id + " not found.");
            return;
        }

        if( window.on_scroll_to_comment && window.on_scroll_to_comment({comment: $comment}) === false )
            return;

        // Scroll to the comment.
        scrollToElement( $comment, speed, COMMENT_SCROLL_TOP_OFFSET );
    }

    function scrollToElement( $element, speed, offset )
    {
        if( DISABLE_COMMENT_SCROLL ) {
            return;
        }

        if( $element.length )
            $(scrollElement).animate( {scrollTop: $element.offset().top - (offset || 0) }, speed || 1000 );
    }

    function onCommentPosted( comment_id, is_moderated, $comment )
    {
        var $message_span;
        if( is_moderated )
            $message_span = $("#comment-moderated-message").fadeIn(200);
        else
            $message_span = $("#comment-added-message").fadeIn(200);

        setTimeout(function(){ scrollToComment(comment_id, 1000); }, 1000);
        setTimeout(function(){ $message_span.fadeOut(500) }, 4000);
    }

    function showThreadedReplyForm(event) {
        event.preventDefault();

        var $a = $(this);
        var comment_id = $a.data('comment-id');

        $('#id_parent').val(comment_id);
        $('.js-comments-form').insertAfter($a.closest('.comment-item'));
    };

    function cancelThreadedReplyForm(event) {
        if(event)
            event.preventDefault();

        cancelThreadedReplyFormHelper({})
    }

    function cancelThreadedReplyFormHelper(data) {
        var object_id = data['object_id'];
        var the_form = $('#comment-form-' + object_id);

        $('#id_comment').val('', the_form);
        $('#id_parent').val('', the_form);
        $('.js-comments-form', the_form).appendTo($('.js-comments-form-orig-position', the_form));
    }

    /*
      Based on django-ajaxcomments, BSD licensed.
      Copyright (c) 2009 Brandon Konkle and individual contributors.

      Updated to be more generic, more fancy, and usable with different templates.
     */
    var commentBusy = false;
    var previewAutoAdded = false;

    function ajaxComment(form, args)
    {
        var onsuccess = args.onsuccess;
        var preview = !!args.preview;

        $('div.comment-error').remove();
        if (commentBusy) {
            return false;
        }

        commentBusy = true;
        var $form = $(form);
        var comment = $form.serialize() + (preview ? '&preview=1' : '');
        var url = $form.attr('action') || './';
        var ajaxurl = $form.attr('data-ajax-action');

        // Add a wait animation
        if( ! preview )
            $('#comment-waiting').fadeIn(1000);

        // Use AJAX to post the comment.
        $.ajax({
            type: 'POST',
            url: ajaxurl || url,
            data: comment,
            dataType: 'json',
            success: function(data) {
                commentBusy = false;
                removeWaitAnimation();
                removeErrors();

                if (data.success) {
                    var $added;
                    if( preview )
                        $added = commentPreview(data);
                    else
                        $added = commentSuccess(data);

                    if( onsuccess )
                        args.onsuccess(data.comment_id, data.is_moderated, $added);
                }
                else {
                    commentFailure(data);
                }
            },
            error: function(data) {
                commentBusy = false;
                removeWaitAnimation();

                // Submit as non-ajax instead
                //$form.unbind('submit').submit();
            }
        });

        return false;
    }

    function commentSuccess(data)
    {
        var object_id = data['object_id'];
        var the_form = $('#comment-form-' + object_id);

        // Clean form
        $('form.js-comments-form textarea', the_form).last().val("");
        $('#id_comment', the_form).val('');
        cancelThreadedReplyFormHelper(data);  // in case threaded comments are used.

        // Show comment
        var had_preview = removePreview(data);
        var $new_comment = addComment(data);

        if( had_preview )
            // Avoid double jump when preview was removed. Instead refade to final comment.
            $new_comment.hide().fadeIn(600);
        else
            // Smooth introduction to the new comment.
            $new_comment.hide().show(600);

        return $new_comment;
    }

    function addComment(data)
    {
        // data contains the server-side response.
        var html = data['html']
        var parent_id = data['parent_id'];
        var object_id = data['object_id'];

        var $new_comment;
        if(parent_id)
        {
            var $parentLi = $("#c" + parseInt(parent_id)).parent('li.comment-wrapper');
            var $commentUl = $parentLi.children('ul');
            if( $commentUl.length == 0 )
                $commentUl = $parentLi.append('

').children('ul.comment-list-wrapper');
            $commentUl.append('
' + html + '
');
        }
        else
        {
            var $comments = getCommentsDiv(object_id);
            $comments.append(html).removeClass('empty');
        }

        return $("#c" + parseInt(data.comment_id));
    }

    function commentPreview(data)
    {
        var object_id = data['object_id'];
        var $previewarea = $("#comment-preview-area");
        if( $previewarea.length == 0 )
        {
            // If not explicitly added to the HTML, include a previewarea in the comments.
            // This should at least give the same markup.
            getCommentsDiv(object_id).append('

').addClass('has-preview');
            $previewarea = $("#comment-preview-area");
            previewAutoAdded = true;
        }

        var had_preview = $previewarea.hasClass('has-preview-loaded');
        $previewarea.html(data.html).addClass('has-preview-loaded');
        if( ! had_preview )
            $previewarea.hide().show(600);

        // Scroll to preview, but allow time to render it.
        setTimeout(function(){ scrollToElement( $previewarea, 500, PREVIEW_SCROLL_TOP_OFFSET ); }, 500);
    }

    function commentFailure(data)
    {
        // Show mew errors
        for (var field_name in data.errors) {
            if(field_name) {
                var $field = $('#id_' + field_name);

                // Twitter bootstrap style
                $field.after('' + data.errors[field_name] + '');
                $field.closest('.control-group').addClass('error');
            }
        }
    }

    function removeErrors()
    {
        $('form.js-comments-form .js-errors').remove();
        $('form.js-comments-form .control-group.error').removeClass('error');
    }

    function getCommentsDiv(object_id)
    {
        var $comments = $("#comments-" + object_id);
        if( $comments.length == 0 )
            alert("Internal error - unable to display comment.\n\nreason: container is missing in the page.");
        return $comments;
    }

    function removePreview(data)
    {
        var object_id = data['object_id'];
        var the_form = $('#comment-form-' + object_id);
        var the_list = $('#comments-' + object_id);

        var $previewarea = $("#comment-preview-area", the_list);
        var had_preview = $previewarea.hasClass('has-preview-loaded');

        if( previewAutoAdded )
            $previewarea.remove();  // make sure it's added at the end again later.
        else
            $previewarea.html('');

        // Update classes. allowing CSS to add/remove margins for example.
        $previewarea.removeClass('has-preview-loaded')
        $(the_list).removeClass('has-preview');

        return had_preview;
    }

    function removeWaitAnimation()
    {
        // Remove the wait animation and message
        $('#comment-waiting').hide().stop();
    }

})(window.jQuery);
<|endoftext|>


<commit_before>var bodyParser = require('body-parser');
var express = require('express');
var r = require('rethinkdb');

var app = express();

app.get('/', function (request, response) {
  r.connect({ host: 'localhost', port: 28015 }, function(err, conn) {
    if (err) {
      throw err;
    }
    r.db('test').tableCreate('Message').run(conn, function(err, result) {
      if (err) {
        throw err;
      }
      console.log(result);
      r.table('Message').insert({content: 'sup world'}).run(
        conn,
        function(err, result) {
          if (err) {
            throw err;
          }
          console.log(result);
          response.send("Got to the center of the nest");
        });
    });
  });
});

var server = app.listen(3000, function () {
  var host = server.address().address;
  var port = server.address().port;

  console.log('Example app listening at http://%s:%s', host, port);
});
<commit_msg>updated to accept a world in which the table is already created<commit_after>var bodyParser = require('body-parser');
var express = require('express');
var r = require('rethinkdb');

var app = express();

app.get('/', function (request, response) {
  r.connect({ host: 'localhost', port: 28015 }, function(err, conn) {
    if (err) {
      console.log('error in connect', err);
      throw err;
    }
    r.db('test').table('Message').insert({content: 'sup world'}).run(
      conn,
      function(err, result) {
        if (err) {
          throw err;
          }
        console.log(result);
        response.send("Got to the center of the nest");
      });
  });
});

var server = app.listen(3000, function () {
  var host = server.address().address;
  var port = server.address().port;

  console.log('Example app listening at http://%s:%s', host, port);
});
<|endoftext|>


<commit_before>var PodcastManager;

(function(){
	var instance;

	PodcastManager = function() {
		if(instance) {
			return instance;
		}

		this.podcastList = [];

		function loadPodcastsFromSync(loaded) {
			chrome.storage.sync.get('syncPodcastList', function(storageObject) {
				var syncPodcastList;

				if(typeof storageObject.syncPodcastList === "undefined") {
					syncPodcastList = [];
				}
				else {
					syncPodcastList = storageObject.syncPodcastList;
				}

				if( loaded(syncPodcastList) ) {
					chrome.storage.sync.set({'syncPodcastList': syncPodcastList});
				}
			});
		};

		this.addPodcast = function(url, afterLoad) {
			if(url !== '') {
				var that = this;
				loadPodcastsFromSync(function(syncPodcastList) {
					var podcastExistInStorage = false;
					syncPodcastList.forEach(function(podcast) {
						if(podcast.url && podcast.url === url) {
							podcastExistInStorage = true;
						}
					});

					if(podcastExistInStorage) {
						return;
					}

					var podcastForSync = {
						url: url
					};

					syncPodcastList.push(podcastForSync);

					var podcast = new Podcast(podcastForSync.url);

					that.podcastList.push(podcast);

					podcast.load(afterLoad);

					return true;
				});
			}
		}

		this.deletePodcast = function(url) {
			var that = this;
			this.podcastList.forEach(function(item) {
				if( item.url === url) {
					item.deleteFromStorage();
					that.podcastList.splice(that.podcastList.indexOf(item), 1);
					return false;
				}
			});

			loadPodcastsFromSync(function(syncPodcastList) {
				syncPodcastList.forEach(function(item) {
					if( item.url === url) {
						syncPodcastList.splice(syncPodcastList.indexOf(item), 1);
						return false;
					}
				});

				return true;
			})
		}

		this.updatePodcast = function(url, callback) {
			if(url !== '') {
				var podcast;
				podcast = this.getPodcast(url);

				podcast.update(callback);
			}
			else {
				this.podcastList.forEach(function(podcast) {
					podcast.update(callback);
				});
			}
		}

		this.getPodcast = function(url) {
			var podcast;

			this.podcastList.forEach(function(item) {
				if( item.url === url) {
					podcast = item;
					return false;
				}
			});

			return podcast;
		}

		this.deleteAllPodcasts = function () {
			chrome.storage.sync.set({'syncPodcastList': []});
			this.podcastList.forEach(function(item) {
				item.deleteFromStorage();
			});
			this.podcastList = [];
		}

		this.getAllEpisodes = function() {
			var allEpisodes = [];

			this.podcastList.forEach(function(podcast) {
				podcast.episodes.forEach(function(episode) {
					var episodeContainer = {
						podcast: podcast,
						episode: episode,
						pubDate: episode.pubDate // to facilitate reuse of sorting function
					};

					allEpisodes.push(episodeContainer);
				})
			});

			allEpisodes.sort(byPubDateDescending);

			return allEpisodes;
		}

		instance = this;

		loadPodcasts = function() {
			loadPodcastsFromSync(function(syncPodcastList) {
				syncPodcastList.forEach(function(storedPodcast) {
					var podcast = new Podcast(storedPodcast.url);

					instance.podcastList.push(podcast);

					podcast.load();
				});
			});
		};

		loadPodcasts();

	}
})();
<commit_msg>Newly added podcasts on top<commit_after>var PodcastManager;

(function(){
	var instance;

	PodcastManager = function() {
		if(instance) {
			return instance;
		}

		this.podcastList = [];

		function loadPodcastsFromSync(loaded) {
			chrome.storage.sync.get('syncPodcastList', function(storageObject) {
				var syncPodcastList;

				if(typeof storageObject.syncPodcastList === "undefined") {
					syncPodcastList = [];
				}
				else {
					syncPodcastList = storageObject.syncPodcastList;
				}

				if( loaded(syncPodcastList) ) {
					chrome.storage.sync.set({'syncPodcastList': syncPodcastList});
				}
			});
		};

		this.addPodcast = function(url, afterLoad) {
			if(url !== '') {
				var that = this;
				loadPodcastsFromSync(function(syncPodcastList) {
					var podcastExistInStorage = false;
					syncPodcastList.forEach(function(podcast) {
						if(podcast.url && podcast.url === url) {
							podcastExistInStorage = true;
						}
					});

					if(podcastExistInStorage) {
						return;
					}

					var podcastForSync = {
						url: url
					};

					syncPodcastList.unshift(podcastForSync);

					var podcast = new Podcast(podcastForSync.url);

					that.podcastList.unshift(podcast);

					podcast.load(afterLoad);

					return true;
				});
			}
		}

		this.deletePodcast = function(url) {
			var that = this;
			this.podcastList.forEach(function(item) {
				if( item.url === url) {
					item.deleteFromStorage();
					that.podcastList.splice(that.podcastList.indexOf(item), 1);
					return false;
				}
			});

			loadPodcastsFromSync(function(syncPodcastList) {
				syncPodcastList.forEach(function(item) {
					if( item.url === url) {
						syncPodcastList.splice(syncPodcastList.indexOf(item), 1);
						return false;
					}
				});

				return true;
			})
		}

		this.updatePodcast = function(url, callback) {
			if(url !== '') {
				var podcast;
				podcast = this.getPodcast(url);

				podcast.update(callback);
			}
			else {
				this.podcastList.forEach(function(podcast) {
					podcast.update(callback);
				});
			}
		}

		this.getPodcast = function(url) {
			var podcast;

			this.podcastList.forEach(function(item) {
				if( item.url === url) {
					podcast = item;
					return false;
				}
			});

			return podcast;
		}

		this.deleteAllPodcasts = function () {
			chrome.storage.sync.set({'syncPodcastList': []});
			this.podcastList.forEach(function(item) {
				item.deleteFromStorage();
			});
			this.podcastList = [];
		}

		this.getAllEpisodes = function() {
			var allEpisodes = [];

			this.podcastList.forEach(function(podcast) {
				podcast.episodes.forEach(function(episode) {
					var episodeContainer = {
						podcast: podcast,
						episode: episode,
						pubDate: episode.pubDate // to facilitate reuse of sorting function
					};

					allEpisodes.push(episodeContainer);
				})
			});

			allEpisodes.sort(byPubDateDescending);

			return allEpisodes;
		}

		instance = this;

		loadPodcasts = function() {
			loadPodcastsFromSync(function(syncPodcastList) {
				syncPodcastList.forEach(function(storedPodcast) {
					var podcast = new Podcast(storedPodcast.url);

					instance.podcastList.push(podcast);

					podcast.load();
				});
			});
		};

		loadPodcasts();

	}
})();
<|endoftext|>


<commit_before>/*
Copyright 2012 Google Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Author: Boris Smus (smus@chromium.org)
*/

(function(){

"use strict";

/**
 * @ngdoc service
 * @name tcpClientService
 */
angular.module("angular-chrome-app-tcp-client")
.service("tcpClientService",
["$log",
function($log)
{
  /**
   * Creates an instance of the client
   *
   * @param {String} host The remote host to connect to
   * @param {Number} port The port to connect to at the remote host
   */
  function TcpClient(host, port) {
    this.host = host;
    this.port = port;
    this._onReceive = this._onReceive.bind(this);
    this._onReceiveError = this._onReceiveError.bind(this);

    // Callback functions.
    this.callbacks = {
      connect: null,    // Called when socket is connected.
      disconnect: null, // Called when socket is disconnected.
      recv: null,       // Called when client receives data from server.
      sent: null        // Called when client sends data to server.
    };

    // Socket.
    this.socketId = null;
    this.isConnected = false;

    log('initialized tcp client');
  }

  /**
   * Connects to the TCP socket, and creates an open socket.
   *
   * @see http://developer.chrome.com/apps/sockets_tcp.html#method-create
   * @param {Function} callback The function to call on connection
   */
  TcpClient.prototype.connect = function(callback) {
    // Register connect callback.
    this.callbacks.connect = callback;

    chrome.sockets.tcp.create({}, this._onCreate.bind(this));
  };

  /**
   * Sends a message down the wire to the remote side
   *
   * @see http://developer.chrome.com/apps/sockets_tcp.html#method-send
   * @param {String} msg The message to send
   * @param {Function} callback The function to call when the message has sent
   */
  TcpClient.prototype.sendMessage = function(msg, callback) {
    // Register sent callback.
    this.callbacks.sent = callback;

    this._stringToArrayBuffer(msg + '\n', function(arrayBuffer) {
      chrome.sockets.tcp.send(this.socketId, arrayBuffer, this._onSendComplete.bind(this));
    }.bind(this));
  };

  /**
   * Sets the callback for when a message is received
   *
   * @param {Function} callback The function to call when a message has arrived
   */
  TcpClient.prototype.addResponseListener = function(callback) {
    // Register received callback.
    this.callbacks.recv = callback;
  };

  /**
   * Disconnects from the remote side
   *
   * @see http://developer.chrome.com/apps/sockets_tcp.html#method-disconnect
   */
  TcpClient.prototype.disconnect = function() {
    chrome.sockets.tcp.onReceive.removeListener(this._onReceive);
    chrome.sockets.tcp.onReceiveError.removeListener(this._onReceiveError);
    chrome.sockets.tcp.disconnect(this.socketId);
    chrome.sockets.tcp.close(this.socketId);
    this.socketId = null;
    this.isConnected = false;
  };

  /**
   * The callback function used for when we attempt to have Chrome
   * create a socket. If the socket is successfully created
   * we go ahead and connect to the remote side.
   *
   * @private
   * @see http://developer.chrome.com/apps/sockets_tcp.html#method-connect
   * @param {Object} createInfo The socket details
   */
  TcpClient.prototype._onCreate = function(createInfo) {
    if (chrome.runtime.lastError) {
      error('Unable to create socket: ' + chrome.runtime.lastError.message);
    }

    this.socketId = createInfo.socketId;
    this.isConnected = true;
    chrome.sockets.tcp.connect(this.socketId, this.host, this.port, this._onConnectComplete.bind(this));
  };

  /**
   * The callback function used for when we attempt to have Chrome
   * connect to the remote side. If a successful connection is
   * made then polling starts to check for data to read
   *
   * @private
   * @param {Number} resultCode Indicates whether the connection was successful
   */
  TcpClient.prototype._onConnectComplete = function(resultCode) {
    if (resultCode < 0) {
      error('Unable to connect to server');
      return;
    }

    // Start listening to message events.
    chrome.sockets.tcp.onReceive.addListener(this._onReceive);
    chrome.sockets.tcp.onReceiveError.addListener(this._onReceiveError);

    if (this.callbacks.connect) {
      console.log('connect complete');
      this.callbacks.connect();
    }
    log('onConnectComplete');
  };

  /**
   * Callback function for when data has been read from the socket.
   * Converts the array buffer that is read in to a string
   * and sends it on for further processing by passing it to
   * the previously assigned callback function.
   *
   * @see http://developer.chrome.com/apps/sockets_tcp.html#event-onReceive
   *
   * @private
   * @see TcpClient.prototype.addResponseListener
   * @param {Object} receiveInfo The incoming message
   */
  TcpClient.prototype._onReceive = function(receiveInfo) {
    if (receiveInfo.socketId != this.socketId)
      return;

    if (this.callbacks.recv) {
      log('onDataRead');
      // Convert ArrayBuffer to string.
      this._arrayBufferToString(receiveInfo.data, function(str) {
        this.callbacks.recv(str);
      }.bind(this));
    }
  };

  /**
   * Callback function for an error occurs on the socket.
   *
   * @see http://developer.chrome.com/apps/sockets_tcp.html#event-onReceiveError
   *
   * @private
   * @param {Object} info The incoming message
   */
  TcpClient.prototype._onReceiveError = function(info) {
    if (info.socketId != this.socketId)
      return;

    error('Unable to receive data from socket: ' + info.resultCode);
  };

  /**
   * Callback for when data has been successfully
   * sent to the socket.
   *
   * @private
   * @param {Object} sendInfo The outgoing message
   */
  TcpClient.prototype._onSendComplete = function(sendInfo) {
    log('onSendComplete');
    // Call sent callback.
    if (this.callbacks.sent) {
      this.callbacks.sent(sendInfo);
    }
  };

  /**
   * Converts an array buffer to a string
   *
   * @private
   * @param {ArrayBuffer} buf The buffer to convert
   * @param {Function} callback The function to call when conversion is complete
   */
  TcpClient.prototype._arrayBufferToString = function(buf, callback) {
    var reader = new FileReader();
    reader.onload = function(e) {
      callback(e.target.result);
    };
    var blob=new Blob([ buf ], { type: 'application/octet-stream' });
    reader.readAsText(blob);
  };

  /**
   * Converts a string to an array buffer
   *
   * @private
   * @param {String} str The string to convert
   * @param {Function} callback The function to call when conversion is complete
   */
  TcpClient.prototype._stringToArrayBuffer = function(str, callback) {
    var bb = new Blob([str]);
    var f = new FileReader();
    f.onload = function(e) {
       callback(e.target.result);
    };
    f.readAsArrayBuffer(bb);
  };

  /**
   * Wrapper function for logging
   */
  function log(msg) {
    console.log(msg);
  }

  /**
   * Wrapper function for error logging
   */
  function error(msg) {
    console.error(msg);
  }

  //constructor for a service instance object
  return {
    /**
     * instantiates tcp service, initializes the client
     *
     * @param {String} host The remote host to connect to
     * @param {Number} port The port to connect to at the remote host
     */
    getInstance: function (host, port)
    {
      return new TcpClient(host, port);
    }
  };
}
]);
})();
<commit_msg>add method for sending a raw array buffer<commit_after>/*
Copyright 2012 Google Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Author: Boris Smus (smus@chromium.org)
*/

(function(){

"use strict";

/**
 * @ngdoc service
 * @name tcpClientService
 */
angular.module("angular-chrome-app-tcp-client")
.service("tcpClientService",
["$log",
function($log)
{
  /**
   * Creates an instance of the client
   *
   * @param {String} host The remote host to connect to
   * @param {Number} port The port to connect to at the remote host
   */
  function TcpClient(host, port) {
    this.host = host;
    this.port = port;
    this._onReceive = this._onReceive.bind(this);
    this._onReceiveError = this._onReceiveError.bind(this);

    // Callback functions.
    this.callbacks = {
      connect: null,    // Called when socket is connected.
      disconnect: null, // Called when socket is disconnected.
      recv: null,       // Called when client receives data from server.
      sent: null        // Called when client sends data to server.
    };

    // Socket.
    this.socketId = null;
    this.isConnected = false;

    log('initialized tcp client');
  }

  /**
   * Connects to the TCP socket, and creates an open socket.
   *
   * @see http://developer.chrome.com/apps/sockets_tcp.html#method-create
   * @param {Function} callback The function to call on connection
   */
  TcpClient.prototype.connect = function(callback) {
    // Register connect callback.
    this.callbacks.connect = callback;

    chrome.sockets.tcp.create({}, this._onCreate.bind(this));
  };

  /**
   * Sends a message down the wire to the remote side
   *
   * @see http://developer.chrome.com/apps/sockets_tcp.html#method-send
   * @param {String} msg The message to send
   * @param {Function} callback The function to call when the message has sent
   */
  TcpClient.prototype.sendMessage = function(msg, callback) {
    // Register sent callback.
    this.callbacks.sent = callback;

    this._stringToArrayBuffer(msg + '\n', function(arrayBuffer) {
      chrome.sockets.tcp.send(this.socketId, arrayBuffer, this._onSendComplete.bind(this));
    }.bind(this));
  };

  /**
   * Sends a raw array buffer down the wire to the remote side
   *
   * @see http://developer.chrome.com/apps/sockets_tcp.html#method-send
   * @param {ArrayBuffer} msg The message to send
   * @param {Function} callback The function to call when the message has sent
   */
  TcpClient.prototype.sendArrayBuffer = function(arrayBuffer, callback)
  {
    // Register sent callback.
    this.callbacks.sent = callback;
    chrome.sockets.tcp.send(this.socketId, arrayBuffer, this._onSendComplete.bind(this));
  };

  /**
   * Sets the callback for when a message is received
   *
   * @param {Function} callback The function to call when a message has arrived
   */
  TcpClient.prototype.addResponseListener = function(callback) {
    // Register received callback.
    this.callbacks.recv = callback;
  };

  /**
   * Disconnects from the remote side
   *
   * @see http://developer.chrome.com/apps/sockets_tcp.html#method-disconnect
   */
  TcpClient.prototype.disconnect = function() {
    chrome.sockets.tcp.onReceive.removeListener(this._onReceive);
    chrome.sockets.tcp.onReceiveError.removeListener(this._onReceiveError);
    chrome.sockets.tcp.disconnect(this.socketId);
    chrome.sockets.tcp.close(this.socketId);
    this.socketId = null;
    this.isConnected = false;
  };

  /**
   * The callback function used for when we attempt to have Chrome
   * create a socket. If the socket is successfully created
   * we go ahead and connect to the remote side.
   *
   * @private
   * @see http://developer.chrome.com/apps/sockets_tcp.html#method-connect
   * @param {Object} createInfo The socket details
   */
  TcpClient.prototype._onCreate = function(createInfo) {
    if (chrome.runtime.lastError) {
      error('Unable to create socket: ' + chrome.runtime.lastError.message);
    }

    this.socketId = createInfo.socketId;
    this.isConnected = true;
    chrome.sockets.tcp.connect(this.socketId, this.host, this.port, this._onConnectComplete.bind(this));
  };

  /**
   * The callback function used for when we attempt to have Chrome
   * connect to the remote side. If a successful connection is
   * made then polling starts to check for data to read
   *
   * @private
   * @param {Number} resultCode Indicates whether the connection was successful
   */
  TcpClient.prototype._onConnectComplete = function(resultCode) {
    if (resultCode < 0) {
      error('Unable to connect to server');
      return;
    }

    // Start listening to message events.
    chrome.sockets.tcp.onReceive.addListener(this._onReceive);
    chrome.sockets.tcp.onReceiveError.addListener(this._onReceiveError);

    if (this.callbacks.connect) {
      console.log('connect complete');
      this.callbacks.connect();
    }
    log('onConnectComplete');
  };

  /**
   * Callback function for when data has been read from the socket.
   * Converts the array buffer that is read in to a string
   * and sends it on for further processing by passing it to
   * the previously assigned callback function.
   *
   * @see http://developer.chrome.com/apps/sockets_tcp.html#event-onReceive
   *
   * @private
   * @see TcpClient.prototype.addResponseListener
   * @param {Object} receiveInfo The incoming message
   */
  TcpClient.prototype._onReceive = function(receiveInfo) {
    if (receiveInfo.socketId != this.socketId)
      return;

    if (this.callbacks.recv) {
      log('onDataRead');
      // Convert ArrayBuffer to string.
      this._arrayBufferToString(receiveInfo.data, function(str) {
        this.callbacks.recv(str);
      }.bind(this));
    }
  };

  /**
   * Callback function for an error occurs on the socket.
   *
   * @see http://developer.chrome.com/apps/sockets_tcp.html#event-onReceiveError
   *
   * @private
   * @param {Object} info The incoming message
   */
  TcpClient.prototype._onReceiveError = function(info) {
    if (info.socketId != this.socketId)
      return;

    error('Unable to receive data from socket: ' + info.resultCode);
  };

  /**
   * Callback for when data has been successfully
   * sent to the socket.
   *
   * @private
   * @param {Object} sendInfo The outgoing message
   */
  TcpClient.prototype._onSendComplete = function(sendInfo) {
    log('onSendComplete');
    // Call sent callback.
    if (this.callbacks.sent) {
      this.callbacks.sent(sendInfo);
    }
  };

  /**
   * Converts an array buffer to a string
   *
   * @private
   * @param {ArrayBuffer} buf The buffer to convert
   * @param {Function} callback The function to call when conversion is complete
   */
  TcpClient.prototype._arrayBufferToString = function(buf, callback) {
    var reader = new FileReader();
    reader.onload = function(e) {
      callback(e.target.result);
    };
    var blob=new Blob([ buf ], { type: 'application/octet-stream' });
    reader.readAsText(blob);
  };

  /**
   * Converts a string to an array buffer
   *
   * @private
   * @param {String} str The string to convert
   * @param {Function} callback The function to call when conversion is complete
   */
  TcpClient.prototype._stringToArrayBuffer = function(str, callback) {
    var bb = new Blob([str]);
    var f = new FileReader();
    f.onload = function(e) {
       callback(e.target.result);
    };
    f.readAsArrayBuffer(bb);
  };

  /**
   * Wrapper function for logging
   */
  function log(msg) {
    console.log(msg);
  }

  /**
   * Wrapper function for error logging
   */
  function error(msg) {
    console.error(msg);
  }

  //constructor for a service instance object
  return {
    /**
     * instantiates tcp service, initializes the client
     *
     * @param {String} host The remote host to connect to
     * @param {Number} port The port to connect to at the remote host
     */
    getInstance: function (host, port)
    {
      return new TcpClient(host, port);
    }
  };
}
]);
})();
<|endoftext|>