From b415ee086fdae54a9680c4c80e8eabb4d7b8f7b8 Mon Sep 17 00:00:00 2001 From: Scritches Date: Wed, 18 Apr 2018 00:26:05 -0400 Subject: [PATCH 1/2] Add OEIS module ## Queries the **Online Encyclopedia of Integer Sequences** for interesting number sequences. #### Sequence by example: ``` ~sequence 1 2 3 4 5 ``` #### Sequence by ID number ``` ~sequence a27 ``` #### Sequence by keywords ``` ~sequence positive integers ``` In all cases the following is returned: ``` [oeis] A000027: "The positive integers." - (1, 2, 3, 4, 5, 6, 7, 8, ...) https://oeis.org/A000027 ``` --- modules/oeis/config.json | 3 + modules/oeis/oeis.js | 114 ++++++++++++++++++++++++++++++++++++++ modules/oeis/strings.json | 11 ++++ 3 files changed, 128 insertions(+) create mode 100644 modules/oeis/config.json create mode 100644 modules/oeis/oeis.js create mode 100644 modules/oeis/strings.json diff --git a/modules/oeis/config.json b/modules/oeis/config.json new file mode 100644 index 0000000..5a951d2 --- /dev/null +++ b/modules/oeis/config.json @@ -0,0 +1,3 @@ +{ + "outputPrefix": "\u00033oeis\u000f" +} diff --git a/modules/oeis/oeis.js b/modules/oeis/oeis.js new file mode 100644 index 0000000..7a23fdf --- /dev/null +++ b/modules/oeis/oeis.js @@ -0,0 +1,114 @@ +/** + * Module Name: oeis + * Description: Interacts with the Online Encyclopedia of Integer Sequences + * API to provide integer sequence lookups and related information + */ + +var rp = require('request-promise-native'); + +var OEIS = function(dbot) { + this.apiRoot = 'https://oeis.org/search'; + this.webRoot = 'https://oeis.org/'; + + this.internalAPI = { + 'parseResult': result => { + return { + a: result.number, + a6: 'A' + result.number.toString().padStart(6, '0'), + name: result.name.slice(0, result.name.indexOf('.') + 1), + sample: result.data.split(',').slice(0, 8), + more: result.data.length > 8, + url: this.webRoot + 'A' + result.number.toString().padStart(6, '0') + }; + }, + + 'outputError': (event, e) => { + switch(e) { + case 'no-results': event.reply(dbot.t('sequence_not_found')); return; + } + + console.log(e); + event.reply(dbot.t('oeis_error')); + } + }; + + this.api = { + 'lookupSequenceByKeywords': async keywords => { + var body = await rp({ + url: this.apiRoot, + qs: { + fmt: 'json', + q: '"' + keywords + '"' + }, + json: true + }); + + if(!body.results) throw 'no-results'; + return this.internalAPI.parseResult(body.results[0]); + }, + + 'lookupSequenceByExample': async (terms, inOrder) => { + var joinChar = inOrder ? ',' : ' '; + var body = await rp({ + url: this.apiRoot, + qs: { + fmt: 'json', + q: terms.join(joinChar) + }, + json: true + }); + + if(!body.results) throw 'no-results'; + return this.internalAPI.parseResult(body.results[0]); + }, + + 'lookupSequenceByA': async a => { + var body = await rp({ + url: this.apiRoot, + qs: { + fmt: 'json', + q: 'A' + a.toString().padStart(6, '0') + }, + json: true + }); + + if(!body.results) throw 'no-results'; + return this.internalAPI.parseResult(body.results[0]); + } + }; + + this.commands = { + '~sequence': async event => { + var result; + + try { + if (event.input[1]) { + // digit sequence + var terms = event.params.slice(1); + result = await this.api.lookupSequenceByExample(terms, true); + } else if (event.input[2]) { + // A-number + var a = event.input[2]; + result = await this.api.lookupSequenceByA(a); + } else { + // Keyword search + var keywords = event.params.slice(1).join(' '); + result = await this.api.lookupSequenceByKeywords(keywords); + } + } + catch(e) { + this.internalAPI.outputError(event, e); + return; + } + + result.sample = result.sample.join(', '); + if (result.more) result.sample += ', ...'; + + event.reply(dbot.t('output_sequence', result)); + } + } + + this.commands['~sequence'].regex = [/^sequence ((?:-?\d\s?)+)|A((?:\d)+)|([\D\s]*)$/i, 4]; +} + +exports.fetch = dbot => new OEIS(dbot); \ No newline at end of file diff --git a/modules/oeis/strings.json b/modules/oeis/strings.json new file mode 100644 index 0000000..8e489bd --- /dev/null +++ b/modules/oeis/strings.json @@ -0,0 +1,11 @@ +{ + "output_sequence": { + "en": "{a6}: \"{name}\" - ({sample}) {url}" + }, + "sequence_not_found": { + "en": "The sequence could not be identified." + }, + "oeis_error": { + "en": "Error communicating with the OEIS database." + } +} \ No newline at end of file From f7b83e98b7aadf568b2961e371c96d9c506ead21 Mon Sep 17 00:00:00 2001 From: Scritches Date: Wed, 18 Apr 2018 00:50:22 -0400 Subject: [PATCH 2/2] support for random sequences --- modules/oeis/oeis.js | 42 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/modules/oeis/oeis.js b/modules/oeis/oeis.js index 7a23fdf..8debcc7 100644 --- a/modules/oeis/oeis.js +++ b/modules/oeis/oeis.js @@ -74,6 +74,28 @@ var OEIS = function(dbot) { if(!body.results) throw 'no-results'; return this.internalAPI.parseResult(body.results[0]); + }, + + 'getRandomSequenceA': async set => { + // This feature uses OEIS's 'webcam' which serves up random entries + // each time the page is refreshed. It appears to be the only way to get + // valid random entries from the database. The alternative is to just generate + // random A-numbers from the set of all A-numbers, but that seems dirty to me. + var body = await rp({ + url: this.webRoot + '/webcam', + qs: { + fromjavascript: 1, + q: 'keyword:' + set + } + }); + + // Find where the A-number is located + var i = body.indexOf('