pidgin/nest

Merge

2019-05-16, John Bailey
8958060289bd
Merge
  • +11 -0
    .dockerignore
  • +2 -1
    .hgignore
  • +10 -7
    Dockerfile
  • +11 -7
    convey.yml
  • +4 -0
    dev-server.sh
  • +6 -0
    hugo/archetypes/archetypes/default.md
  • +29 -1
    hugo/config.toml
  • +1 -0
    hugo/content/contributing/_index.md
  • +3 -0
    hugo/content/development/design-guidelines.md
  • +3 -0
    hugo/content/development/faq.md
  • +39 -33
    hugo/content/drafts/release-process.md
  • +90 -0
    hugo/content/drafts/voice-and-video-API.md
  • +83 -0
    hugo/content/drafts/voice-and-video.md
  • +3 -0
    hugo/content/gsoc/ideas.md
  • +3 -0
    hugo/content/gsoc/instructions.md
  • +3 -0
    hugo/content/i18n/tips.md
  • +1 -1
    hugo/content/plugins/_index.md
  • +0 -14
    hugo/content/plugins/trusted-plugins.md
  • +656 -101
    hugo/data/plugins.json
  • +12 -0
    hugo/data/supporters.json
  • +15 -0
    hugo/i18n/en.toml
  • +2 -2
    hugo/layouts/partials/footline.html
  • +2 -2
    hugo/layouts/partials/supporters.html
  • +73 -9
    hugo/layouts/shortcodes/plugintable.html
  • +25 -2
    hugo/static/css/custom.css
  • +159 -0
    hugo/static/oauth.html
  • +26 -0
    hugo/themes/learn/i18n/nl.toml
  • +0 -1
    hugo/themes/learn/layouts/404.html
  • +0 -1
    hugo/themes/learn/layouts/partials/footer.html
  • +24 -15
    hugo/themes/learn/layouts/partials/header.html
  • +4 -4
    hugo/themes/learn/layouts/partials/menu.html
  • +0 -5
    hugo/themes/learn/layouts/partials/toc.html
  • +0 -8
    hugo/themes/learn/static/css/featherlight.min.css
  • +0 -3
    hugo/themes/learn/static/css/theme.css
  • +0 -8
    hugo/themes/learn/static/js/featherlight.min.js
  • +0 -59
    hugo/themes/learn/static/js/hugo-learn.js
  • +0 -6
    hugo/themes/learn/static/js/learn.js
  • +952 -0
    package-lock.json
  • +4 -1
    package.json
  • +6 -0
    readme.md
  • +7 -2
    tools/migrate-tracker.js
  • +189 -192
    tools/paths.txt
  • +164 -0
    tools/visual-diff.js
  • --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/.dockerignore Thu May 16 22:10:20 2019 -0400
    @@ -0,0 +1,11 @@
    +.dockerignore
    +.hg
    +.hgignore
    +.idea
    +.npmrc
    +.vscode
    +Dockerfile
    +community.md
    +convey.yml
    +node_modules
    +readme.md
    --- a/.hgignore Mon Feb 11 12:43:24 2019 -0500
    +++ b/.hgignore Thu May 16 22:10:20 2019 -0400
    @@ -3,4 +3,5 @@
    public/
    node_modules/
    docker-compose.override.yml
    -
    +differencify_reports
    +tools/diff-config.json
    --- a/Dockerfile Mon Feb 11 12:43:24 2019 -0500
    +++ b/Dockerfile Thu May 16 22:10:20 2019 -0400
    @@ -7,17 +7,20 @@
    apt-get clean && \
    rm -rf /var/lib/apt/lists
    -COPY . /hugo
    +COPY package-lock.json package.json /nest/
    RUN set -ex && \
    - cd /hugo && \
    - hugo -s hugo -d ../public && \
    - npm ci --production && \
    - npm run tidy
    + cd /nest && \
    + npm ci --production && \
    + npm cache clean --force
    +
    +COPY . /nest
    +
    +RUN hugo -s /nest/hugo -d /nest/public && \
    + node /nest/tools/pre-prod.js
    FROM rwgrim/goserve
    -COPY --from=build /hugo/public /html
    +COPY --from=build /nest/public /html
    EXPOSE 3000/tcp
    -
    --- a/convey.yml Mon Feb 11 12:43:24 2019 -0500
    +++ b/convey.yml Thu May 16 22:10:20 2019 -0400
    @@ -1,6 +1,10 @@
    environment:
    - REPO=pidgin/nest
    - TAG=latest
    + - REGISTER_USERNAME
    + - REGISTRY_PASSWORD
    + - REGISTRY=docker.io
    +
    tasks:
    import:
    type: docker/import
    @@ -8,22 +12,22 @@
    build:
    type: docker/build
    dockerfile: Dockerfile
    - tag: ${REPO}:${TAG}
    + tag: ${REGISTRY}/${REPO}:${TAG}
    files: .
    push:
    type: docker/push
    - image: ${REPO}:${TAG}
    + image: ${REGISTRY}/${REPO}:${TAG}
    clean:
    type: docker/remove
    - image: ${REPO}:${TAG}
    + image: ${REGISTRY}/${REPO}:${TAG}
    login:
    type: docker/login
    - username: ${DOCKERHUB_USERNAME}
    - password: ${DOCKERHUB_PASSWORD}
    - server: docker.io
    + username: ${REGISTRY_USERNAME}
    + password: ${REGISTRY_PASSWORD}
    + server: ${REGISTRY}
    logout:
    type: docker/logout
    - server: docker.io
    + server: ${REGISTRY}
    plans:
    default:
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/dev-server.sh Thu May 16 22:10:20 2019 -0400
    @@ -0,0 +1,4 @@
    +#!/bin/sh -e
    +
    +hugo server -s hugo -D --disableFastRender -v --verboseLog --noHTTPCache --i18n-warnings
    +
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/hugo/archetypes/archetypes/default.md Thu May 16 22:10:20 2019 -0400
    @@ -0,0 +1,6 @@
    +---
    +title: "{{ replace .Name "-" " " | title }}"
    +date: {{ .Date }}
    +replaces: []
    +---
    +
    --- a/hugo/config.toml Mon Feb 11 12:43:24 2019 -0500
    +++ b/hugo/config.toml Thu May 16 22:10:20 2019 -0400
    @@ -21,11 +21,39 @@
    # Shourtcuts
    [[menu.shortcuts]]
    - name = "<i class='fab fa-fw fa-bitbucket'></i> Bitbucket repo"
    + name = "<i class='fab fa-fw fa-bitbucket'></i> Bitbucket"
    identifier = "bitbucket"
    url = "https://bitbucket.org/pidgin/"
    + weight = 1000
    [[menu.shortcuts]]
    name = "<i class='fab fa-fw fa-discord'></i> Discord"
    identifier = "discord"
    url = "https://discord.gg/pB9fbVC"
    +
    +[[menu.shortcuts]]
    + name = "<i class='fab fa-fw fa-facebook-f'></i> Facebook"
    + identifier = "facebook"
    + url = "https://www.facebook.com/pidgin.im/"
    +
    +# This is broke, see https://bitbucket.org/pidgin/nest/issues/1/
    +# [[menu.shortcuts]]
    +# name = "<i class='fas fa-fw fa-comment-dots'></i> IRC"
    +# identifier = "irc"
    +# url = "ircs://chat.freenode.net:6697/#pidgin"
    +
    +[[menu.shortcuts]]
    + name = "<i class='fab fa-fw fa-reddit-alien'></i> Reddit"
    + identifier = "reddit"
    + url = "https://reddit.com/r/pidgin"
    +
    +[[menu.shortcuts]]
    + name = "<i class='fas fa-fw fa-tshirt'></i> Merchandise"
    + identifier = "merchandise"
    + url = "https://shop.spreadshirt.com/imfreedom"
    + weigth = 900
    +
    +[[menu.shortcuts]]
    + name = "<i class='fab fa-fw fa-twitter'></i> Twitter"
    + identifier = "twitter"
    + url = "https://twitter.com/impidgin"
    --- a/hugo/content/contributing/_index.md Mon Feb 11 12:43:24 2019 -0500
    +++ b/hugo/content/contributing/_index.md Thu May 16 22:10:20 2019 -0400
    @@ -3,6 +3,7 @@
    date: 2019-02-03T19:49:30-05:00
    anchor: "contributing"
    weight: 10
    +original: true
    ---
    Pidgin is a huge project with a ton of things to be done, even if you're not a coder. Below is a short list of things you can do to help get involved!!
    --- a/hugo/content/development/design-guidelines.md Mon Feb 11 12:43:24 2019 -0500
    +++ b/hugo/content/development/design-guidelines.md Thu May 16 22:10:20 2019 -0400
    @@ -2,6 +2,9 @@
    title: "Design Guidelines"
    date: 2019-02-03T20:47:20-05:00
    anchor: "design-guidelines"
    +replaces: [
    + "developer.pidgin.im/wiki/DesignGuidelines",
    +]
    ---
    ## Applicability
    --- a/hugo/content/development/faq.md Mon Feb 11 12:43:24 2019 -0500
    +++ b/hugo/content/development/faq.md Thu May 16 22:10:20 2019 -0400
    @@ -2,6 +2,9 @@
    title: "FAQ"
    date: 2019-02-03T20:57:00-05:00
    anchor: "development-faq"
    +replaces: [
    + "developer.pidgin.im/wiki/Development%20FAQ",
    +]
    ---
    The following is a list of Frequently Asked Questions (FAQs), with answers, and notes related to development using LibPurple.
    --- a/hugo/content/drafts/release-process.md Mon Feb 11 12:43:24 2019 -0500
    +++ b/hugo/content/drafts/release-process.md Thu May 16 22:10:20 2019 -0400
    @@ -1,6 +1,9 @@
    ---
    title: "Release Process"
    draft: true
    +replaces: [
    + "developer.pidgin.im/wiki/ReleaseProcess",
    +]
    ---
    The release process for Pidgin is kind of tedious but is described in great detail below.
    @@ -25,17 +28,19 @@
    Ask Gary Kramlich or Richard Laager if you need administrative access to [Pidgin's Transifex project](https://www.transifex.com/projects/p/pidgin/resources/) for the following steps.
    **Steps**
    +
    1. Fetch and commit all translations from Transifex.
    - a. `cd po`
    - a. `make pidgin.pot`
    - a. `tx pull --force` - Pulls all translations from Transifex, even if local timestamp is newer than remote.
    - a. `XGETTEXT_ARGS=--no-location intltool-update --report` - Merges current strings into translations and strips filename and line numbers to keep diffs smaller.
    - a. `find -name \*.po -exec msgfmt -cv {} \;` - Check for mismatched c-format specifiers. These can cause crashes so look at the output carefully! If any are found, follow these steps:
    - 1. Edit the translation in Transifex.
    - 1. Remove the string with the mismatched c-format specifiers (leave it blank).
    - 1. `tx pull --force --language=NN` - Pull the updated translation from Transifex.
    + 1. `cd po`
    + 1. `make pidgin.pot`
    + 1. `tx pull --force` - Pulls all translations from Transifex, even if local timestamp is newer than remote.
    + 1. `XGETTEXT_ARGS=--no-location intltool-update --report` - Merges current strings into translations and strips filename and line numbers to keep diffs smaller.
    + 1. `find -name \*.po -exec msgfmt -cv {} \;` - Check for mismatched c-format specifiers. These can cause crashes so look at the output carefully! If any are found, follow these steps:
    + 1. Edit the translation in Transifex.
    + 1. Remove the string with the mismatched c-format specifiers (leave it blank).
    + 1. `tx pull --force --language=NN` - Pull the updated translation from Transifex.
    **Other Pre-Release Steps**
    +
    1. Make sure list of translators in `pidgin/gtkdialogs.c` matches the Transifex translations teams. (TODO: This is labor intensive and error prone. Should find a way to automate.)
    1. Check there are no open tickets for this release milestone
    1. Make sure the date and version number are correct in ChangeLog and ChangeLog.API
    @@ -46,46 +51,47 @@
    1. Verify that win32 builds succeed (including building installers).
    ## Release
    +
    1. Tag the repository. The tag should have a `v` prefix. Ie: `v2.12.0`.
    1. Extract the tagged code `hg archive -r $TAG ../pidgin-$VERSION`.
    1. `cd ../pidgin-$VERSION`
    1. Run `./autogen.sh`
    - 1. Run `make release`
    - This will perform the following steps (which can also be done by hand at this point):
    - a. `make commit-check` - Checks a few files for correctness (UTF-8 encoding, sort order, etc.).
    - a. `make version-check` - Make sure version string does not contain "dev," version is correct in ChangeLogs, and we're building from a clean hg tag.
    - a. `make distcheck` - Standard automake target. Builds and verifies tarballs. If "distcheck" fails and you're sure the failure is innocuous then you can use `make dist`, instead.
    - a. `make sign-packages` - Creates a gpg signature of the two tarballs.
    + 1. Run `make release`: This will perform the following steps (which can also be done by hand at this point):
    + 1. `make commit-check` - Checks a few files for correctness (UTF-8 encoding, sort order, etc.).
    + 1. `make version-check` - Make sure version string does not contain "dev," version is correct in ChangeLogs, and we're building from a clean hg tag.
    + 1. `make distcheck` - Standard automake target. Builds and verifies tarballs. If "distcheck" fails and you're sure the failure is innocuous then you can use `make dist`, instead.
    + 1. `make sign-packages` - Creates a gpg signature of the two tarballs.
    1. [wiki:BuildingWinPidgin Build on Windows]
    - a. If there's a new GTK+ Bundle, upload the zip file to [Sourceforge](https://sourceforge.net/projects/pidgin/files/Pidgin/) and make sure that the `BUNDLE_SHA1SUM` in `pidgin/win32/nsis/generate_gtk_zip.sh` is correct (this should have been checked before `make release`).
    - a. Check the authenticode signature and timestamp for the installers (unfortunately needs to be done on a Windows box with the Platform SDK installed)
    -```
    -signtool.exe verify /pa /tw pidgin-$VERSION-offline.exe
    -signtool.exe verify /pa /tw pidgin-$VERSION.exe
    -```
    - a. Install `pidgin-$VERSION-offline.exe` and check the authenticode signature and timestamp of pidgin.exe
    -```
    -signtool.exe verify /pa /tw %ProgramFiles(x86)%\Pidgin\pidgin.exe
    -```
    + 1. If there's a new GTK+ Bundle, upload the zip file to [Sourceforge](https://sourceforge.net/projects/pidgin/files/Pidgin/) and make sure that the `BUNDLE_SHA1SUM` in `pidgin/win32/nsis/generate_gtk_zip.sh` is correct (this should have been checked before `make release`).
    + 1. Check the authenticode signature and timestamp for the installers (unfortunately needs to be done on a Windows box with the Platform SDK installed)
    +
    + signtool.exe verify /pa /tw pidgin-$VERSION-offline.exe
    + signtool.exe verify /pa /tw pidgin-$VERSION.exe
    +
    + 1. Install `pidgin-$VERSION-offline.exe` and check the authenticode signature and timestamp of pidgin.exe
    +
    + signtool.exe verify /pa /tw %ProgramFiles(x86)%\Pidgin\pidgin.exe
    +
    1. `hg push` the tag.
    1. Upload the two tarballs, the two signatures, and the Windows builds to [Sourceforge](https://sourceforge.net/projects/pidgin/files/Pidgin/)
    1. Wait a few hours and let people test.
    1. Build and upload new API docs.
    - a. Run `make` locally?
    - a. `scp docs/reference/libpurple/html nicobar.pidgin.im:/srv/www/developer.pidgin.im/doxygen/x.y.z/libpurple/`
    - a. `scp docs/reference/pidgin/html nicobar.pidgin.im:/srv/www/developer.pidgin.im/doxygen/x.y.z/pidgin/`
    - a. `scp docs/reference/finch/html nicobar.pidgin.im:/srv/www/developer.pidgin.im/doxygen/x.y.z/finch/`
    + 1. Run `make` locally?
    + 2. `scp docs/reference/libpurple/html nicobar.pidgin.im:/srv/www/developer.pidgin.im/doxygen/x.y.z/libpurple/`
    + 3. `scp docs/reference/pidgin/html nicobar.pidgin.im:/srv/www/developer.pidgin.im/doxygen/x.y.z/pidgin/`
    + 4. `scp docs/reference/finch/html nicobar.pidgin.im:/srv/www/developer.pidgin.im/doxygen/x.y.z/finch/`
    1. Update the Pidgin website
    - a. Change `inc/version.inc.php` (only for full releases, not for betas)
    - a. Update the ChangeLog in https://bitbucket.org/pidgin/www/ (this is used by the release notification plugin)
    + 1. Change `inc/version.inc.php` (only for full releases, not for betas)
    + 2. Update the ChangeLog in https://bitbucket.org/pidgin/www/ (this is used by the release notification plugin)
    1. Send announcement email to announce and packagers mailing lists (sending to announce also sends to support and devel)
    - * Someone must approve the posts in the [support](https://pidgin.im/cgi-bin/mailman/admindb/support) and [devel](https://pidgin.im/cgi-bin/mailman/admindb/devel) admin interface.
    + * Someone must approve the posts in the [support](https://pidgin.im/cgi-bin/mailman/admindb/support) and [devel](https://pidgin.im/cgi-bin/mailman/admindb/devel) admin interface.
    ## Post Release
    +
    1. Increment version number in `configure.ac` & set `purple_version_suffix`and `gnt_version_suffix` to `devel`
    1. Update `#pidgin` topic
    1. Add new Trac Version for this release
    1. Add new Trac milestone for the next release
    - 1. "Complete" old milestone
    + 1. "Complete" old milestone
    1. Bump the auto-close script to target auto-closed bugs to the new milestone (/srv/trac/developer.pidgin.im/mercurial_support/trac-hg-post-commit-hook.py on nicobar.pidgin.im)
    - 1. Update "The Road to" on WikiStart to list tickets for the new version
    \ No newline at end of file
    + 1. Update "The Road to" on WikiStart to list tickets for the new version
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/hugo/content/drafts/voice-and-video-API.md Thu May 16 22:10:20 2019 -0400
    @@ -0,0 +1,90 @@
    +---
    +title: "Voice and Video API"
    +date: 2019-03-16T20:15:02Z
    +replaces: [
    + "developer.pidgin.im/wiki/vvAPI",
    +]
    +---
    +
    +For functions that could be per conference, session, participant, or stream, they would have a session and a participant parameter. A NULL for either of these would be a wildcard.
    +
    +### PurpleMediaManager?
    +
    +#### Functions
    +
    +```
    +*_initiate # Creates a PurpleMedia instance. Probably have a flag as to whether it's the initiator or responder
    +```
    +
    +#### Signals
    +
    +```
    +init-media # Same as the current signal. Is triggered when *_initiate is called
    +init-video-src # These are all triggered when the corresponding *_get_\* functions are called
    +init-video-sink # The one problem I've thought of with them is that this way it wouldn't
    +init-audio-src # be very easy to have multiple srcs or sinks of the same type.
    +init-audio-sink
    +```
    +
    +#### Get
    +
    +```
    +*_get # Returns a global instance of the PurpleMediaManager
    +
    +*_get_pipeline # Returns a global pipeline to be used for all PurpleMedia instances.
    +
    +*_get_video_src # These all create their respective types if they don't exist.
    +*_get_video_sink # Otherwise they return a src/sink-pad for the existing src/sink.
    +*_get_audio_src
    +*_get_audio_sink
    +
    +# The next three functions will probably have a type parameter (audio or video, src or sink)
    +*_get_plugins # Return a list of audio/video GStreamer plugins (eg. v4lsrc, alsasrc)
    +*_get_devices # Return a list of devices for a specific plugin
    +*_get_devices_autodetect # Eventually, return a list of devices detected for all supported plugins
    +```
    +
    +### PurpleMedia?
    +
    +#### Functions
    +
    +All of these functions will have parameters for session_id and participant_id NULL for either of these would indicate a wildcard and do this operation for all matching streams
    +
    +```
    +*_add_stream # Adds a stream/session/participant to the conference, automatically creates participants and FsSessions as necessary
    +*_add_candidate # Adds a single candidate to the stream (May not be necessary. Could alternately add a list)
    +*_set_candidates # Sets a list of candidates for the stream
    +*_set_codecs # Sets a list of codecs for the stream
    +*_set_direction # Changes the direction of a stream/session/participant (could use *_add_stream to accomplish this)
    +
    +*_accept # Accept a session (User clicked the accept button)
    +
    +# The following two could probably be merged into one function
    +*_mute # Mutes an audio stream/session/participant (sending and/or receiving?)
    +*_pause # Pauses a video stream/session/participant (sending and/or receiving?)
    +
    +*_end # Ends a stream/session/participant/conference
    +```
    +
    +#### Signals
    +
    +These signals also apply to the wildcard note above
    +
    +```
    +ready # Waits for both codecs-ready to be TRUE and candidates-prepared to have fired (possibly also wait for the user to click accept if they are the responder otherwise we'll probably need an "accepted" signal)
    +state-changed # Has an enum state (containing such states as connected, end, and ice-specific values) Signals for stream/session/participant/conference
    +```
    +
    +More signals may be necessary for different protocols. Jingle ice-udp may also need a new-candidate and/or new-candidate-pair and a codecs-changed equivalent
    +
    +#### Get
    +
    +I'm not certain all of these will be necessary
    +
    +```
    +*_codecs # gets codecs per sessions
    +*_candidates # gets candidates per stream
    +*_streams # gets stream_ids by session or by participant
    +*_sessions # gets session_ids in the conference
    +*_participants # gets participant names by conference or by session
    +```
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/hugo/content/drafts/voice-and-video.md Thu May 16 22:10:20 2019 -0400
    @@ -0,0 +1,83 @@
    +---
    +title: "Voice and Video"
    +date: 2019-03-16T16:58:31Z
    +replaces: [
    + "developer.pidgin.im/wiki/vv",
    +]
    +---
    +
    +## Voice and Video
    +
    +Voice and video in libPurple is being worked on using [​Farstream](http://www.freedesktop.org/wiki/Software/Farstream/) (formerly Farsight). There are a few parts to this implementation. Firstly, basic API support needs to be added to libPurple. Then Pidgin and Finch need to be able to initiate, participate in, and terminate the voice and video sessions. After these two requirements are met, each protocol will require both the signaling to be implemented (such as SIP or Jingle) and the proper Farstream plugins.
    +
    +Farstream has rawudp, iceudp, and multicast transmitter plugins and an MSN webcam plugin. Basic voice and video support for libPurple, Pidgin, and Finch (voice support only) have been added to the im.pidgin.pidgin development branch. XMPP/GTalk/Gmail is working, but not complete. None of the other protocols have had much work done.
    +
    +### Protocol Specific Information
    +
    +#### XMPP/GTalk
    +
    +XMPP, GTalk, and Gmail use RTP. XMPP uses Jingle. GTalk and Gmail use their own flavor of Jingle. XMPP uses rawudp and XMPP, GTalk, and Gmail use the libnice Farstream transmitter plugin.
    +
    +Voice and video support for XMPP/GTalk was worked on for a [Summer of Code project](/wiki/GSoC2008/VoiceAndVideo)
    +
    +#### MSN
    +
    +MSN has several different voice and video types:
    +
    +- MSN Audio Conference (WLM 2009)
    +- MSN Video Conference (WLM 2009. Includes audio. Allows the h263 codec)
    +- MSN Audio Conference (pre-WLM 2009. Sometimes works with WLM2009)
    +- MSN Video Conference (pre-WLM 2009. Sometimes works with WLM2009. Includes audio. Only uses the wmv3 codec for which there is no open source encoder/GStreamer element)
    +- MSN Webcam
    +
    +A Farsight2 plugin for MSN Webcam has been released.
    +
    +[​http://imfreedom.org/wiki/MSN:AV](http://imfreedom.org/wiki/MSN:AV) has more information about the protocol.
    +
    +#### Oscar (AIM, iChat, ICQ)
    +
    +All Oscar protocols use RTP and SIP.
    +
    +#### Yahoo
    +
    +Yahoo voice uses straight SIP. It binds to the SIP server upon login and sends INVITEs as necessary.
    +
    +Yahoo webcam uses the JPEG2000 codec with proprietary transport and signalling. The old Farsight Yahoo plugin will need to be ported to the new Farstream API.
    +
    +#### Sametime
    +
    +Sametime seems to support at least voice chat [​http://publib.boulder.ibm.com/infocenter/sametime/v8r0/index.jsp?topic=/com.ibm.help.sametime.standard.doc/st_adm_avserv_aboutvoicechat_r.html](http://publib.boulder.ibm.com/infocenter/sametime/v8r0/index.jsp?topic=/com.ibm.help.sametime.standard.doc/st_adm_avserv_aboutvoicechat_r.html)
    +
    +#### Gadu-gadu
    +
    +This is a placeholder for information regarding GG voice An announcement that might be of interest: [​http://www.finanznachrichten.de/nachrichten-2008-10/12104971-global-ip-solutions-ab-gadu-gadu-launches-new-version-of-instant-messenger-with-excellent-voice-powered-by-gips-004.htm](http://www.finanznachrichten.de/nachrichten-2008-10/12104971-global-ip-solutions-ab-gadu-gadu-launches-new-version-of-instant-messenger-with-excellent-voice-powered-by-gips-004.htm)
    +
    +### Building with Voice and Video
    +
    +Please be familiar with compiling and installing code from source. Please also submit any bugs you find to Trac ([TipsForBugReports](/wiki/TipsForBugReports)).
    +
    +Make sure you are using the latest release of Pidgin.
    +
    +Farsight 2 0.0.9 and libNice 0.0.7 are the minimum versions required, but the newest versions you can get are best. Make sure to check Farsight2's README and make sure you have all of the dependencies for it. gst-plugins-base is also required for the gstreamer-interfaces-0.10 interface. Some distros call it libgstreamer-plugins-base0.10-dev. If everything in order, the configure script should output this line:
    +
    +> Build with voice and video.... yes
    +
    +For help with building, see [Installing Pidgin](/wiki/Installing%20Pidgin#Compiling). Please carefully read through that section and any extra information for the distribution you're using.
    +
    +#### Codec Configuration
    +
    +If a certain codec isn't working for you, you need to create an "fs-codec.conf" file in your purple config directory. See this for the specification: [​fs-codec-list-from-keyfile](http://farsight.freedesktop.org/apidoc/farsight2/farsight2-libs-FsCodec.html#fs-codec-list-from-keyfile)
    +
    +So, for example, if you want to disable the MPV codec you'd put this in the fs-codec.conf file:
    +
    +```
    +[video/mpv]
    +id=-1
    +```
    +
    +### Links
    +
    +- [​http://www.freedesktop.org/wiki/Software/Farstream/](http://www.freedesktop.org/wiki/Software/Farstream/)
    +- [​http://code.google.com/apis/talk/libjingle/index.html](http://code.google.com/apis/talk/libjingle/index.html)
    +- [​http://trac.adium.im/wiki/VoiceAndVideo](http://trac.adium.im/wiki/VoiceAndVideo)
    +- [​http://trac.adium.im/wiki/PidginVV](http://trac.adium.im/wiki/PidginVV)
    --- a/hugo/content/gsoc/ideas.md Mon Feb 11 12:43:24 2019 -0500
    +++ b/hugo/content/gsoc/ideas.md Thu May 16 22:10:20 2019 -0400
    @@ -2,6 +2,9 @@
    title: "GSoC Ideas"
    date: 2019-01-10T22:32:00-06:00
    anchor: "gsoc-ideas"
    +replaces: [
    + "https://developer.pidgin.im/wiki/SoCIdeas",
    +]
    ---
    These ideas are starting points for Google Summer of Code projects that the Pidgin, Finch, and libpurple community has agreed are generally desirable and high impact. For smaller projects, community-submitted ideas, or projects that for some reason we are not sure are in scope for SoC, please see [wiki:SoCAndBountyIdeas]. (You can submit SoC proposals with those ideas, or your own ideas, as well, you just have to convince us they're suitable!)
    --- a/hugo/content/gsoc/instructions.md Mon Feb 11 12:43:24 2019 -0500
    +++ b/hugo/content/gsoc/instructions.md Thu May 16 22:10:20 2019 -0400
    @@ -2,6 +2,9 @@
    title: "GSoC Instructions"
    date: 2019-01-10T22:32:00-06:00
    anchor: "gsoc-instructions"
    +replaces: [
    + "developer.pidgin.im/wiki/SoCApplicationInstructions"
    +]
    ---
    Our project has historically allowed a wide variety of applications on topics both solicited and unsolicited, and we do not intend to change this policy. However, every application must meet some criteria, which we have set out here, to be considered.
    --- a/hugo/content/i18n/tips.md Mon Feb 11 12:43:24 2019 -0500
    +++ b/hugo/content/i18n/tips.md Thu May 16 22:10:20 2019 -0400
    @@ -1,6 +1,9 @@
    ---
    title: "Tips"
    anchor: "i18n-tips"
    +replaces: [
    + "developer.pidgin.im/wiki/TipsForTranslators",
    +]
    ---
    ### Can I help translate?
    --- a/hugo/content/plugins/_index.md Mon Feb 11 12:43:24 2019 -0500
    +++ b/hugo/content/plugins/_index.md Thu May 16 22:10:20 2019 -0400
    @@ -4,4 +4,4 @@
    anchor: "plugins"
    ---
    -Pidgin has a lot of plugins...
    +{{< plugintable >}}
    --- a/hugo/content/plugins/trusted-plugins.md Mon Feb 11 12:43:24 2019 -0500
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,14 +0,0 @@
    ----
    -title: "Trusted Plugins"
    -date: 2019-01-10T22:32:00-06:00
    -anchor: "trusted-plugins"
    ----
    -
    -This page contains a list of plugins from trusted authors. What's make's an
    -author trusted you ask? Basically they've been working with us for a long time
    -and they put out some great software!
    -
    -If you believe someone should be on this list, please open a pull request with
    -the update or let grim know.
    -
    -{{< plugintable >}}
    --- a/hugo/data/plugins.json Mon Feb 11 12:43:24 2019 -0500
    +++ b/hugo/data/plugins.json Thu May 16 22:10:20 2019 -0400
    @@ -1,203 +1,758 @@
    [
    {
    + "heading": "Amazon Chime",
    + "isFirstParty": false,
    + "maintainer": "Amazon Web Services - Labs",
    + "type": "Protocol",
    + "info": "Online meeting and video conferencing",
    + "repo": "https://github.com/awslabs/pidgin-chime/"
    + },
    + {
    + "heading": "Battle.net Classic",
    + "isFirstParty": false,
    + "maintainer": "nmbook",
    + "type": "Protocol",
    + "info": "Blizzard's gaming network: notably for StarCraft, Diablo II, and WarCraft III",
    + "repo": "https://github.com/nmbook/pidgin-libbnet/"
    + },
    + {
    "heading": "Battle.net v2",
    - "logo": "https://bytebucket.org/EionRobb/purple-battlenet/raw/8cb9309fd358f7fba5d50e285b1092d5bed8aee0/battlenet48.png",
    + "isFirstParty": false,
    + "logo": "https://bitbucket.org/EionRobb/purple-battlenet/raw/99eeb650769701ba923840fcb1c90166446dd28a/battlenet48.png",
    "maintainer": "EionRobb",
    "type": "Protocol",
    - "info": "Supports Battle.net v2 to libpurple based clients like Pidgin.",
    - "repo": "https://bitbucket.org/EionRobb/purple-battlenet/overview"
    + "info": "Blizzard's gaming network for WoW, Overwatch and others",
    + "repo": "https://bitbucket.org/EionRobb/purple-battlenet/src/default/"
    + },
    + {
    + "heading": "Campfire",
    + "isFirstParty": false,
    + "logo": "https://raw.githubusercontent.com/jrfoell/campfire-libpurple/master/campfire48.png",
    + "maintainer": "jrfoell",
    + "type": "Protocol",
    + "info": "Protocol plugin for Basecamp's Campfire IM",
    + "repo": "https://github.com/jrfoell/campfire-libpurple/"
    + },
    + {
    + "heading": "Deltachat",
    + "isFirstParty": false,
    + "maintainer": "ccpp",
    + "type": "Protocol",
    + "info": "IM over email",
    + "repo": "https://github.com/ccpp/deltachat-purple/"
    },
    {
    "heading": "Discord",
    - "logo": "https://github.com/EionRobb/purple-discord/raw/master/discord48.png",
    + "isFirstParty": false,
    "maintainer": "EionRobb",
    "type": "Protocol",
    - "info": "Supports [Discord](https://discordapp.com/) to libpurple based clients like Pidgin.",
    - "repo": "https://github.com/EionRobb/purple-discord#readme"
    + "info": "Text chat for gamers",
    + "repo": "https://github.com/EionRobb/purple-discord/"
    + },
    + {
    + "heading": "Docker",
    + "isFirstParty": false,
    + "maintainer": "samuelkarp",
    + "type": "Protocol",
    + "info": "Send stdin commands to Docker containers",
    + "repo": "https://github.com/samuelkarp/purple-docker/"
    },
    {
    - "heading": "Facebook Messenger",
    - "logo": "https://bytebucket.org/pidgin/main/raw/7d94ae110549af114d518ad42e6c7e3a621e5041/pidgin/pixmaps/protocols/48/facebook.png",
    - "maintainer": "dx",
    + "heading": "F-List",
    + "isFirstParty": false,
    + "maintainer": "flist-pidgin",
    "type": "Protocol",
    - "info": "Supports [Facebook Messenger](https://messenger.com) to libpurple based clients like Pidgin.",
    - "repo": "https://github.com/dequis/purple-facebook/wiki"
    + "info": "F-List roleplaying community",
    + "repo": "https://code.google.com/archive/p/flist-pidgin/"
    + },
    + {
    + "heading": "Facebook",
    + "isFirstParty": false,
    + "maintainer": "dequis",
    + "type": "Protocol",
    + "info": "Facebook chat",
    + "repo": "https://github.com/dequis/purple-facebook/wiki/"
    },
    {
    "heading": "Gammu",
    - "logo": "https://github.com/EionRobb/purple-gammu/raw/master/icons/48/gammu.png",
    + "isFirstParty": false,
    + "logo": "https://raw.githubusercontent.com/EionRobb/purple-gammu/master/icons/48/gammu.png",
    "maintainer": "EionRobb",
    "type": "Protocol",
    - "info": "Supports [Gammu](https://wammu.eu/gammu/) to libpurple based clients like Pidgin.",
    - "repo": "https://github.com/EionRobb/purple-gammu"
    + "info": "Send SMS through your feature phone via usb/serial/bluetooth/irda",
    + "repo": "https://github.com/EionRobb/purple-gammu/"
    + },
    + {
    + "heading": "GroupMe",
    + "isFirstParty": false,
    + "maintainer": "Alyssa Rosenzweig",
    + "type": "Protocol",
    + "info": "GroupMe group messaging",
    + "repo": "https://notabug.org/alyssa/groupme-purple/"
    },
    {
    "heading": "Hangouts",
    - "logo": "https://bitbucket.org/EionRobb/purple-hangouts/avatar",
    + "isFirstParty": false,
    + "logo": "https://bitbucket-assetroot.s3.amazonaws.com/c/photos/2016/Jan/10/593383661-1-purple-hangouts-logo_avatar.png",
    + "maintainer": "EionRobb",
    + "type": "Protocol",
    + "info": "Alternative plugin for Google Hangouts",
    + "repo": "https://bitbucket.org/EionRobb/purple-hangouts/src/default/"
    + },
    + {
    + "heading": "Heroes of Newerth",
    + "isFirstParty": false,
    + "logo": "https://raw.githubusercontent.com/theli-ua/honpurple/master/data/pixmaps/pidgin/emblems/16/hon_ingame.png",
    + "maintainer": "theli-ua",
    + "type": "Protocol",
    + "info": "Online video game",
    + "repo": "https://github.com/theli-ua/honpurple/"
    + },
    + {
    + "heading": "ICQ WIM (IcyQue)",
    + "isFirstParty": false,
    "maintainer": "EionRobb",
    "type": "Protocol",
    - "info": "Supports [Hangouts](https://hangouts.google.com) to libpurple based clients like Pidgin.",
    - "repo": "https://bitbucket.org/EionRobb/purple-hangouts/"
    + "info": "Replacement ICQ plugin",
    + "repo": "https://github.com/EionRobb/icyque/"
    + },
    + {
    + "heading": "Internet Citizen's Band (ICB)",
    + "isFirstParty": false,
    + "logo": "https://raw.githubusercontent.com/pelotasplus/pidgin-icb/master/icb_48.png",
    + "maintainer": "pelotasplus",
    + "type": "Protocol",
    + "info": "ICB",
    + "repo": "https://github.com/pelotasplus/pidgin-icb/"
    + },
    + {
    + "heading": "JRC",
    + "isFirstParty": false,
    + "maintainer": "telyn",
    + "type": "Protocol",
    + "info": "libpurple implementation of a JRChat client",
    + "repo": "https://github.com/telyn/prpl-jrc/"
    + },
    + {
    + "heading": "LINE",
    + "isFirstParty": false,
    + "logo": "http://altrepo.eu/uploads/project/avatar/4/purple-line.png",
    + "maintainer": "Naver",
    + "type": "Protocol",
    + "info": "Mobile SMS replacement",
    + "repo": "http://altrepo.eu/git/purple-line/"
    + },
    + {
    + "heading": "Mail.ru Agent (mrim-prpl)",
    + "isFirstParty": false,
    + "logo": "https://bitbucket.org/mrim-prpl-team/mrim-prpl/raw/4e5df9df3912d37e66959dbaec0eb6f278e5a108/pixmaps/mrim48.png",
    + "maintainer": "mrim-prpl-team",
    + "type": "Protocol",
    + "info": "Russian network",
    + "repo": "https://bitbucket.org/mrim-prpl-team/mrim-prpl/src/master/"
    + },
    + {
    + "heading": "Mail.ru Agent (pidgin-mra)",
    + "isFirstParty": false,
    + "logo": "https://raw.githubusercontent.com/dreadatour/pidgin-mra/master/img/mra48.png",
    + "maintainer": "dreadatour",
    + "type": "Protocol",
    + "info": "Russian network",
    + "repo": "https://github.com/dreadatour/pidgin-mra/"
    + },
    + {
    + "heading": "Matrix",
    + "isFirstParty": false,
    + "logo": "https://raw.githubusercontent.com/matrix-org/purple-matrix/master/matrix-48px.png",
    + "maintainer": "matrix-org",
    + "type": "Protocol",
    + "info": "Distributed IM",
    + "repo": "https://github.com/matrix-org/purple-matrix#readme/"
    },
    {
    "heading": "Mattermost",
    - "logo": "https://github.com/EionRobb/purple-mattermost/raw/master/mattermost48.png",
    + "isFirstParty": false,
    + "logo": "https://raw.githubusercontent.com/EionRobb/purple-mattermost/master/mattermost48.png",
    "maintainer": "EionRobb",
    "type": "Protocol",
    - "info": "Supports [Mattermost](https://about.mattermost.com/) to libpurple based clients like Pidgin.",
    - "repo": "https://github.com/EionRobb/purple-mattermost#readme"
    + "info": "Open-source replacement for Slack",
    + "repo": "https://github.com/EionRobb/purple-mattermost/"
    + },
    + {
    + "heading": "Microblog",
    + "isFirstParty": false,
    + "maintainer": "fr0nk",
    + "type": "Protocol",
    + "info": "Twitter/Identica/Laconica updates",
    + "repo": "https://github.com/fr0nk/microblog-purple2/"
    + },
    + {
    + "heading": "msn-pecan",
    + "isFirstParty": false,
    + "maintainer": "felipec",
    + "type": "Protocol",
    + "info": "Alternative MSN access",
    + "repo": "https://github.com/felipec/msn-pecan/"
    + },
    + {
    + "heading": "Mumble",
    + "isFirstParty": false,
    + "maintainer": "petteripitkanen",
    + "type": "Protocol",
    + "info": "Gaming voice chat",
    + "repo": "https://bitbucket.org/petteripitkanen/purple-mumble/"
    + },
    + {
    + "heading": "NateOn",
    + "isFirstParty": false,
    + "maintainer": "kaisyu",
    + "type": "Protocol",
    + "info": "Korean network",
    + "repo": "https://github.com/kaisyu/pidgin-nateon/"
    },
    {
    "heading": "NetNexus",
    + "isFirstParty": false,
    "maintainer": "EionRobb",
    "type": "Protocol",
    - "info": "Supports [NetNexus](http://www.netnexus.com/) to libpurple based clients like Pidgin.",
    - "repo": "https://github.com/EionRobb/netnexus-pidgin"
    + "info": "netnexus.com's chatrooms",
    + "repo": "https://github.com/EionRobb/netnexus-pidgin/"
    + },
    + {
    + "heading": "Netsoul",
    + "isFirstParty": false,
    + "logo": "https://raw.githubusercontent.com/wlallemand/netsoul-purple/master/pixmaps/48/netsoul.png",
    + "maintainer": "wlallemand",
    + "type": "Protocol",
    + "info": "French network",
    + "repo": "https://github.com/wlallemand/netsoul-purple/"
    },
    {
    "heading": "Ning",
    + "isFirstParty": false,
    "maintainer": "EionRobb",
    "type": "Protocol",
    - "info": "Supports [Ning](https://www.ning.com/) to libpurple based clients like Pidgin.",
    - "repo": "https://github.com/EionRobb/pidgin-ning"
    + "info": "Ning-based social networks",
    + "repo": "https://github.com/EionRobb/pidgin-ning/"
    },
    {
    "heading": "OkCupid",
    - "logo": "https://github.com/EionRobb/okcupid-pidgin/raw/master/icons/48/okcupid.png",
    + "isFirstParty": false,
    + "logo": "https://raw.githubusercontent.com/EionRobb/okcupid-pidgin/master/icons/48/okcupid.png",
    "maintainer": "EionRobb",
    "type": "Protocol",
    - "info": "Supports [OkCupid](https://www.okcupid.com/) to libpurple based clients like Pidgin.",
    - "repo": "https://github.com/EionRobb/okcupid-pidgin"
    + "info": "OKCupid dating website",
    + "repo": "https://github.com/EionRobb/okcupid-pidgin/"
    },
    {
    "heading": "Omegle",
    + "isFirstParty": false,
    "maintainer": "EionRobb",
    "type": "Protocol",
    - "info": "Supports [Omegle](http://www.omegle.com/) to libpurple based clients like Pidgin.",
    - "repo": "https://github.com/EionRobb/pidgin-omegle"
    + "info": "omegle.com's web-based random chat",
    + "repo": "https://github.com/EionRobb/pidgin-omegle/"
    + },
    + {
    + "heading": "Pidgin-Twitter",
    + "isFirstParty": false,
    + "maintainer": "honeyplanet",
    + "type": "Protocol",
    + "info": "Twitter plugin",
    + "repo": "http://www.honeyplanet.jp/pidgin-twitter/"
    + },
    + {
    + "heading": "PubNub",
    + "isFirstParty": false,
    + "logo": "https://raw.githubusercontent.com/pubnub/c/master/examples/libpurple/pubnub48.png",
    + "maintainer": "pubnub",
    + "type": "Protocol",
    + "info": "Real-time messaging system",
    + "repo": "https://github.com/pubnub/c/tree/master/examples/libpurple/"
    + },
    + {
    + "heading": "Pulse SMS",
    + "isFirstParty": false,
    + "logo": "https://raw.githubusercontent.com/EionRobb/purple-pulsesms/master/pulsesms48.png",
    + "maintainer": "EionRobb",
    + "type": "Protocol",
    + "info": "SMS messaging via your Android phone",
    + "repo": "https://github.com/EionRobb/purple-pulsesms/"
    + },
    + {
    + "heading": "purple-feed",
    + "isFirstParty": false,
    + "logo": "https://raw.githubusercontent.com/moraxy/libpurple-feed/master/feed48.png",
    + "maintainer": "moraxy",
    + "type": "Protocol",
    + "info": "RSS and Atom feed reader",
    + "repo": "https://github.com/moraxy/libpurple-feed/"
    },
    {
    "heading": "Pushbullet",
    - "logo": "https://github.com/EionRobb/pidgin-pushbullet/raw/master/icons/pushbullet48.png",
    + "isFirstParty": false,
    + "logo": "https://raw.githubusercontent.com/EionRobb/pidgin-pushbullet/master/icons/pushbullet48.png",
    "maintainer": "EionRobb",
    "type": "Protocol",
    - "info": "Supports [Pushbullet](https://www.pushbullet.com/) to libpurple based clients like Pidgin.",
    - "repo": "https://github.com/EionRobb/pidgin-pushbullet"
    + "info": "Send pushes and SMS (Android-only) via Pushbullet",
    + "repo": "https://github.com/EionRobb/pidgin-pushbullet/"
    + },
    + {
    + "heading": "QQ (libqq-pidgin)",
    + "isFirstParty": false,
    + "maintainer": "libqq-pidgin",
    + "type": "Protocol",
    + "info": "QQ protocol support",
    + "repo": "https://code.google.com/archive/p/libqq-pidgin/"
    + },
    + {
    + "heading": "QQ (pidgin-lwqq)",
    + "isFirstParty": false,
    + "logo": "https://raw.githubusercontent.com/xiehuc/pidgin-lwqq/master/res/48.png",
    + "maintainer": "xiehuc",
    + "type": "Protocol",
    + "info": "QQ protocol support (Based on WebQQ)",
    + "repo": "https://github.com/xiehuc/pidgin-lwqq/"
    + },
    + {
    + "heading": "Rediffbol",
    + "isFirstParty": false,
    + "maintainer": "Arnold Noronha",
    + "type": "Protocol",
    + "info": "Indian network",
    + "repo": "http://rediffbol-prpl.sourceforge.net/"
    },
    {
    "heading": "Rocket.Chat",
    - "logo": "https://bytebucket.org/EionRobb/purple-rocketchat/raw/fb8dcc6497825785afdb57582e08f96a078fb618/rocketchat48.png",
    + "isFirstParty": false,
    + "logo": "https://bitbucket-assetroot.s3.amazonaws.com/c/photos/2016/Oct/23/2899019825-5-purple-rocketchat-logo_avatar.png",
    "maintainer": "EionRobb",
    "type": "Protocol",
    - "info": "Supports [Rocket.Chat](https://rocket.chat) to libpurple based clients like Pidgin.",
    - "repo": "https://bitbucket.org/EionRobb/purple-rocketchat/overview"
    + "info": "Open-source replacement for Slack",
    + "repo": "https://bitbucket.org/EionRobb/purple-rocketchat/overview/"
    + },
    + {
    + "heading": "Signal",
    + "isFirstParty": false,
    + "maintainer": "hoehermann",
    + "type": "Protocol",
    + "info": "Secure mobile messaging",
    + "repo": "https://github.com/hoehermann/libpurple-signald/"
    },
    {
    "heading": "Skype",
    - "logo": "https://github.com/EionRobb/skype4pidgin/raw/master/skypeweb/icons/48/skype.png",
    + "isFirstParty": false,
    + "logo": "https://raw.githubusercontent.com/EionRobb/skype4pidgin/master/skypeweb/icons/48/skype.png",
    "maintainer": "EionRobb",
    "type": "Protocol",
    - "info": "Supports [Skype](https://www.skype.com) to libpurple based clients like Pidgin.",
    - "repo": "https://github.com/EionRobb/skype4pidgin/tree/master/skypeweb"
    + "info": "Skype IM protocol support",
    + "repo": "https://github.com/EionRobb/skype4pidgin/tree/master/skypeweb/"
    + },
    + {
    + "heading": "Slack",
    + "isFirstParty": false,
    + "logo": "https://raw.githubusercontent.com/dylex/slack-libpurple/master/img/slack48.png",
    + "maintainer": "dylex",
    + "type": "Protocol",
    + "info": "Team collaboration tool",
    + "repo": "https://github.com/dylex/slack-libpurple/"
    },
    {
    - "heading": "Steam Mobile",
    - "logo": "https://github.com/EionRobb/pidgin-opensteamworks/raw/master/steam-mobile/steam48.png",
    - "maintainer": "EionRobb",
    + "heading": "SIPE",
    + "isFirstParty": false,
    + "maintainer": "Stefan Becker",
    "type": "Protocol",
    - "info": "Supports [Steam](https://store.steampowered.com) to libpurple based clients like Pidgin.",
    - "repo": "https://github.com/EionRobb/pidgin-opensteamworks/tree/master/steam-mobile"
    + "info": "Microsoft Office Communicator, Reuters Messaging",
    + "repo": "http://sipe.sourceforge.net/"
    },
    {
    - "heading": "Yahoo! 2017",
    - "logo": "https://github.com/EionRobb/funyahoo-plusplus/raw/master/icons/48/yahoo.png",
    + "heading": "SMS",
    + "isFirstParty": false,
    + "logo": "https://source.puri.sm/Librem5/purple-mm-sms/raw/master/icons/mm-sms-48px.png",
    + "maintainer": "Librem5",
    + "type": "Protocol",
    + "info": "Purple SMS plugin using ModemManager",
    + "repo": "https://source.puri.sm/Librem5/purple-mm-sms/"
    + },
    + {
    + "heading": "Spinp",
    + "isFirstParty": false,
    + "maintainer": "farcdev",
    + "type": "Protocol",
    + "info": "Decentralised chat",
    + "repo": "https://github.com/farcdev/spinp/"
    + },
    + {
    + "heading": "Steam IM (mobile)",
    + "isFirstParty": false,
    + "logo": "https://raw.githubusercontent.com/EionRobb/pidgin-opensteamworks/master/steam-mobile/steam48.png",
    "maintainer": "EionRobb",
    "type": "Protocol",
    - "info": "Supports Yahoo! 2017 to libpurple based clients like Pidgin.",
    - "repo": "https://github.com/EionRobb/funyahoo-plusplus"
    + "info": "Steam Friends gaming network",
    + "repo": "https://github.com/EionRobb/pidgin-opensteamworks/tree/master/steam-mobile/"
    + },
    + {
    + "heading": "Steam IM (native)",
    + "isFirstParty": false,
    + "logo": "https://raw.githubusercontent.com/EionRobb/pidgin-opensteamworks/master/steam-mobile/steam48.png",
    + "maintainer": "seishun",
    + "type": "Protocol",
    + "info": "Steam Friends gaming network",
    + "repo": "https://github.com/seishun/SteamPP#steampurple/"
    + },
    + {
    + "heading": "Telegram",
    + "isFirstParty": false,
    + "logo": "https://raw.githubusercontent.com/majn/telegram-purple/master/imgs/telegram48.png",
    + "maintainer": "majn",
    + "type": "Protocol",
    + "info": "Secure messenger",
    + "repo": "https://github.com/majn/telegram-purple#readme/"
    + },
    + {
    + "heading": "Threema",
    + "isFirstParty": false,
    + "maintainer": "hbruintjes",
    + "type": "Protocol",
    + "info": "Threema",
    + "repo": "https://github.com/hbruintjes/ceema/"
    },
    {
    - "heading": "Capsnot",
    - "maintainer": "EionRobb",
    - "type": "Notification",
    - "info": "Informs for new messages with the NumLock, CapsLock or ScrollLock LEDs.",
    - "repo": "https://github.com/EionRobb/pidgin-capsnot"
    + "heading": "TorChat",
    + "isFirstParty": false,
    + "maintainer": "prof7bit",
    + "type": "Protocol",
    + "info": "p2p instant messaging through Tor hidden service tunnels",
    + "repo": "https://github.com/prof7bit/TorChat/downloads/"
    + },
    + {
    + "heading": "Trillian (IMPP)",
    + "isFirstParty": false,
    + "maintainer": "Hi-Angel",
    + "type": "Protocol",
    + "info": "Trillian Astra protocol",
    + "repo": "https://github.com/Hi-Angel/purple-impp/"
    + },
    + {
    + "heading": "Twitter Protocol",
    + "isFirstParty": false,
    + "logo": "https://raw.githubusercontent.com/mikeage/prpltwtr/twitter-json/data/48/prpltwtr.png",
    + "maintainer": "mikeage",
    + "type": "Protocol",
    + "info": "Access Twitter (and status.net / identi.ca) feeds like chat rooms",
    + "repo": "https://github.com/mikeage/prpltwtr/"
    + },
    + {
    + "heading": "Wechat",
    + "isFirstParty": false,
    + "maintainer": "sbwtw",
    + "type": "Protocol",
    + "info": "Wechat Protocol Support",
    + "repo": "https://github.com/sbwtw/pidgin-wechat/"
    + },
    + {
    + "heading": "WhatsApp",
    + "isFirstParty": false,
    + "logo": "https://raw.githubusercontent.com/davidgfnet/whatsapp-purple/master/whatsapp48.png",
    + "maintainer": "davidgfnet",
    + "type": "Protocol",
    + "info": "WhatsApp IM protocol",
    + "repo": "https://github.com/davidgfnet/whatsapp-purple/"
    },
    {
    - "heading": "Ignore Nick Change",
    + "heading": "WhatsApp (purple-gowhatsapp)",
    + "isFirstParty": false,
    + "maintainer": "hoehermann",
    + "type": "Protocol",
    + "info": "WhatsApp IM protocol",
    + "repo": "https://github.com/hoehermann/purple-gowhatsapp/"
    + },
    + {
    + "heading": "WinMX Peer Network",
    + "isFirstParty": false,
    + "maintainer": "ranma42",
    + "type": "Protocol",
    + "info": "File sharing network",
    + "repo": "https://sourceforge.net/projects/wpn-gaim-prpl/"
    + },
    + {
    + "heading": "Yahoo",
    + "isFirstParty": false,
    + "logo": "https://raw.githubusercontent.com/EionRobb/funyahoo-plusplus/master/icons/48/yahoo.png",
    "maintainer": "EionRobb",
    - "type": "Interface Tweaks",
    - "info": "This plugin hides name change messages in large rooms, except for those users actively taking part in a conversation.",
    - "repo": "https://github.com/EionRobb/pidgin-ignore-nickchange"
    + "type": "Protocol",
    + "info": "Replacement plugin for Yahoo 2016",
    + "repo": "https://github.com/EionRobb/funyahoo-plusplus/"
    + },
    + {
    + "heading": "Authorization Blocker",
    + "isFirstParty": false,
    + "maintainer": "kgraefe",
    + "type": "Security/Privacy",
    + "info": "The plugin blocks the first authorization request of a contact and answers with the order to ask for authorization again. This helps to prevent spam on ICQ accounts.",
    + "repo": "https://launchpad.net/pidgin-authorization-blocker/"
    },
    {
    - "heading": "Media Emblems",
    - "maintainer": "EionRobb",
    - "type": "Interface Tweaks",
    - "info": "Adds emblems to the buddy list to show if a user supports Voice or Video calls.",
    - "repo": "https://github.com/EionRobb/pidgin-media-emblems"
    + "heading": "bOt_tOOls",
    + "isFirstParty": false,
    + "maintainer": "Eric Dziewa",
    + "type": "Security/Privacy",
    + "info": "Configurable plugin for auto-ignoring yahoo spammers",
    + "repo": "http://eric.dziewa.com/?p=522"
    + },
    + {
    + "heading": "Bot Sentry",
    + "isFirstParty": false,
    + "maintainer": "deckrider",
    + "type": "Security/Privacy",
    + "info": "Stop spam bots",
    + "repo": "https://sourceforge.net/projects/pidgin-bs/"
    + },
    + {
    + "heading": "IM of Trust",
    + "isFirstParty": false,
    + "maintainer": "kgraefe",
    + "type": "Security/Privacy",
    + "info": "Pidgin IM of Trust blocks authorization requests based on online lists",
    + "repo": "https://launchpad.net/pidgin-imot/"
    + },
    + {
    + "heading": "lurch",
    + "isFirstParty": false,
    + "maintainer": "gkdr",
    + "type": "Security/Privacy",
    + "info": "Encrypts XMPP conversations using OMEMO",
    + "repo": "https://github.com/gkdr/lurch/"
    + },
    + {
    + "heading": "Off-the-Record Messaging (OTR)",
    + "isFirstParty": false,
    + "maintainer": "OTR Development Team",
    + "type": "Security/Privacy",
    + "info": "Encrypts conversations and provides security even when keys are compromised",
    + "repo": "https://otr.cypherpunks.ca/"
    + },
    + {
    + "heading": "Pidgin-Encryption",
    + "isFirstParty": false,
    + "maintainer": "obobo",
    + "type": "Security/Privacy",
    + "info": "Encrypts conversations using stored RSA keys",
    + "repo": "http://pidgin-encrypt.sourceforge.net/"
    },
    {
    - "heading": "Pidgin Group Chat Typing Notifications",
    - "maintainer": "EionRobb",
    - "type": "Interface Tweaks",
    - "info": "Display typing notifications of users in a compatible multi-user chat.",
    - "repo": "https://github.com/EionRobb/pidgin-groupchat-typing-notifications"
    + "heading": "pidgin-gnome-keyring",
    + "isFirstParty": false,
    + "maintainer": "aebrahim",
    + "type": "Security/Privacy",
    + "info": "Stores account passwords in the system keyring instead of as plaintext",
    + "repo": "https://github.com/aebrahim/pidgin-gnome-keyring/"
    + },
    + {
    + "heading": "Pidgin-GPG",
    + "isFirstParty": false,
    + "maintainer": "Alex Segler",
    + "type": "Security/Privacy",
    + "info": "Pidgin GPG/OPENPGP (XEP-0027) Plugin",
    + "repo": "https://github.com/segler-alex/Pidgin-GPG/wiki/"
    + },
    + {
    + "heading": "Pidgin-Paranoia",
    + "isFirstParty": false,
    + "maintainer": "boognu, nowic",
    + "type": "Security/Privacy",
    + "info": "Encrypts conversations using one-time pads",
    + "repo": "http://pidgin-paranoia.sourceforge.net/"
    + },
    + {
    + "heading": "Pidgin-privacy-please",
    + "isFirstParty": false,
    + "maintainer": "cockroach",
    + "type": "Security/Privacy",
    + "info": "Stop spam bots",
    + "repo": "http://freshmeat.sourceforge.net/projects/pidgin-pp/"
    + },
    + {
    + "heading": "pidgin-wincred",
    + "isFirstParty": false,
    + "maintainer": "aebrahim",
    + "type": "Security/Privacy",
    + "info": "Save passwords as windows credentials instead of as plaintext",
    + "repo": "https://github.com/aebrahim/pidgin-wincred/"
    },
    {
    - "heading": "Protocol Icon Override",
    - "maintainer": "EionRobb",
    - "type": "Interface Tweaks",
    - "info": "Lets you pick the protocol icon to display per-account.",
    - "repo": "https://github.com/EionRobb/pidgin-icon-override"
    + "heading": "Audible Alerts",
    + "isFirstParty": false,
    + "maintainer": "meiser024",
    + "type": "Notifications",
    + "info": "Audible notification of a received IM by reading the buddy's screen name",
    + "repo": "https://sourceforge.net/projects/audiblealerts/"
    + },
    + {
    + "heading": "Bluetooth Notifier",
    + "isFirstParty": false,
    + "maintainer": "holthuis",
    + "type": "Notifications",
    + "info": "Sends new chat messages directly to your cell phone or any other Bluetooth-enabled device",
    + "repo": "https://code.google.com/archive/p/pidgin-bt/"
    + },
    + {
    + "heading": "Chatpop",
    + "isFirstParty": false,
    + "maintainer": "teleshoes",
    + "type": "Notifications",
    + "info": "Show open chats when receiving a persistent chat message",
    + "repo": "https://github.com/teleshoes/chatpop-pidgin/"
    },
    {
    - "heading": "Windows 7 Taskbar",
    - "maintainer": "EionRobb",
    - "type": "Interface Tweaks",
    - "info": "Adds new Windows 7 eye-candy such as task bar menu, progress and emblems",
    - "repo": "https://github.com/EionRobb/pidgin-win7#readme"
    + "heading": "Command-execute",
    + "isFirstParty": false,
    + "maintainer": "tymm",
    + "type": "Notifications",
    + "info": "Executes a command on a new message and works for both Pidgin and Finch",
    + "repo": "https://github.com/tymm/command-execute/"
    + },
    + {
    + "heading": "Command-notification",
    + "isFirstParty": false,
    + "maintainer": "GuySoft",
    + "type": "Notifications",
    + "info": "Based off Led-notification this plugin will execute a command on receiving a new message ",
    + "repo": "https://guysoft.wordpress.com/2010/02/14/pidgin-x-chat-plugin-new-message/"
    + },
    + {
    + "heading": "pidgin-im-gnome-shell-extension",
    + "isFirstParty": false,
    + "maintainer": "muffinmad",
    + "type": "Notifications",
    + "info": "Make Pidgin IM conversations appear in the Gnome Shell message tray",
    + "repo": "https://github.com/muffinmad/pidgin-im-gnome-shell-extension#readme/"
    + },
    + {
    + "heading": "Guifications",
    + "isFirstParty": false,
    + "maintainer": "Gary Kramlich",
    + "type": "Notifications",
    + "info": "Provides toaster popup notifications",
    + "repo": "https://bitbucket.org/rw_grim/guifications2/"
    },
    {
    - "heading": "Windows Smooth Scrolling",
    - "maintainer": "EionRobb",
    - "type": "Interface Tweaks",
    - "info": "Gives more precise scrolling control eg with trackpads.",
    - "repo": "https://github.com/EionRobb/pidgin-windows-smooth-scrolling/releases"
    + "heading": "IM Pusher",
    + "isFirstParty": false,
    + "maintainer": "coolwanglu",
    + "type": "Notifications",
    + "info": "An extension of Notifo Notifications, pushes your messages at specified statuses (e.g. when you are away), two push services (notifo & pushme.to) are supported",
    + "repo": "https://github.com/coolwanglu/pidgin-im-pusher/"
    + },
    + {
    + "heading": "Keyboard LED Notification",
    + "isFirstParty": false,
    + "maintainer": "Gabriel Cséfalvay",
    + "type": "Notifications",
    + "info": "LegLedNot is a keyboard LED notification plugin for Pidgin",
    + "repo": "https://sites.google.com/site/pidginlednotification/"
    },
    {
    - "heading": "Pidgin Juice",
    - "maintainer": "EionRobb",
    - "type": "Accounts and Logs",
    - "info": "Web-based iPhone interface for Pidgin/Finch.",
    - "repo": "https://github.com/EionRobb/pidgin-juice"
    + "heading": "KNotifications",
    + "isFirstParty": false,
    + "maintainer": "mrovi",
    + "type": "Notifications",
    + "info": "Perl plugin that provides KDE 4 notifications",
    + "repo": "https://code.google.com/archive/p/pidgin-knotifications/"
    + },
    + {
    + "heading": "Led-notification",
    + "isFirstParty": false,
    + "maintainer": "Simo Mattila",
    + "type": "Notifications",
    + "info": "Provides notifications with laptops' extra LEDs and similar",
    + "repo": "https://sites.google.com/site/simohmattila/led-notification/"
    + },
    + {
    + "heading": "led-notification",
    + "isFirstParty": false,
    + "maintainer": "Sitwon",
    + "type": "Notifications",
    + "info": "Fork of Led-notification. Adds support for ThinkPads",
    + "repo": "https://github.com/Sitwon/led-notification/"
    + },
    + {
    + "heading": "MX610-notification",
    + "isFirstParty": false,
    + "maintainer": "Simo Mattila",
    + "type": "Notifications",
    + "info": "Provides notifications with Logitech MX610's IM led",
    + "repo": "https://sites.google.com/site/simohmattila/mx610-notification/"
    },
    {
    - "heading": "SQLite Logger",
    + "heading": "pidgin-capsnot",
    + "isFirstParty": false,
    "maintainer": "EionRobb",
    - "type": "Accounts and Logs",
    - "info": "IM/Chat logger with a SQLite backend.",
    - "repo": "https://github.com/EionRobb/pidgin-sqlite-log/tree/master"
    + "type": "Notifications",
    + "info": "Keyboard LED Notification (caps-lock/num-lock/scroll-lock) for Pidgin/Finch",
    + "repo": "https://github.com/EionRobb/pidgin-capsnot/"
    + },
    + {
    + "heading": "Pidgin-dock",
    + "isFirstParty": false,
    + "maintainer": "Sergey Klimov",
    + "type": "Notifications",
    + "info": "Emulate Mac OS X - dock behaviour with cairo-dock",
    + "repo": "https://code.google.com/archive/p/pidgin-cairo-dock/"
    + },
    + {
    + "heading": "Pidgin Advanced Sound Notification",
    + "isFirstParty": false,
    + "maintainer": "kgraefe",
    + "type": "Notifications",
    + "info": "This plugin adds sounds for some notifications to pidgin (Incoming file transfer, Authentication requested, etc.)",
    + "repo": "https://launchpad.net/pidgin-advanced-sound-notification/"
    },
    {
    - "heading": "Auto Translate",
    - "maintainer": "EionRobb",
    - "type": "Miscellaneous",
    - "info": "Auto translates incoming IMs.",
    - "repo": "https://github.com/EionRobb/purple-translate"
    + "heading": "PidginSnarl",
    + "isFirstParty": false,
    + "maintainer": "sven",
    + "type": "Notifications",
    + "info": "Notifications using Snarl on Windows",
    + "repo": "tlhan-ghun.de/Projects/PidginSnarl/"
    + },
    + {
    + "heading": "purple-libnotify+",
    + "isFirstParty": false,
    + "maintainer": "sardemff7",
    + "type": "Notifications",
    + "info": "Provides libnotify notifications",
    + "repo": "https://github.com/sardemff7/purple-libnotify-plus#purple-libnotify/"
    },
    {
    - "heading": "No IRC /who",
    - "maintainer": "EionRobb",
    - "type": "Miscellaneous",
    - "info": "Removes the periodic /who check from the IRC protocol, to stop flooding, slowdowns and \"Max sendq exceeded\" errors.",
    - "repo": "https://github.com/EionRobb/pidgin-no-irc-who"
    + "heading": "Smart Ear",
    + "isFirstParty": false,
    + "maintainer": "Matt Perry",
    + "type": "Notifications",
    + "info": "Customized per-buddy sound events",
    + "repo": "http://somewhere.fscked.org/proj/smartear/"
    + },
    + {
    + "heading": "Windows 8 Toast Notifications",
    + "isFirstParty": false,
    + "maintainer": "Adrian Keenan",
    + "type": "Notifications",
    + "info": "Native win8 toast notifications",
    + "repo": "https://github.com/adriankeenan/pidgin-toast-8/"
    + },
    + {
    + "heading": "Windows Toast Notifications",
    + "isFirstParty": false,
    + "maintainer": "Christian Galla",
    + "type": "Notifications",
    + "info": "Shows notifications when receiving messages, in the standard Windows design",
    + "repo": "https://github.com/ChristianGalla/PidginWinToastNotifications/"
    },
    {
    "heading": "XMPP Ignore Groups",
    + "isFirstParty": false,
    "maintainer": "EionRobb",
    "type": "Miscellaneous",
    - "info": "Ignores server-sent XMPP groups so that you can move buddies around on annoying servers (e.g. Facebook).",
    + "info": "Ignores server-sent XMPP groups so that you can move buddies around on annoying servers (e.g. Facebook)",
    "repo": "https://github.com/EionRobb/pidgin-xmpp-ignore-groups"
    }
    ]
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/hugo/data/supporters.json Thu May 16 22:10:20 2019 -0400
    @@ -0,0 +1,12 @@
    +[
    + {
    + "url": "https://sourceforge.net",
    + "badge": "Sourceforge_logo.png"
    + }, {
    + "url": "https://networkredux.com/",
    + "badge": "networkredux.png"
    + }, {
    + "url": "https://packagecloud.io/",
    + "badge": "packagecloud.png"
    + }
    +]
    \ No newline at end of file
    --- a/hugo/i18n/en.toml Mon Feb 11 12:43:24 2019 -0500
    +++ b/hugo/i18n/en.toml Thu May 16 22:10:20 2019 -0400
    @@ -30,3 +30,18 @@
    [Repo]
    other = "Repo"
    +
    +[Trusted]
    +other = "Trusted"
    +
    +[Trusted-Info]
    +other = "What makes an author trusted you ask? Basically they've been working with us for a long time and they put out some great software!"
    +
    +[Community]
    +other = "Community"
    +
    +[Community-Info]
    +other = "Created by the pidgin communtiy"
    +
    +[Plugin-Info]
    +other = "This page contains a list of plugins from trusted authors and the community. If you believe a plugin should be on this list, please get in touch with us or open a pull request with the update."
    --- a/hugo/layouts/partials/footline.html Mon Feb 11 12:43:24 2019 -0500
    +++ b/hugo/layouts/partials/footline.html Thu May 16 22:10:20 2019 -0400
    @@ -1,6 +1,6 @@
    -<footer class=" footline" >
    +<footer class="footline" >
    <hr>
    -
    +
    {{ with .Params.LastModifierDisplayName }}
    <i class='fas fa-user'></i> <a href="mailto:{{ $.Params.LastModifierEmail }}">{{ . }}</a> {{ with $.Date }} <i class='fas fa-calendar'></i> {{ .Format "02/01/2006" }}{{ end }}
    </div>
    --- a/hugo/layouts/partials/supporters.html Mon Feb 11 12:43:24 2019 -0500
    +++ b/hugo/layouts/partials/supporters.html Thu May 16 22:10:20 2019 -0400
    @@ -1,8 +1,8 @@
    <section class="supporters">
    <b>{{ T "Our-Supporters" }}</b>
    <div>
    - {{ range (readDir "./static/images/badges") }}
    - <a> <img src="/images/badges/{{ .Name }}" /> </a> {{ end }}
    + {{ range .Site.Data.supporters }}
    + <a href="{{ .url | safeHTMLAttr }}"> <img src="/images/badges/{{ .badge }}" /> </a> {{ end }}
    </div>
    </section>
    --- a/hugo/layouts/shortcodes/plugintable.html Mon Feb 11 12:43:24 2019 -0500
    +++ b/hugo/layouts/shortcodes/plugintable.html Thu May 16 22:10:20 2019 -0400
    @@ -1,5 +1,48 @@
    +{{/*** Templates ***/}}
    +{{ define "trusted" }}
    + <span aria-label="{{ T "Trusted" }}" class="tooltipped tooltipped-s">
    + <i class="fas fa-check-circle " style="color:#784a85"></i>
    + </span>
    +{{ end }}
    +{{ define "community" }}
    + <span aria-label="{{ T "Community" }}" class="tooltipped tooltipped-s">
    + <i class="fas fa-users" style="color:green"></i>
    + </span>
    +{{ end }}
    +
    +{{/*** Content ***/}}
    +<p>
    + {{ T "Plugin-Info" }}
    +</p>
    +
    +<ul>
    + <li>{{ template "trusted" }} {{ T "Trusted-Info" }}</li>
    + <li>{{ template "community" }} {{ T "Community-Info" }}</li>
    +</ul>
    +
    <div id="plugin-filters">
    + <div id="publisher-selector">
    + <label style="display: inline-block;">
    + <input type="radio" id="all" name="publisher" style="margin-right: 0; margin-left: 0.75rem;" value="all" checked>
    + All
    + </label>
    +
    + <label style="display: inline-block;">
    + <input type="radio" id="pidgin" name="publisher" style="margin-right: 0; margin-left: 0.75rem;" value="pidgin">
    + {{ template "trusted" }}
    + {{ T "Trusted" }}
    + </label>
    +
    + <label style="display: inline-block;">
    + <input type="radio" id="community" name="publisher" style="margin-right: 0; margin-left: 0.75rem;"
    + value="community">
    + {{ template "community" }}
    + {{ T "Community" }}
    + </label>
    + </div>
    +
    <input type="text" id="plugin-filter-search" placeholder="{{ T "Search-placeholder" }}" />
    +
    <div id="protocol-selector"></div>
    </div>
    @@ -13,18 +56,28 @@
    {{ T "Repo" }}
    </th>
    </thead>
    +
    <tbody>
    {{ range .Site.Data.plugins }}
    - <tr data-type="{{ .type }}">
    + <tr data-type="{{ .type }}" {{ if .isTrusted }}isTrusted="true"{{ end }}>
    <td>
    - <img src="{{ .logo }}" />
    + {{ if .logo }}<img src="{{ .logo }}" />{{ else }}&nbsp;{{ end }}
    </td>
    +
    <td class="pulgin-heading">
    {{ .heading }}
    </td>
    +
    <td class="pulgin-info">
    + {{ if .isTrusted }}
    + {{ template "trusted" }}
    + {{ else }}
    + {{ template "community" }}
    + {{ end }}
    +
    <b>{{ .type }}</b> {{ .info | markdownify }}
    </td>
    +
    <td class="pulgin-repo">
    <a href="{{ .repo }}">{{ .maintainer }}</a>
    </td>
    @@ -38,10 +91,8 @@
    const selectorsContainer = document.getElementById("protocol-selector");
    const search = document.getElementById("plugin-filter-search");
    search.addEventListener("input", debounce(1000 * 0.5, filterRows));
    - const [, ...rows] = (
    - document.getElementById("protocol-table")
    - .getElementsByTagName("tr")
    - );
    + const [, ...rows] =
    + document.getElementById("protocol-table").getElementsByTagName("tr");
    const types = {};
    const typeFilter = new Set();
    const rowinfo = rows.map(elem => {
    @@ -57,9 +108,13 @@
    head: getContents("pulgin-heading", elem),
    info: getContents("pulgin-info", elem),
    repo: getContents("pulgin-repo", elem),
    + isTrusted: elem.getAttribute('isTrusted') == 'true'
    }
    })
    + document.getElementById("publisher-selector")
    + .addEventListener('click', filterRows)
    +
    Object.keys(types).forEach(type => {
    const label = createAndAppend("label", selectorsContainer);
    label.classList.add('pidgin-plugin-filter-checkbox')
    @@ -72,7 +127,7 @@
    /////////////////////////
    - function getContents(className, elem = document){
    + function getContents(className, elem){
    return (
    elem.getElementsByClassName(className)[0]
    .textContent.toLowerCase()
    @@ -84,21 +139,30 @@
    filterRows();
    }
    + const publisherRadioQuery = 'input[name="publisher"]:checked'
    +
    function filterRows() {
    const str = (search.value || "").toLowerCase()
    + const publisherSelector = document.querySelector(publisherRadioQuery).value;
    rowinfo.forEach((row) => {
    - if (shouldFilter(row, str))
    + if (shouldFilter(row, publisherSelector, str))
    row.elem.classList.remove("filter-hide");
    else
    row.elem.classList.add("filter-hide");
    });
    }
    - function shouldFilter(row, str) {
    + function shouldFilter(row, publisher, str) {
    return (
    // Checkboxes
    (!typeFilter.size || typeFilter.has(row.elem.dataset.type))
    + // Provider
    + && (
    + publisher == 'all'
    + || (publisher == 'pidgin' && row.isTrusted)
    + || (publisher == 'community' && !row.isTrusted)
    + )
    // Search box
    && (
    !str
    --- a/hugo/static/css/custom.css Mon Feb 11 12:43:24 2019 -0500
    +++ b/hugo/static/css/custom.css Thu May 16 22:10:20 2019 -0400
    @@ -19,9 +19,32 @@
    border-radius: 25px;
    color: rgb(0, 0, 0) !important;
    background: #fff;
    - padding: 10px;
    - width: 200px;
    + padding: 10px;
    + width: 100%;
    text-align: center;
    font-weight: bolder;
    font-size: 20px;
    }
    +
    +#body-inner li p {
    + /* This is to fix the unwanted p-tags that blackfriday adds */
    + margin-block-start: 0;
    + margin-block-end: 0;
    +}
    +
    +#body-inner li pre {
    + margin: 1rem 0;
    +}
    +
    +#body-inner li {
    + margin-block-start: 0.3rem;
    + margin-block-end: 0.3rem;
    +}
    +
    +nav#TableOfContents code {
    + /* Make titles with code snippets look nicer */
    + white-space: nowrap;
    + color: #8451a1;
    + background: #e2e2fd;
    + padding: 0px 2px;
    +}
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/hugo/static/oauth.html Thu May 16 22:10:20 2019 -0400
    @@ -0,0 +1,159 @@
    +<!DOCTYPE html>
    +<html>
    + <head>
    + <title>libpurple oauth helper</title>
    +
    + <meta charset="utf-8" />
    + <meta name="viewport" content="width=device-width, initial-scale=1" />
    + <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
    +
    + <script
    + src="https://code.jquery.com/jquery-3.2.1.min.js"
    + integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4="
    + crossorigin="anonymous"
    + ></script>
    + <link
    + href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css"
    + rel="stylesheet"
    + integrity="sha384-wvfXpqpZZVQGK6TAh5PVlGOfQNHSoD2xbE+QkPxCAFlNEevoEH3Sl0sibVcOQVnN"
    + crossorigin="anonymous"
    + />
    + <link
    + rel="stylesheet"
    + href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"
    + integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u"
    + crossorigin="anonymous"
    + />
    + <script
    + src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"
    + integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa"
    + crossorigin="anonymous"
    + ></script>
    +
    + <style>
    + body {
    + margin-top: 1em;
    + }
    + .blur {
    + filter: blur(3px);
    + }
    + </style>
    + </head>
    + <body>
    + <div class="container">
    + <div class="col-sm-8 col-sm-offset-2">
    + <div class="row">
    + <img
    + src="/images/pidgin-circle-256.png"
    + class="img-responsive center-block"
    + />
    + </div>
    +
    + <div class="row">
    + <div class="panel panel-info">
    + <div class="panel-heading">About</div>
    + <div class="panel-body">
    + This page helps you to login your accounts that
    + require oauth authentication. Due to the way
    + OAuth2's implicit flow works, we do not have access
    + to, nor do we store, this access token.
    + </div>
    + </div>
    + </div>
    +
    + <div class="row">
    + <div class="panel panel-success">
    + <div class="panel-heading">Usage</div>
    + <div class="panel-body">
    + To use this page, click the copy button next to the
    + access token and paste it into the password entry
    + for the pidgin account you just enabled.
    + </div>
    + </div>
    + </div>
    +
    + <div class="row">
    + <div class="alert alert-warning" role="alert">
    + <strong>Warning!</strong> This access code is used to
    + access your account. Do not share it with anyone!
    + </div>
    + </div>
    +
    + <div class="row">
    + <div class="input-group">
    + <span class="input-group-btn">
    + <button
    + class="btn btn-secondary"
    + type="button"
    + id="access_token_toggle"
    + onclick="toggleAccessToken()"
    + >
    + Show
    + </button>
    + </span>
    + <input
    + type="text"
    + class="blur form-control"
    + id="access_token"
    + />
    + <span class="input-group-btn">
    + <button
    + type="button"
    + class="btn btn-default"
    + aria-label="Copy to clipboard"
    + onclick="copyToClipboard();"
    + >
    + <span
    + class="glyphicon glyphicon-copy"
    + aria-hidden="true"
    + ></span>
    + </button>
    + </span>
    + </div>
    + </div>
    + </div>
    + </div>
    + <script type="text/javascript">
    + $(document).ready(function() {
    + // set the input box's value to the value of access_token in window.location.hash
    + var data = window.location.hash.slice(1);
    + var vars = data.split("&");
    + for (var i = 0; i < vars.length; i++) {
    + var parts = vars[i].split("=");
    + if (parts[0] == "access_token") {
    + // remove the hash from the url so we don't leak it.
    + window.location.hash = "";
    +
    + // update the input box with the access token
    + var element = $("#access_token");
    + element.val(parts[1]);
    + element.select();
    +
    + // stop processing
    + break;
    + }
    + }
    + });
    +
    + function copyToClipboard(e) {
    + $("#access_token").select();
    + document.execCommand("copy");
    + }
    +
    + function toggleAccessToken() {
    + var toggle = $("#access_token_toggle");
    + var token = $("#access_token");
    +
    + if (toggle.text() == "Show") {
    + toggle.text("Hide");
    + token.removeClass("blur");
    + } else {
    + toggle.text("Show");
    + token.addClass("blur");
    + }
    +
    + token.select();
    + }
    + </script>
    + </body>
    +</html>
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/hugo/themes/learn/i18n/nl.toml Thu May 16 22:10:20 2019 -0400
    @@ -0,0 +1,26 @@
    +[Search-placeholder]
    +other = "Zoeken..."
    +
    +[Clear-History]
    +other = "Wis geschiedenis"
    +
    +[Attachments-label]
    +other = "Bijlagen"
    +
    +[title-404]
    +other = "Error"
    +
    +[message-404]
    +other = "Blijkbaar bestaat deze pagina niet ¯\\_(ツ)_/¯."
    +
    +[Go-to-homepage]
    +other = "Naar startpagina"
    +
    +[Edit-this-page]
    +other = "Deze pagina bewerken"
    +
    +[Shortcuts-Title]
    +other = "Snelkoppelingen"
    +
    +[Expand-title]
    +other = "Lees meer..."
    --- a/hugo/themes/learn/layouts/404.html Mon Feb 11 12:43:24 2019 -0500
    +++ b/hugo/themes/learn/layouts/404.html Thu May 16 22:10:20 2019 -0400
    @@ -18,7 +18,6 @@
    <link href="{{ "css/nucleus.css" | relURL }}{{ if $assetBusting }}?{{ now.Unix }}{{ end }}" rel="stylesheet">
    <link href="{{ "css/fontawesome-all.min.css" | relURL }}{{ if $assetBusting }}?{{ now.Unix }}{{ end }}" rel="stylesheet">
    <link href="{{ "css/hybrid.css" | relURL }}{{ if $assetBusting }}?{{ now.Unix }}{{ end }}" rel="stylesheet">
    - <link href="{{ "css/featherlight.min.css" | relURL }}{{ if $assetBusting }}?{{ now.Unix }}{{ end }}" rel="stylesheet">
    <link href="{{ "css/perfect-scrollbar.min.css" | relURL }}{{ if $assetBusting }}?{{ now.Unix }}{{ end }}" rel="stylesheet">
    <link href="{{ "css/horsey.css" | relURL }}{{ if $assetBusting }}?{{ now.Unix }}{{ end }}" rel="stylesheet">
    <link href="{{ "css/theme.css" | relURL }}{{ if $assetBusting }}?{{ now.Unix }}{{ end }}" rel="stylesheet">
    --- a/hugo/themes/learn/layouts/partials/footer.html Mon Feb 11 12:43:24 2019 -0500
    +++ b/hugo/themes/learn/layouts/partials/footer.html Thu May 16 22:10:20 2019 -0400
    @@ -61,7 +61,6 @@
    <script src="{{ "js/perfect-scrollbar.min.js" | relURL }}{{ if not .Site.Params.disableAssetsBusting }}?{{ now.Unix }}{{ end }}"></script>
    <script src="{{ "js/perfect-scrollbar.jquery.min.js" | relURL }}{{ if not .Site.Params.disableAssetsBusting }}?{{ now.Unix }}{{ end }}"></script>
    <script src="{{ "js/jquery.sticky.js" | relURL }}{{ if not .Site.Params.disableAssetsBusting }}?{{ now.Unix }}{{ end }}"></script>
    - <script src="{{ "js/featherlight.min.js" | relURL }}{{ if not .Site.Params.disableAssetsBusting }}?{{ now.Unix }}{{ end }}"></script>
    <script src="{{ "js/html5shiv-printshiv.min.js" | relURL }}{{ if not .Site.Params.disableAssetsBusting }}?{{ now.Unix }}{{ end }}"></script>
    <script src="{{ "js/highlight.pack.js" | relURL }}{{ if not .Site.Params.disableAssetsBusting }}?{{ now.Unix }}{{ end }}"></script>
    <script>hljs.initHighlightingOnLoad();</script>
    --- a/hugo/themes/learn/layouts/partials/header.html Mon Feb 11 12:43:24 2019 -0500
    +++ b/hugo/themes/learn/layouts/partials/header.html Thu May 16 22:10:20 2019 -0400
    @@ -12,7 +12,6 @@
    <link href="{{ "css/nucleus.css" | relURL }}{{ if $assetBusting }}?{{ now.Unix }}{{ end }}" rel="stylesheet">
    <link href="{{ "css/fontawesome-all.min.css" | relURL }}{{ if $assetBusting }}?{{ now.Unix }}{{ end }}" rel="stylesheet">
    <link href="{{ "css/hybrid.css" | relURL }}{{ if $assetBusting }}?{{ now.Unix }}{{ end }}" rel="stylesheet">
    - <link href="{{ "css/featherlight.min.css" | relURL }}{{ if $assetBusting }}?{{ now.Unix }}{{ end }}" rel="stylesheet">
    <link href="{{ "css/perfect-scrollbar.min.css" | relURL }}{{ if $assetBusting }}?{{ now.Unix }}{{ end }}" rel="stylesheet">
    <link href="{{ "css/auto-complete.css" | relURL }}{{ if $assetBusting }}?{{ now.Unix }}{{ end }}" rel="stylesheet">
    <link href="{{ "css/theme.css" | relURL }}{{ if $assetBusting }}?{{ now.Unix }}{{ end }}" rel="stylesheet">
    @@ -82,27 +81,37 @@
    </div>
    {{ if $toc }}
    - {{ partial "toc.html" . }}
    + <div class="progress">
    + <div class="wrapper">
    + {{ .TableOfContents }}
    + </div>
    + </div>
    {{ end }}
    </div>
    </div>
    {{ end }}
    - {{/* TODO: Remove disgusting conditional tag spanning file */}}
    {{ if .Params.chapter }}
    <div id="chapter">
    {{ end }}
    +
    + {{ if and (not .IsHome) (not .Params.chapter) }}
    + <h1>{{ .Title }}</h1>
    + {{ end }}
    +
    + {{ if gt .WordCount 400 }}
    + {{ .TableOfContents }}
    + {{ end }}
    +
    <div id="body-inner">
    - {{ if and (not .IsHome) (not .Params.chapter) }}
    - <h1>{{ .Title }}</h1>
    - {{ end }}
    - {{ define "breadcrumb" }}
    - {{ $parent := .page.Parent }}
    - {{ if $parent }}
    - {{ $value := (printf "<a href='%s'>%s</a> > %s" $parent.URL $parent.Title .value) }}
    - {{ template "breadcrumb" dict "page" $parent "value" $value }}
    - {{ else }}
    - {{ .value|safeHTML }}
    - {{ end }}
    - {{ end }}
    +{{/*** Templates ***/}}
    +{{ define "breadcrumb" }}
    + {{ $parent := .page.Parent }}
    + {{ if $parent }}
    + {{ $value := (printf "<a href='%s'>%s</a> > %s" $parent.URL $parent.Title .value) }}
    + {{ template "breadcrumb" dict "page" $parent "value" $value }}
    + {{ else }}
    + {{ .value|safeHTML }}
    + {{ end }}
    +{{ end }}
    --- a/hugo/themes/learn/layouts/partials/menu.html Mon Feb 11 12:43:24 2019 -0500
    +++ b/hugo/themes/learn/layouts/partials/menu.html Thu May 16 22:10:20 2019 -0400
    @@ -92,10 +92,10 @@
    <!-- templates -->
    {{ define "section-tree-nav" }}
    -{{ $showvisitedlinks := .showvisitedlinks }}
    -{{ $currentNode := .currentnode }}
    -{{ with .sect }}
    - {{ if .IsSection }}
    + {{ $showvisitedlinks := .showvisitedlinks }}
    + {{ $currentNode := .currentnode }}
    + {{ with .sect }}
    + {{ if .IsSection }}
    {{ safeHTML .Params.head }}
    <li data-nav-id="{{ .URL }}" title="{{ .Title }}" class="dd-item
    {{- if .IsAncestor $currentNode }} parent{{ end -}}
    --- a/hugo/themes/learn/layouts/partials/toc.html Mon Feb 11 12:43:24 2019 -0500
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,5 +0,0 @@
    -<div class="progress">
    - <div class="wrapper">
    -{{ .TableOfContents }}
    - </div>
    -</div>
    --- a/hugo/themes/learn/static/css/featherlight.min.css Mon Feb 11 12:43:24 2019 -0500
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,8 +0,0 @@
    -/**
    - * Featherlight - ultra slim jQuery lightbox
    - * Version 1.2.3 - http://noelboss.github.io/featherlight/
    - *
    - * Copyright 2015, Noël Raoul Bossart (http://www.noelboss.com)
    - * MIT Licensed.
    -**/
    -@media all{.featherlight{display:none;position:fixed;top:0;right:0;bottom:0;left:0;z-index:2147483647;text-align:center;white-space:nowrap;cursor:pointer;background:#333;background:rgba(0,0,0,0)}.featherlight:last-of-type{background:rgba(0,0,0,.8)}.featherlight:before{content:'';display:inline-block;height:100%;vertical-align:middle;margin-right:-.25em}.featherlight .featherlight-content{position:relative;text-align:left;vertical-align:middle;display:inline-block;overflow:auto;padding:25px 25px 0;border-bottom:25px solid transparent;min-width:30%;margin-left:5%;margin-right:5%;max-height:95%;background:#fff;cursor:auto;white-space:normal}.featherlight .featherlight-inner{display:block}.featherlight .featherlight-close-icon{position:absolute;z-index:9999;top:0;right:0;line-height:25px;width:25px;cursor:pointer;text-align:center;font:Arial,sans-serif;background:#fff;background:rgba(255,255,255,.3);color:#000}.featherlight .featherlight-image{width:100%}.featherlight-iframe .featherlight-content{border-bottom:0;padding:0}.featherlight iframe{border:0}}@media only screen and (max-width:1024px){.featherlight .featherlight-content{margin-left:10px;margin-right:10px;max-height:98%;padding:10px 10px 0;border-bottom:10px solid transparent}}
    \ No newline at end of file
    --- a/hugo/themes/learn/static/css/theme.css Mon Feb 11 12:43:24 2019 -0500
    +++ b/hugo/themes/learn/static/css/theme.css Thu May 16 22:10:20 2019 -0400
    @@ -917,9 +917,6 @@
    #github-contrib i {
    vertical-align: middle;
    }
    -.featherlight img {
    - margin: 0 !important;
    -}
    .lifecycle #body-inner ul {
    list-style: none;
    margin: 0;
    --- a/hugo/themes/learn/static/js/featherlight.min.js Mon Feb 11 12:43:24 2019 -0500
    +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
    @@ -1,8 +0,0 @@
    -/**
    - * Featherlight - ultra slim jQuery lightbox
    - * Version 1.2.3 - http://noelboss.github.io/featherlight/
    - *
    - * Copyright 2015, Noël Raoul Bossart (http://www.noelboss.com)
    - * MIT Licensed.
    -**/
    -!function(a){"use strict";function b(a,c){if(!(this instanceof b)){var d=new b(a,c);return d.open(),d}this.id=b.id++,this.setup(a,c),this.chainCallbacks(b._callbackChain)}if("undefined"==typeof a)return void("console"in window&&window.console.info("Too much lightness, Featherlight needs jQuery."));var c=[],d=function(b){return c=a.grep(c,function(a){return a!==b&&a.$instance.closest("body").length>0})},e=function(a,b){var c={},d=new RegExp("^"+b+"([A-Z])(.*)");for(var e in a){var f=e.match(d);if(f){var g=(f[1]+f[2].replace(/([A-Z])/g,"-$1")).toLowerCase();c[g]=a[e]}}return c},f={keyup:"onKeyUp",resize:"onResize"},g=function(c){a.each(b.opened().reverse(),function(){return c.isDefaultPrevented()||!1!==this[f[c.type]](c)?void 0:(c.preventDefault(),c.stopPropagation(),!1)})},h=function(c){if(c!==b._globalHandlerInstalled){b._globalHandlerInstalled=c;var d=a.map(f,function(a,c){return c+"."+b.prototype.namespace}).join(" ");a(window)[c?"on":"off"](d,g)}};b.prototype={constructor:b,namespace:"featherlight",targetAttr:"data-featherlight",variant:null,resetCss:!1,background:null,openTrigger:"click",closeTrigger:"click",filter:null,root:"body",openSpeed:250,closeSpeed:250,closeOnClick:"background",closeOnEsc:!0,closeIcon:"&#10005;",loading:"",otherClose:null,beforeOpen:a.noop,beforeContent:a.noop,beforeClose:a.noop,afterOpen:a.noop,afterContent:a.noop,afterClose:a.noop,onKeyUp:a.noop,onResize:a.noop,type:null,contentFilters:["jquery","image","html","ajax","iframe","text"],setup:function(b,c){"object"!=typeof b||b instanceof a!=!1||c||(c=b,b=void 0);var d=a.extend(this,c,{target:b}),e=d.resetCss?d.namespace+"-reset":d.namespace,f=a(d.background||['<div class="'+e+"-loading "+e+'">','<div class="'+e+'-content">','<span class="'+e+"-close-icon "+d.namespace+'-close">',d.closeIcon,"</span>",'<div class="'+d.namespace+'-inner">'+d.loading+"</div>","</div>","</div>"].join("")),g="."+d.namespace+"-close"+(d.otherClose?","+d.otherClose:"");return d.$instance=f.clone().addClass(d.variant),d.$instance.on(d.closeTrigger+"."+d.namespace,function(b){var c=a(b.target);("background"===d.closeOnClick&&c.is("."+d.namespace)||"anywhere"===d.closeOnClick||c.closest(g).length)&&(b.preventDefault(),d.close())}),this},getContent:function(){var b=this,c=this.constructor.contentFilters,d=function(a){return b.$currentTarget&&b.$currentTarget.attr(a)},e=d(b.targetAttr),f=b.target||e||"",g=c[b.type];if(!g&&f in c&&(g=c[f],f=b.target&&e),f=f||d("href")||"",!g)for(var h in c)b[h]&&(g=c[h],f=b[h]);if(!g){var i=f;if(f=null,a.each(b.contentFilters,function(){return g=c[this],g.test&&(f=g.test(i)),!f&&g.regex&&i.match&&i.match(g.regex)&&(f=i),!f}),!f)return"console"in window&&window.console.error("Featherlight: no content filter found "+(i?' for "'+i+'"':" (no target specified)")),!1}return g.process.call(b,f)},setContent:function(b){var c=this;return(b.is("iframe")||a("iframe",b).length>0)&&c.$instance.addClass(c.namespace+"-iframe"),c.$instance.removeClass(c.namespace+"-loading"),c.$instance.find("."+c.namespace+"-inner").slice(1).remove().end().replaceWith(a.contains(c.$instance[0],b[0])?"":b),c.$content=b.addClass(c.namespace+"-inner"),c},open:function(b){var d=this;if(d.$instance.hide().appendTo(d.root),!(b&&b.isDefaultPrevented()||d.beforeOpen(b)===!1)){b&&b.preventDefault();var e=d.getContent();if(e)return c.push(d),h(!0),d.$instance.fadeIn(d.openSpeed),d.beforeContent(b),a.when(e).always(function(a){d.setContent(a),d.afterContent(b)}).then(d.$instance.promise()).done(function(){d.afterOpen(b)})}return d.$instance.detach(),a.Deferred().reject().promise()},close:function(b){var c=this,e=a.Deferred();return c.beforeClose(b)===!1?e.reject():(0===d(c).length&&h(!1),c.$instance.fadeOut(c.closeSpeed,function(){c.$instance.detach(),c.afterClose(b),e.resolve()})),e.promise()},chainCallbacks:function(b){for(var c in b)this[c]=a.proxy(b[c],this,a.proxy(this[c],this))}},a.extend(b,{id:0,autoBind:"[data-featherlight]",defaults:b.prototype,contentFilters:{jquery:{regex:/^[#.]\w/,test:function(b){return b instanceof a&&b},process:function(b){return a(b).clone(!0)}},image:{regex:/\.(png|jpg|jpeg|gif|tiff|bmp)(\?\S*)?$/i,process:function(b){var c=this,d=a.Deferred(),e=new Image,f=a('<img src="'+b+'" alt="" class="'+c.namespace+'-image" />');return e.onload=function(){f.naturalWidth=e.width,f.naturalHeight=e.height,d.resolve(f)},e.onerror=function(){d.reject(f)},e.src=b,d.promise()}},html:{regex:/^\s*<[\w!][^<]*>/,process:function(b){return a(b)}},ajax:{regex:/./,process:function(b){var c=a.Deferred(),d=a("<div></div>").load(b,function(a,b){"error"!==b&&c.resolve(d.contents()),c.fail()});return c.promise()}},iframe:{process:function(b){var c=new a.Deferred,d=a("<iframe/>").hide().attr("src",b).css(e(this,"iframe")).on("load",function(){c.resolve(d.show())}).appendTo(this.$instance.find("."+this.namespace+"-content"));return c.promise()}},text:{process:function(b){return a("<div>",{text:b})}}},functionAttributes:["beforeOpen","afterOpen","beforeContent","afterContent","beforeClose","afterClose"],readElementConfig:function(b,c){var d=this,e=new RegExp("^data-"+c+"-(.*)"),f={};return b&&b.attributes&&a.each(b.attributes,function(){var b=this.name.match(e);if(b){var c=this.value,g=a.camelCase(b[1]);if(a.inArray(g,d.functionAttributes)>=0)c=new Function(c);else try{c=a.parseJSON(c)}catch(h){}f[g]=c}}),f},extend:function(b,c){var d=function(){this.constructor=b};return d.prototype=this.prototype,b.prototype=new d,b.__super__=this.prototype,a.extend(b,this,c),b.defaults=b.prototype,b},attach:function(b,c,d){var e=this;"object"!=typeof c||c instanceof a!=!1||d||(d=c,c=void 0),d=a.extend({},d);var f=d.namespace||e.defaults.namespace,g=a.extend({},e.defaults,e.readElementConfig(b[0],f),d);return b.on(g.openTrigger+"."+g.namespace,g.filter,function(f){var h=a.extend({$source:b,$currentTarget:a(this)},e.readElementConfig(b[0],g.namespace),e.readElementConfig(this,g.namespace),d);new e(c,h).open(f)}),b},current:function(){var a=this.opened();return a[a.length-1]||null},opened:function(){var b=this;return d(),a.grep(c,function(a){return a instanceof b})},close:function(){var a=this.current();return a?a.close():void 0},_onReady:function(){var b=this;b.autoBind&&(b.attach(a(document),{filter:b.autoBind}),a(b.autoBind).filter("[data-featherlight-filter]").each(function(){b.attach(a(this))}))},_callbackChain:{onKeyUp:function(a,b){return 27===b.keyCode?(this.closeOnEsc&&this.$instance.find("."+this.namespace+"-close:first").click(),!1):a(b)},onResize:function(a,b){if(this.$content.naturalWidth){var c=this.$content.naturalWidth,d=this.$content.naturalHeight;this.$content.css("width","").css("height","");var e=Math.max(c/parseInt(this.$content.parent().css("width"),10),d/parseInt(this.$content.parent().css("height"),10));e>1&&this.$content.css("width",""+c/e+"px").css("height",""+d/e+"px")}return a(b)},afterContent:function(a,b){var c=a(b);return this.onResize(b),c}}}),a.featherlight=b,a.fn.featherlight=function(a,c){return b.attach(this,a,c)},a(document).ready(function(){b._onReady()})}(jQuery);
    \ No newline at end of file
    --- a/hugo/themes/learn/static/js/hugo-learn.js Mon Feb 11 12:43:24 2019 -0500
    +++ b/hugo/themes/learn/static/js/hugo-learn.js Thu May 16 22:10:20 2019 -0400
    @@ -1,62 +1,3 @@
    -// Get Parameters from some url
    -var getUrlParameter = function getUrlParameter(sPageURL) {
    - var url = sPageURL.split('?');
    - var obj = {};
    - if (url.length == 2) {
    - var sURLVariables = url[1].split('&'),
    - sParameterName,
    - i;
    - for (i = 0; i < sURLVariables.length; i++) {
    - sParameterName = sURLVariables[i].split('=');
    - obj[sParameterName[0]] = sParameterName[1];
    - }
    - return obj;
    - } else {
    - return undefined;
    - }
    -};
    -
    -// Execute actions on images generated from Markdown pages
    -var images = $("div#body-inner img").not(".inline");
    -// Wrap image inside a featherlight (to get a full size view in a popup)
    -images.wrap(function(){
    - var image =$(this);
    - if (!image.parent("a").length) {
    - return "<a href='" + image[0].src + "' data-featherlight='image'></a>";
    - }
    -});
    -
    -// Change styles, depending on parameters set to the image
    -images.each(function(index){
    - var image = $(this)
    - var o = getUrlParameter(image[0].src);
    - if (typeof o !== "undefined") {
    - var h = o["height"];
    - var w = o["width"];
    - var c = o["classes"];
    - image.css("width", function() {
    - if (typeof w !== "undefined") {
    - return w;
    - } else {
    - return "auto";
    - }
    - });
    - image.css("height", function() {
    - if (typeof h !== "undefined") {
    - return h;
    - } else {
    - return "auto";
    - }
    - });
    - if (typeof c !== "undefined") {
    - var classes = c.split(',');
    - for (i = 0; i < classes.length; i++) {
    - image.addClass(classes[i]);
    - }
    - }
    - }
    -});
    -
    // Stick the top to the top of the screen when scrolling
    $(document).ready(function(){
    $("#top-bar").sticky({topSpacing:0, zIndex: 1000});
    --- a/hugo/themes/learn/static/js/learn.js Mon Feb 11 12:43:24 2019 -0500
    +++ b/hugo/themes/learn/static/js/learn.js Thu May 16 22:10:20 2019 -0400
    @@ -381,12 +381,6 @@
    $(".highlightable").highlight(sessionStorage.getItem('search-value'), { element: 'mark' });
    });
    -$(function() {
    - $('a[rel="lightbox"]').featherlight({
    - root: 'section#body'
    - });
    -});
    -
    jQuery.extend({
    highlight: function(node, re, nodeName, className) {
    if (node.nodeType === 3) {
    --- a/package-lock.json Mon Feb 11 12:43:24 2019 -0500
    +++ b/package-lock.json Thu May 16 22:10:20 2019 -0400
    @@ -22,6 +22,25 @@
    "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
    "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
    },
    + "agent-base": {
    + "version": "4.2.1",
    + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.1.tgz",
    + "integrity": "sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==",
    + "requires": {
    + "es6-promisify": "^5.0.0"
    + }
    + },
    + "ajv": {
    + "version": "6.10.0",
    + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz",
    + "integrity": "sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg==",
    + "requires": {
    + "fast-deep-equal": "^2.0.1",
    + "fast-json-stable-stringify": "^2.0.0",
    + "json-schema-traverse": "^0.4.1",
    + "uri-js": "^4.2.2"
    + }
    + },
    "ansi-styles": {
    "version": "3.2.1",
    "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
    @@ -38,11 +57,62 @@
    "sprintf-js": "~1.0.2"
    }
    },
    + "asn1": {
    + "version": "0.2.4",
    + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
    + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==",
    + "requires": {
    + "safer-buffer": "~2.1.0"
    + }
    + },
    + "assert-plus": {
    + "version": "1.0.0",
    + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
    + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
    + },
    + "async-limiter": {
    + "version": "1.0.0",
    + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz",
    + "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg=="
    + },
    + "asynckit": {
    + "version": "0.4.0",
    + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
    + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
    + },
    + "aws-sign2": {
    + "version": "0.7.0",
    + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
    + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg="
    + },
    + "aws4": {
    + "version": "1.8.0",
    + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz",
    + "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ=="
    + },
    "balanced-match": {
    "version": "1.0.0",
    "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
    "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
    },
    + "bcrypt-pbkdf": {
    + "version": "1.0.2",
    + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
    + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
    + "requires": {
    + "tweetnacl": "^0.14.3"
    + }
    + },
    + "bignumber.js": {
    + "version": "2.4.0",
    + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-2.4.0.tgz",
    + "integrity": "sha1-g4qZLan51zfg9LLbC+YrsJ3Qxeg="
    + },
    + "bmp-js": {
    + "version": "0.0.3",
    + "resolved": "https://registry.npmjs.org/bmp-js/-/bmp-js-0.0.3.tgz",
    + "integrity": "sha1-ZBE+nHzxICs3btYHvzBibr5XsYo="
    + },
    "boolbase": {
    "version": "1.0.0",
    "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
    @@ -57,6 +127,21 @@
    "concat-map": "0.0.1"
    }
    },
    + "buffer-equal": {
    + "version": "0.0.1",
    + "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-0.0.1.tgz",
    + "integrity": "sha1-kbx0sR6kBbyRa8aqkI+q+ltKrEs="
    + },
    + "buffer-from": {
    + "version": "1.1.1",
    + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
    + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A=="
    + },
    + "caseless": {
    + "version": "0.12.0",
    + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
    + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
    + },
    "chalk": {
    "version": "2.4.2",
    "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
    @@ -67,6 +152,11 @@
    "supports-color": "^5.3.0"
    }
    },
    + "check-types": {
    + "version": "7.4.0",
    + "resolved": "https://registry.npmjs.org/check-types/-/check-types-7.4.0.tgz",
    + "integrity": "sha512-YbulWHdfP99UfZ73NcUDlNJhEIDgm9Doq9GhpyXbF+7Aegi3CVV7qqMCKTTqJxlvEvnQBp9IA+dxsGN6xK/nSg=="
    + },
    "coa": {
    "version": "2.0.2",
    "resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz",
    @@ -95,6 +185,14 @@
    "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz",
    "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM="
    },
    + "combined-stream": {
    + "version": "1.0.7",
    + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz",
    + "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==",
    + "requires": {
    + "delayed-stream": "~1.0.0"
    + }
    + },
    "commander": {
    "version": "2.19.0",
    "resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz",
    @@ -105,6 +203,17 @@
    "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
    "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
    },
    + "concat-stream": {
    + "version": "1.6.2",
    + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
    + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
    + "requires": {
    + "buffer-from": "^1.0.0",
    + "inherits": "^2.0.3",
    + "readable-stream": "^2.2.2",
    + "typedarray": "^0.0.6"
    + }
    + },
    "config-chain": {
    "version": "1.1.12",
    "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz",
    @@ -114,6 +223,11 @@
    "proto-list": "~1.2.1"
    }
    },
    + "core-util-is": {
    + "version": "1.0.2",
    + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
    + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
    + },
    "css-select": {
    "version": "2.0.2",
    "resolved": "https://registry.npmjs.org/css-select/-/css-select-2.0.2.tgz",
    @@ -168,6 +282,22 @@
    }
    }
    },
    + "dashdash": {
    + "version": "1.14.1",
    + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
    + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
    + "requires": {
    + "assert-plus": "^1.0.0"
    + }
    + },
    + "debug": {
    + "version": "4.1.1",
    + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
    + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
    + "requires": {
    + "ms": "^2.1.1"
    + }
    + },
    "define-properties": {
    "version": "1.1.3",
    "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
    @@ -176,6 +306,26 @@
    "object-keys": "^1.0.12"
    }
    },
    + "delayed-stream": {
    + "version": "1.0.0",
    + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
    + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
    + },
    + "differencify": {
    + "version": "1.5.3",
    + "resolved": "https://registry.npmjs.org/differencify/-/differencify-1.5.3.tgz",
    + "integrity": "sha512-QdUlxG59aHvJTReMNiIuTES7FdqIucsBQ5szyh5H2exc5rSk47ZZAcEpKmVeXf3j3JgjT73U4RFx2ob376qTrg==",
    + "requires": {
    + "chalk": "^2.4.1",
    + "check-types": "^7.4.0",
    + "fs": "0.0.2",
    + "jimp": "^0.2.28",
    + "mockeer": "0.0.3",
    + "pkg-dir": "2.0.0",
    + "puppeteer": "^1.8.0",
    + "type-detect": "^4.0.8"
    + }
    + },
    "dom-serializer": {
    "version": "0.1.0",
    "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz",
    @@ -192,6 +342,11 @@
    }
    }
    },
    + "dom-walk": {
    + "version": "0.1.1",
    + "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.1.tgz",
    + "integrity": "sha1-ZyIm3HTI95mtNTB9+TaroRrNYBg="
    + },
    "domelementtype": {
    "version": "1.3.1",
    "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz",
    @@ -206,6 +361,15 @@
    "domelementtype": "1"
    }
    },
    + "ecc-jsbn": {
    + "version": "0.1.2",
    + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
    + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=",
    + "requires": {
    + "jsbn": "~0.1.0",
    + "safer-buffer": "^2.1.0"
    + }
    + },
    "editorconfig": {
    "version": "0.15.2",
    "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-0.15.2.tgz",
    @@ -247,6 +411,26 @@
    "is-symbol": "^1.0.2"
    }
    },
    + "es6-promise": {
    + "version": "3.3.1",
    + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz",
    + "integrity": "sha1-oIzd6EzNvzTQJ6FFG8kdS80ophM="
    + },
    + "es6-promisify": {
    + "version": "5.0.0",
    + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz",
    + "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=",
    + "requires": {
    + "es6-promise": "^4.0.3"
    + },
    + "dependencies": {
    + "es6-promise": {
    + "version": "4.2.6",
    + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.6.tgz",
    + "integrity": "sha512-aRVgGdnmW2OiySVPUC9e6m+plolMAJKjZnQlCwNSuK5yQ0JN61DZSO1X1Ufd1foqWRAlig0rhduTCHe7sVtK5Q=="
    + }
    + }
    + },
    "escape-string-regexp": {
    "version": "1.0.5",
    "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
    @@ -257,6 +441,116 @@
    "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
    "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
    },
    + "exif-parser": {
    + "version": "0.1.12",
    + "resolved": "https://registry.npmjs.org/exif-parser/-/exif-parser-0.1.12.tgz",
    + "integrity": "sha1-WKnS1ywCwfbwKg70qRZicrd2CSI="
    + },
    + "extend": {
    + "version": "3.0.2",
    + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
    + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
    + },
    + "extract-zip": {
    + "version": "1.6.7",
    + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.6.7.tgz",
    + "integrity": "sha1-qEC0uK9kAyZMjbV/Txp0Mz74H+k=",
    + "requires": {
    + "concat-stream": "1.6.2",
    + "debug": "2.6.9",
    + "mkdirp": "0.5.1",
    + "yauzl": "2.4.1"
    + },
    + "dependencies": {
    + "debug": {
    + "version": "2.6.9",
    + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
    + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
    + "requires": {
    + "ms": "2.0.0"
    + }
    + },
    + "ms": {
    + "version": "2.0.0",
    + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
    + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
    + }
    + }
    + },
    + "extsprintf": {
    + "version": "1.3.0",
    + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
    + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU="
    + },
    + "fast-deep-equal": {
    + "version": "2.0.1",
    + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
    + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk="
    + },
    + "fast-json-stable-stringify": {
    + "version": "2.0.0",
    + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz",
    + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I="
    + },
    + "fd-slicer": {
    + "version": "1.0.1",
    + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz",
    + "integrity": "sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU=",
    + "requires": {
    + "pend": "~1.2.0"
    + }
    + },
    + "file-type": {
    + "version": "3.9.0",
    + "resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz",
    + "integrity": "sha1-JXoHg4TR24CHvESdEH1SpSZyuek="
    + },
    + "filename-reserved-regex": {
    + "version": "2.0.0",
    + "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz",
    + "integrity": "sha1-q/c9+rc10EVECr/qLZHzieu/oik="
    + },
    + "filenamify": {
    + "version": "2.1.0",
    + "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-2.1.0.tgz",
    + "integrity": "sha512-ICw7NTT6RsDp2rnYKVd8Fu4cr6ITzGy3+u4vUujPkabyaz+03F24NWEX7fs5fp+kBonlaqPH8fAO2NM+SXt/JA==",
    + "requires": {
    + "filename-reserved-regex": "^2.0.0",
    + "strip-outer": "^1.0.0",
    + "trim-repeated": "^1.0.0"
    + }
    + },
    + "find-up": {
    + "version": "2.1.0",
    + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz",
    + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=",
    + "requires": {
    + "locate-path": "^2.0.0"
    + }
    + },
    + "for-each": {
    + "version": "0.3.3",
    + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
    + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==",
    + "requires": {
    + "is-callable": "^1.1.3"
    + }
    + },
    + "forever-agent": {
    + "version": "0.6.1",
    + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
    + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE="
    + },
    + "form-data": {
    + "version": "2.3.3",
    + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
    + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
    + "requires": {
    + "asynckit": "^0.4.0",
    + "combined-stream": "^1.0.6",
    + "mime-types": "^2.1.12"
    + }
    + },
    "front-matter": {
    "version": "3.0.1",
    "resolved": "https://registry.npmjs.org/front-matter/-/front-matter-3.0.1.tgz",
    @@ -266,6 +560,11 @@
    "js-yaml": "^3.10.0"
    }
    },
    + "fs": {
    + "version": "0.0.2",
    + "resolved": "https://registry.npmjs.org/fs/-/fs-0.0.2.tgz",
    + "integrity": "sha1-4fJE7zkzwbKmS9R5kTYGDQ9ZFPg="
    + },
    "fs.realpath": {
    "version": "1.0.0",
    "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
    @@ -276,6 +575,14 @@
    "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
    "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
    },
    + "getpass": {
    + "version": "0.1.7",
    + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
    + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
    + "requires": {
    + "assert-plus": "^1.0.0"
    + }
    + },
    "glob": {
    "version": "7.1.3",
    "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz",
    @@ -289,6 +596,29 @@
    "path-is-absolute": "^1.0.0"
    }
    },
    + "global": {
    + "version": "4.3.2",
    + "resolved": "https://registry.npmjs.org/global/-/global-4.3.2.tgz",
    + "integrity": "sha1-52mJJopsdMOJCLEwWxD8DjlOnQ8=",
    + "requires": {
    + "min-document": "^2.19.0",
    + "process": "~0.5.1"
    + }
    + },
    + "har-schema": {
    + "version": "2.0.0",
    + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
    + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI="
    + },
    + "har-validator": {
    + "version": "5.1.3",
    + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz",
    + "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==",
    + "requires": {
    + "ajv": "^6.5.5",
    + "har-schema": "^2.0.0"
    + }
    + },
    "has": {
    "version": "1.0.3",
    "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
    @@ -307,6 +637,40 @@
    "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz",
    "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q="
    },
    + "http-signature": {
    + "version": "1.2.0",
    + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
    + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
    + "requires": {
    + "assert-plus": "^1.0.0",
    + "jsprim": "^1.2.2",
    + "sshpk": "^1.7.0"
    + }
    + },
    + "https-proxy-agent": {
    + "version": "2.2.1",
    + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz",
    + "integrity": "sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ==",
    + "requires": {
    + "agent-base": "^4.1.0",
    + "debug": "^3.1.0"
    + },
    + "dependencies": {
    + "debug": {
    + "version": "3.2.6",
    + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
    + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
    + "requires": {
    + "ms": "^2.1.1"
    + }
    + }
    + }
    + },
    + "image-extensions": {
    + "version": "1.1.0",
    + "resolved": "https://registry.npmjs.org/image-extensions/-/image-extensions-1.1.0.tgz",
    + "integrity": "sha1-uOa/YDnfAFbjM1AqALZjejEF2JQ="
    + },
    "inflight": {
    "version": "1.0.6",
    "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
    @@ -326,6 +690,11 @@
    "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
    "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw=="
    },
    + "ip-regex": {
    + "version": "1.0.3",
    + "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-1.0.3.tgz",
    + "integrity": "sha1-3FiQdvZZ9BnCIgOaMzFvHHOH7/0="
    + },
    "is-callable": {
    "version": "1.1.4",
    "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz",
    @@ -336,6 +705,19 @@
    "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz",
    "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY="
    },
    + "is-function": {
    + "version": "1.0.1",
    + "resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.1.tgz",
    + "integrity": "sha1-Es+5i2W1fdPRk6MSH19uL0N2ArU="
    + },
    + "is-image": {
    + "version": "2.0.0",
    + "resolved": "https://registry.npmjs.org/is-image/-/is-image-2.0.0.tgz",
    + "integrity": "sha1-RUyVaVeN4xhpNx+/rqSVj0YbPgw=",
    + "requires": {
    + "image-extensions": "^1.0.1"
    + }
    + },
    "is-regex": {
    "version": "1.0.4",
    "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz",
    @@ -352,6 +734,49 @@
    "has-symbols": "^1.0.0"
    }
    },
    + "is-typedarray": {
    + "version": "1.0.0",
    + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
    + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="
    + },
    + "isarray": {
    + "version": "1.0.0",
    + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
    + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
    + },
    + "isstream": {
    + "version": "0.1.2",
    + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
    + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo="
    + },
    + "jimp": {
    + "version": "0.2.28",
    + "resolved": "https://registry.npmjs.org/jimp/-/jimp-0.2.28.tgz",
    + "integrity": "sha1-3VKak3GQ9ClXp5N9Gsw6d2KZbqI=",
    + "requires": {
    + "bignumber.js": "^2.1.0",
    + "bmp-js": "0.0.3",
    + "es6-promise": "^3.0.2",
    + "exif-parser": "^0.1.9",
    + "file-type": "^3.1.0",
    + "jpeg-js": "^0.2.0",
    + "load-bmfont": "^1.2.3",
    + "mime": "^1.3.4",
    + "mkdirp": "0.5.1",
    + "pixelmatch": "^4.0.0",
    + "pngjs": "^3.0.0",
    + "read-chunk": "^1.0.1",
    + "request": "^2.65.0",
    + "stream-to-buffer": "^0.1.0",
    + "tinycolor2": "^1.1.2",
    + "url-regex": "^3.0.0"
    + }
    + },
    + "jpeg-js": {
    + "version": "0.2.0",
    + "resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.2.0.tgz",
    + "integrity": "sha1-U+RI7J0mPmgyZkZ+lELSxaLvVII="
    + },
    "js-beautify": {
    "version": "1.8.9",
    "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.8.9.tgz",
    @@ -373,6 +798,61 @@
    "esprima": "^4.0.0"
    }
    },
    + "jsbn": {
    + "version": "0.1.1",
    + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
    + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM="
    + },
    + "json-schema": {
    + "version": "0.2.3",
    + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
    + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM="
    + },
    + "json-schema-traverse": {
    + "version": "0.4.1",
    + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
    + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
    + },
    + "json-stringify-safe": {
    + "version": "5.0.1",
    + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
    + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus="
    + },
    + "jsprim": {
    + "version": "1.4.1",
    + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
    + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
    + "requires": {
    + "assert-plus": "1.0.0",
    + "extsprintf": "1.3.0",
    + "json-schema": "0.2.3",
    + "verror": "1.10.0"
    + }
    + },
    + "load-bmfont": {
    + "version": "1.4.0",
    + "resolved": "https://registry.npmjs.org/load-bmfont/-/load-bmfont-1.4.0.tgz",
    + "integrity": "sha512-kT63aTAlNhZARowaNYcY29Fn/QYkc52M3l6V1ifRcPewg2lvUZDAj7R6dXjOL9D0sict76op3T5+odumDSF81g==",
    + "requires": {
    + "buffer-equal": "0.0.1",
    + "mime": "^1.3.4",
    + "parse-bmfont-ascii": "^1.0.3",
    + "parse-bmfont-binary": "^1.0.5",
    + "parse-bmfont-xml": "^1.1.4",
    + "phin": "^2.9.1",
    + "xhr": "^2.0.1",
    + "xtend": "^4.0.0"
    + }
    + },
    + "locate-path": {
    + "version": "2.0.0",
    + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz",
    + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=",
    + "requires": {
    + "p-locate": "^2.0.0",
    + "path-exists": "^3.0.0"
    + }
    + },
    "lru-cache": {
    "version": "4.1.5",
    "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz",
    @@ -387,6 +867,32 @@
    "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-1.1.4.tgz",
    "integrity": "sha512-FSYbp3lyKjyj3E7fMl6rYvUdX0FBXaluGqlFoYESWQlyUTq8R+wp0rkFxoYFqZlHCvsUXGjyJmLQSnXToYhOSA=="
    },
    + "mime": {
    + "version": "1.6.0",
    + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
    + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="
    + },
    + "mime-db": {
    + "version": "1.38.0",
    + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.38.0.tgz",
    + "integrity": "sha512-bqVioMFFzc2awcdJZIzR3HjZFX20QhilVS7hytkKrv7xFAn8bM1gzc/FOX2awLISvWe0PV8ptFKcon+wZ5qYkg=="
    + },
    + "mime-types": {
    + "version": "2.1.22",
    + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.22.tgz",
    + "integrity": "sha512-aGl6TZGnhm/li6F7yx82bJiBZwgiEa4Hf6CNr8YO+r5UHr53tSTYZb102zyU50DOWWKeOv0uQLRL0/9EiKWCog==",
    + "requires": {
    + "mime-db": "~1.38.0"
    + }
    + },
    + "min-document": {
    + "version": "2.19.0",
    + "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz",
    + "integrity": "sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU=",
    + "requires": {
    + "dom-walk": "^0.1.0"
    + }
    + },
    "minimatch": {
    "version": "3.0.4",
    "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
    @@ -408,6 +914,23 @@
    "minimist": "0.0.8"
    }
    },
    + "mockeer": {
    + "version": "0.0.3",
    + "resolved": "https://registry.npmjs.org/mockeer/-/mockeer-0.0.3.tgz",
    + "integrity": "sha512-3ubkRjeyz3I3nmJxvey28kasWUY4ZLTCJFqRvSn74E+HoTgzJCB9JX6m17/9/ahbwcFAogw0X/bgrZb/vMd/dw==",
    + "requires": {
    + "check-types": "^7.4.0",
    + "filenamify": "^2.1.0",
    + "is-image": "^2.0.0",
    + "type-detect": "^4.0.8",
    + "url-parse": "^1.4.4"
    + }
    + },
    + "ms": {
    + "version": "2.1.1",
    + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
    + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
    + },
    "nopt": {
    "version": "4.0.1",
    "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz",
    @@ -425,6 +948,11 @@
    "boolbase": "~1.0.0"
    }
    },
    + "oauth-sign": {
    + "version": "0.9.0",
    + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
    + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ=="
    + },
    "object-keys": {
    "version": "1.0.12",
    "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.12.tgz",
    @@ -477,26 +1005,247 @@
    "os-tmpdir": "^1.0.0"
    }
    },
    + "p-limit": {
    + "version": "1.3.0",
    + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz",
    + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==",
    + "requires": {
    + "p-try": "^1.0.0"
    + }
    + },
    + "p-locate": {
    + "version": "2.0.0",
    + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz",
    + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=",
    + "requires": {
    + "p-limit": "^1.1.0"
    + }
    + },
    + "p-try": {
    + "version": "1.0.0",
    + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz",
    + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M="
    + },
    + "parse-bmfont-ascii": {
    + "version": "1.0.6",
    + "resolved": "https://registry.npmjs.org/parse-bmfont-ascii/-/parse-bmfont-ascii-1.0.6.tgz",
    + "integrity": "sha1-Eaw8P/WPfCAgqyJ2kHkQjU36AoU="
    + },
    + "parse-bmfont-binary": {
    + "version": "1.0.6",
    + "resolved": "https://registry.npmjs.org/parse-bmfont-binary/-/parse-bmfont-binary-1.0.6.tgz",
    + "integrity": "sha1-0Di0dtPp3Z2x4RoLDlOiJ5K2kAY="
    + },
    + "parse-bmfont-xml": {
    + "version": "1.1.4",
    + "resolved": "https://registry.npmjs.org/parse-bmfont-xml/-/parse-bmfont-xml-1.1.4.tgz",
    + "integrity": "sha512-bjnliEOmGv3y1aMEfREMBJ9tfL3WR0i0CKPj61DnSLaoxWR3nLrsQrEbCId/8rF4NyRF0cCqisSVXyQYWM+mCQ==",
    + "requires": {
    + "xml-parse-from-string": "^1.0.0",
    + "xml2js": "^0.4.5"
    + }
    + },
    + "parse-headers": {
    + "version": "2.0.2",
    + "resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.2.tgz",
    + "integrity": "sha512-/LypJhzFmyBIDYP9aDVgeyEb5sQfbfY5mnDq4hVhlQ69js87wXfmEI5V3xI6vvXasqebp0oCytYFLxsBVfCzSg==",
    + "requires": {
    + "for-each": "^0.3.3",
    + "string.prototype.trim": "^1.1.2"
    + }
    + },
    + "path-exists": {
    + "version": "3.0.0",
    + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
    + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU="
    + },
    "path-is-absolute": {
    "version": "1.0.1",
    "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
    "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
    },
    + "pend": {
    + "version": "1.2.0",
    + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
    + "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA="
    + },
    + "performance-now": {
    + "version": "2.1.0",
    + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
    + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
    + },
    + "phin": {
    + "version": "2.9.3",
    + "resolved": "https://registry.npmjs.org/phin/-/phin-2.9.3.tgz",
    + "integrity": "sha512-CzFr90qM24ju5f88quFC/6qohjC144rehe5n6DH900lgXmUe86+xCKc10ev56gRKC4/BkHUoG4uSiQgBiIXwDA=="
    + },
    + "pixelmatch": {
    + "version": "4.0.2",
    + "resolved": "https://registry.npmjs.org/pixelmatch/-/pixelmatch-4.0.2.tgz",
    + "integrity": "sha1-j0fc7FARtHe2fbA8JDvB8wheiFQ=",
    + "requires": {
    + "pngjs": "^3.0.0"
    + }
    + },
    + "pkg-dir": {
    + "version": "2.0.0",
    + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz",
    + "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=",
    + "requires": {
    + "find-up": "^2.1.0"
    + }
    + },
    + "pngjs": {
    + "version": "3.4.0",
    + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.4.0.tgz",
    + "integrity": "sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w=="
    + },
    + "process": {
    + "version": "0.5.2",
    + "resolved": "https://registry.npmjs.org/process/-/process-0.5.2.tgz",
    + "integrity": "sha1-FjjYqONML0QKkduVq5rrZ3/Bhc8="
    + },
    + "process-nextick-args": {
    + "version": "2.0.0",
    + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
    + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw=="
    + },
    + "progress": {
    + "version": "2.0.3",
    + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
    + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA=="
    + },
    "proto-list": {
    "version": "1.2.4",
    "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz",
    "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk="
    },
    + "proxy-from-env": {
    + "version": "1.0.0",
    + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.0.0.tgz",
    + "integrity": "sha1-M8UDmPcOp+uW0h97gXYwpVeRx+4="
    + },
    "pseudomap": {
    "version": "1.0.2",
    "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
    "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM="
    },
    + "psl": {
    + "version": "1.1.31",
    + "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.31.tgz",
    + "integrity": "sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw=="
    + },
    + "punycode": {
    + "version": "2.1.1",
    + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
    + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
    + },
    + "puppeteer": {
    + "version": "1.13.0",
    + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-1.13.0.tgz",
    + "integrity": "sha512-LUXgvhjfB/P6IOUDAKxOcbCz9ISwBLL9UpKghYrcBDwrOGx1m60y0iN2M64mdAUbT4+7oZM5DTxOW7equa2fxQ==",
    + "requires": {
    + "debug": "^4.1.0",
    + "extract-zip": "^1.6.6",
    + "https-proxy-agent": "^2.2.1",
    + "mime": "^2.0.3",
    + "progress": "^2.0.1",
    + "proxy-from-env": "^1.0.0",
    + "rimraf": "^2.6.1",
    + "ws": "^6.1.0"
    + },
    + "dependencies": {
    + "mime": {
    + "version": "2.4.0",
    + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.0.tgz",
    + "integrity": "sha512-ikBcWwyqXQSHKtciCcctu9YfPbFYZ4+gbHEmE0Q8jzcTYQg5dHCr3g2wwAZjPoJfQVXZq6KXAjpXOTf5/cjT7w=="
    + }
    + }
    + },
    "q": {
    "version": "1.5.1",
    "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz",
    "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc="
    },
    + "qs": {
    + "version": "6.5.2",
    + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
    + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA=="
    + },
    + "querystringify": {
    + "version": "2.1.0",
    + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.0.tgz",
    + "integrity": "sha512-sluvZZ1YiTLD5jsqZcDmFyV2EwToyXZBfpoVOmktMmW+VEnhgakFHnasVph65fOjGPTWN0Nw3+XQaSeMayr0kg=="
    + },
    + "read-chunk": {
    + "version": "1.0.1",
    + "resolved": "https://registry.npmjs.org/read-chunk/-/read-chunk-1.0.1.tgz",
    + "integrity": "sha1-X2jKswfmY/GZk1J9m1icrORmEZQ="
    + },
    + "readable-stream": {
    + "version": "2.3.6",
    + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
    + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
    + "requires": {
    + "core-util-is": "~1.0.0",
    + "inherits": "~2.0.3",
    + "isarray": "~1.0.0",
    + "process-nextick-args": "~2.0.0",
    + "safe-buffer": "~5.1.1",
    + "string_decoder": "~1.1.1",
    + "util-deprecate": "~1.0.1"
    + }
    + },
    + "request": {
    + "version": "2.88.0",
    + "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz",
    + "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==",
    + "requires": {
    + "aws-sign2": "~0.7.0",
    + "aws4": "^1.8.0",
    + "caseless": "~0.12.0",
    + "combined-stream": "~1.0.6",
    + "extend": "~3.0.2",
    + "forever-agent": "~0.6.1",
    + "form-data": "~2.3.2",
    + "har-validator": "~5.1.0",
    + "http-signature": "~1.2.0",
    + "is-typedarray": "~1.0.0",
    + "isstream": "~0.1.2",
    + "json-stringify-safe": "~5.0.1",
    + "mime-types": "~2.1.19",
    + "oauth-sign": "~0.9.0",
    + "performance-now": "^2.1.0",
    + "qs": "~6.5.2",
    + "safe-buffer": "^5.1.2",
    + "tough-cookie": "~2.4.3",
    + "tunnel-agent": "^0.6.0",
    + "uuid": "^3.3.2"
    + }
    + },
    + "requires-port": {
    + "version": "1.0.0",
    + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
    + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8="
    + },
    + "rimraf": {
    + "version": "2.6.3",
    + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
    + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
    + "requires": {
    + "glob": "^7.1.3"
    + }
    + },
    + "safe-buffer": {
    + "version": "5.1.2",
    + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
    + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
    + },
    + "safer-buffer": {
    + "version": "2.1.2",
    + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
    + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
    + },
    "sax": {
    "version": "1.2.4",
    "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
    @@ -522,11 +1271,66 @@
    "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
    "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
    },
    + "sshpk": {
    + "version": "1.16.1",
    + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz",
    + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==",
    + "requires": {
    + "asn1": "~0.2.3",
    + "assert-plus": "^1.0.0",
    + "bcrypt-pbkdf": "^1.0.0",
    + "dashdash": "^1.12.0",
    + "ecc-jsbn": "~0.1.1",
    + "getpass": "^0.1.1",
    + "jsbn": "~0.1.0",
    + "safer-buffer": "^2.0.2",
    + "tweetnacl": "~0.14.0"
    + }
    + },
    "stable": {
    "version": "0.1.8",
    "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz",
    "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w=="
    },
    + "stream-to": {
    + "version": "0.2.2",
    + "resolved": "https://registry.npmjs.org/stream-to/-/stream-to-0.2.2.tgz",
    + "integrity": "sha1-hDBgmNhf25kLn6MAsbPM9V6O8B0="
    + },
    + "stream-to-buffer": {
    + "version": "0.1.0",
    + "resolved": "https://registry.npmjs.org/stream-to-buffer/-/stream-to-buffer-0.1.0.tgz",
    + "integrity": "sha1-JnmdkDqyAlyb1VCsRxcbAPjdgKk=",
    + "requires": {
    + "stream-to": "~0.2.0"
    + }
    + },
    + "string.prototype.trim": {
    + "version": "1.1.2",
    + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.1.2.tgz",
    + "integrity": "sha1-0E3iyJ4Tf019IG8Ia17S+ua+jOo=",
    + "requires": {
    + "define-properties": "^1.1.2",
    + "es-abstract": "^1.5.0",
    + "function-bind": "^1.0.2"
    + }
    + },
    + "string_decoder": {
    + "version": "1.1.1",
    + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
    + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
    + "requires": {
    + "safe-buffer": "~5.1.0"
    + }
    + },
    + "strip-outer": {
    + "version": "1.0.1",
    + "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz",
    + "integrity": "sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==",
    + "requires": {
    + "escape-string-regexp": "^1.0.2"
    + }
    + },
    "supports-color": {
    "version": "5.5.0",
    "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
    @@ -556,11 +1360,93 @@
    "util.promisify": "~1.0.0"
    }
    },
    + "tinycolor2": {
    + "version": "1.4.1",
    + "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.4.1.tgz",
    + "integrity": "sha1-9PrTM0R7wLB9TcjpIJ2POaisd+g="
    + },
    + "tough-cookie": {
    + "version": "2.4.3",
    + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz",
    + "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==",
    + "requires": {
    + "psl": "^1.1.24",
    + "punycode": "^1.4.1"
    + },
    + "dependencies": {
    + "punycode": {
    + "version": "1.4.1",
    + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
    + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4="
    + }
    + }
    + },
    + "trim-repeated": {
    + "version": "1.0.0",
    + "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz",
    + "integrity": "sha1-42RqLqTokTEr9+rObPsFOAvAHCE=",
    + "requires": {
    + "escape-string-regexp": "^1.0.2"
    + }
    + },
    + "tunnel-agent": {
    + "version": "0.6.0",
    + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
    + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
    + "requires": {
    + "safe-buffer": "^5.0.1"
    + }
    + },
    + "tweetnacl": {
    + "version": "0.14.5",
    + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
    + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q="
    + },
    + "type-detect": {
    + "version": "4.0.8",
    + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
    + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g=="
    + },
    + "typedarray": {
    + "version": "0.0.6",
    + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
    + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="
    + },
    "unquote": {
    "version": "1.1.1",
    "resolved": "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz",
    "integrity": "sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ="
    },
    + "uri-js": {
    + "version": "4.2.2",
    + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
    + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==",
    + "requires": {
    + "punycode": "^2.1.0"
    + }
    + },
    + "url-parse": {
    + "version": "1.4.4",
    + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.4.tgz",
    + "integrity": "sha512-/92DTTorg4JjktLNLe6GPS2/RvAd/RGr6LuktmWSMLEOa6rjnlrFXNgSbSmkNvCoL2T028A0a1JaJLzRMlFoHg==",
    + "requires": {
    + "querystringify": "^2.0.0",
    + "requires-port": "^1.0.0"
    + }
    + },
    + "url-regex": {
    + "version": "3.2.0",
    + "resolved": "https://registry.npmjs.org/url-regex/-/url-regex-3.2.0.tgz",
    + "integrity": "sha1-260eDJ4p4QXdCx8J9oYvf9tIJyQ=",
    + "requires": {
    + "ip-regex": "^1.0.1"
    + }
    + },
    + "util-deprecate": {
    + "version": "1.0.2",
    + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
    + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
    + },
    "util.promisify": {
    "version": "1.0.0",
    "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz",
    @@ -570,15 +1456,81 @@
    "object.getownpropertydescriptors": "^2.0.3"
    }
    },
    + "uuid": {
    + "version": "3.3.2",
    + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz",
    + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA=="
    + },
    + "verror": {
    + "version": "1.10.0",
    + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
    + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
    + "requires": {
    + "assert-plus": "^1.0.0",
    + "core-util-is": "1.0.2",
    + "extsprintf": "^1.2.0"
    + }
    + },
    "wrappy": {
    "version": "1.0.2",
    "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
    "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
    },
    + "ws": {
    + "version": "6.2.0",
    + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.0.tgz",
    + "integrity": "sha512-deZYUNlt2O4buFCa3t5bKLf8A7FPP/TVjwOeVNpw818Ma5nk4MLXls2eoEGS39o8119QIYxTrTDoPQ5B/gTD6w==",
    + "requires": {
    + "async-limiter": "~1.0.0"
    + }
    + },
    + "xhr": {
    + "version": "2.5.0",
    + "resolved": "https://registry.npmjs.org/xhr/-/xhr-2.5.0.tgz",
    + "integrity": "sha512-4nlO/14t3BNUZRXIXfXe+3N6w3s1KoxcJUUURctd64BLRe67E4gRwp4PjywtDY72fXpZ1y6Ch0VZQRY/gMPzzQ==",
    + "requires": {
    + "global": "~4.3.0",
    + "is-function": "^1.0.1",
    + "parse-headers": "^2.0.0",
    + "xtend": "^4.0.0"
    + }
    + },
    + "xml-parse-from-string": {
    + "version": "1.0.1",
    + "resolved": "https://registry.npmjs.org/xml-parse-from-string/-/xml-parse-from-string-1.0.1.tgz",
    + "integrity": "sha1-qQKekp09vN7RafPG4oI42VpdWig="
    + },
    + "xml2js": {
    + "version": "0.4.19",
    + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz",
    + "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==",
    + "requires": {
    + "sax": ">=0.6.0",
    + "xmlbuilder": "~9.0.1"
    + }
    + },
    + "xmlbuilder": {
    + "version": "9.0.7",
    + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz",
    + "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0="
    + },
    + "xtend": {
    + "version": "4.0.1",
    + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
    + "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68="
    + },
    "yallist": {
    "version": "2.1.2",
    "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
    "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI="
    + },
    + "yauzl": {
    + "version": "2.4.1",
    + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.4.1.tgz",
    + "integrity": "sha1-lSj0QtqxsihOWLQ3m7GU4i4MQAU=",
    + "requires": {
    + "fd-slicer": "~1.0.1"
    + }
    }
    }
    }
    --- a/package.json Mon Feb 11 12:43:24 2019 -0500
    +++ b/package.json Thu May 16 22:10:20 2019 -0400
    @@ -1,5 +1,6 @@
    {
    "dependencies": {
    + "differencify": "^1.5.3",
    "js-beautify": "^1.8.9",
    "svgo": "^1.1.1"
    },
    @@ -7,6 +8,8 @@
    "front-matter": "^3.0.1"
    },
    "scripts": {
    - "tidy": "node tools/pre-prod"
    + "regression":"node tools/visual-diff.js",
    + "tidy": "node tools/pre-prod",
    + "migration-tracker": "node tools/migrate-tracker.js"
    }
    }
    --- a/readme.md Mon Feb 11 12:43:24 2019 -0500
    +++ b/readme.md Thu May 16 22:10:20 2019 -0400
    @@ -39,3 +39,9 @@
    ## Hugo config
    To disable **Copy Code to Clipboard** the `disableInlineCopyToClipBoard` switch can be used either in **config** `[params]` **or** in the front matter of the individual page
    +
    +## Tools
    +
    +* **Visual Regression**
    + 1. [Run dev server](#Developing-Docs)
    + 1. To run the visual diff tool call `node tools/visual-diff.js` or `npm run regression`
    \ No newline at end of file
    --- a/tools/migrate-tracker.js Mon Feb 11 12:43:24 2019 -0500
    +++ b/tools/migrate-tracker.js Thu May 16 22:10:20 2019 -0400
    @@ -5,6 +5,9 @@
    const paths = fs
    .readFileSync(path.join(__dirname, "paths.txt"), "utf8")
    .split("\r\n");
    +const obsoleteRegex = /\s#(\s+)?obsolete(\s+)?$/i;
    +const migrating = paths.filter(path => !obsoleteRegex.test("# obsolete"));
    +
    const covered = new Set();
    function getFront(path) {
    @@ -66,11 +69,13 @@
    })
    .forEach(page => page.replaces.forEach(path => covered.add(path)));
    -const countOfCovered = paths.reduce(
    +const countOfCovered = migrating.reduce(
    (acc, path) => acc + (covered.has(path) ? 1 : 0),
    0
    );
    +const percentComplete = (countOfCovered / migrating.length * 100).toPrecision(2);
    +const countOfObsolete = paths.length - migrating.length;
    console.log(
    - `Currently there are ${countOfCovered} of ${paths.length} pages covered`
    + `tracking ${paths.length} pages, ${countOfCovered}/${migrating.length} (${percentComplete}%) migrated, ${countOfObsolete} obsoleted`
    );
    --- a/tools/paths.txt Mon Feb 11 12:43:24 2019 -0500
    +++ b/tools/paths.txt Thu May 16 22:10:20 2019 -0400
    @@ -7,20 +7,17 @@
    pidgin.im/download/mac/
    pidgin.im/download/source/
    planet.pidgin.im/
    -planet.pidgin.im/
    -planet.pidgin.im/rss20.xml
    -planet.pidgin.im/atom.xml
    planet.pidgin.im/rss20.xml
    planet.pidgin.im/atom.xml
    -developer.pidgin.im/wiki/Adola
    -developer.pidgin.im/wiki/AfterTwoOhOh
    -developer.pidgin.im/wiki/AliasFunctionReview
    +developer.pidgin.im/wiki/Adola # obsolete
    +developer.pidgin.im/wiki/AfterTwoOhOh # obsolete
    +developer.pidgin.im/wiki/AliasFunctionReview # obsolete
    developer.pidgin.im/wiki/Are%20the%20packages%20signed
    -developer.pidgin.im/wiki/Authors
    -developer.pidgin.im/wiki/BadContent
    -developer.pidgin.im/wiki/BranchStatus
    +developer.pidgin.im/wiki/Authors # obsolete
    +developer.pidgin.im/wiki/BadContent # obsolete
    +developer.pidgin.im/wiki/BranchStatus # obsolete
    developer.pidgin.im/wiki/BuddyListThemes
    -developer.pidgin.im/wiki/BugTracking
    +developer.pidgin.im/wiki/BugTracking # obsolete
    developer.pidgin.im/wiki/Building%20Pidgin
    developer.pidgin.im/wiki/BuildingWinPidgin
    developer.pidgin.im/wiki/BuildingWinPidgin/3.0.0
    @@ -37,31 +34,31 @@
    developer.pidgin.im/wiki/CHowTo/RequestAPIHowTo
    developer.pidgin.im/wiki/CHowTo/SignalsHowTo
    developer.pidgin.im/wiki/CHowTo/Valgrind
    -developer.pidgin.im/wiki/CamelCase
    +developer.pidgin.im/wiki/CamelCase # obsolete
    developer.pidgin.im/wiki/CertMgr
    developer.pidgin.im/wiki/CertMgr/Log
    developer.pidgin.im/wiki/CertMgr/ToDo
    -developer.pidgin.im/wiki/ChangeLog
    +developer.pidgin.im/wiki/ChangeLog # obsolete
    developer.pidgin.im/wiki/ConfigurationFiles
    developer.pidgin.im/wiki/ConversationThemes
    -developer.pidgin.im/wiki/DbusHowto
    -developer.pidgin.im/wiki/Dependencies
    -developer.pidgin.im/wiki/Dependencies/3.0.0
    +developer.pidgin.im/wiki/DbusHowto # obsolete
    +developer.pidgin.im/wiki/Dependencies # obsolete
    +developer.pidgin.im/wiki/Dependencies/3.0.0 # obsolete
    developer.pidgin.im/wiki/DesignGuidelines
    -developer.pidgin.im/wiki/DeveloperPages
    +developer.pidgin.im/wiki/DeveloperPages # obsolete
    developer.pidgin.im/wiki/Development%20FAQ
    -developer.pidgin.im/wiki/Doxygen
    -developer.pidgin.im/wiki/EditorConfigs
    +developer.pidgin.im/wiki/Doxygen # obsolete
    +developer.pidgin.im/wiki/EditorConfigs # obsolete
    developer.pidgin.im/wiki/EndToEndXMPPCrypto
    developer.pidgin.im/wiki/FAQ
    developer.pidgin.im/wiki/FAQAllInOne
    developer.pidgin.im/wiki/FAQssl
    developer.pidgin.im/wiki/FSUES
    -developer.pidgin.im/wiki/FinchFeat
    -developer.pidgin.im/wiki/FreeNode
    -developer.pidgin.im/wiki/FullChangeLog
    -developer.pidgin.im/wiki/FunPidgin
    -developer.pidgin.im/wiki/GObjectFeatures
    +developer.pidgin.im/wiki/FinchFeat # obsolete
    +developer.pidgin.im/wiki/FreeNode # obsolete
    +developer.pidgin.im/wiki/FullChangeLog # obsolete
    +developer.pidgin.im/wiki/FunPidgin # obsolete
    +developer.pidgin.im/wiki/GObjectFeatures # obsolete
    developer.pidgin.im/wiki/GSoC2008/FinchImprovements
    developer.pidgin.im/wiki/GSoC2008/MasterPassword
    developer.pidgin.im/wiki/GSoC2008/ThemeImprovements
    @@ -89,74 +86,74 @@
    developer.pidgin.im/wiki/GSoC2012/Android/new-client
    developer.pidgin.im/wiki/GSoC2012/Android/structure
    developer.pidgin.im/wiki/GSoC2012/Statscollector
    -developer.pidgin.im/wiki/GTK3
    +developer.pidgin.im/wiki/GTK3 # obsolete
    developer.pidgin.im/wiki/GetABacktrace
    -developer.pidgin.im/wiki/GntEntry
    -developer.pidgin.im/wiki/Gobjectification
    +developer.pidgin.im/wiki/GntEntry # obsolete
    +developer.pidgin.im/wiki/Gobjectification # obsolete
    developer.pidgin.im/wiki/Help
    -developer.pidgin.im/wiki/HelpWanted
    -developer.pidgin.im/wiki/ICQEncodingProgress
    -developer.pidgin.im/wiki/ICQStatusMessagesProgress
    -developer.pidgin.im/wiki/IdeaForMTNBranches
    -developer.pidgin.im/wiki/Igd
    +developer.pidgin.im/wiki/HelpWanted # obsolete
    +developer.pidgin.im/wiki/ICQEncodingProgress # obsolete
    +developer.pidgin.im/wiki/ICQStatusMessagesProgress # obsolete
    +developer.pidgin.im/wiki/IdeaForMTNBranches # obsolete
    +developer.pidgin.im/wiki/Igd # obsolete
    developer.pidgin.im/wiki/ImportCustomSmileysFromEmesene
    developer.pidgin.im/wiki/Installing%20Pidgin
    developer.pidgin.im/wiki/Installing%20Pidgin%20on%20Ubuntu
    developer.pidgin.im/wiki/Installing%20Pidgin%20on%20Windows
    -developer.pidgin.im/wiki/InterMapTxt
    -developer.pidgin.im/wiki/InterTrac
    -developer.pidgin.im/wiki/InterWiki
    -developer.pidgin.im/wiki/KeePass
    -developer.pidgin.im/wiki/KeyringSupport
    -developer.pidgin.im/wiki/List%20Of%20Supported%20Features
    -developer.pidgin.im/wiki/LocalTracChanges
    -developer.pidgin.im/wiki/Luke's%20Notes
    -developer.pidgin.im/wiki/MSNCertIssue
    -developer.pidgin.im/wiki/Maiku
    -developer.pidgin.im/wiki/MarkDoliner
    -developer.pidgin.im/wiki/Merchandise
    -developer.pidgin.im/wiki/MonoLoader
    -developer.pidgin.im/wiki/MonotoneBestPractices
    -developer.pidgin.im/wiki/MonotoneLimitations
    -developer.pidgin.im/wiki/MonotoneRcSnippets
    -developer.pidgin.im/wiki/MsimIMToDo
    -developer.pidgin.im/wiki/NateOn
    -developer.pidgin.im/wiki/NetworkManager
    -developer.pidgin.im/wiki/OpenBugs
    -developer.pidgin.im/wiki/OpenFire
    -developer.pidgin.im/wiki/OpenPatches
    -developer.pidgin.im/wiki/OpenTickets
    +developer.pidgin.im/wiki/InterMapTxt # obsolete
    +developer.pidgin.im/wiki/InterTrac # obsolete
    +developer.pidgin.im/wiki/InterWiki # obsolete
    +developer.pidgin.im/wiki/KeePass # obsolete
    +developer.pidgin.im/wiki/KeyringSupport # obsolete
    +developer.pidgin.im/wiki/List%20Of%20Supported%20Features # obsolete
    +developer.pidgin.im/wiki/LocalTracChanges # obsolete
    +developer.pidgin.im/wiki/Luke's%20Notes # obsolete
    +developer.pidgin.im/wiki/MSNCertIssue # obsolete
    +developer.pidgin.im/wiki/Maiku # obsolete
    +developer.pidgin.im/wiki/MarkDoliner # obsolete
    +developer.pidgin.im/wiki/Merchandise # obsolete
    +developer.pidgin.im/wiki/MonoLoader # obsolete
    +developer.pidgin.im/wiki/MonotoneBestPractices # obsolete
    +developer.pidgin.im/wiki/MonotoneLimitations # obsolete
    +developer.pidgin.im/wiki/MonotoneRcSnippets # obsolete
    +developer.pidgin.im/wiki/MsimIMToDo # obsolete
    +developer.pidgin.im/wiki/NateOn # obsolete
    +developer.pidgin.im/wiki/NetworkManager # obsolete
    +developer.pidgin.im/wiki/OpenBugs # obsolete
    +developer.pidgin.im/wiki/OpenFire # obsolete
    +developer.pidgin.im/wiki/OpenPatches # obsolete
    +developer.pidgin.im/wiki/OpenTickets # obsolete
    developer.pidgin.im/wiki/Openfire%20Client%20SSL%20Authentication%20How-to
    -developer.pidgin.im/wiki/PageTemplates
    -developer.pidgin.im/wiki/PalTalk
    -developer.pidgin.im/wiki/PatchesNeedingImprovement
    -developer.pidgin.im/wiki/PatchesNeedingReview
    -developer.pidgin.im/wiki/Perl_API
    -developer.pidgin.im/wiki/Pidgin%202.0%20Changelog
    +developer.pidgin.im/wiki/PageTemplates # obsolete
    +developer.pidgin.im/wiki/PalTalk # obsolete
    +developer.pidgin.im/wiki/PatchesNeedingImprovement # obsolete
    +developer.pidgin.im/wiki/PatchesNeedingReview # obsolete
    +developer.pidgin.im/wiki/Perl_API # obsolete
    +developer.pidgin.im/wiki/Pidgin%202.0%20Changelog # obsolete
    developer.pidgin.im/wiki/PidginCommunity
    -developer.pidgin.im/wiki/PidginTwoFiveSix
    -developer.pidgin.im/wiki/PidginWebsite
    +developer.pidgin.im/wiki/PidginTwoFiveSix # obsolete
    +developer.pidgin.im/wiki/PidginWebsite # obsolete
    developer.pidgin.im/wiki/PlainTextPasswords
    developer.pidgin.im/wiki/PossibleLicenseViolations
    developer.pidgin.im/wiki/PrivacyRewrite
    -developer.pidgin.im/wiki/ProgressReport
    +developer.pidgin.im/wiki/ProgressReport # obsolete
    developer.pidgin.im/wiki/Protocol%20Specific%20Questions
    developer.pidgin.im/wiki/PurpleArchitecture
    -developer.pidgin.im/wiki/PurpleCommander
    -developer.pidgin.im/wiki/PythonHowTo
    -developer.pidgin.im/wiki/QuLogic
    -developer.pidgin.im/wiki/RecentChanges
    -developer.pidgin.im/wiki/RejectedPatches
    +developer.pidgin.im/wiki/PurpleCommander # obsolete
    +developer.pidgin.im/wiki/PythonHowTo # obsolete
    +developer.pidgin.im/wiki/QuLogic # obsolete
    +developer.pidgin.im/wiki/RecentChanges # obsolete
    +developer.pidgin.im/wiki/RejectedPatches # obsolete
    developer.pidgin.im/wiki/ReleaseProcess
    developer.pidgin.im/wiki/RemoteLogging
    developer.pidgin.im/wiki/RightThingToDo
    -developer.pidgin.im/wiki/Roadmap3.0.0
    +developer.pidgin.im/wiki/Roadmap3.0.0 # obsolete
    developer.pidgin.im/wiki/SampleGtkrc2.0
    -developer.pidgin.im/wiki/SandBox
    +developer.pidgin.im/wiki/SandBox # obsolete
    developer.pidgin.im/wiki/Scripting%20and%20Plugins
    developer.pidgin.im/wiki/SecurityVulnerabilityProcess
    -developer.pidgin.im/wiki/Sim-on
    -developer.pidgin.im/wiki/SlpArchitecture
    +developer.pidgin.im/wiki/Sim-on # obsolete
    +developer.pidgin.im/wiki/SlpArchitecture # obsolete
    developer.pidgin.im/wiki/SmileyThemes
    developer.pidgin.im/wiki/SoCAndBountyIdeas
    developer.pidgin.im/wiki/SoCApplicationInstructions
    @@ -165,10 +162,10 @@
    developer.pidgin.im/wiki/SoundThemes
    developer.pidgin.im/wiki/SpreadPidginAvatars
    developer.pidgin.im/wiki/StatusIconThemes
    -developer.pidgin.im/wiki/SteamFriendsProtocolSpec
    -developer.pidgin.im/wiki/StupidMoronStu
    +developer.pidgin.im/wiki/SteamFriendsProtocolSpec # obsolete
    +developer.pidgin.im/wiki/StupidMoronStu # obsolete
    developer.pidgin.im/wiki/StyleGuide
    -developer.pidgin.im/wiki/Sulabh
    +developer.pidgin.im/wiki/Sulabh # obsolete
    developer.pidgin.im/wiki/SummerOfCode2007
    developer.pidgin.im/wiki/SummerOfCode2008
    developer.pidgin.im/wiki/SummerOfCode2009
    @@ -177,140 +174,140 @@
    developer.pidgin.im/wiki/SummerOfCode2012
    developer.pidgin.im/wiki/SummerOfCode2013
    developer.pidgin.im/wiki/SummerOfCode2015
    -developer.pidgin.im/wiki/SunStudio
    +developer.pidgin.im/wiki/SunStudio # obsolete
    developer.pidgin.im/wiki/SupportedXEPs
    -developer.pidgin.im/wiki/Telepathy
    -developer.pidgin.im/wiki/TelepathyHaze
    +developer.pidgin.im/wiki/Telepathy # obsolete
    +developer.pidgin.im/wiki/TelepathyHaze # obsolete
    developer.pidgin.im/wiki/ThemingPidgin
    developer.pidgin.im/wiki/ThirdPartyPlugins
    developer.pidgin.im/wiki/ThirdPartySmileyThemes
    -developer.pidgin.im/wiki/TicketStats
    +developer.pidgin.im/wiki/TicketStats # obsolete
    developer.pidgin.im/wiki/TipsForBugReports
    developer.pidgin.im/wiki/TipsForPatchReports
    developer.pidgin.im/wiki/TipsForPatchSubmissions
    developer.pidgin.im/wiki/TipsForTranslators
    -developer.pidgin.im/wiki/TitleIndex
    -developer.pidgin.im/wiki/TracAccessibility
    -developer.pidgin.im/wiki/TracAdmin
    -developer.pidgin.im/wiki/TracBackup
    -developer.pidgin.im/wiki/TracBatchModify
    -developer.pidgin.im/wiki/TracBrowser
    -developer.pidgin.im/wiki/TracCgi
    -developer.pidgin.im/wiki/TracChangeset
    -developer.pidgin.im/wiki/TracEnvironment
    -developer.pidgin.im/wiki/TracFastCgi
    -developer.pidgin.im/wiki/TracFineGrainedPermissions
    -developer.pidgin.im/wiki/TracGuide
    -developer.pidgin.im/wiki/TracImport
    -developer.pidgin.im/wiki/TracIni
    -developer.pidgin.im/wiki/TracInstall
    -developer.pidgin.im/wiki/TracInterfaceCustomization
    -developer.pidgin.im/wiki/TracLinks
    -developer.pidgin.im/wiki/TracLogging
    -developer.pidgin.im/wiki/TracModPython
    -developer.pidgin.im/wiki/TracModWSGI
    -developer.pidgin.im/wiki/TracNavigation
    -developer.pidgin.im/wiki/TracNotification
    -developer.pidgin.im/wiki/TracPermissions
    -developer.pidgin.im/wiki/TracPlugins
    -developer.pidgin.im/wiki/TracQuery
    -developer.pidgin.im/wiki/TracReports
    -developer.pidgin.im/wiki/TracRepositoryAdmin
    -developer.pidgin.im/wiki/TracRevisionLog
    -developer.pidgin.im/wiki/TracRoadmap
    -developer.pidgin.im/wiki/TracRss
    -developer.pidgin.im/wiki/TracSearch
    -developer.pidgin.im/wiki/TracStandalone
    -developer.pidgin.im/wiki/TracSupport
    -developer.pidgin.im/wiki/TracSyntaxColoring
    -developer.pidgin.im/wiki/TracTickets
    -developer.pidgin.im/wiki/TracTicketsCustomFields
    -developer.pidgin.im/wiki/TracTimeline
    -developer.pidgin.im/wiki/TracUnicode
    -developer.pidgin.im/wiki/TracUpgrade
    -developer.pidgin.im/wiki/TracWiki
    -developer.pidgin.im/wiki/TracWorkflow
    +developer.pidgin.im/wiki/TitleIndex # obsolete
    +developer.pidgin.im/wiki/TracAccessibility # obsolete
    +developer.pidgin.im/wiki/TracAdmin # obsolete
    +developer.pidgin.im/wiki/TracBackup # obsolete
    +developer.pidgin.im/wiki/TracBatchModify # obsolete
    +developer.pidgin.im/wiki/TracBrowser # obsolete
    +developer.pidgin.im/wiki/TracCgi # obsolete
    +developer.pidgin.im/wiki/TracChangeset # obsolete
    +developer.pidgin.im/wiki/TracEnvironment # obsolete
    +developer.pidgin.im/wiki/TracFastCgi # obsolete
    +developer.pidgin.im/wiki/TracFineGrainedPermissions # obsolete
    +developer.pidgin.im/wiki/TracGuide # obsolete
    +developer.pidgin.im/wiki/TracImport # obsolete
    +developer.pidgin.im/wiki/TracIni # obsolete
    +developer.pidgin.im/wiki/TracInstall # obsolete
    +developer.pidgin.im/wiki/TracInterfaceCustomization # obsolete
    +developer.pidgin.im/wiki/TracLinks # obsolete
    +developer.pidgin.im/wiki/TracLogging # obsolete
    +developer.pidgin.im/wiki/TracModPython # obsolete
    +developer.pidgin.im/wiki/TracModWSGI # obsolete
    +developer.pidgin.im/wiki/TracNavigation # obsolete
    +developer.pidgin.im/wiki/TracNotification # obsolete
    +developer.pidgin.im/wiki/TracPermissions # obsolete
    +developer.pidgin.im/wiki/TracPlugins # obsolete
    +developer.pidgin.im/wiki/TracQuery # obsolete
    +developer.pidgin.im/wiki/TracReports # obsolete
    +developer.pidgin.im/wiki/TracRepositoryAdmin # obsolete
    +developer.pidgin.im/wiki/TracRevisionLog # obsolete
    +developer.pidgin.im/wiki/TracRoadmap # obsolete
    +developer.pidgin.im/wiki/TracRss # obsolete
    +developer.pidgin.im/wiki/TracSearch # obsolete
    +developer.pidgin.im/wiki/TracStandalone # obsolete
    +developer.pidgin.im/wiki/TracSupport # obsolete
    +developer.pidgin.im/wiki/TracSyntaxColoring # obsolete
    +developer.pidgin.im/wiki/TracTickets # obsolete
    +developer.pidgin.im/wiki/TracTicketsCustomFields # obsolete
    +developer.pidgin.im/wiki/TracTimeline # obsolete
    +developer.pidgin.im/wiki/TracUnicode # obsolete
    +developer.pidgin.im/wiki/TracUpgrade # obsolete
    +developer.pidgin.im/wiki/TracWiki # obsolete
    +developer.pidgin.im/wiki/TracWorkflow # obsolete
    developer.pidgin.im/wiki/TranslationsAndStringFreezes
    -developer.pidgin.im/wiki/UpdateMsnSupport
    +developer.pidgin.im/wiki/UpdateMsnSupport # obsolete
    developer.pidgin.im/wiki/Using%20Finch
    developer.pidgin.im/wiki/Using%20Libpurple
    developer.pidgin.im/wiki/Using%20Pidgin
    developer.pidgin.im/wiki/UsingPidgin/N900
    developer.pidgin.im/wiki/UsingPidginMercurial
    -developer.pidgin.im/wiki/UsingPidginMonotone
    +developer.pidgin.im/wiki/UsingPidginMonotone # obsolete
    developer.pidgin.im/wiki/UsingThisSite
    -developer.pidgin.im/wiki/VirtualBox
    +developer.pidgin.im/wiki/VirtualBox # obsolete
    developer.pidgin.im/wiki/VirtualClassroom
    -developer.pidgin.im/wiki/WebKit
    -developer.pidgin.im/wiki/WebsiteDesignComps
    -developer.pidgin.im/wiki/WebsiteWireframes
    +developer.pidgin.im/wiki/WebKit # obsolete
    +developer.pidgin.im/wiki/WebsiteDesignComps # obsolete
    +developer.pidgin.im/wiki/WebsiteWireframes # obsolete
    developer.pidgin.im/wiki/WhatIsLibpurple
    developer.pidgin.im/wiki/WhyNoiOSVersion
    -developer.pidgin.im/wiki/WhyPackagesExist
    -developer.pidgin.im/wiki/WikiDeletePage
    -developer.pidgin.im/wiki/WikiFormatting
    -developer.pidgin.im/wiki/WikiHtml
    -developer.pidgin.im/wiki/WikiMacros
    -developer.pidgin.im/wiki/WikiNewPage
    -developer.pidgin.im/wiki/WikiPageNames
    -developer.pidgin.im/wiki/WikiProcessors
    -developer.pidgin.im/wiki/WikiRestructuredText
    -developer.pidgin.im/wiki/WikiRestructuredTextLinks
    +developer.pidgin.im/wiki/WhyPackagesExist # obsolete
    +developer.pidgin.im/wiki/WikiDeletePage # obsolete
    +developer.pidgin.im/wiki/WikiFormatting # obsolete
    +developer.pidgin.im/wiki/WikiHtml # obsolete
    +developer.pidgin.im/wiki/WikiMacros # obsolete
    +developer.pidgin.im/wiki/WikiNewPage # obsolete
    +developer.pidgin.im/wiki/WikiPageNames # obsolete
    +developer.pidgin.im/wiki/WikiProcessors # obsolete
    +developer.pidgin.im/wiki/WikiRestructuredText # obsolete
    +developer.pidgin.im/wiki/WikiRestructuredTextLinks # obsolete
    developer.pidgin.im/wiki/WikiStart
    -developer.pidgin.im/wiki/XDG_dirs
    -developer.pidgin.im/wiki/akronix
    -developer.pidgin.im/wiki/aluink
    -developer.pidgin.im/wiki/bartosz
    -developer.pidgin.im/wiki/caseyho
    -developer.pidgin.im/wiki/charkins
    -developer.pidgin.im/wiki/darkrain42
    -developer.pidgin.im/wiki/datallah
    -developer.pidgin.im/wiki/davidgray
    -developer.pidgin.im/wiki/db42
    -developer.pidgin.im/wiki/deryni
    -developer.pidgin.im/wiki/ecoffey
    -developer.pidgin.im/wiki/ehempel
    -developer.pidgin.im/wiki/elb
    -developer.pidgin.im/wiki/evands
    -developer.pidgin.im/wiki/felipec
    -developer.pidgin.im/wiki/ffdragon
    -developer.pidgin.im/wiki/fmoo
    -developer.pidgin.im/wiki/gillux
    -developer.pidgin.im/wiki/grim
    -developer.pidgin.im/wiki/hanzz
    -developer.pidgin.im/wiki/hbons
    -developer.pidgin.im/wiki/ivan.komarov
    -developer.pidgin.im/wiki/jeff
    -developer.pidgin.im/wiki/joekepley
    -developer.pidgin.im/wiki/khc
    -developer.pidgin.im/wiki/kkszysiu
    -developer.pidgin.im/wiki/kstange
    -developer.pidgin.im/wiki/lschiere
    -developer.pidgin.im/wiki/malu
    -developer.pidgin.im/wiki/mmcco
    -developer.pidgin.im/wiki/mshkutkov
    -developer.pidgin.im/wiki/nakulgulati
    -developer.pidgin.im/wiki/nosnilmot
    -developer.pidgin.im/wiki/nwalp
    -developer.pidgin.im/wiki/prekshu
    -developer.pidgin.im/wiki/prpl_id
    -developer.pidgin.im/wiki/queueram
    -developer.pidgin.im/wiki/rekkanoryo
    -developer.pidgin.im/wiki/resiak
    -developer.pidgin.im/wiki/rlaager
    -developer.pidgin.im/wiki/ryanb
    -developer.pidgin.im/wiki/sadrul
    -developer.pidgin.im/wiki/salinasv
    -developer.pidgin.im/wiki/scrouaf
    -developer.pidgin.im/wiki/seanegan
    -developer.pidgin.im/wiki/sgarrity
    -developer.pidgin.im/wiki/shellreef
    +developer.pidgin.im/wiki/XDG_dirs # obsolete
    +developer.pidgin.im/wiki/akronix # obsolete
    +developer.pidgin.im/wiki/aluink # obsolete
    +developer.pidgin.im/wiki/bartosz # obsolete
    +developer.pidgin.im/wiki/caseyho # obsolete
    +developer.pidgin.im/wiki/charkins # obsolete
    +developer.pidgin.im/wiki/darkrain42 # obsolete
    +developer.pidgin.im/wiki/datallah # obsolete
    +developer.pidgin.im/wiki/davidgray # obsolete
    +developer.pidgin.im/wiki/db42 # obsolete
    +developer.pidgin.im/wiki/deryni # obsolete
    +developer.pidgin.im/wiki/ecoffey # obsolete
    +developer.pidgin.im/wiki/ehempel # obsolete
    +developer.pidgin.im/wiki/elb # obsolete
    +developer.pidgin.im/wiki/evands # obsolete
    +developer.pidgin.im/wiki/felipec # obsolete
    +developer.pidgin.im/wiki/ffdragon # obsolete
    +developer.pidgin.im/wiki/fmoo # obsolete
    +developer.pidgin.im/wiki/gillux # obsolete
    +developer.pidgin.im/wiki/grim # obsolete
    +developer.pidgin.im/wiki/hanzz # obsolete
    +developer.pidgin.im/wiki/hbons # obsolete
    +developer.pidgin.im/wiki/ivan.komarov # obsolete
    +developer.pidgin.im/wiki/jeff # obsolete
    +developer.pidgin.im/wiki/joekepley # obsolete
    +developer.pidgin.im/wiki/khc # obsolete
    +developer.pidgin.im/wiki/kkszysiu # obsolete
    +developer.pidgin.im/wiki/kstange # obsolete
    +developer.pidgin.im/wiki/lschiere # obsolete
    +developer.pidgin.im/wiki/malu # obsolete
    +developer.pidgin.im/wiki/mmcco # obsolete
    +developer.pidgin.im/wiki/mshkutkov # obsolete
    +developer.pidgin.im/wiki/nakulgulati # obsolete
    +developer.pidgin.im/wiki/nosnilmot # obsolete
    +developer.pidgin.im/wiki/nwalp # obsolete
    +developer.pidgin.im/wiki/prekshu # obsolete
    +developer.pidgin.im/wiki/prpl_id # obsolete
    +developer.pidgin.im/wiki/queueram # obsolete
    +developer.pidgin.im/wiki/rekkanoryo # obsolete
    +developer.pidgin.im/wiki/resiak # obsolete
    +developer.pidgin.im/wiki/rlaager # obsolete
    +developer.pidgin.im/wiki/ryanb # obsolete
    +developer.pidgin.im/wiki/sadrul # obsolete
    +developer.pidgin.im/wiki/salinasv # obsolete
    +developer.pidgin.im/wiki/scrouaf # obsolete
    +developer.pidgin.im/wiki/seanegan # obsolete
    +developer.pidgin.im/wiki/sgarrity # obsolete
    +developer.pidgin.im/wiki/shellreef # obsolete
    developer.pidgin.im/wiki/shortcuts
    -developer.pidgin.im/wiki/siege
    -developer.pidgin.im/wiki/sttwister
    -developer.pidgin.im/wiki/typ0
    -developer.pidgin.im/wiki/utopianheaven
    -developer.pidgin.im/wiki/vv
    -developer.pidgin.im/wiki/vvAPI
    -developer.pidgin.im/wiki/wabz
    -developer.pidgin.im/wiki/wehlhard
    \ No newline at end of file
    +developer.pidgin.im/wiki/siege # obsolete
    +developer.pidgin.im/wiki/sttwister # obsolete
    +developer.pidgin.im/wiki/typ0 # obsolete
    +developer.pidgin.im/wiki/utopianheaven # obsolete
    +developer.pidgin.im/wiki/vv # obsolete
    +developer.pidgin.im/wiki/vvAPI # obsolete
    +developer.pidgin.im/wiki/wabz # obsolete
    +developer.pidgin.im/wiki/wehlhard # obsolete
    \ No newline at end of file
    --- /dev/null Thu Jan 01 00:00:00 1970 +0000
    +++ b/tools/visual-diff.js Thu May 16 22:10:20 2019 -0400
    @@ -0,0 +1,164 @@
    +try {
    + var config = require('./diff-config.json')
    +} catch (e) {
    + config = {}
    +}
    +
    +const {
    + dir = 'http://localhost:1313',
    + waitToScreenShotTime = 500,
    + additionalPages = ['404.html'],
    + verbose = false,
    + maxJobs = 15,
    +} = config
    +
    +console.log('Config being used', {
    + dir,
    + waitToScreenShotTime,
    + additionalPages,
    + verbose,
    + maxJobs,
    +})
    +
    +const fetch = require(/^http:/.test(dir) ? 'http' : 'https')
    +
    +const Differencify = require('differencify')
    +const differencify = new Differencify()
    +
    +// WARNING: Chnaging these values may invalidate previous snapshots
    +const viewports = Object.freeze({
    + phone: Object.freeze({ width: 320, height: 1000 }),
    + tablet: Object.freeze({ width: 768, height: 4000 }),
    + massive: Object.freeze({ width: 1440, height: 4000 }),
    +})
    +const viewportKeys = Object.keys(viewports)
    +const nonIdentical = []
    +
    +;(async () => {
    + const stack = []
    + // Map the target pages
    + const pages = (await fetch_json(`${dir}/index.json`))
    + .map(u => u.uri)
    + .concat(additionalPages.map(p => `${dir}/${p}`))
    + .sort()
    +
    + console.log(`Diffing these pages:`)
    +
    + // Populates stack with tests
    + for (const pagePath of pages) {
    + console.log('\t' + pagePath.trim().replace(dir, ''))
    +
    + for (const viewportName of viewportKeys) {
    + stack.push(() => checkPage(pagePath, viewportName))
    + }
    + }
    +
    + // Run tests
    + await differencify.launchBrowser({ timeout: 0 })
    + await concurrence(stack)
    + await differencify.cleanup()
    +
    + // Output results
    + if (nonIdentical.length) {
    + console.log(`Pages that have changed:`)
    + console.log(
    + nonIdentical
    + .sort()
    + .map(p => '\t' + p)
    + .join('\n')
    + )
    + } else {
    + console.log('No differences detected')
    + }
    +})()
    +
    +/**
    + * Handles Differencify
    + * @param {string} url path to page
    + * @param {string} viewportName key to viewport config
    + */
    +async function checkPage(url, viewportName) {
    + const viewport = viewports[viewportName]
    + const path = url.replace(dir, '')
    + const testName = `page-${viewportName}-${safeFileName(path)}`
    +
    + try {
    + await differencify
    + .init({ testName, timeout: 0 })
    + .newPage()
    + .setViewport(viewport)
    + .goto(url)
    + .wait(waitToScreenShotTime)
    + .screenshot()
    + .toMatchSnapshot()
    + .result(result => {
    + if (!result) nonIdentical.push(`${viewportName} ${path}`)
    + })
    + .close()
    + .end()
    + } catch (error) {
    + console.error(error)
    + }
    +
    + if (verbose) console.log(`checked ${viewportName} ${path}`)
    +}
    +
    +/**
    + * Fetches and parses JSON from web resource
    + * @param {string} url to resource to fetch
    + */
    +function fetch_json(url) {
    + return new Promise(resolve =>
    + fetch.get(url, res => {
    + res.setEncoding('utf8')
    + let body = ''
    + res.on('data', data => (body += data))
    + res.on('end', () => resolve(JSON.parse(body)))
    + })
    + )
    +}
    +
    +/**
    + * Creates a file safe string
    + * @param {string} str Possibly unsafe url
    + */
    +function safeFileName(str) {
    + return str
    + .replace(/[^a-z0-9]/gi, '_')
    + .toLowerCase()
    + .replace(/^_|_$/, '')
    +}
    +
    +/**
    + * Handles concurrence
    + * @param {Function[]} stack The fucntions to be called
    + */
    +function concurrence(stack) {
    + const er = e => console.error(e)
    + let count = 0
    +
    + return new Promise(resolve => {
    + pull()
    +
    + function pull() {
    + while (count < maxJobs) {
    + let fn = stack.pop()
    +
    + if (!fn) return
    +
    + fn()
    + .catch(er)
    + .then(cont)
    + .catch(er)
    +
    + count++
    + }
    + }
    +
    + function cont() {
    + count--
    + if (count === 0 && stack.length === 0) return resolve()
    + pull()
    + }
    + }).catch(er)
    +}