<commit_before>'use strict';

const apiai = require('apiai');
const express = require('express');
const bodyParser = require('body-parser');
const uuid = require('node-uuid');
const request = require('request');
const JSONbig = require('json-bigint');
const async = require('async');

const REST_PORT = (process.env.PORT || 5000);
const APIAI_ACCESS_TOKEN = process.env.APIAI_ACCESS_TOKEN;
const APIAI_LANG = process.env.APIAI_LANG || 'en';
const FB_VERIFY_TOKEN = process.env.FB_VERIFY_TOKEN;
const FB_PAGE_ACCESS_TOKEN = process.env.FB_PAGE_ACCESS_TOKEN;
const FS_CLIENT_SECRET = process.env.FS_CLIENT_SECRET;
const FS_CLIENT_ID = process.env.FS_CLIENT_ID;

const apiAiService = apiai(APIAI_ACCESS_TOKEN, {language: APIAI_LANG, requestSource: "fb"});
const sessionIds = new Map();

const foursquareVersion = '20160108';

const actionFindVenue = 'findVenue';
const intentFindVenue = 'FindVenue';

function processEvent(event) {
    var sender = event.sender.id.toString();

    if ((event.message && event.message.text) || (event.postback && event.postback.payload)) {
        var text = event.message ? event.message.text : event.postback.payload;
        // Handle a text message from this sender

        if (!sessionIds.has(sender)) {
            sessionIds.set(sender, uuid.v1());
        }

        console.log("Text:", text);

        let apiaiRequest = apiAiService.textRequest(text,
            {
                sessionId: sessionIds.get(sender)
            });

        apiaiRequest.on('response', (response) => {
            if (isDefined(response.result)) {
                let responseText = response.result.fulfillment.speech;
                let responseData = response.result.fulfillment.data;
                var action = response.result.action;
                var intentName = response.result.metadata.intentName;
                var parameters = response.result.parameters;

                console.log(action);

                if (isDefined(responseData) && isDefined(responseData.facebook)) {
                    if (!Array.isArray(responseData.facebook)) {
                        try {
                            console.log('Response as formatted message');
                            sendFBMessage(sender, responseData.facebook);
                        } catch (err) {
                            sendFBMessage(sender, {text: err.message});
                        }
                    } else {
                        async.eachSeries(responseData.facebook, (facebookMessage, callback) => {
                            try {
                                if (facebookMessage.sender_action) {
                                    console.log('Response as sender action');
                                    sendFBSenderAction(sender, facebookMessage.sender_action, callback);
                                }
                                else {
                                    console.log('Response as formatted message');
                                    sendFBMessage(sender, facebookMessage, callback);
                                }
                            } catch (err) {
                                sendFBMessage(sender, {text: err.message}, callback);
                            }
                        });
                    }
                } else if (isDefined(responseText)) {
                    console.log('Response as text message');
                    // facebook API limit for text length is 320,
                    // so we must split message if needed
                    var splittedText = splitResponse(responseText);

                    async.eachSeries(splittedText, (textPart, callback) => {
                        sendFBMessage(sender, {text: textPart}, callback);
                    });
                } else if (isDefined(action) && isDefined(intentName)) {
                    if (action === actionFindVenue && intentName == intentFindVenue) {
                        if (isDefined(parameters)) {
                            console.log('Found parameters');
                            var foursquareResponse = splitResponse(findVenue(parameters));

                            async.eachSeries(splittedText, (textPart, callback) => {
                                sendFBMessage(sender, {text: textPart}, callback);
                            });
                        }
                    }
                }

            }
        });

        apiaiRequest.on('error', (error) => console.error(error));
        apiaiRequest.end();
    }
}

function splitResponse(str) {
    if (str.length <= 320) {
        return [str];
    }

    return chunkString(str, 300);
}

function chunkString(s, len) {
    var curr = len, prev = 0;

    var output = [];

    while (s[curr]) {
        if (s[curr++] == ' ') {
            output.push(s.substring(prev, curr));
            prev = curr;
            curr += len;
        }
        else {
            var currReverse = curr;
            do {
                if (s.substring(currReverse - 1, currReverse) == ' ') {
                    output.push(s.substring(prev, currReverse));
                    prev = currReverse;
                    curr = currReverse + len;
                    break;
                }
                currReverse--;
            } while (currReverse > prev)
        }
    }
    output.push(s.substr(prev));
    return output;
}

function sendFBMessage(sender, messageData, callback) {
    request({
        url: 'https://graph.facebook.com/v2.6/me/messages',
        qs: {access_token: FB_PAGE_ACCESS_TOKEN},
        method: 'POST',
        json: {
            recipient: {id: sender},
            message: messageData
        }
    }, (error, response, body) => {
        if (error) {
            console.log('Error sending message: ', error);
        } else if (response.body.error) {
            console.log('Error: ', response.body.error);
        }

        if (callback) {
            callback();
        }
    });
}

function sendFBSenderAction(sender, action, callback) {
    setTimeout(() => {
        request({
            url: 'https://graph.facebook.com/v2.6/me/messages',
            qs: {access_token: FB_PAGE_ACCESS_TOKEN},
            method: 'POST',
            json: {
                recipient: {id: sender},
                sender_action: action
            }
        }, (error, response, body) => {
            if (error) {
                console.log('Error sending action: ', error);
            } else if (response.body.error) {
                console.log('Error: ', response.body.error);
            }
            if (callback) {
                callback();
            }
        });
    }, 1000);
}

function doSubscribeRequest() {
    request({
            method: 'POST',
            uri: "https://graph.facebook.com/v2.6/me/subscribed_apps?access_token=" + FB_PAGE_ACCESS_TOKEN
        },
        (error, response, body) => {
            if (error) {
                console.error('Error while subscription: ', error);
            } else {
                console.log('Subscription result: ', response.body);
            }
        });
}

function isDefined(obj) {
    if (typeof obj == 'undefined') {
        return false;
    }

    if (!obj) {
        return false;
    }

    return obj != null;
}

const app = express();

app.use(bodyParser.text({type: 'application/json'}));

app.get('/webhook/', (req, res) => {
    if (req.query['hub.verify_token'] == FB_VERIFY_TOKEN) {
        res.send(req.query['hub.challenge']);

        setTimeout(() => {
            doSubscribeRequest();
        }, 3000);
    } else {
        res.send('Error, wrong validation token');
    }
});

app.post('/webhook/', (req, res) => {
    try {
        var data = JSONbig.parse(req.body);

        if (data.entry) {
            let entries = data.entry;
            entries.forEach((entry) => {
                let messaging_events = entry.messaging;
                if (messaging_events) {
                    messaging_events.forEach((event) => {
                        if (event.message && !event.message.is_echo ||
                            event.postback && event.postback.payload) {
                            processEvent(event);
                        }
                    });
                }
            });
        }

        return res.status(200).json({
            status: "ok"
        });
    } catch (err) {
        return res.status(400).json({
            status: "error",
            error: err
        });
    }

});

app.listen(REST_PORT, () => {
    console.log('Rest service ready on port ' + REST_PORT);
});

doSubscribeRequest();

function formatGETOptions(parameters) {

    if (!isDefined(parameters.venue)) {
        parameters.venue = 'restaurant';
    }

    var options = {
        method: 'GET'
        uri: 'http://api.foursquare.com/v2/venues/explore',
        qs: {
            client_id: FS_CLIENT_ID,
            client_secret: FS_CLIENT_SECRET,
            v: foursquareVersion,
            m: foursquare,
            near: parameters.address,
            query: parameters.venue,
            limit: 5,
        },
        json: true
    };

    console.log(options.url);

    return options;
}

function findVenue(parameters) {

    var response = "";

    var options = formatGETOptions(parameters);

    request(options)
        .then(function (res) {
            response = res;
        })
        .catch(function(err) {
            console.log('GET error: ' + err.message)
    })

    console.log(typeof(str));
    console.log(str.length);
    return str;
}<commit_msg>no message<commit_after>'use strict';

const apiai = require('apiai');
const express = require('express');
const bodyParser = require('body-parser');
const uuid = require('node-uuid');
const request = require('request');
const JSONbig = require('json-bigint');
const async = require('async');

const REST_PORT = (process.env.PORT || 5000);
const APIAI_ACCESS_TOKEN = process.env.APIAI_ACCESS_TOKEN;
const APIAI_LANG = process.env.APIAI_LANG || 'en';
const FB_VERIFY_TOKEN = process.env.FB_VERIFY_TOKEN;
const FB_PAGE_ACCESS_TOKEN = process.env.FB_PAGE_ACCESS_TOKEN;
const FS_CLIENT_SECRET = process.env.FS_CLIENT_SECRET;
const FS_CLIENT_ID = process.env.FS_CLIENT_ID;

const apiAiService = apiai(APIAI_ACCESS_TOKEN, {language: APIAI_LANG, requestSource: "fb"});
const sessionIds = new Map();

const foursquareVersion = '20160108';

const actionFindVenue = 'findVenue';
const intentFindVenue = 'FindVenue';

function processEvent(event) {
    var sender = event.sender.id.toString();

    if ((event.message && event.message.text) || (event.postback && event.postback.payload)) {
        var text = event.message ? event.message.text : event.postback.payload;
        // Handle a text message from this sender

        if (!sessionIds.has(sender)) {
            sessionIds.set(sender, uuid.v1());
        }

        console.log("Text:", text);

        let apiaiRequest = apiAiService.textRequest(text,
            {
                sessionId: sessionIds.get(sender)
            });

        apiaiRequest.on('response', (response) => {
            if (isDefined(response.result)) {
                let responseText = response.result.fulfillment.speech;
                let responseData = response.result.fulfillment.data;
                var action = response.result.action;
                var intentName = response.result.metadata.intentName;
                var parameters = response.result.parameters;

                console.log(action);

                if (isDefined(responseData) && isDefined(responseData.facebook)) {
                    if (!Array.isArray(responseData.facebook)) {
                        try {
                            console.log('Response as formatted message');
                            sendFBMessage(sender, responseData.facebook);
                        } catch (err) {
                            sendFBMessage(sender, {text: err.message});
                        }
                    } else {
                        async.eachSeries(responseData.facebook, (facebookMessage, callback) => {
                            try {
                                if (facebookMessage.sender_action) {
                                    console.log('Response as sender action');
                                    sendFBSenderAction(sender, facebookMessage.sender_action, callback);
                                }
                                else {
                                    console.log('Response as formatted message');
                                    sendFBMessage(sender, facebookMessage, callback);
                                }
                            } catch (err) {
                                sendFBMessage(sender, {text: err.message}, callback);
                            }
                        });
                    }
                } else if (isDefined(responseText)) {
                    console.log('Response as text message');
                    // facebook API limit for text length is 320,
                    // so we must split message if needed
                    var splittedText = splitResponse(responseText);

                    async.eachSeries(splittedText, (textPart, callback) => {
                        sendFBMessage(sender, {text: textPart}, callback);
                    });
                } else if (isDefined(action) && isDefined(intentName)) {
                    if (action === actionFindVenue && intentName == intentFindVenue) {
                        if (isDefined(parameters)) {
                            console.log('Found parameters');
                            var foursquareResponse = splitResponse(findVenue(parameters));

                            async.eachSeries(splittedText, (textPart, callback) => {
                                sendFBMessage(sender, {text: textPart}, callback);
                            });
                        }
                    }
                }

            }
        });

        apiaiRequest.on('error', (error) => console.error(error));
        apiaiRequest.end();
    }
}

function splitResponse(str) {
    if (str.length <= 320) {
        return [str];
    }

    return chunkString(str, 300);
}

function chunkString(s, len) {
    var curr = len, prev = 0;

    var output = [];

    while (s[curr]) {
        if (s[curr++] == ' ') {
            output.push(s.substring(prev, curr));
            prev = curr;
            curr += len;
        }
        else {
            var currReverse = curr;
            do {
                if (s.substring(currReverse - 1, currReverse) == ' ') {
                    output.push(s.substring(prev, currReverse));
                    prev = currReverse;
                    curr = currReverse + len;
                    break;
                }
                currReverse--;
            } while (currReverse > prev)
        }
    }
    output.push(s.substr(prev));
    return output;
}

function sendFBMessage(sender, messageData, callback) {
    request({
        url: 'https://graph.facebook.com/v2.6/me/messages',
        qs: {access_token: FB_PAGE_ACCESS_TOKEN},
        method: 'POST',
        json: {
            recipient: {id: sender},
            message: messageData
        }
    }, (error, response, body) => {
        if (error) {
            console.log('Error sending message: ', error);
        } else if (response.body.error) {
            console.log('Error: ', response.body.error);
        }

        if (callback) {
            callback();
        }
    });
}

function sendFBSenderAction(sender, action, callback) {
    setTimeout(() => {
        request({
            url: 'https://graph.facebook.com/v2.6/me/messages',
            qs: {access_token: FB_PAGE_ACCESS_TOKEN},
            method: 'POST',
            json: {
                recipient: {id: sender},
                sender_action: action
            }
        }, (error, response, body) => {
            if (error) {
                console.log('Error sending action: ', error);
            } else if (response.body.error) {
                console.log('Error: ', response.body.error);
            }
            if (callback) {
                callback();
            }
        });
    }, 1000);
}

function doSubscribeRequest() {
    request({
            method: 'POST',
            uri: "https://graph.facebook.com/v2.6/me/subscribed_apps?access_token=" + FB_PAGE_ACCESS_TOKEN
        },
        (error, response, body) => {
            if (error) {
                console.error('Error while subscription: ', error);
            } else {
                console.log('Subscription result: ', response.body);
            }
        });
}

function isDefined(obj) {
    if (typeof obj == 'undefined') {
        return false;
    }

    if (!obj) {
        return false;
    }

    return obj != null;
}

const app = express();

app.use(bodyParser.text({type: 'application/json'}));

app.get('/webhook/', (req, res) => {
    if (req.query['hub.verify_token'] == FB_VERIFY_TOKEN) {
        res.send(req.query['hub.challenge']);

        setTimeout(() => {
            doSubscribeRequest();
        }, 3000);
    } else {
        res.send('Error, wrong validation token');
    }
});

app.post('/webhook/', (req, res) => {
    try {
        var data = JSONbig.parse(req.body);

        if (data.entry) {
            let entries = data.entry;
            entries.forEach((entry) => {
                let messaging_events = entry.messaging;
                if (messaging_events) {
                    messaging_events.forEach((event) => {
                        if (event.message && !event.message.is_echo ||
                            event.postback && event.postback.payload) {
                            processEvent(event);
                        }
                    });
                }
            });
        }

        return res.status(200).json({
            status: "ok"
        });
    } catch (err) {
        return res.status(400).json({
            status: "error",
            error: err
        });
    }

});

app.listen(REST_PORT, () => {
    console.log('Rest service ready on port ' + REST_PORT);
});

doSubscribeRequest();

function formatGETOptions(parameters) {

    if (!isDefined(parameters.venue)) {
        parameters.venue = 'restaurant';
    }

    var options = {
        method: 'GET',
        uri: 'http://api.foursquare.com/v2/venues/explore',
        qs: {
            client_id: FS_CLIENT_ID,
            client_secret: FS_CLIENT_SECRET,
            v: foursquareVersion,
            m: foursquare,
            near: parameters.address,
            query: parameters.venue,
            limit: 5,
        },
        json: true
    };

    console.log(options.url);

    return options;
}

function findVenue(parameters) {

    var response = "";

    var options = formatGETOptions(parameters);

    request(options)
        .then(function (res) {
            response = res;
        })
        .catch(function(err) {
            console.log('GET error: ' + err.message)
    })

    console.log(typeof(str));
    console.log(str.length);
    return str;
}<|endoftext|>


<commit_before>'use strict';

function setup (app) {
    var profiled = conf('NODETIME_ENABLED');
    var nodetime;

    if (profiled) {
        nodetime = require('nodetime');
        app.use(nodetime.expressErrorHandler());
    }

    app.use(handler);
}

function handler (err, req, res, next) {
    if (req.xhr) {
        res.send(500, { error: 'Internal Server Error!' });
    } else {
        res.send(500, 'Internal Server Error!');
    }
}

module.exports = {
    setup: setup
};
<commit_msg>errorHnalder logs errors<commit_after>'use strict';

function setup (app) {
    var profiled = conf('NODETIME_ENABLED');
    var nodetime;

    if (profiled) {
        nodetime = require('nodetime');
        app.use(nodetime.expressErrorHandler());
    }

    app.use(handler);
}

function handler (err, req, res, next) {
    var result;
    var info = err.stack ? '\n' + err.stack : ': ' + err;

    if (req.xhr) {
        result = { error: 'Internal Server Error!' };
    } else {
        result = 'Internal Server Error!';
    }

    res.send(500, result);
    logger.info('Error handled on request for %s%s', req.url, info);
}

module.exports = {
    setup: setup
};
<|endoftext|>


<commit_before>/*!
  Form / application "onsubmit" handler, and analytics.
*/

var jsonabc = require("jsonabc");

window.appSort = appSort;

function appSort(ev, tid) {
  var inputStr = document.getElementById(tid).value;
  var noarray = document.getElementById("noarray").checked;

  ev.preventDefault();

  try {
    var output = jsonabc.sort(inputStr, noarray);

    document.getElementById(tid).value = output;

    console.warn("jsonabc input:", JSON.parse(inputStr), noarray);
  } catch (ex) {
    window.alert("Incorrect JSON object");
  }
}
<commit_msg>adds semistandard fix<commit_after>/*!
  Form / application "onsubmit" handler, and analytics.
*/

var jsonabc = require('jsonabc');

window.appSort = appSort;

function appSort (ev, tid) {
  var inputStr = document.getElementById(tid).value;
  var noarray = document.getElementById('noarray').checked;

  ev.preventDefault();

  try {
    var output = jsonabc.sort(inputStr, noarray);

    document.getElementById(tid).value = output;

    console.warn('jsonabc input:', JSON.parse(inputStr), noarray);
  } catch (ex) {
    window.alert('Incorrect JSON object');
  }
}
<|endoftext|>


<commit_before>angular.module('ot.view.buildSearch', [
    'ui.router',
    'ot.service.core',
    'ot.service.structure'
])
    .config(function ($stateProvider) {
        $stateProvider.state('build-search', {
            url: '/build-search/{projectId}',
            templateUrl: 'app/view/view.buildSearch.tpl.html',
            controller: 'BuildSearchCtrl'
        });
    })
    .controller('BuildSearchCtrl', function ($scope, $stateParams, $http, ot, otStructureService) {
        var view = ot.view();
        // Project's id
        var projectId = $stateParams.projectId;

        // Loading the project
        function loadProject() {
            otStructureService.getProject(projectId).then(function (projectResource) {
                $scope.project = projectResource;
                // View settings
                view.breadcrumbs = ot.projectBreadcrumbs(projectResource);
                view.title = "Build search";
                // View commands
                view.commands = [
                    ot.viewApiCommand(projectResource._buildSearch),
                    ot.viewCloseCommand('/project/' + projectResource.id)
                ];
                return ot.pageCall($http.get(projectResource._buildSearch));
            }).then(function (searchForm) {
                $scope.searchForm = searchForm;
            });
        }

        // Initialization
        loadProject();

        // Search
        $scope.submitSearch = function () {
            ot.pageCall($http.get($scope.searchForm._search, {params: $scope.data})).then(function (result) {
                $scope.buildViews = result.resources;
            });
        };

    })
;<commit_msg>#173 Build search - correction of submit data<commit_after>angular.module('ot.view.buildSearch', [
    'ui.router',
    'ot.service.core',
    'ot.service.form',
    'ot.service.structure'
])
    .config(function ($stateProvider) {
        $stateProvider.state('build-search', {
            url: '/build-search/{projectId}',
            templateUrl: 'app/view/view.buildSearch.tpl.html',
            controller: 'BuildSearchCtrl'
        });
    })
    .controller('BuildSearchCtrl', function ($scope, $stateParams, $http, ot, otStructureService, otFormService) {
        var view = ot.view();
        // Project's id
        var projectId = $stateParams.projectId;

        // Loading the project
        function loadProject() {
            otStructureService.getProject(projectId).then(function (projectResource) {
                $scope.project = projectResource;
                // View settings
                view.breadcrumbs = ot.projectBreadcrumbs(projectResource);
                view.title = "Build search";
                // View commands
                view.commands = [
                    ot.viewApiCommand(projectResource._buildSearch),
                    ot.viewCloseCommand('/project/' + projectResource.id)
                ];
                return ot.pageCall($http.get(projectResource._buildSearch));
            }).then(function (searchForm) {
                $scope.searchForm = searchForm;
                $scope.data = otFormService.prepareForDisplay(searchForm);
            });
        }

        // Initialization
        loadProject();

        // Search
        $scope.submitSearch = function () {
            ot.pageCall($http.get($scope.searchForm._search, {params: $scope.data})).then(function (result) {
                $scope.buildViews = result.resources;
            });
        };

    })
;<|endoftext|>


<commit_before>import {Rx} from '@cycle/core';
import {h} from '@cycle/dom';

import TimeTravel from 'cycle-time-travel';

function todoView ({todo, complete}) {
  return (
    h('.todo', [
      h('span.title', todo),
      h('input.complete', {type: 'checkbox', checked: complete})
    ])
  );
}

function todosView (todos) {
  return (
    h('.todos', todos.map(todoView))
  );
}

function todoAppView (todos) {
  return (
    h('.todo-app', [
      h('input.new-todo'),
      h('button.add-todo', 'Add todo'),
      todosView(todos)
    ])
  );
}

function addTodo (todo) {
  return (todos) => {
    return todos.concat([{todo, complete: false}]);
  };
}

export default function main ({DOM}) {
  const newTodoText$ = DOM
    .select('.new-todo')
    .events('input')
    .map(event => event.target.value);

  const addTodo$ = DOM
    .select('.add-todo')
    .events('click')
    .withLatestFrom(newTodoText$, (_, todoText) => addTodo(todoText));

  const startingTodos = [
    {todo: 'Display todos', complete: true},
    {todo: 'Add todos', complete: true},
    {todo: 'Toggle todo', complete: false}
  ];

  const action$ = addTodo$;

  const todos$ = action$
    .startWith(startingTodos)
    .scan((todos, action) => action(todos));

  const timeTravel = TimeTravel(DOM, [
    {stream: todos$, label: 'todos$', feature: true},
    {stream: addTodo$, label: 'addTodo$'},
    {stream: newTodoText$, label: 'newTodoText$'}
  ]);

  const view$ = timeTravel.timeTravel.todos$.map(todoAppView);

  return {
    DOM: Rx.Observable.combineLatest(view$, timeTravel.DOM,
      (...vtrees) => h('div', vtrees)
    )
  };
}

<commit_msg>Toggle todos<commit_after>import {Rx} from '@cycle/core';
import {h} from '@cycle/dom';

import TimeTravel from 'cycle-time-travel';

function todoView ({todo, complete}, index) {
  return (
    h('.todo', [
      h('span.title', todo),
      h('input.toggle', {type: 'checkbox', checked: complete, todoId: index})
    ])
  );
}

function todosView (todos) {
  return (
    h('.todos', todos.map(todoView))
  );
}

function todoAppView (todos) {
  return (
    h('.todo-app', [
      h('input.new-todo'),
      h('button.add-todo', 'Add todo'),
      todosView(todos)
    ])
  );
}

function addTodo (todo) {
  return (todos) => {
    return todos.concat([{todo, complete: false}]);
  };
}

function toggleTodo ({complete, index}) {
  return (todos) => {
    const newTodos = todos.slice(); // duplicate

    newTodos[index].complete = complete;

    return newTodos;
  };
}

export default function main ({DOM}) {
  const newTodoText$ = DOM
    .select('.new-todo')
    .events('input')
    .map(event => event.target.value);

  const addTodo$ = DOM
    .select('.add-todo')
    .events('click')
    .withLatestFrom(newTodoText$, (_, todoText) => addTodo(todoText));

  const toggleTodo$ = DOM
    .select('.toggle')
    .events('click')
    .map(event => ({complete: event.target.checked, index: event.target.todoId}))
    .map(toggleTodo)

  const startingTodos = [
    {todo: 'Display todos', complete: true},
    {todo: 'Add todos', complete: true},
    {todo: 'Toggle todo', complete: true},
    {todo: 'Clear complete', complete: false}
  ];

  const action$ = addTodo$.merge(toggleTodo$);

  const todos$ = action$
    .startWith(startingTodos)
    .scan((todos, action) => action(todos));

  const timeTravel = TimeTravel(DOM, [
    {stream: todos$, label: 'todos$', feature: true},
    {stream: addTodo$, label: 'addTodo$'},
    {stream: newTodoText$, label: 'newTodoText$'},
    {stream: toggleTodo$, label: 'toggleTodo$'}
  ]);

  const view$ = timeTravel.timeTravel.todos$.map(todoAppView);

  return {
    DOM: Rx.Observable.combineLatest(view$, timeTravel.DOM,
      (...vtrees) => h('div', vtrees)
    )
  };
}

<|endoftext|>


<commit_before>var k = Mousetrap;
var m = require('mithril');
var partial = require('chessground').util.partial;

function findOnlyOrig(allDests, dest) {
  var found;
  for (var key in allDests)
    if (allDests[key].indexOf(dest) > -1) {
      if (found) return;
      found = key;
    }
  return found;
}

module.exports = {
  ctrl: function(root) {
    var cg = root.chessground;
    var focus = m.prop(false);
    return {
      focus: focus,
      select: function(key) {
        var selected = cg.data.selected;
        if (selected === key) return cg.cancelMove();
        var onlyOrig = selected ? null : findOnlyOrig(cg.data.movable.dests, key);
        if (onlyOrig) cg.selectSquare(onlyOrig);
        cg.selectSquare(key);
      }
    };
  },
  view: function(ctrl) {
    return m('div.keyboard-move', [
      m('input', {
        config: function(el, isUpdate) {
          if (!isUpdate) {
            el.focus();
            k.bind('enter', function() {
              el.focus();
            });
          }
        },
        onfocus: partial(ctrl.focus, true),
        onblur: partial(ctrl.focus, false),
        onkeyup: function(e) {
          var v = e.target.value;
          if (v.length < 2) return;
          if (v.match(/[a-h][1-8]/)) ctrl.select(v);
          e.target.value = '';
        }
      }),
      ctrl.focus() ?
      m('em', 'Enter coordinates to select squares (like e4 or g8)') :
      m('strong', 'Press <enter> to focus')
    ]);
  }
};
<commit_msg>press / in keyboard move input to focus on the chat<commit_after>var k = Mousetrap;
var m = require('mithril');
var partial = require('chessground').util.partial;

function findOnlyOrig(allDests, dest) {
  var found;
  for (var key in allDests)
    if (allDests[key].indexOf(dest) > -1) {
      if (found) return;
      found = key;
    }
  return found;
}

module.exports = {
  ctrl: function(root) {
    var cg = root.chessground;
    var focus = m.prop(false);
    return {
      focus: focus,
      select: function(key) {
        var selected = cg.data.selected;
        if (selected === key) return cg.cancelMove();
        var onlyOrig = selected ? null : findOnlyOrig(cg.data.movable.dests, key);
        if (onlyOrig) cg.selectSquare(onlyOrig);
        cg.selectSquare(key);
      }
    };
  },
  view: function(ctrl) {
    return m('div.keyboard-move', [
      m('input', {
        config: function(el, isUpdate) {
          if (!isUpdate) {
            el.focus();
            k.bind('enter', function() {
              el.focus();
            });
          }
        },
        onfocus: partial(ctrl.focus, true),
        onblur: partial(ctrl.focus, false),
        onkeyup: function(e) {
          var v = e.target.value;
          if (v.indexOf('/') > -1) {
            var chatInput = document.querySelector('.mchat input.lichess_say');
            if (chatInput) chatInput.focus();
          } else {
            if (v.length < 2) return;
            if (v.match(/[a-h][1-8]/)) ctrl.select(v);
          }
          e.target.value = '';
        }
      }),
      ctrl.focus() ?
      m('em', 'Enter coordinates to select squares (like e4 or g8)') :
      m('strong', 'Press <enter> to focus')
    ]);
  }
};
<|endoftext|>


<commit_before>console.log('Booting application');

//

var debug = require('debug')('alarmclock:app');

require('modules/SebastiaanLuca/Helpers/src/ProcessHelper.js');
require('modules/SebastiaanLuca/Helpers/src/KeepAwake.js');

var Volume = require('modules/SebastiaanLuca/Volume/src/Volume.js');
var Player = require('modules/SebastiaanLuca/Player/src/MpdPlayer.js');
var Playlist = require('modules/SebastiaanLuca/Player/src/Playlist.js');

var AlarmClock = require('modules/SebastiaanLuca/AlarmClock/src/AlarmClock.js');
var Controls = require('modules/SebastiaanLuca/Controls/src/Controls.js');

// Use event handlers to link events of certain modules to their counterparts
var ControlsEventHandler = require('EventHandlers/ControlsEventHandler.js');
var PlayerEventHandler = require('EventHandlers/PlayerEventHandler.js');
var AlarmEventHandler = require('EventHandlers/AlarmEventHandler.js');

//

var DEFAULT_VOLUME = 90;

//

/*
 * Volume
 */

// Set default system volume
Volume.setVolume(DEFAULT_VOLUME);

/*
 * Player
 */

// TODO: move to config file
// See https://github.com/motdotla/dotenv + https://github.com/harishanchu/nodejs-config
// TODO: add button to reset (player playlist and reload+readd streams from config file (should it have changed))
var tracks = [
    'http://mp3.streampower.be/stubru-high.mp3',
    //    'http://mp3.streampower.be/mnm-high.mp3',
    //    'http://mp3.streampower.be/klara-high.mp3',

    'http://www.plusfm.net/plusfm.m3u',
    'http://stream.boosh.fm:8000/booshfm_128.mp3',
    'http://stream.house-radio.com:8000/main.m3u',
    'http://1.fm/TuneIn/dubstep128k.pls',
    'http://uk1.internet-radio.com:15634/listen.pls',
    'http://www.radiofeeds.co.uk/bbc1xtra.pls',
    'http://178.20.171.32:8058/',
    'http://nsbradio.co.uk/listen128k.pls',
    'http://www.uzic.ch/tek.m3u',
    'http://smoothlounge.com/streams/smoothlounge_256.pls',
    'http://dnbheaven.com/128kbps.m3u',
    'http://uk2.internet-radio.com:30252/;listen.mp3',
    'http://www.danceattack.fm/Dance_Attack_FM.m3u',
    'https://control.internet-radio.com:2199/tunein/ukvibes.pls',
    'https://control.internet-radio.com:2199/tunein/deeplondon.pls',
    'http://dancewave.online/dance.mp3.m3u',
    'http://listen.54house.fm/listen.pls',
    'http://majestic.wavestreamer.com:9623/listen.pls',
    'http://www.dogglounge.com/listen.pls',

    'http://uk2.internet-radio.com:31491/listen.pls',
    'http://listen.radionomy.com/jamjazz.m3u',
    'http://listen.radionomy.com/jampro-jazz.m3u',

    // Local backup audio file as backup alarm
    // See ~/Music/
    'cuckoo.mp3'
];

// Create a playlist
playlist = new Playlist(tracks);

// Create a player using our playlist
player = new Player(playlist);

// Set some player options
player.repeat(true);

/*
 * Alarm
 */

// Create an alarm clock using our player
var alarm = new AlarmClock({
    // Run every day at
    at: {hour: 8, minute: 0},

    // Auto-snooze after x minutes
    playTime: 5 * 60,

    // Set speaker target volume
    volume: DEFAULT_VOLUME,

    // Duration to increase volume to target level (in minutes)
    increaseDuration: 15
}, player);

/*
 * Event handling
 */
new ControlsEventHandler(Controls, player);
new PlayerEventHandler(player, Controls);
new AlarmEventHandler(alarm, Controls);

//

console.log('Application ready!');

Controls.enableAppRunningIndicatorLed(true);<commit_msg>Tweak configuration<commit_after>console.log('Booting application');

//

var debug = require('debug')('alarmclock:app');

require('modules/SebastiaanLuca/Helpers/src/ProcessHelper.js');
require('modules/SebastiaanLuca/Helpers/src/KeepAwake.js');

var Volume = require('modules/SebastiaanLuca/Volume/src/Volume.js');
var Player = require('modules/SebastiaanLuca/Player/src/MpdPlayer.js');
var Playlist = require('modules/SebastiaanLuca/Player/src/Playlist.js');

var AlarmClock = require('modules/SebastiaanLuca/AlarmClock/src/AlarmClock.js');
var Controls = require('modules/SebastiaanLuca/Controls/src/Controls.js');

// Use event handlers to link events of certain modules to their counterparts
var ControlsEventHandler = require('EventHandlers/ControlsEventHandler.js');
var PlayerEventHandler = require('EventHandlers/PlayerEventHandler.js');
var AlarmEventHandler = require('EventHandlers/AlarmEventHandler.js');

//

var DEFAULT_VOLUME = 90;

//

/*
 * Volume
 */

// Set default system volume
Volume.setVolume(DEFAULT_VOLUME);

/*
 * Player
 */

// TODO: move to config file
// See https://github.com/motdotla/dotenv + https://github.com/harishanchu/nodejs-config
// TODO: add button to reset (player playlist and reload+readd streams from config file (should it have changed))
var tracks = [
    'http://mp3.streampower.be/stubru-high.mp3',
    //    'http://mp3.streampower.be/mnm-high.mp3',
    //    'http://mp3.streampower.be/klara-high.mp3',

    'http://www.plusfm.net/plusfm.m3u',
    'http://stream.boosh.fm:8000/booshfm_128.mp3',
    'http://stream.house-radio.com:8000/main.m3u',
    'http://1.fm/TuneIn/dubstep128k.pls',
    'http://uk1.internet-radio.com:15634/listen.pls',
    'http://www.radiofeeds.co.uk/bbc1xtra.pls',
    'http://178.20.171.32:8058/',
    'http://nsbradio.co.uk/listen128k.pls',
    'http://www.uzic.ch/tek.m3u',
    'http://smoothlounge.com/streams/smoothlounge_256.pls',
    'http://dnbheaven.com/128kbps.m3u',
    'http://uk2.internet-radio.com:30252/;listen.mp3',
    'http://www.danceattack.fm/Dance_Attack_FM.m3u',
    'https://control.internet-radio.com:2199/tunein/ukvibes.pls',
    'https://control.internet-radio.com:2199/tunein/deeplondon.pls',
    'http://dancewave.online/dance.mp3.m3u',
    'http://listen.54house.fm/listen.pls',
    'http://majestic.wavestreamer.com:9623/listen.pls',
    'http://www.dogglounge.com/listen.pls',

    'http://uk2.internet-radio.com:31491/listen.pls',
    'http://listen.radionomy.com/jamjazz.m3u',
    'http://listen.radionomy.com/jampro-jazz.m3u',

    // Local backup audio file as backup alarm
    // See ~/Music/
    'cuckoo.mp3',
];

// Create a playlist
const playlist = new Playlist(tracks);

// Create a player using our playlist
player = new Player(playlist);

// Set some player options
player.repeat(true);

/*
 * Alarm
 */

// Create an alarm clock using our player
const alarm = new AlarmClock({
    // Run every day at
    at: {hour: 9, minute: 0},

    // Auto-snooze after x minutes
    playTime: 5 * 60,

    // Set speaker target volume
    volume: DEFAULT_VOLUME,

    // Duration to increase volume to target level (in minutes)
    increaseDuration: 10,
}, player);

/*
 * Event handling
 */
new ControlsEventHandler(Controls, player);
new PlayerEventHandler(player, Controls);
new AlarmEventHandler(alarm, Controls);

//

console.log('Application ready!');

Controls.enableAppRunningIndicatorLed(true);
<|endoftext|>


<commit_before>/**
 * @overview ccm component for interpret JavaScript expressions
 * @author André Kless <andre.kless@web.de> 2016
 * @license The MIT License (MIT)
 */

ccm.component( /** @lends ccm.components.eval */ {

  /*-------------------------------------------- public component members --------------------------------------------*/

  /**
   * @summary component index
   * @type {ccm.types.index}
   */
  index: 'eval',

  /**
   * @summary default instance configuration
   * @type {ccm.components.eval.types.config}
   */
  config: {

    style:     [ ccm.load,  '../eval/layout.css' ],
    data: {
      store:   [ ccm.store, '../eval/datastore.json' ],
      key:     'demo'
    },
    button:   'Submit',
    onFinish: function ( result ) { console.log( result ); }

  },

  /*-------------------------------------------- public component classes --------------------------------------------*/

  /**
   * @summary constructor for creating ccm instances out of this component
   * @class
   */
  Instance: function () {

    /*------------------------------------- private and public instance members --------------------------------------*/

    /**
     * @summary own context
     * @private
     */
    var self = this;

    /**
     * @summary contains privatized config members
     * @type {ccm.components.eval.types.config}
     */
    var my;

    /*------------------------------------------- public instance methods --------------------------------------------*/

    /**
     * @summary initialize ccm instance
     * @description
     * Called one-time when this ccm instance is created, all dependencies are solved and before dependent ccm components, instances and datastores are initialized.
     * This method will be removed by ccm after the one-time call.
     * @param {function} callback - callback when this instance is initialized
     */
    this.init = function ( callback ) {

      // privatize security relevant config members
      my = ccm.helper.privatize( self, 'button', 'fieldset', 'data', 'onFinish' );

      // perform callback
      callback();

    };

    /**
     * @summary render content in own website area
     * @param {function} [callback] - callback when content is rendered
     */
    this.render = function ( callback ) {

      /**
       * website area for own content
       * @type {ccm.types.element}
       */
      var element = ccm.helper.element( self );

      // get dataset for editing
      ccm.helper.dataset( my.data, function ( dataset ) {

        /**
         * ccm HTML data for own website area
         * @type {ccm.types.html}
         */
        var html = [ { class: 'code', contenteditable: true, inner: dataset.html }, { tag: 'button', inner: my.button, onclick: '%%' } ];

        // generate ccm HTML data for HTML fieldset
        generateFieldset();

        // set content of own website area
        element.html( ccm.helper.html( html, submit ) );

        // perform callback
        if ( callback ) callback();

        /**
         * generate ccm HTML data for HTML fieldset
         */
        function generateFieldset() {

          if ( my.fieldset ) {
            html = { tag: 'fieldset', inner: html };
            if ( typeof my.fieldset === 'string' )
              html.inner.unshift( { tag: 'legend', inner: my.fieldset } );
          }

        }

        /**
         * submit callback of the HTML form
         * @returns {boolean}
         */
        function submit() {

          var $code = ccm.helper.find( self, '.code' );
          dataset.html = $code.html();
          dataset.text = $code.text();
          var result;

          // try to interpret JavaScript expression
          try { result = JSON.parse( dataset.text ); } catch ( err ) {
            try { result = eval( '(' + dataset.text + ')' ); } catch ( err ) {
              alert( 'input is not valid' ); return false;
            }
          }

          // update dataset in datastore
          my.data.store.set( dataset, function ( dataset ) {

            // add result of interpreted JavaScript expression to dataset
            dataset.result = result;

            // perform given submit callback with dataset
            my.onFinish( dataset );

          } );

          // prevent page reload
          return false;

        }

      } );

    }

  }

  /*------------------------------------------------ type definitions ------------------------------------------------*/

  /**
   * @namespace ccm.components.eval
   */

  /**
   * @namespace ccm.components.eval.types
   */

  /**
   * @summary ccm instance configuration
   * @typedef {ccm.config} ccm.components.eval.types.config
   * @property {ccm.types.element} element - ccm instance website area
   * @property {ccm.types.dependency} style - CSS for own website area
   * @property {ccm.types.dependency} data.store - ccm datastore that contains the [dataset for editing]{@link ccm.components.eval.types.dataset}
   * @property {ccm.types.key} data.key - key of [dataset for editing]{@link ccm.components.eval.types.dataset}
   * @property {boolean|string} button - button caption
   * @property {boolean|string} fieldset - wraps a fieldset

   *

   * falsy: no fieldset

   * true: fieldset without a legend

   * string: fieldset with given string as legend
   * @property {ccm.components.eval.types.onFinish} onFinish - callback for button click event
   * @example {
   *   element:  jQuery( 'body' ),
   *   classes:  'ccm-eval',
   *   style:    [ ccm.load,  '../eval/layout.css' ],
   *   data: {
   *     store:  [ ccm.store, '../eval/datastore.json' ],
   *     key:    'demo'
   *   },
   *   button:   'Submit',
   *   onFinish: function ( result ) { console.log( result ); }
   * }
   */

  /**
   * @summary dataset for editing
   * @typedef {ccm.types.dataset} ccm.components.eval.types.dataset
   * @property {ccm.types.key} key - dataset key
   * @property {string} html - result of .html()
   * @property {string} text - result of .text()
   * @property {*} result - interpreted result (only set in dataset via onFinish callback)
   * @example {
   *   key:  'demo',
   *   html: "{
  foo: 'bar',
  baz: function () { alert('Hello, World!'); }
}"
   *   text: "{  foo: 'bar',  baz: function () { alert('Hello, World!'); }}"
   * }
   */

  /**
   * @callback ccm.components.eval.types.onFinish
   * @summary callback for button click event
   * @param {ccm.components.eval.types.dataset} result - resulting dataset (with included interpreted result)
   * @example function ( dataset ) { console.log( dataset.result ); }
   */

  /**
   * @external ccm.types
   * @see {@link http://akless.github.io/ccm-developer/api/ccm/ccm.types.html}
   */

} );<commit_msg>minor change<commit_after>/**
 * @overview ccm component for interpret JavaScript expressions
 * @author André Kless <andre.kless@web.de> 2016
 * @license The MIT License (MIT)
 */

ccm.component( /** @lends ccm.components.eval */ {

  /*-------------------------------------------- public component members --------------------------------------------*/

  /**
   * @summary component index
   * @type {ccm.types.index}
   */
  index: 'eval',

  /**
   * @summary default instance configuration
   * @type {ccm.components.eval.types.config}
   */
  config: {

    style:    [ ccm.load,  '../eval/layout.css' ],
    data:     {
      store:  [ ccm.store, '../eval/datastore.json' ],
      key:    'demo'
    },
    button:   'Submit',
    onFinish: function ( result ) { console.log( result ); }

  },

  /*-------------------------------------------- public component classes --------------------------------------------*/

  /**
   * @summary constructor for creating ccm instances out of this component
   * @class
   */
  Instance: function () {

    /*------------------------------------- private and public instance members --------------------------------------*/

    /**
     * @summary own context
     * @private
     */
    var self = this;

    /**
     * @summary contains privatized config members
     * @type {ccm.components.eval.types.config}
     */
    var my;

    /*------------------------------------------- public instance methods --------------------------------------------*/

    /**
     * @summary initialize ccm instance
     * @description
     * Called one-time when this ccm instance is created, all dependencies are solved and before dependent ccm components, instances and datastores are initialized.
     * This method will be removed by ccm after the one-time call.
     * @param {function} callback - callback when this instance is initialized
     */
    this.init = function ( callback ) {

      // privatize security relevant config members
      my = ccm.helper.privatize( self, 'button', 'fieldset', 'data', 'onFinish' );

      // perform callback
      callback();

    };

    /**
     * @summary render content in own website area
     * @param {function} [callback] - callback when content is rendered
     */
    this.render = function ( callback ) {

      /**
       * website area for own content
       * @type {ccm.types.element}
       */
      var element = ccm.helper.element( self );

      // get dataset for editing
      ccm.helper.dataset( my.data, function ( dataset ) {

        /**
         * ccm HTML data for own website area
         * @type {ccm.types.html}
         */
        var html = [ { class: 'code', contenteditable: true, inner: dataset.html }, { tag: 'button', inner: my.button, onclick: '%%' } ];

        // generate ccm HTML data for HTML fieldset
        generateFieldset();

        // set content of own website area
        element.html( ccm.helper.html( html, submit ) );

        // perform callback
        if ( callback ) callback();

        /**
         * generate ccm HTML data for HTML fieldset
         */
        function generateFieldset() {

          if ( my.fieldset ) {
            html = { tag: 'fieldset', inner: html };
            if ( typeof my.fieldset === 'string' )
              html.inner.unshift( { tag: 'legend', inner: my.fieldset } );
          }

        }

        /**
         * submit callback of the HTML form
         * @returns {boolean}
         */
        function submit() {

          var $code = ccm.helper.find( self, '.code' );
          dataset.html = $code.html();
          dataset.text = $code.text();
          var result;

          // try to interpret JavaScript expression
          try { result = JSON.parse( dataset.text ); } catch ( err ) {
            try { result = eval( '(' + dataset.text + ')' ); } catch ( err ) {
              alert( 'input is not valid' ); return false;
            }
          }

          // update dataset in datastore
          my.data.store.set( dataset, function ( dataset ) {

            // add result of interpreted JavaScript expression to dataset
            dataset.result = result;

            // perform given submit callback with dataset
            my.onFinish( dataset );

          } );

          // prevent page reload
          return false;

        }

      } );

    }

  }

  /*------------------------------------------------ type definitions ------------------------------------------------*/

  /**
   * @namespace ccm.components.eval
   */

  /**
   * @namespace ccm.components.eval.types
   */

  /**
   * @summary ccm instance configuration
   * @typedef {ccm.config} ccm.components.eval.types.config
   * @property {ccm.types.element} element - ccm instance website area
   * @property {ccm.types.dependency} style - CSS for own website area
   * @property {ccm.types.dependency} data.store - ccm datastore that contains the [dataset for editing]{@link ccm.components.eval.types.dataset}
   * @property {ccm.types.key} data.key - key of [dataset for editing]{@link ccm.components.eval.types.dataset}
   * @property {boolean|string} button - button caption
   * @property {boolean|string} fieldset - wraps a fieldset

   *

   * falsy: no fieldset

   * true: fieldset without a legend

   * string: fieldset with given string as legend
   * @property {ccm.components.eval.types.onFinish} onFinish - callback for button click event
   * @example {
   *   element:  jQuery( 'body' ),
   *   classes:  'ccm-eval',
   *   style:    [ ccm.load,  '../eval/layout.css' ],
   *   data: {
   *     store:  [ ccm.store, '../eval/datastore.json' ],
   *     key:    'demo'
   *   },
   *   button:   'Submit',
   *   onFinish: function ( result ) { console.log( result ); }
   * }
   */

  /**
   * @summary dataset for editing
   * @typedef {ccm.types.dataset} ccm.components.eval.types.dataset
   * @property {ccm.types.key} key - dataset key
   * @property {string} html - result of .html()
   * @property {string} text - result of .text()
   * @property {*} result - interpreted result (only set in dataset via onFinish callback)
   * @example {
   *   key:  'demo',
   *   html: "{
  foo: 'bar',
  baz: function () { alert('Hello, World!'); }
}"
   *   text: "{  foo: 'bar',  baz: function () { alert('Hello, World!'); }}"
   * }
   */

  /**
   * @callback ccm.components.eval.types.onFinish
   * @summary callback for button click event
   * @param {ccm.components.eval.types.dataset} result - resulting dataset (with included interpreted result)
   * @example function ( dataset ) { console.log( dataset.result ); }
   */

  /**
   * @external ccm.types
   * @see {@link http://akless.github.io/ccm-developer/api/ccm/ccm.types.html}
   */

} );<|endoftext|>


<commit_before>'use strict';

var htmlToUnicode = require('../../gl3d/lib/html2unicode');
var str2RGBArray = require('../../gl3d/lib/str2rgbarray');

function Axes2DOptions(scene) {
    this.gl = scene.gl;
    this.pixelRatio = scene.pixelRatio;

    this.screenBox = [0, 0, 1, 1];
    this.viewBox = [0 ,0, 1, 1];
    this.dataBox = [-1, -1, 1, 1];

    this.borderLineEnable = [false, false, false, false];
    this.borderLineWidth = [1, 1, 1, 1];
    this.borderLineColor = [
        [0, 0, 0, 1],
        [0, 0, 0, 1],
        [0, 0, 0, 1],
        [0, 0, 0, 1]
    ];

    this.ticks = [[], []];
    this.tickEnable = [true, true, false, false];
    this.tickPad = [15, 15, 15, 15];
    this.tickAngle = [0, 0, 0, 0];
    this.tickColor = [
        [0, 0, 0, 1],
        [0, 0, 0, 1],
        [0, 0, 0, 1],
        [0, 0, 0, 1]
    ];
    this.tickMarkWidth = [0, 0, 0, 0];
    this.tickMarkLength = [0, 0, 0, 0];

    this.labels = ['x', 'y'];
    this.labelEnable = [true, true, false, false];
    this.labelAngle  = [0, Math.PI/2, 0, 3.0*Math.PI/2];
    this.labelPad = [15, 15, 15, 15];
    this.labelSize = [12, 12];
    this.labelFont = ['sans-serif', 'sans-serif'];
    this.labelColor = [
        [0, 0, 0, 1],
        [0, 0, 0, 1],
        [0, 0, 0, 1],
        [0, 0, 0, 1]
    ];

    this.title = '';
    this.titleEnable = true;
    this.titleCenter = [0, 0, 0, 0];
    this.titleAngle = 0;
    this.titleColor = [0, 0, 0, 1];
    this.titleFont = 'sans-serif';
    this.titleSize = 18;

    this.gridLineEnable = [true, true];
    this.gridLineColor = [
        [0, 0, 0, 0.5],
        [0, 0, 0, 0.5]
    ];
    this.gridLineWidth = [1, 1];

    this.zeroLineEnable = [true, true];
    this.zeroLineWidth = [1, 1];
    this.zeroLineColor = [
        [0, 0, 0, 1],
        [0, 0, 0, 1]
    ];

    this.borderColor = [0, 0, 0, 0];
    this.backgroundColor = [0, 0, 0, 0];
}

var proto = Axes2DOptions.prototype;

var AXES = ['xaxis', 'yaxis'];

proto.merge = function(options) {

    // titles are rendered in SVG
    this.titleEnable = false;
    this.backgroundColor = str2RGBArray(options.plot_bgcolor);

    var axisName, ax, axTitle;
    var hasAxisInDfltPos, hasAxisInAltrPos, mirrorLines, mirrorTicks;

    for(var i = 0; i < 2; ++i) {
        axisName = AXES[i];
        ax = options[axisName];

        axTitle = /Click to enter .+ title/.test(ax.title) ?  '' : ax.title;

        for(var j = 0; j <= 2; j += 2) {
            this.labelEnable[i+j] = false;
            this.labels[i+j] = htmlToUnicode(axTitle);
            this.labelColor[i+j] = str2RGBArray(ax.titlefont.color);
            this.labelFont[i+j] = ax.titlefont.family;
            this.labelSize[i+j] = ax.titlefont.size;
            this.labelPad[i+j] = this.getLabelPad(axisName, ax);

            this.tickEnable[i+j] = false;
            this.tickColor[i+j] = str2RGBArray(ax.tickcolor);
            this.tickAngle[i+j] = (ax.tickangle === 'auto') ? 0 : -ax.tickangle;
            this.tickPad[i+j] = this.getTickPad(axisName, ax);

            this.borderLineEnable[i+j] = false;
            this.borderLineColor[i+j] = str2RGBArray(ax.linecolor);
            this.borderLineWidth[i+j] = ax.linewidth || 0;
        }

        hasAxisInDfltPos = this.hasAxisInDfltPos(axisName, ax);
        hasAxisInAltrPos = this.hasAxisInAltrPos(axisName, ax);
        mirrorLines = (ax.mirror);
        mirrorTicks = (ax.mirror === 'ticks') || (ax.mirror === 'allticks');

        if(hasAxisInDfltPos) this.labelEnable[i] = ax.showticklabels;
        else if(hasAxisInAltrPos) this.labelEnable[i+2] = ax.showticklabels;

        if(hasAxisInDfltPos || mirrorLines) this.borderLineEnable[i] = ax.showline;
        if(hasAxisInAltrPos || mirrorLines) this.borderLineEnable[i+2] = ax.showline;

        if(hasAxisInDfltPos || mirrorTicks) this.tickEnable[i] = ax.showticklabels;
        if(hasAxisInAltrPos || mirrorTicks) this.tickEnable[i+2] = ax.showticklabels;

        // TODO
        this.tickMarkLength[i^1] = ax.ticklen;
        this.tickMarkWidth[i^1] = ax.tickwidth;

        this.gridLineEnable[i] = ax.showgrid;
        this.gridLineColor[i] = str2RGBArray(ax.gridcolor);
        this.gridLineWidth[i] = ax.gridwidth;

        this.zeroLineEnable[i] = ax.zeroline;
        this.zeroLineColor[i] = str2RGBArray(ax.zerolinecolor);
        this.zeroLineWidth[i] = ax.zerolinewidth;
    }

    this.reFormatBorderOptions('borderLineEnable');
    this.reFormatBorderOptions('borderLineWidth');
    this.reFormatBorderOptions('borderLineColor');
};

proto.getLabelPad = function(axisName, ax) {
    var offsetBase = 1.5,
        fontSize = ax.titlefont.size,
        showticklabels = ax.showticklabels;

    return {
        xaxis: (ax.side === 'top') ?
            -10 + fontSize * (offsetBase + (showticklabels ? 1 : 0)) :
            -10 + fontSize * (offsetBase + (showticklabels ? 0.5 : 0)),
        yaxis: (ax.side === 'right') ?
            10 + fontSize * (offsetBase + (showticklabels ? 1 : 0.5)) :
            10 + fontSize * (offsetBase + (showticklabels ? 0.5 : 0))
    }[axisName];
};

// TODO ??
proto.getTickPad = function(axisName, ax) {
    return 15;
};

// has an axis in default position (i.e. bottom/left) ?
proto.hasAxisInDfltPos = function(axisName, ax) {
    var axSide = ax.side;

    return {
        xaxis: (axSide === 'bottom'),
        yaxis: (axSide === 'left')
    }[axisName];
};

// has an axis in alternate position (i.e. top/right) ?
proto.hasAxisInAltrPos = function(axisName, ax) {
    var axSide = ax.side;

    return {
        xaxis: (axSide === 'top'),
        yaxis: (axSide === 'right')
    }[axisName];
};

// need to rotate gl-vis border options by 90 degree to be on-par cartesian
proto.reFormatBorderOptions = function(optName) {
    var val = this[optName];
    this[optName] = [ val[1], val[0], val[3], val[2] ];
};

function createAxes2D(scene) {
    return new Axes2DOptions(scene);
}

module.exports = createAxes2D;
<commit_msg>fix tick marks convert logic<commit_after>'use strict';

var htmlToUnicode = require('../../gl3d/lib/html2unicode');
var str2RGBArray = require('../../gl3d/lib/str2rgbarray');

function Axes2DOptions(scene) {
    this.gl = scene.gl;
    this.pixelRatio = scene.pixelRatio;

    this.screenBox = [0, 0, 1, 1];
    this.viewBox = [0 ,0, 1, 1];
    this.dataBox = [-1, -1, 1, 1];

    this.borderLineEnable = [false, false, false, false];
    this.borderLineWidth = [1, 1, 1, 1];
    this.borderLineColor = [
        [0, 0, 0, 1],
        [0, 0, 0, 1],
        [0, 0, 0, 1],
        [0, 0, 0, 1]
    ];

    this.ticks = [[], []];
    this.tickEnable = [true, true, false, false];
    this.tickPad = [15, 15, 15, 15];
    this.tickAngle = [0, 0, 0, 0];
    this.tickColor = [
        [0, 0, 0, 1],
        [0, 0, 0, 1],
        [0, 0, 0, 1],
        [0, 0, 0, 1]
    ];
    this.tickMarkLength = [0, 0, 0, 0];
    this.tickMarkWidth = [0, 0, 0, 0];
    this.tickMarkColor = [
        [0, 0, 0, 1],
        [0, 0, 0, 1],
        [0, 0, 0, 1],
        [0, 0, 0, 1]
    ];

    this.labels = ['x', 'y'];
    this.labelEnable = [true, true, false, false];
    this.labelAngle  = [0, Math.PI/2, 0, 3.0*Math.PI/2];
    this.labelPad = [15, 15, 15, 15];
    this.labelSize = [12, 12];
    this.labelFont = ['sans-serif', 'sans-serif'];
    this.labelColor = [
        [0, 0, 0, 1],
        [0, 0, 0, 1],
        [0, 0, 0, 1],
        [0, 0, 0, 1]
    ];

    this.title = '';
    this.titleEnable = true;
    this.titleCenter = [0, 0, 0, 0];
    this.titleAngle = 0;
    this.titleColor = [0, 0, 0, 1];
    this.titleFont = 'sans-serif';
    this.titleSize = 18;

    this.gridLineEnable = [true, true];
    this.gridLineColor = [
        [0, 0, 0, 0.5],
        [0, 0, 0, 0.5]
    ];
    this.gridLineWidth = [1, 1];

    this.zeroLineEnable = [true, true];
    this.zeroLineWidth = [1, 1];
    this.zeroLineColor = [
        [0, 0, 0, 1],
        [0, 0, 0, 1]
    ];

    this.borderColor = [0, 0, 0, 0];
    this.backgroundColor = [0, 0, 0, 0];
}

var proto = Axes2DOptions.prototype;

var AXES = ['xaxis', 'yaxis'];

proto.merge = function(options) {

    // titles are rendered in SVG
    this.titleEnable = false;
    this.backgroundColor = str2RGBArray(options.plot_bgcolor);

    var axisName, ax, axTitle;
    var hasAxisInDfltPos, hasAxisInAltrPos, mirrorLines, mirrorTicks;
    var i, j;

    for(i = 0; i < 2; ++i) {
        axisName = AXES[i];
        ax = options[axisName];

        axTitle = /Click to enter .+ title/.test(ax.title) ?  '' : ax.title;

        for(j = 0; j <= 2; j += 2) {
            this.labelEnable[i+j] = false;
            this.labels[i+j] = htmlToUnicode(axTitle);
            this.labelColor[i+j] = str2RGBArray(ax.titlefont.color);
            this.labelFont[i+j] = ax.titlefont.family;
            this.labelSize[i+j] = ax.titlefont.size;
            this.labelPad[i+j] = this.getLabelPad(axisName, ax);

            this.tickEnable[i+j] = false;
            this.tickColor[i+j] = str2RGBArray((ax.tickfont || {}).color);
            this.tickAngle[i+j] = (ax.tickangle === 'auto') ? 0 : -ax.tickangle;
            this.tickPad[i+j] = this.getTickPad(axisName, ax);

            this.tickMarkLength[i+j] = 0;
            this.tickMarkWidth[i+j] = ax.tickwidth || 0;
            this.tickMarkColor[i+j] = str2RGBArray(ax.tickcolor);

            this.borderLineEnable[i+j] = false;
            this.borderLineColor[i+j] = str2RGBArray(ax.linecolor);
            this.borderLineWidth[i+j] = ax.linewidth || 0;
        }

        hasAxisInDfltPos = this.hasAxisInDfltPos(axisName, ax);
        hasAxisInAltrPos = this.hasAxisInAltrPos(axisName, ax);
        mirrorLines = (ax.mirror);
        mirrorTicks = (ax.mirror === 'ticks') || (ax.mirror === 'allticks');

        // axis title and tick label can only appear of one side of the scene
        // grid lines and ticks can appear on both sides of the scene

        if(hasAxisInDfltPos) this.labelEnable[i] = true;
        else if(hasAxisInAltrPos) this.labelEnable[i+2] = true;

        if(hasAxisInDfltPos) this.tickEnable[i] = ax.showticklabels;
        else if(hasAxisInAltrPos) this.tickEnable[i+2] = ax.showticklabels;

        if(hasAxisInDfltPos || mirrorLines) this.borderLineEnable[i] = ax.showline;
        if(hasAxisInAltrPos || mirrorLines) this.borderLineEnable[i+2] = ax.showline;

        if(hasAxisInDfltPos || mirrorTicks) this.tickMarkLength[i] = this.getTickMarkLength(ax);
        if(hasAxisInAltrPos || mirrorTicks) this.tickMarkLength[i+2] = this.getTickMarkLength(ax);

        this.gridLineEnable[i] = ax.showgrid;
        this.gridLineColor[i] = str2RGBArray(ax.gridcolor);
        this.gridLineWidth[i] = ax.gridwidth;

        this.zeroLineEnable[i] = ax.zeroline;
        this.zeroLineColor[i] = str2RGBArray(ax.zerolinecolor);
        this.zeroLineWidth[i] = ax.zerolinewidth;
    }

    var optionsToReFormat = [
        'borderLineEnable', 'borderLineWidth', 'borderLineColor',
        'tickMarkLength', 'tickMarkWidth', 'tickMarkColor'
    ];
    for(i = 0; i < optionsToReFormat.length; i++) {
        this.reFormatOption(optionsToReFormat[i]);
    }
};

proto.getLabelPad = function(axisName, ax) {
    var offsetBase = 1.5,
        fontSize = ax.titlefont.size,
        showticklabels = ax.showticklabels;

    return {
        xaxis: (ax.side === 'top') ?
            -10 + fontSize * (offsetBase + (showticklabels ? 1 : 0)) :
            -10 + fontSize * (offsetBase + (showticklabels ? 0.5 : 0)),
        yaxis: (ax.side === 'right') ?
            10 + fontSize * (offsetBase + (showticklabels ? 1 : 0.5)) :
            10 + fontSize * (offsetBase + (showticklabels ? 0.5 : 0))
    }[axisName];
};

// has an axis in default position (i.e. bottom/left) ?
proto.hasAxisInDfltPos = function(axisName, ax) {
    var axSide = ax.side;
    return {
        xaxis: (axSide === 'bottom'),
        yaxis: (axSide === 'left')
    }[axisName];
};

// has an axis in alternate position (i.e. top/right) ?
proto.hasAxisInAltrPos = function(axisName, ax) {
    var axSide = ax.side;
    return {
        xaxis: (axSide === 'top'),
        yaxis: (axSide === 'right')
    }[axisName];
};

// TODO
proto.getTickPad = function() {
    return 15;
};

proto.getTickMarkLength = function(ax) {
    if(!ax.ticks) return 0;

    var ticklen = ax.ticklen;
    return (ax.ticks === 'inside') ? -ticklen : ticklen;
};

// rotate some gl-vis options by 90 degree to be on-par cartesian
proto.reFormatOption = function(optName) {
    var val = this[optName];
    this[optName] = [ val[1], val[0], val[3], val[2] ];
};

function createAxes2D(scene) {
    return new Axes2DOptions(scene);
}

module.exports = createAxes2D;
<|endoftext|>


<commit_before>import React, { useCallback } from 'react';
import { useDocked } from 'openfin-react-hooks';
import { snapAndDock } from 'openfin-layouts';

import './Titlebar.css';

export default () => {
  const isDocked = useDocked();

  const onMinimizeClick = useCallback(async () => {
    const currentWindow = await window.fin.Window.getCurrent();
    currentWindow.minimize();
  }, []);

  const onCloseClick = useCallback(async () => {
    const currentWindow = await window.fin.Window.getCurrent();
    currentWindow.close();
  }, []);

  const onUndockClick = useCallback(async () => {
    await snapAndDock.undockWindow();
  }, []);

  return (

        {isDocked &&

}

  )
}
<commit_msg>Fix issue with close icon not appearing<commit_after>import React, { useCallback } from 'react';
import { useDocked } from 'openfin-react-hooks';
import { snapAndDock } from 'openfin-layouts';

import './Titlebar.css';

export default () => {
  const isDocked = useDocked();

  const onMinimizeClick = useCallback(async () => {
    const currentWindow = await window.fin.Window.getCurrent();
    currentWindow.minimize();
  }, []);

  const onCloseClick = useCallback(async () => {
    const currentWindow = await window.fin.Window.getCurrent();
    currentWindow.close();
  }, []);

  const onUndockClick = useCallback(async () => {
    await snapAndDock.undockWindow();
  }, []);

  return (

        {isDocked &&

}

  )
}
<|endoftext|>


<commit_before>const { apiKey } = require('../config/config.json');
import { weatherIcons } from './weather-icons.constant';

class Weather {

  constructor($http) {
    this.$http = $http;
  }

  getTemperature(searchQuery, countryCode = 'US') {

    const q = `${searchQuery},${countryCode}`;

    return this.$http({
      method: 'GET',
      url: 'http://api.openweathermap.org/data/2.5/weather',
      params: {
        units: 'imperial', // degrees in fahrenheit
        APPID: apiKey, // apiKey from `config.json`
        q, // query string
      }
    })
    .then(({ data }) => data);

  }

  getIcon(info) {
    const code = info.weather[0].id;
    const hour = new Date().getHours();
    let { icon } = weatherIcons[code];
    let dorn = '';

    // If we are not in the ranges mentioned above, add a day/night prefix.
    if (!(code > 699 && code < 800) && !(code > 899 && code < 1000)) {
      dorn = (hour > 6 && hour < 20) ? 'day-' : 'night-';
    }

    return `wi-${dorn}${icon}`;
  }

}

export const WeatherService = [
  '$http',
  Weather
]
<commit_msg>Service: added case for night clear<commit_after>const { apiKey } = require('../config/config.json');
import { weatherIcons } from './weather-icons.constant';

class Weather {

  constructor($http) {
    this.$http = $http;
  }

  getTemperature(searchQuery, countryCode = 'US') {

    const q = `${searchQuery},${countryCode}`;

    return this.$http({
      method: 'GET',
      url: 'http://api.openweathermap.org/data/2.5/weather',
      params: {
        units: 'imperial', // degrees in fahrenheit
        APPID: apiKey, // apiKey from `config.json`
        q, // query string
      }
    })
    .then(({ data }) => data);

  }

  getIcon(info) {
    const code = info.weather[0].id;
    const hour = new Date().getHours();
    let { icon } = weatherIcons[code];
    let dorn = '';

    // If we are not in the ranges mentioned above, add a day/night prefix.
    if (!(code > 699 && code < 800) && !(code > 899 && code < 1000)) {
      dorn = (hour > 6 && hour < 20) ? 'day-' : 'night-';
    }

    // Night edge case
    if (dorn.startsWith('night') && icon.startsWith('sunny')) {
      icon = 'clear';
    }

    return `wi-${dorn}${icon}`;
  }

}

export const WeatherService = [
  '$http',
  Weather
]
<|endoftext|>


<commit_before>var map;
OpenLayers.ProxyHost = "proxy.cgi?url=";

function init() {
    map = new OpenLayers.Map("map");

    var base = new OpenLayers.Layer.WMS("OpenLayers WMS",
        "http://tilecache.osgeo.org/wms-c/Basic.py",
        {layers: "basic"}
    );
    map.addLayer(base);

    // allow testing of specific renderers via "?renderer=Canvas", etc
    var renderer = OpenLayers.Util.getParameters(window.location.href).renderer;
    renderer = (renderer) ? [renderer] : OpenLayers.Layer.Vector.prototype.renderers;

    var wfs = new OpenLayers.Layer.Vector("States", {
        strategies: [new OpenLayers.Strategy.BBOX()],
        protocol: new OpenLayers.Protocol.WFS({
            url: "http://demo.opengeo.org/geoserver/wfs",
            featureType: "states",
            featureNS: "http://www.openplans.org/topp"
        }),
        renderers: renderer
    });
    map.addLayer(wfs);

    map.zoomToExtent(new OpenLayers.Bounds(-140.4, 25.1, -44.4, 50.5));
}
<commit_msg>Updating WMS url.<commit_after>var map;
OpenLayers.ProxyHost = "proxy.cgi?url=";

function init() {
    // allow testing of specific renderers via "?renderer=Canvas", etc
    var renderer = OpenLayers.Util.getParameters(window.location.href).renderer;
    renderer = (renderer) ? [renderer] : OpenLayers.Layer.Vector.prototype.renderers;

    map = new OpenLayers.Map({
        div: "map",
        layers: [
            new OpenLayers.Layer.WMS("OpenLayers WMS",
                "http://vmap0.tiles.osgeo.org/wms/vmap0",
                {layers: "basic"}
            ),
            new OpenLayers.Layer.Vector("States", {
                strategies: [new OpenLayers.Strategy.BBOX()],
                protocol: new OpenLayers.Protocol.WFS({
                    url: "http://demo.opengeo.org/geoserver/wfs",
                    featureType: "states",
                    featureNS: "http://www.openplans.org/topp"
                }),
                renderers: renderer
            })
        ],
        center: [-95.8506355, 37.163851],
        zoom: 3
    });
}
<|endoftext|>


<commit_before>// Underscore-contrib (underscore.array.builders.js 0.0.1)
// (c) 2013 Michael Fogus and DocumentCloud Inc.
// Underscore-contrib may be freely distributed under the MIT license.

(function(root) {

  // Baseline setup
  // --------------

  // Establish the root object, `window` in the browser, or `global` on the server.
  var _ = root._ || require('underscore');

  // Helpers
  // -------

  // Create quick reference variables for speed access to core prototypes.
  var slice   = Array.prototype.slice,
      concat  = Array.prototype.concat;

  // Mixing in the array builders
  // ----------------------------

  _.mixin({
    // Concatenates one or more arrays given as arguments.  If given objects and
    // scalars as arguments `cat` will plop them down in place in the result
    // array.  If given an `arguments` object, `cat` will treat it like an array
    // and concatenate it likewise.
    cat: function() {
      return _.reduce(arguments, function(acc, elem) {
        if (_.isArguments(elem)) {
          return concat.call(acc, slice.call(elem));
        }
        else {
          return concat.call(acc, elem);
        }
      }, []);
    },

    // 'Constructs' an array by putting an element at its front
    cons: function(head, tail) {
      return _.cat([head], tail);
    },

    // Takes an array and parititions it some number of times into
    // sub-arrays of size n.  Allows and optional padding array as
    // the third argument to fill in the tail partition when n is
    // not sufficient to build paritions of the same size.
    partition: function(array, n, pad) {
      var p = function(array) {
        if (array == null) return [];

        var part = _.take(array, n);

        if (n === _.size(part)) {
          return _.cons(part, p(_.drop(array, n)));
        }
        else {
          return pad ? [_.take(_.cat(part, pad), n)] : [];
        }
      };

      return p(array);
    },

    // Takes an array and parititions it some number of times into
    // sub-arrays of size n.  If the array given cannot fill the size
    // needs of the final partition then a smaller partition is used
    // for the last.
    partitionAll: function(array, n, step) {
      step = (step != null) ? step : n;

      var p = function(array, n, step) {
        if (_.isEmpty(array)) return [];

        return _.cons(_.take(array, n),
                      p(_.drop(array, step), n, step));
      };

      return p(array, n, step);
    },

    // Maps a function over an array and concatenates all of the results.
    mapcat: function(array, fun) {
      return _.cat.apply(null, _.map(array, fun));
    },

    // Returns an array with some item between each element
    // of a given array.
    interpose: function(array, inter) {
      if (!_.isArray(array)) throw new TypeError;
      var sz = _.size(array);
      if (sz === 0) return array;
      if (sz === 1) return array;

      return slice(_.mapcat(array, function(elem) {
        return _.cons(elem, [inter]);
      }), 0, -1);
    }

  });

})(this);
<commit_msg>Added first draft of _.interpose<commit_after>// Underscore-contrib (underscore.array.builders.js 0.0.1)
// (c) 2013 Michael Fogus and DocumentCloud Inc.
// Underscore-contrib may be freely distributed under the MIT license.

(function(root) {

  // Baseline setup
  // --------------

  // Establish the root object, `window` in the browser, or `global` on the server.
  var _ = root._ || require('underscore');

  // Helpers
  // -------

  // Create quick reference variables for speed access to core prototypes.
  var slice   = Array.prototype.slice,
      concat  = Array.prototype.concat;

  // Mixing in the array builders
  // ----------------------------

  _.mixin({
    // Concatenates one or more arrays given as arguments.  If given objects and
    // scalars as arguments `cat` will plop them down in place in the result
    // array.  If given an `arguments` object, `cat` will treat it like an array
    // and concatenate it likewise.
    cat: function() {
      return _.reduce(arguments, function(acc, elem) {
        if (_.isArguments(elem)) {
          return concat.call(acc, slice.call(elem));
        }
        else {
          return concat.call(acc, elem);
        }
      }, []);
    },

    // 'Constructs' an array by putting an element at its front
    cons: function(head, tail) {
      return _.cat([head], tail);
    },

    // Takes an array and parititions it some number of times into
    // sub-arrays of size n.  Allows and optional padding array as
    // the third argument to fill in the tail partition when n is
    // not sufficient to build paritions of the same size.
    partition: function(array, n, pad) {
      var p = function(array) {
        if (array == null) return [];

        var part = _.take(array, n);

        if (n === _.size(part)) {
          return _.cons(part, p(_.drop(array, n)));
        }
        else {
          return pad ? [_.take(_.cat(part, pad), n)] : [];
        }
      };

      return p(array);
    },

    // Takes an array and parititions it some number of times into
    // sub-arrays of size n.  If the array given cannot fill the size
    // needs of the final partition then a smaller partition is used
    // for the last.
    partitionAll: function(array, n, step) {
      step = (step != null) ? step : n;

      var p = function(array, n, step) {
        if (_.isEmpty(array)) return [];

        return _.cons(_.take(array, n),
                      p(_.drop(array, step), n, step));
      };

      return p(array, n, step);
    },

    // Maps a function over an array and concatenates all of the results.
    mapcat: function(array, fun) {
      return _.cat.apply(null, _.map(array, fun));
    },

    // Returns an array with some item between each element
    // of a given array.
    interpose: function(array, inter) {
      if (!_.isArray(array)) throw new TypeError;
      var sz = _.size(array);
      if (sz === 0) return array;
      if (sz === 1) return array;

      return slice.call(_.mapcat(array, function(elem) {
        return _.cons(elem, [inter]);
      }), 0, -1);
    }

  });

})(this);
<|endoftext|>


<commit_before>// @flow
import { action, observable, computed, toJS } from 'mobx';
import BigNumber from 'bignumber.js';
import moment from 'moment/moment';
import { ipcRenderer } from 'electron';
import { includes } from 'lodash';
import Store from './lib/Store';
import Request from './lib/LocalizedRequest';
import environment from '../../../common/environment';
import { THEMES } from '../themes/index';
import { ROUTES } from '../routes-config';
import { GET_LOGS, DOWNLOAD_LOGS, COMPRESS_LOGS, DELETE_COMPRESSED_LOGS } from '../../../common/ipc-api';
import LocalizableError from '../i18n/LocalizableError';
import globalMessages from '../i18n/global-messages';
import { WalletSupportRequestLogsCompressError } from '../i18n/errors';
import type { LogFiles, CompressedFileDownload } from '../types/LogTypes';

export default class SettingsStore extends Store {

  LANGUAGE_OPTIONS = [
    { value: 'en-US', label: globalMessages.languageEnglish },
    { value: 'ja-JP', label: globalMessages.languageJapanese },
    // { value: 'zh-CN', label: globalMessages.languageChinese },
    // { value: 'ko-KR', label: globalMessages.languageKorean },
    // { value: 'de-DE', label: globalMessages.languageGerman },
    // { value: 'hr-HR', label: globalMessages.languageCroatian },
  ];

  @observable bigNumberDecimalFormat = {
    decimalSeparator: '.',
    groupSeparator: ',',
    groupSize: 3,
    secondaryGroupSize: 0,
    fractionGroupSeparator: ' ',
    fractionGroupSize: 0
  };

  /* eslint-disable max-len */
  @observable getProfileLocaleRequest: Request<string> = new Request(this.api.localStorage.getUserLocale);
  @observable setProfileLocaleRequest: Request<string> = new Request(this.api.localStorage.setUserLocale);
  @observable getTermsOfUseAcceptanceRequest: Request<string> = new Request(this.api.localStorage.getTermsOfUseAcceptance);
  @observable setTermsOfUseAcceptanceRequest: Request<string> = new Request(this.api.localStorage.setTermsOfUseAcceptance);
  @observable getThemeRequest: Request<string> = new Request(this.api.localStorage.getUserTheme);
  @observable setThemeRequest: Request<string> = new Request(this.api.localStorage.setUserTheme);
  @observable sendBugReport: Request<any> = new Request(this.api[environment.API].sendBugReport);
  @observable error: ?LocalizableError = null;
  @observable logFiles: LogFiles = {};
  @observable compressedLog: ?string = null;
  @observable isCompressing: boolean = false;
  @observable compressedFileDownload: CompressedFileDownload = {};
  /* eslint-enable max-len */

  setup() {
    this.actions.profile.updateLocale.listen(this._updateLocale);
    this.actions.profile.acceptTermsOfUse.listen(this._acceptTermsOfUse);
    this.actions.profile.updateTheme.listen(this._updateTheme);
    this.actions.profile.getLogs.listen(this._getLogs);
    this.actions.profile.resetBugReportDialog.listen(this._resetBugReportDialog);
    this.actions.profile.downloadLogs.listen(this._downloadLogs);
    this.actions.profile.compressLogs.listen(this._compressLogs);
    this.actions.profile.deleteCompressedLogs.listen(this._deleteCompressedFiles);
    this.actions.profile.sendBugReport.listen(this._sendBugReport);
    ipcRenderer.on(GET_LOGS.SUCCESS, this._onGetLogsSuccess);
    ipcRenderer.on(DOWNLOAD_LOGS.SUCCESS, this._onDownloadLogsSuccess);
    ipcRenderer.on(COMPRESS_LOGS.SUCCESS, this._onCompressLogsSuccess);
    ipcRenderer.on(COMPRESS_LOGS.ERROR, this._onCompressLogsError);
    this.registerReactions([
      this._setBigNumberFormat,
      this._updateMomentJsLocaleAfterLocaleChange,
      this._reloadAboutWindowOnLocaleChange,
      this._redirectToLanguageSelectionIfNoLocaleSet,
      this._redirectToTermsOfUseScreenIfTermsNotAccepted,
      this._redirectToMainUiAfterTermsAreAccepted,
    ]);
    this._getTermsOfUseAcceptance();
  }

  teardown() {
    super.teardown();
    ipcRenderer.removeAllListeners(GET_LOGS.SUCCESS);
    ipcRenderer.removeAllListeners(DOWNLOAD_LOGS.SUCCESS);
    ipcRenderer.removeAllListeners(COMPRESS_LOGS.SUCCESS);
    ipcRenderer.removeAllListeners(COMPRESS_LOGS.ERROR);
  }

  _setBigNumberFormat = () => {
    BigNumber.config({ FORMAT: this.bigNumberDecimalFormat });
  };

  @computed get currentLocale(): string {
    const { result } = this.getProfileLocaleRequest.execute();
    if (this.isCurrentLocaleSet) return result;
    return 'en-US'; // default
  }

  @computed get hasLoadedCurrentLocale(): boolean {
    return (
      this.getProfileLocaleRequest.wasExecuted && this.getProfileLocaleRequest.result !== null
    );
  }

  @computed get isCurrentLocaleSet(): boolean {
    return (this.getProfileLocaleRequest.result !== null && this.getProfileLocaleRequest.result !== '');
  }

  @computed get currentTheme(): string {
    const { result } = this.getThemeRequest.execute();
    if (this.isCurrentThemeSet) return result;
    if (environment.isAdaApi()) {
      return environment.isMainnet() ? THEMES.DARK_BLUE : THEMES.LIGHT_BLUE; // defaults
    }
    return THEMES.LIGHT_BLUE; // default for ETC
  }

  @computed get isCurrentThemeSet(): boolean {
    return (this.getThemeRequest.result !== null && this.getThemeRequest.result !== '');
  }

  @computed get hasLoadedCurrentTheme(): boolean {
    return (this.getThemeRequest.wasExecuted && this.getThemeRequest.result !== null);
  }

  @computed get termsOfUse(): string {
    const network = environment.isMainnet() ? 'mainnet' : 'other';
    return require(`../i18n/locales/terms-of-use/${environment.API}/${network}/${this.currentLocale}.md`);
  }

  @computed get hasLoadedTermsOfUseAcceptance(): boolean {
    return (
      this.getTermsOfUseAcceptanceRequest.wasExecuted &&
      this.getTermsOfUseAcceptanceRequest.result !== null
    );
  }

  @computed get areTermsOfUseAccepted(): boolean {
    return this.getTermsOfUseAcceptanceRequest.result === true;
  }

  @computed get isSettingsPage(): boolean {
    const { currentRoute } = this.stores.app;
    return includes(ROUTES.PROFILE, currentRoute) || includes(ROUTES.SETTINGS, currentRoute);
  }

  _updateLocale = async ({ locale }: { locale: string }) => {
    await this.setProfileLocaleRequest.execute(locale);
    await this.getProfileLocaleRequest.execute();
  };

  _updateTheme = async ({ theme }: { theme: string }) => {
    await this.setThemeRequest.execute(theme);
    await this.getThemeRequest.execute();
  };

  _updateMomentJsLocaleAfterLocaleChange = () => {
    moment.locale(this.currentLocale);
  };

  _acceptTermsOfUse = async () => {
    await this.setTermsOfUseAcceptanceRequest.execute();
    await this.getTermsOfUseAcceptanceRequest.execute();
  };

  _getTermsOfUseAcceptance = () => {
    this.getTermsOfUseAcceptanceRequest.execute();
  };

  _redirectToLanguageSelectionIfNoLocaleSet = () => {
    const { isConnected } = this.stores.networkStatus;
    if (isConnected && this.hasLoadedCurrentLocale && !this.isCurrentLocaleSet) {
      this.actions.router.goToRoute.trigger({ route: ROUTES.PROFILE.LANGUAGE_SELECTION });
    }
  };

  _redirectToTermsOfUseScreenIfTermsNotAccepted = () => {
    const { isConnected } = this.stores.networkStatus;
    if (isConnected && this.isCurrentLocaleSet &&
      this.hasLoadedTermsOfUseAcceptance && !this.areTermsOfUseAccepted) {
      this.actions.router.goToRoute.trigger({ route: ROUTES.PROFILE.TERMS_OF_USE });
    }
  };

  _isOnTermsOfUsePage = () => this.stores.app.currentRoute === ROUTES.PROFILE.TERMS_OF_USE;

  _redirectToMainUiAfterTermsAreAccepted = () => {
    if (this.areTermsOfUseAccepted && this._isOnTermsOfUsePage()) {
      this._redirectToRoot();
    }
  };

  _redirectToRoot = () => {
    this.actions.router.goToRoute.trigger({ route: ROUTES.ROOT });
  };

  _reloadAboutWindowOnLocaleChange = () => {
    // register mobx observer for currentLocale in order to trigger reaction on change
    this.currentLocale; // eslint-disable-line
    ipcRenderer.send('reload-about-window');
  };

  _getLogs = () => {
    ipcRenderer.send(GET_LOGS.REQUEST);
  };

  _resetBugReportDialog = () => {
    this._deleteCompressedFiles();
    this._reset();
    this.actions.dialogs.closeActiveDialog.trigger();
  };

  _downloadLogs = action(({ destination, fresh }) => {
    this.compressedFileDownload = {
      inProgress: true,
      destination,
    };

    if (this.compressedLog && fresh !== true) {
      // logs already compressed, trigger download
      ipcRenderer.send(DOWNLOAD_LOGS.REQUEST, this.compressedLog, destination);
    } else {
      // start process: getLogs -> compressLogs -> downloadLogs (again)
      this._getLogs();
    }
  });

  _onGetLogsSuccess = action((event, res) => {
    this.logFiles = res;
    if (this.compressedFileDownload.inProgress) {
      this._compressLogs({ logs: res });
    }
  });

  _onDownloadLogsSuccess = action(() => {
    this.compressedFileDownload = {};
  });

  _compressLogs = action(({ logs }) => {
    this.isCompressing = true;
    ipcRenderer.send(COMPRESS_LOGS.REQUEST, toJS(logs));
  });

  _onCompressLogsSuccess = action((event, res) => {
    this.isCompressing = false;
    this.compressedLog = res;
    if (this.compressedFileDownload.inProgress) {
      this._downloadLogs({ destination: this.compressedFileDownload.destination });
    }
  });

  _onCompressLogsError = action(() => {
    this.error = new WalletSupportRequestLogsCompressError();
  });

  _sendBugReport = action(({ email, subject, problem, compressedLog } : {
    email: string,
    subject: string,
    problem: string,
    compressedLog: ?string,
  }) => {
    this.sendBugReport.execute({
      email, subject, problem, compressedLog,
    })
      .then(action(() => {
        this._resetBugReportDialog();
      }))
      .catch(action((error) => {
        this.error = error;
      }));
  });

  _deleteCompressedFiles = action(() => {
    if (this.compressedLog) {
      ipcRenderer.send(DELETE_COMPRESSED_LOGS.REQUEST, this.compressedLog);
      this.compressedLog = null;
    }
  });

  @action _reset = () => {
    this.error = null;
    this.compressedLog = null;
    this.compressedFileDownload = {};
  };
}
<commit_msg>[DDW-81] minor refactoring<commit_after>// @flow
import { action, observable, computed, toJS } from 'mobx';
import BigNumber from 'bignumber.js';
import moment from 'moment/moment';
import { ipcRenderer } from 'electron';
import { includes } from 'lodash';
import Store from './lib/Store';
import Request from './lib/LocalizedRequest';
import environment from '../../../common/environment';
import { THEMES } from '../themes/index';
import { ROUTES } from '../routes-config';
import { GET_LOGS, DOWNLOAD_LOGS, COMPRESS_LOGS, DELETE_COMPRESSED_LOGS } from '../../../common/ipc-api';
import LocalizableError from '../i18n/LocalizableError';
import globalMessages from '../i18n/global-messages';
import { WalletSupportRequestLogsCompressError } from '../i18n/errors';
import type { LogFiles, CompressedFileDownload } from '../types/LogTypes';

export default class SettingsStore extends Store {

  LANGUAGE_OPTIONS = [
    { value: 'en-US', label: globalMessages.languageEnglish },
    { value: 'ja-JP', label: globalMessages.languageJapanese },
    // { value: 'zh-CN', label: globalMessages.languageChinese },
    // { value: 'ko-KR', label: globalMessages.languageKorean },
    // { value: 'de-DE', label: globalMessages.languageGerman },
    // { value: 'hr-HR', label: globalMessages.languageCroatian },
  ];

  @observable bigNumberDecimalFormat = {
    decimalSeparator: '.',
    groupSeparator: ',',
    groupSize: 3,
    secondaryGroupSize: 0,
    fractionGroupSeparator: ' ',
    fractionGroupSize: 0
  };

  /* eslint-disable max-len */
  @observable getProfileLocaleRequest: Request<string> = new Request(this.api.localStorage.getUserLocale);
  @observable setProfileLocaleRequest: Request<string> = new Request(this.api.localStorage.setUserLocale);
  @observable getTermsOfUseAcceptanceRequest: Request<string> = new Request(this.api.localStorage.getTermsOfUseAcceptance);
  @observable setTermsOfUseAcceptanceRequest: Request<string> = new Request(this.api.localStorage.setTermsOfUseAcceptance);
  @observable getThemeRequest: Request<string> = new Request(this.api.localStorage.getUserTheme);
  @observable setThemeRequest: Request<string> = new Request(this.api.localStorage.setUserTheme);
  @observable sendBugReport: Request<any> = new Request(this.api[environment.API].sendBugReport);
  @observable error: ?LocalizableError = null;
  @observable logFiles: LogFiles = {};
  @observable compressedLog: ?string = null;
  @observable isCompressing: boolean = false;
  @observable compressedFileDownload: CompressedFileDownload = {};
  /* eslint-enable max-len */

  setup() {
    this.actions.profile.updateLocale.listen(this._updateLocale);
    this.actions.profile.acceptTermsOfUse.listen(this._acceptTermsOfUse);
    this.actions.profile.updateTheme.listen(this._updateTheme);
    this.actions.profile.getLogs.listen(this._getLogs);
    this.actions.profile.resetBugReportDialog.listen(this._resetBugReportDialog);
    this.actions.profile.downloadLogs.listen(this._downloadLogs);
    this.actions.profile.compressLogs.listen(this._compressLogs);
    this.actions.profile.deleteCompressedLogs.listen(this._deleteCompressedFiles);
    this.actions.profile.sendBugReport.listen(this._sendBugReport);
    ipcRenderer.on(GET_LOGS.SUCCESS, this._onGetLogsSuccess);
    ipcRenderer.on(DOWNLOAD_LOGS.SUCCESS, this._onDownloadLogsSuccess);
    ipcRenderer.on(COMPRESS_LOGS.SUCCESS, this._onCompressLogsSuccess);
    ipcRenderer.on(COMPRESS_LOGS.ERROR, this._onCompressLogsError);
    this.registerReactions([
      this._setBigNumberFormat,
      this._updateMomentJsLocaleAfterLocaleChange,
      this._reloadAboutWindowOnLocaleChange,
      this._redirectToLanguageSelectionIfNoLocaleSet,
      this._redirectToTermsOfUseScreenIfTermsNotAccepted,
      this._redirectToMainUiAfterTermsAreAccepted,
    ]);
    this._getTermsOfUseAcceptance();
  }

  teardown() {
    super.teardown();
    ipcRenderer.removeAllListeners(GET_LOGS.SUCCESS);
    ipcRenderer.removeAllListeners(DOWNLOAD_LOGS.SUCCESS);
    ipcRenderer.removeAllListeners(COMPRESS_LOGS.SUCCESS);
    ipcRenderer.removeAllListeners(COMPRESS_LOGS.ERROR);
  }

  _setBigNumberFormat = () => {
    BigNumber.config({ FORMAT: this.bigNumberDecimalFormat });
  };

  @computed get currentLocale(): string {
    const { result } = this.getProfileLocaleRequest.execute();
    if (this.isCurrentLocaleSet) return result;
    return 'en-US'; // default
  }

  @computed get hasLoadedCurrentLocale(): boolean {
    return (
      this.getProfileLocaleRequest.wasExecuted && this.getProfileLocaleRequest.result !== null
    );
  }

  @computed get isCurrentLocaleSet(): boolean {
    return (this.getProfileLocaleRequest.result !== null && this.getProfileLocaleRequest.result !== '');
  }

  @computed get currentTheme(): string {
    const { result } = this.getThemeRequest.execute();
    if (this.isCurrentThemeSet) return result;
    if (environment.isAdaApi()) {
      return environment.isMainnet() ? THEMES.DARK_BLUE : THEMES.LIGHT_BLUE; // defaults
    }
    return THEMES.LIGHT_BLUE; // default for ETC
  }

  @computed get isCurrentThemeSet(): boolean {
    return (this.getThemeRequest.result !== null && this.getThemeRequest.result !== '');
  }

  @computed get hasLoadedCurrentTheme(): boolean {
    return (this.getThemeRequest.wasExecuted && this.getThemeRequest.result !== null);
  }

  @computed get termsOfUse(): string {
    const network = environment.isMainnet() ? 'mainnet' : 'other';
    return require(`../i18n/locales/terms-of-use/${environment.API}/${network}/${this.currentLocale}.md`);
  }

  @computed get hasLoadedTermsOfUseAcceptance(): boolean {
    return (
      this.getTermsOfUseAcceptanceRequest.wasExecuted &&
      this.getTermsOfUseAcceptanceRequest.result !== null
    );
  }

  @computed get areTermsOfUseAccepted(): boolean {
    return this.getTermsOfUseAcceptanceRequest.result === true;
  }

  @computed get isSettingsPage(): boolean {
    const { currentRoute } = this.stores.app;
    return includes(ROUTES.PROFILE, currentRoute) || includes(ROUTES.SETTINGS, currentRoute);
  }

  _updateLocale = async ({ locale }: { locale: string }) => {
    await this.setProfileLocaleRequest.execute(locale);
    await this.getProfileLocaleRequest.execute();
  };

  _updateTheme = async ({ theme }: { theme: string }) => {
    await this.setThemeRequest.execute(theme);
    await this.getThemeRequest.execute();
  };

  _updateMomentJsLocaleAfterLocaleChange = () => {
    moment.locale(this.currentLocale);
  };

  _acceptTermsOfUse = async () => {
    await this.setTermsOfUseAcceptanceRequest.execute();
    await this.getTermsOfUseAcceptanceRequest.execute();
  };

  _getTermsOfUseAcceptance = () => {
    this.getTermsOfUseAcceptanceRequest.execute();
  };

  _redirectToLanguageSelectionIfNoLocaleSet = () => {
    const { isConnected } = this.stores.networkStatus;
    if (isConnected && this.hasLoadedCurrentLocale && !this.isCurrentLocaleSet) {
      this.actions.router.goToRoute.trigger({ route: ROUTES.PROFILE.LANGUAGE_SELECTION });
    }
  };

  _redirectToTermsOfUseScreenIfTermsNotAccepted = () => {
    const { isConnected } = this.stores.networkStatus;
    const termsOfUseNotAccepted = this.hasLoadedTermsOfUseAcceptance && !this.areTermsOfUseAccepted;
    if (isConnected && this.isCurrentLocaleSet && termsOfUseNotAccepted) {
      this.actions.router.goToRoute.trigger({ route: ROUTES.PROFILE.TERMS_OF_USE });
    }
  };

  _isOnTermsOfUsePage = () => this.stores.app.currentRoute === ROUTES.PROFILE.TERMS_OF_USE;

  _redirectToMainUiAfterTermsAreAccepted = () => {
    if (this.areTermsOfUseAccepted && this._isOnTermsOfUsePage()) {
      this._redirectToRoot();
    }
  };

  _redirectToRoot = () => {
    this.actions.router.goToRoute.trigger({ route: ROUTES.ROOT });
  };

  _reloadAboutWindowOnLocaleChange = () => {
    // register mobx observer for currentLocale in order to trigger reaction on change
    this.currentLocale; // eslint-disable-line
    ipcRenderer.send('reload-about-window');
  };

  _getLogs = () => {
    ipcRenderer.send(GET_LOGS.REQUEST);
  };

  _resetBugReportDialog = () => {
    this._deleteCompressedFiles();
    this._reset();
    this.actions.dialogs.closeActiveDialog.trigger();
  };

  _downloadLogs = action(({ destination, fresh }) => {
    this.compressedFileDownload = {
      inProgress: true,
      destination,
    };

    if (this.compressedLog && fresh !== true) {
      // logs already compressed, trigger download
      ipcRenderer.send(DOWNLOAD_LOGS.REQUEST, this.compressedLog, destination);
    } else {
      // start process: getLogs -> compressLogs -> downloadLogs (again)
      this._getLogs();
    }
  });

  _onGetLogsSuccess = action((event, res) => {
    this.logFiles = res;
    if (this.compressedFileDownload.inProgress) {
      this._compressLogs({ logs: res });
    }
  });

  _onDownloadLogsSuccess = action(() => {
    this.compressedFileDownload = {};
  });

  _compressLogs = action(({ logs }) => {
    this.isCompressing = true;
    ipcRenderer.send(COMPRESS_LOGS.REQUEST, toJS(logs));
  });

  _onCompressLogsSuccess = action((event, res) => {
    this.isCompressing = false;
    this.compressedLog = res;
    if (this.compressedFileDownload.inProgress) {
      this._downloadLogs({ destination: this.compressedFileDownload.destination });
    }
  });

  _onCompressLogsError = action(() => {
    this.error = new WalletSupportRequestLogsCompressError();
  });

  _sendBugReport = action(({ email, subject, problem, compressedLog } : {
    email: string,
    subject: string,
    problem: string,
    compressedLog: ?string,
  }) => {
    this.sendBugReport.execute({
      email, subject, problem, compressedLog,
    })
      .then(action(() => {
        this._resetBugReportDialog();
      }))
      .catch(action((error) => {
        this.error = error;
      }));
  });

  _deleteCompressedFiles = action(() => {
    if (this.compressedLog) {
      ipcRenderer.send(DELETE_COMPRESSED_LOGS.REQUEST, this.compressedLog);
      this.compressedLog = null;
    }
  });

  @action _reset = () => {
    this.error = null;
    this.compressedLog = null;
    this.compressedFileDownload = {};
  };
}
<|endoftext|>