<commit_before>//= require js-cookie/v2.0.2
//= require mustache

/*
 * Plugin Name: Jquery Shopping Cart
 *
 * Author: Instant Website Team
 *
 * Note: Call Jquery Shopping Cart after jQuery in Application JS loaded
 */

window.addEventListener("load", function() {
  (function($) {

    ShoppingCart = function(element) {
      this.item = null;
      this.$element = null;
      this.cart = [];
      this.locales = null;

      this.init(element);
    }

    ShoppingCart.prototype.init = function(element) {
      this.$element     = $(element);
      this.locales      = this.$element.data('ecommerce-locales')
      this.checkoutUrl  = this.$element.data('checkout-url')
      this.assignCookieToCart();
      this.bindClickAddToCart();
      this.updateItemInList();
      this.updateTotalItems();
      this.bindClickCartIcon();
      this.bindClickDocument();
    }

    ShoppingCart.prototype.assignCookieToCart = function() {
      var getCookieVal = Cookies.getJSON('shopping-cart');

      if(getCookieVal != undefined) {
        this.cart = getCookieVal.items;
      }
    }

    ShoppingCart.prototype.bindClickDocument = function() {
      var $element = this.$element;

      $(document).on('click', function (e) {
        var container = $('.shopping-cart-icon')

        if (!container.is(e.target) && container.has(e.target).length === 0) {
          $element.find('.badge-open').removeClass('badge-show')
        }
      });
    }

    ShoppingCart.prototype.bindClickCartIcon = function() {
      var $element = this.$element;

      $element.find('.shop-badge').on('click', function() {
        $element.find('.badge-open').toggleClass('badge-show');
      })
    }

    ShoppingCart.prototype.bindClickAddToCart = function() {
      var self = this;

      this.$element.find('.js-add-to-cart').each(function() {
        $(this).click(function() {
          var qty = self.$element.find('#js-item-qty').val() || 1;

          if(self.isPositiveNumber(qty)) {
            var  product = $(this).data('product').product;

            product.quantity = parseInt(qty);
            self.item = product;

            self.addToCart();
            self.updateTotalItems();
            self.flyImageToCart();
          }
        });
      });
    }

    ShoppingCart.prototype.addToCart = function() {
      this.assignCookieToCart();

      if(this.itemExists()) {
        this.updateItem();
      }else {
        this.addItem();
      }

      this.updateItemInList();
    }

    ShoppingCart.prototype.flyImageToCart = function() {
      var wrapper = $("#js-fly-image-to-cart-box"),
        imgToDrag = wrapper.find("img").eq(0),
        top       = (wrapper.offset().top + wrapper.outerHeight()/2) - 75,
        left      = (wrapper.offset().left + wrapper.outerWidth()/2) - 75,
        cartIcon  = this.$element.find(".shop-badge"),
        imgclone;

      if (imgToDrag) {
          imgclone = imgToDrag.clone()
          .offset({
            top: top,
            left: left
        })
          .css({
            'opacity':  '0.5',
            'z-index':  '100',
            'width':    '150px',
            'height':   '150px',
            'position': 'absolute'
        })
          .appendTo($('body'))
          .animate({
            'width': 45,
            'height': 45,
            'top': cartIcon.offset().top + 10,
            'left': cartIcon.offset().left + 10
        }, 1200, 'easeInOutExpo');

        setTimeout(function () {
            cartIcon.effect("shake", {
              times: 2
            }, 200);
        }, 1500);

        imgclone.animate({
          'width': 0,
          'height': 0
        }, function () {
          $(this).detach()
        });
      }
    }

    ShoppingCart.prototype.addItem = function() {
      this.cart.push(this.item);
    }

    ShoppingCart.prototype.updateItem = function() {
      var cart = this.cart,
          item = this.item;

      for(var i=0; i<cart.length; i++) {
        if (cart[i]["id"] == item.id) {
          cart[i]["quantity"] += item.quantity;
        }
      }

      this.cart = cart;
    }

    ShoppingCart.prototype.bindClickRemoveFromCart = function() {
      var self = this;

      this.$element.find('.remove-from-cart').each(function() {
        $(this).on("click", function(e) {
          e.stopPropagation();

          self.removeItem($(this).data('id'));
          self.updateTotalItems();
        })
      })
    }

    ShoppingCart.prototype.removeItem = function(item_id) {
      var cart = this.cart;

      for(var i=0; i<cart.length; i++) {
        if (cart[i]["id"] == item_id) {
          cart = $.grep(cart, function(value) {
            return value != cart[i];
          });
        }
      }

      this.cart = cart;
      this.updateItemInList();
      this.$element.find('.badge-open').addClass('badge-show')
    }

    ShoppingCart.prototype.updateTotalItems = function() {
      var cart = this.cart,
          totalItems = 0;

      for(var i=0; i<cart.length; i++) {
        totalItems += cart[i]["quantity"];
      }

      this.$element.find('#total-items').html(totalItems);
    }

    ShoppingCart.prototype.getTotal = function() {
      var cart = this.cart,
          subtotal = 0,
          total = 0,
          currencyCode = $('body').data('currency-code');

      for(var i=0; i<cart.length; i++) {
        subtotal = cart[i]['quantity'] * cart[i]['price'];

        total += subtotal;
      }

      return this.formatCurrency(total, currencyCode);
    }

    ShoppingCart.prototype.itemExists = function() {
      var cart = this.cart,
          item  = this.item;

      for(var i=0; i<cart.length; i++) {
        if (cart[i]["id"] == item.id) return true;
      }
    }

    ShoppingCart.prototype.updateItemInList = function() {
      var cart = this.cart,
          $unOrderList = $('
'),
          $liSubtotal  = $('
');

          $unOrderList.append(this.buildLiHeader());

          for(var i=0; i<cart.length; i++) {
            $unOrderList.append(this.buildItemLi(cart[i]));
          }

      $unOrderList.append(this.buildSubtotalLi());
      $('#shopping-cart-list').html($unOrderList);

      this.bindClickRemoveFromCart();
      this.emptyCart();
      this.toggleBadge();
      Cookies.set('shopping-cart', { items: this.cart });
    }

    ShoppingCart.prototype.buildLiHeader = function() {
      $liHeader = $('
'),
      $h4 = $('
').text(this.locales.shopping_cart);

      return $liHeader.append($h4);
    }

    ShoppingCart.prototype.buildItemLi = function(item) {
      var currencyCode = $('body').data('currency-code'),
          qtyWithPrice = item.quantity + " x " + item.price + " " + currencyCode,
          $li = $('
'),
          $wrapperLeft = $('
'),
          $wrapperRight = $('
'),
          $imgWrapper = $('
'),
          $img = $('').attr({src: item.image_url}),

          $button = $('<button type="button" class="close remove-from-cart"/>'),
          $overflowH = $('
'),
          $link = $('').text(item.name).attr({href: item.url}),
          $small = $('').text(qtyWithPrice);

      $button.attr({'data-id': item.id}).text("×");
      $imgWrapper.append($img);
      $wrapperLeft.append($imgWrapper);
      $overflowH.append($link, $small)
      $wrapperRight.append($button, $overflowH)

      return $li.append($wrapperLeft, $wrapperRight);
    }

    ShoppingCart.prototype.buildSubtotalLi = function() {
      var totalCost = this.getTotal(),
          $li = $('
'),
          $div = $('
'),
          $spanLabel = $('').text(this.locales.subtotal),
          $spanCost = $('').text(totalCost);
          $btnCheckout = $('').text(this.locales.checkout);

      $div.append($spanLabel, $spanCost);

      return $li.append($div, this.checkoutForm());
    }

    ShoppingCart.prototype.checkoutForm = function() {
      var template = $('#tmpl-checkout').html();
      var data = {
        'products': this.cart,
        'checkout_url': this.checkoutUrl
      };

      // TODO: checkout button locale
      Mustache.parse(template);   // optional, speeds up future uses
      return Mustache.render(template, data);
    }

    ShoppingCart.prototype.emptyCart = function() {
      $unOrderList = $('
'),
      $liEmptyMessage = $('
').text(this.locales.empty_cart);

      $unOrderList.append(this.buildLiHeader(), $liEmptyMessage);

      if(this.cart.length == 0 ) {
        $('#shopping-cart-list').html($unOrderList);
      }
    }

    ShoppingCart.prototype.toggleBadge = function() {
      if(this.cart.length == 0 ) {
        this.$element.find('#total-items').hide();
        $('.fa-shopping-cart').addClass('empty-cart');
      }else {
        this.$element.find('#total-items').show();
        $('.fa-shopping-cart').removeClass('empty-cart');
      }
    }

    ShoppingCart.prototype.isPositiveNumber = function(val) {
      var pattern = /^\d+$/;

      return pattern.test(val) && parseInt(val) > 0
    }

    ShoppingCart.prototype.formatCurrency = function(num, currency) {
      return num.toFixed(2).replace(/(\d)(?=(\d{3})+\.)/g, "$1,") + " " + currency;
    }

    function Plugin() {
      return new ShoppingCart(this);
    }

    var old = $.fn.shoppingCart;

    $.fn.shoppingCart = Plugin;
    $.fn.shoppingCart.Constructor = ShoppingCart;

    // SHOPPING CART NO CONFLICT
    // =================================

    $.fn.shoppingCart.noConflict = function () {
      $.fn.shoppingCart = old;
      return this;
    }

  }(jQuery));

  // init jquery shopping cart
  $('.js-shopping-cart').shoppingCart();
});<commit_msg>fix effect image fly to cart when apply on muiltiple products<commit_after>//= require js-cookie/v2.0.2
//= require mustache

/*
 * Plugin Name: Jquery Shopping Cart
 *
 * Author: Instant Website Team
 *
 * Note: Call Jquery Shopping Cart after jQuery in Application JS loaded
 */

window.addEventListener("load", function() {
  (function($) {

    ShoppingCart = function(element) {
      this.item = null;
      this.$element = null;
      this.cart = [];
      this.locales = null;

      this.init(element);
    }

    ShoppingCart.prototype.init = function(element) {
      this.$element     = $(element);
      this.locales      = this.$element.data('ecommerce-locales')
      this.checkoutUrl  = this.$element.data('checkout-url')
      this.assignCookieToCart();
      this.bindClickAddToCart();
      this.updateItemInList();
      this.updateTotalItems();
      this.bindClickCartIcon();
      this.bindClickDocument();
    }

    ShoppingCart.prototype.assignCookieToCart = function() {
      var getCookieVal = Cookies.getJSON('shopping-cart');

      if(getCookieVal != undefined) {
        this.cart = getCookieVal.items;
      }
    }

    ShoppingCart.prototype.bindClickDocument = function() {
      var $element = this.$element;

      $(document).on('click', function (e) {
        var container = $('.shopping-cart-icon')

        if (!container.is(e.target) && container.has(e.target).length === 0) {
          $element.find('.badge-open').removeClass('badge-show')
        }
      });
    }

    ShoppingCart.prototype.bindClickCartIcon = function() {
      var $element = this.$element;

      $element.find('.shop-badge').on('click', function() {
        $element.find('.badge-open').toggleClass('badge-show');
      })
    }

    ShoppingCart.prototype.bindClickAddToCart = function() {
      var self = this;

      this.$element.find('.js-add-to-cart').each(function() {
        $(this).click(function() {
          var qty = self.$element.find('#js-item-qty').val() || 1;

          if(self.isPositiveNumber(qty)) {
            var  product = $(this).data('product').product;

            product.quantity = parseInt(qty);
            self.item = product;

            self.addToCart();
            self.updateTotalItems();
            self.flyImageToCart(this);
          }
        });
      });
    }

    ShoppingCart.prototype.addToCart = function() {
      this.assignCookieToCart();

      if(this.itemExists()) {
        this.updateItem();
      }else {
        this.addItem();
      }

      this.updateItemInList();
    }

    ShoppingCart.prototype.flyImageToCart = function(addToCartEl) {
      var wrapper = $(addToCartEl).closest(".js-shopping-cart"),
        imgToDrag = wrapper.find(".js-image-fly-to-cart").eq(0),
        top       = (imgToDrag.offset().top + (imgToDrag.outerHeight()/2)) - 75,
        left      = (imgToDrag.offset().left + imgToDrag.outerWidth()/2) - 75,
        cartIcon  = this.$element.find(".shop-badge"),
        imgclone;

      if (imgToDrag) {
          imgClone = imgToDrag.clone()
          .offset({
            top: top,
            left: left
        })
          .css({
            'opacity':  '0.5',
            'z-index':  '100',
            'width':    '150px',
            'height':   '150px',
            'position': 'absolute'
        })
          .appendTo($('body'))
          .animate({
            'width': 45,
            'height': 45,
            'top': cartIcon.offset().top + 10,
            'left': cartIcon.offset().left + 10
        }, 1200, 'easeInOutExpo');

        setTimeout(function () {
            cartIcon.effect("shake", {
              times: 2
            }, 200);
        }, 1500);

        imgClone.animate({
          'width': 0,
          'height': 0
        }, function () {
          $(this).detach()
        });
      }
    }

    ShoppingCart.prototype.addItem = function() {
      this.cart.push(this.item);
    }

    ShoppingCart.prototype.updateItem = function() {
      var cart = this.cart,
          item = this.item;

      for(var i=0; i<cart.length; i++) {
        if (cart[i]["id"] == item.id) {
          cart[i]["quantity"] += item.quantity;
        }
      }

      this.cart = cart;
    }

    ShoppingCart.prototype.bindClickRemoveFromCart = function() {
      var self = this;

      this.$element.find('.remove-from-cart').each(function() {
        $(this).on("click", function(e) {
          e.stopPropagation();

          self.removeItem($(this).data('id'));
          self.updateTotalItems();
        })
      })
    }

    ShoppingCart.prototype.removeItem = function(item_id) {
      var cart = this.cart;

      for(var i=0; i<cart.length; i++) {
        if (cart[i]["id"] == item_id) {
          cart = $.grep(cart, function(value) {
            return value != cart[i];
          });
        }
      }

      this.cart = cart;
      this.updateItemInList();
      this.$element.find('.badge-open').addClass('badge-show')
    }

    ShoppingCart.prototype.updateTotalItems = function() {
      var cart = this.cart,
          totalItems = 0;

      for(var i=0; i<cart.length; i++) {
        totalItems += cart[i]["quantity"];
      }

      this.$element.find('#total-items').html(totalItems);
    }

    ShoppingCart.prototype.getTotal = function() {
      var cart = this.cart,
          subtotal = 0,
          total = 0,
          currencyCode = $('body').data('currency-code');

      for(var i=0; i<cart.length; i++) {
        subtotal = cart[i]['quantity'] * cart[i]['price'];

        total += subtotal;
      }

      return this.formatCurrency(total, currencyCode);
    }

    ShoppingCart.prototype.itemExists = function() {
      var cart = this.cart,
          item  = this.item;

      for(var i=0; i<cart.length; i++) {
        if (cart[i]["id"] == item.id) return true;
      }
    }

    ShoppingCart.prototype.updateItemInList = function() {
      var cart = this.cart,
          $unOrderList = $('
'),
          $liSubtotal  = $('
');

          $unOrderList.append(this.buildLiHeader());

          for(var i=0; i<cart.length; i++) {
            $unOrderList.append(this.buildItemLi(cart[i]));
          }

      $unOrderList.append(this.buildSubtotalLi());
      $('#shopping-cart-list').html($unOrderList);

      this.bindClickRemoveFromCart();
      this.emptyCart();
      this.toggleBadge();
      Cookies.set('shopping-cart', { items: this.cart });
    }

    ShoppingCart.prototype.buildLiHeader = function() {
      $liHeader = $('
'),
      $h4 = $('
').text(this.locales.shopping_cart);

      return $liHeader.append($h4);
    }

    ShoppingCart.prototype.buildItemLi = function(item) {
      var currencyCode = $('body').data('currency-code'),
          qtyWithPrice = item.quantity + " x " + item.price + " " + currencyCode,
          $li = $('
'),
          $wrapperLeft = $('
'),
          $wrapperRight = $('
'),
          $imgWrapper = $('
'),
          $img = $('').attr({src: item.image_url}),

          $button = $('<button type="button" class="close remove-from-cart"/>'),
          $overflowH = $('
'),
          $link = $('').text(item.name).attr({href: item.url}),
          $small = $('').text(qtyWithPrice);

      $button.attr({'data-id': item.id}).text("×");
      $imgWrapper.append($img);
      $wrapperLeft.append($imgWrapper);
      $overflowH.append($link, $small)
      $wrapperRight.append($button, $overflowH)

      return $li.append($wrapperLeft, $wrapperRight);
    }

    ShoppingCart.prototype.buildSubtotalLi = function() {
      var totalCost = this.getTotal(),
          $li = $('
'),
          $div = $('
'),
          $spanLabel = $('').text(this.locales.subtotal),
          $spanCost = $('').text(totalCost);
          $btnCheckout = $('').text(this.locales.checkout);

      $div.append($spanLabel, $spanCost);

      return $li.append($div, this.checkoutForm());
    }

    ShoppingCart.prototype.checkoutForm = function() {
      var template = $('#tmpl-checkout').html();
      var data = {
        'products': this.cart,
        'checkout_url': this.checkoutUrl
      };

      // TODO: checkout button locale
      Mustache.parse(template);   // optional, speeds up future uses
      return Mustache.render(template, data);
    }

    ShoppingCart.prototype.emptyCart = function() {
      $unOrderList = $('
'),
      $liEmptyMessage = $('
').text(this.locales.empty_cart);

      $unOrderList.append(this.buildLiHeader(), $liEmptyMessage);

      if(this.cart.length == 0 ) {
        $('#shopping-cart-list').html($unOrderList);
      }
    }

    ShoppingCart.prototype.toggleBadge = function() {
      if(this.cart.length == 0 ) {
        this.$element.find('#total-items').hide();
        $('.fa-shopping-cart').addClass('empty-cart');
      }else {
        this.$element.find('#total-items').show();
        $('.fa-shopping-cart').removeClass('empty-cart');
      }
    }

    ShoppingCart.prototype.isPositiveNumber = function(val) {
      var pattern = /^\d+$/;

      return pattern.test(val) && parseInt(val) > 0
    }

    ShoppingCart.prototype.formatCurrency = function(num, currency) {
      return num.toFixed(2).replace(/(\d)(?=(\d{3})+\.)/g, "$1,") + " " + currency;
    }

    function Plugin() {
      return new ShoppingCart(this);
    }

    var old = $.fn.shoppingCart;

    $.fn.shoppingCart = Plugin;
    $.fn.shoppingCart.Constructor = ShoppingCart;

    // SHOPPING CART NO CONFLICT
    // =================================

    $.fn.shoppingCart.noConflict = function () {
      $.fn.shoppingCart = old;
      return this;
    }

  }(jQuery));

  // init jquery shopping cart
  $('.js-shopping-cart').shoppingCart();
});<|endoftext|>


<commit_before>import moment from 'moment';
import axios from 'axios';

export const REQUEST_OFFERS = 'REQUEST_OFFERS';
export function requestOffers() {
  return {
    type: REQUEST_OFFERS
  };
}

export const RECEIVE_OFFERS = 'RECEIVE_OFFERS';
export function receiveOffers(offers) {
  return {
    type: RECEIVE_OFFERS,
    offers,
    receivedAt: moment()
  };
}

export const INVALIDATE_OFFERS = 'INVALIDATE_OFFERS';
export function invalidateOffers() {
  return {
    type: INVALIDATE_OFFERS
  }
}

export function fetchOffers() {
  return dispatch => {
    dispatch(requestOffers());
    return axios.get('/api/offers')
      .then(resp => dispatch(receiveOffers(resp.data)));
  }
}

function shouldFetchOffers(state) {
  const offers = state.offers;
  if (!offers) {
    return true;
  } else if (offers.isFetching) {
    return false;
  } else {
    return offers.didInvalidate;
  }
}

export function fetchOffersIfNeeded() {
  return (dispatch, getState) => {
    if (shouldFetchOffers(getState())) {
      return dispatch(fetchOffers());
    } else {
      return Promise.resolve();
    }
  }
}
<commit_msg>Add the filter action<commit_after>import moment from 'moment';
import axios from 'axios';

export const REQUEST_OFFERS = 'REQUEST_OFFERS';
export function requestOffers() {
  return {
    type: REQUEST_OFFERS
  };
}

export const RECEIVE_OFFERS = 'RECEIVE_OFFERS';
export function receiveOffers(offers) {
  return {
    type: RECEIVE_OFFERS,
    offers,
    receivedAt: moment()
  };
}

export const INVALIDATE_OFFERS = 'INVALIDATE_OFFERS';
export function invalidateOffers() {
  return {
    type: INVALIDATE_OFFERS
  }
}

export function fetchOffers() {
  return dispatch => {
    dispatch(requestOffers());
    return axios.get('/api/offers')
      .then(resp => dispatch(receiveOffers(resp.data)));
  }
}

export const FILTER_OFFER = 'FILTER_OFFER';
export function filterOffer(text) {
  return {
    type: FILTER_OFFER,
    text
  }
}

function shouldFetchOffers(state) {
  const offers = state.offers;
  if (!offers) {
    return true;
  } else if (offers.isFetching) {
    return false;
  } else {
    return offers.didInvalidate;
  }
}

export function fetchOffersIfNeeded() {
  return (dispatch, getState) => {
    if (shouldFetchOffers(getState())) {
      return dispatch(fetchOffers());
    } else {
      return Promise.resolve();
    }
  }
}
<|endoftext|>


<commit_before>import { takeLatest, takeEvery } from 'redux-saga'
import { put, call } from 'redux-saga/effects'
import * as searchBoxActions from "./searchBoxActions"
import * as trackActions from "./trackActions"
import * as playlistActions from "./trackActions"
import endpoints from "../lib/media_endpoints";

export function* searchSaga() {
  yield* takeLatest(searchBoxActions.SET_SEARCH_QUERY, search)
}

function* search(action) {
  try {
    if (action.activeFeedId === 'playlists' || action.query === "") {
      return;
    }

    const results = yield call(endpoints['search_' + action.searchSource], action.query)

    yield put(searchBoxActions.receiveSearchResults(results))
  } catch (e) {
    if (e.type !== "MANUAL_CANCEL") {
      throw e
    }
  }
}

export function* addVoteSaga() {
  yield* takeEvery(
    [
      trackActions.TRACK_UPVOTE,
      trackActions.TRACK_DOWNVOTE,
      trackActions.PLAYLIST_UPVOTE,
      trackActions.PLAYLIST_DOWNVOTE,
    ]
    , addVote)
}

export function* addItemSaga() {
  yield* takeEvery(
    [
      trackActions.TRACK_ADD_NEW,
      playlistActions.PLAYLIST_ADD_NEW,
    ]
    , addItem)
}

export function* removeItemSaga() {
  yield* takeEvery(
    [
      trackActions.TRACK_REMOVE,
      playlistActions.PLAYLIST_REMOVE
    ]
    , removeItem)
}

function addVote(action) {
  console.log("action:",action);
  const { item } = action
  backend.call('add_vote', {
    id: item.id,
    vote: action.user_vote,
    type: item.type
  })
}

function* addItem(action) {
  const { item } = action
  backend.call('add_item', {
    ...item
  });
}

export function* removeItem(action) {
  const { item } = action
  backend.call('remove_item', {
    ...item
  });
}

export default [searchSaga, addVoteSaga, addItemSaga, removeItemSaga];
<commit_msg>Export saga helper functions so they can be tested<commit_after>import { takeLatest, takeEvery } from 'redux-saga'
import { put, call } from 'redux-saga/effects'
import * as searchBoxActions from "./searchBoxActions"
import * as trackActions from "./trackActions"
import * as playlistActions from "./trackActions"
import endpoints from "../lib/media_endpoints";

export function* searchSaga() {
  yield* takeLatest(searchBoxActions.SET_SEARCH_QUERY, search)
}

export function* search(action) {
  try {
    if (action.activeFeedId === 'playlists' || action.query === "") {
      return;
    }

    const results = yield call(endpoints['search_' + action.searchSource], action.query)

    yield put(searchBoxActions.receiveSearchResults(results))
  } catch (e) {
    if (e.type !== "MANUAL_CANCEL") {
      throw e
    }
  }
}

export function* addVoteSaga() {
  yield* takeEvery(
    [
      trackActions.TRACK_UPVOTE,
      trackActions.TRACK_DOWNVOTE,
      trackActions.PLAYLIST_UPVOTE,
      trackActions.PLAYLIST_DOWNVOTE,
    ]
    , addVote)
}

export function* addItemSaga() {
  yield* takeEvery(
    [
      trackActions.TRACK_ADD_NEW,
      playlistActions.PLAYLIST_ADD_NEW
    ]
    , addItem)
}

export function* removeItemSaga() {
  yield* takeEvery(
    [
      trackActions.TRACK_REMOVE,
      playlistActions.PLAYLIST_REMOVE
    ]
    , removeItem)
}

export function addVote(action) {
  console.log("action:",action);
  const { item } = action
  backend.call('add_vote', {
    id: item.id,
    vote: action.user_vote,
    type: item.type
  })
}

export function* addItem(action) {
  const { item } = action
  backend.call('add_item', {
    ...item
  });
}

export function* removeItem(action) {
  const { item } = action
  backend.call('remove_item', {
    ...item
  });
}

export default [searchSaga, addVoteSaga, addItemSaga, removeItemSaga];
<|endoftext|>


<commit_before>(function () {
  'use strict';

  /**
   * Effect's WebGL implementation by Pekka Väänänen
   */

  // http://dvolvr.davidwaterston.com/2012/06/24/javascript-accurate-timing-is-almost-here/
  var getNow = (function() {
    // Returns the number of milliseconds elapsed since either the browser navigationStart event or
    // the UNIX epoch, depending on availability.
    // Where the browser supports 'performance' we use that as it is more accurate (microsoeconds
    // will be returned in the fractional part) and more reliable as it does not rely on the system time.
    // Where 'performance' is not available, we will fall back to Date().getTime().

    var performance = window.performance || {};

    performance.now = (function() {
      return performance.now    ||
      performance.webkitNow     ||
      performance.msNow         ||
      performance.oNow          ||
      performance.mozNow        ||
      function() { return new Date().getTime(); };
    })();

    return performance.now();

  });

  function initGL(canvas) {
    try {
      window.gl = canvas.getContext("experimental-webgl");
    } catch(e) {
    }
    if (!gl) {
      console.error("Could not initialise WebGL.");
    }

    return gl;
  }

  // from gl-matrix
  function makeOrtho(out, left, right, bottom, top, near, far) {
      var lr = 1 / (left - right),
          bt = 1 / (bottom - top),
          nf = 1 / (near - far);
      out[0] = -2 * lr;
      out[1] = 0;
      out[2] = 0;
      out[3] = 0;
      out[4] = 0;
      out[5] = -2 * bt;
      out[6] = 0;
      out[7] = 0;
      out[8] = 0;
      out[9] = 0;
      out[10] = 2 * nf;
      out[11] = 0;
      out[12] = (left + right) * lr;
      out[13] = (top + bottom) * bt;
      out[14] = (far + near) * nf;
      out[15] = 1;
      return out;
  }

  function start(gl, canvas, textures) {
    var vertexSource = [
      "precision mediump float;",
      "attribute vec2 position;",
      "attribute float number;",
      "varying mediump vec2 vTextureCoord;",
      "varying mediump float vAlpha;",
      "uniform mat4 projection;",
      "uniform vec2 screen;",
      "uniform float time;",
      "highp float rand(vec2 co)",
      "{",
        "highp float a = 12.9898;",
        "highp float b = 78.233;",
        "highp float c = 43758.5453;",
        "highp float dt= dot(co.xy ,vec2(a,b));",
        "highp float sn= mod(dt,3.14);",
        "return fract(sin(sn) * c);",
      "}",
      "void main() { ",
        "const float speed = 2.0;",
        "const float size = 20.0;",
        "float t = time;",
        "vec3 r = vec3(rand(vec2(number*2.0,0.0)), rand(vec2(0.0, number)), rand(vec2(number, 0.0)));",
        "float scaling = (0.1 + 0.3 * r.z) * size;",
        "float theta=t*(r.g-0.5);",
        "float cos_theta=cos(theta);",
        "float sin_theta=sin(theta);",
        "mat2 rotation_matrix=mat2(cos_theta, sin_theta, -sin_theta, cos_theta);",
        "",
        "vec2 ofs = vec2(",
          "r.x * screen.x, ",
          "abs(sin(r.z)) * screen.y * 2.0 - t*(10.0 + r.y * speed)",
        ");",
        "",
        "ofs.y = mod(ofs.y, screen.y + scaling*4.0) - scaling*2.0;",
        "ofs.x = mod(ofs.x, screen.x) + sin(ofs.y*(0.01*r.z))*(80.0*r.y);",
        "",
        "vAlpha = (1.0 - ofs.y / screen.y) * (0.1 + rand(vec2(number*3.0, 0.0)));",
        "vAlpha *= 0.7;",
        "",
        "vec2 pos = (rotation_matrix*position)*scaling + ofs;",
        "gl_Position = projection * vec4(pos, 0, 1);",
        "vTextureCoord = position;",
      "}"].join('\n');

    var fragmentSource = [
      "precision mediump float;",
      "varying mediump vec2 vTextureCoord;",
      "varying mediump float vAlpha;",
      "uniform sampler2D uSampler;",
      "void main() { ",
        "vec2 coord = 0.5*(vec2(1.0) + vTextureCoord.st);",
        //"float circle = 1.0 - length(vTextureCoord.st) / 0.707107; // sqrt(2.0) * 0.5",
        //"circle = min(1.0, circle*4.0);",
        "vec4 color = texture2D(uSampler, coord);",
        "gl_FragColor = vec4(color.rgb, color.a*vAlpha);",
      "}"].join('\n');

    var quad_vertices = [
      -1.0, 1.0,
      -1.0, -1.0,
       1.0, -1.0,
       1.0, -1.0,
       1.0, 1.0,
      -1.0, 1.0
    ];

    var vertices = [];
    var point_numbers = [];
    var MAX_QUADS = 2000;
    var particleCount, time;

    // Create huge vertex position and quad number buffers.
    for (var i = 0; i < MAX_QUADS ; i++) {
      vertices.push.apply(vertices, quad_vertices);
      // Each vertex has a quad index stored as an attribute.
      point_numbers.push(i, i, i, i, i, i);
    }

    var vertexPosBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, vertexPosBuffer);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);

    var pointNumberBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, pointNumberBuffer);
    gl.bufferData(gl.ARRAY_BUFFER, new Uint16Array(point_numbers), gl.STATIC_DRAW);

    var program = createProgram(vertexSource, fragmentSource);
    gl.useProgram(program);

    gl.clearColor(0,0, 0.0, 0.0, 0.0);

    var debounce = function (func, wait, immediate) {
      var timeout;
      return function() {
        var context = this, args = arguments;
        var later = function() {
          timeout = null;
          if (!immediate) func.apply(context, args);
        };
        var callNow = immediate && !timeout;
        clearTimeout(timeout);
        timeout = setTimeout(later, wait);
        if (callNow) func.apply(context, args);
      };
    };

    var setupViewport = function() {
      gl.viewport(0, 0, canvas.width, canvas.height);
      // out, left, right, bottom, top, near, far
      var projectionMatrix = makeOrtho(new Array(16), 0.0, canvas.width, 0.0, canvas.height, 0.0, 1.0);
      gl.uniformMatrix4fv(gl.getUniformLocation(program, "projection"), false, projectionMatrix);
      gl.uniform2f(gl.getUniformLocation(program, "screen"), canvas.width, canvas.height);
    };

    var resize = function() {
      var width = window.innerWidth;
      var height = Math.floor(window.innerHeight / 2.5);
      canvas.width = width;
      canvas.height = height;
      setupViewport();
      particleCount = Math.floor(Math.min(MAX_QUADS, canvas.width / 3));
    };

    resize();
    window.addEventListener('resize', debounce(resize, 500));

    program.vertexPosAttrib = gl.getAttribLocation(program, 'position');
    gl.enableVertexAttribArray(program.vertexPosAttrib);
    program.pointNumberAttrib = gl.getAttribLocation(program, 'number');
    gl.enableVertexAttribArray(program.pointNumberAttrib);

    gl.enable(gl.BLEND);
    gl.blendFunc(gl.SRC_ALPHA, gl.ONE); // Additive blending since the sprites are white anyway.
    gl.disable(gl.DEPTH_TEST);

    gl.activeTexture(gl.TEXTURE0);
    gl.bindTexture(gl.TEXTURE_2D, textures["flake"]);
    gl.uniform1i(gl.getUniformLocation(program, "uSampler"), 0);

    var startTime = getNow();

    function draw() {
      time = 100.0 + (getNow() - startTime) / 1000.0;
      gl.clear(gl.COLOR_BUFFER_BIT);
      gl.uniform1f(gl.getUniformLocation(program, "time"), time);

      gl.bindBuffer(gl.ARRAY_BUFFER, vertexPosBuffer);
      gl.vertexAttribPointer(program.vertexPosAttrib, 2, gl.FLOAT, false, 0, 0);

      gl.bindBuffer(gl.ARRAY_BUFFER, pointNumberBuffer);
      gl.vertexAttribPointer(program.pointNumberAttrib, 1, gl.UNSIGNED_SHORT, false, 2, 0);

      gl.drawArrays(gl.TRIANGLES, 0, 6 * particleCount);

      requestAnimationFrame(draw);
    }

    requestAnimationFrame(draw);
  }

  function loadTexture(path, doneCallback) {
    var texture = gl.createTexture();
    var image = new Image();
    image.onload = function() {
      handleTextureLoaded(image, texture);
      doneCallback(texture);
    }
    image.src = path;
  }

  function handleTextureLoaded(image, texture) {
    gl.bindTexture(gl.TEXTURE_2D, texture);
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST);
    gl.generateMipmap(gl.TEXTURE_2D);
    gl.bindTexture(gl.TEXTURE_2D, null);
  }

  function initEffect() {
    var canvas = document.getElementById('demo-canvas');
    if (!canvas) return;

    var gl = initGL(canvas);
    if (!gl) return;

    // A 32x32 transparent white unicode snowflake
    var textureData="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4AEKFzot8VJPDwAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAADJElEQVRYw+1XW6hMURg+7tc6TkiRDrmXW1EiRXlByCEPUqKQDrk8iEjtg/KCyCWUB/I0kgcdl4dT4+GcTE0iBjV0hmGapumYMbc9e26+P2vXb1l77Z1mlI5Vf3vttf9//d/617++9e+mpn+1RSKRYdVq9QtJpVLZ8tcBRKPR4TXRAGBH/wAQj8dHIuT3SqXSIhlAOp1uwbeL5XJ5dcMAwEEHOcSzArljA0D/ISQp+u+CweDgujhMpVJjaEUkyWRyNFa6Fw76ag6t+rPdhV0zorSM7IrF4hzPDk3TnApptd8xyXJ7csuy5tJYJpMZCydXIWXJeQ/0l7BovRTjV+yxcDg8FDpLdSF+BMlDjFgsNkIFwG54X8Ccn1XM9QsARGMd+mFILp/PT/rNOUI1Ex8tNuknyDknAG6ngAHohDzh0YL+MWUEBIhO1f7+KQBpm3oRic2uuQCltVD+KBnfzmaz490A+Hy+gXjfA/0Msy1i7CTZeCIYKJ+AUVaxghS+HQ6FQkNUAAB8pWrlwvYBEnya1rnf7x8ExbfMyIKch1zjWY/+ezhrY+8dkPuSwwCAHcTzM48EJbYb2RhC+TFyYhbL+nkY66q5NOh8hePthmEMYOx5ClKgxbmSFBlgdWs0+bERE31QOCYHZxKJxCgHjmklCnfNAdpfOuNO34lsKLwKAH1Y+T7aRgdWbUZEp7sCwCSHBNff5FkP8phI/E9c67IFrxGlVdKp2I3xBAG3t0aXhL1y1kOO81NBk2FsP3u/BOmWsx5ANuH5go9jbIU2ArRqGN2QuZ6digsUTtUxxHMbvkcdIhPQ3gMSzy+EwRtpgqfYw9luRCSy/jTEZLYmdHZqwy9uunFQvk450CAqDvAbU74HZkDhG1NOE/3W4TJ6BnnFawboH3AioR5RVNzK5XITdNdxoVCYzAAc0V3HlNzQaaeqifKIFuu09/PhdLGuIKGiApMdxUTfpfD6QDZTdAUJ1Y1EZJ4rJIoCnO0iEcbrVSwos6Fg0zay85z5HovSy8xZF+t321lPx5AANKQqFqX3c6xug5yEVE/SjYj+1v9/Rv0DQL3aD7ongqaFwd3yAAAAAElFTkSuQmCC";

    loadTexture(textureData, function (flakeTexture) {
      start(gl, canvas, {"flake" : flakeTexture});
    });

  }

  initEffect();
})();
<commit_msg>Fade in and out in header effect<commit_after>(function () {
  'use strict';

  /**
   * Effect's WebGL implementation by Pekka Väänänen
   */

  // http://dvolvr.davidwaterston.com/2012/06/24/javascript-accurate-timing-is-almost-here/
  var getNow = (function() {
    // Returns the number of milliseconds elapsed since either the browser navigationStart event or
    // the UNIX epoch, depending on availability.
    // Where the browser supports 'performance' we use that as it is more accurate (microsoeconds
    // will be returned in the fractional part) and more reliable as it does not rely on the system time.
    // Where 'performance' is not available, we will fall back to Date().getTime().

    var performance = window.performance || {};

    performance.now = (function() {
      return performance.now    ||
      performance.webkitNow     ||
      performance.msNow         ||
      performance.oNow          ||
      performance.mozNow        ||
      function() { return new Date().getTime(); };
    })();

    return performance.now();

  });

  function initGL(canvas) {
    try {
      window.gl = canvas.getContext("experimental-webgl");
    } catch(e) {
    }
    if (!gl) {
      console.error("Could not initialise WebGL.");
    }

    return gl;
  }

  // from gl-matrix
  function makeOrtho(out, left, right, bottom, top, near, far) {
      var lr = 1 / (left - right),
          bt = 1 / (bottom - top),
          nf = 1 / (near - far);
      out[0] = -2 * lr;
      out[1] = 0;
      out[2] = 0;
      out[3] = 0;
      out[4] = 0;
      out[5] = -2 * bt;
      out[6] = 0;
      out[7] = 0;
      out[8] = 0;
      out[9] = 0;
      out[10] = 2 * nf;
      out[11] = 0;
      out[12] = (left + right) * lr;
      out[13] = (top + bottom) * bt;
      out[14] = (far + near) * nf;
      out[15] = 1;
      return out;
  }

  function start(gl, canvas, textures) {
    var vertexSource = [
      "precision mediump float;",
      "attribute vec2 position;",
      "attribute float number;",
      "varying mediump vec2 vTextureCoord;",
      "varying mediump float vAlpha;",
      "uniform mat4 projection;",
      "uniform vec2 screen;",
      "uniform float time;",
      "highp float rand(vec2 co)",
      "{",
        "highp float a = 12.9898;",
        "highp float b = 78.233;",
        "highp float c = 43758.5453;",
        "highp float dt= dot(co.xy ,vec2(a,b));",
        "highp float sn= mod(dt,3.14);",
        "return fract(sin(sn) * c);",
      "}",
      "void main() { ",
        "const float speed = 2.0;",
        "const float size = 20.0;",
        "float t = time;",
        "vec3 r = vec3(rand(vec2(number*2.0,0.0)), rand(vec2(0.0, number)), rand(vec2(number, 0.0)));",
        "float scaling = (0.1 + 0.3 * r.z) * size;",
        "float theta=t*(r.g-0.5);",
        "float cos_theta=cos(theta);",
        "float sin_theta=sin(theta);",
        "mat2 rotation_matrix=mat2(cos_theta, sin_theta, -sin_theta, cos_theta);",
        "",
        "vec2 ofs = vec2(",
          "r.x * screen.x, ",
          "abs(sin(r.z)) * screen.y * 2.0 - t*(10.0 + r.y * speed)",
        ");",
        "",
        "ofs.y = mod(ofs.y, screen.y + scaling*4.0) - scaling*2.0;",
        "ofs.x = mod(ofs.x, screen.x) + sin(ofs.y*(0.01*r.z))*(80.0*r.y);",
        "",
        "vAlpha = (1.0-2.0*abs(0.5 - ofs.y / screen.y)) * (0.1 + rand(vec2(number*3.0, 0.0)));",
        "vAlpha *= 0.7;",
        "",
        "vec2 pos = (rotation_matrix*position)*scaling + ofs;",
        "gl_Position = projection * vec4(pos, 0, 1);",
        "vTextureCoord = position;",
      "}"].join('\n');

    var fragmentSource = [
      "precision mediump float;",
      "varying mediump vec2 vTextureCoord;",
      "varying mediump float vAlpha;",
      "uniform sampler2D uSampler;",
      "void main() { ",
        "vec2 coord = 0.5*(vec2(1.0) + vTextureCoord.st);",
        "vec4 color = texture2D(uSampler, coord);",
        "gl_FragColor = vec4(color.rgb, color.a*vAlpha);",
      "}"].join('\n');

    var quad_vertices = [
      -1.0, 1.0,
      -1.0, -1.0,
       1.0, -1.0,
       1.0, -1.0,
       1.0, 1.0,
      -1.0, 1.0
    ];

    var vertices = [];
    var point_numbers = [];
    var MAX_QUADS = 2000;
    var particleCount, time;

    // Create huge vertex position and quad number buffers.
    for (var i = 0; i < MAX_QUADS ; i++) {
      vertices.push.apply(vertices, quad_vertices);
      // Each vertex has a quad index stored as an attribute.
      point_numbers.push(i, i, i, i, i, i);
    }

    var vertexPosBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, vertexPosBuffer);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);

    var pointNumberBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, pointNumberBuffer);
    gl.bufferData(gl.ARRAY_BUFFER, new Uint16Array(point_numbers), gl.STATIC_DRAW);

    var program = createProgram(vertexSource, fragmentSource);
    gl.useProgram(program);

    gl.clearColor(0,0, 0.0, 0.0, 0.0);

    var debounce = function (func, wait, immediate) {
      var timeout;
      return function() {
        var context = this, args = arguments;
        var later = function() {
          timeout = null;
          if (!immediate) func.apply(context, args);
        };
        var callNow = immediate && !timeout;
        clearTimeout(timeout);
        timeout = setTimeout(later, wait);
        if (callNow) func.apply(context, args);
      };
    };

    var setupViewport = function() {
      gl.viewport(0, 0, canvas.width, canvas.height);
      // out, left, right, bottom, top, near, far
      var projectionMatrix = makeOrtho(new Array(16), 0.0, canvas.width, 0.0, canvas.height, 0.0, 1.0);
      gl.uniformMatrix4fv(gl.getUniformLocation(program, "projection"), false, projectionMatrix);
      gl.uniform2f(gl.getUniformLocation(program, "screen"), canvas.width, canvas.height);
    };

    var resize = function() {
      var width = window.innerWidth;
      var height = Math.floor(window.innerHeight / 2.5);
      canvas.width = width;
      canvas.height = height;
      setupViewport();
      particleCount = Math.floor(Math.min(MAX_QUADS, canvas.width / 3));
    };

    resize();
    window.addEventListener('resize', debounce(resize, 500));

    program.vertexPosAttrib = gl.getAttribLocation(program, 'position');
    gl.enableVertexAttribArray(program.vertexPosAttrib);
    program.pointNumberAttrib = gl.getAttribLocation(program, 'number');
    gl.enableVertexAttribArray(program.pointNumberAttrib);

    gl.enable(gl.BLEND);
    gl.blendFunc(gl.SRC_ALPHA, gl.ONE); // Additive blending since the sprites are white anyway.
    gl.disable(gl.DEPTH_TEST);

    gl.activeTexture(gl.TEXTURE0);
    gl.bindTexture(gl.TEXTURE_2D, textures["flake"]);
    gl.uniform1i(gl.getUniformLocation(program, "uSampler"), 0);

    var startTime = getNow();

    function draw() {
      time = 100.0 + (getNow() - startTime) / 1000.0;
      gl.clear(gl.COLOR_BUFFER_BIT);
      gl.uniform1f(gl.getUniformLocation(program, "time"), time);

      gl.bindBuffer(gl.ARRAY_BUFFER, vertexPosBuffer);
      gl.vertexAttribPointer(program.vertexPosAttrib, 2, gl.FLOAT, false, 0, 0);

      gl.bindBuffer(gl.ARRAY_BUFFER, pointNumberBuffer);
      gl.vertexAttribPointer(program.pointNumberAttrib, 1, gl.UNSIGNED_SHORT, false, 2, 0);

      gl.drawArrays(gl.TRIANGLES, 0, 6 * particleCount);

      requestAnimationFrame(draw);
    }

    requestAnimationFrame(draw);
  }

  function loadTexture(path, doneCallback) {
    var texture = gl.createTexture();
    var image = new Image();
    image.onload = function() {
      handleTextureLoaded(image, texture);
      doneCallback(texture);
    }
    image.src = path;
  }

  function handleTextureLoaded(image, texture) {
    gl.bindTexture(gl.TEXTURE_2D, texture);
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST);
    gl.generateMipmap(gl.TEXTURE_2D);
    gl.bindTexture(gl.TEXTURE_2D, null);
  }

  function initEffect() {
    var canvas = document.getElementById('demo-canvas');
    if (!canvas) return;

    var gl = initGL(canvas);
    if (!gl) return;

    // A 32x32 transparent white unicode snowflake
    var textureData="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4AEKFzot8VJPDwAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAADJElEQVRYw+1XW6hMURg+7tc6TkiRDrmXW1EiRXlByCEPUqKQDrk8iEjtg/KCyCWUB/I0kgcdl4dT4+GcTE0iBjV0hmGapumYMbc9e26+P2vXb1l77Z1mlI5Vf3vttf9//d/617++9e+mpn+1RSKRYdVq9QtJpVLZ8tcBRKPR4TXRAGBH/wAQj8dHIuT3SqXSIhlAOp1uwbeL5XJ5dcMAwEEHOcSzArljA0D/ISQp+u+CweDgujhMpVJjaEUkyWRyNFa6Fw76ag6t+rPdhV0zorSM7IrF4hzPDk3TnApptd8xyXJ7csuy5tJYJpMZCydXIWXJeQ/0l7BovRTjV+yxcDg8FDpLdSF+BMlDjFgsNkIFwG54X8Ccn1XM9QsARGMd+mFILp/PT/rNOUI1Ex8tNuknyDknAG6ngAHohDzh0YL+MWUEBIhO1f7+KQBpm3oRic2uuQCltVD+KBnfzmaz490A+Hy+gXjfA/0Msy1i7CTZeCIYKJ+AUVaxghS+HQ6FQkNUAAB8pWrlwvYBEnya1rnf7x8ExbfMyIKch1zjWY/+ezhrY+8dkPuSwwCAHcTzM48EJbYb2RhC+TFyYhbL+nkY66q5NOh8hePthmEMYOx5ClKgxbmSFBlgdWs0+bERE31QOCYHZxKJxCgHjmklCnfNAdpfOuNO34lsKLwKAH1Y+T7aRgdWbUZEp7sCwCSHBNff5FkP8phI/E9c67IFrxGlVdKp2I3xBAG3t0aXhL1y1kOO81NBk2FsP3u/BOmWsx5ANuH5go9jbIU2ArRqGN2QuZ6digsUTtUxxHMbvkcdIhPQ3gMSzy+EwRtpgqfYw9luRCSy/jTEZLYmdHZqwy9uunFQvk450CAqDvAbU74HZkDhG1NOE/3W4TJ6BnnFawboH3AioR5RVNzK5XITdNdxoVCYzAAc0V3HlNzQaaeqifKIFuu09/PhdLGuIKGiApMdxUTfpfD6QDZTdAUJ1Y1EZJ4rJIoCnO0iEcbrVSwos6Fg0zay85z5HovSy8xZF+t321lPx5AANKQqFqX3c6xug5yEVE/SjYj+1v9/Rv0DQL3aD7ongqaFwd3yAAAAAElFTkSuQmCC";

    loadTexture(textureData, function (flakeTexture) {
      start(gl, canvas, {"flake" : flakeTexture});
    });

  }

  initEffect();
})();
<|endoftext|>


<commit_before><script>
  var editor = ace.edit("editor");
  editor.setTheme("ace/theme/monokai");
  editor.getSession().setMode("ace/mode/javascript");
</script><commit_msg>Source.js fixed<commit_after>var editor = ace.edit("editor");
editor.setTheme("ace/theme/monokai");
editor.getSession().setMode("ace/mode/javascript");<|endoftext|>


<commit_before>/* globals require */
/* jshint esversion: 6 */

const os = require('os');
const path = require('path');
const process = require('process');
const fs = require('fs');
const del = require('del');
const _ = require('lodash');
const mkdirp = require('mkdirp');
const gulp = require('gulp');
const help = require('gulp-help-four');
const gulpWatch = require('gulp-watch');
const livereload = require('gulp-livereload');
const connect = require('connect');
const serverStatic = require('serve-static');
const opn = require('opn');
const rename = require('gulp-rename');
const textTransform = require('gulp-text-simple');
const lazypipe = require('lazypipe');
const merge = require('merge-stream');
const mdproc = require('mdproc');
const mdinclude = require('mdinclude');
const mdquery = require('mdquery').transform;
<% if (needsGlob) { %>var glob = require('glob');
<% } if (needsDateFormat) { %>var dateFormat = require('dateformat');
<% } if (needsExec) { %>var exec = require('gulp-exec');
<% } %>
help(gulp, { hideEmpty: true });

const preProcess = textTransform(require('./config/preprocessing.js'));
const htmlPostProcess = textTransform(require('./config/html-postprocessing.js'));
var injectLiveReload = false;

function setTerminalTitle(title) {
	process.stdout.write(String.fromCharCode(27) + "]0;" + title + String.fromCharCode(7));
}

function loadConfig() {
	return JSON.parse(fs.readFileSync('./config/mdproc.json', 'utf8'));
}

function loadGraphs() {
	return JSON.parse(fs.readFileSync('./config/graphs.json', 'utf8'));
}

function runTask(taskFn) {
	taskFn(function () {});
}

function markdownPipeline(opt) {
	var cfg = loadConfig();
	return lazypipe()
		.pipe(mdinclude)
		.pipe(mdquery)
		.pipe(mdproc.references, { prefixCaption: opt.prefixCaption })
		.pipe(mdproc.badges)
		.pipe(preProcess, {cfg: cfg})
		();
}

function graphextract(prefixCaption, imgFormat, cb) {
	var graphs = loadGraphs();
	if (graphs.autograph.sources.length > 0) {
		var tasks = _.map(graphs.autograph.sources, function (g) {
			var opt = _.assign(
				{ imgFormat: imgFormat },
				g.options);
			return gulp.src(g.sourceFile)
				.pipe(markdownPipeline({ prefixCaption: prefixCaption }))
				.pipe(mdproc.autograph(opt))
				.pipe(rename({ basename: g.name }))
				.pipe(gulp.dest(graphs.autograph.target));
		});
		return merge(tasks);
	} else {
		cb();
	}
}

function dotex(prefixCaption, imgFormat, cb) {
	var graphs = loadGraphs();
	if (graphs.dotex.sources.length) {
		var tasks = _.map(graphs.dotex.sources, function (g) {
			var opt = _.assign(
				{ imgFormat: imgFormat },
				g.options);
			return gulp.src(g.sourceFile)
				.pipe(markdownPipeline({ prefixCaption: prefixCaption }))
				.pipe(mdproc.dotex(opt))
				.pipe(rename({ basename: g.name }))
				.pipe(gulp.dest(graphs.dotex.target));
		});
		return merge(tasks);
	} else {
		cb();
	}
}

function clean(cb) {
	var cfg = loadConfig();
	del.sync(cfg.target_dir);

	var graphs = loadGraphs();
	if (graphs.autograph.target) {
		del.sync(graphs.autograph.target);
	}
	if (graphs.dotex.target) {
		del.sync(graphs.dotex.target);
	}
	cb();
}

function copyImages() {
	var cfg = loadConfig();
	return gulp.src(cfg.image_files, { base: 'src' })
		.pipe(gulp.dest(cfg.target_dir));
}

function autographSvg(cb) { return graphextract(true, 'svg', cb); }
function dotexSvg(cb) { return dotex(true, 'svg', cb); }
const imagesSvg = gulp.parallel(autographSvg, dotexSvg);

function autographPng(cb) { return graphextract(true, 'png', cb); }
function dotexPng(cb) { return dotex(true, 'png', cb); }
const imagesPng = gulp.parallel(autographPng, dotexPng);
<% if (supportPdf) { %>
function autographPdf(cb) { return graphextract(false, 'pdf', cb); }
function dotexPdf(cb) { return dotex(true, 'pdf', cb); }
const imagesPdf = gulp.parallel(autographPdf, dotexPdf);
<% } %>
function html() {
	var cfg = loadConfig();
	cfg.injectLiveReload = injectLiveReload;
	return gulp.src(cfg.markdown_files)
		.pipe(markdownPipeline({ prefixCaption: true }))
		.pipe(mdproc.md2html(_.assign({ basePath: 'src' }, cfg.options, cfg.md2html_options)))
		.pipe(htmlPostProcess({cfg: cfg}))
		.pipe(gulp.dest(cfg.target_dir))
		.pipe(livereload());
}

function docx() {
	var cfg = loadConfig();
	return gulp.src(cfg.markdown_files)
		.pipe(markdownPipeline({ prefixCaption: true }))
		.pipe(mdproc.md2docx(_.assign({}, cfg.options, cfg.md2docx_options)))
		.pipe(gulp.dest(cfg.target_dir));
}
<% if (supportPdf) { %>
function tex() {
	var cfg = loadConfig();
	return gulp.src(cfg.markdown_files)
		.pipe(markdownPipeline({ prefixCaption: false }))
		.pipe(mdproc.md2tex(_.assign({}, cfg.options, cfg.md2tex_options || cfg.md2pdf_options)))
		.pipe(gulp.dest(cfg.target_dir));
}

function pdf() {
	var cfg = loadConfig();
	return gulp.src(cfg.markdown_files)
		.pipe(markdownPipeline({ prefixCaption: false }))
		.pipe(mdproc.md2pdf(_.assign({}, cfg.options, cfg.md2pdf_options)))
		.pipe(gulp.dest(cfg.target_dir));
}
<% } %>
const formatTasks = {
	'html': html,
	'docx': docx,
<% if (supportPdf) { %>	'tex': tex,
	'pdf': pdf
<% } %>};

const all =
	gulp.series(
		gulp.parallel(imagesSvg, imagesPng<% if (supportPdf) { %>, imagesPdf<% } %>),
		copyImages,
		gulp.series(html, docx<% if (supportPdf) { %>, tex, pdf<% } %>));

const autobuildTasks =
	_.map(loadConfig().default_formats,
		function(taskName) { return formatTasks[taskName]; });
const autobuild = _.spread(gulp.series)(autobuildTasks);

function openMainFile(cb) {
	const cfg = loadConfig();
	opn(path.resolve(path.join(process.cwd(), cfg.target_dir, cfg.main + '.html')),
		cfg.default_browser ? { app: cfg.default_browser } : undefined);
	cb();
}

function watch() {
	setTerminalTitle('MdProc watch - ' + __dirname);
	const cfg = loadConfig();
	return watch(cfg.watched_files,
		{ verbose: true, readDelay: 200 },
		function () {
			try {
				runTask(autobuild);
			} catch(err) {
				console.log('ERROR: ' + err.message);
			}
		});
}

function openLivereload(cb) {
	const cfg = loadConfig();
	opn('http://localhost:' + cfg.server_port + '/' + cfg.main + '.html',
		cfg.default_browser ? { app: cfg.default_browser } : undefined);
	cb();
}

function serve() {
	setTerminalTitle('MdProc serve - ' + __dirname);
	const cfg = loadConfig();
	injectLiveReload = true;
	runTask(autobuild);
	const server = connect();
	server.use(serverStatic(cfg.target_dir));
	server.listen(cfg.server_port);
	livereload.listen({ port: cfg.livereload_port });
	setTimeout(function () { runTask(openLivereload); }, 1000);
	return gulpWatch(cfg.watched_files,
		{ verbose: true, readDelay: 200},
		function () {
			try {
				runTask(html);
			} catch(err) {
				console.log('ERROR: ' + err.message);
			}
		});
}

gulp.task('default', 'Build the output in the default formats', autobuild);
gulp.task('clean', 'Remove all generated output', clean);
gulp.task('copy-images', false, copyImages);
gulp.task('autograph:svg', false, autographSvg);
gulp.task('dotex:svg', false, dotexSvg);
gulp.task('images:svg', false, imagesSvg);
gulp.task('autograph:png', false, autographPng);
gulp.task('dotex:png', false, dotexPng);
gulp.task('images:png', false, imagesPng);
<% if (supportPdf) { %>gulp.task('autograph:pdf', false, autographPdf);
gulp.task('dotex:pdf', false, dotexPdf);
gulp.task('images:pdf', false, imagesPdf);
<% } %>gulp.task('html', 'Build the HTML output', gulp.series(imagesSvg, copyImages, html));
gulp.task('docx', 'Build the DOCX output', gulp.series(imagesPng, copyImages, docx));
<% if (supportPdf) { %>gulp.task('tex', 'Build the TeX output', gulp.series(imagesPdf, copyImages, tex));
gulp.task('pdf', 'Build the PDF output', gulp.series(imagesPdf, copyImages, pdf));
<% } %>gulp.task('all', 'Build the output in all formats', all);
gulp.task('autobuild', false, autobuild);
gulp.task('watch', 'Watch the source files and build automatically', gulp.series(autobuild, watch));
gulp.task('open-main-file', 'Show the HTML result of the main file in the default browser', openMainFile);
gulp.task('open-main-in-browser', 'Show the livereload URL of the main file in the default browser', openLivereload);
gulp.task('serve', 'Show HTML in default browser and refresh on changes', gulp.series(html, serve));

<% if (projectType === 'Personal Log') { %>
function today(cb) {
	const now = new Date();
	const yearDir = path.join('src', 'log', dateFormat(now, 'yyyy'));
	const monthDir = path.join(yearDir, dateFormat(now, 'mm'));
	const entryFile = path.join(monthDir, dateFormat(now, 'yyyy-mm-dd') + '.md');
	const headline = '## ' + dateFormat('yyyy-mm-dd dddd') +
		' {#log_' + dateFormat('yyyy-mm-dd') + '}';
	const text = headline + os.EOL + os.EOL;
	mkdirp(monthDir, function (err) {
		if (err) {
			cb(err);
			return;
		}
		fs.stat(entryFile, function (err, stats) {
			if (err && err.code === 'ENOENT') {
				fs.writeFile(entryFile, text, 'utf8', cb);
			} else {
				cb(err);
			}
		});
	});
}
gulp.task('today', 'Create a new file for todays entries', today);
<% } %><commit_msg>renamed task open-main-in-browser to open-livereload<commit_after>/* globals require */
/* jshint esversion: 6 */

const os = require('os');
const path = require('path');
const process = require('process');
const fs = require('fs');
const del = require('del');
const _ = require('lodash');
const mkdirp = require('mkdirp');
const gulp = require('gulp');
const help = require('gulp-help-four');
const gulpWatch = require('gulp-watch');
const livereload = require('gulp-livereload');
const connect = require('connect');
const serverStatic = require('serve-static');
const opn = require('opn');
const rename = require('gulp-rename');
const textTransform = require('gulp-text-simple');
const lazypipe = require('lazypipe');
const merge = require('merge-stream');
const mdproc = require('mdproc');
const mdinclude = require('mdinclude');
const mdquery = require('mdquery').transform;
<% if (needsGlob) { %>var glob = require('glob');
<% } if (needsDateFormat) { %>var dateFormat = require('dateformat');
<% } if (needsExec) { %>var exec = require('gulp-exec');
<% } %>
help(gulp, { hideEmpty: true });

const preProcess = textTransform(require('./config/preprocessing.js'));
const htmlPostProcess = textTransform(require('./config/html-postprocessing.js'));
var injectLiveReload = false;

function setTerminalTitle(title) {
	process.stdout.write(String.fromCharCode(27) + "]0;" + title + String.fromCharCode(7));
}

function loadConfig() {
	return JSON.parse(fs.readFileSync('./config/mdproc.json', 'utf8'));
}

function loadGraphs() {
	return JSON.parse(fs.readFileSync('./config/graphs.json', 'utf8'));
}

function runTask(taskFn) {
	taskFn(function () {});
}

function markdownPipeline(opt) {
	var cfg = loadConfig();
	return lazypipe()
		.pipe(mdinclude)
		.pipe(mdquery)
		.pipe(mdproc.references, { prefixCaption: opt.prefixCaption })
		.pipe(mdproc.badges)
		.pipe(preProcess, {cfg: cfg})
		();
}

function graphextract(prefixCaption, imgFormat, cb) {
	var graphs = loadGraphs();
	if (graphs.autograph.sources.length > 0) {
		var tasks = _.map(graphs.autograph.sources, function (g) {
			var opt = _.assign(
				{ imgFormat: imgFormat },
				g.options);
			return gulp.src(g.sourceFile)
				.pipe(markdownPipeline({ prefixCaption: prefixCaption }))
				.pipe(mdproc.autograph(opt))
				.pipe(rename({ basename: g.name }))
				.pipe(gulp.dest(graphs.autograph.target));
		});
		return merge(tasks);
	} else {
		cb();
	}
}

function dotex(prefixCaption, imgFormat, cb) {
	var graphs = loadGraphs();
	if (graphs.dotex.sources.length) {
		var tasks = _.map(graphs.dotex.sources, function (g) {
			var opt = _.assign(
				{ imgFormat: imgFormat },
				g.options);
			return gulp.src(g.sourceFile)
				.pipe(markdownPipeline({ prefixCaption: prefixCaption }))
				.pipe(mdproc.dotex(opt))
				.pipe(rename({ basename: g.name }))
				.pipe(gulp.dest(graphs.dotex.target));
		});
		return merge(tasks);
	} else {
		cb();
	}
}

function clean(cb) {
	var cfg = loadConfig();
	del.sync(cfg.target_dir);

	var graphs = loadGraphs();
	if (graphs.autograph.target) {
		del.sync(graphs.autograph.target);
	}
	if (graphs.dotex.target) {
		del.sync(graphs.dotex.target);
	}
	cb();
}

function copyImages() {
	var cfg = loadConfig();
	return gulp.src(cfg.image_files, { base: 'src' })
		.pipe(gulp.dest(cfg.target_dir));
}

function autographSvg(cb) { return graphextract(true, 'svg', cb); }
function dotexSvg(cb) { return dotex(true, 'svg', cb); }
const imagesSvg = gulp.parallel(autographSvg, dotexSvg);

function autographPng(cb) { return graphextract(true, 'png', cb); }
function dotexPng(cb) { return dotex(true, 'png', cb); }
const imagesPng = gulp.parallel(autographPng, dotexPng);
<% if (supportPdf) { %>
function autographPdf(cb) { return graphextract(false, 'pdf', cb); }
function dotexPdf(cb) { return dotex(true, 'pdf', cb); }
const imagesPdf = gulp.parallel(autographPdf, dotexPdf);
<% } %>
function html() {
	var cfg = loadConfig();
	cfg.injectLiveReload = injectLiveReload;
	return gulp.src(cfg.markdown_files)
		.pipe(markdownPipeline({ prefixCaption: true }))
		.pipe(mdproc.md2html(_.assign({ basePath: 'src' }, cfg.options, cfg.md2html_options)))
		.pipe(htmlPostProcess({cfg: cfg}))
		.pipe(gulp.dest(cfg.target_dir))
		.pipe(livereload());
}

function docx() {
	var cfg = loadConfig();
	return gulp.src(cfg.markdown_files)
		.pipe(markdownPipeline({ prefixCaption: true }))
		.pipe(mdproc.md2docx(_.assign({}, cfg.options, cfg.md2docx_options)))
		.pipe(gulp.dest(cfg.target_dir));
}
<% if (supportPdf) { %>
function tex() {
	var cfg = loadConfig();
	return gulp.src(cfg.markdown_files)
		.pipe(markdownPipeline({ prefixCaption: false }))
		.pipe(mdproc.md2tex(_.assign({}, cfg.options, cfg.md2tex_options || cfg.md2pdf_options)))
		.pipe(gulp.dest(cfg.target_dir));
}

function pdf() {
	var cfg = loadConfig();
	return gulp.src(cfg.markdown_files)
		.pipe(markdownPipeline({ prefixCaption: false }))
		.pipe(mdproc.md2pdf(_.assign({}, cfg.options, cfg.md2pdf_options)))
		.pipe(gulp.dest(cfg.target_dir));
}
<% } %>
const formatTasks = {
	'html': html,
	'docx': docx,
<% if (supportPdf) { %>	'tex': tex,
	'pdf': pdf
<% } %>};

const all =
	gulp.series(
		gulp.parallel(imagesSvg, imagesPng<% if (supportPdf) { %>, imagesPdf<% } %>),
		copyImages,
		gulp.series(html, docx<% if (supportPdf) { %>, tex, pdf<% } %>));

const autobuildTasks =
	_.map(loadConfig().default_formats,
		function(taskName) { return formatTasks[taskName]; });
const autobuild = _.spread(gulp.series)(autobuildTasks);

function openMainFile(cb) {
	const cfg = loadConfig();
	opn(path.resolve(path.join(process.cwd(), cfg.target_dir, cfg.main + '.html')),
		cfg.default_browser ? { app: cfg.default_browser } : undefined);
	cb();
}

function watch() {
	setTerminalTitle('MdProc watch - ' + __dirname);
	const cfg = loadConfig();
	return watch(cfg.watched_files,
		{ verbose: true, readDelay: 200 },
		function () {
			try {
				runTask(autobuild);
			} catch(err) {
				console.log('ERROR: ' + err.message);
			}
		});
}

function openLivereload(cb) {
	const cfg = loadConfig();
	opn('http://localhost:' + cfg.server_port + '/' + cfg.main + '.html',
		cfg.default_browser ? { app: cfg.default_browser } : undefined);
	cb();
}

function serve() {
	setTerminalTitle('MdProc serve - ' + __dirname);
	const cfg = loadConfig();
	injectLiveReload = true;
	runTask(autobuild);
	const server = connect();
	server.use(serverStatic(cfg.target_dir));
	server.listen(cfg.server_port);
	livereload.listen({ port: cfg.livereload_port });
	setTimeout(function () { runTask(openLivereload); }, 1000);
	return gulpWatch(cfg.watched_files,
		{ verbose: true, readDelay: 200},
		function () {
			try {
				runTask(html);
			} catch(err) {
				console.log('ERROR: ' + err.message);
			}
		});
}

gulp.task('default', 'Build the output in the default formats', autobuild);
gulp.task('clean', 'Remove all generated output', clean);
gulp.task('copy-images', false, copyImages);
gulp.task('autograph:svg', false, autographSvg);
gulp.task('dotex:svg', false, dotexSvg);
gulp.task('images:svg', false, imagesSvg);
gulp.task('autograph:png', false, autographPng);
gulp.task('dotex:png', false, dotexPng);
gulp.task('images:png', false, imagesPng);
<% if (supportPdf) { %>gulp.task('autograph:pdf', false, autographPdf);
gulp.task('dotex:pdf', false, dotexPdf);
gulp.task('images:pdf', false, imagesPdf);
<% } %>gulp.task('html', 'Build the HTML output', gulp.series(imagesSvg, copyImages, html));
gulp.task('docx', 'Build the DOCX output', gulp.series(imagesPng, copyImages, docx));
<% if (supportPdf) { %>gulp.task('tex', 'Build the TeX output', gulp.series(imagesPdf, copyImages, tex));
gulp.task('pdf', 'Build the PDF output', gulp.series(imagesPdf, copyImages, pdf));
<% } %>gulp.task('all', 'Build the output in all formats', all);
gulp.task('autobuild', false, autobuild);
gulp.task('watch', 'Watch the source files and build automatically', gulp.series(autobuild, watch));
gulp.task('open-main-file', 'Show the HTML result of the main file in the default browser', openMainFile);
gulp.task('serve', 'Show HTML in default browser and refresh on changes', gulp.series(html, serve));
gulp.task('open-livereload', 'Show the livereload URL of the main file in the default browser', openLivereload);

<% if (projectType === 'Personal Log') { %>
function today(cb) {
	const now = new Date();
	const yearDir = path.join('src', 'log', dateFormat(now, 'yyyy'));
	const monthDir = path.join(yearDir, dateFormat(now, 'mm'));
	const entryFile = path.join(monthDir, dateFormat(now, 'yyyy-mm-dd') + '.md');
	const headline = '## ' + dateFormat('yyyy-mm-dd dddd') +
		' {#log_' + dateFormat('yyyy-mm-dd') + '}';
	const text = headline + os.EOL + os.EOL;
	mkdirp(monthDir, function (err) {
		if (err) {
			cb(err);
			return;
		}
		fs.stat(entryFile, function (err, stats) {
			if (err && err.code === 'ENOENT') {
				fs.writeFile(entryFile, text, 'utf8', cb);
			} else {
				cb(err);
			}
		});
	});
}
gulp.task('today', 'Create a new file for todays entries', today);
<% } %><|endoftext|>


<commit_before>/* globals require */

var path = require('path');
var fs = require('fs');

var gulp = require('gulp');
var watch = require('gulp-watch');
var mdproc = require('mdproc');

var cfg = require('./config.json');

var preProcess = function(mdtext) {
	// here you can modify mdtext to change the Markdown source
	// before compiling it with Pandoc

	// E.g. add a copyright footer to all documents
	var copyright = "Copyright © by " +
		"[<%= authorName %>](mailto:<%= authorEmail %>) " +
		"(<%= (new Date()).getFullYear() %>).";
	var lastChange = "Document compiled at " + (new Date()).toDateString() + ".";
	mdtext = mdtext + "\n\n-----\n\n" + copyright + "  \n" + lastChange + "\n";

	return mdtext;
};

gulp.task('prepare-target-dir', function () {
	if (!fs.existsSync(cfg.target_dir)) {
		fs.mkdirSync(cfg.target_dir);
	}
});

gulp.task('copy-images', function () {
	return gulp.src(cfg.image_files, { base: 'src' })
		.pipe(gulp.dest(cfg.target_dir));
});

gulp.task('html', ['prepare-target-dir', 'copy-images'],
	mdproc.buildHtmlTask(
		cfg.markdown_files, cfg.target_dir,
		{
			imgFormat: 'svg',
			customTransformation: preProcess
		}));

gulp.task('docx', ['prepare-target-dir', 'copy-images'],
	mdproc.buildDocxTask(
		cfg.markdown_files, cfg.target_dir,
		{
			customTransformation: preProcess
		}));
<% if (supportPdf) { %>
gulp.task('tex', ['prepare-target-dir', 'copy-images'],
	mdproc.buildLaTeXTask(
		cfg.markdown_files, cfg.target_dir,
		{
			vars: cfg.latex_vars,
			customTransformation: preProcess
		}));

gulp.task('pdf', ['prepare-target-dir', 'copy-images'],
	mdproc.buildPdfTask(
		cfg.markdown_files, cfg.target_dir,
		{
			vars: cfg.latex_vars,
			customTransformation: preProcess
		}));
<% } %>
gulp.task('all', ['html', 'docx'<% if (supportPdf) { %>, 'tex', 'pdf'<% } %>]);

gulp.task('autobuild', cfg.default_formats);

gulp.task('watch', ['autobuild'], function () {
	watch(cfg.watch_files,
		{ verbose: true, readDelay: 200 },
		function () { gulp.start('autobuild'); });
});

gulp.task('default', ['autobuild']);
<commit_msg>improved gulp task 'prepare-target-dir' with async fs.access instead of deprecated fs.existsSync<commit_after>/* globals require */

var path = require('path');
var fs = require('fs');

var gulp = require('gulp');
var watch = require('gulp-watch');
var mdproc = require('mdproc');

var cfg = require('./config.json');

var preProcess = function(mdtext) {
	// here you can modify mdtext to change the Markdown source
	// before compiling it with Pandoc

	// E.g. add a copyright footer to all documents
	var copyright = "Copyright © by " +
		"[<%= authorName %>](mailto:<%= authorEmail %>) " +
		"(<%= (new Date()).getFullYear() %>).";
	var lastChange = "Document compiled at " + (new Date()).toDateString() + ".";
	mdtext = mdtext + "\n\n-----\n\n" + copyright + "  \n" + lastChange + "\n";

	return mdtext;
};

gulp.task('prepare-target-dir', function (cb) {
	fs.access(cfg.target_dir, fs.R_OK | fs.W_OK, function (err) {
		if (err) {
			fs.mkdir(cfg.target_dir, cb);
		} else {
			cb();
		}
	});
});

gulp.task('copy-images', function () {
	return gulp.src(cfg.image_files, { base: 'src' })
		.pipe(gulp.dest(cfg.target_dir));
});

gulp.task('html', ['prepare-target-dir', 'copy-images'],
	mdproc.buildHtmlTask(
		cfg.markdown_files, cfg.target_dir,
		{
			imgFormat: 'svg',
			customTransformation: preProcess
		}));

gulp.task('docx', ['prepare-target-dir', 'copy-images'],
	mdproc.buildDocxTask(
		cfg.markdown_files, cfg.target_dir,
		{
			customTransformation: preProcess
		}));
<% if (supportPdf) { %>
gulp.task('tex', ['prepare-target-dir', 'copy-images'],
	mdproc.buildLaTeXTask(
		cfg.markdown_files, cfg.target_dir,
		{
			vars: cfg.latex_vars,
			customTransformation: preProcess
		}));

gulp.task('pdf', ['prepare-target-dir', 'copy-images'],
	mdproc.buildPdfTask(
		cfg.markdown_files, cfg.target_dir,
		{
			vars: cfg.latex_vars,
			customTransformation: preProcess
		}));
<% } %>
gulp.task('all', ['html', 'docx'<% if (supportPdf) { %>, 'tex', 'pdf'<% } %>]);

gulp.task('autobuild', cfg.default_formats);

gulp.task('watch', ['autobuild'], function () {
	watch(cfg.watch_files,
		{ verbose: true, readDelay: 200 },
		function () { gulp.start('autobuild'); });
});

gulp.task('default', ['autobuild']);
<|endoftext|>