<commit_before>// config/auth.js
var host       = process.env.OPENSHIFT_NODEJS_IP || process.env.IP;
var port     = process.env.OPENSHIFT_INTERNAL_PORT || process.env.OPENSHIFT_NODEJS_PORT || process.env.PORT || 8080;
var service = 'http://'+host+':'+port;
var callFacebook = service+'/auth/facebook/callback';
var callTwitter = service+'/auth/twitter/callback';
var callGoogle = service+'/auth/google/callback';

// expose our config directly to our application using module.exports
module.exports = {

	'facebookAuth' : {
		'clientID' 		: process.env.facebookclientID, // your App ID
		'clientSecret' 	:  process.env.facebookclientSecret, // your App Secret
		'callbackURL' 	: callFacebook
	},

	'twitterAuth' : {
		'consumerKey' 		:  process.env.twitterconsumerKey,
		'consumerSecret' 	:  process.env.twitterconsumerSecret,
		'callbackURL' 		: callTwitter
	},

	'googleAuth' : {
		'clientID' 		:  process.env.googleclientID,
		'clientSecret' 	:  process.env.googleclientSecret,
		'callbackURL' 	: callGoogle
	}

};
<commit_msg>Arreglando las direcciones del host<commit_after>// config/auth.js
var service = process.env.URLSERVICE;
var callFacebook = service+'/auth/facebook/callback';
var callTwitter = service+'/auth/twitter/callback';
var callGoogle = service+'/auth/google/callback';

// expose our config directly to our application using module.exports
module.exports = {

	'facebookAuth' : {
		'clientID' 		: process.env.facebookclientID, // your App ID
		'clientSecret' 	:  process.env.facebookclientSecret, // your App Secret
		'callbackURL' 	: callFacebook
	},

	'twitterAuth' : {
		'consumerKey' 		:  process.env.twitterconsumerKey,
		'consumerSecret' 	:  process.env.twitterconsumerSecret,
		'callbackURL' 		: callTwitter
	},

	'googleAuth' : {
		'clientID' 		:  process.env.googleclientID,
		'clientSecret' 	:  process.env.googleclientSecret,
		'callbackURL' 	: callGoogle
	}

};
<|endoftext|>


<commit_before>/* eslint-disable no-await-in-loop */
import { promisify } from 'util';

import moment from 'moment';
import N3 from 'n3';
import PgCursor from 'pg-cursor';
import pgFormat from 'pg-format';
import noop from 'lodash/noop';
import config from 'config';

const { literal, namedNode, quad } = N3.DataFactory;

const schema = 'http://schema.org/';
const frf = 'http://freefeed.net/';
const rdfs = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';

export const prefixes = { schema, rdfs };

const schemaType = (id, typeName) =>
  quad(namedNode(id), namedNode(`${rdfs}type`), namedNode(`${schema}${typeName}`));

const intToIso = (timestamp) => moment(parseInt(timestamp)).format();
const fixIso = (badIsoTimestamp) => moment(badIsoTimestamp).format();

const createdAt = (id, isoTimestamp) =>
  quad(namedNode(id), namedNode(`${schema}dateCreated`), literal(isoTimestamp));

const updatedAt = (id, isoTimestamp) =>
  quad(namedNode(id), namedNode(`${schema}dateModified`), literal(isoTimestamp));

const hasBlogPost = (blogId, postId) =>
  quad(namedNode(blogId), namedNode(`${schema}blogPost`), namedNode(postId));

const objUrl = (id, url) => quad(namedNode(id), namedNode(`${schema}url`), literal(url));

const objIdentifier = (id, identifier) =>
  quad(namedNode(id), namedNode(`${schema}identifier`), literal(identifier));

const objName = (id, name) => quad(namedNode(id), namedNode(`${schema}name`), literal(name));

const objDescription = (id, description) =>
  quad(namedNode(id), namedNode(`${schema}description`), literal(description));

const hasText = (objectId, text) =>
  quad(namedNode(objectId), namedNode(`${schema}text`), literal(text));

const hasComment = (postId, commentId) =>
  quad(namedNode(postId), namedNode(`${schema}comment`), namedNode(commentId));

const hasAttachment = (postId, attachmentId) =>
  quad(namedNode(postId), namedNode(`${schema}sharedContent`), namedNode(attachmentId));

const hasMimetype = (objId, mimeType) =>
  quad(namedNode(objId), namedNode(`${schema}encodingFormat`), literal(mimeType));

const hasFilename = (objId, filename) =>
  quad(namedNode(objId), namedNode(`${schema}alternateName`), literal(filename));

const hasUpvoteCount = (commentId, count) =>
  quad(namedNode(commentId), namedNode(`${schema}upvoteCount`), literal(parseInt(count)));

const hasAuthor = (objectId, authorId) =>
  quad(namedNode(objectId), namedNode(`${schema}author`), namedNode(authorId));

const actionAgent = (actionId, agentId) =>
  quad(namedNode(actionId), namedNode(`${schema}agent`), namedNode(agentId));

const actionObject = (actionId, objectId) =>
  quad(namedNode(actionId), namedNode(`${schema}object`), namedNode(objectId));

const actionStart = (actionId, isoTimestamp) =>
  quad(namedNode(actionId), namedNode(`${schema}startTime`), literal(isoTimestamp));

const messageSender = (messageId, userId) =>
  quad(namedNode(messageId), namedNode(`${schema}sender`), namedNode(userId));

const messageRecipient = (messageId, userId) =>
  quad(namedNode(messageId), namedNode(`${schema}recipient`), namedNode(userId));

export class DataProvider {
  dbAdapter;

  constructor(dbAdapter) {
    this.dbAdapter = dbAdapter;
  }

  async userTimelineAsQuads(userUuid) {
    process.stdout.write(`- getting user-data\n`);
    const user = await this.dbAdapter.getFeedOwnerById(userUuid);

    const knex = this.dbAdapter.database;
    const pg = await knex.client.acquireConnection();

    const writer = N3.Writer({
      format: 'N-Triples',
      prefixes,
    });

    const addQuad = promisify(writer.addQuad).bind(writer);
    const getResult = promisify(writer.end).bind(writer);

    const blogId = `urn:uuid:${user.id}`;

    await addQuad(schemaType(blogId, 'Blog'));
    await addQuad(objUrl(blogId, `https://freefeed.net/${user.username}`));
    await addQuad(objIdentifier(blogId, user.username));
    await addQuad(objName(blogId, user.screenName));
    await addQuad(objDescription(blogId, user.description));
    await addQuad(createdAt(blogId, intToIso(user.createdAt)));
    await addQuad(updatedAt(blogId, intToIso(user.updatedAt)));

    const otherUsers = new Set();

    const commentsAsQuads = async function (postUuid, postResourceId) {
      const comments = await knex.raw(
        'SELECT "u"."uid", "u"."username", "u"."screen_name", "c"."uid" AS "comment_uuid", "c"."id" AS "comment_id", "c"."body", "c"."created_at", "c"."updated_at" FROM "users" AS "u" INNER JOIN "comments" AS "c" ON "c"."user_id" = "u"."uid" WHERE "c"."post_id" = ? AND "c"."hide_type" = 0',
        [postUuid],
      );
      const cPromises = comments.rows.map(async (comment) => {
        const userId = `urn:uuid:${comment.uid}`;
        const commentId = comment.comment_id;
        const commentResourceId = `urn:uuid:${comment.comment_uuid}`;

        await addQuad(hasComment(postResourceId, commentResourceId));
        await addQuad(schemaType(commentResourceId, 'Comment'));
        await addQuad(hasAuthor(commentResourceId, userId));
        await addQuad(hasText(commentResourceId, comment.body));
        await addQuad(createdAt(commentResourceId, fixIso(comment.created_at)));
        await addQuad(updatedAt(commentResourceId, fixIso(comment.updated_at)));

        Reflect.deleteProperty(comment, 'comment_id');
        Reflect.deleteProperty(comment, 'comment_uuid');
        Reflect.deleteProperty(comment, 'body');
        Reflect.deleteProperty(comment, 'created_at');
        Reflect.deleteProperty(comment, 'updated_at');
        otherUsers.add(comment);

        const cLikers = await knex.raw(
          'SELECT "u"."uid", "u"."username", "u"."screen_name", "l"."created_at" FROM "users" AS "u" INNER JOIN "comment_likes" AS "l" ON "l"."user_id" = "u"."id" WHERE "l"."comment_id" = ?',
          [commentId],
        );
        await addQuad(hasUpvoteCount(commentResourceId, cLikers.rows.length));

        const clPromises = cLikers.rows.map(async (cLiker) => {
          const clikerResourceId = `urn:uuid:${cLiker.uid}`;
          const clikeResourceId = `${frf}${comment.comment_uuid}/like/${cLiker.uid}`;

          await addQuad(schemaType(clikeResourceId, 'LikeAction'));
          await addQuad(actionAgent(clikeResourceId, clikerResourceId));
          await addQuad(actionObject(clikeResourceId, commentResourceId));
          await addQuad(actionStart(clikeResourceId, fixIso(cLiker.created_at)));

          Reflect.deleteProperty(cLiker, 'created_at');
          otherUsers.add(cLiker);
        });

        await Promise.all(clPromises);
      });

      return cPromises;
    };

    process.stdout.write(`- getting user's posts: `);

    {
      // User's posts
      const timeline = await user.getPostsTimeline();

      const sql = `SELECT * FROM "posts" WHERE "feed_ids" && '{${timeline.intId}}'`;
      const cursor = pg.query(new PgCursor(sql));
      const read = promisify(cursor.read).bind(cursor);

      // eslint-disable-next-line no-constant-condition
      while (true) {
        const rows = await read(100);

        if (rows.length === 0) {
          cursor.close(noop);
          break;
        }

        process.stdout.write('.');

        for (const postRow of rows) {
          const postResourceId = `urn:uuid:${postRow.uid}`;

          await addQuad(hasBlogPost(blogId, postResourceId));
          await addQuad(schemaType(postResourceId, 'BlogPosting'));
          await addQuad(
            objUrl(postResourceId, `https://freefeed.net/${user.username}/${postRow.uid}`),
          );
          await addQuad(createdAt(postResourceId, fixIso(postRow.created_at)));
          await addQuad(updatedAt(postResourceId, fixIso(postRow.updated_at)));
          await addQuad(hasText(postResourceId, postRow.body));

          const likers = await knex.raw(
            'SELECT "u"."uid", "u"."username", "u"."screen_name", "l"."created_at" FROM "users" AS "u" INNER JOIN "likes" AS "l" ON "l"."user_id" = "u"."uid" WHERE "l"."post_id" = ?',
            [postRow.uid],
          );
          const lPromises = likers.rows.map(async (liker) => {
            const userId = `urn:uuid:${liker.uid}`;
            const likeId = `${frf}${postRow.uid}/like/${liker.uid}`;

            await addQuad(schemaType(likeId, 'LikeAction'));
            await addQuad(actionAgent(likeId, userId));
            await addQuad(actionObject(likeId, postResourceId));
            await addQuad(actionStart(likeId, fixIso(liker.created_at)));

            Reflect.deleteProperty(liker, 'created_at');
            otherUsers.add(liker);
          });

          const cPromises = await commentsAsQuads(postRow.uid, postResourceId);

          await Promise.all(lPromises); // likes
          await Promise.all(cPromises); // comments + comment-likes
        }
      }
    }

    process.stdout.write('\n');

    process.stdout.write(`- getting user's direct messages: `);

    {
      // Direct messages
      const timeline = await user.getDirectsTimeline();

      const sql = `SELECT * FROM "posts" WHERE "feed_ids" && '{${timeline.intId}}'`;
      const cursor = pg.query(new PgCursor(sql));
      const read = promisify(cursor.read).bind(cursor);

      // eslint-disable-next-line no-constant-condition
      while (true) {
        const rows = await read(100);

        if (rows.length === 0) {
          cursor.close(noop);
          break;
        }

        process.stdout.write('.');

        for (const postRow of rows) {
          const postResourceId = `urn:uuid:${postRow.uid}`;

          let senderId = user.id;
          let sender = blogId;
          let postUrl = `https://freefeed.net/${user.username}/${postRow.uid}`;

          if (postRow.user_id !== userUuid) {
            const authorRows = await knex.raw(
              'SELECT "u"."uid", "u"."username", "u"."screen_name" FROM "users" AS "u" WHERE "u"."uid" = ?',
              [postRow.user_id],
            );
            const [author] = authorRows.rows;

            senderId = author.uid;
            sender = `urn:uuid:${author.uid}`;
            postUrl = `https://freefeed.net/${author.username}/${postRow.uid}`;

            otherUsers.add(author);
          }

          await addQuad(schemaType(postResourceId, 'Message'));
          await addQuad(messageSender(postResourceId, sender));
          await addQuad(objUrl(postResourceId, postUrl));
          await addQuad(createdAt(postResourceId, fixIso(postRow.created_at)));
          await addQuad(updatedAt(postResourceId, fixIso(postRow.updated_at)));
          await addQuad(hasText(postResourceId, postRow.body));

          const recipientSql = pgFormat(
            'SELECT "u"."uid", "u"."username", "u"."screen_name" FROM "users" AS "u" inner join feeds f on f.user_id = u.uid where f.id in (%L)',
            postRow.destination_feed_ids,
          );
          const recipientResult = await knex.raw(recipientSql);
          const rPromises = recipientResult.rows.map(async (recipient) => {
            if (recipient.uid === senderId) {
              return;
            }

            const recipientUrl = `urn:uuid:${recipient.uid}`;
            await addQuad(messageRecipient(postResourceId, recipientUrl));

            otherUsers.add(recipient);
          });

          const likers = await knex.raw(
            'SELECT "u"."uid", "u"."username", "u"."screen_name", "l"."created_at" FROM "users" AS "u" INNER JOIN "likes" AS "l" ON "l"."user_id" = "u"."uid" WHERE "l"."post_id" = ?',
            [postRow.uid],
          );
          const lPromises = likers.rows.map(async (liker) => {
            const userId = `urn:uuid:${liker.uid}`;
            const likeId = `${frf}${postRow.uid}/like/${liker.uid}`;

            await addQuad(schemaType(likeId, 'LikeAction'));
            await addQuad(actionAgent(likeId, userId));
            await addQuad(actionObject(likeId, postResourceId));
            await addQuad(actionStart(likeId, fixIso(liker.created_at)));

            Reflect.deleteProperty(liker, 'created_at');
            otherUsers.add(liker);
          });

          const cPromises = await commentsAsQuads(postRow.uid, postResourceId);

          await Promise.all(rPromises); // recipients
          await Promise.all(lPromises); // likes
          await Promise.all(cPromises); // comments + comment-likes
        }
      }
    }

    process.stdout.write('\n');

    const downloadUrls = [];
    process.stdout.write(`- getting user's attachments: `);

    {
      const attachmentTypes = {
        audio: 'AudioObject',
        general: 'DataDownload',
        image: 'ImageObject',
      };

      const sql = `SELECT * FROM "attachments" WHERE "user_id" = $1`; // using '$1' instead of '?' as we're VERY close to postgres in this call
      const cursor = pg.query(new PgCursor(sql, [user.id]));
      const read = promisify(cursor.read).bind(cursor);

      // eslint-disable-next-line no-constant-condition
      while (true) {
        const rows = await read(100);

        if (rows.length === 0) {
          cursor.close(noop);
          break;
        }

        process.stdout.write('.');

        for (const attachmentRow of rows) {
          if (attachmentRow.media_type === null) {
            // skip bogus attachments
            continue;
          }

          const attResourceId = `urn:uuid:${attachmentRow.uid}`;

          let downloadUrl = `${config.attachments.url}${config.attachments.path}${attachmentRow.uid}`;

          if (attachmentRow.file_extension) {
            downloadUrl = `${downloadUrl}.${attachmentRow.file_extension}`;
          }

          downloadUrls.push(downloadUrl);

          await addQuad(schemaType(attResourceId, attachmentTypes[attachmentRow.media_type]));
          await addQuad(createdAt(attResourceId, fixIso(attachmentRow.created_at)));
          await addQuad(updatedAt(attResourceId, fixIso(attachmentRow.updated_at)));
          await addQuad(objUrl(attResourceId, downloadUrl));
          await addQuad(hasFilename(attResourceId, attachmentRow.file_name));

          if (attachmentRow.mime_type) {
            await addQuad(hasMimetype(attResourceId, attachmentRow.mime_type));
          }

          if (attachmentRow.post_id) {
            // some attachments are not connected to posts
            const postResourceId = `urn:uuid:${attachmentRow.post_id}`;
            await addQuad(hasAttachment(postResourceId, attResourceId));
          }
        }
      }
    }

    process.stdout.write('\n');

    process.stdout.write(`- storing additional user-resources\n`);

    for (const otherUser of [...otherUsers]) {
      const userId = `urn:uuid:${otherUser.uid}`;

      await addQuad(schemaType(userId, 'Blog'));
      await addQuad(objIdentifier(userId, otherUser.username));
      await addQuad(objName(userId, otherUser.screen_name));
    }

    knex.client.releaseConnection(pg);
    const ntriples = await getResult();

    return { ntriples, downloadUrls };
  }
}
<commit_msg>Update GDPR-export script for new N3.js API<commit_after>/* eslint-disable no-await-in-loop */
import { promisify } from 'util';

import moment from 'moment';
import { DataFactory, Writer } from 'n3';
import PgCursor from 'pg-cursor';
import pgFormat from 'pg-format';
import noop from 'lodash/noop';
import config from 'config';

const { literal, namedNode, quad } = DataFactory;

const schema = 'http://schema.org/';
const frf = 'http://freefeed.net/';
const rdfs = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';

export const prefixes = { schema, rdfs };

const schemaType = (id, typeName) =>
  quad(namedNode(id), namedNode(`${rdfs}type`), namedNode(`${schema}${typeName}`));

const intToIso = (timestamp) => moment(parseInt(timestamp)).format();
const fixIso = (badIsoTimestamp) => moment(badIsoTimestamp).format();

const createdAt = (id, isoTimestamp) =>
  quad(namedNode(id), namedNode(`${schema}dateCreated`), literal(isoTimestamp));

const updatedAt = (id, isoTimestamp) =>
  quad(namedNode(id), namedNode(`${schema}dateModified`), literal(isoTimestamp));

const hasBlogPost = (blogId, postId) =>
  quad(namedNode(blogId), namedNode(`${schema}blogPost`), namedNode(postId));

const objUrl = (id, url) => quad(namedNode(id), namedNode(`${schema}url`), literal(url));

const objIdentifier = (id, identifier) =>
  quad(namedNode(id), namedNode(`${schema}identifier`), literal(identifier));

const objName = (id, name) => quad(namedNode(id), namedNode(`${schema}name`), literal(name));

const objDescription = (id, description) =>
  quad(namedNode(id), namedNode(`${schema}description`), literal(description));

const hasText = (objectId, text) =>
  quad(namedNode(objectId), namedNode(`${schema}text`), literal(text));

const hasComment = (postId, commentId) =>
  quad(namedNode(postId), namedNode(`${schema}comment`), namedNode(commentId));

const hasAttachment = (postId, attachmentId) =>
  quad(namedNode(postId), namedNode(`${schema}sharedContent`), namedNode(attachmentId));

const hasMimetype = (objId, mimeType) =>
  quad(namedNode(objId), namedNode(`${schema}encodingFormat`), literal(mimeType));

const hasFilename = (objId, filename) =>
  quad(namedNode(objId), namedNode(`${schema}alternateName`), literal(filename));

const hasUpvoteCount = (commentId, count) =>
  quad(namedNode(commentId), namedNode(`${schema}upvoteCount`), literal(parseInt(count)));

const hasAuthor = (objectId, authorId) =>
  quad(namedNode(objectId), namedNode(`${schema}author`), namedNode(authorId));

const actionAgent = (actionId, agentId) =>
  quad(namedNode(actionId), namedNode(`${schema}agent`), namedNode(agentId));

const actionObject = (actionId, objectId) =>
  quad(namedNode(actionId), namedNode(`${schema}object`), namedNode(objectId));

const actionStart = (actionId, isoTimestamp) =>
  quad(namedNode(actionId), namedNode(`${schema}startTime`), literal(isoTimestamp));

const messageSender = (messageId, userId) =>
  quad(namedNode(messageId), namedNode(`${schema}sender`), namedNode(userId));

const messageRecipient = (messageId, userId) =>
  quad(namedNode(messageId), namedNode(`${schema}recipient`), namedNode(userId));

export class DataProvider {
  dbAdapter;

  constructor(dbAdapter) {
    this.dbAdapter = dbAdapter;
  }

  async userTimelineAsQuads(userUuid) {
    process.stdout.write(`- getting user-data\n`);
    const user = await this.dbAdapter.getFeedOwnerById(userUuid);

    const knex = this.dbAdapter.database;
    const pg = await knex.client.acquireConnection();

    const writer = new Writer({
      format: 'N-Triples',
      prefixes,
    });

    const addQuad = promisify(writer.addQuad).bind(writer);
    const getResult = promisify(writer.end).bind(writer);

    const blogId = `urn:uuid:${user.id}`;

    await addQuad(schemaType(blogId, 'Blog'));
    await addQuad(objUrl(blogId, `https://freefeed.net/${user.username}`));
    await addQuad(objIdentifier(blogId, user.username));
    await addQuad(objName(blogId, user.screenName));
    await addQuad(objDescription(blogId, user.description));
    await addQuad(createdAt(blogId, intToIso(user.createdAt)));
    await addQuad(updatedAt(blogId, intToIso(user.updatedAt)));

    const otherUsers = new Set();

    const commentsAsQuads = async function (postUuid, postResourceId) {
      const comments = await knex.raw(
        'SELECT "u"."uid", "u"."username", "u"."screen_name", "c"."uid" AS "comment_uuid", "c"."id" AS "comment_id", "c"."body", "c"."created_at", "c"."updated_at" FROM "users" AS "u" INNER JOIN "comments" AS "c" ON "c"."user_id" = "u"."uid" WHERE "c"."post_id" = ? AND "c"."hide_type" = 0',
        [postUuid],
      );
      const cPromises = comments.rows.map(async (comment) => {
        const userId = `urn:uuid:${comment.uid}`;
        const commentId = comment.comment_id;
        const commentResourceId = `urn:uuid:${comment.comment_uuid}`;

        await addQuad(hasComment(postResourceId, commentResourceId));
        await addQuad(schemaType(commentResourceId, 'Comment'));
        await addQuad(hasAuthor(commentResourceId, userId));
        await addQuad(hasText(commentResourceId, comment.body));
        await addQuad(createdAt(commentResourceId, fixIso(comment.created_at)));
        await addQuad(updatedAt(commentResourceId, fixIso(comment.updated_at)));

        Reflect.deleteProperty(comment, 'comment_id');
        Reflect.deleteProperty(comment, 'comment_uuid');
        Reflect.deleteProperty(comment, 'body');
        Reflect.deleteProperty(comment, 'created_at');
        Reflect.deleteProperty(comment, 'updated_at');
        otherUsers.add(comment);

        const cLikers = await knex.raw(
          'SELECT "u"."uid", "u"."username", "u"."screen_name", "l"."created_at" FROM "users" AS "u" INNER JOIN "comment_likes" AS "l" ON "l"."user_id" = "u"."id" WHERE "l"."comment_id" = ?',
          [commentId],
        );
        await addQuad(hasUpvoteCount(commentResourceId, cLikers.rows.length));

        const clPromises = cLikers.rows.map(async (cLiker) => {
          const clikerResourceId = `urn:uuid:${cLiker.uid}`;
          const clikeResourceId = `${frf}${comment.comment_uuid}/like/${cLiker.uid}`;

          await addQuad(schemaType(clikeResourceId, 'LikeAction'));
          await addQuad(actionAgent(clikeResourceId, clikerResourceId));
          await addQuad(actionObject(clikeResourceId, commentResourceId));
          await addQuad(actionStart(clikeResourceId, fixIso(cLiker.created_at)));

          Reflect.deleteProperty(cLiker, 'created_at');
          otherUsers.add(cLiker);
        });

        await Promise.all(clPromises);
      });

      return cPromises;
    };

    process.stdout.write(`- getting user's posts: `);

    {
      // User's posts
      const timeline = await user.getPostsTimeline();

      const sql = `SELECT * FROM "posts" WHERE "feed_ids" && '{${timeline.intId}}'`;
      const cursor = pg.query(new PgCursor(sql));
      const read = promisify(cursor.read).bind(cursor);

      // eslint-disable-next-line no-constant-condition
      while (true) {
        const rows = await read(100);

        if (rows.length === 0) {
          cursor.close(noop);
          break;
        }

        process.stdout.write('.');

        for (const postRow of rows) {
          const postResourceId = `urn:uuid:${postRow.uid}`;

          await addQuad(hasBlogPost(blogId, postResourceId));
          await addQuad(schemaType(postResourceId, 'BlogPosting'));
          await addQuad(
            objUrl(postResourceId, `https://freefeed.net/${user.username}/${postRow.uid}`),
          );
          await addQuad(createdAt(postResourceId, fixIso(postRow.created_at)));
          await addQuad(updatedAt(postResourceId, fixIso(postRow.updated_at)));
          await addQuad(hasText(postResourceId, postRow.body));

          const likers = await knex.raw(
            'SELECT "u"."uid", "u"."username", "u"."screen_name", "l"."created_at" FROM "users" AS "u" INNER JOIN "likes" AS "l" ON "l"."user_id" = "u"."uid" WHERE "l"."post_id" = ?',
            [postRow.uid],
          );
          const lPromises = likers.rows.map(async (liker) => {
            const userId = `urn:uuid:${liker.uid}`;
            const likeId = `${frf}${postRow.uid}/like/${liker.uid}`;

            await addQuad(schemaType(likeId, 'LikeAction'));
            await addQuad(actionAgent(likeId, userId));
            await addQuad(actionObject(likeId, postResourceId));
            await addQuad(actionStart(likeId, fixIso(liker.created_at)));

            Reflect.deleteProperty(liker, 'created_at');
            otherUsers.add(liker);
          });

          const cPromises = await commentsAsQuads(postRow.uid, postResourceId);

          await Promise.all(lPromises); // likes
          await Promise.all(cPromises); // comments + comment-likes
        }
      }
    }

    process.stdout.write('\n');

    process.stdout.write(`- getting user's direct messages: `);

    {
      // Direct messages
      const timeline = await user.getDirectsTimeline();

      const sql = `SELECT * FROM "posts" WHERE "feed_ids" && '{${timeline.intId}}'`;
      const cursor = pg.query(new PgCursor(sql));
      const read = promisify(cursor.read).bind(cursor);

      // eslint-disable-next-line no-constant-condition
      while (true) {
        const rows = await read(100);

        if (rows.length === 0) {
          cursor.close(noop);
          break;
        }

        process.stdout.write('.');

        for (const postRow of rows) {
          const postResourceId = `urn:uuid:${postRow.uid}`;

          let senderId = user.id;
          let sender = blogId;
          let postUrl = `https://freefeed.net/${user.username}/${postRow.uid}`;

          if (postRow.user_id !== userUuid) {
            const authorRows = await knex.raw(
              'SELECT "u"."uid", "u"."username", "u"."screen_name" FROM "users" AS "u" WHERE "u"."uid" = ?',
              [postRow.user_id],
            );
            const [author] = authorRows.rows;

            senderId = author.uid;
            sender = `urn:uuid:${author.uid}`;
            postUrl = `https://freefeed.net/${author.username}/${postRow.uid}`;

            otherUsers.add(author);
          }

          await addQuad(schemaType(postResourceId, 'Message'));
          await addQuad(messageSender(postResourceId, sender));
          await addQuad(objUrl(postResourceId, postUrl));
          await addQuad(createdAt(postResourceId, fixIso(postRow.created_at)));
          await addQuad(updatedAt(postResourceId, fixIso(postRow.updated_at)));
          await addQuad(hasText(postResourceId, postRow.body));

          const recipientSql = pgFormat(
            'SELECT "u"."uid", "u"."username", "u"."screen_name" FROM "users" AS "u" inner join feeds f on f.user_id = u.uid where f.id in (%L)',
            postRow.destination_feed_ids,
          );
          const recipientResult = await knex.raw(recipientSql);
          const rPromises = recipientResult.rows.map(async (recipient) => {
            if (recipient.uid === senderId) {
              return;
            }

            const recipientUrl = `urn:uuid:${recipient.uid}`;
            await addQuad(messageRecipient(postResourceId, recipientUrl));

            otherUsers.add(recipient);
          });

          const likers = await knex.raw(
            'SELECT "u"."uid", "u"."username", "u"."screen_name", "l"."created_at" FROM "users" AS "u" INNER JOIN "likes" AS "l" ON "l"."user_id" = "u"."uid" WHERE "l"."post_id" = ?',
            [postRow.uid],
          );
          const lPromises = likers.rows.map(async (liker) => {
            const userId = `urn:uuid:${liker.uid}`;
            const likeId = `${frf}${postRow.uid}/like/${liker.uid}`;

            await addQuad(schemaType(likeId, 'LikeAction'));
            await addQuad(actionAgent(likeId, userId));
            await addQuad(actionObject(likeId, postResourceId));
            await addQuad(actionStart(likeId, fixIso(liker.created_at)));

            Reflect.deleteProperty(liker, 'created_at');
            otherUsers.add(liker);
          });

          const cPromises = await commentsAsQuads(postRow.uid, postResourceId);

          await Promise.all(rPromises); // recipients
          await Promise.all(lPromises); // likes
          await Promise.all(cPromises); // comments + comment-likes
        }
      }
    }

    process.stdout.write('\n');

    const downloadUrls = [];
    process.stdout.write(`- getting user's attachments: `);

    {
      const attachmentTypes = {
        audio: 'AudioObject',
        general: 'DataDownload',
        image: 'ImageObject',
      };

      const sql = `SELECT * FROM "attachments" WHERE "user_id" = $1`; // using '$1' instead of '?' as we're VERY close to postgres in this call
      const cursor = pg.query(new PgCursor(sql, [user.id]));
      const read = promisify(cursor.read).bind(cursor);

      // eslint-disable-next-line no-constant-condition
      while (true) {
        const rows = await read(100);

        if (rows.length === 0) {
          cursor.close(noop);
          break;
        }

        process.stdout.write('.');

        for (const attachmentRow of rows) {
          if (attachmentRow.media_type === null) {
            // skip bogus attachments
            continue;
          }

          const attResourceId = `urn:uuid:${attachmentRow.uid}`;

          let downloadUrl = `${config.attachments.url}${config.attachments.path}${attachmentRow.uid}`;

          if (attachmentRow.file_extension) {
            downloadUrl = `${downloadUrl}.${attachmentRow.file_extension}`;
          }

          downloadUrls.push(downloadUrl);

          await addQuad(schemaType(attResourceId, attachmentTypes[attachmentRow.media_type]));
          await addQuad(createdAt(attResourceId, fixIso(attachmentRow.created_at)));
          await addQuad(updatedAt(attResourceId, fixIso(attachmentRow.updated_at)));
          await addQuad(objUrl(attResourceId, downloadUrl));
          await addQuad(hasFilename(attResourceId, attachmentRow.file_name));

          if (attachmentRow.mime_type) {
            await addQuad(hasMimetype(attResourceId, attachmentRow.mime_type));
          }

          if (attachmentRow.post_id) {
            // some attachments are not connected to posts
            const postResourceId = `urn:uuid:${attachmentRow.post_id}`;
            await addQuad(hasAttachment(postResourceId, attResourceId));
          }
        }
      }
    }

    process.stdout.write('\n');

    process.stdout.write(`- storing additional user-resources\n`);

    for (const otherUser of [...otherUsers]) {
      const userId = `urn:uuid:${otherUser.uid}`;

      await addQuad(schemaType(userId, 'Blog'));
      await addQuad(objIdentifier(userId, otherUser.username));
      await addQuad(objName(userId, otherUser.screen_name));
    }

    knex.client.releaseConnection(pg);
    const ntriples = await getResult();

    return { ntriples, downloadUrls };
  }
}
<|endoftext|>


<commit_before>console.log('hello world');<commit_msg>Updated display and added a simple option for toggling automation.<commit_after>
// Reconfigure static page display
// ========================

var container = $('#game');
var column = $('.column');

container.css({
    fontFamily: 'Courier New',
    fontSize: '12px',
    minWidth: '1300px',
    top: '32px'
});

column.css({
    minHeight: 'inherit',
    maxWidth: 'inherit',
    padding: '1%',
    margin: 0
});

var left = $('#leftColumn');
var middle = $('#midColumn');
var right = $('#rightColumn');

left.css({
    overflowY: 'hidden',
    height: '94%',
    width: '26%'
});

middle.css({
    marginTop: '1%',
    height: '94%',
    width: '48%'
});

right.css({
    height: '94%',
    width: '19%'
});

// Reconfigure dynamic page display
// ================================

var addRule = function (rule) {
    var sheets = document.styleSheets;

    for (var i = 0; i < sheets.length; i++) {
        var sheet = sheets[i];

        sheet.insertRule(rule, 0);
    }
};

addRule('#gameLog .msg {' +
'display: block;' +
'}');

addRule('#game .btn {' +
'border-radius: 0px;' +
'font-family: "Courier New";' +
'font-size: "10px";' +
'margin: 0 0 5px 0;' +
'}');

// Add options element
// ===================

var optionsElement = $('<div/>', {css: {marginBottom: '10px'}});
var toggleEngine = $('<input/>', {
    id: 'toggle-engine',
    type: 'checkbox',
    checked: 'checked'
});
var toggleEngineLabel = $('<label/>', {
    'for': 'toggle-engine',
    text: 'Toggle Kitten Scientists!'
});

right.prepend(optionsElement.append(toggleEngine, toggleEngineLabel));

<|endoftext|>


<commit_before>'use strict';

/* Services */

// Demonstrate how to register services
// In this case it is a simple value service.
angular.module('myApp.services', []).
  value('version', '0.1')
  .factory("moviesService", function($http){
    var _movies = [];

    var _getMovies = function(){
        $http.get("js/data/movies.json")
            .then(function(results){
                //Success
                angular.copy(results.data, _movies); //this is the preferred; instead of $scope.movies = result.data
            }, function(results){
                //Error
            })
    }

    var _addNewMovie = function(movie){
        _movies.splice(0, 0, movie);
    }
    var _removeMovie = function(idx){
    	var person_to_delete = _movies[idx];
    	_movies.splice(idx, 1);
    	/*
    	angular.forEach(_movies, function(value, key){
    		if(value.id == movie.id){
	  		   _movies.splice(idx, 1);
  		  	}
    	});
    	*/
    }

    return{
        movies: _movies,
        getMovies: _getMovies,
        addNewMovie: _addNewMovie,
        removeMovie:_removeMovie
    };
});

<commit_msg>Updating service to remove a particular index clicked<commit_after>'use strict';

/* Services */

// Demonstrate how to register services
// In this case it is a simple value service.
angular.module('myApp.services', []).
  value('version', '0.1')
  .factory("moviesService", function($http){
    var _movies = [];

    var _getMovies = function(){
        $http.get("js/data/movies.json")
            .then(function(results){
                //Success
                angular.copy(results.data, _movies); //this is the preferred; instead of $scope.movies = result.data
            }, function(results){
                //Error
            })
    }

    var _addNewMovie = function(movie){
        _movies.splice(0, 0, movie);
    }
    var _removeMovie = function(idx){
    	var person_to_delete = _movies[idx.id];
    	_movies.splice(idx.id, 1);
    	/*
    	angular.forEach(_movies, function(value, key){
    		if(value.id == movie.id){
	  		   _movies.splice(idx, 1);
  		  	}
    	});
    	*/
    }

    return{
        movies: _movies,
        getMovies: _getMovies,
        addNewMovie: _addNewMovie,
        removeMovie:_removeMovie
    };
});

<|endoftext|>


<commit_before>'use strict';

// Declare app level module which depends on views, and components
angular.module('myApp', [
  'ngRoute',
  'myApp.view1',
  'myApp.view2',
  'myApp.version'
]).
config(['$routeProvider', function($routeProvider) {
  $routeProvider.otherwise({redirectTo: '/view1'});
}]);
<commit_msg>services changes<commit_after>angular.module('F1FeederApp.services', []).
  factory('ergastAPIservice', function($http) {

    var ergastAPI = {};

    ergastAPI.getDrivers = function() {
      return $http({
        method: 'JSONP',
        url: 'http://ergast.com/api/f1/2013/driverStandings.json?callback=JSON_CALLBACK'
      });
    }

    return ergastAPI;
  });
<|endoftext|>


<commit_before>Template.setup_finish.events({
  'click .finish-button': function (e) {
    var enableDiagnostics = $('.install-diagonistics input').attr('checked') ? true : false;
    Installs.insert({version: Installer.CURRENT_VERSION});
    var settings = Settings.findOne();
    if (!settings) {
      Settings.insert({tracking: enableDiagnostics});
    } else {
      settings.update(settings._id, {
        $set: {
          tracking: true
        }
      });
    }
    Router.go('dashboard_apps');
    e.preventDefault();
    e.stopPropagation();
    return false;
  }
});
<commit_msg>Fixed tracking not being applied.<commit_after>Template.setup_finish.events({
  'click .finish-button': function (e) {
    var enableDiagnostics = $('.install-diagonistics input').attr('checked') ? true : false;
    Installs.insert({version: Installer.CURRENT_VERSION});
    var settings = Settings.findOne();
    if (!settings) {
      Settings.insert({tracking: enableDiagnostics});
    } else {
      settings.update(settings._id, {
        $set: {
          tracking: enableDiagnostics
        }
      });
    }
    Router.go('dashboard_apps');
    e.preventDefault();
    e.stopPropagation();
    return false;
  }
});
<|endoftext|>


<commit_before>"use strict";
angular.module('myApp.login', ['firebase.utils', 'firebase.auth', 'ngRoute'])

    .config(['$routeProvider', function($routeProvider) {
      $routeProvider.when('/login', {
        controller: 'LoginCtrl',
        templateUrl: 'login/login.html'
      });
    }])

    .controller('LoginCtrl', ['$scope', 'Auth', '$location', 'fbutil', '$firebaseObject', function($scope, Auth, $location, fbutil, $firebaseObject) {
      $scope.email = null;
      $scope.pass = null;

      $scope.login = function(email, pass) {
        Auth.$authWithOAuthPopup('google', {scope:'email'})
            .then(function (authObject) {
              console.log(authObject);
                var profile = $firebaseObject(fbutil.ref('users', authObject.uid));
              var ref = fbutil.ref('users', authObject.uid);

                var obj = $firebaseObject(ref);

                // to take an action after the data loads, use the $loaded() promise
                obj.$loaded().then(function() {
                    console.log("loaded record:", obj.$id, obj.someOtherKeyInData);

                    // To iterate the key/value pairs of the object, use angular.forEach()
                    angular.forEach(obj, function(value, key) {
                        console.log(key, value);
                    });
                });
              return fbutil.handler(function(cb) {
                ref.set({email: authObject.google.email, name: authObject.google.cachedUserProfile.name, online: 'true'}, cb);
              });
            })
            .then(function(/* user */) {
              // redirect to the account page
              var authdata = Auth.$getAuth();
              console.log('Login UID = '+authdata.uid);
              $location.path('/account');
            }, function(err) {
              $scope.err = errMessage(err);
            });
      };
    }]);<commit_msg>no message<commit_after>"use strict";
angular.module('myApp.login', ['firebase.utils', 'firebase.auth', 'ngRoute'])

    .config(['$routeProvider', function($routeProvider) {
      $routeProvider.when('/login', {
        controller: 'LoginCtrl',
        templateUrl: 'login/login.html'
      });
    }])

    .controller('LoginCtrl', ['$scope', 'Auth', '$location', 'fbutil', '$firebaseObject', function($scope, Auth, $location, fbutil, $firebaseObject) {
      $scope.email = null;
      $scope.pass = null;

      $scope.login = function(email, pass) {
        Auth.$authWithOAuthPopup('google', {scope:'email'})
            .then(function (authObject) {
              console.log(authObject);
              var ref = fbutil.ref('users', authObject.uid);

                var obj = $firebaseObject(ref);

                // to take an action after the data loads, use the $loaded() promise
                obj.$loaded().then(function() {
                    console.log("loaded record:", obj.$id, obj.someOtherKeyInData);

                    // To iterate the key/value pairs of the object, use angular.forEach()
                    angular.forEach(obj, function(value, key) {
                        console.log(key, value);
                    });

                    if(obj.online){
                        console.log('exist');
                        obj.online = 'update';
                        obj.$save();
                    }else{
                        return fbutil.handler(function(cb) {
                            ref.set({email: authObject.google.email, name: authObject.google.cachedUserProfile.name, online: 'true'}, cb);
                        });
                    }
                });

            })
            .then(function(/* user */) {
              // redirect to the account page
              var authdata = Auth.$getAuth();
              console.log('Login UID = '+authdata.uid);
              $location.path('/account');
            }, function(err) {
              $scope.err = errMessage(err);
            });
      };
    }]);<|endoftext|>


<commit_before>import eventMatches from '../polyfills/event-matches';

export default class FabButton {
  constructor(element) {
    if (!element || element.nodeType !== Node.ELEMENT_NODE) {
      throw new TypeError('DOM element should be given to initialize this widget.');
    }
    this.element = element;

    this.constructor.components.set(this.element, this);

    element.addEventListener('click', (event) => this.toggle(event));
  }

  static init(target = document) {
    if (target.nodeType !== Node.ELEMENT_NODE && target.nodeType !== Node.DOCUMENT_NODE) {
      throw new Error('DOM document or DOM element should be given to search for and initialize this widget.');
    }
    if (target.nodeType === Node.ELEMENT_NODE && target.dataset.fab !== undefined) {
      this.create(target);
    } else {
      const handler = (event) => {
        const element = eventMatches(event, '[data-fab]');
        if (element && !this.components.has(element)) {
          this.create(element).toggle(event);
        }
      };
      target.addEventListener('click', handler);
      return {
        release: () => target.removeEventListener('click', handler),
      };
    }
  }

  toggle(event) {
    if (this.element.tagName === 'A') {
      event.preventDefault();
    }

    if (this.element.dataset.state === 'closed') {
      this.element.dataset.state = 'open';
    } else {
      this.element.dataset.state = 'closed';
    }
  }

  release() {
    this.constructor.components.delete(this.element);
  }

  static create(element) {
    return this.components.get(element) || new this(element);
  }
}

FabButton.components = new WeakMap();
<commit_msg>JSDoc comments for floating action button, refs #564. (#1202)<commit_after>import eventMatches from '../polyfills/event-matches';

export default class FabButton {
  /**
   * Floating action button.
   * @implements Component
   * @param {HTMLElement} element The element working as a floting action button.
   */
  constructor(element) {
    if (!element || element.nodeType !== Node.ELEMENT_NODE) {
      throw new TypeError('DOM element should be given to initialize this widget.');
    }
    this.element = element;

    this.constructor.components.set(this.element, this);

    element.addEventListener('click', (event) => this.toggle(event));
  }

  /**
   * Instantiates floating action buttons in the given element.
   * If the given element indicates that it's an floating action button (having `data-fab` attribute), instantiates it.
   * Otherwise, instantiates floating action buttons by clicking on floating action buttons in the given node.
   * @param {Node} target The DOM node to instantiate floating action buttons in. Should be a document or an element.
   * @returns {Handle} The handle to remove the event listener to handle clicking.
   */
  static init(target = document) {
    if (target.nodeType !== Node.ELEMENT_NODE && target.nodeType !== Node.DOCUMENT_NODE) {
      throw new Error('DOM document or DOM element should be given to search for and initialize this widget.');
    }
    if (target.nodeType === Node.ELEMENT_NODE && target.dataset.fab !== undefined) {
      this.create(target);
    } else {
      const handler = (event) => {
        const element = eventMatches(event, '[data-fab]');
        if (element && !this.components.has(element)) {
          this.create(element).toggle(event);
        }
      };
      target.addEventListener('click', handler);
      return {
        release: () => target.removeEventListener('click', handler),
      };
    }
  }

  /**
   * Toggles this floating action button.
   * @param {Event} event The event triggering this method.
   */
  toggle(event) {
    if (this.element.tagName === 'A') {
      event.preventDefault();
    }

    if (this.element.dataset.state === 'closed') {
      this.element.dataset.state = 'open';
    } else {
      this.element.dataset.state = 'closed';
    }
  }

  release() {
    this.constructor.components.delete(this.element);
  }

  /**
   * Instantiates floating action button of the given element.
   * @param {HTMLElement} element The element.
   */
  static create(element) {
    return this.components.get(element) || new this(element);
  }
}

/**
 * The map associating DOM element and floating action button instance.
 * @type {WeakMap}
 */
FabButton.components = new WeakMap();
<|endoftext|>


<commit_before>/// <binding BeforeBuild='default' Clean='clean' />
/// <reference path="wwwroot/ts/tsd.d.ts" />
"use strict";

var gulp = require("gulp"),
    shell = require("gulp-shell"),
    rimraf = require("rimraf"),
    concat = require("gulp-concat"),
    cssmin = require("gulp-cssmin"),
    uglify = require("gulp-uglify"),
    sass = require("gulp-sass"),
    autoprefixer = require("gulp-autoprefixer"),
    sourcemaps = require("gulp-sourcemaps"),
    ts = require("gulp-typescript");

var paths = {
    webroot: "./wwwroot/"
};

paths.ts = paths.webroot + "ts/**/*.ts";
paths.js = paths.webroot + "js/**/*.js";
paths.minJs = paths.webroot + "js/**/*.min.js";
paths.css = paths.webroot + "css/**/*.css";
paths.minCss = paths.webroot + "css/**/*.min.css";
paths.concatJsDest = paths.webroot + "js/site.min.js";
paths.concatCssDest = paths.webroot + "css/site.min.css";

gulp.task("clean:js", function (cb) {
    rimraf(paths.webroot + "js/", cb);
});

gulp.task("clean:css", function (cb) {
    rimraf(paths.webroot + "css/", cb);
});

gulp.task("clean", ["clean:js", "clean:css"]);

gulp.task("min:js",["typescript"], function () {
    return gulp.src([paths.js, "!" + paths.minJs], { base: "." })
        .pipe(concat(paths.concatJsDest))
        .pipe(uglify())
        .pipe(gulp.dest("."));
});

gulp.task("min:css", function () {
    return gulp.src([paths.css, "!" + paths.minCss])
        .pipe(concat(paths.concatCssDest))
        .pipe(cssmin())
        .pipe(gulp.dest("."));
});

gulp.task("min", ["min:js", "sass"]);

gulp.task("default", ["min"]);

gulp.task("install", ["min"]);

gulp.task("typescript", ["tsd:rebundle"] ,function () {
    return gulp.src(paths.ts)
        .pipe(ts({
            noImplicitAny: true,
            out: "site.js"
        })
        .pipe(gulp.dest(paths.webroot + "js/")));
});

gulp.task("tsd:install", shell.task([
        "\"node_modules/.bin/tsd\" install"
])
);

gulp.task("tsd:rebundle",["tsd:install"], shell.task([
        "\"node_modules/.bin/tsd\" rebundle"
])
);

gulp.task("sass", function () {
    return gulp.src(paths.webroot +"sass/*.scss")
        .pipe(sass().on('error', sass.logError))
        .pipe(sourcemaps.init())
        .pipe(autoprefixer())
        .pipe(concat("stylesheet.css"))
        .pipe(sourcemaps.write("."))
        .pipe(cssmin())
        .pipe(gulp.dest(paths.webroot + "css/"));
});<commit_msg>remove min:js<commit_after>/// <binding BeforeBuild='default' Clean='clean' />
/// <reference path="wwwroot/ts/tsd.d.ts" />
"use strict";

var gulp = require("gulp"),
    shell = require("gulp-shell"),
    rimraf = require("rimraf"),
    concat = require("gulp-concat"),
    cssmin = require("gulp-cssmin"),
    uglify = require("gulp-uglify"),
    sass = require("gulp-sass"),
    autoprefixer = require("gulp-autoprefixer"),
    sourcemaps = require("gulp-sourcemaps"),
    ts = require("gulp-typescript");

var paths = {
    webroot: "./wwwroot/"
};

paths.ts = paths.webroot + "ts/**/*.ts";
paths.js = paths.webroot + "js/**/*.js";
paths.minJs = paths.webroot + "js/**/*.min.js";
paths.css = paths.webroot + "css/**/*.css";
paths.minCss = paths.webroot + "css/**/*.min.css";
paths.concatJsDest = paths.webroot + "js/site.min.js";
paths.concatCssDest = paths.webroot + "css/site.min.css";

gulp.task("clean:js", function (cb) {
    rimraf(paths.webroot + "js/", cb);
});

gulp.task("clean:css", function (cb) {
    rimraf(paths.webroot + "css/", cb);
});

gulp.task("clean", ["clean:js", "clean:css"]);

gulp.task("min:js",["typescript"], function () {
    return gulp.src([paths.js, "!" + paths.minJs], { base: "." })
        .pipe(concat(paths.concatJsDest))
        .pipe(uglify())
        .pipe(gulp.dest("."));
});

gulp.task("min:css", function () {
    return gulp.src([paths.css, "!" + paths.minCss])
        .pipe(concat(paths.concatCssDest))
        .pipe(cssmin())
        .pipe(gulp.dest("."));
});

gulp.task("min", ["typescript","sass"]);

gulp.task("default", ["min"]);

gulp.task("install", ["min"]);

gulp.task("typescript", ["tsd:rebundle"] ,function () {
    return gulp.src(paths.ts)
        .pipe(ts({
            noImplicitAny: true,
            out: "site.js"
        })
        .pipe(gulp.dest(paths.webroot + "js/")));
});

gulp.task("tsd:install", shell.task([
        "\"node_modules/.bin/tsd\" install"
])
);

gulp.task("tsd:rebundle",["tsd:install"], shell.task([
        "\"node_modules/.bin/tsd\" rebundle"
])
);

gulp.task("sass", function () {
    return gulp.src(paths.webroot +"sass/*.scss")
        .pipe(sourcemaps.init())
        .pipe(sass().on('error', sass.logError))
        .pipe(autoprefixer())
        .pipe(concat("stylesheet.css"))
        .pipe(cssmin())
        .pipe(sourcemaps.write("."))
        .pipe(gulp.dest(paths.webroot + "css/"));
});<|endoftext|>


<commit_before>/**
 * Copyright 2012 Adobe Systems Incorporated
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

/**
 * Pender Event
 *
 * basic base class definition supporting custom events
 * written to avoid dependency on a larger library
 * defines a very basic custom event api
 * author: Lorin Beer
 * email : lorin@adobe.com
 */

var PenderEvent = {
    _listeners : {},

    addListener : function (event,listener) {
	if (typeof _listeners[event] === "undefined") {
	    _listeners[event] = [];
	}
	_listeners[event].push (listener);
    },

    fire : function (event,firer) {
	var i = 0;
	if (!(typeof _listeners[event] === "unidentified")) {
	    listeners[i].handle(event,firer);
	}
    }
}<commit_msg>tweaked fixed access syntax error<commit_after>/**
 * Copyright 2012 Adobe Systems Incorporated
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

/**
 * Pender Event
 *
 * basic base class definition supporting custom events
 * written to avoid dependency on a larger library
 * defines a very basic custom event api
 * author: Lorin Beer
 * email : lorin@adobe.com
 */

var PenderEvent = {
    _listeners : {},

    addListener : function (event,listener) {
	if (typeof this._listeners[event] === "undefined") {
	    this._listeners[event] = [];
	}
	this._listeners[event].push (listener);
    },

    fire : function (event,firer) {
	var i = 0;
	if (!(typeof this._listeners[event] === "unidentified")) {
	    this._listeners[i].handle(event,firer);
	}
    }
}<|endoftext|>


<commit_before>// This is a bit of a wreck right now. Don't look.
window.Dynamic = (function() {

	var _models = [];
	var _dynamicNodes = [];

	/**
	 * Gets all elements with specified attribute
	 * Doesn't support 'for' attribute in ie7
	 * @private
	 * @param {String} node
	 * @param {String} attr
	 * @return {NodeList|Array} Matching nodes
	 */
	var _getElementsWithAttribute = function(node, attr) {
		if (node.querySelectorAll) {
			return node.querySelectorAll('[' + attr + ']');
		} else {
			var matchingNodes = [];
			var allNodes = node.getElementsByTagName('*');

			for (var i=0, iLen=allNodes.length; i<iLen; i++) {
				var thisNode = allNodes[i];
				if (thisNode.getAttribute(attr)) {
					matchingNodes.push(thisNode);
				}
			}
			return matchingNodes;
		}
	};

	/**
	 * Add an event listener
	 *
	 * @private
	 * @param {HTMLElement} node The node to add the listener to
	 * @param {String} evt Name of the event to listen for
	 * @param {Function} callback
	 * @return {Event} The event
	 */
	var _addEvent = function(node, evt, callback) {
		if (node.addEventListener) {
			return node.addEventListener(evt, callback, false);
		} else if (node.attachEvent)  {
			return node.attachEvent('on' + evt, callback);
		}
	};

	/**
	 * Delegated event listener for tags
	 *
	 * @private
	 * @Param {String} tag The type of element to listen for
	 * @param {String} evt Name of the event to listen for
	 * @param {Function} callback
	 * @param {HTMLElement} container Node to add the listener to
	 * @return {Event} The added event
	 */
	var _addDelegateByTag = function(tag, evt, callback, container) {
		container = container || document.body;

		// Change events don't bubble in ie8-
		// Add listener to every tag instead (boo)
		if (evt === 'change' && !container.addEventListener) {
			var changeNodes = container.getElementsByTagName(tag);
			for (var i=0; i<changeNodes.length; i++) {
				_addEvent(changeNodes[i], evt, function(ev) {
					var target = ev.target || ev.srcElement;
					callback.apply(target);
				});
			}
			return true;
		}

		return _addEvent(container, evt, function(ev) {
			var target = ev.target || ev.srcElement;
			if (target.nodeName === tag.toUpperCase()) {
				callback.apply(target);
			}
		});
	};

	var _getNodeValue = function(node) {
		if (node.type === 'checkbox' || node.type === 'radio') {
			return node.checked;
		}
		return node.value;
	};

	var _getRadioModelValue = function(radioModel) {
		for (var i=0, iLen=radioModel.node.length; i<iLen; i++) {
			var radio = radioModel.node[i];
			if (radio.checked) {
				return radio.value;
			}
		}
		return '';
	};

	var _initModel = function(node) {
		if (node.nodeName === 'INPUT' || node.nodeName === 'SELECT') {
			var modelName = node.getAttribute('data-model');

			if (node.type === 'radio') {
				if (_models[modelName]) {
					_models[modelName].node.push(node);
				} else {
					_models[modelName] = {
						node: [node],
						value: ''
					};
				}
				_models[modelName].value = _getRadioModelValue(_models[modelName]);
			} else {
				_models[modelName] = {
					node: node,
					value: _getNodeValue(node)
				};
			}

		} else {
			// garbage
		}
	};

	var _checkModel = function() {
		var modelName = this.getAttribute('data-model');

		if (modelName) {
			if (_models[modelName]) {
				var model = _models[modelName];
				var oldValue = model.value;

				if (this.type === 'radio') {
					model.value = _getRadioModelValue(model);
				} else {
					model.value = _getNodeValue(this);
				}

				if (model.value !== oldValue) {
					_applyRules();
				}
			} else {
				// create model?
			}
		}
	};

	var _applyRules = function() {
		var flattenedModels = _getFlattenedModels();
		for (var i=0, iLen=_dynamicNodes.length; i<iLen; i++) {
			var node = _dynamicNodes[i];
			var val;
			var expr = node.getAttribute('data-show');

			with (flattenedModels) {
				val = eval(expr); // it's either this or a large expression parsing library
			}

			node.style.display = (val) ? '' : 'none';
		}
	};

	var _getFlattenedModels = function() {
		var flattened = [];
		for (var i in _models) {
			flattened[i] = _models[i].value;
		}
		return flattened;
	};

	(function init() {
		var modelList = _getElementsWithAttribute(document, 'data-model');
		for (var i=0, iLen=modelList.length; i<iLen; i++) {
			_initModel(modelList[i]);
		}

		_dynamicNodes = _getElementsWithAttribute(document, 'data-show');

		_addDelegateByTag('input', 'click', _checkModel);
		_addDelegateByTag('input', 'change', _checkModel);
		_addDelegateByTag('input', 'keyup', _checkModel);
		_addDelegateByTag('select', 'change', _checkModel);

		_applyRules();
	})();

	return {
		_models: _models
	};

})();
<commit_msg>onready function, add name attrs to radios<commit_after>// This is a bit of a wreck right now. Don't look.
window.Dynamic = (function() {

	var _models = [];
	var _dynamicNodes = [];

	/**
	 * Gets all elements with specified attribute
	 * Doesn't support 'for' attribute in ie7
	 * @private
	 * @param {String} node
	 * @param {String} attr
	 * @return {NodeList|Array} Matching nodes
	 */
	var _getElementsWithAttribute = function(node, attr) {
		if (node.querySelectorAll) {
			return node.querySelectorAll('[' + attr + ']');
		} else {
			var matchingNodes = [];
			var allNodes = node.getElementsByTagName('*');

			for (var i=0, iLen=allNodes.length; i<iLen; i++) {
				var thisNode = allNodes[i];
				if (thisNode.getAttribute(attr)) {
					matchingNodes.push(thisNode);
				}
			}
			return matchingNodes;
		}
	};

	/**
	 * Add an event listener
	 *
	 * @private
	 * @param {HTMLElement} node The node to add the listener to
	 * @param {String} evt Name of the event to listen for
	 * @param {Function} callback
	 * @return {Event} The event
	 */
	var _addEvent = function(node, evt, callback) {
		if (node.addEventListener) {
			return node.addEventListener(evt, callback, false);
		} else if (node.attachEvent)  {
			return node.attachEvent('on' + evt, callback);
		}
	};

	/**
	 * Delegated event listener for tags
	 *
	 * @private
	 * @Param {String} tag The type of element to listen for
	 * @param {String} evt Name of the event to listen for
	 * @param {Function} callback
	 * @param {HTMLElement} container Node to add the listener to
	 * @return {Event} The added event
	 */
	var _addDelegateByTag = function(tag, evt, callback, container) {
		container = container || document.body;

		// Change events don't bubble in ie8-
		// Add listener to every tag instead (boo)
		if (evt === 'change' && !container.addEventListener) {
			var changeNodes = container.getElementsByTagName(tag);
			for (var i=0; i<changeNodes.length; i++) {
				_addEvent(changeNodes[i], evt, function(ev) {
					var target = ev.target || ev.srcElement;
					callback.apply(target);
				});
			}
			return true;
		}

		return _addEvent(container, evt, function(ev) {
			var target = ev.target || ev.srcElement;
			if (target.nodeName === tag.toUpperCase()) {
				callback.apply(target);
			}
		});
	};

	var _onReady = function(callback) {
		var ieTimeout;

		var ready = function(ev) {
			callback();
			cleanup(ev);
		};

		var cleanup = function(ev) {
			if (document.addEventListener) {
				document.removeEventListener('DOMContentLoaded', ready, false);
				window.removeEventListener('load', ready, false);
			} else if (ev) { // don't run if it was the setTimeout
				window.detachEvent('onreadystatechange', ready);
				clearTimeout(ieTimeout);
			}
		};

		if (document.readyState === 'complete') {
			callback();
		} else if (document.addEventListener) {
			document.addEventListener('DOMContentLoaded', ready, false);
			window.addEventListener('load', ready, false); //failsafe
		} else {
			// works unless page is rendered progressively (it'll fire too soon)
			// @see http://snook.ca/archives/javascript/settimeout_solve_domcontentloaded
			ieTimeout = setTimeout(ready);

			document.attachEvent('onreadystatechange', function(ev) {
				if (document.readyState === 'complete') { // can't trust 'interactive'
					ready(ev);
				}
			});
		}
	};

	var _getNodeValue = function(node) {
		if (node.type === 'checkbox' || node.type === 'radio') {
			return node.checked;
		}
		return node.value;
	};

	var _getRadioModelValue = function(radioModel) {
		for (var i=0, iLen=radioModel.node.length; i<iLen; i++) {
			var radio = radioModel.node[i];
			if (radio.checked) {
				return radio.value;
			}
		}
		return '';
	};

	var _initModel = function(node) {
		if (node.nodeName === 'INPUT' || node.nodeName === 'SELECT') {
			var modelName = node.getAttribute('data-model');

			if (node.type === 'radio') {
				if (_models[modelName]) {
					_models[modelName].node.push(node);
				} else {
					_models[modelName] = {
						node: [node],
						value: ''
					};
				}
				if (!node.getAttribute('name')) {
					node.setAttribute('name', modelName);
				}
				_models[modelName].value = _getRadioModelValue(_models[modelName]);
			} else {
				_models[modelName] = {
					node: node,
					value: _getNodeValue(node)
				};
			}

		} else {
			// garbage
		}
	};

	var _checkModel = function() {
		var modelName = this.getAttribute('data-model');

		if (modelName) {
			if (_models[modelName]) {
				var model = _models[modelName];
				var oldValue = model.value;

				if (this.type === 'radio') {
					model.value = _getRadioModelValue(model);
				} else {
					model.value = _getNodeValue(this);
				}

				if (model.value !== oldValue) {
					_applyRules();
				}
			} else {
				// create model?
			}
		}
	};

	var _applyRules = function() {
		var flattenedModels = _getFlattenedModels();
		for (var i=0, iLen=_dynamicNodes.length; i<iLen; i++) {
			var node = _dynamicNodes[i];
			var parsedExpressionValue;
			var expr = node.getAttribute('data-show');

			with (flattenedModels) {
				parsedExpressionValue = eval(expr); // it's either this or a large expression parsing library
			}

			node.style.display = (parsedExpressionValue) ? '' : 'none';
		}
	};

	var _getFlattenedModels = function() {
		var flattened = [];
		for (var i in _models) {
			flattened[i] = _models[i].value;
		}
		return flattened;
	};

	var _getDynNodes = function() {
		var modelList = _getElementsWithAttribute(document, 'data-model');
		for (var i=0, iLen=modelList.length; i<iLen; i++) {
			_initModel(modelList[i]);
		}

		_dynamicNodes = _getElementsWithAttribute(document, 'data-show');

		_applyRules();
	};

	(function init() {
		_onReady(function() {
			_getDynNodes();

			_addDelegateByTag('input', 'click', _checkModel);
			_addDelegateByTag('input', 'change', _checkModel);
			_addDelegateByTag('input', 'keyup', _checkModel);
			_addDelegateByTag('select', 'change', _checkModel);
		});
	})();

	return {
		_models: _models
	};

})();
<|endoftext|>


<commit_before>var _ = require('underscore');
var marked = require('marked');
var Backbone = require('backbone');
var jsyaml = require('js-yaml');
var util = require('.././util');

module.exports = Backbone.Model.extend({
  idAttribute: 'path',

  initialize: function(attributes, options) {
    options = _.clone(options) || {};
    _.bindAll(this);

    this.isClone = function() {
      return !!options.clone;
    };

    this.placeholder = new Date().format('Y-m-d') + '-your-filename.md';
    var path = attributes.path.split('?')[0];

    // Append placeholder name if file is new and
    // path matches a directory in collection or is empty string
    var dir = attributes.collection.findWhere({ path: path });
    if (this.isNew() && (!path || (dir && dir.get('type') === 'tree'))) {
      path = path ? path + '/' + this.placeholder : this.placeholder;
    }

    var extension = util.extension(path);
    var permissions = attributes.repo ?
      attributes.repo.get('permissions') : undefined;
    var type;

    this.collection = attributes.collection;

    if (this.isNew() || attributes.type === 'blob') {
      type = 'file';
    } else {
      type = attributes.type;
    }

    this.set({
      'binary': util.isBinary(extension),
      'content': this.isNew() && _.isUndefined(attributes.content) ? t('main.new.body') : attributes.content,
      'content_url': attributes.url,
      'draft': function() {
        var path = this.get('path');
        return util.draft(path);
      },
      'extension': extension,
      'lang': util.mode(extension),
      'media': util.isMedia(extension),
      'markdown': util.isMarkdown(extension),
      'name': util.extractFilename(path)[1],
      'oldpath': path,
      'path': path,
      'type': type,
      'writable': permissions ? permissions.push : false
    });
  },

  get: function(attr) {
    // Return result of functions set on model
    var value = Backbone.Model.prototype.get.call(this, attr);
    return _.isFunction(value) ? value.call(this) : value;
  },

  isNew: function() {
    return this.get('sha') == null;
  },

  parse: function(resp, options) {
    if (typeof resp === 'string') {
      return this.parseContent(resp);
    } else if (typeof resp === 'object') {
      // TODO: whitelist resp JSON
      return _.omit(resp, 'content');
    }
  },

  parseContent: function(resp, options) {
    // Extract YAML from a post, trims whitespace
    resp = resp.replace(/\r\n/g, '\n'); // normalize a little bit

    var hasMetadata = !!util.hasMetadata(resp);

    if (!hasMetadata) return {
      content: resp,
      metadata: false,
      previous: resp
    };

    var res = {
      previous: resp
    };

    res.content = resp.replace(/^(---\n)((.|\n)*?)---\n?/, function(match, dashes, frontmatter) {
      var regex = /published: false/;

      try {
        // TODO: _.defaults for each key
        res.metadata = jsyaml.safeLoad(frontmatter);

        // Default to published unless explicitly set to false
        res.metadata.published = !regex.test(frontmatter);
      } catch(err) {
        console.log('ERROR encoding YAML');
      }

      return '';
    }).trim();

    return res;
  },

  getContent: function(options) {
    options = options ? _.clone(options) : {};

    Backbone.Model.prototype.fetch.call(this, _.extend(options, {
      dataType: 'text',
      headers: {
        'Accept': 'application/vnd.github.raw'
      },
      url: this.get('content_url')
    }));
  },

  getContentSync: function(options) {
    options = options ? _.clone(options) : {};

    return Backbone.Model.prototype.fetch.call(this, _.extend(options, {
      async: false,
      dataType: 'text',
      headers: {
        'Accept': 'application/vnd.github.raw'
      },
      url: this.get('content_url')
    }));
  },

  serialize: function() {
    var metadata = this.get('metadata');

    var content = this.get('content') || '';
    var frontmatter;

    if (metadata) {
      try {
        frontmatter = jsyaml.safeDump(metadata).trim();
      } catch(err) {
        throw err;
      }

      return ['---', frontmatter, '---'].join('\n') + '\n\n' + content;
    } else {
      return content;
    }
  },

  encode: function(content) {
    // Encode UTF-8 to Base64
    // https://developer.mozilla.org/en-US/docs/Web/API/window.btoa#Unicode_Strings
    return window.btoa(window.unescape(window.encodeURIComponent(content)));
  },

  decode: function(content) {
    // Decode Base64 to UTF-8
    // https://developer.mozilla.org/en-US/docs/Web/API/window.btoa#Unicode_Strings
    return window.decodeURIComponent(window.escape(window.atob(content)));
  },

  getAttributes: function() {
    var data = {};

    _.each(this.attributes, function(value, key) {
      data[key] = this.get(key);
    }, this);

    return data;
  },

  toJSON: function() {
    // Override default toJSON method to only send necessary data to GitHub
    var path = this.get('oldpath') || this.get('path');
    var content = this.serialize();

    var data = {
      path: path,
      message: this.get('message') || this.get('placeholder'),
      content: this.get('binary') ? window.btoa(content) : this.encode(content),
      branch: this.collection.branch.get('name')
    };

    // Set sha if modifying existing file
    if (!this.isNew()) data.sha = this.get('sha');

    return data;
  },

  clone: function(attributes, options) {
    options = _.clone(options) || {};

    return new this.constructor(_.extend(_.pick(this.attributes, [
      'branch',
      'collection',
      'content',
      'metadata',
      'repo'
    ]), attributes), _.extend(options, {
      clone: true
    }));
  },

  fetch: function(options) {
    options = options ? _.clone(options) : {};

    // Series necessary for accurate isNew() check in getContent
    if (this.isNew()) {
      if (_.isFunction(options.success)) options.success();
      if (_.isFunction(options.complete)) options.complete();
    } else {
      // TODO: use deffered to fire callbacks when both functions complete
      Backbone.Model.prototype.fetch.call(this, _.omit(options, 'success', 'error', 'complete'));
      this.getContent.apply(this, arguments);
    }
  },

  save: function(options) {
    options = options ? _.clone(options) : {};

    var success = options.success;

    // set method to PUT even when this.isNew()
    if (this.isNew()) {
      options = _.extend(options, {
        type: 'PUT'
      });
    }

    options.success = (function(model, res, options) {
      this.set(_.extend(res.content, {
        previous: this.serialize()
      }));

      if (_.isFunction(success)) success.apply(this, arguments);
    }).bind(this);

    // Call save method with undefined attributes
    Backbone.Model.prototype.save.call(this, undefined, options);
  },

  patch: function(options) {
    options = _.clone(options) || {};

    var success = options.success;
    var error = options.error;

    this.collection.repo.fork({
      success: (function(repo, branch) {
        repo.ref({
          'ref': 'refs/heads/' + branch,
          'sha': this.collection.branch.get('sha'),
          'success': (function(res) {
            repo.branches.fetch({
              success: (function(collection, res, options) {
                branch = collection.findWhere({ name: branch });

                // Create new File model in forked repo
                // TODO: serialize metadata, set raw content
                var file = new module.exports({
                  branch: branch,
                  collection: collection,
                  content: this.get('content'),
                  path: this.get('path'),
                  repo: repo,
                  sha: this.get('sha')
                });

                // Add to collection on save
                file.save({
                  success: (function(model, res, options) {
                    // Update model attributes and add to collection
                    model.set(res.content);
                    branch.files.add(model);

                    $.ajax({
                      type: 'POST',
                      url: this.collection.repo.url() + '/pulls',
                      data: JSON.stringify({
                        title: res.commit.message,
                        body: 'This pull request has been automatically generated by prose.io.',
                        base: this.collection.branch.get('name'),
                        head: repo.get('owner').login + ':' + branch.get('name')
                      }),
                      success: success,
                      error: error
                    });
                  }).bind(this),
                  error: error
                });
              }).bind(this),
              error: error
            });
          }).bind(this),
          'error': options.error
        });
      }).bind(this),
      error: options.error
    });
  },

  destroy: function(options) {
    options = _.clone(options) || {};

    var path = this.get('path');

    var data = {
      path: path,
      message: t('actions.commits.deleted', { filename: path }),
      sha: this.get('sha'),
      branch: this.collection.branch.get('name')
    };

    var url = this.url().split('?')[0];
    var params = _.map(_.pairs(data), function(param) { return param.join('='); }).join('&');

    Backbone.Model.prototype.destroy.call(this, _.extend(options, {
      url: url + '?' + params,
      error: function(model, xhr, options) {
        // TODO: handle 422 Unprocessable Entity error
        console.log(model, xhr, options);
      },
      wait: true
    }));
  },

  url: function() {
    return this.collection.repo.url() + '/contents/' + this.get('path') + '?ref=' + this.collection.branch.get('name');
  },

  validate: function(attributes, options) {

    // For testing:
    // if (attributes) return 'uh oh spaghetti o'
    // Fail validation if path conflicts with another file in repo
    if (this.collection.where({ path: attributes.path }).length > 1) return t('actions.save.fileNameExists');

    // Fail validation if name matches default
    var name = util.extractFilename(this.get('path'));
    if (name === this.placeholder) return 'File name is default';

    // Fail validation if marked returns an error
    // TODO: does this work as callback?
    marked(attributes.content, {}, function(err, content) {
      if (err) return err;
    });
  }
});
<commit_msg>fix appending placeholder to path if path === '_drafts'<commit_after>var _ = require('underscore');
var marked = require('marked');
var Backbone = require('backbone');
var jsyaml = require('js-yaml');
var util = require('.././util');

module.exports = Backbone.Model.extend({
  idAttribute: 'path',

  initialize: function(attributes, options) {
    options = _.clone(options) || {};
    _.bindAll(this);

    this.isClone = function() {
      return !!options.clone;
    };

    this.placeholder = new Date().format('Y-m-d') + '-your-filename.md';
    var path = attributes.path.split('?')[0];

    // Append placeholder name if file is new and
    // path is an empty string, matches _drafts
    // or matches a directory in collection
    var dir = attributes.collection.get(path);
    if (this.isNew() && (!path || path === '_drafts' ||
      (dir && dir.get('type') === 'tree'))) {
      path = path ? path + '/' + this.placeholder : this.placeholder;
    }

    var extension = util.extension(path);
    var permissions = attributes.repo ?
      attributes.repo.get('permissions') : undefined;
    var type;

    this.collection = attributes.collection;

    if (this.isNew() || attributes.type === 'blob') {
      type = 'file';
    } else {
      type = attributes.type;
    }

    this.set({
      'binary': util.isBinary(extension),
      'content': this.isNew() && _.isUndefined(attributes.content) ? t('main.new.body') : attributes.content,
      'content_url': attributes.url,
      'draft': function() {
        var path = this.get('path');
        return util.draft(path);
      },
      'extension': extension,
      'lang': util.mode(extension),
      'media': util.isMedia(extension),
      'markdown': util.isMarkdown(extension),
      'name': util.extractFilename(path)[1],
      'oldpath': path,
      'path': path,
      'type': type,
      'writable': permissions ? permissions.push : false
    });
  },

  get: function(attr) {
    // Return result of functions set on model
    var value = Backbone.Model.prototype.get.call(this, attr);
    return _.isFunction(value) ? value.call(this) : value;
  },

  isNew: function() {
    return this.get('sha') == null;
  },

  parse: function(resp, options) {
    if (typeof resp === 'string') {
      return this.parseContent(resp);
    } else if (typeof resp === 'object') {
      // TODO: whitelist resp JSON
      return _.omit(resp, 'content');
    }
  },

  parseContent: function(resp, options) {
    // Extract YAML from a post, trims whitespace
    resp = resp.replace(/\r\n/g, '\n'); // normalize a little bit

    var hasMetadata = !!util.hasMetadata(resp);

    if (!hasMetadata) return {
      content: resp,
      metadata: false,
      previous: resp
    };

    var res = {
      previous: resp
    };

    res.content = resp.replace(/^(---\n)((.|\n)*?)---\n?/, function(match, dashes, frontmatter) {
      var regex = /published: false/;

      try {
        // TODO: _.defaults for each key
        res.metadata = jsyaml.safeLoad(frontmatter);

        // Default to published unless explicitly set to false
        res.metadata.published = !regex.test(frontmatter);
      } catch(err) {
        console.log('ERROR encoding YAML');
      }

      return '';
    }).trim();

    return res;
  },

  getContent: function(options) {
    options = options ? _.clone(options) : {};

    Backbone.Model.prototype.fetch.call(this, _.extend(options, {
      dataType: 'text',
      headers: {
        'Accept': 'application/vnd.github.raw'
      },
      url: this.get('content_url')
    }));
  },

  getContentSync: function(options) {
    options = options ? _.clone(options) : {};

    return Backbone.Model.prototype.fetch.call(this, _.extend(options, {
      async: false,
      dataType: 'text',
      headers: {
        'Accept': 'application/vnd.github.raw'
      },
      url: this.get('content_url')
    }));
  },

  serialize: function() {
    var metadata = this.get('metadata');

    var content = this.get('content') || '';
    var frontmatter;

    if (metadata) {
      try {
        frontmatter = jsyaml.safeDump(metadata).trim();
      } catch(err) {
        throw err;
      }

      return ['---', frontmatter, '---'].join('\n') + '\n\n' + content;
    } else {
      return content;
    }
  },

  encode: function(content) {
    // Encode UTF-8 to Base64
    // https://developer.mozilla.org/en-US/docs/Web/API/window.btoa#Unicode_Strings
    return window.btoa(window.unescape(window.encodeURIComponent(content)));
  },

  decode: function(content) {
    // Decode Base64 to UTF-8
    // https://developer.mozilla.org/en-US/docs/Web/API/window.btoa#Unicode_Strings
    return window.decodeURIComponent(window.escape(window.atob(content)));
  },

  getAttributes: function() {
    var data = {};

    _.each(this.attributes, function(value, key) {
      data[key] = this.get(key);
    }, this);

    return data;
  },

  toJSON: function() {
    // Override default toJSON method to only send necessary data to GitHub
    var path = this.get('oldpath') || this.get('path');
    var content = this.serialize();

    var data = {
      path: path,
      message: this.get('message') || this.get('placeholder'),
      content: this.get('binary') ? window.btoa(content) : this.encode(content),
      branch: this.collection.branch.get('name')
    };

    // Set sha if modifying existing file
    if (!this.isNew()) data.sha = this.get('sha');

    return data;
  },

  clone: function(attributes, options) {
    options = _.clone(options) || {};

    return new this.constructor(_.extend(_.pick(this.attributes, [
      'branch',
      'collection',
      'content',
      'metadata',
      'repo'
    ]), attributes), _.extend(options, {
      clone: true
    }));
  },

  fetch: function(options) {
    options = options ? _.clone(options) : {};

    // Series necessary for accurate isNew() check in getContent
    if (this.isNew()) {
      if (_.isFunction(options.success)) options.success();
      if (_.isFunction(options.complete)) options.complete();
    } else {
      // TODO: use deffered to fire callbacks when both functions complete
      Backbone.Model.prototype.fetch.call(this, _.omit(options, 'success', 'error', 'complete'));
      this.getContent.apply(this, arguments);
    }
  },

  save: function(options) {
    options = options ? _.clone(options) : {};

    var success = options.success;

    // set method to PUT even when this.isNew()
    if (this.isNew()) {
      options = _.extend(options, {
        type: 'PUT'
      });
    }

    options.success = (function(model, res, options) {
      this.set(_.extend(res.content, {
        previous: this.serialize()
      }));

      if (_.isFunction(success)) success.apply(this, arguments);
    }).bind(this);

    // Call save method with undefined attributes
    Backbone.Model.prototype.save.call(this, undefined, options);
  },

  patch: function(options) {
    options = _.clone(options) || {};

    var success = options.success;
    var error = options.error;

    this.collection.repo.fork({
      success: (function(repo, branch) {
        repo.ref({
          'ref': 'refs/heads/' + branch,
          'sha': this.collection.branch.get('sha'),
          'success': (function(res) {
            repo.branches.fetch({
              success: (function(collection, res, options) {
                branch = collection.findWhere({ name: branch });

                // Create new File model in forked repo
                // TODO: serialize metadata, set raw content
                var file = new module.exports({
                  branch: branch,
                  collection: collection,
                  content: this.get('content'),
                  path: this.get('path'),
                  repo: repo,
                  sha: this.get('sha')
                });

                // Add to collection on save
                file.save({
                  success: (function(model, res, options) {
                    // Update model attributes and add to collection
                    model.set(res.content);
                    branch.files.add(model);

                    $.ajax({
                      type: 'POST',
                      url: this.collection.repo.url() + '/pulls',
                      data: JSON.stringify({
                        title: res.commit.message,
                        body: 'This pull request has been automatically generated by prose.io.',
                        base: this.collection.branch.get('name'),
                        head: repo.get('owner').login + ':' + branch.get('name')
                      }),
                      success: success,
                      error: error
                    });
                  }).bind(this),
                  error: error
                });
              }).bind(this),
              error: error
            });
          }).bind(this),
          'error': options.error
        });
      }).bind(this),
      error: options.error
    });
  },

  destroy: function(options) {
    options = _.clone(options) || {};

    var path = this.get('path');

    var data = {
      path: path,
      message: t('actions.commits.deleted', { filename: path }),
      sha: this.get('sha'),
      branch: this.collection.branch.get('name')
    };

    var url = this.url().split('?')[0];
    var params = _.map(_.pairs(data), function(param) { return param.join('='); }).join('&');

    Backbone.Model.prototype.destroy.call(this, _.extend(options, {
      url: url + '?' + params,
      error: function(model, xhr, options) {
        // TODO: handle 422 Unprocessable Entity error
        console.log(model, xhr, options);
      },
      wait: true
    }));
  },

  url: function() {
    return this.collection.repo.url() + '/contents/' + this.get('path') + '?ref=' + this.collection.branch.get('name');
  },

  validate: function(attributes, options) {

    // For testing:
    // if (attributes) return 'uh oh spaghetti o'
    // Fail validation if path conflicts with another file in repo
    if (this.collection.where({ path: attributes.path }).length > 1) return t('actions.save.fileNameExists');

    // Fail validation if name matches default
    var name = util.extractFilename(this.get('path'));
    if (name === this.placeholder) return 'File name is default';

    // Fail validation if marked returns an error
    // TODO: does this work as callback?
    marked(attributes.content, {}, function(err, content) {
      if (err) return err;
    });
  }
});
<|endoftext|>


<commit_before>import DS from 'ember-data'

export default DS.Model.extend({
  title: DS.attr('string'),
  author: DS.attr('string'),
  updatedAt: DS.attr('date'),
  content: DS.attr('string'),
  slug: DS.attr('string')
})
<commit_msg>Sample times added<commit_after>import DS from 'ember-data'

export default DS.Model.extend({
  title: DS.attr('string'),
  author: DS.attr('string'),
  updatedAt: DS.attr('date'),
  content: DS.attr('string'),
  slug: DS.attr('string'),
  lastUpdated: Ember.computed(function () {
    var times = ['20', '1h', '5min', '10sec']
    return times[Math.floor(Math.random() * times.length)]
  })
})
<|endoftext|>


<commit_before>module.exports = function (Schema, mongoose) {
  var CommentSchema = new Schema({
    author    : { type: Schema.ObjectID },
    body      : { type: String },
    timestamp : { type: Date },
    tempname  : { type: String }
  });
  var Comment = mongoose.model('Comment', CommentSchema);
  var PostSchema = new Schema({
    timestamp : { type: Date },
    loc       : { type: Point, coordinates: [] },
    author    : { type: Schema.ObjectID },
    body      : { type: String },
    comments  : [ Comment ],
    tempname  : { type: String }
  });
  return mongoose.model('Post', PostSchema);
};<commit_msg>added list of tempnames to post model<commit_after>module.exports = function (Schema, mongoose) {
  var CommentSchema = new Schema({
    author    : { type: Schema.ObjectID },
    body      : { type: String },
    timestamp : { type: Date },
    tempname  : { type: String }
  });
  var Comment = mongoose.model('Comment', CommentSchema);
  var PostSchema = new Schema({
    timestamp : { type: Date },
    loc       : { type: Point, coordinates: [] },
    author    : { type: Schema.ObjectID },
    body      : { type: String },
    comments  : [ Comment ],
    tempname  : { type: String },
    tempnames : [{ type: String }]
  });
  return mongoose.model('Post', PostSchema);
};<|endoftext|>


<commit_before>define([
   "dojo/_base/declare",
   "dojo/on",
   "dojo/dom",
   "dojo/dom-construct",
   "dojo/dom-attr",
   "dojo/dom-class",

   "dijit/Destroyable",

  ], function(
    declare
  , on
  , dom
  , domConstruct
  , domAttr
  , domClass

  , Destroyable

  ){

  var setOverlayClickableFunc = function(value){

    // Set the method. This "IF" is necessary in case this is being added
    // to a dgrid, which is NOT watchable and doesn't have _set...
    if(this._set) this._set('overlayClickable', !! value);
    else this.overlayClickable = value;

    // This will make the widget call this.overlayClick function
    // (other widget will probably on() themselves on it to retry
    // whatever failed and caused the overlay to appear in the first place
    domClass.toggle( this.overlayNode, 'overlayClickable', value );

  }

  var setOverlayedFunc = function(value){

    // Set the method. This "IF" is necessary in case this is being added
    // to a dgrid, which is NOT watchable and doesn't have _set...
    if( this._set) this._set('overlayed', !!value);
    else this.overlayed = !!value;

    // Set the 'display' CSS value so that it becomes visible/invisible
    domAttr.set( this.overlayNode, { style: { display: value ? 'block' : 'none' } } );

  };

  return declare( Destroyable, {

    overlayed: false,
    overlayClickable: false,

    postCreate: function(){
      this.inherited(arguments);

      var that = this;

      // Create the overlay widget, place it as first in the widget
      var overlay = domConstruct.create('div', {
        className: 'overlay',
        style: {
          'position': 'absolute',
          'top': 0,
          'bottom': 0,
          'left': 0,
          'right': 0,
          'z-index': 99,
          'display': 'none',
          'background': 'rgba(0,0,0,0.32)'
        },
      }, this.domNode, 'first' );

      // Set the overlayNode attribute of the widget
      this.overlayNode = overlay;

      this.own(

        on( this.overlayNode, 'click', function(e){
          if( that.overlayClickable && typeof( that.onOverlayClick ) === 'function' ) {
            that.onOverlayClick(e);
          }
        })

      );

    },

    // This is so that this mixin is compatible with _WidgetBase and with dgrid
    _setOverlayed: setOverlayedFunc,
    _setOverlayedAttr: setOverlayedFunc,

    // Set the widget's overlay as "clickable'" or not. If it's not, the widget's
    // onOverlayClick won't get called when the overlay is clicked
    _setOverlayClickableAttr: setOverlayClickableFunc,
    _setOverlayClickable: setOverlayClickableFunc,

    onOverlayClick: function(e){ },

  });

});
<commit_msg>Changed that into self<commit_after>define([
   "dojo/_base/declare",
   "dojo/on",
   "dojo/dom",
   "dojo/dom-construct",
   "dojo/dom-attr",
   "dojo/dom-class",

   "dijit/Destroyable",

  ], function(
    declare
  , on
  , dom
  , domConstruct
  , domAttr
  , domClass

  , Destroyable

  ){

  var setOverlayClickableFunc = function(value){

    // Set the method. This "IF" is necessary in case this is being added
    // to a dgrid, which is NOT watchable and doesn't have _set...
    if(this._set) this._set('overlayClickable', !! value);
    else this.overlayClickable = value;

    // This will make the widget call this.overlayClick function
    // (other widget will probably on() themselves on it to retry
    // whatever failed and caused the overlay to appear in the first place
    domClass.toggle( this.overlayNode, 'overlayClickable', value );

  }

  var setOverlayedFunc = function(value){

    // Set the method. This "IF" is necessary in case this is being added
    // to a dgrid, which is NOT watchable and doesn't have _set...
    if( this._set) this._set('overlayed', !!value);
    else this.overlayed = !!value;

    // Set the 'display' CSS value so that it becomes visible/invisible
    domAttr.set( this.overlayNode, { style: { display: value ? 'block' : 'none' } } );

  };

  return declare( Destroyable, {

    overlayed: false,
    overlayClickable: false,

    postCreate: function(){
      this.inherited(arguments);

      var self = this;

      // Create the overlay widget, place it as first in the widget
      var overlay = domConstruct.create('div', {
        className: 'overlay',
        style: {
          'position': 'absolute',
          'top': 0,
          'bottom': 0,
          'left': 0,
          'right': 0,
          'z-index': 99,
          'display': 'none',
          'background': 'rgba(0,0,0,0.32)'
        },
      }, this.domNode, 'first' );

      // Set the overlayNode attribute of the widget
      this.overlayNode = overlay;

      this.own(

        on( self.overlayNode, 'click', function(e){
          if( self.overlayClickable && typeof( self.onOverlayClick ) === 'function' ) {
            self.onOverlayClick(e);
          }
        })

      );

    },

    // This is so that this mixin is compatible with _WidgetBase and with dgrid
    _setOverlayed: setOverlayedFunc,
    _setOverlayedAttr: setOverlayedFunc,

    // Set the widget's overlay as "clickable'" or not. If it's not, the widget's
    // onOverlayClick won't get called when the overlay is clicked
    _setOverlayClickableAttr: setOverlayClickableFunc,
    _setOverlayClickable: setOverlayClickableFunc,

    onOverlayClick: function(e){ },

  });

});
<|endoftext|>