<commit_before>describe("ilios_base", function() {

  it("should create a global ilios object", function() {
    expect(ilios).toBeDefined();
  });

  describe("ilios", function () {

    it("should have a namespace method", function () {
      expect(typeof ilios.namespace).toBe("function");
    });

    it("should have a lang namespace", function () {
      expect(typeof ilios.lang).toBe("object");
    });

    it("should have an alert namespace", function () {
      expect(typeof ilios.alert).toBe("object");
    });

    it("should have a global namespace", function () {
      expect(typeof ilios.global).toBe("object");
    });

    describe("namespace()", function () {
      afterEach(function () {
        delete ilios.foo;
      });

      it("should create the supplied namespace", function () {
        expect(typeof ilios.foo).toBe("undefined");
        ilios.namespace('foo');
        expect(typeof ilios.foo).toBe("object");
      });

      it("should create namespaces with depth > 1", function () {
        expect(typeof ilios.foo).toBe("undefined");
        ilios.namespace('foo.bar');
        expect(typeof ilios.foo).toBe("object");
        expect(typeof ilios.foo.bar).toBe("object");
      });

      it("should allow you to create a space twice", function () {
        expect(typeof ilios.foo).toBe("undefined");
        ilios.namespace('foo.bar');
        ilios.namespace('foo.baz');
        expect(typeof ilios.foo.bar).toBe("object");
        expect(typeof ilios.foo.baz).toBe("object");
      });
    });

    describe("lang", function () {
      describe("trim()", function () {
        it("should remove leading white space", function () {
          expect(ilios.lang.trim(" foo")).toBe("foo");
        });

        it("should remove trailing white space", function () {
          expect(ilios.lang.trim("foo  ")).toBe("foo");
        });

        it("should remove leading and trailing white space", function () {
          expect(ilios.lang.trim("  foo   ")).toBe("foo");
        });

        it("should not affect strings without leading or trailing spaces", function () {
          expect(ilios.lang.trim("foo")).toBe("foo");
        });

        it("should not affect spaces that are not leading or trailing", function () {
          expect(ilios.lang.trim("foo bar")).toBe("foo bar");
        });
      });

      describe("ellipsisedOfLength()", function () {
        it("should truncate str to specified number of characters and add an ellipsis", function () {
          expect(ilios.lang.ellipsisedOfLength("abcdefghijklmnopqrstuvwxyz", 10)).toBe("abcdefghij...");
        });

        it("should return str if it is shorter than length", function () {
          expect(ilios.lang.ellipsisedOfLength("abc", 10)).toBe("abc");
        });
      });
    });

    describe("alert", function () {
      describe("networkActivityI18NStrings", function () {
        it("should initialize networkActivityI18NStrings to an empty array", function () {
          expect(ilios.alert.networkActivityI18NStrings).toEqual([]);
        });
      });

      describe("updateServerInteractionProgress()", function () {
        var div;
        var text;

        beforeEach(function () {
          div = document.createElement("div");
          div.setAttribute("id", "save_in_progress_div");

          text = document.createElement("span");
          text.setAttribute("id", "save_in_progress_text");

          div.appendChild(text);

          document.body.appendChild(div);

          // test double
          window.ilios_i18nVendor = {getI18NString: function (string) { return string; }};
        });

        afterEach(function () {
          div.parentNode.removeChild(div);
          // reset alert queue to empty
          ilios.alert.networkActivityI18NStrings = [];

          // delete test double
          delete window.ilios_i18nVendor;
        });

        it("should hide save_in_progress_div if no messages in queue", function () {
          div.setAttribute("style", "display:block");
          ilios.alert.updateServerInteractionProgress();
          expect(div.getAttribute("style")).toMatch(/display:\s*none;?/);
        });

        it("should show save_in_progress_div a message is in the queue", function () {
          div.setAttribute("style", "display:none");
          ilios.alert.networkActivityI18NStrings = ["Whoa! Something's happening!"];
          ilios.alert.updateServerInteractionProgress();
          expect(div.getAttribute("style")).toMatch(/display:\s*block;?/);
        });

        it("should update text with first message in queue", function () {
          ilios.alert.networkActivityI18NStrings = ["I am Spartacus!", "No, I am Spartacus!"];
          ilios.alert.updateServerInteractionProgress();
          expect(text.innerHTML).toBe("I am Spartacus!");
        });
      });

      describe('simpleHidingHandler', function () {
        it("should call hide() on the element", function () {
          var testDouble = {hide: function () {}};
          spyOn(testDouble, "hide");
          ilios.alert.simpleHidingHandler.call(testDouble);
          expect(testDouble.hide).toHaveBeenCalled();
        });
      });
    });
  });
});
<commit_msg>acceptHandler<commit_after>describe("ilios_base", function() {

  it("should create a global ilios object", function() {
    expect(ilios).toBeDefined();
  });

  describe("ilios", function () {

    it("should have a namespace method", function () {
      expect(typeof ilios.namespace).toBe("function");
    });

    it("should have a lang namespace", function () {
      expect(typeof ilios.lang).toBe("object");
    });

    it("should have an alert namespace", function () {
      expect(typeof ilios.alert).toBe("object");
    });

    it("should have a global namespace", function () {
      expect(typeof ilios.global).toBe("object");
    });

    describe("namespace()", function () {
      afterEach(function () {
        delete ilios.foo;
      });

      it("should create the supplied namespace", function () {
        expect(typeof ilios.foo).toBe("undefined");
        ilios.namespace('foo');
        expect(typeof ilios.foo).toBe("object");
      });

      it("should create namespaces with depth > 1", function () {
        expect(typeof ilios.foo).toBe("undefined");
        ilios.namespace('foo.bar');
        expect(typeof ilios.foo).toBe("object");
        expect(typeof ilios.foo.bar).toBe("object");
      });

      it("should allow you to create a space twice", function () {
        expect(typeof ilios.foo).toBe("undefined");
        ilios.namespace('foo.bar');
        ilios.namespace('foo.baz');
        expect(typeof ilios.foo.bar).toBe("object");
        expect(typeof ilios.foo.baz).toBe("object");
      });
    });

    describe("lang", function () {
      describe("trim()", function () {
        it("should remove leading white space", function () {
          expect(ilios.lang.trim(" foo")).toBe("foo");
        });

        it("should remove trailing white space", function () {
          expect(ilios.lang.trim("foo  ")).toBe("foo");
        });

        it("should remove leading and trailing white space", function () {
          expect(ilios.lang.trim("  foo   ")).toBe("foo");
        });

        it("should not affect strings without leading or trailing spaces", function () {
          expect(ilios.lang.trim("foo")).toBe("foo");
        });

        it("should not affect spaces that are not leading or trailing", function () {
          expect(ilios.lang.trim("foo bar")).toBe("foo bar");
        });
      });

      describe("ellipsisedOfLength()", function () {
        it("should truncate str to specified number of characters and add an ellipsis", function () {
          expect(ilios.lang.ellipsisedOfLength("abcdefghijklmnopqrstuvwxyz", 10)).toBe("abcdefghij...");
        });

        it("should return str if it is shorter than length", function () {
          expect(ilios.lang.ellipsisedOfLength("abc", 10)).toBe("abc");
        });
      });
    });

    describe("alert", function () {
      describe("networkActivityI18NStrings", function () {
        it("should initialize networkActivityI18NStrings to an empty array", function () {
          expect(ilios.alert.networkActivityI18NStrings).toEqual([]);
        });
      });

      describe("updateServerInteractionProgress()", function () {
        var div;
        var text;

        beforeEach(function () {
          div = document.createElement("div");
          div.setAttribute("id", "save_in_progress_div");

          text = document.createElement("span");
          text.setAttribute("id", "save_in_progress_text");

          div.appendChild(text);

          document.body.appendChild(div);

          // test double
          window.ilios_i18nVendor = {getI18NString: function (string) { return string; }};
        });

        afterEach(function () {
          div.parentNode.removeChild(div);
          // reset alert queue to empty
          ilios.alert.networkActivityI18NStrings = [];

          // delete test double
          delete window.ilios_i18nVendor;
        });

        it("should hide save_in_progress_div if no messages in queue", function () {
          div.setAttribute("style", "display:block");
          ilios.alert.updateServerInteractionProgress();
          expect(div.getAttribute("style")).toMatch(/display:\s*none;?/);
        });

        it("should show save_in_progress_div a message is in the queue", function () {
          div.setAttribute("style", "display:none");
          ilios.alert.networkActivityI18NStrings = ["Whoa! Something's happening!"];
          ilios.alert.updateServerInteractionProgress();
          expect(div.getAttribute("style")).toMatch(/display:\s*block;?/);
        });

        it("should update text with first message in queue", function () {
          ilios.alert.networkActivityI18NStrings = ["I am Spartacus!", "No, I am Spartacus!"];
          ilios.alert.updateServerInteractionProgress();
          expect(text.innerHTML).toBe("I am Spartacus!");
        });
      });

      describe("simpleHidingHandler()", function () {
        it("should call hide() on the element", function () {
          var testDouble = {hide: function () {}};
          spyOn(testDouble, "hide");
          ilios.alert.simpleHidingHandler.call(testDouble);
          expect(testDouble.hide).toHaveBeenCalled();
        });
      });

      describe("alert()", function () {
        beforeEach(function () {
          testDouble = {
            render: jasmine.createSpy(),
            configButtons: jasmine.createSpy(),
            setBody: jasmine.createSpy(),
            cfg: {
              setProperty: jasmine.createSpy(),
              queueProperty: jasmine.createSpy()
            },
            bringToTop: jasmine.createSpy(),
            show: jasmine.createSpy()
          };
          spyOn(ilios.alert, "createConfirmDialog").and.returnValue(testDouble);
          delete ilios.alert.confirmDialog;
        });

        it("should use simpleHidingHandler() if we do not send an acceptHandler", function () {
          ilios.alert.alert("foo", "bar");
          var expected = [[{
            text: "bar",
            handler: {
              fn: ilios.alert.simpleHidingHandler,
              obj: {},
              scope: undefined
            },
            isDefault: true
          }]];
          expect(testDouble.configButtons).toHaveBeenCalledWith(null, expected, null);
        });

        it("should use acceptHandler if specified", function () {
          var acceptHandler = function () { return "I am the handler!";};
          ilios.alert.alert("foo", "bar", acceptHandler);
          var expected = [[{
            text: "bar",
            handler: {
              fn: acceptHandler,
              obj: {},
              scope:undefined
            },
            isDefault: true
          }]];
          expect(testDouble.configButtons).toHaveBeenCalledWith(null, expected, null);
        });
      });
    });
  });
});
<|endoftext|>


<commit_before>'use strict'
const url = require('url')
const Site = use('site')
const cache = use('cache')
const moment = require('moment')
const tagmap = use('tagmap')('ao3')
const qr = require('@perl/qr')
const forEach = use('for-each')

class ArchiveOfOurOwn extends Site {
  static matches (siteUrlStr) {
    const siteUrl = url.parse(siteUrlStr)
    const hostname = siteUrl.hostname
    if (!qr`(^|www[.])archiveofourown.org$`.test(hostname)) return false
    const path = siteUrl.pathname || siteUrl.path || ''
    if (!qr`^(/collections/[^/]+)?(/works/\d+|/users/)`.test(path)) return false
    return true
  }

  constructor (siteUrlStr) {
    super(siteUrlStr)
    this.link = this.link.replace(qr`/works/(\d+).*?$`, '/works/$1')
    this.publisher = 'archiveofourown.org'
    this.publisherName = 'Archive of Our Own'
    this.type = 'ao3'
    this.shortName = 'ao3'
    const siteUrl = url.parse(siteUrlStr)
    const path = siteUrl.pathname || siteUrl.path || ''
    const ficMatch = path.match(qr`^/works/(\d+)`)
    this.workId = ficMatch && ficMatch[1]
  }

  normalizeLink (href, base) {
    if (!href) return
    return super.normalizeLink(href, base)
      .replace(/#.*$/, '')
      .replace(/[/]collections[/][^/]+[/]?/, '/')
  }
  normalizeFicLink (href, base) {
    return super.normalizeFicLink(href, base)
      .replace(/[/]chapters[/]\d+/, '')
  }
  normalizeAuthorLink (href, base) {
    return super.normalizeAuthorLink(href, base)
      .replace(qr`/pseuds/.*`, '/profile')
  }
  chapterIndex () {
    return 'https://archiveofourown.org/works/' + this.workId + '/navigate'
  }
  tagGroup ($, prefix, $dd) {
    const tags = []
    $dd.find('li').each((ii, vv) => {
      tags.push(prefix + ':' + $(vv).text().trim())
    })
    return tags
  }
  async getFicMetadata (fetch, fic) {
    fic.link = this.normalizeFicLink(this.link)
    fic.publisher = this.publisherName
    fic.chapterHeadings = true
    const [meta, html] = await fetch(this.chapterIndex())
    const cheerio = require('cheerio')
    const $ = cheerio.load(html)
    if ($('.error-503-maintenance').length) {
      const err = new Error($('#main').text().trim().split(/\n/).map(l => l.trim()).join('\n'))
      err.link = this.chapterIndex()
      err.code = 503
      err.site = this.publisherName
      await cache.clearUrl(err.link)
      throw err
    }
    const base = $('base').attr('href') || this.chapterIndex()
    const $heading = $('h2.heading')
    fic.title = $heading.find('a[rel!="author"]').text()
    if (/\[archived by/.test($heading.text())) {
      $heading.find('a').remove()
      const author = $heading.text().trim().replace(/.*by (.*) \[archived by.*/, '$1').trim()
      fic.author = author
    } else {
      const $author = $heading.find('a[rel="author"]')
      const aus = []
      $author.each((ii, ac) => {
        const $ac = $(ac)
        const authorUrl = (this.normalizeChapterLink($ac.attr('href'), base) || '').replace(qr`/pseuds/.*`, '/profile')
        const authorName = $ac.text()
        fic.authors.push({name: authorName, link: authorUrl})
        if ((!fic.author && !fic.authorUrl) || ((!fic.author || !fic.authorUrl) && (authorUrl && authorName))) {
          fic.author = authorName
          fic.authorUrl = authorUrl
        }
      })
    }
    const $metadata = $('ol.index').find('li').first()
    const metadataLink = this.normalizeChapterLink($metadata.find('a').attr('href'), base)
    const Chapter = use('fic').Chapter
    const chapter = await new Chapter({link: metadataLink}).getContent(fetch)

    if (chapter.$('.error-503-maintenance').length) {
      const err = new Error(chapter.$('#main').text().trim().split(/\n/).map(l => l.trim()).join('\n'))
      err.link = chapter.fetchWith()
      err.code = 503
      err.site = this.publisherName
      await cache.clearUrl(err.link)
      throw err
    }
    const $meta = chapter.$('dl.meta')
    const ratings = this.tagGroup(chapter.$, 'rating', $meta.find('dd.rating'))
    const warnings = this.tagGroup(chapter.$, 'warning', $meta.find('dd.warnings'))
      .filter(warn => !/No Archive Warnings Apply/.test(warn))
    const category = this.tagGroup(chapter.$, 'category', $meta.find('dd.category'))
    const fandom = this.tagGroup(chapter.$, 'fandom', $meta.find('dd.fandom'))
      .map(r => r.replace(/ - Fandom$/, ''))
    const relationship = this.tagGroup(chapter.$, '', $meta.find('dd.relationship'))
      .filter(r => r !== ':Friendship - Relationship')
      .map(r => r.replace(/^:/, qr`/`.test(r) ? 'ship:' : 'friendship:'))
      .map(r => r.replace(qr.g`\s*(/)\s*`, '/'))
      .map(r => r.replace(qr.g`\s*([&])\s*`, ' & '))
      .map(r => r.replace(/ - Relationship$/, ''))
    const characters = this.tagGroup(chapter.$, 'character', $meta.find('dd.character'))
      .map(t => t.replace(/ - Character$/, ''))
    const freeform = this.tagGroup(chapter.$, 'freeform', $meta.find('dd.freeform'))
      .map(t => t.replace(/ - Freeform$/, ''))
    const language = 'language:' + $meta.find('dd.language').text().trim()
    fic.tags = [].concat(ratings, warnings, category, fandom, relationship, characters, freeform, language)
    const $stats = $meta.find('dl.stats')
    const chapterCounts = $stats.find('dd.chapters').text().trim().split('/')
    const written = chapterCounts[0]
    const planned = chapterCounts[1]
    if (written === planned) {
      if (written === '1') {
        fic.tags.push('status:one-shot')
      } else {
        fic.tags.push('status:complete')
      }
    }
    fic.tags = tagmap(fic.tags)
    fic.created = moment.utc($stats.find('dd.published').text().trim())
    const modified = $stats.find('dd.status').text().trim()
    fic.modified = modified && moment.utc(modified)
    fic.words = Number($stats.find('dd.words').text().trim())
    fic.comments = Number($stats.find('dd.comments').text().trim())
    fic.kudos = Number($stats.find('dd.kudos').text().trim())
    fic.bookmarks = Number($stats.find('dd.bookmarks').text().trim())
    fic.hits = Number($stats.find('dd.hits').text().trim())
    fic.title = chapter.$('h2.title').text().trim()
    fic.description = (chapter.$('.summary').find('.userstuff').html() || '').replace(/<p>/g, '\n<p>').replace(/^\s+|\s+$/g, '')
    const chapterList = $('ol.index').find('li')
    chapterList.each((ii, vv) => {
      const $vv = $(vv)
      const name = $vv.find('a').text().replace(/^\d+[.] /, '')
      const link = this.normalizeChapterLink($vv.find('a').attr('href'), base)
      const created = moment.utc($vv.find('span.datetime').text(), '(YYYY-MM-DD)')
      fic.addChapter({name, link, created})
    })
  }

  async getChapter (fetch, chapterInfo) {
    const [meta, html] = await fetch(chapterInfo.fetchWith())
    const ChapterContent = use('chapter-content')
    const chapter = new ChapterContent(chapterInfo, {html, site: this})
    if (chapter.$('.error-503-maintenance').length) {
      const err = new Error(chapter.$('#main').text().trim().split(/\n/).map(l => l.trim()).join('\n'))
      err.link = chapter.fetchWith()
      err.code = 503
      err.site = this.publisherName
      await cache.clearUrl(err.link)
      throw err
    }
    if (chapter.$('p.caution').length) {
      chapterInfo.fetchFrom = chapterInfo.fetchWith() + '?view_adult=true'
      return this.getChapter(fetch, chapterInfo)
    }
    chapter.base = chapter.$('base').attr('href') || meta.finalUrl
    if (meta.finalUrl !== chapter.link) {
      chapter.fetchFrom = chapter.link
      chapter.link = meta.finalUrl
    }
    const $content = chapter.$('div[role="article"]')
    $content.find('h3.landmark').remove()

    const notes = chapter.$('#notes').find('.userstuff').html()
    const endNotes = chapter.$('div.end').find('.userstuff').html()
    let content = ''
    if (notes && !/\(See the end of the chapter for.*notes.*.\)/.test(notes)) {
      content += `<aside style="border: solid black 1px; padding: 1em">${notes}</aside>`
    }
    content += $content.html()
    if (endNotes) content += `<aside epub:type="endnote" style="border: solid black 1px; padding: 1em">${endNotes}</aside>`
    chapter.content = content
    return chapter
  }
  async getUserInfo (fetch, externalName, link) {
    link = link.replace(qr`/pseuds/.*`, '/profile')
    const cheerio = require('cheerio')
    const authCookies = require(`${__dirname}/../.authors_cookies.json`)
    const [res, auhtml] = await fetch(link)
    const $ = cheerio.load(auhtml)
    const name = $('div.user div.header h2').text().trim() || externalName
    const location = $('dt.location ~ dd').first().text().trim() || undefined
    const image_src = $('img.icon').first().attr('src')
    const image = (image_src && !/xicon_user/.test(image_src)) ? url.resolve(link, image_src) : undefined

    const profile = $('div.bio blockquote.userstuff').html() || undefined
    return {name, link, location, image, profile}
  }
}

module.exports = ArchiveOfOurOwn
<commit_msg>ao3: Very short respones are invalid, refuse to cache and throw<commit_after>'use strict'
const url = require('url')
const Site = use('site')
const cache = use('cache')
const moment = require('moment')
const tagmap = use('tagmap')('ao3')
const qr = require('@perl/qr')
const forEach = use('for-each')

class ArchiveOfOurOwn extends Site {
  static matches (siteUrlStr) {
    const siteUrl = url.parse(siteUrlStr)
    const hostname = siteUrl.hostname
    if (!qr`(^|www[.])archiveofourown.org$`.test(hostname)) return false
    const path = siteUrl.pathname || siteUrl.path || ''
    if (!qr`^(/collections/[^/]+)?(/works/\d+|/users/)`.test(path)) return false
    return true
  }

  constructor (siteUrlStr) {
    super(siteUrlStr)
    this.link = this.link.replace(qr`/works/(\d+).*?$`, '/works/$1')
    this.publisher = 'archiveofourown.org'
    this.publisherName = 'Archive of Our Own'
    this.type = 'ao3'
    this.shortName = 'ao3'
    const siteUrl = url.parse(siteUrlStr)
    const path = siteUrl.pathname || siteUrl.path || ''
    const ficMatch = path.match(qr`^/works/(\d+)`)
    this.workId = ficMatch && ficMatch[1]
  }

  normalizeLink (href, base) {
    if (!href) return
    return super.normalizeLink(href, base)
      .replace(/#.*$/, '')
      .replace(/[/]collections[/][^/]+[/]?/, '/')
  }
  normalizeFicLink (href, base) {
    return super.normalizeFicLink(href, base)
      .replace(/[/]chapters[/]\d+/, '')
  }
  normalizeAuthorLink (href, base) {
    return super.normalizeAuthorLink(href, base)
      .replace(qr`/pseuds/.*`, '/profile')
  }
  chapterIndex () {
    return 'https://archiveofourown.org/works/' + this.workId + '/navigate'
  }
  tagGroup ($, prefix, $dd) {
    const tags = []
    $dd.find('li').each((ii, vv) => {
      tags.push(prefix + ':' + $(vv).text().trim())
    })
    return tags
  }
  async getFicMetadata (fetch, fic) {
    fic.link = this.normalizeFicLink(this.link)
    fic.publisher = this.publisherName
    fic.chapterHeadings = true
    const [meta, html] = await fetch(this.chapterIndex())
    const cheerio = require('cheerio')
    const $ = cheerio.load(html)
    if ($('.error-503-maintenance').length) {
      const err = new Error($('#main').text().trim().split(/\n/).map(l => l.trim()).join('\n'))
      err.link = this.chapterIndex()
      err.code = 503
      err.site = this.publisherName
      await cache.clearUrl(err.link)
      throw err
    }
    if (html.length < 1500) {
      try {
        const j = JSON.parse(html)
        const err = new Error(j.meta.statusText)
        err.link = j.url
        err.code = j.code
        err.site = this.publisherName
        await cache.clearUrl(j.url)
        throw err
      } catch (_) {}
    }
    const base = $('base').attr('href') || this.chapterIndex()
    const $heading = $('h2.heading')
    fic.title = $heading.find('a[rel!="author"]').text()
    if (/\[archived by/.test($heading.text())) {
      $heading.find('a').remove()
      const author = $heading.text().trim().replace(/.*by (.*) \[archived by.*/, '$1').trim()
      fic.author = author
    } else {
      const $author = $heading.find('a[rel="author"]')
      const aus = []
      $author.each((ii, ac) => {
        const $ac = $(ac)
        const authorUrl = (this.normalizeChapterLink($ac.attr('href'), base) || '').replace(qr`/pseuds/.*`, '/profile')
        const authorName = $ac.text()
        fic.authors.push({name: authorName, link: authorUrl})
        if ((!fic.author && !fic.authorUrl) || ((!fic.author || !fic.authorUrl) && (authorUrl && authorName))) {
          fic.author = authorName
          fic.authorUrl = authorUrl
        }
      })
    }
    const $metadata = $('ol.index').find('li').first()
    const metadataLink = this.normalizeChapterLink($metadata.find('a').attr('href'), base)
    const Chapter = use('fic').Chapter
    const chapter = await new Chapter({link: metadataLink}).getContent(fetch)

    if (chapter.$('.error-503-maintenance').length) {
      const err = new Error(chapter.$('#main').text().trim().split(/\n/).map(l => l.trim()).join('\n'))
      err.link = chapter.fetchWith()
      err.code = 503
      err.site = this.publisherName
      await cache.clearUrl(err.link)
      throw err
    }
    const $meta = chapter.$('dl.meta')
    const ratings = this.tagGroup(chapter.$, 'rating', $meta.find('dd.rating'))
    const warnings = this.tagGroup(chapter.$, 'warning', $meta.find('dd.warnings'))
      .filter(warn => !/No Archive Warnings Apply/.test(warn))
    const category = this.tagGroup(chapter.$, 'category', $meta.find('dd.category'))
    const fandom = this.tagGroup(chapter.$, 'fandom', $meta.find('dd.fandom'))
      .map(r => r.replace(/ - Fandom$/, ''))
    const relationship = this.tagGroup(chapter.$, '', $meta.find('dd.relationship'))
      .filter(r => r !== ':Friendship - Relationship')
      .map(r => r.replace(/^:/, qr`/`.test(r) ? 'ship:' : 'friendship:'))
      .map(r => r.replace(qr.g`\s*(/)\s*`, '/'))
      .map(r => r.replace(qr.g`\s*([&])\s*`, ' & '))
      .map(r => r.replace(/ - Relationship$/, ''))
    const characters = this.tagGroup(chapter.$, 'character', $meta.find('dd.character'))
      .map(t => t.replace(/ - Character$/, ''))
    const freeform = this.tagGroup(chapter.$, 'freeform', $meta.find('dd.freeform'))
      .map(t => t.replace(/ - Freeform$/, ''))
    const language = 'language:' + $meta.find('dd.language').text().trim()
    fic.tags = [].concat(ratings, warnings, category, fandom, relationship, characters, freeform, language)
    const $stats = $meta.find('dl.stats')
    const chapterCounts = $stats.find('dd.chapters').text().trim().split('/')
    const written = chapterCounts[0]
    const planned = chapterCounts[1]
    if (written === planned) {
      if (written === '1') {
        fic.tags.push('status:one-shot')
      } else {
        fic.tags.push('status:complete')
      }
    }
    fic.tags = tagmap(fic.tags)
    fic.created = moment.utc($stats.find('dd.published').text().trim())
    const modified = $stats.find('dd.status').text().trim()
    fic.modified = modified && moment.utc(modified)
    fic.words = Number($stats.find('dd.words').text().trim())
    fic.comments = Number($stats.find('dd.comments').text().trim())
    fic.kudos = Number($stats.find('dd.kudos').text().trim())
    fic.bookmarks = Number($stats.find('dd.bookmarks').text().trim())
    fic.hits = Number($stats.find('dd.hits').text().trim())
    fic.title = chapter.$('h2.title').text().trim()
    fic.description = (chapter.$('.summary').find('.userstuff').html() || '').replace(/<p>/g, '\n<p>').replace(/^\s+|\s+$/g, '')
    const chapterList = $('ol.index').find('li')
    chapterList.each((ii, vv) => {
      const $vv = $(vv)
      const name = $vv.find('a').text().replace(/^\d+[.] /, '')
      const link = this.normalizeChapterLink($vv.find('a').attr('href'), base)
      const created = moment.utc($vv.find('span.datetime').text(), '(YYYY-MM-DD)')
      fic.addChapter({name, link, created})
    })
  }

  async getChapter (fetch, chapterInfo) {
    const [meta, html] = await fetch(chapterInfo.fetchWith())
    const ChapterContent = use('chapter-content')
    const chapter = new ChapterContent(chapterInfo, {html, site: this})
    if (chapter.$('.error-503-maintenance').length) {
      const err = new Error(chapter.$('#main').text().trim().split(/\n/).map(l => l.trim()).join('\n'))
      err.link = chapter.fetchWith()
      err.code = 503
      err.site = this.publisherName
      await cache.clearUrl(err.link)
      throw err
    }
    if (chapter.$('p.caution').length) {
      chapterInfo.fetchFrom = chapterInfo.fetchWith() + '?view_adult=true'
      return this.getChapter(fetch, chapterInfo)
    }
    chapter.base = chapter.$('base').attr('href') || meta.finalUrl
    if (meta.finalUrl !== chapter.link) {
      chapter.fetchFrom = chapter.link
      chapter.link = meta.finalUrl
    }
    const $content = chapter.$('div[role="article"]')
    $content.find('h3.landmark').remove()

    const notes = chapter.$('#notes').find('.userstuff').html()
    const endNotes = chapter.$('div.end').find('.userstuff').html()
    let content = ''
    if (notes && !/\(See the end of the chapter for.*notes.*.\)/.test(notes)) {
      content += `<aside style="border: solid black 1px; padding: 1em">${notes}</aside>`
    }
    content += $content.html()
    if (endNotes) content += `<aside epub:type="endnote" style="border: solid black 1px; padding: 1em">${endNotes}</aside>`
    chapter.content = content
    return chapter
  }
  async getUserInfo (fetch, externalName, link) {
    link = link.replace(qr`/pseuds/.*`, '/profile')
    const cheerio = require('cheerio')
    const authCookies = require(`${__dirname}/../.authors_cookies.json`)
    const [res, auhtml] = await fetch(link)
    const $ = cheerio.load(auhtml)
    const name = $('div.user div.header h2').text().trim() || externalName
    const location = $('dt.location ~ dd').first().text().trim() || undefined
    const image_src = $('img.icon').first().attr('src')
    const image = (image_src && !/xicon_user/.test(image_src)) ? url.resolve(link, image_src) : undefined

    const profile = $('div.bio blockquote.userstuff').html() || undefined
    return {name, link, location, image, profile}
  }
}

module.exports = ArchiveOfOurOwn
<|endoftext|>


<commit_before>const global = (1, eval)("this")
global.global = global
global.globalThis = global
global.frames = global
global.self = global

const document = {
  documentElement: {},
  getElementById: () => undefined,
}

const window = {
  document,
  location: {
    href: "",
  },
}

const navigator = {}

global.navigator = navigator
global.window = window
global.document = document
<commit_msg>fix: add Intl polyfill for SSR<commit_after>const global = (1, eval)("this")
global.global = global
global.globalThis = global
global.frames = global
global.self = global

const document = {
  documentElement: {},
  getElementById: () => undefined,
}

const window = {
  document,
  location: {
    href: "",
  },
}

const navigator = {}
global.navigator = navigator
global.window = window
global.document = document

// Intl polyfill is required until v8go supports Intl
class NoopFormat {
  format(arg0) {
    return arg0 ? arg0.toString() : ""
  }
}

global.Intl = {
  NumberFormat: NoopFormat,
  DateTimeFormat: NoopFormat,
}
<|endoftext|>


<commit_before>'use strict';

/* global runtime */
var TCPServerSocket = runtime.net.TCPServerSocket;
var TCPSocket = runtime.net.TCPSocket;
var enc = new TextEncoder();

exports.stringToBuffer = function(str) {
  return enc.encode(str);
};

exports.stringToSocketData = function(str) {
  return enc.encode(str);
};

exports.createServerHandle = function(httpServer) {
  var socket = new TCPServerSocket();
  socket.onconnect = function(connSocket) {
    connSocket.ondata = function(u8) {
      httpServer._dataHandler(connSocket, u8);
    };

    connSocket.onend = function() {
      httpServer._endHandler(connSocket);
    };

    httpServer._connectionHandler(connSocket);
  };

  return socket;
};

exports.listen = function(handle, port) {
  handle.listen(port);
};

exports.unlisten = function(handle) {
  handle.close();
};

exports.sendAndClose = function(socket, u8) {
  socket.send(u8);
  socket.close();
};

exports.close = function(socket) {
  socket.close();
};

exports.send = function(socket, u8) {
  socket.send(u8);
};

exports.createClientHandle = function(httpClient) {
  var socket = new TCPSocket();

  socket.onopen = function() {
    httpClient._openHandler();
  }

  socket.ondata = function(u8) {
    httpClient._dataHandler(u8);
  }

  socket.onend = function() {
    socket.close();
    httpClient._endHandler();
  }

  socket.onclose = function() {
    httpClient._closeHandler();
  }

  return socket;
}

exports.closeClientHandle = function(socket) {
  socket.close();
}

exports.connect = function(handle, ip, port) {
  handle.open(ip, port);
}
<commit_msg>Fix server connections memory leak on runtime backend<commit_after>'use strict';

/* global runtime */
var TCPServerSocket = runtime.net.TCPServerSocket;
var TCPSocket = runtime.net.TCPSocket;
var enc = new TextEncoder();

exports.stringToBuffer = function(str) {
  return enc.encode(str);
};

exports.stringToSocketData = function(str) {
  return enc.encode(str);
};

exports.createServerHandle = function(httpServer) {
  var socket = new TCPServerSocket();
  socket.onconnect = function(connSocket) {
    connSocket.ondata = function(u8) {
      httpServer._dataHandler(connSocket, u8);
    };

    connSocket.onend = function() {
      httpServer._endHandler(connSocket);
    };

    connSocket.onclose = function() {
      httpServer._closeHandler(connSocket);
    };

    httpServer._connectionHandler(connSocket);
  };

  return socket;
};

exports.listen = function(handle, port) {
  handle.listen(port);
};

exports.unlisten = function(handle) {
  handle.close();
};

exports.sendAndClose = function(socket, u8) {
  socket.send(u8);
  socket.close();
};

exports.close = function(socket) {
  socket.close();
};

exports.send = function(socket, u8) {
  socket.send(u8);
};

exports.createClientHandle = function(httpClient) {
  var socket = new TCPSocket();

  socket.onopen = function() {
    httpClient._openHandler();
  }

  socket.ondata = function(u8) {
    httpClient._dataHandler(u8);
  }

  socket.onend = function() {
    socket.close();
    httpClient._endHandler();
  }

  socket.onclose = function() {
    httpClient._closeHandler();
  }

  return socket;
}

exports.closeClientHandle = function(socket) {
  socket.close();
}

exports.connect = function(handle, ip, port) {
  handle.open(ip, port);
}
<|endoftext|>


<commit_before>module.exports = {
  Colors: {
    // GRAYSCALE
    ASH: '#ACB0B3',
    CHARCOAL: '#56595A',
    FOG: '#E3E6E7',
    PORCELAIN: '#F7F8F8',
    WHITE: '#FFFFFF',

    // ACCENTS
    PRIMARY: '#359BCF',
    BANANA: '#FBB600',
    ORANGE: '#EF7625',
    LIME: '#2EBE51',
    STRAWBERRY: '#E22727',

    // CHART COLORS
    BASE_ARC: '#F5F5F5',
    YELLOW: '#f6a01e',
    GREEN: '#00a89c',
    BLUE: '#359BCF',
    RED: '#EE4235',

    // CATEGORY COLORS
    AUTO_TRANSPORT: '#4B9DBC',
    BILLS_UTILITIES: '#EF9B2C',
    BUSINESS: '#B3DE8C',
    EDUCATION: '#F8AB3A',
    ENTERTAINMENT: '#AB5B89',
    FEES: '#FF9696',
    FINANCIAL: '#6BCDDB',
    FOOD_DINING: '#58AC7B',
    GIFTS_CHARITY: '#347AA5',
    HEALTH_FITNESS: '#5C446E',
    HOME: '#FFD84D',
    INCOME: '#133F49',
    INVESTMENTS: '#FF7070',
    KIDS: '#82D196',
    PETS: '#85507B',
    PERSONAL_CARE: '#338B7A',
    SHOPPING: '#CF5F84',
    TAXES: '#32588D',
    TRAVEL: '#e37434',
    UNCATEGORIZED: '#FA5555',

    // SCRIM
    SCRIM: 'rgba(247,248,248,0.9)'
  },

  FontSizes: {
    JUMBO: 30,
    XXLARGE: 21,
    XLARGE: 17,
    LARGE: 15,
    MEDIUM: 13,
    SMALL: 11,
    TINY: 10
  },

  Fonts: {
    THIN: 'ProximaNovaThin, Helvetica, Arial, sans-serif',
    LIGHT: 'ProximaNovaLight, Helvetica, Arial, sans-serif',
    REGULAR: 'ProximaNovaRegular, Helvetica, Arial, sans-serif',
    ITALIC: 'ProximaNovaRegularItalic, Helvetica, Arial, sans-serif',
    SEMIBOLD: 'ProximaNovaSemibold, Helvetica, Arial, sans-serif'
  },

  //Box Shadows
  ShadowLow: '0 1px 2px rgba(0,0,0,0.1)',
  ShadowMed: '0 2px 6px rgba(0,0,0,0.1)',
  ShadowHigh: '0 10px 30px 5px rgba(0,0,0,0.1)',

  adjustColor (col, amt) {
    let color = col;
    let usePound = false;

    if (color[0] === '#') {
      color = color.slice(1);
      usePound = true;
    }

    const num = parseInt(color, 16);

    let r = (num >> 16) + amt;

    if (r > 255) {
      r = 255;
    } else if (r < 0) {
      r = 0;
    }

    let b = ((num >> 8) & 0x00FF) + amt;

    if (b > 255) {
      b = 255;
    } else if (b < 0) {
      b = 0;
    }

    let g = (num & 0x0000FF) + amt;

    if (g > 255) {
      g = 255;
    } else if (g < 0) {
      g = 0;
    }

    return (usePound ? '#' : '') + (g | (b << 8) | (r << 16)).toString(16);
  },

  adjustHexOpacity (color, opacity) {
    const r = parseInt(color.slice(1, 3), 16);
    const g = parseInt(color.slice(3, 5), 16);
    const b = parseInt(color.slice(5, 7), 16);

    return 'rgba(' + r + ', ' + g + ', ' + b + ', ' + opacity + ')';
  }
};
<commit_msg>add spacing constant<commit_after>module.exports = {
  Colors: {
    // GRAYSCALE
    ASH: '#ACB0B3',
    CHARCOAL: '#56595A',
    FOG: '#E3E6E7',
    PORCELAIN: '#F7F8F8',
    WHITE: '#FFFFFF',

    // ACCENTS
    PRIMARY: '#359BCF',
    BANANA: '#FBB600',
    ORANGE: '#EF7625',
    LIME: '#2EBE51',
    STRAWBERRY: '#E22727',

    // CHART COLORS
    BASE_ARC: '#F5F5F5',
    YELLOW: '#f6a01e',
    GREEN: '#00a89c',
    BLUE: '#359BCF',
    RED: '#EE4235',

    // CATEGORY COLORS
    AUTO_TRANSPORT: '#4B9DBC',
    BILLS_UTILITIES: '#EF9B2C',
    BUSINESS: '#B3DE8C',
    EDUCATION: '#F8AB3A',
    ENTERTAINMENT: '#AB5B89',
    FEES: '#FF9696',
    FINANCIAL: '#6BCDDB',
    FOOD_DINING: '#58AC7B',
    GIFTS_CHARITY: '#347AA5',
    HEALTH_FITNESS: '#5C446E',
    HOME: '#FFD84D',
    INCOME: '#133F49',
    INVESTMENTS: '#FF7070',
    KIDS: '#82D196',
    PETS: '#85507B',
    PERSONAL_CARE: '#338B7A',
    SHOPPING: '#CF5F84',
    TAXES: '#32588D',
    TRAVEL: '#e37434',
    UNCATEGORIZED: '#FA5555',

    // SCRIM
    SCRIM: 'rgba(247,248,248,0.9)'
  },

  FontSizes: {
    JUMBO: 30,
    XXLARGE: 21,
    XLARGE: 17,
    LARGE: 15,
    MEDIUM: 13,
    SMALL: 11,
    TINY: 10
  },

  Fonts: {
    THIN: 'ProximaNovaThin, Helvetica, Arial, sans-serif',
    LIGHT: 'ProximaNovaLight, Helvetica, Arial, sans-serif',
    REGULAR: 'ProximaNovaRegular, Helvetica, Arial, sans-serif',
    ITALIC: 'ProximaNovaRegularItalic, Helvetica, Arial, sans-serif',
    SEMIBOLD: 'ProximaNovaSemibold, Helvetica, Arial, sans-serif'
  },

  //Box Shadows
  ShadowLow: '0 1px 2px rgba(0,0,0,0.1)',
  ShadowMed: '0 2px 6px rgba(0,0,0,0.1)',
  ShadowHigh: '0 10px 30px 5px rgba(0,0,0,0.1)',

  Spacing: {
    XLARGE: 30,
    LARGE: 20,
    MEDIUM: 15,
    SMALL: 10,
    XSMALL: 5
  },

  adjustColor (col, amt) {
    let color = col;
    let usePound = false;

    if (color[0] === '#') {
      color = color.slice(1);
      usePound = true;
    }

    const num = parseInt(color, 16);

    let r = (num >> 16) + amt;

    if (r > 255) {
      r = 255;
    } else if (r < 0) {
      r = 0;
    }

    let b = ((num >> 8) & 0x00FF) + amt;

    if (b > 255) {
      b = 255;
    } else if (b < 0) {
      b = 0;
    }

    let g = (num & 0x0000FF) + amt;

    if (g > 255) {
      g = 255;
    } else if (g < 0) {
      g = 0;
    }

    return (usePound ? '#' : '') + (g | (b << 8) | (r << 16)).toString(16);
  },

  adjustHexOpacity (color, opacity) {
    const r = parseInt(color.slice(1, 3), 16);
    const g = parseInt(color.slice(3, 5), 16);
    const b = parseInt(color.slice(5, 7), 16);

    return 'rgba(' + r + ', ' + g + ', ' + b + ', ' + opacity + ')';
  }
};
<|endoftext|>


<commit_before>var config = {
  host : "chat.freenode.net",
  nick : "repltbot",
  channel : "#test5566",
  pingTimeout : 600 * 1000,
  identifier : "*",
  floodProtection : 1000,
  saveFolder : "save",
  saveName : "cm.json",
  init : function (commandManager, helper) {
    var path = require("path");

    var chatLogPath = 'chatlog.json';
    var regexConfigPath = 'regex.json';
    var titleParserConfigPath = 'titleparse.json';
    var mailboxPath = 'mailbox.json';

    var CommandSay = require('./lib/commands/commandsay.js')
    var CommandRainbow = require('./lib/commands/commandrainbow.js')
    var CommandRainbow2 = require('./lib/commands/commandrainbow2.js')
    var CommandLog = require('./lib/commands/commandlog.js')
    var CommandUptime = require('./lib/commands/commanduptime.js')
    var CommandPass = require('./lib/commands/commandpass.js')
    var CommandLookup = require('./lib/commands/commandnslookup.js')
    var CommandNotifyAll = require('./lib/commands/commandnotifyall.js')
    var CommandRand = require('./lib/commands/commandrand.js')
    var CommandReply = require('./lib/commands/commandreply.js')
    var CommandFortune = require('./lib/commands/fortune')
    var CommandRegex = require('./lib/commands/commandregex.js')
    var CommandPython = require('./lib/commands/commandpy.js')
    var CommandMorse = require('./lib/commands/commandmorse.js')
    var CommandMe = require('./lib/commands/commandme.js')
    var CommandMail = require('./lib/commands/commandmail.js')

    commandManager.register ("say", new CommandSay, []);
    commandManager.register ("rainbow", new CommandRainbow, []);
    commandManager.register ("rainbow2", new CommandRainbow2, []);
    commandManager.register ("log", new CommandLog(helper.createStorage(chatLogPath)), []);
    commandManager.register ("uptime", new CommandUptime(), []);
    commandManager.register ("pass", new CommandPass(), []);
    commandManager.register ("notifyall", new CommandNotifyAll(), ['na']);
    commandManager.register ("lookup", new CommandLookup(), []);
    commandManager.register ("rand", new CommandRand(), []);
    commandManager.register ("reply", new CommandReply(), []);
    commandManager.register ("fortune", new CommandFortune(), []);
    commandManager.register ("regex", new CommandRegex(helper.createStorage(regexConfigPath)), []);
    commandManager.register ("python", new CommandPython(), ['py']);
    commandManager.register ("morse", new CommandMorse(), []);
    commandManager.register ("me", new CommandMe(), []);
    commandManager.register ("mail", new CommandMail(helper.createStorage(mailboxPath)), []);

    helper.safeLoad(function(){
      var CommandTitle = require('./lib/commands/titleparser')
      commandManager.register ("title", new CommandTitle(helper.createStorage(titleParserConfigPath)), []);
    }, "title");

    helper.safeLoad(function(){
      var CommandTrace = require('./lib/commands/commandtrace.js')
      commandManager.register ("trace", new CommandTrace(), ['t']);
    }, "trace");

    helper.safeLoad(function(){
      var CommandPing = require('./lib/commands/commandping.js')
      commandManager.register ("ping", new CommandPing(), ['p']);
    }, "ping");

    helper.safeLoad(function(){
      var CommandFindFastestServer = require('./lib/commands/commandfindfastestserver.js')
      commandManager.register ("findfastestserver", new CommandFindFastestServer(), ['ffs']);
    }, "findFastestServer");

  }
}
module.exports = config<commit_msg>add mcstatus to config<commit_after>var config = {
  host : "chat.freenode.net",
  nick : "repltbot",
  channel : "#test5566",
  pingTimeout : 600 * 1000,
  identifier : "*",
  floodProtection : 1000,
  saveFolder : "save",
  saveName : "cm.json",
  init : function (commandManager, helper) {
    var path = require("path");

    var chatLogPath = 'chatlog.json';
    var regexConfigPath = 'regex.json';
    var titleParserConfigPath = 'titleparse.json';
    var mailboxPath = 'mailbox.json';

    var CommandSay = require('./lib/commands/commandsay.js')
    var CommandRainbow = require('./lib/commands/commandrainbow.js')
    var CommandRainbow2 = require('./lib/commands/commandrainbow2.js')
    var CommandLog = require('./lib/commands/commandlog.js')
    var CommandUptime = require('./lib/commands/commanduptime.js')
    var CommandPass = require('./lib/commands/commandpass.js')
    var CommandLookup = require('./lib/commands/commandnslookup.js')
    var CommandNotifyAll = require('./lib/commands/commandnotifyall.js')
    var CommandRand = require('./lib/commands/commandrand.js')
    var CommandReply = require('./lib/commands/commandreply.js')
    var CommandFortune = require('./lib/commands/fortune')
    var CommandRegex = require('./lib/commands/commandregex.js')
    var CommandPython = require('./lib/commands/commandpy.js')
    var CommandMorse = require('./lib/commands/commandmorse.js')
    var CommandMe = require('./lib/commands/commandme.js')
    var CommandMail = require('./lib/commands/commandmail.js')
    var CommandMcStatus = require('./lib/commands/commandmcstatus.js');

    commandManager.register ("say", new CommandSay, []);
    commandManager.register ("rainbow", new CommandRainbow, []);
    commandManager.register ("rainbow2", new CommandRainbow2, []);
    commandManager.register ("log", new CommandLog(helper.createStorage(chatLogPath)), []);
    commandManager.register ("uptime", new CommandUptime(), []);
    commandManager.register ("pass", new CommandPass(), []);
    commandManager.register ("notifyall", new CommandNotifyAll(), ['na']);
    commandManager.register ("lookup", new CommandLookup(), []);
    commandManager.register ("rand", new CommandRand(), []);
    commandManager.register ("reply", new CommandReply(), []);
    commandManager.register ("fortune", new CommandFortune(), []);
    commandManager.register ("regex", new CommandRegex(helper.createStorage(regexConfigPath)), []);
    commandManager.register ("python", new CommandPython(), ['py']);
    commandManager.register ("morse", new CommandMorse(), []);
    commandManager.register ("me", new CommandMe(), []);
    commandManager.register ("mail", new CommandMail(helper.createStorage(mailboxPath)), []);
    commandManager.register ("mcstatus", new CommandMcStatus(), ['mc']);

    helper.safeLoad(function(){
      var CommandTitle = require('./lib/commands/titleparser')
      commandManager.register ("title", new CommandTitle(helper.createStorage(titleParserConfigPath)), []);
    }, "title");

    helper.safeLoad(function(){
      var CommandTrace = require('./lib/commands/commandtrace.js')
      commandManager.register ("trace", new CommandTrace(), ['t']);
    }, "trace");

    helper.safeLoad(function(){
      var CommandPing = require('./lib/commands/commandping.js')
      commandManager.register ("ping", new CommandPing(), ['p']);
    }, "ping");

    helper.safeLoad(function(){
      var CommandFindFastestServer = require('./lib/commands/commandfindfastestserver.js')
      commandManager.register ("findfastestserver", new CommandFindFastestServer(), ['ffs']);
    }, "findFastestServer");

  }
}
module.exports = config<|endoftext|>


<commit_before>const fs = require('fs');
const path = require('path');

const webshot = require('webshot');
const request = require('request');
const styleNames = require('./utility/styleNames.js');
const prettier = require('prettier');
const untildify = require('untildify');
const gm = require('gm').subClass({
    imageMagick: true
});

const VERSION = '9.10.0';

const opts = {
    resolution: 1,
    theme: 'hybrid',
    font: 'Source Code Pro',
    fontSize: 20,
    background: '#fff',
    output: null,
    prettify: true, // use prettify to format `js`
    style: null, // override code styles injected by theme
    webshotCustomConfig: {
        // Using webshots default options
        shotSize: {
            width: 'window',
            height: 'window'
        },
        windowSize: {
            width: 1024,
            height: 768
        },
        shotOffset: {
            top: 0,
            right: 0,
            bottom: 0,
            left: 0
        }
    }
};

/**
 * Function to check whether file is JS or JSX.
 * This is used to define the parser to prettify code.
 * Currently only JS is supported. More formats are in development.
 * @param fileName: Name of the file.
 * @returns string: '.js' or '.jsx'
 */

function checkFileExtension(fileName) {
    if (fileName.endsWith('.js')) {
        return '.js';
    }
    return '';
}

function insertMissingOptions(options) {
    return { ...opts, ...options };
}
/**
 * Prettify code based on the extension of the file.
 */

const prettify = (source, ext) => {
    switch (ext) {
        case '.js': {
            return prettier.format(source, {
                printWidth: 80,
                tabWidth: 4,
                singleQuote: true,
                trailingComma: 'none',
                bracketSpacing: true,
                parser: 'babylon'
            });
        }

        default: {
            return source;
        }
    }
};

function checkIfThemeExists(themeName) {
    if (styleNames.indexOf(themeName) !== -1) return true;
    return false;
}

function setBackground(cssURL, options) {
    request(cssURL, function(error, response, html) {
        if (!error && response.statusCode == 200) {
            let location,
                firstOccurence,
                backgroundOccurence,
                semiColonOccurence,
                colonOccurence;
            let sliced;

            location = html.toString().indexOf('.hljs{');
            sliced = html.slice(location);
            firstOccurence = sliced.indexOf('}') + 1;
            sliced = sliced.slice(0, firstOccurence);
            backgroundOccurence = sliced.indexOf('background');
            sliced = sliced.slice(backgroundOccurence);
            colonOccurence = sliced.indexOf(':') + 1;
            semiColonOccurence = sliced.indexOf(';');
            sliced = sliced.slice(colonOccurence, semiColonOccurence);
            options['background'] = sliced;
        }
    });
}

function generateHTML(sourceCode, options) {
    let themeName = options.theme.toLowerCase();

    let theme = checkIfThemeExists(themeName)
        ? `${themeName}.min.css`
        : 'hybrid.min.css';

    let cssURL = `https://cdnjs.cloudflare.com/ajax/libs/highlight.js/${VERSION}/styles/${theme}`;

    setBackground(cssURL, options);

    let scriptURL = `https://cdnjs.cloudflare.com/ajax/libs/highlight.js/${VERSION}/highlight.min.js`;

    let style = options.style ||
        `code{font-family: '${options.font}'; font-size:${options.fontSize}px; padding:20px}`;

    return `

        <link href="https://fonts.googleapis.com/css?family=Source+Code+Pro" rel="stylesheet">
        <link rel="stylesheet" href="${cssURL}" />

        ${sourceCode}

    </body}

    `;
}

/**Main function.
 * Set default arguments,
 * if options are not passed
 */

function codeSnipper(fileName, options = opts) {
    options = {
        ...opts,
        ext: checkFileExtension(fileName),
        ...options
    };

    // Initialize webshot's configuration, setting resolution(zoomFactor) if passed.
    let webshotConfig = {
        siteType: 'html',
        zoomFactor: options.resolution || 2.5,
        ...options.webshotCustomConfig
    };

    const imagePath = path.join(process.cwd(), fileName);

    const imageName = options.output
        ? untildify(options.output)
        : imagePath + '.png';

    //Read File and prettify code. Synchronous version is used for simplicity
    let sourceCode = '';
    fs.readFile(imagePath, (err, data) => {
        if (err) {
            throw new Error(err);
        }

        sourceCode = options.prettify
            ? prettify(data.toString(), options.ext)
            : data.toString();

        //Generate HTML
        const htmlString = generateHTML(sourceCode, options);

        webshot(htmlString, imageName, webshotConfig, err => {
            if (!err) {
                console.log('Image successfully saved as %s', imageName);
                gm(imageName)
                    .trim()
                    .trim()
                    .borderColor(options.background)
                    .border(20, 20)
                    .write(imageName, err => {
                        if (err) {
                            throw new Error(err);
                        }
                    });
            } else {
                throw new Error(err);
            }
            return;
        });
    });
    return 0;
}

module.exports = codeSnipper;
<commit_msg>Removing extraneous code<commit_after>const fs = require('fs');
const path = require('path');

const webshot = require('webshot');
const request = require('request');
const styleNames = require('./utility/styleNames.js');
const prettier = require('prettier');
const untildify = require('untildify');
const gm = require('gm').subClass({
    imageMagick: true
});

const VERSION = '9.10.0';

const opts = {
    resolution: 1,
    theme: 'hybrid',
    font: 'Source Code Pro',
    fontSize: 20,
    background: '#fff',
    output: null,
    prettify: true, // use prettify to format `js`
    style: null, // override code styles injected by theme
    webshotCustomConfig: {
        // Using webshots default options
        shotSize: {
            width: 'window',
            height: 'window'
        },
        windowSize: {
            width: 1024,
            height: 768
        },
        shotOffset: {
            top: 0,
            right: 0,
            bottom: 0,
            left: 0
        }
    }
};

/**
 * Function to check whether file is JS or JSX.
 * This is used to define the parser to prettify code.
 * Currently only JS is supported. More formats are in development.
 * @param fileName: Name of the file.
 * @returns string: '.js' or '.jsx'
 */
function checkFileExtension(fileName) {
    if (fileName.endsWith('.js')) {
        return '.js';
    }
    return '';
}

/**
 * Prettify code based on the extension of the file.
 */
const prettify = (source, ext) => {
    switch (ext) {
        case '.js': {
            return prettier.format(source, {
                printWidth: 80,
                tabWidth: 4,
                singleQuote: true,
                trailingComma: 'none',
                bracketSpacing: true,
                parser: 'babylon'
            });
        }

        default: {
            return source;
        }
    }
};

function checkIfThemeExists(themeName) {
    if (styleNames.indexOf(themeName) !== -1) return true;
    return false;
}

function setBackground(cssURL, options) {
    request(cssURL, function(error, response, html) {
        if (!error && response.statusCode == 200) {
            let location,
                firstOccurence,
                backgroundOccurence,
                semiColonOccurence,
                colonOccurence;
            let sliced;

            location = html.toString().indexOf('.hljs{');
            sliced = html.slice(location);
            firstOccurence = sliced.indexOf('}') + 1;
            sliced = sliced.slice(0, firstOccurence);
            backgroundOccurence = sliced.indexOf('background');
            sliced = sliced.slice(backgroundOccurence);
            colonOccurence = sliced.indexOf(':') + 1;
            semiColonOccurence = sliced.indexOf(';');
            sliced = sliced.slice(colonOccurence, semiColonOccurence);
            options['background'] = sliced;
        }
    });
}

function generateHTML(sourceCode, options) {
    let themeName = options.theme.toLowerCase();

    let theme = checkIfThemeExists(themeName)
        ? `${themeName}.min.css`
        : 'hybrid.min.css';

    let cssURL = `https://cdnjs.cloudflare.com/ajax/libs/highlight.js/${VERSION}/styles/${theme}`;

    setBackground(cssURL, options);

    let scriptURL = `https://cdnjs.cloudflare.com/ajax/libs/highlight.js/${VERSION}/highlight.min.js`;

    let style = options.style ||
        `code{font-family: '${options.font}'; font-size:${options.fontSize}px; padding:20px}`;

    return `

        <link href="https://fonts.googleapis.com/css?family=Source+Code+Pro" rel="stylesheet">
        <link rel="stylesheet" href="${cssURL}" />

        ${sourceCode}

    </body}

    `;
}

/**Main function.
 * Set default arguments,
 * if options are not passed
 */

function codeSnipper(fileName, options = opts) {
    options = {
        ...opts,
        ext: checkFileExtension(fileName),
        ...options
    };

    // Initialize webshot's configuration, setting resolution(zoomFactor) if passed.
    let webshotConfig = {
        siteType: 'html',
        zoomFactor: options.resolution || 2.5,
        ...options.webshotCustomConfig
    };

    const imagePath = path.join(process.cwd(), fileName);

    const imageName = options.output
        ? untildify(options.output)
        : imagePath + '.png';

    //Read File and prettify code. Synchronous version is used for simplicity
    let sourceCode = '';
    fs.readFile(imagePath, (err, data) => {
        if (err) {
            throw new Error(err);
        }

        sourceCode = options.prettify
            ? prettify(data.toString(), options.ext)
            : data.toString();

        //Generate HTML
        const htmlString = generateHTML(sourceCode, options);

        webshot(htmlString, imageName, webshotConfig, err => {
            if (!err) {
                console.log('Image successfully saved as %s', imageName);
                gm(imageName)
                    .trim()
                    .trim()
                    .borderColor(options.background)
                    .border(20, 20)
                    .write(imageName, err => {
                        if (err) {
                            throw new Error(err);
                        }
                    });
            } else {
                throw new Error(err);
            }
            return;
        });
    });
    return 0;
}

module.exports = codeSnipper;
<|endoftext|>


<commit_before>/**
 *  plugin.js is part of PetitVerdot
 *  Copyright (c) by Alexander Henka, 19.11.14.
 *  Project URL: https://github.com/OnkelHenky/PetitVerdot
 *
 * +--------------------------------------------------------------------------+
 * | LICENSE INFORMATION                                                      |
 * | ===================                                                      |
 * |                                                                          |
 * | 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.                                           |
 * |                                                                          |
 * | For more information see:                                                |
 * | https://github.com/OnkelHenky/PinotGris/blob/master/README.md            |
 * |                                                                          |
 * +--------------------------------------------------------------------------+
 */

/*
 * +---------------------------------------------------------------------------+
 * |                              PetitVerdot                                  |
 * |                           ================                                |
 * |        Plugin for SeBuilder to export  Merlot's blueprint format          |
 * +---------------------------------------------------------------------------+
 *
 * +---------------------------------------------------------------------------+
 * | From Wikipedia                                                            |
 * | ==============                                                            |
 * |                                                                           |
 * | Petit Verdot is a variety of red wine grape, principally used in classic  |
 * | Bordeaux blends.It ripens much later than the other varieties in Bordeaux,|
 * | often too late, so it fell out of favour in its home region.              |
 * | When it does ripen, it is added in small amounts to add tannin, colour    |
 * | and flavour to the blend. It has attracted attention among winemakers     |
 * | in the New World, where it ripens more reliably and has been made into    |
 * | single varietal wine. It is also useful in 'stiffening' the mid palate    |
 * | of Cabernet Sauvignon blends.                                             |
 * |                                                                           |
 * | When young its aromas have been likened to banana and pencil shavings.    |
 * | Strong tones of violet and leather develop as it matures.                 |
 * |                                                                           |
 * | Source: http://en.wikipedia.org/wiki/Petit_Verdot                         |
 * +---------------------------------------------------------------------------+
 */

var PetitVerdot = PetitVerdot || {};

/**
 * @description
 * This function is getting called when the builder is shutting down.
 * Therefore, it allows to implement cleanup stuff here.
 */
PetitVerdot.shutdown = function(){

};

builder.registerPostLoadHook(function() {
    builder.gui.menu.addItem("suite", "PetitVerdot", 'ssdsdsd', function(){});
});

<commit_msg>Minor stuff<commit_after>/**
 *  plugin.js is part of PetitVerdot
 *  Copyright (c) by Alexander Henka, 19.11.14.
 *  Project URL: https://github.com/OnkelHenky/PetitVerdot
 *
 * +--------------------------------------------------------------------------+
 * | LICENSE INFORMATION                                                      |
 * | ===================                                                      |
 * |                                                                          |
 * | 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.                                           |
 * |                                                                          |
 * | For more information see:                                                |
 * | https://github.com/OnkelHenky/PetitVerdot/blob/master/README.md          |
 * |                                                                          |
 * +--------------------------------------------------------------------------+
 */

/*
 * +---------------------------------------------------------------------------+
 * |                              PetitVerdot                                  |
 * |                           ================                                |
 * |        Plugin for SeBuilder to export  Merlot's blueprint format          |
 * +---------------------------------------------------------------------------+
 *
 * +---------------------------------------------------------------------------+
 * | From Wikipedia                                                            |
 * | ==============                                                            |
 * |                                                                           |
 * | Petit Verdot is a variety of red wine grape, principally used in classic  |
 * | Bordeaux blends.It ripens much later than the other varieties in Bordeaux,|
 * | often too late, so it fell out of favour in its home region.              |
 * | When it does ripen, it is added in small amounts to add tannin, colour    |
 * | and flavour to the blend. It has attracted attention among winemakers     |
 * | in the New World, where it ripens more reliably and has been made into    |
 * | single varietal wine. It is also useful in 'stiffening' the mid palate    |
 * | of Cabernet Sauvignon blends.                                             |
 * |                                                                           |
 * | When young its aromas have been likened to banana and pencil shavings.    |
 * | Strong tones of violet and leather develop as it matures.                 |
 * |                                                                           |
 * | Source: http://en.wikipedia.org/wiki/Petit_Verdot                         |
 * +---------------------------------------------------------------------------+
 */

var PetitVerdot = PetitVerdot || {};

/**
 * @description
 * This function is getting called when the builder is shutting down.
 * Therefore, it allows to implement cleanup stuff here.
 */
PetitVerdot.shutdown = function(){

};

builder.registerPostLoadHook(function() {
    builder.gui.menu.addItem("suite", "PetitVerdot", 'ssdsdsd', function(){});
});

<|endoftext|>


<commit_before>/*
 * Authors: Isaac Zylstra and Victor Norman @ Calvin College, Grand Rapids, MI.
 * Contact: vtn2@calvin.edu
 */

(function(ext) {

    //The variable that will hold the json to be read from
    var jsonObject = null;

    //The scale applied to the kinect data to make it map to the canvas better.
    var xScale = 240;
    var yScale = 180;
    var zScale = 200;

    //The status of the kinect
    var status = 0;

    //alert letting the user know what needs to be done before loading the extension.
    alert("BEFORE CLICKING OK: Make sure the kinect is connected and your JSON websocket server has started");

    console.log("connecting to server ..");

    // create a new websocket and connect
    window.ws = new WebSocket('ws://localhost:8181/');

    // when data is comming from the server, this method is called
    ws.onmessage = function (evt) {
        jsonObject = JSON.parse(evt.data);
            if(jsonObject.bodies == '')
            {
                status = 1;
            } else
            {
                status = 2;
            }
    };

    // when the connection is established, this method is called
    ws.onopen = function () {
        console.log('.. connection open');
    };

    // when the connection is closed, this method is called
    ws.onclose = function () {
        console.log('.. connection closed');
        status = 0;
    };

    // Cleanup function when the extension is unloaded
    ext._shutdown = function()
    {
    window.ws.close();
    };

    // Reports status of kinect
    ext._getStatus = function() {
        if(status == 0)
        {
        return {status: 0, msg: 'Kinect is not connected to Scratch'};
        }
        if(status == 1)
        {
            return {status: 1, msg: 'Kinect is connected, but is not detecting any bodies'};
        }
        if(status == 2)
        {
            return {status: 2, msg: 'Kinect is sending body data'};
        }
    };

        // Block and block menu descriptions
    var descriptor = {
        blocks: [
            ['r', '%m.b %m.j %m.c', 'joints', 'Body 1', 'Head', 'x'],
            ['r', 'Body ID %n %m.j %m.c', 'jointsID', '0', 'Head', 'x'],
            ['b', '%m.b %m.d Handstate is %m.h', 'handstate', 'Body 1', 'Left', 'Closed'],
            ['r', '%m.b %m.d Handstate', 'handdebug', 'Body 1', 'Left'], //Comment out of final version.
            ['r', '%m.b ID', 'bodyid', 'Body 1'],
            ['b', '%m.b tracked', 'tracked', 'Body 1'],
            ['b', 'connected', 'connected'],
            ['', 'Basic body check', 'basic_body_check'], //Comment out of final version.
            ['', 'Test Block', 'test'], //Comment out of final
            ['', 'Start new local connection', 'local'],
            ['', 'connect to %s', 'ipconnect', '0.0.0.0'],
            ['', 'Close connection', 'closeconn'], //Comment out of final version.
            ['', 'console.log %n', 'write'], //Comment out of final version.
            ['', 'bad only %n', 'writeB'] //Comment out of final version.
        ],

        menus: {
	    j: ['Left Ankle', 'Right Ankle', 'Left Elbow', 'Right Elbow', 'Left Foot', 'Right Foot', 'Left Hand', 'Right Hand', 'Left Hand Tip', 'Right Hand Tip', 'Head', 'Left Hip', 'Right Hip', 'Left Knee', 'Right Knee', 'Neck', 'Left Shoulder', 'Right Shoulder', 'Spine Base', 'Spine Middle', 'Spine Shoulder', 'Left Thumb', 'Right Thumb', 'Left Wrist', 'Right Wrist'],
        b: ['Body 1', 'Body 2', 'Body 3', 'Body 4', 'Body 5', 'Body 6'],
        h: ['Unknown', 'Not Tracked', 'Open', 'Closed', 'Lasso'],
        c: ['x', 'y', 'z'],
        d: ['Left', 'Right']
    }
    };

    //restarts the local connection
    ext.local = function() {
        window.ws.close();
        console.log("connecting to local server ..");
        window.ws = new WebSocket('ws://localhost:8181/');

        // when data is comming from the server, this method is called
        ws.onmessage = function (evt) {
            jsonObject = JSON.parse(evt.data);
            if(jsonObject.bodies == '')
            {
                status = 1;
            } else
            {
                status = 2;
            }
    };

    // when the connection is established, this method is called
    ws.onopen = function () {
        console.log('.. connection open');
    };

    // when the connection is closed, this method is called
    ws.onclose = function () {
        console.log('.. connection closed');
        status = 0;
    };
    };

    //s: a string containing the ip the user wishes to connect to.
    //Creates a remote connection to s.
    ext.ipconnect = function(string) {
        window.ws.close();
        console.log("connecting to "+string+' ..');
        window.ws = new WebSocket('ws://'+string+':8181/');

        // when data is comming from the server, this method is called
        ws.onmessage = function (evt) {
            jsonObject = JSON.parse(evt.data);
            if(jsonObject.bodies == '')
            {
                status = 1;
            } else
            {
                status = 2;
            }
        };

        // when the connection is established, this method is called
        ws.onopen = function () {
        console.log('.. connection open');
        };

        // when the connection is closed, this method is called
        ws.onclose = function () {
        console.log('.. connection closed');
        status = 0;
        };
    }

    //Closes the current connection
    ext.closeconn = function()
    {
        window.ws.close();
    }

    //m: the number to be written to the console
    //Outputs numeric content to console
    ext.write = function(number){
        console.log(number);
    };

    //m: input to be compared to 0
    //Writes "bad" in console if the input is 0
    ext.writeB = function(number){
        if(number == 0)
        {
            console.log("bad");
        }
    };

    //Checks the body 1 head x coordinate
    //Good for check if any data is getting in from the kinect
    ext.basic_body_check = function() {
        console.log(jsonObject.bodies[0].joints[3].x*xScale);
    };

    //m: the body chosen (Body 1-6)
    //Gives the id of the selected body
    ext.bodyid = function(body)
    {
        switch(body){
            case 'Body 1': return jsonObject.bodies[0].id;
            case 'Body 2': return jsonObject.bodies[1].id;
            case 'Body 3': return jsonObject.bodies[2].id;
            case 'Body 4': return jsonObject.bodies[3].id;
            case 'Body 5': return jsonObject.bodies[4].id;
            case 'Body 6': return jsonObject.bodies[5].id;
        }
    }

    ext.test = function()
    {
        var b = -1;
        var bodyID = jsonObject.bodies[0].id;
        for(i = 0; i < 6; i++)
        {
            if(bodyID != 0)
            {
                if(bodyID == jsonObject.bodies[i].id)
                {
                    b = i;
                    //b = jsonObject.bodies[5].id;
                }
            }

        }
        console.log(jsonObject.bodies[b].id);
        //console.log(b);
    }

        //True if scratch is receiving the kinect (but not necessarily data)
    ext.connected = function()
    {
        if(status == 0){
            return false;
        }

        if(status == 1 || 2){
            return true;
        }
    };

    //m: the body chosen (Body 1-6)
    //True if scratch is receiving the chosen body data
    ext.tracked = function(body)
    {
        var i = -1;
        switch(body){
            case 'Body 1': i = 0;
                break;
            case 'Body 2': i = 1;
                break;
            case 'Body 3': i = 2;
                break;
            case 'Body 4': i = 3;
                break;
            case 'Body 5': i = 4;
                break;
            case 'Body 6': i = 5;
                break;
        }

        return jsonObject.bodies[i].id != 0;
    };

    //l: the body chosen (Body 1-6)
    //d: which handstate (left or right)
    //Outputs the left handstate of the selected body
    ext.handdebug = function(body,direction)
    {
        var i;
        switch(body){
            case 'Body 1': i=0;
                break;
            case 'Body 2': i=1;
                break;
            case 'Body 3': i=2;
                break;
            case 'Body 4': i=3;
                break;
            case 'Body 5': i=4;
                break;
            case 'Body 6': i=5;
                break;
        }

        switch(direction)
        {
            case 'Left': return jsonObject.bodies[i].lhandstate;
            case 'Right': return jsonObject.bodies[i].rhandstate;
        }
    }

    //l: The selected body (Body 1-6)
    //d: Which handstate (left or right)
    //n: The selected handstate (Unknown, Not Tracked, Open, Closed, Lasso)
    //Returns true if the selected bodies left handstate is the same as block selected one.
    ext.handstate = function(body,direction,handstate)
    {
        var i;
        var j;
        switch(body){
            case 'Body 1': i=0;
                break;
            case 'Body 2': i=1;
                break;
            case 'Body 3': i=2;
                break;
            case 'Body 4': i=3;
                break;
            case 'Body 5': i=4;
                break;
            case 'Body 6': i=5;
                break;
        }

        switch(handstate)
        {
            case 'Unknown': j = 0;
                break;
            case 'Not Tracked': j = 1;
                break;
            case 'Open': j = 2;
                break;
            case 'Closed': j = 3;
                break;
            case 'Lasso': j = 4;
                break;
        }

        switch(direction)
        {
            case 'Left': return jsonObject.bodies[i].lhandstate == j;
            case 'Right': return jsonObject.bodies[i].rhandstate == j;
        }
    }

    //l: The body chosen (Body 1-6).
    //k1: The joint chosen (All joint the kinect v2 tracks).
    //x: The chosen coordinate (x, y, or z).
    //Gets the coordinate chosen from the joint chosen from the body chosen
    ext.joints = function(body,joint,coordinate)
    {
        var a = -1;
        var b = -1;

        switch(joint){
            case 'Left Ankle': a=14;
                break;
            case 'Right Ankle': a=18;
                break;
            case 'Left Elbow': a=5;
                break;
            case 'Right Elbow': a=9;
                break;
            case 'Left Foot': a=15;
                break;
            case 'Right Foot': a=19;
                break;
            case 'Left Hand': a=7;
                break;
            case 'Right Hand': a=11;
                break;
            case 'Left Hand Tip': a=21;
                break;
            case 'Right Hand Tip': a=23;
                break;
            case 'Head': a=3;
                break;
            case 'Left Hip': a=12;
                break;
            case 'Right Hip': a=16;
                break;
            case 'Left Knee': a=13;
                break;
            case 'Right Knee': a=17;
                break;
            case 'Neck': a=2;
                break;
            case 'Left Shoulder': a=4;
                break;
            case 'Right Shoulder': a=8;
                break;
            case 'Spine Base': a=0;
                break;
            case 'Spine Middle': a=1;
                break;
            case 'Spine Shoulder': a=20;
                break;
            case 'Left Thumb': a=22;
                break;
            case 'Right Thumb': a=24;
                break;
            case 'Left Wrist': a=6;
                break;
            case 'Right Wrist': a=10;
                break;
        }

        switch(body){
            case 'Body 1': b=0;
                break;
            case 'Body 2': b=1;
                break;
            case 'Body 3': b=2;
                break;
            case 'Body 4': b=3;
                break;
            case 'Body 5': b=4;
                break;
            case 'Body 6': b=5;
                break;
        }

        switch(coordinate){
            case 'x': return jsonObject.bodies[b].joints[a].x*xScale;
            case 'y': return jsonObject.bodies[b].joints[a].y*yScale;
            case 'z': return jsonObject.bodies[b].joints[a].z*zScale;
        }
    }

        //l: The body chosen (Body 1-6).
    //k1: The joint chosen (All joint the kinect v2 tracks).
    //x: The chosen coordinate (x, y, or z).
    //Gets the coordinate chosen from the joint chosen from the body chosen
    ext.jointsID = function(bodyID,joint,coordinate)
    {
        var a = -1;
        var b = -1;

        switch(joint){
            case 'Left Ankle': a=14;
                break;
            case 'Right Ankle': a=18;
                break;
            case 'Left Elbow': a=5;
                break;
            case 'Right Elbow': a=9;
                break;
            case 'Left Foot': a=15;
                break;
            case 'Right Foot': a=19;
                break;
            case 'Left Hand': a=7;
                break;
            case 'Right Hand': a=11;
                break;
            case 'Left Hand Tip': a=21;
                break;
            case 'Right Hand Tip': a=23;
                break;
            case 'Head': a=3;
                break;
            case 'Left Hip': a=12;
                break;
            case 'Right Hip': a=16;
                break;
            case 'Left Knee': a=13;
                break;
            case 'Right Knee': a=17;
                break;
            case 'Neck': a=2;
                break;
            case 'Left Shoulder': a=4;
                break;
            case 'Right Shoulder': a=8;
                break;
            case 'Spine Base': a=0;
                break;
            case 'Spine Middle': a=1;
                break;
            case 'Spine Shoulder': a=20;
                break;
            case 'Left Thumb': a=22;
                break;
            case 'Right Thumb': a=24;
                break;
            case 'Left Wrist': a=6;
                break;
            case 'Right Wrist': a=10;
                break;
        }

        for(i = 0; i < 6; i++)
        {
            if(bodyID != 0)
            {
                if(bodyID == jsonObject.bodies[i].id)
                {
                    b = i;
                }
            }
        }
        console.log(b);

        switch(coordinate){
            case 'x': return jsonObject.bodies[b].joints[a].x*xScale;
            case 'y': return jsonObject.bodies[b].joints[a].y*yScale;
            case 'z': return jsonObject.bodies[b].joints[a].z*zScale;
        }
    }

    // Register the extension
    ScratchExtensions.register('SkelScratch', descriptor, ext);
})({});<commit_msg>Save check for tomorrow<commit_after>/*
 * Authors: Isaac Zylstra and Victor Norman @ Calvin College, Grand Rapids, MI.
 * Contact: vtn2@calvin.edu
 */

(function(ext) {

    //The variable that will hold the json to be read from
    var jsonObject = null;

    //The scale applied to the kinect data to make it map to the canvas better.
    var xScale = 240;
    var yScale = 180;
    var zScale = 200;

    //The status of the kinect
    var status = 0;

    //alert letting the user know what needs to be done before loading the extension.
    alert("BEFORE CLICKING OK: Make sure the kinect is connected and your JSON websocket server has started");

    console.log("connecting to server ..");

    // create a new websocket and connect
    window.ws = new WebSocket('ws://localhost:8181/');

    // when data is comming from the server, this method is called
    ws.onmessage = function (evt) {
        jsonObject = JSON.parse(evt.data);
            if(jsonObject.bodies == '')
            {
                status = 1;
            } else
            {
                status = 2;
            }
    };

    // when the connection is established, this method is called
    ws.onopen = function () {
        console.log('.. connection open');
    };

    // when the connection is closed, this method is called
    ws.onclose = function () {
        console.log('.. connection closed');
        status = 0;
    };

    // Cleanup function when the extension is unloaded
    ext._shutdown = function()
    {
    window.ws.close();
    };

    // Reports status of kinect
    ext._getStatus = function() {
        if(status == 0)
        {
        return {status: 0, msg: 'Kinect is not connected to Scratch'};
        }
        if(status == 1)
        {
            return {status: 1, msg: 'Kinect is connected, but is not detecting any bodies'};
        }
        if(status == 2)
        {
            return {status: 2, msg: 'Kinect is sending body data'};
        }
    };

        // Block and block menu descriptions
    var descriptor = {
        blocks: [
            ['r', '%m.b %m.j %m.c', 'joints', 'Body 1', 'Head', 'x'],
            ['r', 'Body ID %n %m.j %m.c', 'jointsID', '0', 'Head', 'x'],
            ['b', '%m.b %m.d Handstate is %m.h', 'handstate', 'Body 1', 'Left', 'Closed'],
            ['r', '%m.b %m.d Handstate', 'handdebug', 'Body 1', 'Left'], //Comment out of final version.
            ['r', '%m.b ID', 'bodyid', 'Body 1'],
            ['b', '%m.b tracked', 'tracked', 'Body 1'],
            ['b', 'connected', 'connected'],
            ['', 'Basic body check', 'basic_body_check'], //Comment out of final version.
            ['', 'Test Block', 'test'], //Comment out of final
            ['', 'Start new local connection', 'local'],
            ['', 'connect to %s', 'ipconnect', '0.0.0.0'],
            ['', 'Close connection', 'closeconn'], //Comment out of final version.
            ['', 'console.log %n', 'write'], //Comment out of final version.
            ['', 'bad only %n', 'writeB'] //Comment out of final version.
        ],

        menus: {
	    j: ['Left Ankle', 'Right Ankle', 'Left Elbow', 'Right Elbow', 'Left Foot', 'Right Foot', 'Left Hand', 'Right Hand', 'Left Hand Tip', 'Right Hand Tip', 'Head', 'Left Hip', 'Right Hip', 'Left Knee', 'Right Knee', 'Neck', 'Left Shoulder', 'Right Shoulder', 'Spine Base', 'Spine Middle', 'Spine Shoulder', 'Left Thumb', 'Right Thumb', 'Left Wrist', 'Right Wrist'],
        b: ['Body 1', 'Body 2', 'Body 3', 'Body 4', 'Body 5', 'Body 6'],
        h: ['Unknown', 'Not Tracked', 'Open', 'Closed', 'Lasso'],
        c: ['x', 'y', 'z'],
        d: ['Left', 'Right']
    }
    };

    //restarts the local connection
    ext.local = function() {
        window.ws.close();
        console.log("connecting to local server ..");
        window.ws = new WebSocket('ws://localhost:8181/');

        // when data is comming from the server, this method is called
        ws.onmessage = function (evt) {
            jsonObject = JSON.parse(evt.data);
            if(jsonObject.bodies == '')
            {
                status = 1;
            } else
            {
                status = 2;
            }
    };

    // when the connection is established, this method is called
    ws.onopen = function () {
        console.log('.. connection open');
    };

    // when the connection is closed, this method is called
    ws.onclose = function () {
        console.log('.. connection closed');
        status = 0;
    };
    };

    //s: a string containing the ip the user wishes to connect to.
    //Creates a remote connection to s.
    ext.ipconnect = function(string) {
        window.ws.close();
        console.log("connecting to "+string+' ..');
        window.ws = new WebSocket('ws://'+string+':8181/');

        // when data is comming from the server, this method is called
        ws.onmessage = function (evt) {
            jsonObject = JSON.parse(evt.data);
            if(jsonObject.bodies == '')
            {
                status = 1;
            } else
            {
                status = 2;
            }
        };

        // when the connection is established, this method is called
        ws.onopen = function () {
        console.log('.. connection open');
        };

        // when the connection is closed, this method is called
        ws.onclose = function () {
        console.log('.. connection closed');
        status = 0;
        };
    }

    //Closes the current connection
    ext.closeconn = function()
    {
        window.ws.close();
    }

    //m: the number to be written to the console
    //Outputs numeric content to console
    ext.write = function(number){
        console.log(number);
    };

    //m: input to be compared to 0
    //Writes "bad" in console if the input is 0
    ext.writeB = function(number){
        if(number == 0)
        {
            console.log("bad");
        }
    };

    //Checks the body 1 head x coordinate
    //Good for check if any data is getting in from the kinect
    ext.basic_body_check = function() {
        console.log(jsonObject.bodies[0].joints[3].x*xScale);
    };

    //m: the body chosen (Body 1-6)
    //Gives the id of the selected body
    ext.bodyid = function(body)
    {
        switch(body){
            case 'Body 1': return jsonObject.bodies[0].id;
            case 'Body 2': return jsonObject.bodies[1].id;
            case 'Body 3': return jsonObject.bodies[2].id;
            case 'Body 4': return jsonObject.bodies[3].id;
            case 'Body 5': return jsonObject.bodies[4].id;
            case 'Body 6': return jsonObject.bodies[5].id;
        }
    }

    ext.test = function()
    {
        var b = -1;
        var bodyID = jsonObject.bodies[0].id;
        for(i = 0; i < 6; i++)
        {
            if(bodyID != 0)
            {
                if(bodyID == jsonObject.bodies[i].id)
                {
                    b = i;
                    //b = jsonObject.bodies[5].id;
                }
            }

        }
        console.log(jsonObject.bodies[b].id);
        //console.log(b);
    }

        //True if scratch is receiving the kinect (but not necessarily data)
    ext.connected = function()
    {
        if(status == 0){
            return false;
        }

        if(status == 1 || 2){
            return true;
        }
    };

    //m: the body chosen (Body 1-6)
    //True if scratch is receiving the chosen body data
    ext.tracked = function(body)
    {
        var i = -1;
        switch(body){
            case 'Body 1': i = 0;
                break;
            case 'Body 2': i = 1;
                break;
            case 'Body 3': i = 2;
                break;
            case 'Body 4': i = 3;
                break;
            case 'Body 5': i = 4;
                break;
            case 'Body 6': i = 5;
                break;
        }

        return jsonObject.bodies[i].id != 0;
    };

    //l: the body chosen (Body 1-6)
    //d: which handstate (left or right)
    //Outputs the left handstate of the selected body
    ext.handdebug = function(body,direction)
    {
        var i;
        switch(body){
            case 'Body 1': i=0;
                break;
            case 'Body 2': i=1;
                break;
            case 'Body 3': i=2;
                break;
            case 'Body 4': i=3;
                break;
            case 'Body 5': i=4;
                break;
            case 'Body 6': i=5;
                break;
        }

        switch(direction)
        {
            case 'Left': return jsonObject.bodies[i].lhandstate;
            case 'Right': return jsonObject.bodies[i].rhandstate;
        }
    }

    //l: The selected body (Body 1-6)
    //d: Which handstate (left or right)
    //n: The selected handstate (Unknown, Not Tracked, Open, Closed, Lasso)
    //Returns true if the selected bodies left handstate is the same as block selected one.
    ext.handstate = function(body,direction,handstate)
    {
        var i;
        var j;
        switch(body){
            case 'Body 1': i=0;
                break;
            case 'Body 2': i=1;
                break;
            case 'Body 3': i=2;
                break;
            case 'Body 4': i=3;
                break;
            case 'Body 5': i=4;
                break;
            case 'Body 6': i=5;
                break;
        }

        switch(handstate)
        {
            case 'Unknown': j = 0;
                break;
            case 'Not Tracked': j = 1;
                break;
            case 'Open': j = 2;
                break;
            case 'Closed': j = 3;
                break;
            case 'Lasso': j = 4;
                break;
        }

        switch(direction)
        {
            case 'Left': return jsonObject.bodies[i].lhandstate == j;
            case 'Right': return jsonObject.bodies[i].rhandstate == j;
        }
    }

    //l: The body chosen (Body 1-6).
    //k1: The joint chosen (All joint the kinect v2 tracks).
    //x: The chosen coordinate (x, y, or z).
    //Gets the coordinate chosen from the joint chosen from the body chosen
    ext.joints = function(body,joint,coordinate)
    {
        var a = -1;
        var b = -1;

        switch(joint){
            case 'Left Ankle': a=14;
                break;
            case 'Right Ankle': a=18;
                break;
            case 'Left Elbow': a=5;
                break;
            case 'Right Elbow': a=9;
                break;
            case 'Left Foot': a=15;
                break;
            case 'Right Foot': a=19;
                break;
            case 'Left Hand': a=7;
                break;
            case 'Right Hand': a=11;
                break;
            case 'Left Hand Tip': a=21;
                break;
            case 'Right Hand Tip': a=23;
                break;
            case 'Head': a=3;
                break;
            case 'Left Hip': a=12;
                break;
            case 'Right Hip': a=16;
                break;
            case 'Left Knee': a=13;
                break;
            case 'Right Knee': a=17;
                break;
            case 'Neck': a=2;
                break;
            case 'Left Shoulder': a=4;
                break;
            case 'Right Shoulder': a=8;
                break;
            case 'Spine Base': a=0;
                break;
            case 'Spine Middle': a=1;
                break;
            case 'Spine Shoulder': a=20;
                break;
            case 'Left Thumb': a=22;
                break;
            case 'Right Thumb': a=24;
                break;
            case 'Left Wrist': a=6;
                break;
            case 'Right Wrist': a=10;
                break;
        }

        switch(body){
            case 'Body 1': b=0;
                break;
            case 'Body 2': b=1;
                break;
            case 'Body 3': b=2;
                break;
            case 'Body 4': b=3;
                break;
            case 'Body 5': b=4;
                break;
            case 'Body 6': b=5;
                break;
        }

        switch(coordinate){
            case 'x': return jsonObject.bodies[b].joints[a].x*xScale;
            case 'y': return jsonObject.bodies[b].joints[a].y*yScale;
            case 'z': return jsonObject.bodies[b].joints[a].z*zScale;
        }
    }

        //l: The body chosen (Body 1-6).
    //k1: The joint chosen (All joint the kinect v2 tracks).
    //x: The chosen coordinate (x, y, or z).
    //Gets the coordinate chosen from the joint chosen from the body chosen
    ext.jointsID = function(bodyID,joint,coordinate)
    {
        var a = -1;
        var b = -1;

        switch(joint){
            case 'Left Ankle': a=14;
                break;
            case 'Right Ankle': a=18;
                break;
            case 'Left Elbow': a=5;
                break;
            case 'Right Elbow': a=9;
                break;
            case 'Left Foot': a=15;
                break;
            case 'Right Foot': a=19;
                break;
            case 'Left Hand': a=7;
                break;
            case 'Right Hand': a=11;
                break;
            case 'Left Hand Tip': a=21;
                break;
            case 'Right Hand Tip': a=23;
                break;
            case 'Head': a=3;
                break;
            case 'Left Hip': a=12;
                break;
            case 'Right Hip': a=16;
                break;
            case 'Left Knee': a=13;
                break;
            case 'Right Knee': a=17;
                break;
            case 'Neck': a=2;
                break;
            case 'Left Shoulder': a=4;
                break;
            case 'Right Shoulder': a=8;
                break;
            case 'Spine Base': a=0;
                break;
            case 'Spine Middle': a=1;
                break;
            case 'Spine Shoulder': a=20;
                break;
            case 'Left Thumb': a=22;
                break;
            case 'Right Thumb': a=24;
                break;
            case 'Left Wrist': a=6;
                break;
            case 'Right Wrist': a=10;
                break;
        }

        for(i = 0; i < 6; i++)
        {
            if(bodyID != 0)
            {
                if(bodyID == jsonObject.bodies[i].id)
                {
                    b = i;
                }
            }
        }

        switch(coordinate){
            case 'x': return jsonObject.bodies[b].joints[a].x*xScale;
            case 'y': return jsonObject.bodies[b].joints[a].y*yScale;
            case 'z': return jsonObject.bodies[b].joints[a].z*zScale;
        }
    }

    // Register the extension
    ScratchExtensions.register('SkelScratch', descriptor, ext);
})({});<|endoftext|>