@ -0,0 +1,10 @@ | |||
*/node_modules | |||
.gitsecret/keys/random_seed | |||
!*.secret | |||
.keys | |||
xi_tracker/config.json | |||
xi_music/config.json | |||
xi_music/commands/secrets.json | |||
xi_comic/config.json | |||
xi_news/config.json | |||
init_db.sql |
@ -1 +0,0 @@ | |||
4061bfee1f8bf7ebbca3e333ec8581d6be602270 |
@ -1 +0,0 @@ | |||
4cd1427e35ec41e32dde2f395bd2292dd6051083 |
@ -1 +0,0 @@ | |||
3a4903efb68cb10057d70a224d4733bd0bdc56e3 |
@ -1 +0,0 @@ | |||
f6aabe81009919d25685b217dc9595d299b3cad9 |
@ -0,0 +1,6 @@ | |||
init_db.sql:bb32c3ee705a5a16e99e50eac4f86ec1e2f0efef1f9fb998facc67d124413701 | |||
xi_comic/config.json:24c8698513b2f855744e2410997c9f2eb68aeefb74ad274106f864760124a13b | |||
xi_music/config.json:ce1527843326f34840ee04a12c3c49ade15d0005fc0db9aa4000298ca99ca62d | |||
xi_tracker/config.json:b7610c60037babef2858c1dbba1b87e1fec0014d79e75889d4c55565055d5ce0 | |||
xi_music/commands/secrets.json:12f928314c51e905c3ef74fc5c15914908151f0d73d7c337493b8413701fc172 | |||
xi_news/config.json:e883fb5c1b71d938bca202c5731a77bce4296ab4076ede59b4e15fb61377e37a |
@ -1 +0,0 @@ | |||
9607cf402ec246f9a4baa64027e1cb1eaac35f06 |
@ -0,0 +1,2 @@ | |||
# xi-bots | |||
A group of bots to use in our private discord server. |
@ -1 +0,0 @@ | |||
c49e104ab5d78bf11d51e12583ed1e8bdf5e7add |
@ -0,0 +1,23 @@ | |||
version: "3.7" | |||
services: | |||
xi_music: | |||
build: | |||
context: ./xi_music | |||
dockerfile: Dockerfile | |||
container_name: xi_music_bot | |||
image: fr1nge/xi_music:latest | |||
xi_comic: | |||
build: | |||
context: ./xi_comic | |||
dockerfile: Dockerfile | |||
container_name: xi_comic_bot | |||
image: fr1nge/xi_comic:latest | |||
xi_ranker: | |||
build: | |||
context: ./xi_ranker | |||
dockerfile: Dockerfile | |||
container_name: xi_ranker_bot | |||
image: fr1nge/xi_ranker:latest | |||
@ -1 +0,0 @@ | |||
088bca44a4ac179bf61d0c242e2a954dcec005c0 |
@ -0,0 +1 @@ | |||
node_modules |
@ -0,0 +1,15 @@ | |||
FROM node:lts | |||
WORKDIR /usr/src/app | |||
COPY package*.json ./ | |||
RUN npm ci | |||
# If you are building your code for production | |||
# # RUN npm ci --only=production | |||
COPY . . | |||
CMD [ "node", "main.js" ] | |||
@ -0,0 +1,16 @@ | |||
const xkcd = require('xkcd-api'); | |||
module.exports = { | |||
name: 'comic', | |||
description: 'Send a random xkcd comic.', | |||
execute(message) { | |||
var message = message; | |||
xkcd.random(function(error, response) { | |||
if (error) { | |||
console.error(error); | |||
} else { | |||
message.channel.send(`**${response.safe_title}**\n*${response.alt}*`, {files: [response.img]}) | |||
} | |||
}); | |||
}, | |||
}; |
@ -0,0 +1,21 @@ | |||
const xkcd = require('xkcd-api'); | |||
module.exports = { | |||
name: 'hail_mary', | |||
description: 'Fuck everyone\'s chat up by sneding a random number of comics between 0-3.', | |||
roles: ['732345527143759943'], | |||
execute(message) { | |||
var message = message; | |||
message.channel.send("Initiating comic hail mary!") | |||
for(i = 0; i < Math.floor(Math.random() * (30 - 0) + 0); i++){ | |||
xkcd.random(function(error, response) { | |||
if (error) { | |||
console.error(error); | |||
} else { | |||
message.channel.send(`**${response.safe_title}**\n*${response.alt}*`, {files: [response.img]}) | |||
} | |||
}); | |||
} | |||
}, | |||
}; |
@ -0,0 +1,66 @@ | |||
const fs = require('fs') | |||
const Discord = require('discord.js'); | |||
const { Client, Collection } = require('discord.js'); | |||
const { | |||
prefix, | |||
token, | |||
} = require('./config.json'); | |||
const client = new Client(); | |||
client.commands = new Discord.Collection(); | |||
const commandFiles = fs.readdirSync('./commands').filter(file => file.endsWith('.js')); | |||
for (const file of commandFiles) { | |||
const command = require(`./commands/${file}`); | |||
client.commands.set(command.name, command); | |||
} | |||
console.log(client.commands); | |||
client.once('ready', () => { | |||
console.log('Ready!'); | |||
}); | |||
client.once('reconnecting', () => { | |||
console.log('Reconnecting!'); | |||
}); | |||
client.once('disconnect', () => { | |||
console.log('Disconnect!'); | |||
}); | |||
client.on('message', async message => { | |||
if (message.author.bot) return; | |||
if (!message.content.startsWith(prefix)) return; | |||
const args = message.content.slice(prefix.length).split(/ +/); | |||
const commandName = args.shift().toLowerCase(); | |||
if (!client.commands.has(commandName)) return; | |||
const command = client.commands.get(commandName); | |||
const permitted_roles = client.commands.get(commandName)["roles"]; | |||
has_roles = false | |||
if (permitted_roles){ | |||
for(i = 0; i < permitted_roles.length; i++){ | |||
if(message.member.roles.cache.has(permitted_roles[i])){ | |||
has_roles = true | |||
} | |||
} | |||
if (!has_roles && permitted_roles.length != 0){ | |||
message.reply('You are not allowed to run this command!'); | |||
return; | |||
} | |||
} | |||
try { | |||
command.execute(message); | |||
} catch (error) { | |||
console.error(error); | |||
message.reply('There was an error trying to execute that command!'); | |||
} | |||
}); | |||
client.login(token); |
@ -0,0 +1,15 @@ | |||
{ | |||
"name": "xi_master", | |||
"version": "1.0.0", | |||
"description": "A master music bot for our xi network discord server", | |||
"author": "Fringe <yigit@yigitcolakoglu.com>", | |||
"main": "main.js", | |||
"scripts": { | |||
"start": "node main.js" | |||
}, | |||
"dependencies": { | |||
"discord.js": "^12.2.0", | |||
"sqlite3": "^5.0.0", | |||
"xkcd-api": "^1.2.0" | |||
} | |||
} |
@ -0,0 +1,2 @@ | |||
node_modules | |||
npm-debug.log |
@ -0,0 +1 @@ | |||
node_modules |
@ -0,0 +1,18 @@ | |||
FROM node:lts | |||
RUN apt-get update || : && apt-get install python -y | |||
RUN apt-get install ffmpeg -y | |||
WORKDIR /usr/src/app | |||
COPY package*.json ./ | |||
RUN npm ci | |||
# If you are building your code for production | |||
# # RUN npm ci --only=production | |||
COPY . . | |||
CMD [ "node", "main.js" ] | |||
@ -0,0 +1,16 @@ | |||
const { Client, Collection } = require('discord.js'); | |||
module.exports = class extends Client { | |||
constructor(config) { | |||
super({ | |||
disableEveryone: true, | |||
disabledEvents: ['TYPING_START'], | |||
}); | |||
this.commands = new Collection(); | |||
this.queue = new Map(); | |||
this.config = config; | |||
} | |||
}; |
@ -0,0 +1,71 @@ | |||
const ytdl = require("ytdl-core"); | |||
module.exports = { | |||
name: 'malatya', | |||
description: 'SWAT', | |||
roles: ['732345527143759943'], | |||
async execute(message){ | |||
const queue = message.client.queue; | |||
const serverQueue = message.client.queue.get(message.guild.id); | |||
const voiceChannel = message.member.voice.channel; | |||
if (!voiceChannel) | |||
return message.channel.send( | |||
"You need to be in a voice channel to SWAT!" | |||
); | |||
if(serverQueue){ | |||
while(serverQueue.songs[0]){ | |||
serverQueue.songs.shift(); | |||
} | |||
serverQueue.songs.push({}); | |||
serverQueue.songs.push({title: "MALATYA", url: "https://www.youtube.com/watch?v=qyczHCg2zhw"}); | |||
serverQueue.connection.dispatcher.end(); | |||
}else{ | |||
const queueContruct = { | |||
textChannel: message.channel, | |||
voiceChannel: voiceChannel, | |||
connection: null, | |||
songs: [], | |||
volume: 5, | |||
playing: true | |||
}; | |||
queue.set(message.guild.id, queueContruct); | |||
queueContruct.songs.push({title: "MALATYA", url: "https://www.youtube.com/watch?v=qyczHCg2zhw"}); | |||
try { | |||
var connection = await voiceChannel.join(); | |||
queueContruct.connection = connection; | |||
this.play(message, queueContruct.songs[0]); | |||
} catch (err) { | |||
console.log(err); | |||
queue.delete(message.guild.id); | |||
return message.channel.send(err); | |||
} | |||
} | |||
}, | |||
play(message, song) { | |||
const queue = message.client.queue; | |||
const guild = message.guild; | |||
const serverQueue = queue.get(message.guild.id); | |||
if (!song) { | |||
serverQueue.voiceChannel.leave(); | |||
queue.delete(guild.id); | |||
return; | |||
} | |||
const dispatcher = serverQueue.connection | |||
.play(ytdl(song.url, { filter: 'audioonly', highWaterMark: 1024 * 1024 * 10 })) | |||
.on("finish", () => { | |||
serverQueue.songs.shift(); | |||
this.play(message, serverQueue.songs[0]); | |||
}) | |||
.on("error", error => console.error(error)); | |||
dispatcher.setVolumeLogarithmic(serverQueue.volume / 5); | |||
serverQueue.textChannel.send(`Start playing: **${song.title}**`); | |||
}, | |||
}; |
@ -0,0 +1,9 @@ | |||
module.exports = { | |||
name: 'nowplaying', | |||
description: 'Get the song that is playing.', | |||
execute(message) { | |||
const serverQueue = message.client.queue.get(message.guild.id); | |||
if (!serverQueue) return message.channel.send('There is nothing playing.'); | |||
return message.channel.send(`Now playing: ${serverQueue.songs[0].title}`); | |||
}, | |||
}; |
@ -0,0 +1,88 @@ | |||
const ytdl = require("ytdl-core"); | |||
module.exports = { | |||
name: "play", | |||
description: "Play a song in your channel!", | |||
roles: ['732550362199752764', '732345527143759943'], | |||
async execute(message) { | |||
try { | |||
const args = message.content.split(" "); | |||
const queue = message.client.queue; | |||
const serverQueue = message.client.queue.get(message.guild.id); | |||
const voiceChannel = message.member.voice.channel; | |||
if (!voiceChannel) | |||
return message.channel.send( | |||
"You need to be in a voice channel to play music!" | |||
); | |||
const permissions = voiceChannel.permissionsFor(message.client.user); | |||
if (!permissions.has("CONNECT") || !permissions.has("SPEAK")) { | |||
return message.channel.send( | |||
"I need the permissions to join and speak in your voice channel!" | |||
); | |||
} | |||
const songInfo = await ytdl.getInfo(args[1]); | |||
const song = { | |||
title: songInfo.videoDetails.title, | |||
url: songInfo.videoDetails.video_url | |||
}; | |||
if (!serverQueue) { | |||
const queueContruct = { | |||
textChannel: message.channel, | |||
voiceChannel: voiceChannel, | |||
connection: null, | |||
songs: [], | |||
volume: 5, | |||
playing: true | |||
}; | |||
queue.set(message.guild.id, queueContruct); | |||
queueContruct.songs.push(song); | |||
try { | |||
var connection = await voiceChannel.join(); | |||
queueContruct.connection = connection; | |||
this.play(message, queueContruct.songs[0]); | |||
} catch (err) { | |||
console.log(err); | |||
queue.delete(message.guild.id); | |||
return message.channel.send(err); | |||
} | |||
} else { | |||
serverQueue.songs.push(song); | |||
return message.channel.send( | |||
`${song.title} has been added to the queue!` | |||
); | |||
} | |||
} catch (error) { | |||
console.log(error); | |||
message.channel.send(error.message); | |||
} | |||
}, | |||
play(message, song) { | |||
const queue = message.client.queue; | |||
const guild = message.guild; | |||
const serverQueue = queue.get(message.guild.id); | |||
if (!song) { | |||
serverQueue.voiceChannel.leave(); | |||
queue.delete(guild.id); | |||
return; | |||
} | |||
const dispatcher = serverQueue.connection | |||
.play(ytdl(song.url, { filter: 'audioonly', highWaterMark: 1024 * 1024 * 10 })) | |||
.on("finish", () => { | |||
serverQueue.songs.shift(); | |||
this.play(message, serverQueue.songs[0]); | |||
}) | |||
.on("error", error => console.error(error)); | |||
dispatcher.setVolumeLogarithmic(serverQueue.volume / 5); | |||
serverQueue.textChannel.send(`Start playing: **${song.title}**`); | |||
} | |||
}; |
@ -0,0 +1,117 @@ | |||
const { google } = require('googleapis'); | |||
const youtube = google.youtube('v3'); | |||
const secrets = require('./secrets.json'); | |||
const ytdl = require("ytdl-core"); | |||
module.exports = { | |||
name: 'playlist', | |||
description: 'Add playlist to the queue.', | |||
roles: ['732550362199752764', '732345527143759943'], | |||
async execute(message) { | |||
var message = message; | |||
const args = message.content.split(" "); | |||
try{ | |||
let playlist_id = args[1].match(/https:\/\/www\.youtube\.com\/watch\?.*list=(.{34}).*/)[1] | |||
youtube.playlistItems.list({ | |||
key: secrets.web.api_key, | |||
part: 'snippet, contentDetails', | |||
playlistId: playlist_id, | |||
maxResults: 50, | |||
}, async (err, results) => { | |||
try { | |||
const queue = message.client.queue; | |||
const serverQueue = message.client.queue.get(message.guild.id); | |||
const voiceChannel = message.member.voice.channel; | |||
if (!voiceChannel) | |||
return message.channel.send( | |||
"You need to be in a voice channel to play music!" | |||
); | |||
const permissions = voiceChannel.permissionsFor(message.client.user); | |||
if (!permissions.has("CONNECT") || !permissions.has("SPEAK")) { | |||
return message.channel.send( | |||
"I need the permissions to join and speak in your voice channel!" | |||
); | |||
} | |||
if (!serverQueue) { | |||
const queueContruct = { | |||
textChannel: message.channel, | |||
voiceChannel: voiceChannel, | |||
connection: null, | |||
songs: [], | |||
volume: 5, | |||
playing: true | |||
}; | |||
queue.set(message.guild.id, queueContruct); | |||
results.data.items.forEach(function(item, index){ | |||
url = "https://www.youtube.com/watch?v=" + item.contentDetails.videoId | |||
let song = { | |||
title: item.snippet.title, | |||
url: url | |||
}; | |||
queueContruct.songs.push(song); | |||
}); | |||
try { | |||
var connection = await voiceChannel.join(); | |||
queueContruct.connection = connection; | |||
this.play(message, queueContruct.songs[0]); | |||
} catch (err) { | |||
console.log(err); | |||
queue.delete(message.guild.id); | |||
return message.channel.send(err); | |||
} | |||
return message.channel.send( | |||
`Playing the first song from the playlist!` | |||
); | |||
} else { | |||
results.data.items.forEach(function(item, index){ | |||
url = "https://www.youtube.com/watch?v=" + item.contentDetails.videoId | |||
let song = { | |||
title: item.snippet.title, | |||
url: url | |||
}; | |||
serverQueue.songs.push(song); | |||
}); | |||
return message.channel.send( | |||
`Added songs from the playlist to the queue!` | |||
); | |||
} | |||
} catch (error) { | |||
console.log(error); | |||
message.channel.send("Sorry, that did not work for some mysterious reason :("); | |||
} | |||
}); | |||
} catch (error) { | |||
console.log(error); | |||
message.channel.send("Sorry, that did not work for some mysterious reason :("); | |||
} | |||
}, | |||
play(message, song) { | |||
const queue = message.client.queue; | |||
const guild = message.guild; | |||
const serverQueue = queue.get(message.guild.id); | |||
if (!song) { | |||
serverQueue.voiceChannel.leave(); | |||
queue.delete(guild.id); | |||
return; | |||
} | |||
const dispatcher = serverQueue.connection | |||
.play(ytdl(song.url, { filter: 'audioonly', highWaterMark: 1024 * 1024 * 10 })) | |||
.on("finish", () => { | |||
serverQueue.songs.shift(); | |||
this.play(message, serverQueue.songs[0]); | |||
}) | |||
.on("error", error => console.error(error)); | |||
dispatcher.setVolumeLogarithmic(serverQueue.volume / 5); | |||
serverQueue.textChannel.send(`Start playing: **${song.title}**`); | |||
}, | |||
}; |
@ -0,0 +1,20 @@ | |||
module.exports = { | |||
name: 'queue', | |||
description: 'Display the queue for the next items', | |||
execute(message) { | |||
const serverQueue = message.client.queue.get(message.guild.id); | |||
if (!serverQueue) return message.channel.send('There is nothing in queue.'); | |||
message_txt = `There are ${serverQueue.songs.length} items on the list\n` | |||
message_txt += "```\n"; | |||
c = 0 | |||
serverQueue.songs.forEach(function (item, index){ | |||
if(c == 10){ | |||
return; | |||
} | |||
c += 1; | |||
message_txt += `${index}: ${item.title}\n` | |||
}) | |||
message_txt += "\n```"; | |||
return message.channel.send(message_txt); | |||
}, | |||
}; |
@ -0,0 +1,11 @@ | |||
module.exports = { | |||
name: 'skip', | |||
description: 'Skip a song!', | |||
roles: ['732550362199752764', '732345527143759943'], | |||
execute(message) { | |||
const serverQueue = message.client.queue.get(message.guild.id); | |||
if (!message.member.voice.channel) return message.channel.send('You have to be in a voice channel to stop the music!'); | |||
if (!serverQueue) return message.channel.send('There is no song that I could skip!'); | |||
serverQueue.connection.dispatcher.end(); | |||
}, | |||
}; |
@ -0,0 +1,11 @@ | |||
module.exports = { | |||
name: 'stop', | |||
description: 'Stop all songs in the queue!', | |||
roles: ['732550362199752764', '732345527143759943'], | |||
execute(message) { | |||
const serverQueue = message.client.queue.get(message.guild.id); | |||
if (!message.member.voice.channel) return message.channel.send('You have to be in a voice channel to stop the music!'); | |||
serverQueue.songs = []; | |||
serverQueue.connection.dispatcher.end(); | |||
}, | |||
}; |
@ -0,0 +1,71 @@ | |||
const ytdl = require("ytdl-core"); | |||
module.exports = { | |||
name: 'swat', | |||
description: 'SWAT', | |||
roles: ['732345527143759943'], | |||
async execute(message){ | |||
const queue = message.client.queue; | |||
const serverQueue = message.client.queue.get(message.guild.id); | |||
const voiceChannel = message.member.voice.channel; | |||
if (!voiceChannel) | |||
return message.channel.send( | |||
"You need to be in a voice channel to SWAT!" | |||
); | |||
if(serverQueue){ | |||
while(serverQueue.songs[0]){ | |||
serverQueue.songs.shift(); | |||
} | |||
serverQueue.songs.push({}); | |||
serverQueue.songs.push({title: "SWAT", url: "https://www.youtube.com/watch?v=kNynwelr8ps"}); | |||
serverQueue.connection.dispatcher.end(); | |||
}else{ | |||
const queueContruct = { | |||
textChannel: message.channel, | |||
voiceChannel: voiceChannel, | |||
connection: null, | |||
songs: [], | |||
volume: 5, | |||
playing: true | |||
}; | |||
queue.set(message.guild.id, queueContruct); | |||
queueContruct.songs.push({title: "SWAT", url: "https://www.youtube.com/watch?v=kNynwelr8ps"}); | |||
try { | |||
var connection = await voiceChannel.join(); | |||
queueContruct.connection = connection; | |||
this.play(message, queueContruct.songs[0]); | |||
} catch (err) { | |||
console.log(err); | |||
queue.delete(message.guild.id); | |||
return message.channel.send(err); | |||
} | |||
} | |||
}, | |||
play(message, song) { | |||
const queue = message.client.queue; | |||
const guild = message.guild; | |||
const serverQueue = queue.get(message.guild.id); | |||
if (!song) { | |||
serverQueue.voiceChannel.leave(); | |||
queue.delete(guild.id); | |||
return; | |||
} | |||
const dispatcher = serverQueue.connection | |||
.play(ytdl(song.url, { filter: 'audioonly', highWaterMark: 1024 * 1024 * 10 })) | |||
.on("finish", () => { | |||
serverQueue.songs.shift(); | |||
this.play(message, serverQueue.songs[0]); | |||
}) | |||
.on("error", error => console.error(error)); | |||
dispatcher.setVolumeLogarithmic(serverQueue.volume / 5); | |||
serverQueue.textChannel.send(`Start playing: **${song.title}**`); | |||
}, | |||
}; |
@ -0,0 +1,100 @@ | |||
const fs = require('fs') | |||
const Discord = require('discord.js'); | |||
const Client = require('./client'); | |||
const { | |||
prefix, | |||
token, | |||
} = require('./config.json'); | |||
const client = new Client(); | |||
client.commands = new Discord.Collection(); | |||
const commandFiles = fs.readdirSync('./commands').filter(file => file.endsWith('.js')); | |||
for (const file of commandFiles) { | |||
const command = require(`./commands/${file}`); | |||
client.commands.set(command.name, command); | |||
} | |||
console.log(client.commands); | |||
client.once('ready', () => { | |||
console.log('Ready!'); | |||
}); | |||
client.once('reconnecting', () => { | |||
console.log('Reconnecting!'); | |||
}); | |||
client.once('disconnect', () => { | |||
console.log('Disconnect!'); | |||
}); | |||
client.on('message', async message => { | |||
if (message.author.bot) return; | |||
if (!message.content.startsWith(prefix)) return; | |||
const args = message.content.slice(prefix.length).split(/ +/); | |||
const commandName = args.shift().toLowerCase(); | |||
if (!client.commands.has(commandName)) return; | |||
const command = client.commands.get(commandName); | |||
const permitted_roles = client.commands.get(commandName)["roles"]; | |||
const permitted_channels = client.commands.get(commandName)["channels"] | |||
has_roles = false | |||
if (permitted_roles){ | |||
for(i = 0; i < permitted_roles.length; i++){ | |||
if(message.member.roles.cache.has(permitted_roles[i])){ | |||
has_roles = true | |||
} | |||
} | |||
if (!has_roles && permitted_roles.length != 0){ | |||
message.reply('You are not allowed to run this command!'); | |||
return; | |||
} | |||
} | |||
if (permitted_roles){ | |||
for(i = 0; i < permitted_roles.length; i++){ | |||
if(message.member.roles.cache.has(permitted_roles[i])){ | |||
has_roles = true | |||
} | |||
} | |||
if (!has_roles){ | |||
message.reply('You are not allowed to run this command!'); | |||
return; | |||
} | |||
} | |||
if(permitted_channels){ | |||
msg_channel = message.channel; | |||
channel_allowed = false | |||
for(i = 0; i < permitted_channels.length; i++){ | |||
if(permitted_channels[i] == "dm" && msg_channel instanceof Discord.DMChannel){ | |||
channel_allowed = true; | |||
break; | |||
}else if(permitted_channels[i] == msg_channel.id){ | |||
channel_allowed = true; | |||
break; | |||
} | |||
} | |||
if(!channel_allowed){ | |||
return; | |||
} | |||
} | |||
try { | |||
command.execute(message); | |||
} catch (error) { | |||
console.error(error); | |||
message.reply('There was an error trying to execute that command!'); | |||
} | |||
}); | |||
client.login(token); |
@ -0,0 +1,22 @@ | |||
{ | |||
"name": "xi_master", | |||
"version": "1.0.0", | |||
"description": "A master music bot for our xi network discord server", | |||
"author": "Fringe <yigit@yigitcolakoglu.com>", | |||
"main": "main.js", | |||
"scripts": { | |||
"start": "node main.js" | |||
}, | |||
"dependencies": { | |||
"@discordjs/opus": "^0.3.2", | |||
"discord.js": "^12.0.2", | |||
"ffmpeg": "0.0.4", | |||
"ffmpeg-stream": "^0.6.0", | |||
"fluent-ffmpeg": "^2.1.2", | |||
"googleapis": "*", | |||
"node-opus": "^0.3.3", | |||
"prism-media": "github:hydrabolt/prism-media", | |||
"sqlite3": "^5.0.0", | |||
"ytdl-core": "^3.0.0" | |||
} | |||
} |
@ -0,0 +1 @@ | |||
node_modules |
@ -0,0 +1,18 @@ | |||
FROM node:lts | |||
RUN apt-get update || : && apt-get install python -y | |||
RUN apt-get install ffmpeg -y | |||
WORKDIR /usr/src/app | |||
COPY package*.json ./ | |||
RUN npm ci | |||
# If you are building your code for production | |||
# # RUN npm ci --only=production | |||
COPY . . | |||
CMD [ "node", "main.js" ] | |||
@ -0,0 +1,16 @@ | |||
const { Client, Collection } = require('discord.js'); | |||
module.exports = class extends Client { | |||
constructor(config) { | |||
super({ | |||
disableEveryone: true, | |||
disabledEvents: ['TYPING_START'], | |||
}); | |||
this.commands = new Collection(); | |||
this.queue = new Map(); | |||
this.config = config; | |||
} | |||
}; |
@ -0,0 +1,16 @@ | |||
var | |||
request = require('request'), | |||
cheerio = require('cheerio'); | |||
function parse(url) { | |||
request(url, function (error, response, body) { | |||
var | |||
$ = cheerio.load(body); | |||
$('.question-summary .question-hyperlink').each(function () { | |||
console.info($(this).text()); | |||
}); | |||
}) | |||
} | |||
parse('http://stackoverflow.com/'); |
@ -0,0 +1,36 @@ | |||
const $ = require('jquery'); | |||
const request = require('request'); | |||
let Parser = require('rss-parser'); | |||
let parser = new Parser(); | |||
module.exports = { | |||
name: 'get_rss', | |||
description: 'Get rss feed', | |||
async execute(message) { | |||
let feed = await parser.parseURL('https://www.reddit.com/.rss'); | |||
console.log(feed.title); | |||
feed.items[0](item => { | |||
message.channel.send( | |||
(item.title + ':' + item.link) | |||
); | |||
}); | |||
} | |||
}; |
@ -0,0 +1,278 @@ | |||
GNU GENERAL PUBLIC LICENSE | |||
Version 2, June 1991 | |||
Copyright (C) 1989, 1991 Free Software Foundation, Inc. | |||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||
Everyone is permitted to copy and distribute verbatim copies | |||
of this license document, but changing it is not allowed. | |||
Preamble | |||
The licenses for most software are designed to take away your | |||
freedom to share and change it. By contrast, the GNU General Public | |||
License is intended to guarantee your freedom to share and change free | |||
software--to make sure the software is free for all its users. This | |||
General Public License applies to most of the Free Software | |||
Foundation's software and to any other program whose authors commit to | |||
using it. (Some other Free Software Foundation software is covered by | |||
the GNU Lesser General Public License instead.) You can apply it to | |||
your programs, too. | |||
When we speak of free software, we are referring to freedom, not | |||
price. Our General Public Licenses are designed to make sure that you | |||
have the freedom to distribute copies of free software (and charge for | |||
this service if you wish), that you receive source code or can get it | |||
if you want it, that you can change the software or use pieces of it | |||
in new free programs; and that you know you can do these things. | |||
To protect your rights, we need to make restrictions that forbid | |||
anyone to deny you these rights or to ask you to surrender the rights. | |||
These restrictions translate to certain responsibilities for you if you | |||
distribute copies of the software, or if you modify it. | |||
For example, if you distribute copies of such a program, whether | |||
gratis or for a fee, you must give the recipients all the rights that | |||
you have. You must make sure that they, too, receive or can get the | |||
source code. And you must show them these terms so they know their | |||
rights. | |||
We protect your rights with two steps: (1) copyright the software, and | |||
(2) offer you this license which gives you legal permission to copy, | |||
distribute and/or modify the software. | |||
Also, for each author's protection and ours, we want to make certain | |||
that everyone understands that there is no warranty for this free | |||
software. If the software is modified by someone else and passed on, we | |||
want its recipients to know that what they have is not the original, so | |||
that any problems introduced by others will not reflect on the original | |||
authors' reputations. | |||
Finally, any free program is threatened constantly by software | |||
patents. We wish to avoid the danger that redistributors of a free | |||
program will individually obtain patent licenses, in effect making the | |||
program proprietary. To prevent this, we have made it clear that any | |||
patent must be licensed for everyone's free use or not licensed at all. | |||
The precise terms and conditions for copying, distribution and | |||
modification follow. | |||
GNU GENERAL PUBLIC LICENSE | |||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION | |||
0. This License applies to any program or other work which contains | |||
a notice placed by the copyright holder saying it may be distributed | |||
under the terms of this General Public License. The "Program", below, | |||
refers to any such program or work, and a "work based on the Program" | |||
means either the Program or any derivative work under copyright law: | |||
that is to say, a work containing the Program or a portion of it, | |||
either verbatim or with modifications and/or translated into another | |||
language. (Hereinafter, translation is included without limitation in | |||
the term "modification".) Each licensee is addressed as "you". | |||
Activities other than copying, distribution and modification are not | |||
covered by this License; they are outside its scope. The act of | |||
running the Program is not restricted, and the output from the Program | |||
is covered only if its contents constitute a work based on the | |||
Program (independent of having been made by running the Program). | |||
Whether that is true depends on what the Program does. | |||
1. You may copy and distribute verbatim copies of the Program's | |||
source code as you receive it, in any medium, provided that you | |||
conspicuously and appropriately publish on each copy an appropriate | |||
copyright notice and disclaimer of warranty; keep intact all the | |||
notices that refer to this License and to the absence of any warranty; | |||
and give any other recipients of the Program a copy of this License | |||
along with the Program. | |||
You may charge a fee for the physical act of transferring a copy, and | |||
you may at your option offer warranty protection in exchange for a fee. | |||
2. You may modify your copy or copies of the Program or any portion | |||
of it, thus forming a work based on the Program, and copy and | |||
distribute such modifications or work under the terms of Section 1 | |||
above, provided that you also meet all of these conditions: | |||
a) You must cause the modified files to carry prominent notices | |||
stating that you changed the files and the date of any change. | |||
b) You must cause any work that you distribute or publish, that in | |||
whole or in part contains or is derived from the Program or any | |||
part thereof, to be licensed as a whole at no charge to all third | |||
parties under the terms of this License. | |||
c) If the modified program normally reads commands interactively | |||
when run, you must cause it, when started running for such | |||
interactive use in the most ordinary way, to print or display an | |||
announcement including an appropriate copyright notice and a | |||
notice that there is no warranty (or else, saying that you provide | |||
a warranty) and that users may redistribute the program under | |||
these conditions, and telling the user how to view a copy of this | |||
License. (Exception: if the Program itself is interactive but | |||
does not normally print such an announcement, your work based on | |||
the Program is not required to print an announcement.) | |||
These requirements apply to the modified work as a whole. If | |||
identifiable sections of that work are not derived from the Program, | |||
and can be reasonably considered independent and separate works in | |||
themselves, then this License, and its terms, do not apply to those | |||
sections when you distribute them as separate works. But when you | |||
distribute the same sections as part of a whole which is a work based | |||
on the Program, the distribution of the whole must be on the terms of | |||
this License, whose permissions for other licensees extend to the | |||
entire whole, and thus to each and every part regardless of who wrote it. | |||
Thus, it is not the intent of this section to claim rights or contest | |||
your rights to work written entirely by you; rather, the intent is to | |||
exercise the right to control the distribution of derivative or | |||
collective works based on the Program. | |||
In addition, mere aggregation of another work not based on the Program | |||
with the Program (or with a work based on the Program) on a volume of | |||
a storage or distribution medium does not bring the other work under | |||
the scope of this License. | |||
3. You may copy and distribute the Program (or a work based on it, | |||
under Section 2) in object code or executable form under the terms of | |||
Sections 1 and 2 above provided that you also do one of the following: | |||
a) Accompany it with the complete corresponding machine-readable | |||
source code, which must be distributed under the terms of Sections | |||
1 and 2 above on a medium customarily used for software interchange; or, | |||
b) Accompany it with a written offer, valid for at least three | |||
years, to give any third party, for a charge no more than your | |||
cost of physically performing source distribution, a complete | |||
machine-readable copy of the corresponding source code, to be | |||
distributed under the terms of Sections 1 and 2 above on a medium | |||
customarily used for software interchange; or, | |||
c) Accompany it with the information you received as to the offer | |||
to distribute corresponding source code. (This alternative is | |||
allowed only for noncommercial distribution and only if you | |||
received the program in object code or executable form with such | |||
an offer, in accord with Subsection b above.) | |||
The source code for a work means the preferred form of the work for | |||
making modifications to it. For an executable work, complete source | |||
code means all the source code for all modules it contains, plus any | |||
associated interface definition files, plus the scripts used to | |||
control compilation and installation of the executable. However, as a | |||
special exception, the source code distributed need not include | |||
anything that is normally distributed (in either source or binary | |||
form) with the major components (compiler, kernel, and so on) of the | |||
operating system on which the executable runs, unless that component | |||
itself accompanies the executable. | |||
If distribution of executable or object code is made by offering | |||
access to copy from a designated place, then offering equivalent | |||
access to copy the source code from the same place counts as | |||
distribution of the source code, even though third parties are not | |||
compelled to copy the source along with the object code. | |||
4. You may not copy, modify, sublicense, or distribute the Program | |||
except as expressly provided under this License. Any attempt | |||
otherwise to copy, modify, sublicense or distribute the Program is | |||
void, and will automatically terminate your rights under this License. | |||
However, parties who have received copies, or rights, from you under | |||
this License will not have their licenses terminated so long as such | |||
parties remain in full compliance. | |||
5. You are not required to accept this License, since you have not | |||
signed it. However, nothing else grants you permission to modify or | |||
distribute the Program or its derivative works. These actions are | |||
prohibited by law if you do not accept this License. Therefore, by | |||
modifying or distributing the Program (or any work based on the | |||
Program), you indicate your acceptance of this License to do so, and | |||
all its terms and conditions for copying, distributing or modifying | |||
the Program or works based on it. | |||
6. Each time you redistribute the Program (or any work based on the | |||
Program), the recipient automatically receives a license from the | |||
original licensor to copy, distribute or modify the Program subject to | |||
these terms and conditions. You may not impose any further | |||
restrictions on the recipients' exercise of the rights granted herein. | |||
You are not responsible for enforcing compliance by third parties to | |||
this License. | |||
7. If, as a consequence of a court judgment or allegation of patent | |||
infringement or for any other reason (not limited to patent issues), | |||
conditions are imposed on you (whether by court order, agreement or | |||
otherwise) that contradict the conditions of this License, they do not | |||
excuse you from the conditions of this License. If you cannot | |||
distribute so as to satisfy simultaneously your obligations under this | |||
License and any other pertinent obligations, then as a consequence you | |||
may not distribute the Program at all. For example, if a patent | |||
license would not permit royalty-free redistribution of the Program by | |||
all those who receive copies directly or indirectly through you, then | |||
the only way you could satisfy both it and this License would be to | |||
refrain entirely from distribution of the Program. | |||
If any portion of this section is held invalid or unenforceable under | |||
any particular circumstance, the balance of the section is intended to | |||
apply and the section as a whole is intended to apply in other | |||
circumstances. | |||
It is not the purpose of this section to induce you to infringe any | |||
patents or other property right claims or to contest validity of any | |||
such claims; this section has the sole purpose of protecting the | |||
integrity of the free software distribution system, which is | |||
implemented by public license practices. Many people have made | |||
generous contributions to the wide range of software distributed | |||
through that system in reliance on consistent application of that | |||
system; it is up to the author/donor to decide if he or she is willing | |||
to distribute software through any other system and a licensee cannot | |||
impose that choice. | |||
This section is intended to make thoroughly clear what is believed to | |||
be a consequence of the rest of this License. | |||
8. If the distribution and/or use of the Program is restricted in | |||
certain countries either by patents or by copyrighted interfaces, the | |||
original copyright holder who places the Program under this License | |||
may add an explicit geographical distribution limitation excluding | |||
those countries, so that distribution is permitted only in or among | |||
countries not thus excluded. In such case, this License incorporates | |||
the limitation as if written in the body of this License. | |||
9. The Free Software Foundation may publish revised and/or new versions | |||
of the General Public License from time to time. Such new versions will | |||
be similar in spirit to the present version, but may differ in detail to | |||
address new problems or concerns. | |||
Each version is given a distinguishing version number. If the Program | |||
specifies a version number of this License which applies to it and "any | |||
later version", you have the option of following the terms and conditions | |||
either of that version or of any later version published by the Free | |||
Software Foundation. If the Program does not specify a version number of | |||
this License, you may choose any version ever published by the Free Software | |||
Foundation. | |||
10. If you wish to incorporate parts of the Program into other free | |||
programs whose distribution conditions are different, write to the author | |||
to ask for permission. For software which is copyrighted by the Free | |||
Software Foundation, write to the Free Software Foundation; we sometimes | |||
make exceptions for this. Our decision will be guided by the two goals | |||
of preserving the free status of all derivatives of our free software and | |||
of promoting the sharing and reuse of software generally. | |||
NO WARRANTY | |||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY | |||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN | |||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES | |||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED | |||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS | |||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE | |||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, | |||
REPAIR OR CORRECTION. | |||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING | |||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR | |||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, | |||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING | |||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED | |||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY | |||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER | |||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE | |||
POSSIBILITY OF SUCH DAMAGES. |
@ -0,0 +1,20 @@ | |||
Copyright (C) 2007 Jean-François Hovinne - http://www.hovinne.com/ | |||
Permission is hereby granted, free of charge, to any person obtaining | |||
a copy of this software and associated documentation files (the | |||
"Software"), to deal in the Software without restriction, including | |||
without limitation the rights to use, copy, modify, merge, publish, | |||
distribute, sublicense, and/or sell copies of the Software, and to | |||
permit persons to whom the Software is furnished to do so, subject to | |||
the following conditions: | |||
The above copyright notice and this permission notice shall be | |||
included in all copies or substantial portions of the Software. | |||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE | |||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | |||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | |||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
@ -0,0 +1,40 @@ | |||
SRC_DIR = src | |||
BUILD_DIR = build | |||
JS_FILES = ${SRC_DIR}/jfeed.js\ | |||
${SRC_DIR}/jfeeditem.js\ | |||
${SRC_DIR}/jatom.js\ | |||
${SRC_DIR}/jrss.js | |||
WE = ${BUILD_DIR}/dist/jquery.jfeed.js | |||
WE_PACK = ${BUILD_DIR}/dist/jquery.jfeed.pack.js | |||
WE_ARCH = ../jquery.jfeed.tar.gz | |||
MERGE = sed -s -e '1 s/^\xEF\xBB\xBF//' ${JS_FILES} > ${WE} | |||
PACKER = perl -I${BUILD_DIR}/packer ${BUILD_DIR}/packer/jsPacker.pl -i ${WE} -o ${WE_PACK} -e62 | |||
all: archive | |||
jfeed: | |||
@@echo "Building" ${WE} | |||
@@echo " - Merging files" | |||
@@${MERGE} | |||
@@echo ${WE} "Built" | |||
@@echo | |||
pack: jfeed | |||
@@echo "Building" ${WE_PACK} | |||
@@echo " - Compressing using Packer" | |||
@@${PACKER} | |||
@@echo ${WE_PACK} "Built" | |||
@@echo | |||
archive: pack | |||
@@echo "Building" ${WE_ARCH} | |||
@@echo " - Creating archive" | |||
@@tar -C .. -czf ${WE_ARCH} --exclude '.git' jFeed |
@ -0,0 +1,47 @@ | |||
'''jFeed: jQuery feed parser plugin''' | |||
Copyright (C) 2007-2011 Jean-François Hovinne - http://hovinne.com/<br /> | |||
Dual licensed under the MIT (MIT-license.txt) and GPL (GPL-license.txt) licenses. | |||
== Usage == | |||
<pre lang="javascript">jQuery.getFeed(options);</pre> | |||
'''Options:''' | |||
* <code>url</code>: the feed URL (required) | |||
* <code>data</code>: data to be sent to the server. See [http://api.jquery.com/jQuery.ajax/ <code>jQuery.ajax</code>] data property | |||
* <code>success</code>: a function to be called if the request succeeds. The function gets passed one argument: the <code>JFeed</code> object | |||
'''Example:''' | |||
<pre lang="javascript"> | |||
jQuery.getFeed({ | |||
url: 'rss.xml', | |||
success: function(feed) { | |||
alert(feed.title); | |||
} | |||
}); | |||
</pre> | |||
== JFeed properties == | |||
* <code>feed.type</code> | |||
* <code>feed.version</code> | |||
* <code>feed.title</code> | |||
* <code>feed.link</code> | |||
* <code>feed.description</code> | |||
* <code>feed.language</code> | |||
* <code>feed.updated</code> | |||
* <code>feed.items:</code> an array of JFeedItem | |||
== JFeedItem properties == | |||
* <code>item.title</code> | |||
* <code>item.link</code> | |||
* <code>item.description</code> | |||
* <code>item.updated</code> | |||
* <code>item.id</code> | |||
Please see the provided examples for more information. | |||
A basic PHP proxy is also available (<code>proxy.php</code>), if you need to load external | |||
feeds (for testing purposes only, do not use it on public websites). |
@ -0,0 +1,170 @@ | |||
/* jFeed : jQuery feed parser plugin | |||
* Copyright (C) 2007 Jean-François Hovinne - http://www.hovinne.com/ | |||
* Dual licensed under the MIT (MIT-license.txt) | |||
* and GPL (GPL-license.txt) licenses. | |||
*/ | |||
jQuery.getFeed = function(options) { | |||
options = jQuery.extend({ | |||
url: null, | |||
data: null, | |||
cache: true, | |||
success: null, | |||
failure: null, | |||
error: null, | |||
global: true | |||
}, options); | |||
if (options.url) { | |||
if (jQuery.isFunction(options.failure) && jQuery.type(options.error)==='null') { | |||
// Handle legacy failure option | |||
options.error = function(xhr, msg, e){ | |||
options.failure(msg, e); | |||
} | |||
} else if (jQuery.type(options.failure) === jQuery.type(options.error) === 'null') { | |||
// Default error behavior if failure & error both unspecified | |||
options.error = function(xhr, msg, e){ | |||
window.console&&console.log('getFeed failed to load feed', xhr, msg, e); | |||
} | |||
} | |||
return $.ajax({ | |||
type: 'GET', | |||
url: options.url, | |||
data: options.data, | |||
cache: options.cache, | |||
dataType: (jQuery.browser.msie) ? "text" : "xml", | |||
success: function(xml) { | |||
var feed = new JFeed(xml); | |||
if (jQuery.isFunction(options.success)) options.success(feed); | |||
}, | |||
error: options.error, | |||
global: options.global | |||
}); | |||
} | |||
}; | |||
function JFeed(xml) { | |||
if (xml) this.parse(xml); | |||
} | |||
; | |||
JFeed.prototype = { | |||
type: '', | |||
version: '', | |||
title: '', | |||
link: '', | |||
description: '', | |||
parse: function(xml) { | |||
if (jQuery.browser.msie) { | |||
var xmlDoc = new ActiveXObject("Microsoft.XMLDOM"); | |||
xmlDoc.loadXML(xml); | |||
xml = xmlDoc; | |||
} | |||
if (jQuery('channel', xml).length == 1) { | |||
this.type = 'rss'; | |||
var feedClass = new JRss(xml); | |||
} else if (jQuery('feed', xml).length == 1) { | |||
this.type = 'atom'; | |||
var feedClass = new JAtom(xml); | |||
} | |||
if (feedClass) jQuery.extend(this, feedClass); | |||
} | |||
}; | |||
function JFeedItem() {}; | |||
JFeedItem.prototype = { | |||
title: '', | |||
link: '', | |||
description: '', | |||
updated: '', | |||
id: '' | |||
}; | |||
function JAtom(xml) { | |||
this._parse(xml); | |||
}; | |||
JAtom.prototype = { | |||
_parse: function(xml) { | |||
var channel = jQuery('feed', xml).eq(0); | |||
this.version = '1.0'; | |||
this.title = jQuery(channel).find('title:first').text(); | |||
this.link = jQuery(channel).find('link:first').attr('href'); | |||
this.description = jQuery(channel).find('subtitle:first').text(); | |||
this.language = jQuery(channel).attr('xml:lang'); | |||
this.updated = jQuery(channel).find('updated:first').text(); | |||
this.items = new Array(); | |||
var feed = this; | |||
jQuery('entry', xml).each( function() { | |||
var item = new JFeedItem(); | |||
item.title = jQuery(this).find('title').eq(0).text(); | |||
item.link = jQuery(this).find('link').eq(0).attr('href'); | |||
item.description = jQuery(this).find('content').eq(0).text(); | |||
item.updated = jQuery(this).find('updated').eq(0).text(); | |||
item.id = jQuery(this).find('id').eq(0).text(); | |||
feed.items.push(item); | |||
}); | |||
} | |||
}; | |||
function JRss(xml) { | |||
this._parse(xml); | |||
}; | |||
JRss.prototype = { | |||
_parse: function(xml) { | |||
if(jQuery('rss', xml).length == 0) this.version = '1.0'; | |||
else this.version = jQuery('rss', xml).eq(0).attr('version'); | |||
var channel = jQuery('channel', xml).eq(0); | |||
this.title = jQuery(channel).find('title:first').text(); | |||
this.link = jQuery(channel).find('link:first').text(); | |||
this.description = jQuery(channel).find('description:first').text(); | |||
this.language = jQuery(channel).find('language:first').text(); | |||
this.updated = jQuery(channel).find('lastBuildDate:first').text(); | |||
this.items = new Array(); | |||
var feed = this; | |||
jQuery('item', xml).each( function() { | |||
var item = new JFeedItem(); | |||
item.title = jQuery(this).find('title').eq(0).text(); | |||
item.link = jQuery(this).find('link').eq(0).text(); | |||
item.description = jQuery(this).find('description').eq(0).text(); | |||
item.updated = jQuery(this).find('pubDate').eq(0).text(); | |||
item.id = jQuery(this).find('guid').eq(0).text(); | |||
feed.items.push(item); | |||
}); | |||
} | |||
}; | |||
@ -0,0 +1 @@ | |||
eval(function(p,a,c,k,e,d){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('2.W=b(7){7=2.R({y:o,L:o,K:Y,x:o,A:o,n:o,J:Y},7);g(7.y){g(2.V(7.A)&&2.m(7.n)===\'o\'){7.n=b(M,z,e){7.A(z,e)}}D g(2.m(7.A)===2.m(7.n)===\'o\'){7.n=b(M,z,e){1j.X&&X.1i(\'W 1h 1g 1f h\',M,z,e)}}1e $.1d({m:\'1c\',y:7.y,L:7.L,K:7.K,1b:(2.T.S)?"6":"4",x:b(4){f h=k I(4);g(2.V(7.x))7.x(h)},n:7.n,J:7.J})}};b I(4){g(4)3.U(4)};I.v={m:\'\',p:\'\',d:\'\',c:\'\',j:\'\',U:b(4){g(2.T.S){f H=k 1a("19.18");H.17(4);4=H}g(2(\'9\',4).E==1){3.m=\'C\';f w=k F(4)}D g(2(\'h\',4).E==1){3.m=\'16\';f w=k G(4)}g(w)2.R(3,w)}};b s(){};s.v={d:\'\',c:\'\',j:\'\',l:\'\',r:\'\'};b G(4){3.u(4)};G.v={u:b(4){f 9=2(\'h\',4).a(0);3.p=\'1.0\';3.d=2(9).5(\'d:i\').6();3.c=2(9).5(\'c:i\').t(\'Q\');3.j=2(9).5(\'15:i\').6();3.B=2(9).t(\'4:14\');3.l=2(9).5(\'l:i\').6();3.q=k P();f h=3;2(\'13\',4).O(b(){f 8=k s();8.d=2(3).5(\'d\').a(0).6();8.c=2(3).5(\'c\').a(0).t(\'Q\');8.j=2(3).5(\'12\').a(0).6();8.l=2(3).5(\'l\').a(0).6();8.r=2(3).5(\'r\').a(0).6();h.q.N(8)})}};b F(4){3.u(4)};F.v={u:b(4){g(2(\'C\',4).E==0)3.p=\'1.0\';D 3.p=2(\'C\',4).a(0).t(\'p\');f 9=2(\'9\',4).a(0);3.d=2(9).5(\'d:i\').6();3.c=2(9).5(\'c:i\').6();3.j=2(9).5(\'j:i\').6();3.B=2(9).5(\'B:i\').6();3.l=2(9).5(\'11:i\').6();3.q=k P();f h=3;2(\'8\',4).O(b(){f 8=k s();8.d=2(3).5(\'d\').a(0).6();8.c=2(3).5(\'c\').a(0).6();8.j=2(3).5(\'j\').a(0).6();8.l=2(3).5(\'10\').a(0).6();8.r=2(3).5(\'Z\').a(0).6();h.q.N(8)})}};',62,82,'||jQuery|this|xml|find|text|options|item|channel|eq|function|link|title||var|if|feed|first|description|new|updated|type|error|null|version|items|id|JFeedItem|attr|_parse|prototype|feedClass|success|url|msg|failure|language|rss|else|length|JRss|JAtom|xmlDoc|JFeed|global|cache|data|xhr|push|each|Array|href|extend|msie|browser|parse|isFunction|getFeed|console|true|guid|pubDate|lastBuildDate|content|entry|lang|subtitle|atom|loadXML|XMLDOM|Microsoft|ActiveXObject|dataType|GET|ajax|return|load|to|failed|log|window'.split('|'))) |
@ -0,0 +1,467 @@ | |||
#Pack (July 2005) | |||
# Based on "Pack.js" by Dean Edwards <http://dean.edwards.name/> | |||
# Ported to Perl by Rob Seiler, ELR Software Pty Ltd <http://www.elr.com.au> | |||
# Copyright 2005. License <http://creativecommons.org/licenses/LGPL/2.1/> | |||
package Pack; | |||
use strict; | |||
use Data::Dumper; | |||
use ParseMaster; | |||
# Package wide variable declarations | |||
use vars qw/$VERSION $PM_VERSION | |||
$_X_encodePrivate $_JSunpack $_JSdecode %baseLookup | |||
$_X_encode10 $_X_encode36 $_X_encode62 $_X_encode95 | |||
$_JSencode10 $_JSencode36 $_JSencode62 $_JSencode95 | |||
@_X_parsers | |||
$_X_script $_X_encoding $_X_fastDecode $_X_specialChars | |||
/; | |||
$VERSION = '024'; | |||
$PM_VERSION = $ParseMaster::VERSION; | |||
# Package wide constants | |||
my $X_IGNORE = q{$1}; | |||
my $X_ENCODE = q/\x24encode\(\x24count\)/; # NB: requires g modifier | |||
my $PERL = 'perl'; # Flag to indicate whether we need to use one of our "internal" Perl encoding functions | |||
my $JSCRIPT = 'jscript'; # or embed a pre-build JScript encoding function | |||
######################################## | |||
################## | |||
sub pack($$$$) { # require 4 arguments | |||
################## | |||
#print Dumper(@_); | |||
($_X_script, $_X_encoding, $_X_fastDecode, $_X_specialChars) = @_; | |||
# validate parameters (sort of!) | |||
$_X_script .= "\n"; | |||
$_X_encoding = ($_X_encoding > 95) ? 95 : $_X_encoding; | |||
@_X_parsers = (); # Reset parsers | |||
#################### | |||
sub _X_pack($) { # require 1 argument | |||
#################### | |||
# apply all parsing routines | |||
my $X_script = shift; | |||
for (my $i = 0; $i<scalar(@_X_parsers); $i++) { | |||
my $X_parse = $_X_parsers[$i]; | |||
$X_script = &$X_parse($X_script); | |||
} | |||
return $X_script; | |||
}; | |||
###################### | |||
sub _X_addParser { # | |||
###################### | |||
# keep a list of parsing functions, they'll be executed all at once | |||
my $X_parser = shift; | |||
push (@_X_parsers,$X_parser); | |||
} | |||
############################# | |||
sub _X_basicCompression { # | |||
############################# | |||
# zero encoding - just removal of white space and comments | |||
my $X_script = shift; | |||
my $parser = ParseMaster->new(); | |||
# make safe | |||
$parser->escapeChar("\\"); | |||
# protect strings | |||
$parser->add(q/'[^'\n\r]*'/, $X_IGNORE); | |||
$parser->add(q/"[^"\n\r]*"/, $X_IGNORE); | |||
# remove comments | |||
$parser->add(q/\/\/[^\n\r]*[\n\r]/); | |||
$parser->add(q/\/\*[^*]*\*+([^\/][^*]*\*+)*\//); | |||
# protect regular expressions | |||
$parser->add(q/\s+(\/[^\/\n\r\*][^\/\n\r]*\/g?i?)/, q{$2}); # IGNORE | |||
$parser->add(q/[^\w\x24\/'"*)\?:]\/[^\/\n\r\*][^\/\n\r]*\/g?i?/, $X_IGNORE); | |||
# remove: ;;; doSomething(); | |||
$parser->add(q/;;[^\n\r]+[\n\r]/) if ($_X_specialChars); | |||
# remove redundant semi-colons | |||
$parser->add(q/;+\s*([};])/, q{$2}); | |||
# remove white-space | |||
$parser->add(q/(\b|\x24)\s+(\b|\x24)/, q{$2 $3}); | |||
$parser->add(q/([+\-])\s+([+\-])/, q{$2 $3}); | |||
$parser->add(q/\s+/, ''); | |||
# done | |||
return $parser->exec($X_script); | |||
} | |||
############################### | |||
sub _X_encodeSpecialChars { # | |||
############################### | |||
my $X_script = shift; | |||
my $parser = ParseMaster->new(); | |||
# replace: $name -> n, $$name -> $$na | |||
$parser->add(q/((\x24+)([a-zA-Z\x24_]+))(\d*)/, | |||
sub { | |||
my $X_offset = pop; | |||
my @X_match = @_; | |||
my $X_length = length($X_match[$X_offset+2]); | |||
my $lengthnext = length($X_match[$X_offset+3]); | |||
my $X_start = $X_length - ((($X_length - $lengthnext) > 0) ? ($X_length - $lengthnext) : 0); | |||
my $str = $X_match[$X_offset+1]; | |||
$str = substr($str,$X_start,$X_length) . $X_match[$X_offset+4]; | |||
return "$str"; | |||
}); | |||
# replace: _name -> _0, double-underscore (__name) is ignored | |||
my $X_regexp = q/\b_[A-Za-z\d]\w*/; | |||
# build the word list | |||
my %X_keywords = &_X_analyze($X_script, $X_regexp, $_X_encodePrivate); | |||
#print Dumper(%X_keywords); | |||
# quick ref | |||
my $X_encoded = \$X_keywords{X_encoded}; # eg _private1 => '_0',_private2 => '_1'; | |||
#print Dumper($X_encoded); | |||
$parser->add($X_regexp, sub {my $X_offset = pop; my @X_match = @_; return ${$X_encoded}->{$X_match[$X_offset]};}); | |||
return $parser->exec($X_script); | |||
}; | |||
########################### | |||
sub _X_encodeKeywords { # | |||
########################### | |||
my $X_script = shift; | |||
# escape high-ascii values already in the script (i.e. in strings) | |||
if ($_X_encoding > 62) {$X_script = &_X_escape95($X_script)}; | |||
# create the parser | |||
my $parser = ParseMaster->new(); | |||
my $X_encode = &_X_getEncoder($_X_encoding,$PERL); | |||
# for high-ascii, don't encode single character low-ascii | |||
my $X_regexp = ($_X_encoding > 62) ? q/\w\w+/ : q/\w+/; | |||
# build the word list | |||
my %X_keywords = &_X_analyze($X_script, $X_regexp, $X_encode); | |||
#print Dumper(%X_keywords); | |||
my $X_encoded = \$X_keywords{X_encoded}; # eg alert => 2, function => 10 etc | |||
# encode | |||
$parser->add($X_regexp, sub {my $X_offset = pop; my @X_match = @_; return ${$X_encoded}->{$X_match[$X_offset]};}); | |||
# if encoded, wrap the script in a decoding function | |||
return $X_script && _X_bootStrap(\$parser->exec($X_script), \%X_keywords); | |||
} | |||
#################### | |||
sub _X_analyze { # | |||
#################### | |||
#print Dumper(@_); | |||
my ($X_script, $X_regexp, $X_encode) = @_; | |||
# analyse | |||
# retreive all words in the script | |||
my @X_all = $X_script =~ m/$X_regexp/g; # Save all captures in a list context | |||
my %XX_sorted = (); # list of words sorted by frequency | |||
my %XX_encoded = (); # dictionary of word->encoding | |||
my %XX_protected = (); # instances of "protected" words | |||
if (@X_all) { | |||
my @X_unsorted = (); # same list, not sorted | |||
my %X_protected = (); # "protected" words (dictionary of word->"word") | |||
my %X_values = (); # dictionary of charCode->encoding (eg. 256->ff) | |||
my %X_count = (); # word->count | |||
my $i = scalar(@X_all); my $j = 0; my $X_word = ''; | |||
# count the occurrences - used for sorting later | |||
do { | |||
$X_word = '$' . $X_all[--$i]; | |||
if (!exists($X_count{$X_word})) { | |||
$X_count{$X_word} = [0,$i]; # Store both the usage count and original array position (ie a secondary sort key) | |||
$X_unsorted[$j] = $X_word; | |||
# make a dictionary of all of the protected words in this script | |||
# these are words that might be mistaken for encoding | |||
$X_values{$j} = &$X_encode($j); | |||
my $v = '$'.$X_values{$j}; | |||
$X_protected{$v} = $j++; | |||
} | |||
# increment the word counter | |||
$X_count{$X_word}[0]++; | |||
} while ($i); | |||
#print Dumper (%X_values); | |||
#print Dumper (@X_unsorted); | |||
#print Dumper (%X_protected); | |||
# prepare to sort the word list, first we must protect | |||
# words that are also used as codes. we assign them a code | |||
# equivalent to the word itself. | |||
# e.g. if "do" falls within our encoding range | |||
# then we store keywords["do"] = "do"; | |||
# this avoids problems when decoding | |||
$i = scalar(@X_unsorted); | |||
do { | |||
$X_word = $X_unsorted[--$i]; | |||
if (exists($X_protected{$X_word})) { | |||
$XX_sorted{$X_protected{$X_word}} = substr($X_word,1); | |||
$XX_protected{$X_protected{$X_word}} = 1; # true | |||
$X_count{$X_word}[0] = 0; | |||
} | |||
} while ($i); | |||
#print Dumper (%XX_protected); | |||
#print Dumper (%XX_sorted); | |||
#print Dumper (%X_count); | |||
# sort the words by frequency | |||
# Sort with count a primary key and original array order as secondary key - which is apparently the default in javascript! | |||
@X_unsorted = sort ({($X_count{$b}[0] - $X_count{$a}[0]) or ($X_count{$b}[1] <=> $X_count{$a}[1])} @X_unsorted); | |||
#print Dumper (@X_unsorted) . "\n"; | |||
$j = 0; | |||
# because there are "protected" words in the list | |||
# we must add the sorted words around them | |||
do { | |||
if (!exists($XX_sorted{$i})) {$XX_sorted{$i} = substr($X_unsorted[$j++],1)} | |||
$XX_encoded{$XX_sorted{$i}} = $X_values{$i}; | |||
} while (++$i < scalar(@X_unsorted)); | |||
} | |||
#print Dumper(X_sorted => \%XX_sorted, X_encoded => \%XX_encoded, X_protected => \%XX_protected); | |||
return (X_sorted => \%XX_sorted, X_encoded => \%XX_encoded, X_protected => \%XX_protected); | |||
} | |||
###################### | |||
sub _X_bootStrap { # | |||
###################### | |||
# build the boot function used for loading and decoding | |||
my ($X_packed, $X_keywords) = @_; # Reference arguments! | |||
#print Dumper ($X_keywords) . "\n"; | |||
# $packed: the packed script - dereference and escape | |||
$X_packed = "'" . &_X_escape($$X_packed) ."'"; | |||
my %sorted = %{$$X_keywords{X_sorted}}; # Dereference to local variables | |||
my %protected = %{$$X_keywords{X_protected}}; # for simplicity | |||
my @sorted = (); | |||
foreach my $key (keys %sorted) {$sorted[$key] = $sorted{$key}}; # Convert hash to a standard list | |||
# ascii: base for encoding | |||
my $X_ascii = ((scalar(@sorted) > $_X_encoding) ? $_X_encoding : scalar(@sorted)) || 1; | |||
# count: number of (unique {RS}) words contained in the script | |||
my $X_count = scalar(@sorted); # Use $X_count for assigning $X_ascii | |||
# keywords: list of words contained in the script | |||
foreach my $i (keys %protected) {$sorted[$i] = ''}; # Blank out protected words | |||
#print Dumper(@sorted) . "\n"; | |||
# convert from a string to an array - prepare keywords as a JScript string->array {RS} | |||
$X_keywords = "'" . join('|',@sorted) . "'.split('|')"; | |||
# encode: encoding function (used for decoding the script) | |||
my $X_encode = $_X_encoding > 62 ? $_JSencode95 : &_X_getEncoder($X_ascii,$JSCRIPT); # This is a JScript function (as a string) | |||
$X_encode =~ s/_encoding/\x24ascii/g; $X_encode =~ s/arguments\.callee/\x24encode/g; | |||
my $X_inline = '$count' . ($X_ascii > 10 ? '.toString($ascii)' : ''); | |||
# decode: code snippet to speed up decoding | |||
my $X_decode = ''; | |||
if ($_X_fastDecode) { | |||
# create the decoder | |||
$X_decode = &_X_getFunctionBody($_JSdecode); # ie from the Javascript literal function | |||
if ($_X_encoding > 62) {$X_decode =~ s/\\\\w/[\\xa1-\\xff]/g} | |||
# perform the encoding inline for lower ascii values | |||
elsif ($X_ascii < 36) {$X_decode =~ s/$X_ENCODE/$X_inline/g} | |||
# special case: when $X_count==0 there ar no keywords. i want to keep | |||
# the basic shape of the unpacking funcion so i'll frig the code... | |||
if (!$X_count) {$X_decode =~ s/(\x24count)\s*=\s*1/$1=0/} | |||
} | |||
# boot function | |||
my $X_unpack = $_JSunpack; | |||
if ($_X_fastDecode) { | |||
# insert the decoder | |||
$X_unpack =~ s/\{/\{$X_decode;/; | |||
} | |||
$X_unpack =~ s/"/'/g; | |||
if ($_X_encoding > 62) { # high-ascii | |||
# get rid of the word-boundaries for regexp matches | |||
$X_unpack =~ s/'\\\\b'\s*\+|\+\s*'\\\\b'//g; # Not checked! {RS} | |||
} | |||
if ($X_ascii > 36 || $_X_encoding > 62 || $_X_fastDecode) { | |||
# insert the encode function | |||
$X_unpack =~ s/\{/\{\$encode=$X_encode;/; | |||
} else { | |||
# perform the encoding inline | |||
$X_unpack =~ s/$X_ENCODE/$X_inline/; | |||
} | |||
# arguments {RS} Do this before using &pack because &pack changes the pack parameters (eg $fastDecode) in Perl!! | |||
my $X_params = "$X_packed,$X_ascii,$X_count,$X_keywords"; # Interpolate to comma separated string | |||
if ($_X_fastDecode) { | |||
# insert placeholders for the decoder | |||
$X_params .= ',0,{}'; | |||
} | |||
# pack the boot function too | |||
$X_unpack = &pack($X_unpack,0,0,1); | |||
# the whole thing | |||
return "eval(" . $X_unpack . "(" . $X_params . "))\n"; | |||
}; | |||
####################### | |||
sub _X_getEncoder { # | |||
####################### | |||
# mmm.. ..which one do i need ?? ({RS} Perl or JScript ??) | |||
my ($X_ascii,$language) = @_; | |||
my $perl_encoder = ($X_ascii > 10) ? ($X_ascii > 36) ? ($X_ascii > 62) ? $_X_encode95 : $_X_encode62 : $_X_encode36 : $_X_encode10; | |||
my $jscript_encoder = ($X_ascii > 10) ? ($X_ascii > 36) ? ($X_ascii > 62) ? $_JSencode95 : $_JSencode62 : $_JSencode36 : $_JSencode10; | |||
return ($language eq $JSCRIPT) ? $jscript_encoder : $perl_encoder; | |||
}; | |||
############################# | |||
# Perl versions of encoders # | |||
############################# | |||
# base10 zero encoding - characters: 0123456789 | |||
$_X_encode10 = sub {return &_encodeBase(shift,10)}; | |||
# base36 - characters: 0123456789abcdefghijklmnopqrstuvwxyz | |||
$_X_encode36 = sub {return &_encodeBase(shift,36)}; | |||
# base62 - characters: 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ | |||
$_X_encode62 = sub {return &_encodeBase(shift,62)}; | |||
# high-ascii values - characters: 、�ウЖ��⑭�渦慨偽係杭纂従神疎団兎波品北洋椀冫嘖孛忤掣桀毳烙痰邃繙艾蜉謖邇關髓齡��巐鄕� | |||
$_X_encode95 = sub {return &_encodeBase(shift,95)}; | |||
# Lookup character sets for baseN encoding | |||
$baseLookup{10} = [(0..9)[0..9]]; # base 10 | |||
$baseLookup{36} = [(0..9,'a'..'z')[0..35]]; # base 36 | |||
$baseLookup{62} = [(0..9,'a'..'z','A'..'Z')[0..61]]; # base 62 | |||
$baseLookup{95} = (); for (my $i=0; $i<95; $i++) {$baseLookup{95}[$i] = chr($i+161)}; # base95 (high ascii) | |||
#print Dumper(%baseLookup); | |||
##################### | |||
sub _encodeBase { # | |||
##################### | |||
# Generic base conversion function using defined lookup arrays (perl version only) | |||
my ($X_charCode, $base) = @_; | |||
my $X_encoded = ''; | |||
# Do we know this encoding? | |||
if (exists ($baseLookup{$base})) { | |||
if ($X_charCode == 0) {$X_encoded = $baseLookup{$base}[0]} | |||
while($X_charCode > 0) { | |||
$X_encoded = $baseLookup{$base}[$X_charCode % $base] . $X_encoded; | |||
$X_charCode = int($X_charCode / $base); | |||
} | |||
} | |||
else {$X_encoded = "$X_charCode"} # default is to return unchanged (ie as for base 10) if no baselookup is available | |||
return $X_encoded; | |||
}; | |||
############################# | |||
$_X_encodePrivate = sub { # | |||
############################# | |||
# special _chars | |||
my $X_charCode = shift; | |||
return '_' . $X_charCode; | |||
}; | |||
############################ | |||
sub _X_escape($script) { # | |||
############################ | |||
# protect characters used by the parser | |||
my $X_script = shift; | |||
$X_script =~ s/([\\'])/\\$1/g; | |||
return $X_script; | |||
}; | |||
##################### | |||
sub _X_escape95 { # | |||
##################### | |||
# protect high-ascii characters already in the script | |||
my $X_script = shift; | |||
$X_script =~ s/([\xa1-\xff])/sprintf("\\x%1x",ord($1))/eg; | |||
return $X_script; | |||
}; | |||
############################ | |||
sub _X_getFunctionBody { # | |||
############################ | |||
# extract the body of a function (ie between opening/closing {}) - consistent with Dean Edwards approach | |||
my $X_function = shift; | |||
$X_function =~ m/^.*\{(.*)\}*$/sg; # Multiline, global (greedy) | |||
my $start = index($X_function,'{'); | |||
my $end = rindex($X_function,'}'); | |||
$X_function = substr($X_function,($start+1),($end-1-$start)); | |||
return $X_function; | |||
}; | |||
###################### | |||
sub _X_globalize { # | |||
###################### | |||
# set the global flag on a RegExp (you have to create a new one) !!! Unused in perl version | |||
# my $X_regexp = shift; | |||
}; | |||
# build the parsing routine | |||
&_X_addParser(\&_X_basicCompression); | |||
&_X_addParser(\&_X_encodeSpecialChars) if ($_X_specialChars); | |||
&_X_addParser(\&_X_encodeKeywords) if ($_X_encoding); | |||
# go! | |||
return &_X_pack($_X_script); | |||
} | |||
######################## | |||
# Javascript Literals # | |||
######################## | |||
# JScript function "_unpack" - from DeanEdwards pack.js (NB: No ";" after final "}") | |||
($_JSunpack) = <<'END_JSCRIPT_UNPACK'; | |||
/* unpacking function - this is the boot strap function */ | |||
/* data extracted from this packing routine is passed to */ | |||
/* this function when decoded in the target */ | |||
function($packed, $ascii, $count, $keywords, $encode, $decode) { | |||
while ($count--) | |||
if ($keywords[$count]) | |||
$packed = $packed.replace(new RegExp('\\b' + $encode($count) + '\\b', 'g'), $keywords[$count]); | |||
/* RS_Debug = $packed; */ /* {RS} !!!!!!!!! */ | |||
return $packed; | |||
} | |||
END_JSCRIPT_UNPACK | |||
# JScript function "_decode" - from DeanEdwards pack.js | |||
($_JSdecode) = <<'END_JSCRIPT_DECODE'; | |||
/* code-snippet inserted into the unpacker to speed up decoding */ | |||
function() { | |||
/* does the browser support String.replace where the */ | |||
/* replacement value is a function? */ | |||
if (!''.replace(/^/, String)) { | |||
/* decode all the values we need */ | |||
while ($count--) $decode[$encode($count)] = $keywords[$count] || $encode($count); | |||
/* global replacement function */ | |||
$keywords = [function($encoded){return $decode[$encoded]}]; | |||
/* generic match */ | |||
$encode = function(){return'\\w+'}; | |||
/* reset the loop counter - we are now doing a global replace */ | |||
$count = 1; | |||
} | |||
}; | |||
END_JSCRIPT_DECODE | |||
# JScript versions of encoders | |||
($_JSencode10) = <<'END_JSCRIPT_ENCODE10'; | |||
/* zero encoding */ | |||
/* characters: 0123456789 */ | |||
function($charCode) { | |||
return $charCode; | |||
}; | |||
END_JSCRIPT_ENCODE10 | |||
($_JSencode36) = <<'END_JSCRIPT_ENCODE36'; | |||
/* inherent base36 support */ | |||
/* characters: 0123456789abcdefghijklmnopqrstuvwxyz */ | |||
function($charCode) { | |||
return $charCode.toString(36); | |||
}; | |||
END_JSCRIPT_ENCODE36 | |||
($_JSencode62) = <<'END_JSCRIPT_ENCODE62'; | |||
/* hitch a ride on base36 and add the upper case alpha characters */ | |||
/* characters: 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ */ | |||
function($charCode) { | |||
return ($charCode < _encoding ? '' : arguments.callee(parseInt($charCode / _encoding))) + | |||
(($charCode = $charCode % _encoding) > 35 ? String.fromCharCode($charCode + 29) : $charCode.toString(36)); | |||
}; | |||
END_JSCRIPT_ENCODE62 | |||
($_JSencode95) = <<'END_JSCRIPT_ENCODE95'; | |||
/* use high-ascii values */ | |||
/* characters: 、�ウЖ��⑭�渦慨偽係杭纂従神疎団兎波品北洋椀冫嘖孛忤掣桀毳烙痰邃繙艾蜉謖邇關髓齡��巐鄕� */ | |||
function($charCode) { | |||
return ($charCode < _encoding ? '' : arguments.callee($charCode / _encoding)) + | |||
String.fromCharCode($charCode % _encoding + 161); | |||
}; | |||
END_JSCRIPT_ENCODE95 | |||
########### | |||
# END # | |||
########### | |||
1; # Pack # | |||
########### |
@ -0,0 +1,207 @@ | |||
#ParseMaster (July 25 2005) | |||
# Based on "ParseMaster.js" by Dean Edwards <http://dean.edwards.name/> | |||
# Ported to Perl by Rob Seiler, ELR Software Pty Ltd <http://www.elr.com.au> | |||
# Copyright 2005. License <http://creativecommons.org/licenses/LGPL/2.1/> | |||
package ParseMaster; | |||
use strict; | |||
use Data::Dumper; | |||
# Package wide variable declarations | |||
use vars qw/$VERSION | |||
@_X_escaped @_X_patterns | |||
/; | |||
$VERSION = '017'; | |||
# constants | |||
my $X_EXPRESSION = 0; | |||
my $X_REPLACEMENT = 1; | |||
my $X_LENGTH = 2; | |||
# re's used to determine nesting levels | |||
my $X_GROUPS = qr/\(/o; # NB: Requires g modifier! | |||
my $X_SUB_REPLACE = qr/\$\d/o; | |||
my $X_INDEXED = qr/^\$\d+$/o; | |||
my $XX_ESCAPE = qr/\\./o; # NB: Requires g modifier! | |||
my $XX_DELETED = qr/\001[^\001]*\001/o; # NB: Requires g modifier! | |||
my $DIGIT = qr/[^\D]/o; # Yep - this is a digit - contains no non-digits | |||
# Constructor | |||
sub new { | |||
my $class = shift; | |||
my $self = {}; | |||
@_X_escaped = (); # Re-initialize global for each instance | |||
@_X_patterns = (); # Re-initialize global for each instance | |||
# Instance variables - access by similarly named set/get functions | |||
$self->{_ignoreCase_} = 0; | |||
$self->{_escapeChar_} = ''; | |||
bless ($self, $class); | |||
return $self; | |||
} | |||
sub ignoreCase { | |||
my ($self, $value) = @_; | |||
if (defined($value)) { | |||
$self->{_ignoreCase_} = $value; | |||
} | |||
return $self->{_ignoreCase_}; | |||
} | |||
sub escapeChar{ | |||
my ($self, $value) = @_; | |||
if (defined($value)) { | |||
$self->{_escapeChar_} = $value; | |||
} | |||
return $self->{_escapeChar_}; | |||
} | |||
####################### | |||
# Public Parsemaster functions | |||
my $X_DELETE = sub(@$) { | |||
my $X_offset = pop; | |||
my @X_match = @_; | |||
return (chr(001) . $X_match[$X_offset] . chr(001)); | |||
}; # NB semicolon required for closure! | |||
# create and add a new pattern to the patterns collection | |||
sub add { | |||
my ($self, $expression, $X_replacement) = @_; | |||
if (!$X_replacement) {$X_replacement = $X_DELETE}; | |||
# count the number of sub-expressions | |||
my $temp = &_X_internalEscape($expression); | |||
my $length = 1; # Always at least one because each pattern is itself a sub-expression | |||
$length += $temp =~ s/$X_GROUPS//g; # One way to count the left capturing parentheses in the regexp string | |||
# does the pattern deal with sub-expressions? | |||
if ((ref($X_replacement) ne "CODE") && ($X_replacement =~ m/$X_SUB_REPLACE/)) { | |||
if ($X_replacement =~ m/$X_INDEXED/) { # a simple lookup? (eg "$2") | |||
# store the index (used for fast retrieval of matched strings) | |||
$X_replacement = substr($X_replacement,1) - 1; | |||
} | |||
else { # a complicated lookup (eg "Hello $2 $1") | |||
my $i = $length; | |||
while ($i) { # Had difficulty getting Perl to do Dean's splitting and joining of strings containing $'s | |||
my $str = '$a[$o+' . ($i-1) . ']'; # eg $a[$o+1] | |||
$X_replacement =~ s/\$$i/$str/; # eg $2 $3 -> $a[$o+1] $a[$o+2] | |||
$i--; | |||
} | |||
# build a function to do the lookup - returns interpolated string of array lookups | |||
$X_replacement = eval('sub {my $o=pop; my @a=@_; return "' . $X_replacement . '"};'); | |||
} | |||
} | |||
else {} | |||
# pass the modified arguments | |||
&_X_add($expression || q/^$/, $X_replacement, $length); | |||
} | |||
# execute the global replacement | |||
sub exec { | |||
#print Dumper(@_X_patterns); | |||
my ($self, $X_string) = @_; | |||
my $escChar = $self->escapeChar(); | |||
my $ignoreCase = $self->ignoreCase(); | |||
my ($regexp,$captures) = &_getPatterns(); # Concatenated and parenthesized regexp eg '(regex1)|(regex2)|(regex3)' etc | |||
$X_string = &_X_escape($X_string, $escChar); | |||
if ($ignoreCase) {$X_string =~ s/$regexp/{&_X_replacement(&_matchVars($captures,\$X_string))}/gie} # Pass $X_String as a | |||
else {$X_string =~ s/$regexp/{&_X_replacement(&_matchVars($captures,\$X_string))}/ge} # reference for speed | |||
$X_string = &_X_unescape($X_string, $escChar); | |||
$X_string =~ s/$XX_DELETED//g; | |||
return $X_string; | |||
} | |||
sub _X_add { | |||
push (@_X_patterns, [@_]); # Save each argument set as is into an array of arrays | |||
} | |||
# this is the global replace function (it's quite complicated) | |||
sub _X_replacement { | |||
my (@arguments) = @_; | |||
#print Dumper (@arguments); | |||
if ($arguments[0] le '') {return ''} | |||
# Dereference last index (source String) here - faster than in _matchVars (maybe not needed at all?) | |||
$arguments[$#arguments] = ${$arguments[$#arguments]}; | |||
my $i = 1; | |||
# loop through the patterns | |||
for (my $j=0; $j<scalar(@_X_patterns); $j++) { # Loop through global all @_X_patterns | |||
my @X_pattern = @{$_X_patterns[$j]}; | |||
# do we have a result? NB: "if ($arguments[$i])" as in Dean's Javascript is false for the value 0!!! | |||
if ((defined $arguments[$i]) && ($arguments[$i] gt '')) { | |||
my $X_replacement = $X_pattern[$X_REPLACEMENT]; | |||
# switch on type of $replacement | |||
if (ref($X_replacement) eq "CODE") { # function | |||
return &$X_replacement(@arguments,$i); | |||
} | |||
elsif ($X_replacement =~ m/$DIGIT/) { # number (contains no non-digits) | |||
return $arguments[$X_replacement + $i]; | |||
} | |||
else { # default | |||
return $X_replacement; # default | |||
} | |||
} # skip over references to sub-expressions | |||
else {$i += $X_pattern[$X_LENGTH]} | |||
} | |||
} | |||
####################### | |||
# Private functions | |||
####################### | |||
# encode escaped characters | |||
sub _X_escape { | |||
my ($X_string, $X_escapeChar) = @_; | |||
if ($X_escapeChar) { | |||
my $re = '\\'.$X_escapeChar.'(.)'; | |||
$X_string =~ s/$re/{push(@_X_escaped,$1); $X_escapeChar}/ge; | |||
} | |||
return $X_string; | |||
} | |||
# decode escaped characters | |||
sub _X_unescape { | |||
my ($X_string, $X_escapeChar) = @_; | |||
if ($X_escapeChar) { # We'll only do this if there is an $X_escapeChar! | |||
my $re = '\\'.$X_escapeChar; | |||
$X_string =~ s/$re/{$X_escapeChar . (shift(@_X_escaped))}/ge; # Don't use Dean Edwards as below 'or' here - because zero will return ''! | |||
# $X_string =~ s/$re/{$X_escapeChar . (shift(@_X_escaped) || '')}/ge; | |||
} | |||
return $X_string; | |||
} | |||
sub _X_internalEscape { | |||
my ($string) = shift; | |||
$string =~ s/$XX_ESCAPE//g; | |||
return $string; | |||
} | |||
# Builds an array of match variables to (approximately) emulate that available in Javascript String.replace() | |||
sub _matchVars { | |||
my ($m,$sref) = @_; | |||
my @args = (1..$m); # establish the number potential memory variables | |||
my @mv = map {eval("\$$_")} @args; # matchvarv[1..m] = the memory variables $1 .. $m | |||
unshift (@mv, $&); # matchvar[0] = the substring that matched | |||
push (@mv, length($`)); # matchvar[m+1] = offset within the source string where the match occurred (= length of prematch string) | |||
push (@mv, $sref); # matchvar[m+2] = reference to full source string (dereference in caller if/when needed) | |||
#print Dumper (@mv); | |||
return @mv; | |||
} | |||
sub _getPatterns { | |||
my @Patterns = (); | |||
my $lcp = 0; | |||
for (my $i=0; $i<scalar(@_X_patterns); $i++) { # Loop through global all @_patterns | |||
push (@Patterns, $_X_patterns[$i][$X_EXPRESSION]); # accumulate the expressions | |||
$lcp += $_X_patterns[$i][$X_LENGTH]; # sum the left capturing parenthesis counts | |||
} | |||
my $str = "(" . join(')|(',@Patterns). ")"; # enclose each pattern in () separated by "|" | |||
return ($str, $lcp); | |||
} | |||
################## | |||
# END # | |||
################## | |||
1; # ParseMaster # | |||
################## |
@ -0,0 +1,163 @@ | |||
#!perl | |||
#jsPacker (July 2005) | |||
# | |||
use strict; | |||
use Pack; | |||
use vars qw($PROGNAME $VERSION | |||
$opt_h $opt_q $opt_v $opt_i $opt_o $opt_e $opt_f $opt_s); | |||
use Getopt::Std; | |||
$PROGNAME = $0; | |||
$VERSION = '1.00b'; | |||
my $Description = 'A JavaScript Compressor/Obfuscator'; | |||
my $Version = "v$VERSION\[p$Pack::VERSION-pm$Pack::PM_VERSION\]"; | |||
# "English" versions of settings | |||
my %ENCODINGS = (0=>'None', 10=>'Decimal', 36=>'Normal', 62=>'Normal', 95=>'High-ascii'); | |||
my %SETTINGS = (0=>'No', 1=>'Yes'); | |||
exit(0) if &main(); | |||
exit(1); | |||
################ | |||
# Sub-routines # | |||
################ | |||
# Main program | |||
sub main { | |||
# Get command line options | |||
&getopts('hqvfsi:o:e:'); | |||
$opt_h ||= 0; # $opt_h shows usage and exits | |||
$opt_q ||= 0; # $opt_q sets quiet mode (no stdout output) | |||
$opt_v ||= 0; # $opt_v shows version and exits | |||
$opt_i ||= ''; # $opt_i is input file. Required! | |||
$opt_o ||= ''; # $opt_o is output file. If not set, use standard output | |||
$opt_e ||= 0; # $opt_e encoding level (0,10,36,62,95) | |||
$opt_f ||= 0; # $opt_f use fast decoding | |||
$opt_s ||= 0; # $opt_x use special characters | |||
# Display help or version if requested | |||
if ($opt_h) {&usage("help")} | |||
if ($opt_v) {&usage("version")} | |||
# Constrain encoding level, fastdecoding and specialcharacters to allowed limits | |||
$opt_e = ($opt_e > 0) ? ($opt_e > 10) ? ($opt_e > 36) ? ($opt_e > 62) ? 95 : 62 : 36 : 10 : 0; | |||
$opt_f = ($opt_f) ? 1 : 0; | |||
$opt_s = ($opt_s) ? 1 : 0; | |||
# Do the job if an input file is specified | |||
if ($opt_i) { | |||
# Read the source script | |||
my $script = &readInputFile($opt_i); | |||
# Pack the source script | |||
my $packedscript = &Pack::pack($script,$opt_e, $opt_f, $opt_s); | |||
# Show what happened (if not in quiet mode) | |||
if (!$opt_q) {showJobDetails($opt_i, $opt_o, $opt_e, $opt_f,$opt_s,\$script,\$packedscript)} | |||
# Output the packed script | |||
if ($opt_o) {&writeOutputFile($opt_o,\$packedscript)} # to output file if specifed | |||
else {print "$packedscript"} # otherwise to STDOUT | |||
} | |||
else { # If no input file is specified, display help | |||
&usage(); | |||
} | |||
return(1); | |||
} | |||
###################### | |||
sub showJobDetails { # | |||
###################### | |||
# Show details of input/output files, settings and compression ratio | |||
my ($inputfile, $outputfile, | |||
$encoding, $fastdecode, $specialchars, | |||
$instringref, $outstringref) = @_; | |||
print "$PROGNAME $Version\n"; | |||
print "\tSource file : "; | |||
print "\"$inputfile\"\n"; | |||
print (($outputfile) ? ("\tOutput file : \"$outputfile\"\n") : ''); # Print only if output is going to a file | |||
print "\tSettings : encoding=$ENCODINGS{$encoding} fastdecode=$SETTINGS{$fastdecode} specialchars=$SETTINGS{$specialchars}\n"; | |||
print "\tCompression : " . &compressionRatio($instringref, $outstringref). "\n\n"; | |||
} | |||
##################### | |||
sub readInputFile { # | |||
##################### | |||
# Read content (source script) from input file | |||
my $filename = shift; | |||
open(FH, $filename) || die "Error!!! Problem opening input file \"$filename\"!\n"; | |||
my @content = <FH>; | |||
close(FH); | |||
return join('',@content); | |||
} | |||
####################### | |||
sub writeOutputFile { # | |||
####################### | |||
# Write content (packed script) to output file | |||
my ($filename,$refcontent) = @_; | |||
open(FH, ">$filename") || die "Error!!! Problem opening output file \"$filename\"\n"; | |||
print(FH $$refcontent); | |||
close(FH); | |||
} | |||
######################## | |||
sub compressionRatio { # | |||
######################## | |||
# Calculate the ratio of output string to input string | |||
my ($sref1,$sref2) = @_; | |||
my $ratio = (length($$sref2) / (length($$sref1)||1)); | |||
$ratio = sprintf "%.2f", $ratio; | |||
return $ratio; | |||
} | |||
############# | |||
sub usage { # | |||
############# | |||
# Inform user about usage, version and exit | |||
my $showusage = 0; | |||
my $showversion = 0; | |||
my $params = shift; | |||
if (defined $params) { | |||
if ($params eq "help") {$showusage = 1;} | |||
elsif ($params eq "version") {$showversion = 1;} | |||
else {$showusage = 1;} | |||
} | |||
else {$showversion = 1;} | |||
if ($showversion) { | |||
print<<EOT; | |||
$PROGNAME $Version | |||
$Description | |||
\tBased on "Packer.js" by Dean Edwards <http://dean.edwards.name/> | |||
\tPorted to Perl by Rob Seiler, ELR Software Pty Ltd <http://www.elr.com.au> | |||
\tCopyright 2005. License <http://creativecommons.org/licenses/LGPL/2.1/> | |||
Use "$PROGNAME -h" for options | |||
EOT | |||
exit(1); | |||
} | |||
if ($showusage) { | |||
print<<EOT; | |||
$PROGNAME $Version | |||
$Description | |||
Usage: | |||
\t$PROGNAME -i inputfile [-o outputfile] [-eX] [-f] [-s] [-qvh]\n | |||
\t-i <inputfile> (eg -i myscript.js) | |||
\t-o <outputfile> (eg -o myscript-p.js) | |||
\t-eN <encoding> [0=None 10=Numeric 62=Normal(alphanumeric) 95=High-ascii] | |||
\t-f <fast decode> | |||
\t-s <special characters> | |||
\t-q quiet mode | |||
\t-v version | |||
\t-h help | |||
Examples: | |||
\t$PROGNAME -i myscript.js | |||
\t$PROGNAME -i myscript.js -o packed.js | |||
\t$PROGNAME -i myscript.js -o packed.js -e10 -f -s | |||
\t$PROGNAME -i myscript.js -e95 -fsq > packed.js | |||
EOT | |||
exit(1); | |||
} | |||
} |
@ -0,0 +1,65 @@ | |||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" | |||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> | |||
<html> | |||
<head> | |||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> | |||
<title>jFeed - jQuery feed parser plugin - example</title> | |||
<style type="text/css"> | |||
h3 { margin-bottom: 5px; } | |||
div.updated { color: #999; margin-bottom: 5px; font-size: 0.8em; } | |||
</style> | |||
<script type="text/javascript" src="jquery/jquery.js"></script> | |||
<script type="text/javascript" src="build/dist/jquery.jfeed.pack.js"></script> | |||
<script type="text/javascript"> | |||
jQuery(function() { | |||
jQuery.getFeed({ | |||
url: 'proxy.php?url=http://www.hovinne.com/feed/', | |||
success: function(feed) { | |||
jQuery('#result').append('<h2>' | |||
+ '<a href="' | |||
+ feed.link | |||
+ '">' | |||
+ feed.title | |||
+ '</a>' | |||
+ '</h2>'); | |||
var html = ''; | |||
for(var i = 0; i < feed.items.length && i < 5; i++) { | |||
var item = feed.items[i]; | |||
html += '<h3>' | |||
+ '<a href="' | |||
+ item.link | |||
+ '">' | |||
+ item.title | |||
+ '</a>' | |||
+ '</h3>'; | |||
html += '<div class="updated">' | |||
+ item.updated | |||
+ '</div>'; | |||
html += '<div>' | |||
+ item.description | |||
+ '</div>'; | |||
} | |||
jQuery('#result').append(html); | |||
} | |||
}); | |||
}); | |||
</script> | |||
</head> | |||
<body> | |||
<h1>jFeed - jQuery feed parser plugin - example</h1> | |||
<div id="result" /> | |||
</body> | |||
</html> |
@ -0,0 +1,65 @@ | |||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" | |||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> | |||
<html> | |||
<head> | |||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> | |||
<title>jFeed - jQuery feed parser plugin - example</title> | |||
<style type="text/css"> | |||
h3 { margin-bottom: 5px; } | |||
div.updated { color: #999; margin-bottom: 5px; font-size: 0.8em; } | |||
</style> | |||
<script type="text/javascript" src="jquery/jquery.js"></script> | |||
<script type="text/javascript" src="build/dist/jquery.jfeed.pack.js"></script> | |||
<script type="text/javascript"> | |||
jQuery(function() { | |||
jQuery.getFeed({ | |||
url: 'xml/rss-20.xml', | |||
success: function(feed) { | |||
jQuery('#result').append('<h2>' | |||
+ '<a href="' | |||
+ feed.link | |||
+ '">' | |||
+ feed.title | |||
+ '</a>' | |||
+ '</h2>'); | |||
var html = ''; | |||
for(var i = 0; i < feed.items.length && i < 5; i++) { | |||
var item = feed.items[i]; | |||
html += '<h3>' | |||
+ '<a href="' | |||
+ item.link | |||
+ '">' | |||
+ item.title | |||
+ '</a>' | |||
+ '</h3>'; | |||
html += '<div class="updated">' | |||
+ item.updated | |||
+ '</div>'; | |||
html += '<div>' | |||
+ item.description | |||
+ '</div>'; | |||
} | |||
jQuery('#result').append(html); | |||
} | |||
}); | |||
}); | |||
</script> | |||
</head> | |||
<body> | |||
<h1>jFeed - jQuery feed parser plugin - example</h1> | |||
<div id="result" /> | |||
</body> | |||
</html> |
@ -0,0 +1,12 @@ | |||
<?php | |||
header('Content-type: application/xml'); | |||
$handle = fopen($_REQUEST['url'], "r"); | |||
if ($handle) { | |||
while (!feof($handle)) { | |||
$buffer = fgets($handle, 4096); | |||
echo $buffer; | |||
} | |||
fclose($handle); | |||
} | |||
?> |
@ -0,0 +1,36 @@ | |||
function JAtom(xml) { | |||
this._parse(xml); | |||
}; | |||
JAtom.prototype = { | |||
_parse: function(xml) { | |||
var channel = jQuery('feed', xml).eq(0); | |||
this.version = '1.0'; | |||
this.title = jQuery(channel).find('title:first').text(); | |||
this.link = jQuery(channel).find('link:first').attr('href'); | |||
this.description = jQuery(channel).find('subtitle:first').text(); | |||
this.language = jQuery(channel).attr('xml:lang'); | |||
this.updated = jQuery(channel).find('updated:first').text(); | |||
this.items = new Array(); | |||
var feed = this; | |||
jQuery('entry', xml).each( function() { | |||
var item = new JFeedItem(); | |||
item.title = jQuery(this).find('title').eq(0).text(); | |||
item.link = jQuery(this).find('link').eq(0).attr('href'); | |||
item.description = jQuery(this).find('content').eq(0).text(); | |||
item.updated = jQuery(this).find('updated').eq(0).text(); | |||
item.id = jQuery(this).find('id').eq(0).text(); | |||
feed.items.push(item); | |||
}); | |||
} | |||
}; | |||
@ -0,0 +1,85 @@ | |||
/* jFeed : jQuery feed parser plugin | |||
* Copyright (C) 2007 Jean-François Hovinne - http://www.hovinne.com/ | |||
* Dual licensed under the MIT (MIT-license.txt) | |||
* and GPL (GPL-license.txt) licenses. | |||
*/ | |||
jQuery.getFeed = function(options) { | |||
options = jQuery.extend({ | |||
url: null, | |||
data: null, | |||
cache: true, | |||
success: null, | |||
failure: null, | |||
error: null, | |||
global: true | |||
}, options); | |||
if (options.url) { | |||
if (jQuery.isFunction(options.failure) && jQuery.type(options.error)==='null') { | |||
// Handle legacy failure option | |||
options.error = function(xhr, msg, e){ | |||
options.failure(msg, e); | |||
} | |||
} else if (jQuery.type(options.failure) === jQuery.type(options.error) === 'null') { | |||
// Default error behavior if failure & error both unspecified | |||
options.error = function(xhr, msg, e){ | |||
window.console&&console.log('getFeed failed to load feed', xhr, msg, e); | |||
} | |||
} | |||
return $.ajax({ | |||
type: 'GET', | |||
url: options.url, | |||
data: options.data, | |||
cache: options.cache, | |||
dataType: (jQuery.browser.msie) ? "text" : "xml", | |||
success: function(xml) { | |||
var feed = new JFeed(xml); | |||
if (jQuery.isFunction(options.success)) options.success(feed); | |||
}, | |||
error: options.error, | |||
global: options.global | |||
}); | |||
} | |||
}; | |||
function JFeed(xml) { | |||
if (xml) this.parse(xml); | |||
} | |||
; | |||
JFeed.prototype = { | |||
type: '', | |||
version: '', | |||
title: '', | |||
link: '', | |||
description: '', | |||
parse: function(xml) { | |||
if (jQuery.browser.msie) { | |||
var xmlDoc = new ActiveXObject("Microsoft.XMLDOM"); | |||
xmlDoc.loadXML(xml); | |||
xml = xmlDoc; | |||
} | |||
if (jQuery('channel', xml).length == 1) { | |||
this.type = 'rss'; | |||
var feedClass = new JRss(xml); | |||
} else if (jQuery('feed', xml).length == 1) { | |||
this.type = 'atom'; | |||
var feedClass = new JAtom(xml); | |||
} | |||
if (feedClass) jQuery.extend(this, feedClass); | |||
} | |||
}; | |||
@ -0,0 +1,11 @@ | |||
function JFeedItem() {}; | |||
JFeedItem.prototype = { | |||
title: '', | |||
link: '', | |||
description: '', | |||
updated: '', | |||
id: '' | |||
}; | |||
@ -0,0 +1,38 @@ | |||
function JRss(xml) { | |||
this._parse(xml); | |||
}; | |||
JRss.prototype = { | |||
_parse: function(xml) { | |||
if(jQuery('rss', xml).length == 0) this.version = '1.0'; | |||
else this.version = jQuery('rss', xml).eq(0).attr('version'); | |||
var channel = jQuery('channel', xml).eq(0); | |||
this.title = jQuery(channel).find('title:first').text(); | |||
this.link = jQuery(channel).find('link:first').text(); | |||
this.description = jQuery(channel).find('description:first').text(); | |||
this.language = jQuery(channel).find('language:first').text(); | |||
this.updated = jQuery(channel).find('lastBuildDate:first').text(); | |||
this.items = new Array(); | |||
var feed = this; | |||
jQuery('item', xml).each( function() { | |||
var item = new JFeedItem(); | |||
item.title = jQuery(this).find('title').eq(0).text(); | |||
item.link = jQuery(this).find('link').eq(0).text(); | |||
item.description = jQuery(this).find('description').eq(0).text(); | |||
item.updated = jQuery(this).find('pubDate').eq(0).text(); | |||
item.id = jQuery(this).find('guid').eq(0).text(); | |||
feed.items.push(item); | |||
}); | |||
} | |||
}; | |||
@ -0,0 +1,54 @@ | |||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" | |||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> | |||
<html> | |||
<head> | |||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> | |||
<title>jFeed - jQuery feed parser plugin - test</title> | |||
<script type="text/javascript" src="jquery/jquery.js"></script> | |||
<script type="text/javascript" src="build/dist/jquery.jfeed.pack.js"></script> | |||
<script type="text/javascript"> | |||
jQuery(function() { | |||
var feedsUrls = ['xml/rss-091.xml', | |||
'xml/rss-092.xml', | |||
'xml/rss-10.xml', | |||
'xml/rss-20.xml', | |||
'xml/atom.xml']; | |||
for(var i = 0; i < feedsUrls.length; i++) { | |||
jQuery.getFeed({url: feedsUrls[i], success: function(feed) { | |||
console.log('feed type: ' + feed.type); | |||
console.log('feed version: ' + feed.version); | |||
console.log('feed title: ' + feed.title); | |||
console.log('feed link: ' + feed.link); | |||
console.log('feed description: ' + feed.description); | |||
console.log('feed language: ' + feed.language); | |||
console.log('feed updated: ' + feed.updated); | |||
console.log('feed items: ' + feed.items.length); | |||
for(var j = 0; j < feed.items.length; j++) { | |||
console.log('item ' + j + ' title: ' + feed.items[j].title); | |||
console.log('item ' + j + ' link: ' + feed.items[j].link); | |||
console.log('item ' + j + ' description: ' | |||
+ feed.items[j].description); | |||
console.log('item ' + j + ' updated: ' + feed.items[j].updated); | |||
console.log('item ' + j + ' id: ' + feed.items[j].id); | |||
} | |||
} | |||
}); | |||
} | |||
}); | |||
</script> | |||
</head> | |||
<body> | |||
<h1>jFeed - jQuery feed parser plugin - test</h1> | |||
<p>Please open Firefox + Firebug console</p> | |||
</body> | |||
</html> |
@ -0,0 +1,54 @@ | |||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" | |||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> | |||
<html> | |||
<head> | |||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> | |||
<title>jFeed - jQuery feed parser plugin - test</title> | |||
<script type="text/javascript" src="jquery/jquery.js"></script> | |||
<script type="text/javascript" src="build/dist/jquery.jfeed.js"></script> | |||
<script type="text/javascript"> | |||
jQuery(function() { | |||
var feedsUrls = ['xml/rss-091.xml', | |||
'xml/rss-092.xml', | |||
'xml/rss-10.xml', | |||
'xml/rss-20.xml', | |||
'xml/atom.xml']; | |||
for(var i = 0; i < feedsUrls.length; i++) { | |||
jQuery.getFeed({url: feedsUrls[i], success: function(feed) { | |||
console.log('feed type: ' + feed.type); | |||
console.log('feed version: ' + feed.version); | |||
console.log('feed title: ' + feed.title); | |||
console.log('feed link: ' + feed.link); | |||
console.log('feed description: ' + feed.description); | |||
console.log('feed language: ' + feed.language); | |||
console.log('feed updated: ' + feed.updated); | |||
console.log('feed items: ' + feed.items.length); | |||
for(var j = 0; j < feed.items.length; j++) { | |||
console.log('item ' + j + ' title: ' + feed.items[j].title); | |||
console.log('item ' + j + ' link: ' + feed.items[j].link); | |||
console.log('item ' + j + ' description: ' | |||
+ feed.items[j].description); | |||
console.log('item ' + j + ' updated: ' + feed.items[j].updated); | |||
console.log('item ' + j + ' id: ' + feed.items[j].id); | |||
} | |||
} | |||
}); | |||
} | |||
}); | |||
</script> | |||
</head> | |||
<body> | |||
<h1>jFeed - jQuery feed parser plugin - test</h1> | |||
<p>Please open Firefox + Firebug console</p> | |||
</body> | |||
</html> |
@ -0,0 +1,64 @@ | |||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" | |||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> | |||
<html> | |||
<head> | |||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> | |||
<title>jFeed - jQuery feed parser plugin - test</title> | |||
<script type="text/javascript" src="jquery/jquery.js"></script> | |||
<script type="text/javascript" src="src/jfeed.js"></script> | |||
<script type="text/javascript" src="src/jfeeditem.js"></script> | |||
<script type="text/javascript" src="src/jatom.js"></script> | |||
<script type="text/javascript" src="src/jrss.js"></script> | |||
<script type="text/javascript"> | |||
jQuery(function() { | |||
var feedsUrls = ['xml/rss-091.xml', | |||
'xml/rss-092.xml', | |||
'xml/rss-10.xml', | |||
'xml/rss-20.xml', | |||
'xml/atom.xml']; | |||
jQuery().ajaxError(function(request, settings, ex) { | |||
console.log('Request error'); | |||
for(var i in ex) { | |||
console.log(i + ': ' + ex[i]); | |||
} | |||
}); | |||
for(var i = 0; i < feedsUrls.length; i++) { | |||
jQuery.getFeed({url: feedsUrls[i], success: function(feed) { | |||
console.log('feed type: ' + feed.type); | |||
console.log('feed version: ' + feed.version); | |||
console.log('feed title: ' + feed.title); | |||
console.log('feed link: ' + feed.link); | |||
console.log('feed description: ' + feed.description); | |||
console.log('feed language: ' + feed.language); | |||
console.log('feed updated: ' + feed.updated); | |||
console.log('feed items: ' + feed.items.length); | |||
for(var j = 0; j < feed.items.length; j++) { | |||
console.log('item ' + j + ' title: ' + feed.items[j].title); | |||
console.log('item ' + j + ' link: ' + feed.items[j].link); | |||
console.log('item ' + j + ' description: ' | |||
+ feed.items[j].description); | |||
console.log('item ' + j + ' updated: ' + feed.items[j].updated); | |||
console.log('item ' + j + ' id: ' + feed.items[j].id); | |||
} | |||
} | |||
}); | |||
} | |||
}); | |||
</script> | |||
</head> | |||
<body> | |||
<h1>jFeed - jQuery feed parser plugin - test</h1> | |||
<p>Please open Firefox + Firebug console</p> | |||
</body> | |||
</html> |
@ -0,0 +1,157 @@ | |||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> | |||
<?xml-stylesheet href="http://www.atomenabled.org/css/atom.css" type="text/css"?> | |||
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-US"> | |||
<title type="html">AtomEnabled.org</title> | |||
<subtitle type="html">Your one stop shop for all Atom API and syndication information.</subtitle> | |||
<link href="http://www.atomenabled.org/atom.xml" rel="self"/> | |||
<icon>http://www.atomenabled.org/favicon.ico</icon> | |||
<link href="http://www.atomenabled.org" rel="alternate" title="AtomEnabled.org" type="text/html"/> | |||
<id>tag:blogger.com,1999:blog-6356614</id> | |||
<updated>2006-09-23T19:44:56Z</updated> | |||
<generator uri="http://www.blogger.com/" version="6.72">Blogger</generator> | |||
<div class="info" xmlns="http://www.w3.org/1999/xhtml">This is an Atom formatted XML site feed. It is intended to be viewed in a Newsreader or syndicated to another site. Please visit the <a href="http://help.blogger.com/bin/answer.py?answer=697">Blogger Help</a> for more info.</div> | |||
<convertLineBreaks xmlns="http://www.blogger.com/atom/ns#">false</convertLineBreaks> | |||
<entry xmlns="http://www.w3.org/2005/Atom"> | |||
<author> | |||
<name>Sam Ruby</name> | |||
</author> | |||
<published>2006-09-23T12:42:00-07:00</published> | |||
<updated>2006-09-23T19:44:56Z</updated> | |||
<link href="http://www.atomenabled.org/2006/09/moving-toward-atom.php" rel="alternate" title="Moving Toward Atom" type="text/html"/> | |||
<id>tag:blogger.com,1999:blog-6356614.post-115904069601028798</id> | |||
<title type="html">Moving Toward Atom</title> | |||
<content type="xhtml" xml:base="http://www.atomenabled.org" xml:space="preserve"> | |||
<div xmlns="http://www.w3.org/1999/xhtml">The US Intelligence Community Metadata Working Group has issued a <a href="https://dnidata.org/education/xnotes/RSS_and_Atom_Considerations.xml">recommendation</a> that the Intelligence Community, over time, move toward adoption of Atom Syndication Format as the Community’s standard XML-based language for syndication feeds.</div> | |||
</content> | |||
<draft xmlns="http://purl.org/atom-blog/ns#">false</draft> | |||
</entry> | |||
<entry xmlns="http://www.w3.org/2005/Atom"> | |||
<author> | |||
<name>Sam Ruby</name> | |||
</author> | |||
<published>2006-08-04T13:50:00-07:00</published> | |||
<updated>2006-08-04T20:53:17Z</updated> | |||
<link href="http://www.atomenabled.org/2006/08/enabling-atom-10-on-wordpress.php" rel="alternate" title="Enabling Atom 1.0 on Wordpress" type="text/html"/> | |||
<id>tag:blogger.com,1999:blog-6356614.post-115472479762549620</id> | |||
<title type="html">Enabling Atom 1.0 on Wordpress</title> | |||
<content type="xhtml" xml:base="http://www.atomenabled.org" xml:space="preserve"> | |||
<div xmlns="http://www.w3.org/1999/xhtml">James Snell has <a href="http://www.snellspace.com/wp/?p=404">posted instructions</a> on how you can produce valid Atom 1.0 feeds with WordPress.</div> | |||
</content> | |||
<draft xmlns="http://purl.org/atom-blog/ns#">false</draft> | |||
</entry> | |||
<entry xmlns="http://www.w3.org/2005/Atom"> | |||
<author> | |||
<name>Sam Ruby</name> | |||
</author> | |||
<published>2006-07-29T21:34:00-07:00</published> | |||
<updated>2006-07-30T04:38:20Z</updated> | |||
<link href="http://www.atomenabled.org/2006/07/tri-xml-2006-presentation.php" rel="alternate" title="Tri-XML 2006 presentation" type="text/html"/> | |||
<id>tag:blogger.com,1999:blog-6356614.post-115423429120046231</id> | |||
<title type="html">Tri-XML 2006 presentation</title> | |||
<content type="xhtml" xml:base="http://www.atomenabled.org" xml:space="preserve"> | |||
<div xmlns="http://www.w3.org/1999/xhtml"> | |||
<a href="http://rollerweblogger.org/page/roller">Dave Johnson</a> gave an <a href="http://rollerweblogger.org/page/roller?entry=tri_xml_2006_presentation">excellent talk</a> on the Atom feed format and Atom Publishing Protocol. Here's the abstract: | |||
<blockquote> | |||
<span style="font-weight: bold;">Beyond blogging: Atom format and protocol</span>. Like XML-RPC and SOAP before, feeds and publishing protocols were born in the blogopshere and quickly moved beyond blogging. Nowadays, web service providers are using RSS/Atom feeds and REST-based publishing protocols as lightweight alternatives to SOAP. And developers are finding new ways to combine web services from different sites into new applications, known as "mash-ups" in the lingo of Web 2.0. If you'd like to do the same, then attend this talk to learn about the new IETF Atom feed format (RFC-4287) and the soon-to-be-finalized Atom protocol, which together form a strong foundation for REST-based web services development. | |||
</blockquote>Check it out!</div> | |||
</content> | |||
<draft xmlns="http://purl.org/atom-blog/ns#">false</draft> | |||
</entry> | |||
<entry xmlns="http://www.w3.org/2005/Atom"> | |||
<author> | |||
<name>Sam Ruby</name> | |||
</author> | |||
<published>2006-07-19T14:39:00-07:00</published> | |||
<updated>2006-07-19T23:22:18Z</updated> | |||
<link href="http://www.atomenabled.org/2006/07/atomenabled-bloggers.php" rel="alternate" title="AtomEnabled Bloggers" type="text/html"/> | |||
<id>tag:blogger.com,1999:blog-6356614.post-115334590123672226</id> | |||
<title type="html">AtomEnabled Bloggers</title> | |||
<content type="xhtml" xml:base="http://www.atomenabled.org" xml:space="preserve"> | |||
<div xmlns="http://www.w3.org/1999/xhtml">The following <a href="http://www.blogger.com/">Blogger</a>-generated but independently hosted weblogs have upgraded to <a href="http://www.ietf.org/rfc/rfc4287">Atom 1.0</a>:<ul> | |||
<li> | |||
<a href="http://atomenabled.org/">AtomEnabled.org</a> | |||
</li> | |||
<li> | |||
<a href="http://ceciliaschola.org/">St. Cecilia Schola Cantorum</a> | |||
</li> | |||
<li> | |||
<a href="http://robweir.com/blog/">An Antic Disposition</a> | |||
</li> | |||
</ul> | |||
<p>If your have a blogger-generated but independently hosted weblog, and your host supports PHP, you too can be on this list.</p> | |||
<ol> | |||
<li> | |||
<p> | |||
<b>Install the script</b> | |||
</p> | |||
<p> | |||
<a href="http://intertwingly.net/stories/2006/04/27/atom.php">Download</a> the script, and upload as <code style="font-size: larger;">atom.php</code>. This file should go in the same directory as your weblog.</p> | |||
</li> | |||
<li> | |||
<p> | |||
<b>Promote the new feed</b> | |||
</p> | |||
<p>This can be done in one of two ways:</p> | |||
<ol style="list-style-type: lower-alpha; list-style-image: none; list-style-position: outside;"> | |||
<li> | |||
<p> | |||
<b>Redirect</b> | |||
</p> | |||
<p>This is the most complete and comprehensive approach, however not all hosting providers allow users this level of control over the web server. If yours does, try adding the following to a file named <code style="font-size: larger;">.htaccess</code> to the same directory that you placed the <code style="font-size: larger;">atom.php</code>:</p> | |||
<pre style="font-size: larger; margin-left: 3em;">Redirect atom.xml http://<em>your.host.name</em>/<em>path-to-blog</em>/atom.php</pre> | |||
<p> | |||
<b>Notes:</b> these instructions are for the Apache Web Server. Instructions for other web servers, including Microsoft's IIS will differ. You will need to tailor <em>your.host.name</em> and <em>path-to-blog</em>.</p> | |||
</li> | |||
<li> | |||
<p> | |||
<b>Advertise</b> | |||
</p> | |||
<p>The other approach is to direct your existing and new subscribers to this new feed. Mention the change on your weblog. Update your auto-discovery and other links. To update your links, go into Settings / Site Feed (pictured below)<a href="http://www.atomenabled.org/uploaded_images/BloggerSiteSettings-767978.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"/> | |||
</p> | |||
<a href="http://www.atomenabled.org/uploaded_images/BloggerSiteSettings-767978.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"> | |||
<img alt="Blogger Site Settings" border="0" src="http://www.atomenabled.org/uploaded_images/BloggerSiteSettings-756299.png" style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;"/> | |||
</a> | |||
<p>Once you have navigated to that page, change the <b>Site Feed URL</b> to read:</p> | |||
<pre style="font-size: larger; margin-left: 3em;">http://<em>your.host.name</em>/<em>path-to-blog</em>/atom.php</pre> | |||
<p> | |||
<b>Notes:</b> You will need to tailor <em>your.host.name</em> and <em>path-to-blog</em>. You may also have other references on your template that need to be updated. Once complete, republish your blog via the Posting / Status tab.</p> | |||
</li> | |||
</ol> | |||
</li> | |||
</ol> | |||
<p>If you have another Blogger produced site that has upgraded to Atom 1.0, feel free to leave a pointer to your site on the <a href="http://www.intertwingly.net/wiki/pie/AtomEnabledBloggers">Atom wiki</a>. Once your feed has been verified, this weblog post will be updated.</p> | |||
</div> | |||
</content> | |||
<draft xmlns="http://purl.org/atom-blog/ns#">false</draft> | |||
</entry> | |||
<entry xmlns="http://www.w3.org/2005/Atom"> | |||
<author> | |||
<name>Sam Ruby</name> | |||
</author> | |||
<published>2005-09-15T06:27:00-07:00</published> | |||
<updated>2005-09-15T13:33:06Z</updated> | |||
<link href="http://www.atomenabled.org/2005/09/atomenableds-atom-feed.php" rel="alternate" title="AtomEnabled's Atom Feed" type="text/html"/> | |||
<id>tag:blogger.com,1999:blog-6356614.post-112679118686717868</id> | |||
<title type="html">AtomEnabled's Atom Feed</title> | |||
<content type="xhtml" xml:base="http://www.atomenabled.org" xml:space="preserve"> | |||
<div xmlns="http://www.w3.org/1999/xhtml">This site's <a href="http://www.atomenabled.org/atom.xml">Atom feed</a> has been converted to Atom 1.0. Addionally, the Feed Validator is <a href="http://feedvalidator.org/news/archives/2005/09/15/atom_03_deprecated.html">now issuing deprecation warnings</a> whenever it encounters Atom 0.3 feeds.</div> | |||
</content> | |||
<draft xmlns="http://purl.org/atom-blog/ns#">false</draft> | |||
</entry> | |||
</feed> |
@ -0,0 +1,54 @@ | |||
<?xml version="1.0" encoding="ISO-8859-1"?> | |||
<rss version="0.91"> | |||
<channel> | |||
<title>WriteTheWeb</title> | |||
<link>http://writetheweb.com</link> | |||
<description>News for web users that write back</description> | |||
<language>en-us</language> | |||
<copyright>Copyright 2000, WriteTheWeb team.</copyright> | |||
<managingEditor>editor@writetheweb.com</managingEditor> | |||
<webMaster>webmaster@writetheweb.com</webMaster> | |||
<image> | |||
<title>WriteTheWeb</title> | |||
<url>http://writetheweb.com/images/mynetscape88.gif</url> | |||
<link>http://writetheweb.com</link> | |||
<width>88</width> | |||
<height>31</height> | |||
<description>News for web users that write back</description> | |||
</image> | |||
<item> | |||
<title>Giving the world a pluggable Gnutella</title> | |||
<link>http://writetheweb.com/read.php?item=24</link> | |||
<description>WorldOS is a framework on which to build programs that work like Freenet or Gnutella -allowing distributed applications using peer-to-peer routing.</description> | |||
</item> | |||
<item> | |||
<title>Syndication discussions hot up</title> | |||
<link>http://writetheweb.com/read.php?item=23</link> | |||
<description>After a period of dormancy, the Syndication mailing list has become active again, with contributions from leaders in traditional media and Web syndication.</description> | |||
</item> | |||
<item> | |||
<title>Personal web server integrates file sharing and messaging</title> | |||
<link>http://writetheweb.com/read.php?item=22</link> | |||
<description>The Magi Project is an innovative project to create a combined personal web server and messaging system that enables the sharing and synchronization of information across desktop, laptop and palmtop devices.</description> | |||
</item> | |||
<item> | |||
<title>Syndication and Metadata</title> | |||
<link>http://writetheweb.com/read.php?item=21</link> | |||
<description>RSS is probably the best known metadata format around. RDF is probably one of the least understood. In this essay, published on my O'Reilly Network weblog, I argue that the next generation of RSS should be based on RDF.</description> | |||
</item> | |||
<item> | |||
<title>UK bloggers get organised</title> | |||
<link>http://writetheweb.com/read.php?item=20</link> | |||
<description>Looks like the weblogs scene is gathering pace beyond the shores of the US. There's now a UK-specific page on weblogs.com, and a mailing list at egroups.</description> | |||
</item> | |||
<item> | |||
<title>Yournamehere.com more important than anything</title> | |||
<link>http://writetheweb.com/read.php?item=19</link> | |||
<description>Whatever you're publishing on the web, your site name is the most valuable asset you have, according to Carl Steadman.</description> | |||
</item> | |||
</channel> | |||
</rss> |
@ -0,0 +1,38 @@ | |||
<?xml version="1.0"?> | |||
<!-- RSS generation done by 'Radio UserLand' on Fri, 13 Apr 2001 19:23:02 GMT --> | |||
<rss version="0.92"> | |||
<channel> | |||
<title>Dave Winer: Grateful Dead</title> | |||
<link>http://www.scripting.com/blog/categories/gratefulDead.html</link> | |||
<description>A high-fidelity Grateful Dead song every day. This is where we're experimenting with enclosures on RSS news items that download when you're not using your computer. If it works (it will) it will be the end of the Click-And-Wait multimedia experience on the Internet. </description> | |||
<lastBuildDate>Fri, 13 Apr 2001 19:23:02 GMT</lastBuildDate> | |||
<docs>http://backend.userland.com/rss092</docs> | |||
<managingEditor>dave@userland.com (Dave Winer)</managingEditor> | |||
<webMaster>dave@userland.com (Dave Winer)</webMaster> | |||
<cloud domain="data.ourfavoritesongs.com" port="80" path="/RPC2" registerProcedure="ourFavoriteSongs.rssPleaseNotify" protocol="xml-rpc"/> | |||
<item> | |||
<description>It's been a few days since I added a song to the Grateful Dead channel. Now that there are all these new Radio users, many of whom are tuned into this channel (it's #16 on the hotlist of upstreaming Radio users, there's no way of knowing how many non-upstreaming users are subscribing, have to do something about this..). Anyway, tonight's song is a live version of Weather Report Suite from Dick's Picks Volume 7. It's wistful music. Of course a beautiful song, oft-quoted here on Scripting News. <i>A little change, the wind and rain.</i> | |||
</description> | |||
<enclosure url="http://www.scripting.com/mp3s/weatherReportDicksPicsVol7.mp3" length="6182912" type="audio/mpeg"/> | |||
</item> | |||
<item> | |||
<description>Kevin Drennan started a <a href="http://deadend.editthispage.com/">Grateful Dead Weblog</a>. Hey it's cool, he even has a <a href="http://deadend.editthispage.com/directory/61">directory</a>. <i>A Frontier 7 feature.</i></description> | |||
<source url="http://scriptingnews.userland.com/xml/scriptingNews2.xml">Scripting News</source> | |||
</item> | |||
<item> | |||
<description><a href="http://arts.ucsc.edu/GDead/AGDL/other1.html">The Other One</a>, live instrumental, One From The Vault. Very rhythmic very spacy, you can listen to it many times, and enjoy something new every time.</description> | |||
<enclosure url="http://www.scripting.com/mp3s/theOtherOne.mp3" length="6666097" type="audio/mpeg"/> | |||
</item> | |||
<item> | |||
<description>This is a test of a change I just made. Still diggin..</description> | |||
</item> | |||
<item> | |||
<description>The HTML rendering almost <a href="http://validator.w3.org/check/referer">validates</a>. Close. Hey I wonder if anyone has ever published a style guide for ALT attributes on images? What are you supposed to say in the ALT attribute? I sure don't know. If you're blind send me an email if u cn rd ths. </description> | |||
</item> | |||
</channel> | |||
</rss> |
@ -0,0 +1,53 @@ | |||
<?xml version="1.0"?> | |||
<rdf:RDF | |||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | |||
xmlns="http://purl.org/rss/1.0/" | |||
> | |||
<channel rdf:about="http://www.xml.com/xml/news.rss"> | |||
<title>XML.com</title> | |||
<link>http://xml.com/pub</link> | |||
<description> | |||
XML.com features a rich mix of information and services | |||
for the XML community. | |||
</description> | |||
<image rdf:resource="http://xml.com/universal/images/xml_tiny.gif" /> | |||
<items> | |||
<rdf:Seq> | |||
<rdf:li resource="http://xml.com/pub/2000/08/09/xslt/xslt.html" /> | |||
<rdf:li resource="http://xml.com/pub/2000/08/09/rdfdb/index.html" /> | |||
</rdf:Seq> | |||
</items> | |||
</channel> | |||
<image rdf:about="http://xml.com/universal/images/xml_tiny.gif"> | |||
<title>XML.com</title> | |||
<link>http://www.xml.com</link> | |||
<url>http://xml.com/universal/images/xml_tiny.gif</url> | |||
</image> | |||
<item rdf:about="http://xml.com/pub/2000/08/09/xslt/xslt.html"> | |||
<title>Processing Inclusions with XSLT</title> | |||
<link>http://xml.com/pub/2000/08/09/xslt/xslt.html</link> | |||
<description> | |||
Processing document inclusions with general XML tools can be | |||
problematic. This article proposes a way of preserving inclusion | |||
information through SAX-based processing. | |||
</description> | |||
</item> | |||
<item rdf:about="http://xml.com/pub/2000/08/09/rdfdb/index.html"> | |||
<title>Putting RDF to Work</title> | |||
<link>http://xml.com/pub/2000/08/09/rdfdb/index.html</link> | |||
<description> | |||
Tool and API support for the Resource Description Framework | |||
is slowly coming of age. Edd Dumbill takes a look at RDFDB, | |||
one of the most exciting new RDF toolkits. | |||
</description> | |||
</item> | |||
</rdf:RDF> |
@ -0,0 +1,47 @@ | |||
<?xml version="1.0"?> | |||
<rss version="2.0"> | |||
<channel> | |||
<title>Liftoff News</title> | |||
<link>http://liftoff.msfc.nasa.gov/</link> | |||
<description>Liftoff to Space Exploration.</description> | |||
<language>en-us</language> | |||
<pubDate>Tue, 10 Jun 2003 04:00:00 GMT</pubDate> | |||
<lastBuildDate>Tue, 10 Jun 2003 09:41:01 GMT</lastBuildDate> | |||
<docs>http://blogs.law.harvard.edu/tech/rss</docs> | |||
<generator>Weblog Editor 2.0</generator> | |||
<managingEditor>editor@example.com</managingEditor> | |||
<webMaster>webmaster@example.com</webMaster> | |||
<item> | |||
<title>Star City</title> | |||
<link>http://liftoff.msfc.nasa.gov/news/2003/news-starcity.asp</link> | |||
<description>How do Americans get ready to work with Russians aboard the International Space Station? They take a crash course in culture, language and protocol at Russia's <a href="http://howe.iki.rssi.ru/GCTC/gctc_e.htm">Star City</a>.</description> | |||
<pubDate>Tue, 03 Jun 2003 09:39:21 GMT</pubDate> | |||
<guid>http://liftoff.msfc.nasa.gov/2003/06/03.html#item573</guid> | |||
</item> | |||
<item> | |||
<description>Sky watchers in Europe, Asia, and parts of Alaska and Canada will experience a <a href="http://science.nasa.gov/headlines/y2003/30may_solareclipse.htm">partial eclipse of the Sun</a> on Saturday, May 31st.</description> | |||
<pubDate>Fri, 30 May 2003 11:06:42 GMT</pubDate> | |||
<guid>http://liftoff.msfc.nasa.gov/2003/05/30.html#item572</guid> | |||
</item> | |||
<item> | |||
<title>The Engine That Does More</title> | |||
<link>http://liftoff.msfc.nasa.gov/news/2003/news-VASIMR.asp</link> | |||
<description>Before man travels to Mars, NASA hopes to design new engines that will let us fly through the Solar System more quickly. The proposed VASIMR engine would do that.</description> | |||
<pubDate>Tue, 27 May 2003 08:37:32 GMT</pubDate> | |||
<guid>http://liftoff.msfc.nasa.gov/2003/05/27.html#item571</guid> | |||
</item> | |||
<item> | |||
<title>Astronauts' Dirty Laundry</title> | |||
<link>http://liftoff.msfc.nasa.gov/news/2003/news-laundry.asp</link> | |||
<description>Compared to earlier spacecraft, the International Space Station has many luxuries, but laundry facilities are not one of them. Instead, astronauts have other options.</description> | |||
<pubDate>Tue, 20 May 2003 08:56:02 GMT</pubDate> | |||
<guid>http://liftoff.msfc.nasa.gov/2003/05/20.html#item570</guid> | |||
</item> | |||
</channel> | |||
</rss> |
@ -0,0 +1,67 @@ | |||
const fs = require('fs') | |||
const Discord = require('discord.js'); | |||
const Client = require('./client'); | |||
const fetch = require("node-fetch"); | |||
const { | |||
prefix, | |||
token, | |||
} = require('./config.json'); | |||
const client = new Client(); | |||
client.commands = new Discord.Collection(); | |||
const commandFiles = fs.readdirSync('./commands').filter(file => file.endsWith('.js')); | |||
for (const file of commandFiles) { | |||
const command = require(`./commands/${file}`); | |||
client.commands.set(command.name, command); | |||
} | |||
console.log(client.commands); | |||
client.once('ready', () => { | |||
console.log('Ready!'); | |||
}); | |||
client.once('reconnecting', () => { | |||
console.log('Reconnecting!'); | |||
}); | |||
client.once('disconnect', () => { | |||
console.log('Disconnect!'); | |||
}); | |||
client.on('message', async message => { | |||
if (message.author.bot) return; | |||
if (!message.content.startsWith(prefix)) return; | |||
const args = message.content.slice(prefix.length).split(/ +/); | |||
const commandName = args.shift().toLowerCase(); | |||
if (!client.commands.has(commandName)) return; | |||
const command = client.commands.get(commandName); | |||
const permitted_roles = client.commands.get(commandName)["roles"]; | |||
has_roles = false | |||
if (permitted_roles){ | |||
for(i = 0; i < permitted_roles.length; i++){ | |||
if(message.member.roles.cache.has(permitted_roles[i])){ | |||
has_roles = true | |||
} | |||
} | |||
if (!has_roles && permitted_roles.length != 0){ | |||
message.reply('You are not allowed to run this command!'); | |||
return; | |||
} | |||
} | |||
try { | |||
command.execute(message); | |||
} catch (error) { | |||
console.error(error); | |||
message.reply('There was an error trying to execute that command!'); | |||
} | |||
}); | |||
client.login(token); |
@ -0,0 +1,28 @@ | |||
{ | |||
"name": "xi_master", | |||
"version": "1.0.0", | |||
"description": "A master music bot for our xi network discord server", | |||
"author": "Fringe <yigit@yigitcolakoglu.com>", | |||
"main": "main.js", | |||
"scripts": { | |||
"start": "node main.js" | |||
}, | |||
"dependencies": { | |||
"@discordjs/opus": "^0.1.0", | |||
"cheerio": "^1.0.0-rc.3", | |||
"discord.js": "^12.2.0", | |||
"ffmpeg": "0.0.4", | |||
"fluent-ffmpeg": "^2.1.2", | |||
"googleapis": "*", | |||
"jquery": "^3.5.1", | |||
"jquery-rss": "^4.3.0", | |||
"jsdom": "^16.3.0", | |||
"node-fetch": "^2.6.0", | |||
"node-opus": "^0.3.3", | |||
"request": "^2.88.2", | |||
"rss-parser": "^3.8.0", | |||
"type": "module", | |||
"vanilla-rss": "^1.4.0", | |||
"ytdl-core": "^3.0.0" | |||
} | |||
} |
@ -0,0 +1 @@ | |||
node_modules |
@ -0,0 +1,15 @@ | |||
FROM node:lts | |||
WORKDIR /usr/src/app | |||
COPY package*.json ./ | |||
RUN npm ci | |||
# If you are building your code for production | |||
# # RUN npm ci --only=production | |||
COPY . . | |||
CMD [ "node", "main.js" ] | |||
@ -0,0 +1,28 @@ | |||
Locations list: | |||
1.Organisation 56/68 | |||
2.Domain 732/58 | |||
3.SPF records 1216/64 | |||
4.Subdomain bruteforce 1216/283 | |||
5.passive DNS 1216/520 | |||
6.assetfinder + plausability check 1216/742 | |||
7.Resolve 2202/330 | |||
8.List of Subdomains 2014/666 | |||
9.altdns 2391/666 | |||
10.IPS 2932/328 | |||
11.Masscan all TCP ports 3309/333 | |||
12.VHost discovery 2932/666 | |||
13.Open ports 3721/333 | |||
14.GetAllURLs 969/1116 | |||
15.Check Github 967/1341 | |||
16.Search Engines 966/1566 | |||
17.Subdomain Takeover 2020/1084 | |||
18.httprobe 2392/1084 | |||
19.List of IPs with HTTP=service 3196/1076 | |||
20.Nmap service enumeratiom 4200/549 | |||
21.Vulnerability scan4200/987 | |||
22.Login brute force 4590/990 | |||
In our house, our only source of income is my dad. Since the outbreak we have experienced a recession nationwide, effecting my daily live. On top of that, I'm currently |
@ -0,0 +1,16 @@ | |||
const { Client, Collection } = require('discord.js'); | |||
module.exports = class extends Client { | |||
constructor(config) { | |||
super({ | |||
disableEveryone: true, | |||
disabledEvents: ['TYPING_START'], | |||
}); | |||
this.commands = new Collection(); | |||
this.queue = new Map(); | |||
this.config = config; | |||
} | |||
}; |
@ -0,0 +1,27 @@ | |||
module.exports = { | |||
name: 'downgrade', | |||
channels: ['734387503464710165'], | |||
description: 'Downgrade a user!', | |||
roles: ['732345527143759943'], | |||
execute(message,args) { | |||
var roles_hierarchy = [ | |||
'732558019409346603', // 'kiddie, | |||
'732618552661770241', // 'hunter', | |||
'732618853355356192', // 'hacker', | |||
'732618650158366770' // 'mentor' | |||
]; | |||
var current_index = null | |||
const member = message.mentions.members.first(); | |||
roles_hierarchy.forEach(function(item, index){ | |||
if (member._roles[0] == item) current_index = index; | |||
}); | |||
if(current_index == 0){ | |||
return message.channel.send("This user is already at the lowest level!") | |||
} | |||
console.log(current_index); | |||
member.roles.remove(roles_hierarchy[current_index]); | |||
member.roles.add(roles_hierarchy[current_index - 1]); | |||
return message.channel.send("User downgraded successfully!") | |||
}, | |||
}; |
@ -0,0 +1,94 @@ | |||
const { | |||
mongo_url, | |||
trello_token, | |||
trello_key | |||
} = require('../config.json'); | |||
const { | |||
userModel, | |||
teamModel, | |||
} = require('./schemas.js'); | |||
let mongoose = require('mongoose'); | |||
var Trello = require('trello-node-api')(trello_key, trello_token); | |||
const fetch = require('node-fetch'); | |||
module.exports = { | |||
name: 'email', | |||
channels: ['dm'], | |||
description: 'Update the email address of the user', | |||
async execute(message) { | |||
let email = message.content.split(" ")[1]; | |||
if(!email){ | |||
return message.reply("You must supply an email!") | |||
} | |||
if(!/^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/.test(email)){ | |||
return message.reply("You must supply an email address, not some other input!."); | |||
} | |||
var member_id = message.author.id; | |||
try { | |||
await mongoose.connect( mongo_url, {useNewUrlParser: true, useUnifiedTopology: true}, () => null ); | |||
}catch (error) { | |||
console.log("ERROR WITH MONGODB CONNECTION"); | |||
} | |||
const user_data = await userModel.find({_id: member_id}, "team_id email trello_id"); | |||
if(user_data.length == 0){ | |||
return message.reply("You should be a member of the ξ.network discord channel to run this command!") | |||
} | |||
if(user_data[0].email && user_data[0].team_id !== 0){ | |||
console.log("Deleting user") | |||
let team_data = await teamModel.find({_id: user_data[0].team_id}, "board_id"); | |||
await fetch(`https://api.trello.com/1/boards/${team_data[0].board_id}/members/${user_data[0].trello_id}?key=${trello_key}&token=${trello_token}`, { | |||
method: 'DELETE' | |||
}) | |||
.catch(err => console.error(err)); | |||
} | |||
if(user_data[0].team_id !== "0"){ | |||
let team_data = await teamModel.find({_id: user_data[0].team_id}, "board_id creator"); | |||
let type = "normal"; | |||
if(team_data[0].creator == member_id){ | |||
type = "admin" | |||
} | |||
let addition = await fetch(`https://api.trello.com/1/boards/${team_data[0].board_id}/members?key=${trello_key}&token=${trello_token}&email=${email}&type=${type}`, { | |||
method: 'PUT', | |||
}) | |||
.catch(err => console.error(err)); | |||
let data = await addition.json() | |||
let result = await userModel.findOneAndUpdate( | |||
{_id: member_id}, | |||
{email: email, trello_id: data.memberships[data.memberships.length - 1].idMember}, | |||
{ | |||
new: true, | |||
runValidators: true, | |||
useFindAndModify: false | |||
} | |||
); | |||
}else{ | |||
userModel.findOneAndUpdate( | |||
{_id: member_id}, | |||
{email: email}, | |||
{ | |||
new: true, | |||
runValidators: true, | |||
useFindAndModify: false | |||
} | |||
); | |||
} | |||
message.reply("Email set successfully! You should receive an invite email from trello if you are a member of a team.") | |||
}, | |||
}; |
@ -0,0 +1,45 @@ | |||
module.exports = { | |||
name: 'role_message', | |||
channels: ['734387503464710165'], | |||
description: 'Send the role message!', | |||
roles: ['732345527143759943'], | |||
async execute(message) { | |||
let message_new = await message.client.channels.cache.get("734387503464710165").send(`React to this message to give yourself a role. | |||
:iphone: : mobile development | |||
:nut_and_bolt: : hardware development | |||
:factory: : backend development | |||
:eyeglasses: : frontend development | |||
:spider:(spider) : web development | |||
:globe_with_meridians: : network engineering | |||
:penguin: : unix/linux | |||
:spider_web: : web security | |||
:closed_lock_with_key: : cryptology | |||
:upside_down: : reverse engineering | |||
:police_officer: : network security | |||
`) | |||
Promise.all([ | |||
message_new.react('🔐'), | |||
message_new.react('🙃'), | |||
message_new.react('📱'), | |||
message_new.react('🔩'), | |||
message_new.react('🕸️'), | |||
message_new.react('🏭'), | |||
message_new.react('🕷️'), | |||
message_new.react('🌐'), | |||
message_new.react('👮'), | |||
message_new.react('🐧') | |||
]) | |||
.catch(() => console.error('One of the emojis failed to react.')); | |||
} | |||
} |
@ -0,0 +1,26 @@ | |||
let mongoose = require('mongoose') | |||
module.exports = { | |||
userModel : mongoose.model('users', new mongoose.Schema({ | |||
_id: String, | |||
joined_at: Number, | |||
team_id: String, | |||
profession: Array, | |||
rank: Number, | |||
xp: Number, | |||
email: String, | |||
trello_id: String | |||
})), | |||
teamModel: mongoose.model('teams', new mongoose.Schema({ | |||
_id: mongoose.Types.ObjectId, | |||
team_name: String, | |||
creator: String, | |||
mods: Array, | |||
member_role: String, | |||
mod_role: String, | |||
text_channel: String, | |||
voice_channel: String, | |||
board_id: String | |||
})) | |||
} |
@ -0,0 +1,53 @@ | |||
const { | |||
mongo_url, | |||
trello_token, | |||
trello_key | |||
} = require('../config.json'); | |||
const { | |||
userModel, | |||
teamModel, | |||
} = require('./schemas.js'); | |||
let mongoose = require('mongoose'); | |||
let Trello = require('trello-node-api')(trello_key, trello_token); | |||
module.exports = { | |||
name: 'close', | |||
family: 'team', | |||
channels: ['734387503464710165'], | |||
description: 'Close the team! ', | |||
async execute(message) { | |||
var member_id = message.member.id; | |||
try { | |||
await mongoose.connect( mongo_url, {useNewUrlParser: true, useUnifiedTopology: true}, () => null); | |||
}catch (error) { | |||
console.log("could not connect"); | |||
} | |||
const user_data = await userModel.find({_id: member_id},"team_id trello_id email"); | |||
const team_id = user_data[0].team_id | |||
if(team_id == '0'){ | |||
return message.reply('You must be in a team to quit!'); | |||
} | |||
var teamdata = await teamModel.find({ _id :team_id },'member_role mod_role text_channel voice_channel mods board_id'); | |||
var team = teamdata[0]; | |||
message.guild.roles.fetch(team.member_role).then((role) => role.delete()); | |||
message.guild.roles.fetch(team.mod_role).then((role) => role.delete()); | |||
message.client.channels.fetch(team.text_channel).then((channel) => channel.delete()); | |||
message.client.channels.fetch(team.voice_channel).then((channel) => channel.delete()); | |||
let old_team = new teamModel(team); | |||
old_team.remove(); | |||
Trello.board.del(team.board_id) | |||
.catch(function (error) { | |||
console.log('error', error); | |||
}); | |||
userModel.updateMany({team_id: team_id}, { team_id: 0 }, function(err, res) {}); | |||
message.channel.send("Team closed successfully!") | |||
}, | |||
} |
@ -0,0 +1,159 @@ | |||
const { | |||
mongo_url, | |||
trello_token, | |||
trello_key | |||
} = require('../config.json'); | |||
const { | |||
userModel, | |||
teamModel, | |||
} = require('./schemas.js'); | |||
let mongoose = require('mongoose'); | |||
var Trello = require('trello-node-api')(trello_key, trello_token); | |||
const fetch = require('node-fetch'); | |||
const { strict } = require('assert'); | |||
const { parse } = require('path'); | |||
const allowed_chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"; | |||
module.exports = { | |||
name: 'create', | |||
family: 'team', | |||
channels: ['734387503464710165'], | |||
description: 'Create a team', | |||
async execute(message) { | |||
let team_name = message.content.split(" ")[2]; | |||
if(!team_name){ | |||
return message.reply("You must supply a team name!") | |||
} | |||
if(team_name.length > 20){ | |||
return message.reply("Team names can be 20 letters max."); | |||
} | |||
for (let i = 0; i < team_name.length; i++) { | |||
if(allowed_chars.indexOf(team_name.charAt(i)) == -1){ | |||
return message.reply("Team names can only have letters and underscore"); | |||
} | |||
} | |||
var member_id = message.member.id; | |||
try { | |||
await mongoose.connect( mongo_url, {useNewUrlParser: true, useUnifiedTopology: true}, () => null ); | |||
}catch (error) { | |||
console.log("ERROR WITH MONGODB CONNECTION"); | |||
} | |||
const user_data = await userModel.find({_id: member_id}, "team_id email"); | |||
team = user_data[0].team_id | |||
if(team !== '0'){ | |||
return message.reply("You already are in a team!") | |||
} | |||
const teams_search = await teamModel.find({team_name: team_name}, "id") | |||
if(teams_search.length != 0){ | |||
return message.reply("A team with that name already exists!") | |||
} | |||
let regular_role = await message.guild.roles.create({ | |||
data: { | |||
name: team_name, | |||
color: 'AQUA', | |||
}, | |||
reason: 'This is the role for the members of ' + team_name, | |||
}) | |||
let mod_role = await message.guild.roles.create({ | |||
data: { | |||
name: team_name + "-mod", | |||
color: 'LUMINOUS_VIVID_PINK', | |||
}, | |||
reason: 'This is the role for the mods of ' + team_name, | |||
}) | |||
let text_channel = await message.guild.channels.create(team_name, { | |||
type: 'text', | |||
permissionOverwrites: [ | |||
{ | |||
id: regular_role.id, | |||
allow: ['VIEW_CHANNEL', 'SEND_MESSAGES', 'ATTACH_FILES', 'EMBED_LINKS'], | |||
}, | |||
{ | |||
id: mod_role.id, | |||
allow: ['VIEW_CHANNEL', 'SEND_MESSAGES', 'ATTACH_FILES', 'EMBED_LINKS', 'MENTION_EVERYONE', 'MANAGE_MESSAGES', ], | |||
}, | |||
], | |||
}); | |||
let voice_channel = await message.guild.channels.create(team_name, { | |||
type: 'voice', | |||
permissionOverwrites: [ | |||
{ | |||
id: regular_role.id, | |||
allow: ['CONNECT', 'SPEAK'], | |||
}, | |||
{ | |||
id: mod_role.id, | |||
allow: ['CONNECT', 'SPEAK', 'MUTE_MEMBERS', 'STREAM', 'PRIORITY_SPEAKER' ], | |||
}, | |||
], | |||
}); | |||
message.member.roles.add(mod_role.id); | |||
text_channel.setParent('734080794783383635', { lockPermissions: false }) | |||
voice_channel.setParent('734080915122290778', { lockPermissions: false }) | |||
board = await Trello.board.create({name: team_name + " TODOS"}) | |||
let id = mongoose.Types.ObjectId(); | |||
let new_team = new teamModel({ | |||
_id: id, | |||
team_name: team_name, | |||
creator: member_id, | |||
member_role: regular_role.id, | |||
mod_role: mod_role.id, | |||
text_channel: text_channel.id, | |||
voice_channel: voice_channel.id, | |||
board_id: board.id | |||
}) | |||
await new_team.save(); | |||
await userModel.findOneAndUpdate( | |||
{_id: member_id}, | |||
{team_id: id}, | |||
{ | |||
new: true, | |||
runValidators: true, | |||
useFindAndModify: false | |||
} | |||
); | |||
if(!user_data[0].email){ | |||
message.author.send("You were added to a team but do not have an email on the system. You need an email to access the trello board! Add your email after the !email prefix to set your email address.") | |||
}else{ | |||
let addition = await fetch(`https://api.trello.com/1/boards/${board.id}/members?key=${trello_key}&token=${trello_token}&email=${user_data[0].email}&type=admin`, { | |||
method: 'PUT' | |||
}) | |||
.catch(err => console.error(err)); | |||
let data = await addition.json() | |||
let result = await userModel.findOneAndUpdate( | |||
{_id: member_id}, | |||
{email: user_data[0].email, trello_id: data.members[data.members.length - 1].idMember}, | |||
{ | |||
new: true, | |||
runValidators: true, | |||
useFindAndModify: false | |||
} | |||
); | |||
} | |||
return message.reply("Team created succesfully!") | |||
}, | |||
}; |
@ -0,0 +1,77 @@ | |||
const { | |||
mongo_url, | |||
trello_token, | |||
trello_key | |||
} = require('../config.json'); | |||
const { | |||
userModel, | |||
teamModel, | |||
} = require('./schemas.js'); | |||
let mongoose = require('mongoose'); | |||
module.exports = { | |||
name: 'elevate', | |||
family: 'team', | |||
channels: ['734387503464710165'], | |||
description: 'Elevate a user in a team ', | |||
async execute(message) { | |||
let targets = message.mentions.members | |||
const member_id = message.member.id; | |||
if(targets.size == 0){ | |||
return message.reply("You must supply at least one member!") | |||
}else if(targets.size > 20){ | |||
return message.reply("You can elevate at most 20 users!") | |||
} | |||
try { | |||
await mongoose.connect( mongo_url, {useNewUrlParser: true, useUnifiedTopology: true}, () => null ); | |||
}catch (error) { | |||
console.log("ERROR WITH MONGODB CONNECTION"); | |||
} | |||
const user_data = await userModel.find({_id: member_id}, "team_id"); | |||
if(user_data[0].team_id === "0"){ | |||
return message.reply("You must be in a team to elevate a user!"); | |||
} | |||
const team_data = await teamModel.find({_id: user_data[0].team_id}, "creator mods team_name member_role mod_role"); | |||
const team = team_data[0] | |||
let mods = team.mods | |||
if(member_id !== team.creator && team.mods.indexOf(member_id) === -1){ | |||
return message.reply("You do not have enough privileges for this action!") | |||
} | |||
targets.forEach(async(value, key, map) => { | |||
let target_data = await userModel.find({_id: key}, "team_id"); | |||
if(target_data[0].team_id == team._id){ | |||
let mod_index = team.mods.indexOf(key) | |||
if(mod_index == -1){ | |||
value.roles.remove(team.member_role); | |||
value.roles.add(team.mod_role); | |||
mods.push(key); | |||
let result = await teamModel.findOneAndUpdate( | |||
{_id: team._id}, | |||
{mods: mods}, | |||
{ | |||
new: true, | |||
runValidators: true, | |||
useFindAndModify: false | |||
} | |||
); | |||
message.channel.send(`Elevated user <@${key}>`) | |||
}else{ | |||
message.channel.send(`<@${key}> already elevated!`) | |||
} | |||
}else{ | |||
message.channel.send(`Can't elavate user <@${key}>`); | |||
} | |||
}); | |||
}, | |||
}; |
@ -0,0 +1,103 @@ | |||
const { | |||
mongo_url, | |||
trello_token, | |||
trello_key | |||
} = require('../config.json'); | |||
const { | |||
userModel, | |||
teamModel, | |||
} = require('./schemas.js'); | |||
let mongoose = require('mongoose'); | |||
const fetch = require('node-fetch'); | |||
module.exports = { | |||
name: 'kick', | |||
family: 'team', | |||
channels: ['734387503464710165'], | |||
description: 'Add user to team', | |||
async execute(message) { | |||
let targets = message.mentions.members | |||
const member_id = message.member.id; | |||
if(targets.size == 0){ | |||
return message.reply("You must supply at least one member!") | |||
}else if(targets.size > 20){ | |||
return message.reply("You can add at most 20 users!") | |||
} | |||
try { | |||
await mongoose.connect( mongo_url, {useNewUrlParser: true, useUnifiedTopology: true}, () => null ); | |||
}catch (error) { | |||
console.log("ERROR WITH MONGODB CONNECTION"); | |||
} | |||
const user_data = await userModel.find({_id: member_id}, "team_id"); | |||
if(user_data[0].team_id === "0"){ | |||
return message.reply("You must be in a team to kick a user!"); | |||
} | |||
const team_data = await teamModel.find({_id: user_data[0].team_id}, | |||
"creator board_id mods team_name member_role mod_role"); | |||
const team = team_data[0] | |||
if(member_id !== team.creator && team.mods.indexOf(member_id) === -1){ | |||
return message.reply("You do not have enough privileges for this action!") | |||
} | |||
let mods = team.mods | |||
targets.forEach(async(value, key, map) => { | |||
if(key == member_id){ | |||
return message.reply("You cannot kick yourself!") | |||
}else if (key == team.creator){ | |||
return message.reply("You cannot kick the creator!") | |||
} | |||
let target_data = await userModel.find({_id: key}, "team_id trello_id email"); | |||
if(target_data[0].team_id == team._id){ | |||
let mod_index = team.mods.indexOf(key) | |||
if(mod_index == -1){ | |||
value.roles.remove(team.member_role) | |||
}else{ | |||
value.roles.remove(team.mod_role) | |||
mods.splice(mod_index, 1) | |||
let result = await teamModel.findOneAndUpdate( | |||
{_id: team._id}, | |||
{mods: mods}, | |||
{ | |||
new: true, | |||
runValidators: true, | |||
useFindAndModify: false | |||
} | |||
); | |||
} | |||
let result = await userModel.findOneAndUpdate( | |||
{_id: key}, | |||
{team_id: "0"}, | |||
{ | |||
new: true, | |||
runValidators: true, | |||
useFindAndModify: false | |||
} | |||
); | |||
message.client.users.fetch(key).then((user) => user.send(`You have been kicked from the team ${team.team_name}`)) | |||
if(target_data[0].email){ | |||
console.log("Deleting user from trello") | |||
await fetch(`https://api.trello.com/1/boards/${team.board_id}/members/${target_data[0].trello_id}?key=${trello_key}&token=${trello_token}`, { | |||
method: 'DELETE' | |||
}) | |||
.catch(err => console.error(err)); | |||
} | |||
message.channel.send(`Kicked user <@${key}>`) | |||
}else{ | |||
message.channel.send(`Can't kick user <@${key}>`); | |||
} | |||
}); | |||
}, | |||
}; |
@ -0,0 +1,81 @@ | |||
const { | |||
mongo_url, | |||
trello_token, | |||
trello_key | |||
} = require('../config.json'); | |||
const { | |||
userModel, | |||
teamModel, | |||
} = require('./schemas.js'); | |||
let mongoose = require('mongoose'); | |||
module.exports = { | |||
name: 'lower', | |||
family: 'team', | |||
channel: ['734387503464710165'], | |||
description: 'Lower a user in a team ', | |||
async execute(message) { | |||
let targets = message.mentions.members | |||
const member_id = message.member.id; | |||
if(targets.size == 0){ | |||
return message.reply("You must supply at least one member!") | |||
}else if(targets.size > 20){ | |||
return message.reply("You can lower at most 20 users!") | |||
} | |||
try { | |||
await mongoose.connect( mongo_url, {useNewUrlParser: true, useUnifiedTopology: true}, () => null ); | |||
}catch (error) { | |||
console.log("ERROR WITH MONGODB CONNECTION"); | |||
} | |||
const user_data = await userModel.find({_id: member_id}, "team_id"); | |||
if(user_data[0].team_id === "0"){ | |||
return message.reply("You must be in a team to lower a user!"); | |||
} | |||
const team_data = await teamModel.find({_id: user_data[0].team_id}, "creator mods team_name member_role mod_role"); | |||
const team = team_data[0] | |||
let mods = team.mods | |||
if(member_id !== team.creator && team.mods.indexOf(member_id) === -1){ | |||
return message.reply("You do not have enough privileges for this action!") | |||
} | |||
targets.forEach(async(value, key, map) => { | |||
let target_data = await userModel.find({_id: key}, "team_id"); | |||
if(target_data[0].team_id == team._id){ | |||
if(key == member_id){ | |||
return message.reply("You cannot lower yourself!") | |||
}else if (key == team.creator){ | |||
return message.reply("You cannot lower the creator!") | |||
} | |||
if(mod_index !== -1){ | |||
value.roles.add(team.member_role); | |||
value.roles.remove(team.mod_role); | |||
mods.splice(mod_index, 1) | |||
let result = await teamModel.findOneAndUpdate( | |||
{_id: team._id}, | |||
{mods: mods}, | |||
{ | |||
new: true, | |||
runValidators: true, | |||
useFindAndModify: false | |||
} | |||
); | |||
message.channel.send(`Lowered user <@${key}>`) | |||
}else{ | |||
message.channel.send(`<@${key}> not a mod!`) | |||
} | |||
}else{ | |||
message.channel.send(`Can't lower user <@${key}>`); | |||
} | |||
}); | |||
}, | |||
}; |
@ -0,0 +1,87 @@ | |||
const { | |||
mongo_url, | |||
trello_token, | |||
trello_key | |||
} = require('../config.json'); | |||
const { | |||
userModel, | |||
teamModel, | |||
} = require('./schemas.js'); | |||
let mongoose = require('mongoose'); | |||
var Trello = require('trello-node-api')(trello_key, trello_token); | |||
const fetch = require('node-fetch'); | |||
const { strict } = require('assert'); | |||
const { parse } = require('path'); | |||
module.exports = { | |||
name: 'quit', | |||
family: 'team', | |||
channels: ['734387503464710165'], | |||
description: 'Quit from a team', | |||
async execute(message) { | |||
var member_id = message.member.id; | |||
try { | |||
await mongoose.connect( mongo_url, {useNewUrlParser: true, useUnifiedTopology: true}, () => null); | |||
}catch (error) { | |||
console.log("could not connect"); | |||
} | |||
const user_data = await userModel.find({_id: member_id},"team_id trello_id email"); | |||
const team_id = user_data[0].team_id | |||
if(team_id == '0'){ | |||
return message.reply('You must be in a team to quit!'); | |||
} | |||
const filter = { _id : member_id }; | |||
const update = { team_id : '0' }; | |||
var def = await userModel.findOneAndUpdate(filter, update,{ | |||
new: true, | |||
runValidators: true, | |||
useFindAndModify: false | |||
}); | |||
var teamdata = await teamModel.find({ _id :team_id },'member_role mod_role text_channel voice_channel mods board_id'); | |||
var team = teamdata[0]; | |||
var mods = team.mods; | |||
let mod_index = team.mods.indexOf(member_id) | |||
if(mod_index === -1){ | |||
message.member.roles.remove(team.member_role) | |||
}else{ | |||
message.member.roles.remove(team.mod_role) | |||
mods.splice(mod_index, 1) | |||
} | |||
teamModel.findOneAndUpdate({_id :team_id},{mods : mods}); | |||
if(user_data[0].email){ | |||
await fetch(`https://api.trello.com/1/boards/${team.board_id}/members/${user_data[0].trello_id}?key=${trello_key}&token=${trello_token}`, { | |||
method: 'DELETE' | |||
}) | |||
.catch(err => console.error(err)); | |||
} | |||
let team_members = await userModel.find({team_id: team_id}) | |||
if(team_members.length == 0){ | |||
message.channel.send("No users left in this team. Deleting"); | |||
message.guild.roles.fetch(team.member_role).then((role) => role.delete()); | |||
message.guild.roles.fetch(team.mod_role).then((role) => role.delete()); | |||
message.client.channels.fetch(team.text_channel).then((channel) => channel.delete()); | |||
message.client.channels.fetch(team.voice_channel).then((channel) => channel.delete()); | |||
team.mods = mods; | |||
let old_team = new teamModel(team); | |||
old_team.remove(); | |||
Trello.board.del(team.board_id) | |||
.catch(function (error) { | |||
console.log('error', error); | |||
}); | |||
} | |||
return message.reply('Done!'); | |||
}, | |||
}; |
@ -0,0 +1,90 @@ | |||
const { | |||
mongo_url, | |||
trello_token, | |||
trello_key | |||
} = require('../config.json'); | |||
const { | |||
userModel, | |||
teamModel, | |||
} = require('./schemas.js'); | |||
let mongoose = require('mongoose'); | |||
const fetch = require('node-fetch'); | |||
module.exports = { | |||
name: 'add', | |||
family: 'team', | |||
channels: ['734387503464710165'], | |||
description: 'Add user to team', | |||
async execute(message) { | |||
let targets = message.mentions.members | |||
const member_id = message.member.id; | |||
if(targets.size == 0){ | |||
return message.reply("You must supply at least one member!") | |||
}else if(targets.size > 20){ | |||
return message.reply("You can add at most 20 users!") | |||
} | |||
try { | |||
await mongoose.connect( mongo_url, {useNewUrlParser: true, useUnifiedTopology: true}, () => null ); | |||
}catch (error) { | |||
console.log("ERROR WITH MONGODB CONNECTION"); | |||
} | |||
const user_data = await userModel.find({_id: member_id}, "team_id"); | |||
if(user_data[0].team_id === "0"){ | |||
return message.reply("You must be in a team to add a user!"); | |||
} | |||
const team_data = await teamModel.find({_id: user_data[0].team_id}, "creator mods team_name member_role board_id"); | |||
const team = team_data[0] | |||
if(member_id !== team.creator && team.mods.indexOf(member_id) === -1){ | |||
return message.reply("You do not have enough privileges for this action!") | |||
} | |||
targets.forEach(async(value, key, map) => { | |||
let target_data = await userModel.find({_id: key}, "team_id email"); | |||
if(target_data[0].team_id === "0"){ | |||
value.roles.add(team.member_role) | |||
let result = await userModel.findOneAndUpdate( | |||
{_id: key}, | |||
{team_id: team._id}, | |||
{ | |||
new: true, | |||
runValidators: true, | |||
useFindAndModify: false | |||
} | |||
); | |||
message.client.users.fetch(key).then((user) => user.send(`You have been added to the team ${team.team_name}`)) | |||
if(!target_data[0].email){ | |||
message.client.users.fetch(key).then((user) => user.send("You need an email to access the team's trello board! Add your email after the !email prefix to set your email address.")) | |||
}else{ | |||
let addition = await fetch(`https://api.trello.com/1/boards/${team.board_id}/members?key=${trello_key}&token=${trello_token}&email=${target_data[0].email}&type=normal`, { | |||
method: 'PUT' | |||
}) | |||
.catch(err => console.error(err)); | |||
let data = await addition.json() | |||
let result = await userModel.findOneAndUpdate( | |||
{_id: key}, | |||
{email: target_data[0].email, trello_id: data.memberships[data.memberships.length - 1].idMember}, | |||
{ | |||
new: true, | |||
runValidators: true, | |||
useFindAndModify: false | |||
} | |||
); | |||
} | |||
message.channel.send(`Added user <@${key}>`) | |||
}else{ | |||
message.channel.send(`Can't add user <@${key}>`); | |||
} | |||
}); | |||
}, | |||
}; |
@ -0,0 +1,28 @@ | |||
module.exports = { | |||
name: 'upgrade', | |||
channels: ['734387503464710165'], | |||
description: 'Upgrade a user!', | |||
roles: ['732345527143759943'], | |||
execute(message,args) { | |||
var roles_hierarchy = [ | |||
'732558019409346603', // 'kiddie, | |||
'732618552661770241', // 'hunter', | |||
'732618853355356192', // 'hacker', | |||
'732618650158366770' // 'mentor' | |||
]; | |||
var current_index = null | |||
const member = message.mentions.members.first(); | |||
roles_hierarchy.forEach(function(item, index){ | |||
if (member._roles[0] == item) current_index = index; | |||
}); | |||
if(current_index == roles_hierarchy.length - 1){ | |||
return message.channel.send("This user is already at the highest level!") | |||
} | |||
console.log(current_index); | |||
member.roles.remove(roles_hierarchy[current_index]) | |||
member.roles.add(roles_hierarchy[current_index + 1]); | |||
return message.channel.send("User upgraded successfully!") | |||
}, | |||
}; |
@ -0,0 +1,282 @@ | |||
const fs = require('fs') | |||
const Discord = require('discord.js'); | |||
const Client = require('./client'); | |||
let mongoose = require('mongoose'); | |||
const { | |||
prefix, | |||
token, | |||
mongo_url, | |||
role_message_id | |||
} = require('./config.json'); | |||
const { | |||
userModel, | |||
teamModel, | |||
} = require('./commands/schemas.js'); | |||
const client = new Client({ partials: ['MESSAGE', 'CHANNEL', 'REACTION'] }); | |||
client.commands = new Discord.Collection(); | |||
const commandFiles = fs.readdirSync('./commands').filter(file => file.endsWith('.js')); | |||
for (const file of commandFiles) { | |||
const command = require(`./commands/${file}`); | |||
let prefix = "" | |||
if(!command.name) continue; | |||
if(command.family){ | |||
prefix = command.family + "_" | |||
} | |||
client.commands.set(prefix + command.name, command); | |||
} | |||
console.log(client.commands); | |||
client.once('ready', async () => { | |||
console.log('Ready!'); | |||
async function delete_messages(){ | |||
let fetched; | |||
channel = client.channels.cache.get("734387503464710165") | |||
message_manager = channel.messages | |||
do { | |||
fetched = await message_manager.fetch({ limit: 100 }); | |||
fetched.delete(role_message_id) | |||
channel.bulkDelete(fetched); | |||
} | |||
while(fetched.size >= 3); | |||
} | |||
await delete_messages(); | |||
var minutes = 1, interval = minutes * 60 * 1000; | |||
setInterval(delete_messages, interval); | |||
}); | |||
client.once('reconnecting', () => { | |||
console.log('Reconnecting!'); | |||
}); | |||
client.once('disconnect', () => { | |||
console.log('Disconnect!'); | |||
}); | |||
client.on('message', async message => { | |||
if (message.author.bot) return; | |||
if (!message.content.startsWith(prefix)) return; | |||
const args = message.content.slice(prefix.length).split(/ +/); | |||
const c1 = args.shift().toLowerCase(); | |||
let c2 = args.shift(); | |||
if(c2){ | |||
c2 = c2.toLowerCase() | |||
} | |||
var commandName = null; | |||
if (client.commands.has(c1)){ | |||
commandName = c1; | |||
}else if(client.commands.has(c1 + "_" + c2)){ | |||
commandName = c1 + "_" + c2; | |||
}else{ | |||
return; | |||
} | |||
const command = client.commands.get(commandName); | |||
const permitted_roles = client.commands.get(commandName)["roles"]; | |||
const permitted_channels = client.commands.get(commandName)["channels"] | |||
has_roles = false | |||
if (permitted_roles){ | |||
for(i = 0; i < permitted_roles.length; i++){ | |||
if(message.member.roles.cache.has(permitted_roles[i])){ | |||
has_roles = true | |||
} | |||
} | |||
if (!has_roles){ | |||
message.reply('You are not allowed to run this command!'); | |||
return; | |||
} | |||
} | |||
if(permitted_channels){ | |||
msg_channel = message.channel; | |||
channel_allowed = false | |||
for(i = 0; i < permitted_channels.length; i++){ | |||
if(permitted_channels[i] == "dm" && msg_channel instanceof Discord.DMChannel){ | |||
channel_allowed = true; | |||
break; | |||
}else if(permitted_channels[i] == msg_channel.id){ | |||
channel_allowed = true; | |||
break; | |||
} | |||
} | |||
if(!channel_allowed){ | |||
return; | |||
} | |||
} | |||
try { | |||
command.execute(message,args); | |||
} catch (error) { | |||
console.error(error); | |||
message.reply('There was an error trying to execute that command!'); | |||
} | |||
}); | |||
client.on('guildMemberAdd', member => { | |||
let new_user = new userModel({ | |||
_id: member.id, | |||
joined_at: Date.now(), | |||
team_id: "0", | |||
profession: "", | |||
rank: 1, | |||
xp: 0, | |||
email: "", | |||
trello_id: "" | |||
}) | |||
member.guild.channels.cache.get('734387938418360362').send("Welcome <@"+ member.id +">. Xi up!"); | |||
member.roles.add('732558019409346603'); | |||
try { | |||
mongoose.connect( mongo_url, {useNewUrlParser: true, useUnifiedTopology: true}, () => null ); | |||
let db = mongoose.connection; | |||
db.once("open", function callback () { | |||
new_user.save(); | |||
}); | |||
}catch (error) { | |||
console.log("ERROR WITH MONGODB CONNECTION"); | |||
} | |||
}); | |||
const reaction_to_prof = { | |||
"🔐" : ["734453192921710604" ,"Cryptology"], | |||
"🙃" : ["734453691318403072" ,"Reverse Engineer"], | |||
"📱" : ["734453796306026576" ,"Mobile Developer"], | |||
"🔩" : ["734453830669959218" ,"Hardware Developer"], | |||
"🕸️" : ["734453917345120316" ,"Web security Expert"], | |||
"🏭" : ["734453944700502186" ,"Backend Developer"], | |||
"🕷️" : ["734454002082775040" ,"Web developer"], | |||
"🌐" : ["734454060417024072" ,"Network Engineer"], | |||
"👮" : ["734454093833175151" ,"Network Security "], | |||
"🐧" : ["734454127551053924" ,"Linux Guru"] | |||
}; | |||
const limits = { | |||
1 : 1, | |||
2 : 4, | |||
3 : 6, | |||
4 : 0, | |||
5 : 0 | |||
} | |||
client.on('messageReactionAdd', async (reaction, user) => { | |||
if(reaction.message.id === role_message_id){ | |||
if (reaction.partial) { | |||
try { | |||
await reaction.fetch(); | |||
} catch (error) { | |||
console.log('Something went wrong when fetching the message: ', error); | |||
return; | |||
} | |||
} | |||
let emoji = reaction.emoji.name; | |||
let member = await reaction.message.guild.members.fetch(user.id); | |||
try { | |||
mongoose.connect( mongo_url, {useNewUrlParser: true, useUnifiedTopology: true}, () => null ); | |||
let db = mongoose.connection; | |||
db.once("open", async function callback () { | |||
let user_data = await userModel.find({_id: user.id}, "profession rank") | |||
let profession = user_data[0].profession | |||
let rank = user_data[0].rank | |||
if(limits[rank] < profession.length + 1 && limits[rank] !== 0){ | |||
user.send(`You cannot have more than ${limits[rank]} professions at this rank!`) | |||
return; | |||
} | |||
profession.push(reaction_to_prof[emoji][1]); | |||
member.roles.add( reaction_to_prof[emoji][0]); | |||
userModel.findOneAndUpdate( | |||
{_id: user.id}, | |||
{profession: profession}, | |||
{ | |||
new: true, | |||
runValidators: true, | |||
useFindAndModify: false | |||
}, function(err, result) { | |||
//if (err) {console.log(err); } else {console.log(result);} | |||
}); | |||
user.send(`You now have the profession ${reaction_to_prof[emoji][1]}!`) | |||
}); | |||
}catch (error) { | |||
console.log(error) | |||
console.log("ERROR WITH MONGODB CONNECTION"); | |||
} | |||
} | |||
}); | |||
client.on('messageReactionRemove', async (reaction, user) => { | |||
if(reaction.message.id === role_message_id){ | |||
if (reaction.partial) { | |||
try { | |||
await reaction.fetch(); | |||
} catch (error) { | |||
console.log('Something went wrong when fetching the message: ', error); | |||
return; | |||
} | |||
} | |||
let emoji = reaction.emoji.name; | |||
let member = await reaction.message.guild.members.fetch(user.id); | |||
try { | |||
mongoose.connect( mongo_url, {useNewUrlParser: true, useUnifiedTopology: true}, () => null ); | |||
let db = mongoose.connection; | |||
db.once("open", async function callback () { | |||
let user_data = await userModel.find({_id: user.id}, "profession rank") | |||
let profession = user_data[0].profession | |||
let rank = user_data[0].rank | |||
if(profession_index != -1){ | |||
profession.splice(profession_index, 1) | |||
} | |||
member.roles.remove(reaction_to_prof[emoji][0]); | |||
userModel.findOneAndUpdate( | |||
{_id: user.id}, | |||
{profession: profession}, | |||
{ | |||
new: true, | |||
runValidators: true, | |||
useFindAndModify: false | |||
}, function(err, result) { | |||
// if (err) {console.log(err); } else {console.log(result);} | |||
}); | |||
}); | |||
user.send(`You now don't have the profession ${reaction_to_prof[emoji][1]}!`) | |||
}catch (error) { | |||
console.log(error) | |||
console.log("ERROR WITH MONGODB CONNECTION"); | |||
} | |||
} | |||
}); | |||
// login to Discord with your app's token | |||
client.login(token); |
@ -0,0 +1,815 @@ | |||
{ | |||
"requires": true, | |||
"lockfileVersion": 1, | |||
"dependencies": { | |||
"@discordjs/collection": { | |||
"version": "0.1.5", | |||
"resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-0.1.5.tgz", | |||
"integrity": "sha512-CU1q0UXQUpFNzNB7gufgoisDHP7n+T3tkqTsp3MNUkVJ5+hS3BCvME8uCXAUFlz+6T2FbTCu75A+yQ7HMKqRKw==" | |||
}, | |||
"@discordjs/form-data": { | |||
"version": "3.0.1", | |||
"resolved": "https://registry.npmjs.org/@discordjs/form-data/-/form-data-3.0.1.tgz", | |||
"integrity": "sha512-ZfFsbgEXW71Rw/6EtBdrP5VxBJy4dthyC0tpQKGKmYFImlmmrykO14Za+BiIVduwjte0jXEBlhSKf0MWbFp9Eg==", | |||
"requires": { | |||
"asynckit": "^0.4.0", | |||
"combined-stream": "^1.0.8", | |||
"mime-types": "^2.1.12" | |||
} | |||
}, | |||
"abbrev": { | |||
"version": "1.1.1", | |||
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", | |||
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" | |||
}, | |||
"abort-controller": { | |||
"version": "3.0.0", | |||
"resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", | |||
"integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", | |||
"requires": { | |||
"event-target-shim": "^5.0.0" | |||
} | |||
}, | |||
"ansi-regex": { | |||
"version": "2.1.1", | |||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", | |||
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" | |||
}, | |||
"aproba": { | |||
"version": "1.2.0", | |||
"resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", | |||
"integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" | |||
}, | |||
"are-we-there-yet": { | |||
"version": "1.1.5", | |||
"resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", | |||
"integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", | |||
"requires": { | |||
"delegates": "^1.0.0", | |||
"readable-stream": "^2.0.6" | |||
} | |||
}, | |||
"asynckit": { | |||
"version": "0.4.0", | |||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", | |||
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" | |||
}, | |||
"balanced-match": { | |||
"version": "1.0.0", | |||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", | |||
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" | |||
}, | |||
"bl": { | |||
"version": "2.2.0", | |||
"resolved": "https://registry.npmjs.org/bl/-/bl-2.2.0.tgz", | |||
"integrity": "sha512-wbgvOpqopSr7uq6fJrLH8EsvYMJf9gzfo2jCsL2eTy75qXPukA4pCgHamOQkZtY5vmfVtjB+P3LNlMHW5CEZXA==", | |||
"requires": { | |||
"readable-stream": "^2.3.5", | |||
"safe-buffer": "^5.1.1" | |||
} | |||
}, | |||
"bluebird": { | |||
"version": "3.7.2", | |||
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", | |||
"integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" | |||
}, | |||
"brace-expansion": { | |||
"version": "1.1.11", | |||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", | |||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", | |||
"requires": { | |||
"balanced-match": "^1.0.0", | |||
"concat-map": "0.0.1" | |||
} | |||
}, | |||
"bson": { | |||
"version": "1.1.4", | |||
"resolved": "https://registry.npmjs.org/bson/-/bson-1.1.4.tgz", | |||
"integrity": "sha512-S/yKGU1syOMzO86+dGpg2qGoDL0zvzcb262G+gqEy6TgP6rt6z6qxSFX/8X6vLC91P7G7C3nLs0+bvDzmvBA3Q==" | |||
}, | |||
"canvas": { | |||
"version": "2.6.1", | |||
"resolved": "https://registry.npmjs.org/canvas/-/canvas-2.6.1.tgz", | |||
"integrity": "sha512-S98rKsPcuhfTcYbtF53UIJhcbgIAK533d1kJKMwsMwAIFgfd58MOyxRud3kktlzWiEkFliaJtvyZCBtud/XVEA==", | |||
"requires": { | |||
"nan": "^2.14.0", | |||
"node-pre-gyp": "^0.11.0", | |||
"simple-get": "^3.0.3" | |||
} | |||
}, | |||
"chownr": { | |||
"version": "1.1.4", | |||
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", | |||
"integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" | |||
}, | |||
"code-point-at": { | |||
"version": "1.1.0", | |||
"resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", | |||
"integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" | |||
}, | |||
"combined-stream": { | |||
"version": "1.0.8", | |||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", | |||
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", | |||
"requires": { | |||
"delayed-stream": "~1.0.0" | |||
} | |||
}, | |||
"concat-map": { | |||
"version": "0.0.1", | |||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", | |||
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" | |||
}, | |||
"console-control-strings": { | |||
"version": "1.1.0", | |||
"resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", | |||
"integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" | |||
}, | |||
"core-util-is": { | |||
"version": "1.0.2", | |||
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", | |||
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" | |||
}, | |||
"debug": { | |||
"version": "3.2.6", | |||
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", | |||
"integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", | |||
"requires": { | |||
"ms": "^2.1.1" | |||
} | |||
}, | |||
"decompress-response": { | |||
"version": "4.2.1", | |||
"resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", | |||
"integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", | |||
"requires": { | |||
"mimic-response": "^2.0.0" | |||
} | |||
}, | |||
"deep-extend": { | |||
"version": "0.6.0", | |||
"resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", | |||
"integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" | |||
}, | |||
"delayed-stream": { | |||
"version": "1.0.0", | |||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", | |||
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" | |||
}, | |||
"delegates": { | |||
"version": "1.0.0", | |||
"resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", | |||
"integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" | |||
}, | |||
"denque": { | |||
"version": "1.4.1", | |||
"resolved": "https://registry.npmjs.org/denque/-/denque-1.4.1.tgz", | |||
"integrity": "sha512-OfzPuSZKGcgr96rf1oODnfjqBFmr1DVoc/TrItj3Ohe0Ah1C5WX5Baquw/9U9KovnQ88EqmJbD66rKYUQYN1tQ==" | |||
}, | |||
"detect-libc": { | |||
"version": "1.0.3", | |||
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", | |||
"integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=" | |||
}, | |||
"discord.js": { | |||
"version": "12.2.0", | |||
"resolved": "https://registry.npmjs.org/discord.js/-/discord.js-12.2.0.tgz", | |||
"integrity": "sha512-Ueb/0SOsxXyqwvwFYFe0msMrGqH1OMqpp2Dpbplnlr4MzcRrFWwsBM9gKNZXPVBHWUKiQkwU8AihXBXIvTTSvg==", | |||
"requires": { | |||
"@discordjs/collection": "^0.1.5", | |||
"@discordjs/form-data": "^3.0.1", | |||
"abort-controller": "^3.0.0", | |||
"node-fetch": "^2.6.0", | |||
"prism-media": "^1.2.0", | |||
"setimmediate": "^1.0.5", | |||
"tweetnacl": "^1.0.3", | |||
"ws": "^7.2.1" | |||
} | |||
}, | |||
"event-target-shim": { | |||
"version": "5.0.1", | |||
"resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", | |||
"integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==" | |||
}, | |||
"fs-minipass": { | |||
"version": "1.2.7", | |||
"resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", | |||
"integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==", | |||
"requires": { | |||
"minipass": "^2.6.0" | |||
} | |||
}, | |||
"fs.realpath": { | |||
"version": "1.0.0", | |||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", | |||
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" | |||
}, | |||
"gauge": { | |||
"version": "2.7.4", | |||
"resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", | |||
"integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", | |||
"requires": { | |||
"aproba": "^1.0.3", | |||
"console-control-strings": "^1.0.0", | |||
"has-unicode": "^2.0.0", | |||
"object-assign": "^4.1.0", | |||
"signal-exit": "^3.0.0", | |||
"string-width": "^1.0.1", | |||
"strip-ansi": "^3.0.1", | |||
"wide-align": "^1.1.0" | |||
} | |||
}, | |||
"glob": { | |||
"version": "7.1.6", | |||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", | |||
"integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", | |||
"requires": { | |||
"fs.realpath": "^1.0.0", | |||
"inflight": "^1.0.4", | |||
"inherits": "2", | |||
"minimatch": "^3.0.4", | |||
"once": "^1.3.0", | |||
"path-is-absolute": "^1.0.0" | |||
} | |||
}, | |||
"has-unicode": { | |||
"version": "2.0.1", | |||
"resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", | |||
"integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" | |||
}, | |||
"iconv-lite": { | |||
"version": "0.4.24", | |||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", | |||
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", | |||
"requires": { | |||
"safer-buffer": ">= 2.1.2 < 3" | |||
} | |||
}, | |||
"ignore-walk": { | |||
"version": "3.0.3", | |||
"resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.3.tgz", | |||
"integrity": "sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw==", | |||
"requires": { | |||
"minimatch": "^3.0.4" | |||
} | |||
}, | |||
"inflight": { | |||
"version": "1.0.6", | |||
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", | |||
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", | |||
"requires": { | |||
"once": "^1.3.0", | |||
"wrappy": "1" | |||
} | |||
}, | |||
"inherits": { | |||
"version": "2.0.4", | |||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", | |||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" | |||
}, | |||
"ini": { | |||
"version": "1.3.5", | |||
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", | |||
"integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" | |||
}, | |||
"is-fullwidth-code-point": { | |||
"version": "1.0.0", | |||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", | |||
"integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", | |||
"requires": { | |||
"number-is-nan": "^1.0.0" | |||
} | |||
}, | |||
"isarray": { | |||
"version": "1.0.0", | |||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", | |||
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" | |||
}, | |||
"kareem": { | |||
"version": "2.3.1", | |||
"resolved": "https://registry.npmjs.org/kareem/-/kareem-2.3.1.tgz", | |||
"integrity": "sha512-l3hLhffs9zqoDe8zjmb/mAN4B8VT3L56EUvKNqLFVs9YlFA+zx7ke1DO8STAdDyYNkeSo1nKmjuvQeI12So8Xw==" | |||
}, | |||
"lodash.isplainobject": { | |||
"version": "4.0.6", | |||
"resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", | |||
"integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" | |||
}, | |||
"memory-pager": { | |||
"version": "1.5.0", | |||
"resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", | |||
"integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==" | |||
}, | |||
"mime-db": { | |||
"version": "1.44.0", | |||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", | |||
"integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==" | |||
}, | |||
"mime-types": { | |||
"version": "2.1.27", | |||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", | |||
"integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", | |||
"requires": { | |||
"mime-db": "1.44.0" | |||
} | |||
}, | |||
"mimic-response": { | |||
"version": "2.1.0", | |||
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", | |||
"integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==" | |||
}, | |||
"minimatch": { | |||
"version": "3.0.4", | |||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", | |||
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", | |||
"requires": { | |||
"brace-expansion": "^1.1.7" | |||
} | |||
}, | |||
"minimist": { | |||
"version": "1.2.5", | |||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", | |||
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" | |||
}, | |||
"minipass": { | |||
"version": "2.9.0", | |||
"resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", | |||
"integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", | |||
"requires": { | |||
"safe-buffer": "^5.1.2", | |||
"yallist": "^3.0.0" | |||
} | |||
}, | |||
"minizlib": { | |||
"version": "1.3.3", | |||
"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz", | |||
"integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==", | |||
"requires": { | |||
"minipass": "^2.9.0" | |||
} | |||
}, | |||
"mkdirp": { | |||
"version": "0.5.5", | |||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", | |||
"integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", | |||
"requires": { | |||
"minimist": "^1.2.5" | |||
} | |||
}, | |||
"mongodb": { | |||
"version": "3.5.9", | |||
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.5.9.tgz", | |||
"integrity": "sha512-vXHBY1CsGYcEPoVWhwgxIBeWqP3dSu9RuRDsoLRPTITrcrgm1f0Ubu1xqF9ozMwv53agmEiZm0YGo+7WL3Nbug==", | |||
"requires": { | |||
"bl": "^2.2.0", | |||
"bson": "^1.1.4", | |||
"denque": "^1.4.1", | |||
"require_optional": "^1.0.1", | |||
"safe-buffer": "^5.1.2", | |||
"saslprep": "^1.0.0" | |||
} | |||
}, | |||
"mongoose": { | |||
"version": "5.9.25", | |||
"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.9.25.tgz", | |||
"integrity": "sha512-vz/DqJ3mrHqEIlfRbKmDZ9TzQ1a0hCtSQpjHScIxr4rEtLs0tjsXDeEWcJ/vEEc3oLfP6vRx9V+uYSprXDUvFQ==", | |||
"requires": { | |||
"bson": "^1.1.4", | |||
"kareem": "2.3.1", | |||
"mongodb": "3.5.9", | |||
"mongoose-legacy-pluralize": "1.0.2", | |||
"mpath": "0.7.0", | |||
"mquery": "3.2.2", | |||
"ms": "2.1.2", | |||
"regexp-clone": "1.0.0", | |||
"safe-buffer": "5.2.1", | |||
"sift": "7.0.1", | |||
"sliced": "1.0.1" | |||
}, | |||
"dependencies": { | |||
"safe-buffer": { | |||
"version": "5.2.1", | |||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", | |||
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" | |||
} | |||
} | |||
}, | |||
"mongoose-legacy-pluralize": { | |||
"version": "1.0.2", | |||
"resolved": "https://registry.npmjs.org/mongoose-legacy-pluralize/-/mongoose-legacy-pluralize-1.0.2.tgz", | |||
"integrity": "sha512-Yo/7qQU4/EyIS8YDFSeenIvXxZN+ld7YdV9LqFVQJzTLye8unujAWPZ4NWKfFA+RNjh+wvTWKY9Z3E5XM6ZZiQ==" | |||
}, | |||
"mpath": { | |||
"version": "0.7.0", | |||
"resolved": "https://registry.npmjs.org/mpath/-/mpath-0.7.0.tgz", | |||
"integrity": "sha512-Aiq04hILxhz1L+f7sjGyn7IxYzWm1zLNNXcfhDtx04kZ2Gk7uvFdgZ8ts1cWa/6d0TQmag2yR8zSGZUmp0tFNg==" | |||
}, | |||
"mquery": { | |||
"version": "3.2.2", | |||
"resolved": "https://registry.npmjs.org/mquery/-/mquery-3.2.2.tgz", | |||
"integrity": "sha512-XB52992COp0KP230I3qloVUbkLUxJIu328HBP2t2EsxSFtf4W1HPSOBWOXf1bqxK4Xbb66lfMJ+Bpfd9/yZE1Q==", | |||
"requires": { | |||
"bluebird": "3.5.1", | |||
"debug": "3.1.0", | |||
"regexp-clone": "^1.0.0", | |||
"safe-buffer": "5.1.2", | |||
"sliced": "1.0.1" | |||
}, | |||
"dependencies": { | |||
"bluebird": { | |||
"version": "3.5.1", | |||
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", | |||
"integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==" | |||
}, | |||
"debug": { | |||
"version": "3.1.0", | |||
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", | |||
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", | |||
"requires": { | |||
"ms": "2.0.0" | |||
} | |||
}, | |||
"ms": { | |||
"version": "2.0.0", | |||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", | |||
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" | |||
} | |||
} | |||
}, | |||
"ms": { | |||
"version": "2.1.2", | |||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", | |||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" | |||
}, | |||
"nan": { | |||
"version": "2.14.1", | |||
"resolved": "https://registry.npmjs.org/nan/-/nan-2.14.1.tgz", | |||
"integrity": "sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw==" | |||
}, | |||
"needle": { | |||
"version": "2.5.0", | |||
"resolved": "https://registry.npmjs.org/needle/-/needle-2.5.0.tgz", | |||
"integrity": "sha512-o/qITSDR0JCyCKEQ1/1bnUXMmznxabbwi/Y4WwJElf+evwJNFNwIDMCCt5IigFVxgeGBJESLohGtIS9gEzo1fA==", | |||
"requires": { | |||
"debug": "^3.2.6", | |||
"iconv-lite": "^0.4.4", | |||
"sax": "^1.2.4" | |||
} | |||
}, | |||
"node-fetch": { | |||
"version": "2.6.0", | |||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", | |||
"integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==" | |||
}, | |||
"node-pre-gyp": { | |||
"version": "0.11.0", | |||
"resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.11.0.tgz", | |||
"integrity": "sha512-TwWAOZb0j7e9eGaf9esRx3ZcLaE5tQ2lvYy1pb5IAaG1a2e2Kv5Lms1Y4hpj+ciXJRofIxxlt5haeQ/2ANeE0Q==", | |||
"requires": { | |||
"detect-libc": "^1.0.2", | |||
"mkdirp": "^0.5.1", | |||
"needle": "^2.2.1", | |||
"nopt": "^4.0.1", | |||
"npm-packlist": "^1.1.6", | |||
"npmlog": "^4.0.2", | |||
"rc": "^1.2.7", | |||
"rimraf": "^2.6.1", | |||
"semver": "^5.3.0", | |||
"tar": "^4" | |||
} | |||
}, | |||
"nopt": { | |||
"version": "4.0.3", | |||
"resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz", | |||
"integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==", | |||
"requires": { | |||
"abbrev": "1", | |||
"osenv": "^0.1.4" | |||
} | |||
}, | |||
"npm-bundled": { | |||
"version": "1.1.1", | |||
"resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.1.tgz", | |||
"integrity": "sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA==", | |||
"requires": { | |||
"npm-normalize-package-bin": "^1.0.1" | |||
} | |||
}, | |||
"npm-normalize-package-bin": { | |||
"version": "1.0.1", | |||
"resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", | |||
"integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==" | |||
}, | |||
"npm-packlist": { | |||
"version": "1.4.8", | |||
"resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.8.tgz", | |||
"integrity": "sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A==", | |||
"requires": { | |||
"ignore-walk": "^3.0.1", | |||
"npm-bundled": "^1.0.1", | |||
"npm-normalize-package-bin": "^1.0.1" | |||
} | |||
}, | |||
"npmlog": { | |||
"version": "4.1.2", | |||
"resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", | |||
"integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", | |||
"requires": { | |||
"are-we-there-yet": "~1.1.2", | |||
"console-control-strings": "~1.1.0", | |||
"gauge": "~2.7.3", | |||
"set-blocking": "~2.0.0" | |||
} | |||
}, | |||
"number-is-nan": { | |||
"version": "1.0.1", | |||
"resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", | |||
"integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" | |||
}, | |||
"object-assign": { | |||
"version": "4.1.1", | |||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", | |||
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" | |||
}, | |||
"once": { | |||
"version": "1.4.0", | |||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", | |||
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", | |||
"requires": { | |||
"wrappy": "1" | |||
} | |||
}, | |||
"os-homedir": { | |||
"version": "1.0.2", | |||
"resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", | |||
"integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" | |||
}, | |||
"os-tmpdir": { | |||
"version": "1.0.2", | |||
"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", | |||
"integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" | |||
}, | |||
"osenv": { | |||
"version": "0.1.5", | |||
"resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", | |||
"integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", | |||
"requires": { | |||
"os-homedir": "^1.0.0", | |||
"os-tmpdir": "^1.0.0" | |||
} | |||
}, | |||
"path-is-absolute": { | |||
"version": "1.0.1", | |||
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", | |||
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" | |||
}, | |||
"prism-media": { | |||
"version": "1.2.2", | |||
"resolved": "https://registry.npmjs.org/prism-media/-/prism-media-1.2.2.tgz", | |||
"integrity": "sha512-I+nkWY212lJ500jLe4tN9tWO7nRiBAVdMv76P9kffZjYhw20raMlW1HSSvS+MLXC9MmbNZCazMrAr+5jEEgTuw==" | |||
}, | |||
"process-nextick-args": { | |||
"version": "2.0.1", | |||
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", | |||
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" | |||
}, | |||
"qs": { | |||
"version": "6.9.4", | |||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.9.4.tgz", | |||
"integrity": "sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ==" | |||
}, | |||
"rc": { | |||
"version": "1.2.8", | |||
"resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", | |||
"integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", | |||
"requires": { | |||
"deep-extend": "^0.6.0", | |||
"ini": "~1.3.0", | |||
"minimist": "^1.2.0", | |||
"strip-json-comments": "~2.0.1" | |||
} | |||
}, | |||
"readable-stream": { | |||
"version": "2.3.7", | |||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", | |||
"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", | |||
"requires": { | |||
"core-util-is": "~1.0.0", | |||
"inherits": "~2.0.3", | |||
"isarray": "~1.0.0", | |||
"process-nextick-args": "~2.0.0", | |||
"safe-buffer": "~5.1.1", | |||
"string_decoder": "~1.1.1", | |||
"util-deprecate": "~1.0.1" | |||
} | |||
}, | |||
"regexp-clone": { | |||
"version": "1.0.0", | |||
"resolved": "https://registry.npmjs.org/regexp-clone/-/regexp-clone-1.0.0.tgz", | |||
"integrity": "sha512-TuAasHQNamyyJ2hb97IuBEif4qBHGjPHBS64sZwytpLEqtBQ1gPJTnOaQ6qmpET16cK14kkjbazl6+p0RRv0yw==" | |||
}, | |||
"require_optional": { | |||
"version": "1.0.1", | |||
"resolved": "https://registry.npmjs.org/require_optional/-/require_optional-1.0.1.tgz", | |||
"integrity": "sha512-qhM/y57enGWHAe3v/NcwML6a3/vfESLe/sGM2dII+gEO0BpKRUkWZow/tyloNqJyN6kXSl3RyyM8Ll5D/sJP8g==", | |||
"requires": { | |||
"resolve-from": "^2.0.0", | |||
"semver": "^5.1.0" | |||
} | |||
}, | |||
"resolve-from": { | |||
"version": "2.0.0", | |||
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz", | |||
"integrity": "sha1-lICrIOlP+h2egKgEx+oUdhGWa1c=" | |||
}, | |||
"rimraf": { | |||
"version": "2.7.1", | |||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", | |||
"integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", | |||
"requires": { | |||
"glob": "^7.1.3" | |||
} | |||
}, | |||
"safe-buffer": { | |||
"version": "5.1.2", | |||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", | |||
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" | |||
}, | |||
"safer-buffer": { | |||
"version": "2.1.2", | |||
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", | |||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" | |||
}, | |||
"saslprep": { | |||
"version": "1.0.3", | |||
"resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz", | |||
"integrity": "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==", | |||
"requires": { | |||
"sparse-bitfield": "^3.0.3" | |||
} | |||
}, | |||
"sax": { | |||
"version": "1.2.4", | |||
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", | |||
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" | |||
}, | |||
"semver": { | |||
"version": "5.7.1", | |||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", | |||
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" | |||
}, | |||
"set-blocking": { | |||
"version": "2.0.0", | |||
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", | |||
"integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" | |||
}, | |||
"setimmediate": { | |||
"version": "1.0.5", | |||
"resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", | |||
"integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" | |||
}, | |||
"sift": { | |||
"version": "7.0.1", | |||
"resolved": "https://registry.npmjs.org/sift/-/sift-7.0.1.tgz", | |||
"integrity": "sha512-oqD7PMJ+uO6jV9EQCl0LrRw1OwsiPsiFQR5AR30heR+4Dl7jBBbDLnNvWiak20tzZlSE1H7RB30SX/1j/YYT7g==" | |||
}, | |||
"signal-exit": { | |||
"version": "3.0.3", | |||
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", | |||
"integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==" | |||
}, | |||
"simple-concat": { | |||
"version": "1.0.0", | |||
"resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.0.tgz", | |||
"integrity": "sha1-c0TLuLbib7J9ZrL8hvn21Zl1IcY=" | |||
}, | |||
"simple-get": { | |||
"version": "3.1.0", | |||
"resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.0.tgz", | |||
"integrity": "sha512-bCR6cP+aTdScaQCnQKbPKtJOKDp/hj9EDLJo3Nw4y1QksqaovlW/bnptB6/c1e+qmNIDHRK+oXFDdEqBT8WzUA==", | |||
"requires": { | |||
"decompress-response": "^4.2.0", | |||
"once": "^1.3.1", | |||
"simple-concat": "^1.0.0" | |||
} | |||
}, | |||
"sliced": { | |||
"version": "1.0.1", | |||
"resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz", | |||
"integrity": "sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E=" | |||
}, | |||
"sparse-bitfield": { | |||
"version": "3.0.3", | |||
"resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", | |||
"integrity": "sha1-/0rm5oZWBWuks+eSqzM004JzyhE=", | |||
"requires": { | |||
"memory-pager": "^1.0.2" | |||
} | |||
}, | |||
"string-width": { | |||
"version": "1.0.2", | |||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", | |||
"integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", | |||
"requires": { | |||
"code-point-at": "^1.0.0", | |||
"is-fullwidth-code-point": "^1.0.0", | |||
"strip-ansi": "^3.0.0" | |||
} | |||
}, | |||
"string_decoder": { | |||
"version": "1.1.1", | |||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", | |||
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", | |||
"requires": { | |||
"safe-buffer": "~5.1.0" | |||
} | |||
}, | |||
"strip-ansi": { | |||
"version": "3.0.1", | |||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", | |||
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", | |||
"requires": { | |||
"ansi-regex": "^2.0.0" | |||
} | |||
}, | |||
"strip-json-comments": { | |||
"version": "2.0.1", | |||
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", | |||
"integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" | |||
}, | |||
"tar": { | |||
"version": "4.4.13", | |||
"resolved": "https://registry.npmjs.org/tar/-/tar-4.4.13.tgz", | |||
"integrity": "sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA==", | |||
"requires": { | |||
"chownr": "^1.1.1", | |||
"fs-minipass": "^1.2.5", | |||
"minipass": "^2.8.6", | |||
"minizlib": "^1.2.1", | |||
"mkdirp": "^0.5.0", | |||
"safe-buffer": "^5.1.2", | |||
"yallist": "^3.0.3" | |||
} | |||
}, | |||
"trello-node-api": { | |||
"version": "0.0.9", | |||
"resolved": "https://registry.npmjs.org/trello-node-api/-/trello-node-api-0.0.9.tgz", | |||
"integrity": "sha512-UVkn8rZV427i1tnn/flIkbmIzblEv868poTeOHhMrsblP3ogA6umgy2dh6+1QvjTvBQ1YiVpVUQQp/ZSBZlOMA==", | |||
"requires": { | |||
"bluebird": "^3.7.2", | |||
"debug": "^4.1.1", | |||
"lodash.isplainobject": "^4.0.6", | |||
"qs": "~6.9.1", | |||
"safe-buffer": "^5.2.0" | |||
}, | |||
"dependencies": { | |||
"debug": { | |||
"version": "4.1.1", | |||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", | |||
"integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", | |||
"requires": { | |||
"ms": "^2.1.1" | |||
} | |||
}, | |||
"safe-buffer": { | |||
"version": "5.2.1", | |||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", | |||
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" | |||
} | |||
} | |||
}, | |||
"tweetnacl": { | |||
"version": "1.0.3", | |||
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", | |||
"integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==" | |||
}, | |||
"util-deprecate": { | |||
"version": "1.0.2", | |||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", | |||
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" | |||
}, | |||
"wide-align": { | |||
"version": "1.1.3", | |||
"resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", | |||
"integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", | |||
"requires": { | |||
"string-width": "^1.0.2 || 2" | |||
} | |||
}, | |||
"wrappy": { | |||
"version": "1.0.2", | |||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", | |||
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" | |||
}, | |||
"ws": { | |||
"version": "7.3.1", | |||
"resolved": "https://registry.npmjs.org/ws/-/ws-7.3.1.tgz", | |||
"integrity": "sha512-D3RuNkynyHmEJIpD2qrgVkc9DQ23OrN/moAwZX4L8DfvszsJxpjQuUq3LMx6HoYji9fbIOBY18XWBsAux1ZZUA==" | |||
}, | |||
"yallist": { | |||
"version": "3.1.1", | |||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", | |||
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" | |||
} | |||
} | |||
} |