<commit_before>import express from "express";

import pkg from "../../package.json";

const debug = require("debug")("phenomic:core:api");

const encode = text => new Buffer(text).toString("base64");
const decode = text => new Buffer(text, "base64").toString();

const connect = (list, limit) => {
  const hasNextPage = limit === undefined ? false : list.length >= limit;
  return {
    hasNextPage,
    next: hasNextPage ? encode(list[list.length - 2].key) : null,
    list: list.slice(0, limit)
  };
};

function createServer(db: PhenomicDB, plugins: PhenomicPlugins) {
  debug("creating server");
  const server = express();

  server.get("/", async function(req: express$Request, res: express$Response) {
    debug("get api version");
    res.json({
      engine: "phenomic",
      version: pkg.version
    });
  });

  server.get("/:collection/by-:filter/:value/:order.json", async function(
    req: express$Request,
    res: express$Response
  ) {
    debug(req.url, JSON.stringify(req.params));
    try {
      const reverse = req.params.order === "desc";
      const list = await db.getList(
        req.params.collection,
        { reverse },
        req.params.filter,
        req.params.value
      );
      res.json(connect(list));
    } catch (error) {
      console.error(error);
      res.status(404).end();
    }
  });

  server.get(
    "/:collection/by-:filter/:value/:order/limit-:limit.json",
    async function(req: express$Request, res: express$Response) {
      debug(req.url, JSON.stringify(req.params));
      try {
        const limit = parseInt(req.params.limit);
        const reverse = req.params.order === "desc";
        const list = await db.getList(
          req.params.collection,
          {
            limit: limit + 1,
            reverse
          },
          req.params.filter,
          req.params.value
        );
        res.json(connect(list, limit));
      } catch (error) {
        console.error(error);
        res.status(404).end();
      }
    }
  );

  server.get(
    "/:collection/by-:filter/:value/:order/limit-:limit/after-:after.json",
    async function(req: express$Request, res: express$Response) {
      debug(req.url, JSON.stringify(req.params));
      try {
        const limit = parseInt(req.params.limit);
        const lt = decode(req.params.after);
        // @todo check lt validity (exist?); otherwise, trigger an error (404?)
        // cause during dev all "lt" are responding 200, even random values
        // but in production, it's not the case as only known values are
        // generated as endpoints
        const reverse = req.params.order === "desc";
        const list = await db.getList(
          req.params.collection,
          {
            limit: limit + 1,
            lt,
            reverse
          },
          req.params.filter,
          req.params.value
        );
        res.json(connect(list, limit));
      } catch (error) {
        console.error(error);
        res.status(404).end();
      }
    }
  );

  server.get("/:collection/item/*.json", async function(
    req: express$Request,
    res: express$Response
  ) {
    debug(req.url, JSON.stringify(req.params));
    try {
      const resource = await db.get(req.params.collection, req.params["0"]);
      res.json(resource.value);
    } catch (error) {
      console.error(error);
      res.status(404).end();
    }
  });

  // Install the plugins
  plugins.forEach(plugin => {
    if (typeof plugin.define === "function") {
      debug(`installing plugin '${plugin.name}'`);
      // $FlowFixMe typeof above is not enough?
      plugin.define(server, db);
    } else {
      debug(`plugin '${plugin.name}' have no API definition`);
    }
  });

  return server;
}

export default createServer;
<commit_msg>Add bidirection navigation for pagination<commit_after>import express from "express";

import pkg from "../../package.json";

const debug = require("debug")("phenomic:core:api");

const encode = text => new Buffer(text).toString("base64");
const decode = text => new Buffer(text, "base64").toString();

const connect = (list, limit, previousList = []) => {
  const hasNextPage = limit === undefined ? false : list.length >= limit;
  const hasPreviousPage = previousList.length > 0;
  return {
    hasPreviousPage,
    previousPageIsFirst: previousList.length <= limit,
    previous: hasPreviousPage
      ? encode(previousList[previousList.length - 2].key)
      : null,
    hasNextPage,
    next: hasNextPage ? encode(list[list.length - 1].key) : null,
    list: list.slice(0, limit)
  };
};

function createServer(db: PhenomicDB, plugins: PhenomicPlugins) {
  debug("creating server");
  const server = express();

  server.get("/", async function(req: express$Request, res: express$Response) {
    debug("get api version");
    res.json({
      engine: "phenomic",
      version: pkg.version
    });
  });

  server.get("/:collection/by-:filter/:value/:order.json", async function(
    req: express$Request,
    res: express$Response
  ) {
    debug(req.url, JSON.stringify(req.params));
    try {
      const reverse = req.params.order === "desc";
      const list = await db.getList(
        req.params.collection,
        { reverse },
        req.params.filter,
        req.params.value
      );
      res.json(connect(list));
    } catch (error) {
      console.error(error);
      res.status(404).end();
    }
  });

  server.get(
    "/:collection/by-:filter/:value/:order/limit-:limit.json",
    async function(req: express$Request, res: express$Response) {
      debug(req.url, JSON.stringify(req.params));
      try {
        const limit = parseInt(req.params.limit);
        const reverse = req.params.order === "desc";
        const list = await db.getList(
          req.params.collection,
          {
            limit: limit + 1,
            reverse
          },
          req.params.filter,
          req.params.value
        );
        res.json(connect(list, limit));
      } catch (error) {
        console.error(error);
        res.status(404).end();
      }
    }
  );

  server.get(
    "/:collection/by-:filter/:value/:order/limit-:limit/after-:after.json",
    async function(req: express$Request, res: express$Response) {
      debug(req.url, JSON.stringify(req.params));
      try {
        const limit = parseInt(req.params.limit);
        const lte = decode(req.params.after);
        // @todo check lt validity (exist?); otherwise, trigger an error (404?)
        // cause during dev all "lt" are responding 200, even random values
        // but in production, it's not the case as only known values are
        // generated as endpoints
        const reverse = req.params.order === "desc";
        const [list, previousList] = await Promise.all([
          db.getList(
            req.params.collection,
            {
              limit: limit + 1,
              lte,
              reverse
            },
            req.params.filter,
            req.params.value
          ),
          db.getList(
            req.params.collection,
            {
              limit: limit + 1,
              gt: lte,
              reverse: !reverse
            },
            req.params.filter,
            req.params.value
          )
        ]);
        res.json(connect(list, limit, previousList));
      } catch (error) {
        console.error(error);
        res.status(404).end();
      }
    }
  );

  server.get("/:collection/item/*.json", async function(
    req: express$Request,
    res: express$Response
  ) {
    debug(req.url, JSON.stringify(req.params));
    try {
      const resource = await db.get(req.params.collection, req.params["0"]);
      res.json(resource.value);
    } catch (error) {
      console.error(error);
      res.status(404).end();
    }
  });

  // Install the plugins
  plugins.forEach(plugin => {
    if (typeof plugin.define === "function") {
      debug(`installing plugin '${plugin.name}'`);
      // $FlowFixMe typeof above is not enough?
      plugin.define(server, db);
    } else {
      debug(`plugin '${plugin.name}' have no API definition`);
    }
  });

  return server;
}

export default createServer;
<|endoftext|>


<commit_before>// Amara, universalsubtitles.org
//
// Copyright (C) 2012 Participatory Culture Foundation
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see
// http://www.gnu.org/licenses/agpl-3.0.html.

goog.provide('unisubs.widget.HangingVideoTab');

/**
 * @constructor
 * @param {boolean=} opt_forAnchoring If true, will add a style that gives
 *     the tab absolute position.
 * @implements {unisubs.widget.VideoTab}
 */
unisubs.widget.HangingVideoTab = function(opt_forAnchoring) {
    goog.ui.Component.call(this);
    this.anchorElem_ = null;
    this.imageElem_ = null;
    this.spanElem_ = null;
    this.nudgeElem_ = null;
    this.nudgeSpanElem_ = null;
    this.nudgeClickCallback_ = null;
    this.shareSpanElem_ = null;
    this.shareElem_ = null;
    this.forAnchoring_ = !!opt_forAnchoring;
    this.spinnerGifURL_ = unisubs.imageAssetURL('spinner.gif');
    this.logoURL_ = unisubs.imageAssetURL('small_logo.png');
    this.imageLoader_ = new goog.net.ImageLoader();
    this.imageLoader_.addImage('spinner', this.spinnerGifURL_);
    this.imageLoader_.addImage('small_logo', this.logoURL_);
    this.imageLoader_.start();
};
goog.inherits(unisubs.widget.HangingVideoTab, goog.ui.Component);

unisubs.widget.HangingVideoTab.prototype.createDom = function() {
    unisubs.widget.HangingVideoTab.superClass_.createDom.call(this);
    goog.dom.classes.add(
        this.getElement(),
        "cleanslate", "unisubs-videoTab", 'unisubs-videoTab-' +
            (this.forAnchoring_ ? 'anchoring' : 'static'));
    var $d = goog.bind(this.getDomHelper().createDom, this.getDomHelper());
    this.imageElem_ = $d('img', {'alt': 'small logo'});
    this.spanElem_ = $d('span', 'unisubs-tabTextchoose');
    this.anchorElem_ =
        $d('a', {'className': 'unisubs-subtitleMeLink', 'href':'javascript:void(0);'},
           this.imageElem_, this.spanElem_);
    this.nudgeSpanElem_ = $d('span', 'unisubs-tabTextfinish', 'NUDGE TEXT');
    this.nudgeElem_ = $d('a', {'href':'#'}, this.nudgeSpanElem_);
    goog.dom.append(this.getElement(),
                    this.anchorElem_, this.nudgeElem_);
};

unisubs.widget.HangingVideoTab.prototype.enterDocument = function() {
    unisubs.widget.HangingVideoTab.superClass_.enterDocument.call(this);
    this.showNudge(false);
    this.getHandler().
        listen(this.nudgeElem_, 'click', this.nudgeClicked_);
};

unisubs.widget.HangingVideoTab.prototype.getAnchorElem = function() {
    return this.anchorElem_;
};

unisubs.widget.HangingVideoTab.prototype.showLoading = function() {
    this.imageElem_.src = this.spinnerGifURL_;
    goog.dom.setTextContent(this.spanElem_, "Loading");
};

/**
* Shows the error message on the video tab and never attaches
* any interaction handlers on the widget.
* @param {str=} msg An optional message explaining what went wrong
**/
unisubs.widget.HangingVideoTab.prototype.showError = function(msg) {
    this.imageElem_.src = this.logoURL_;
    goog.dom.setTextContent(this.spanElem_, msg || "Subs Unavailable");
    this.getHandler().listen(
        this.anchorElem_,
        'click',
        function(e) {
            e.preventDefault();
        });
};

/**
 * Just stops loading. If state has changed, stop loading by
 * calling showContent instead.
 *
 */
unisubs.widget.HangingVideoTab.prototype.stopLoading = function() {
    this.imageElem_.src = this.logoURL_;
    if (this.text_)
        goog.dom.setTextContent(this.spanElem_, this.text_);
};

/**
 * Stops loading, and shows text appropriate for content.
 * @param {boolean} hasSubtitles Do subs currently exist for this video?
 * @param {unisubs.widget.SubtitleState=} opt_playSubState Subtitles
 *     that are currently loaded to play in widget.
 */
unisubs.widget.HangingVideoTab.prototype.showContent = function(
    hasSubtitles, opt_playSubState)
{

    if (!hasSubtitles && window.VIDEO_TEAM_NAME !== '' && window.VIDEO_TEAM_WORKFLOW_ENABLED === true) {
        this.show(false);
    }

    this.imageElem_.src = this.logoURL_;
    var text;
    if (opt_playSubState)
        text = opt_playSubState.LANGUAGE ?
            unisubs.languageNameForCode(opt_playSubState.LANGUAGE) :
            "Original Language";
    else
        text = hasSubtitles ? "Select Language" : "Subtitle Me";
    this.text_ = text;
    goog.dom.setTextContent(this.spanElem_, text);
};

unisubs.widget.HangingVideoTab.prototype.nudgeClicked_ = function(e) {
    e.preventDefault();
    unisubs.Tracker.getInstance().trackPageview('Clicks_Improve_Subtitles_or_translation');
    if (this.nudgeClickCallback_)
        this.nudgeClickCallback_();
};

unisubs.widget.HangingVideoTab.prototype.showNudge = function(shows) {
    unisubs.style.setVisibility(this.nudgeElem_, shows);
    unisubs.style.setVisibility(this.nudgeSpanElem_, shows);
     if (shows){
         unisubs.style.setProperty(this.nudgeElem_, 'width', null);

     }else{
         unisubs.style.setWidth(this.nudgeElem_, 0);
     }
    return;
};

/*
 * Creates the share button next to the 'subtitle me', only if
 * this is an off site widget. When clicked will be taken to the
 * url provided.
 * @param shareURL {goog.URI} The url for the 'share' link.
 * @param newWindow {bool=} If true will open on new window.
 */
unisubs.widget.HangingVideoTab.prototype.createShareButton = function (shareURL, newWindow) {
    // users can make share button never show by setting UNISUBS_HIDESHARE.
    // see https://www.pivotaltracker.com/story/show/13700869
    if (!unisubs.isEmbeddedInDifferentDomain() || window['UNISUBS_HIDESHARE']) {
        // no point in taking to the unisubs site if we're here already
        return;
    }
    if(!this.shareElem_){
        var $d = goog.bind(this.getDomHelper().createDom, this.getDomHelper());
        this.shareSpanElem_ = $d('span', {'href':'', 'class':'unisubs-tabTextShare'}, 'Share');
        this.shareElem_ = $d('a', {'href':'', 'class':''}, this.shareSpanElem_);
        this.getElement().appendChild(this.shareElem_);
    }
    var target= newWindow ? "_blank" : "_self";
    goog.dom.setProperties(this.shareElem_, {"href": shareURL.toString(), "target":target});
};

unisubs.widget.HangingVideoTab.prototype.updateNudge = function(text, fn) {
    goog.dom.setTextContent(this.nudgeSpanElem_, text);
    this.nudgeClickCallback_ = fn;
};
unisubs.widget.HangingVideoTab.prototype.show = function(shown) {
    unisubs.style.showElement(this.getElement(), shown);
};
unisubs.widget.HangingVideoTab.prototype.disposeInternal = function() {
    unisubs.widget.HangingVideoTab.superClass_.disposeInternal.call(this);
    this.imageLoader_.dispose();
};
<commit_msg>Debug statement for JS error that happens on staging and not on local.<commit_after>// Amara, universalsubtitles.org
//
// Copyright (C) 2012 Participatory Culture Foundation
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see
// http://www.gnu.org/licenses/agpl-3.0.html.

goog.provide('unisubs.widget.HangingVideoTab');

/**
 * @constructor
 * @param {boolean=} opt_forAnchoring If true, will add a style that gives
 *     the tab absolute position.
 * @implements {unisubs.widget.VideoTab}
 */
unisubs.widget.HangingVideoTab = function(opt_forAnchoring) {
    goog.ui.Component.call(this);
    this.anchorElem_ = null;
    this.imageElem_ = null;
    this.spanElem_ = null;
    this.nudgeElem_ = null;
    this.nudgeSpanElem_ = null;
    this.nudgeClickCallback_ = null;
    this.shareSpanElem_ = null;
    this.shareElem_ = null;
    this.forAnchoring_ = !!opt_forAnchoring;
    this.spinnerGifURL_ = unisubs.imageAssetURL('spinner.gif');
    this.logoURL_ = unisubs.imageAssetURL('small_logo.png');
    this.imageLoader_ = new goog.net.ImageLoader();
    this.imageLoader_.addImage('spinner', this.spinnerGifURL_);
    this.imageLoader_.addImage('small_logo', this.logoURL_);
    this.imageLoader_.start();
};
goog.inherits(unisubs.widget.HangingVideoTab, goog.ui.Component);

unisubs.widget.HangingVideoTab.prototype.createDom = function() {
    unisubs.widget.HangingVideoTab.superClass_.createDom.call(this);
    goog.dom.classes.add(
        this.getElement(),
        "cleanslate", "unisubs-videoTab", 'unisubs-videoTab-' +
            (this.forAnchoring_ ? 'anchoring' : 'static'));
    var $d = goog.bind(this.getDomHelper().createDom, this.getDomHelper());
    this.imageElem_ = $d('img', {'alt': 'small logo'});
    this.spanElem_ = $d('span', 'unisubs-tabTextchoose');
    this.anchorElem_ =
        $d('a', {'className': 'unisubs-subtitleMeLink', 'href':'javascript:void(0);'},
           this.imageElem_, this.spanElem_);
    this.nudgeSpanElem_ = $d('span', 'unisubs-tabTextfinish', 'NUDGE TEXT');
    this.nudgeElem_ = $d('a', {'href':'#'}, this.nudgeSpanElem_);
    goog.dom.append(this.getElement(),
                    this.anchorElem_, this.nudgeElem_);
};

unisubs.widget.HangingVideoTab.prototype.enterDocument = function() {
    unisubs.widget.HangingVideoTab.superClass_.enterDocument.call(this);
    this.showNudge(false);
    this.getHandler().
        listen(this.nudgeElem_, 'click', this.nudgeClicked_);
};

unisubs.widget.HangingVideoTab.prototype.getAnchorElem = function() {
    return this.anchorElem_;
};

unisubs.widget.HangingVideoTab.prototype.showLoading = function() {
    this.imageElem_.src = this.spinnerGifURL_;
    goog.dom.setTextContent(this.spanElem_, "Loading");
};

/**
* Shows the error message on the video tab and never attaches
* any interaction handlers on the widget.
* @param {str=} msg An optional message explaining what went wrong
**/
unisubs.widget.HangingVideoTab.prototype.showError = function(msg) {
    this.imageElem_.src = this.logoURL_;
    goog.dom.setTextContent(this.spanElem_, msg || "Subs Unavailable");
    this.getHandler().listen(
        this.anchorElem_,
        'click',
        function(e) {
            e.preventDefault();
        });
};

/**
 * Just stops loading. If state has changed, stop loading by
 * calling showContent instead.
 *
 */
unisubs.widget.HangingVideoTab.prototype.stopLoading = function() {
    this.imageElem_.src = this.logoURL_;
    if (this.text_)
        goog.dom.setTextContent(this.spanElem_, this.text_);
};

/**
 * Stops loading, and shows text appropriate for content.
 * @param {boolean} hasSubtitles Do subs currently exist for this video?
 * @param {unisubs.widget.SubtitleState=} opt_playSubState Subtitles
 *     that are currently loaded to play in widget.
 */
unisubs.widget.HangingVideoTab.prototype.showContent = function(
    hasSubtitles, opt_playSubState)
{

    console.log(hasSubtitles);
    if (!hasSubtitles && window.VIDEO_TEAM_NAME !== '' && window.VIDEO_TEAM_WORKFLOW_ENABLED === true) {
        this.show(false);
    }

    this.imageElem_.src = this.logoURL_;
    var text;
    if (opt_playSubState)
        text = opt_playSubState.LANGUAGE ?
            unisubs.languageNameForCode(opt_playSubState.LANGUAGE) :
            "Original Language";
    else
        text = hasSubtitles ? "Select Language" : "Subtitle Me";
    this.text_ = text;
    goog.dom.setTextContent(this.spanElem_, text);
};

unisubs.widget.HangingVideoTab.prototype.nudgeClicked_ = function(e) {
    e.preventDefault();
    unisubs.Tracker.getInstance().trackPageview('Clicks_Improve_Subtitles_or_translation');
    if (this.nudgeClickCallback_)
        this.nudgeClickCallback_();
};

unisubs.widget.HangingVideoTab.prototype.showNudge = function(shows) {
    unisubs.style.setVisibility(this.nudgeElem_, shows);
    unisubs.style.setVisibility(this.nudgeSpanElem_, shows);
     if (shows){
         unisubs.style.setProperty(this.nudgeElem_, 'width', null);

     }else{
         unisubs.style.setWidth(this.nudgeElem_, 0);
     }
    return;
};

/*
 * Creates the share button next to the 'subtitle me', only if
 * this is an off site widget. When clicked will be taken to the
 * url provided.
 * @param shareURL {goog.URI} The url for the 'share' link.
 * @param newWindow {bool=} If true will open on new window.
 */
unisubs.widget.HangingVideoTab.prototype.createShareButton = function (shareURL, newWindow) {
    // users can make share button never show by setting UNISUBS_HIDESHARE.
    // see https://www.pivotaltracker.com/story/show/13700869
    if (!unisubs.isEmbeddedInDifferentDomain() || window['UNISUBS_HIDESHARE']) {
        // no point in taking to the unisubs site if we're here already
        return;
    }
    if(!this.shareElem_){
        var $d = goog.bind(this.getDomHelper().createDom, this.getDomHelper());
        this.shareSpanElem_ = $d('span', {'href':'', 'class':'unisubs-tabTextShare'}, 'Share');
        this.shareElem_ = $d('a', {'href':'', 'class':''}, this.shareSpanElem_);
        this.getElement().appendChild(this.shareElem_);
    }
    var target= newWindow ? "_blank" : "_self";
    goog.dom.setProperties(this.shareElem_, {"href": shareURL.toString(), "target":target});
};

unisubs.widget.HangingVideoTab.prototype.updateNudge = function(text, fn) {
    goog.dom.setTextContent(this.nudgeSpanElem_, text);
    this.nudgeClickCallback_ = fn;
};
unisubs.widget.HangingVideoTab.prototype.show = function(shown) {
    unisubs.style.showElement(this.getElement(), shown);
};
unisubs.widget.HangingVideoTab.prototype.disposeInternal = function() {
    unisubs.widget.HangingVideoTab.superClass_.disposeInternal.call(this);
    this.imageLoader_.dispose();
};
<|endoftext|>


<commit_before>import postcss from 'postcss';
import valueParser from 'postcss-value-parser';
import SVGO from 'svgo';
import isSvg from 'is-svg';
import {encode, decode} from './lib/url';

const PLUGIN = 'postcss-svgo';
const dataURI = /data:image\/svg\+xml(;((charset=)?utf-8|base64))?,/i;
const dataURIBase64 = /data:image\/svg\+xml;base64,/i;

function minifyPromise (svgo, decl, opts) {
    const promises = [];

    decl.value = valueParser(decl.value).walk(node => {
        if (node.type !== 'function' || node.value.toLowerCase() !== 'url' || !node.nodes.length) {
            return;
        }

        let {value, quote} = node.nodes[0];
        let isBase64, isUriEncoded;
        let svg = value.replace(dataURI, '');

        if (dataURIBase64.test(value)) {
            svg = Buffer.from(svg, 'base64').toString('utf8');
            isBase64 = true;
        } else {
            let decodedUri;

            try {
                decodedUri = decode(svg);
                isUriEncoded = decodedUri !== svg;
            } catch (e) {
                // Swallow exception if we cannot decode the value
                isUriEncoded = false;
            }

            if (isUriEncoded) {
                svg = decodedUri;
            }
            if (opts.encode !== undefined) {
                isUriEncoded = opts.encode;
            }
        }

        if (!isSvg(svg)) {
            return;
        }

        promises.push(
            svgo.optimize(svg)
                .then(result => {
                    let data, optimizedValue;

                    if (isBase64) {
                        data = Buffer.from(result.data).toString('base64');
                        optimizedValue = 'data:image/svg+xml;base64,' + data;
                    } else {
                        data = isUriEncoded ? encode(result.data) : result.data;
                        // Should always encode # otherwise we yield a broken SVG
                        // in Firefox (works in Chrome however). See this issue:
                        // https://github.com/cssnano/cssnano/issues/245
                        data = data.replace(/#/g, '%23');
                        optimizedValue = 'data:image/svg+xml;charset=utf-8,' + data;
                        quote = isUriEncoded ? '"' : '\'';
                    }

                    node.nodes[0] = Object.assign({}, node.nodes[0], {
                        value: optimizedValue,
                        quote: quote,
                        type: 'string',
                        before: '',
                        after: '',
                    });
                })
                .catch(error => {
                    throw new Error(`${PLUGIN}: ${error}`);
                })
        );

        return false;
    });

    return Promise.all(promises).then(() => (decl.value = decl.value.toString()));
}

export default postcss.plugin(PLUGIN, (opts = {}) => {
    const svgo = new SVGO(opts);
    return css => {
        return new Promise((resolve, reject) => {
            const promises = [];
            css.walkDecls(decl => {
                if (dataURI.test(decl.value)) {
                    promises.push(minifyPromise(svgo, decl, opts));
                }
            });
            return Promise.all(promises).then(resolve, reject);
        });
    };
});
<commit_msg>perf(postcss-svgo): increase perf (#698)<commit_after>import postcss from 'postcss';
import valueParser from 'postcss-value-parser';
import SVGO from 'svgo';
import isSvg from 'is-svg';
import {encode, decode} from './lib/url';

const PLUGIN = 'postcss-svgo';
const dataURI = /data:image\/svg\+xml(;((charset=)?utf-8|base64))?,/i;
const dataURIBase64 = /data:image\/svg\+xml;base64,/i;

function minifyPromise (decl, getSvgo, opts) {
    const promises = [];
    const parsed = valueParser(decl.value);

    decl.value = parsed.walk(node => {
        if (node.type !== 'function' || node.value.toLowerCase() !== 'url' || !node.nodes.length) {
            return;
        }

        let {value, quote} = node.nodes[0];
        let isBase64, isUriEncoded;
        let svg = value.replace(dataURI, '');

        if (dataURIBase64.test(value)) {
            svg = Buffer.from(svg, 'base64').toString('utf8');
            isBase64 = true;
        } else {
            let decodedUri;

            try {
                decodedUri = decode(svg);
                isUriEncoded = decodedUri !== svg;
            } catch (e) {
                // Swallow exception if we cannot decode the value
                isUriEncoded = false;
            }

            if (isUriEncoded) {
                svg = decodedUri;
            }

            if (opts.encode !== undefined) {
                isUriEncoded = opts.encode;
            }
        }

        if (!isSvg(svg)) {
            return;
        }

        promises.push(
            getSvgo().optimize(svg)
                .then(result => {
                    let data, optimizedValue;

                    if (isBase64) {
                        data = Buffer.from(result.data).toString('base64');
                        optimizedValue = 'data:image/svg+xml;base64,' + data;
                    } else {
                        data = isUriEncoded ? encode(result.data) : result.data;
                        // Should always encode # otherwise we yield a broken SVG
                        // in Firefox (works in Chrome however). See this issue:
                        // https://github.com/cssnano/cssnano/issues/245
                        data = data.replace(/#/g, '%23');
                        optimizedValue = 'data:image/svg+xml;charset=utf-8,' + data;
                        quote = isUriEncoded ? '"' : '\'';
                    }

                    node.nodes[0] = Object.assign({}, node.nodes[0], {
                        value: optimizedValue,
                        quote: quote,
                        type: 'string',
                        before: '',
                        after: '',
                    });
                })
                .catch(error => {
                    throw new Error(`${PLUGIN}: ${error}`);
                })
        );

        return false;
    });

    return Promise.all(promises).then(() => (decl.value = decl.value.toString()));
}

export default postcss.plugin(PLUGIN, (opts = {}) => {
    let svgo = null;

    const getSvgo = () => {
        if (!svgo) {
            svgo = new SVGO(opts);
        }

        return svgo;
    };

    return css => {
        return new Promise((resolve, reject) => {
            const svgoQueue = [];

            css.walkDecls(decl => {
                if (!dataURI.test(decl.value)) {
                    return;
                }

                svgoQueue.push(minifyPromise(decl, getSvgo, opts));
            });

            return Promise.all(svgoQueue).then(resolve, reject);
        });
    };
});
<|endoftext|>


<commit_before>// Minimum number of installed extensions, used for toggling user
// recommendations and "Starter Pack" promo pane.
var MIN_EXTENSIONS = 3;

// Parse GUIDS of installed extensions from JSON fragment.
var guids = getGuids();

$(document).ready(function(){
    if ($(".pane").length) {
        initSidebar();

        storePaneLink();

        // Show "Starter Pack" panel only if user has fewer than three extensions.
        if (guids.length >= MIN_EXTENSIONS) {
            $("#starter").closest(".panel").remove();
        }

        initRecs();

        // Set up the promo carousel.
        $("#main-feature").fadeIn("slow").addClass("js").jCarouselLite({
            btnNext: "#main-feature .nav-next a",
            btnPrev: "#main-feature .nav-prev a",
            visible: 1
        });

        initTrunc();
    }
});

function getGuids() {
    // Store GUIDs of installed extensions.
    var guids = [];
    if (location.hash) {
        $.each(JSON.parse(location.hash.slice(1)), function(i, val) {
            if (val.type == "extension") {
                guids.push(i);
            }
        });
    }
    return guids;
}

function storePaneLink() {
    // Store the pane URL so we can link back from the add-on detail pages.
    if (z.hasLocalStorage) {
        localStorage.setItem("discopane-url", location);
    } else {
        $.cookie("discopane-url", location, {path: "/"});
    }
}

function initTrunc() {
    // Trim the add-on title and description text to fit.
    $(".addons h3, .rec-addons h3, p.desc").vtruncate();
    $(window).resize(debounce(function() {
        $(".addons h3 a, .rec-addons h3 a, p.desc").vtruncate();
    }, 200));
}

function initSidebar() {
    var account_url = document.body.getAttribute("data-account-url");
    $.get(account_url, function(data) {
        var $data = $(data);
        if ($data.find("#my-account").length) {
            $("header").addClass("auth");
        }
        $("#right-module").replaceWith(data).slideDown("slow");
    });
}

function initRecs() {
    var showRecs = JSON.parse(document.body.getAttribute("data-show-recs"));
    // Where all the current recommendations data is kept.
    var datastore = {};

    var token2;

    if (z.hasLocalStorage && (!location.hash || !guids.length)) {
        // If the user has opted out of recommendations, clear out any
        // existing recommendations.
        localStorage.removeItem("discopane-recs");
        localStorage.removeItem("discopane-guids");
    }

    function populateRecs() {
        if (datastore.addons !== undefined && datastore.addons.length) {
            var addon_item = template('
' +
                '' +
                '' +
                '
{name}
' +
                '
{summary}
' +
                '
');
            var persona_item = template('
' +
                '' +
                '
{name}
' +
                '
' +
                '
' +
                '
' +
                '

' +
                '

' +
                '
');

            $.each(datastore.addons, function(i, addon) {
                var li;
                if (addon.type == 'persona') {
                    li = persona_item({
                        url: addon.learnmore,
                        name: addon.name,
                        preview: addon.previews[0]
                    });
                } else {
                    li = addon_item({
                        url: addon.learnmore,
                        icon: addon.icon,
                        name: addon.name,
                        summary: $("" + (addon.summary != null ? addon.summary : "") + "").text()
                    });
                }
                $("#recs .slider").append(li);
            });
            $("#recs .gallery").fadeIn("slow").addClass("js").jCarouselLite({
                btnNext: "#recs .nav-next a",
                btnPrev: "#recs .nav-prev a",
                scroll: 3,
                circular: false
            });
            $("#recs #nav-recs").fadeIn("slow").addClass("js");
            setPanelWidth("pane");
            initTrunc();
            $("#recs .persona-preview").previewPersona(true);
        } else {
            var addons_url = $("#more-addons a").attr("href");
            var msg = format(gettext(
                "Sorry, we couldn't find any recommendations for you.
" +
                'Please visit the add-ons site to ' +
                "find an add-on that's right for you."), [addons_url]);
            $("#recs .gallery").hide();
            $("#recs").append('

' + msg + "

");
        }
    }

    // Hide "What are Add-ons?" and show "Recommended for You" module.
    if (showRecs && guids.length > MIN_EXTENSIONS) {
        $("body").removeClass("no-recs").addClass("recs");

        var cacheObject;
        if (z.hasLocalStorage) {
            cacheObject = localStorage.getItem("discopane-recs");
            if (cacheObject) {
                // Load local data.
                cacheObject = JSON.parse(cacheObject);
                if (cacheObject) {
                    datastore = cacheObject;
                    token2 = cacheObject.token2;
                }
            }
        }

        // Get new recommendations if there are no saved recommendations or
        // if the user has new installed add-ons.
        var findRecs = !cacheObject;
        var updateRecs = (
            cacheObject && z.hasLocalStorage &&
            localStorage.getItem("discopane-guids") != guids.toString()
        );
        if (findRecs || updateRecs) {
            var msg;
            if (findRecs) {
                msg = gettext("Finding recommendations…");
            } else if (updateRecs) {
                msg = gettext("Updating recommendations…");
            }
            $("#recs .gallery").hide();
            $("#recs").append('

' +
                              msg + "

");

            var data = {"guids": guids};
            if (token2) {
                data["token2"] = token2;
            }
            datastore = {};
            $.ajax({
                url: document.body.getAttribute("data-recs-url"),
                type: "post",
                data: JSON.stringify(data),
                dataType: "text",
                success: function(raw_data) {
                    $("#recs .loading").remove();
                    datastore = JSON.parse(raw_data);
                    populateRecs();
                    if (z.hasLocalStorage) {
                        localStorage.setItem("discopane-recs", raw_data);
                        localStorage.setItem("discopane-guids", guids);
                    }
                },
                error: function(raw_data) {
                    $("#recs .loading").remove();
                    populateRecs();
                    if (z.hasLocalStorage) {
                        localStorage.setItem("discopane-recs", "{}");
                        localStorage.setItem("discopane-guids", guids);
                    }
                }
            });
        } else {
            populateRecs();
        }
    }
}
<commit_msg>remember when we update so we can refresh later on<commit_after>// Minimum number of installed extensions, used for toggling user
// recommendations and "Starter Pack" promo pane.
var MIN_EXTENSIONS = 3;

// Parse GUIDS of installed extensions from JSON fragment.
var guids = getGuids();

$(document).ready(function(){
    if ($(".pane").length) {
        initSidebar();

        storePaneLink();

        // Show "Starter Pack" panel only if user has fewer than three extensions.
        if (guids.length >= MIN_EXTENSIONS) {
            $("#starter").closest(".panel").remove();
        }

        initRecs();

        // Set up the promo carousel.
        $("#main-feature").fadeIn("slow").addClass("js").jCarouselLite({
            btnNext: "#main-feature .nav-next a",
            btnPrev: "#main-feature .nav-prev a",
            visible: 1
        });

        initTrunc();
    }
});

function getGuids() {
    // Store GUIDs of installed extensions.
    var guids = [];
    if (location.hash) {
        $.each(JSON.parse(location.hash.slice(1)), function(i, val) {
            if (val.type == "extension") {
                guids.push(i);
            }
        });
    }
    return guids;
}

function storePaneLink() {
    // Store the pane URL so we can link back from the add-on detail pages.
    if (z.hasLocalStorage) {
        localStorage.setItem("discopane-url", location);
    } else {
        $.cookie("discopane-url", location, {path: "/"});
    }
}

function initTrunc() {
    // Trim the add-on title and description text to fit.
    $(".addons h3, .rec-addons h3, p.desc").vtruncate();
    $(window).resize(debounce(function() {
        $(".addons h3 a, .rec-addons h3 a, p.desc").vtruncate();
    }, 200));
}

function initSidebar() {
    var account_url = document.body.getAttribute("data-account-url");
    $.get(account_url, function(data) {
        var $data = $(data);
        if ($data.find("#my-account").length) {
            $("header").addClass("auth");
        }
        $("#right-module").replaceWith(data).slideDown("slow");
    });
}

function initRecs() {
    var showRecs = JSON.parse(document.body.getAttribute("data-show-recs"));
    // Where all the current recommendations data is kept.
    var datastore = {};

    var token2;

    if (z.hasLocalStorage && (!location.hash || !guids.length)) {
        // If the user has opted out of recommendations, clear out any
        // existing recommendations.
        localStorage.removeItem("discopane-recs");
        localStorage.removeItem("discopane-guids");
    }

    function populateRecs() {
        if (datastore.addons !== undefined && datastore.addons.length) {
            var addon_item = template('
' +
                '' +
                '' +
                '
{name}
' +
                '
{summary}
' +
                '
');
            var persona_item = template('
' +
                '' +
                '
{name}
' +
                '
' +
                '
' +
                '
' +
                '

' +
                '

' +
                '
');

            $.each(datastore.addons, function(i, addon) {
                var li;
                if (addon.type == 'persona') {
                    li = persona_item({
                        url: addon.learnmore,
                        name: addon.name,
                        preview: addon.previews[0]
                    });
                } else {
                    li = addon_item({
                        url: addon.learnmore,
                        icon: addon.icon,
                        name: addon.name,
                        summary: $("" + (addon.summary != null ? addon.summary : "") + "").text()
                    });
                }
                $("#recs .slider").append(li);
            });
            $("#recs .gallery").fadeIn("slow").addClass("js").jCarouselLite({
                btnNext: "#recs .nav-next a",
                btnPrev: "#recs .nav-prev a",
                scroll: 3,
                circular: false
            });
            $("#recs #nav-recs").fadeIn("slow").addClass("js");
            setPanelWidth("pane");
            initTrunc();
            $("#recs .persona-preview").previewPersona(true);
        } else {
            var addons_url = $("#more-addons a").attr("href");
            var msg = format(gettext(
                "Sorry, we couldn't find any recommendations for you.
" +
                'Please visit the add-ons site to ' +
                "find an add-on that's right for you."), [addons_url]);
            $("#recs .gallery").hide();
            $("#recs").append('

' + msg + "

");
        }
    }

    // Hide "What are Add-ons?" and show "Recommended for You" module.
    if (showRecs && guids.length > MIN_EXTENSIONS) {
        $("body").removeClass("no-recs").addClass("recs");

        var cacheObject;
        if (z.hasLocalStorage) {
            cacheObject = localStorage.getItem("discopane-recs");
            if (cacheObject) {
                // Load local data.
                cacheObject = JSON.parse(cacheObject);
                if (cacheObject) {
                    datastore = cacheObject;
                    token2 = cacheObject.token2;
                }
            }
        }

        // Get new recommendations if there are no saved recommendations or
        // if the user has new installed add-ons.
        var findRecs = !cacheObject;
        var updateRecs = (
            cacheObject && z.hasLocalStorage &&
            localStorage.getItem("discopane-guids") != guids.toString()
        );
        if (findRecs || updateRecs) {
            var msg;
            if (findRecs) {
                msg = gettext("Finding recommendations…");
            } else if (updateRecs) {
                msg = gettext("Updating recommendations…");
            }
            $("#recs .gallery").hide();
            $("#recs").append('

' +
                              msg + "

");

            var data = {"guids": guids};
            if (token2) {
                data["token2"] = token2;
            }
            datastore = {};
            $.ajax({
                url: document.body.getAttribute("data-recs-url"),
                type: "post",
                data: JSON.stringify(data),
                dataType: "text",
                success: function(raw_data) {
                    $("#recs .loading").remove();
                    datastore = JSON.parse(raw_data);
                    populateRecs();
                    if (z.hasLocalStorage) {
                        localStorage.setItem("discopane-updated", new Date());
                        localStorage.setItem("discopane-recs", raw_data);
                        localStorage.setItem("discopane-guids", guids);
                    }
                },
                error: function(raw_data) {
                    $("#recs .loading").remove();
                    populateRecs();
                    if (z.hasLocalStorage) {
                        localStorage.setItem("discopane-recs", "{}");
                        localStorage.setItem("discopane-guids", guids);
                    }
                }
            });
        } else {
            populateRecs();
        }
    }
}
<|endoftext|>


<commit_before>import {
	add,
	remove,
	now
}
from './core';
import Easing from './Easing';
import Interpolation from './Interpolation';
import cloneTween from './clone';
import joinToString from './joinToString';
import toNumber from './toNumber';

// Credits:
// @jkroso for string parse library
// Optimized, Extended by @dalisoft
const Number_Match_RegEx = /\s+|([A-Za-z?().,{}:""\[\]#]+)|([-+\/*%]+=)?([-+*\/%]+)?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/gi;

class Tween {
	constructor(object = {}) {

		this.object = object;
		this._valuesStart = Tween.createEmptyConst(object);
		this._valuesEnd = Tween.createEmptyConst(object);
		this._chainedTweens = [];

		this._duration = 1000;
		this._easingFunction = Easing.Linear.None;
		this._interpolationFunction = Interpolation.None;

		this._startTime = 0;
		this._delayTime = 0;
		this._repeat = 0;
		this._r = 0;
		this._isPlaying = false;
		this._yoyo = false;
		this._reversed = false;

		this._onStartCallbackFired = false;
		this._events = {};
		this._pausedTime = 0;

		return this;

	}
	static createEmptyConst(oldObject) {
		return typeof(oldObject) === "number" ? 0 : Array.isArray(oldObject) ? [] : typeof(oldObject) === "object" ? {}
		 : '';
	}
	static checkValidness(valid) {
		return valid !== undefined && valid !== null && valid !== '' && valid !== NaN && valid !== Infinity;
	}
	isPlaying() {
		return this._isPlaying;
	}
	isStarted() {
		return this._onStartCallbackFired;
	}
	reverse() {

		const {
			_reversed
		} = this;

		this._reversed = !_reversed;

		return this;
	}
	reversed() {
		return this._reversed;
	}
	off(name, fn) {
		if (this._events[name] === undefined) {
			return this;
		}
		if (name !== undefined && fn !== undefined) {
			let eventsList = this._events[name],
			i = 0;
			while (i < eventsList.length) {
				if (eventsList[i] === fn) {
					eventsList.splice(i, 1);
				}
				i++;
			}
		} else if (name !== undefined && fn === undefined) {
			this._events[name] = [];
		}
		return this;
	}
	on(name, fn) {
		if (this._events[name] === undefined) {
			this._events[name] = [];
		}
		this._events[name].push(fn);
		return this;
	}
	once(name, fn) {
		if (this._events[name] === undefined) {
			this._events[name] = [];
		}
		return this.on(name, (...args) => {
			fn.call(this, ...args);
			this.off(name);
		});
	}
	emit(name, a, b, c, d, e) {

		let {
			_events
		} = this;

		let eventFn = _events[name];

		if (!eventFn) {
			return this;
		}

		let i = eventFn.length;
		while (i--) {
			eventFn[i].call(this, a, b, c, d, e);
		}
		return this;

	}
	pause() {

		if (!this._isPlaying) {
			return this;
		}

		this._isPlaying = false;

		remove(this);
		this._pausedTime = now();

		return this.emit('pause', this.object);
	}
	play() {

		if (this._isPlaying) {
			return this;
		}

		this._isPlaying = true;

		this._startTime += now() - this._pausedTime;
		add(this);
		this._pausedTime = now();

		return this.emit('play', this.object);
	}
	restart(noDelay) {

		this._repeat = this._r;
		this._startTime = now() + (noDelay ? 0 : this._delayTime);

		if (!this._isPlaying) {
			add(this);
		}

		return this.emit('restart', this._object);

	}
	seek(time, keepPlaying) {

		this._startTime = now() + Math.max(0, Math.min(
					time, this._duration));

		this.emit('seek', time, this._object);

		return keepPlaying ? this : this.pause();

	}
	duration(amount) {

		this._duration = typeof(amount) === "function" ? amount(this._duration) : amount;

		return this;
	}
	to(properties = {}, duration = 1000) {

		if (typeof properties === "number") {
			let _vE = {
				Number: properties
			};
			this._valuesEnd = _vE;
		} else {
			this._valuesEnd = properties;
		}

		if (typeof duration === "number") {
			this._duration = typeof(duration) === "function" ? duration(this._duration) : duration;
		} else if (typeof duration === "object") {
			for (let prop in duration) {
				this[prop](typeof duration[prop] === "function" ? duration[prop](this._duration) : duration);
			}
		}

		return this;

	}
	start(time) {

		let {
			_startTime,
			_delayTime,
			_valuesEnd,
			_valuesStart,
			object
		} = this;

		_startTime = time !== undefined ? time : now();
		_startTime += _delayTime;

		this._startTime = _startTime;

		for (let property in _valuesEnd) {

			if (typeof _valuesEnd[property] === "object") {
				if (Array.isArray(_valuesEnd[property])) {
					if (typeof object[property] === "number") {
						this._valuesEnd[property] = [object[property]].concat(_valuesEnd[property]);
					} else {
						let clonedTween = cloneTween(this, {
								object: object[property],
								_valuesEnd: _valuesEnd[property],
								_events: {}
							})
							.start()
							.stop();

						this._valuesEnd[property] = clonedTween;
					}
				} else {
					let clonedTween = cloneTween(this, {
							object: object[property],
							_valuesEnd: _valuesEnd[property],
							_events: {}
						})
						.start()
						.stop();

					this._valuesStart[property] = 1;
					this._valuesEnd[property] = clonedTween;
				}
			} else if (typeof _valuesEnd[property] === "string" && typeof object[property] === "string" && Number_Match_RegEx.test(object[property]) && Number_Match_RegEx.test(_valuesEnd[property])) {

				let __get__Start = object[property].match(Number_Match_RegEx);
				__get__Start = __get__Start.map(toNumber);
				let __get__End = _valuesEnd[property].match(Number_Match_RegEx);
				__get__End = __get__End.map(toNumber);
				let clonedTween = cloneTween(this, {
						object: __get__Start,
						_valuesEnd: __get__End,
						_events: {}
					})
					.start()
					.stop();

				clonedTween.join = true; // For string tweening
				this._valuesStart[property] = 1;
				this._valuesEnd[property] = clonedTween;

			}

			// If value presented as function,
			// we should convert to value again by passing function
			if (typeof object[property] === "function") {
				object[property] = this.object[property] = object[property](this);
			}

			if (typeof _valuesEnd[property] === "function") {
				this._valuesEnd[property] = _valuesEnd[property](this);
			}

			// If `to()` specifies a property that doesn't exist in the source object,
			// we should not set that property in the object
			if (Tween.checkValidness(object[property]) === false) {
				continue;
			}

			// If duplicate or non-tweening numerics matched,
			// we should skip from adding to _valuesStart
			if (object[property] === _valuesEnd[property]) {
				continue;
			}

			this._valuesStart[property] = object[property];

		}

		add(this);

		this._isPlaying = true;

		return this;

	}
	stop() {

		let {
			_isPlaying,
			object
		} = this;

		if (!_isPlaying) {
			return this;
		}

		remove(this);
		this._isPlaying = false;

		this.stopChainedTweens();
		return this.emit('stop', object);

	}
	end() {

		const {
			_startTime,
			_duration
		} = this;

		return this.update(_startTime + _duration);

	}
	stopChainedTweens() {

		let {
			_chainedTweens
		} = this;

		_chainedTweens.map(item => item.stop());

		return this;

	}
	delay(amount) {

		this._delayTime = typeof(amount) === "function" ? amount(this._delayTime) : amount;

		return this;

	}
	repeat(amount) {

		this._repeat = typeof(amount) === "function" ? amount(this._repeat) : amount;
		this._r = this._repeat;

		return this;

	}
	repeatDelay(amount) {

		this._repeatDelayTime = typeof(amount) === "function" ? amount(this._repeatDelayTime) : amount;

		return this;

	}
	reverseDelay(amount) {

		this._reverseDelayTime = typeof(amount) === "function" ? amount(this._reverseDelayTime) : amount;

		return this;

	}
	yoyo(state) {

		this._yoyo = typeof(state) === "function" ? state(this._yoyo) : state;

		return this;

	}
	easing(fn) {

		this._easingFunction = fn;

		return this;

	}
	interpolation(fn) {

		this._interpolationFunction = fn;

		return this;

	}
	chain(...args) {

		this._chainedTweens = args;

		return this;

	}
	get(time) {
		this.update(time);
		return this.object;
	}
	update(time) {

		let {
			_onStartCallbackFired,
			_chainedTweens,
			_easingFunction,
			_interpolationFunction,
			_repeat,
			_repeatDelayTime,
			_reverseDelayTime,
			_delayTime,
			_yoyo,
			_reversed,
			_startTime,
			_duration,
			_valuesStart,
			_valuesEnd,
			object
		} = this;

		let property;
		let elapsed;
		let value;

		time = time !== undefined ? time : now();

		if (time < _startTime) {
			return true;
		}

		if (!_onStartCallbackFired) {

			this.emit('start', object);

			this._onStartCallbackFired = true;
		}

		elapsed = (time - _startTime) / _duration;
		elapsed = elapsed > 1 ? 1 : elapsed;
		elapsed = _reversed ? 1 - elapsed : elapsed;

		value = _easingFunction(elapsed);

		for (property in _valuesEnd) {

			// Don't update properties that do not exist in the source object
			if (_valuesStart[property] === undefined) {
				continue;
			}

			let start = _valuesStart[property];
			let end = _valuesEnd[property];

			if (end instanceof Tween) {

				let getValue = end.get(time);

				if (end.join) {

					object[property] = joinToString(getValue);

				} else {

				object[property] = getValue;

				}

			} else if (Array.isArray(end)) {

				object[property] = _interpolationFunction(end, value);

			} else if (typeof(end) === 'string') {

				if (end.charAt(0) === '+' || end.charAt(0) === '-') {
					end = start + parseFloat(end);
				} else {
					end = parseFloat(end);
				}

				// Protect against non numeric properties.
				if (typeof(end) === 'number') {
					object[property] = start + (end - start) * value;
				}
			} else if (typeof(end) === 'number') {
				object[property] = start + (end - start) * value;
			}

		}

		this.emit('update', object, value, elapsed);

		if (elapsed === 1 || (_reversed && elapsed === 0)) {

			if (_repeat) {

				if (isFinite(_repeat)) {
					this._repeat--;
				}

				for (property in _valuesEnd) {

					if (typeof(_valuesEnd[property]) === 'string' && typeof(_valuesStart[property]) === 'number') {
						this._valuesStart[property] = _valuesStart[property] + parseFloat(_valuesEnd[property]);
					}

				}

				// Reassign starting values, restart by making startTime = now
				this.emit(_reversed ? 'reverse' : 'repeat', object);

				if (_yoyo) {
					this._reversed = !_reversed;
				}

				if (!_reversed && _repeatDelayTime) {
					this._startTime += _duration + _repeatDelayTime;
				} else if (_reversed && _reverseDelayTime) {
					this._startTime += _duration + _reverseDelayTime;
				} else {
					this._startTime += _duration;
				}

				return true;

			} else {

				this.emit('complete', object);

				_chainedTweens.map(tween => tween.start(_startTime + _duration));

				return false;

			}
		}
		return true;
	}
}

export default Tween;
<commit_msg>## USER FEATURE REQUEST<commit_after>import {
	add,
	remove,
	now
}
from './core';
import Easing from './Easing';
import Interpolation from './Interpolation';
import cloneTween from './clone';
import joinToString from './joinToString';
import toNumber from './toNumber';

// Credits:
// @jkroso for string parse library
// Optimized, Extended by @dalisoft
const Number_Match_RegEx = /\s+|([A-Za-z?().,{}:""\[\]#]+)|([-+\/*%]+=)?([-+*\/%]+)?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/gi;

class Tween {
	constructor(object = {}, instate) {

		this.object = object;
		this._valuesStart = Tween.createEmptyConst(object);
		this._valuesEnd = Tween.createEmptyConst(object);
		this._chainedTweens = [];

		this._duration = 1000;
		this._easingFunction = Easing.Linear.None;
		this._interpolationFunction = Interpolation.None;

		this._startTime = 0;
		this._delayTime = 0;
		this._repeat = 0;
		this._r = 0;
		this._isPlaying = false;
		this._yoyo = false;
		this._reversed = false;

		this._onStartCallbackFired = false;
		this._events = {};
		this._pausedTime = 0;

		if (instate && instate.to) {

			return new Tween(object).to(instate.to, instate);

		}

		return this;

	}
	static createEmptyConst(oldObject) {
		return typeof(oldObject) === "number" ? 0 : Array.isArray(oldObject) ? [] : typeof(oldObject) === "object" ? {}
		 : '';
	}
	static checkValidness(valid) {
		return valid !== undefined && valid !== null && valid !== '' && valid !== NaN && valid !== Infinity;
	}
	isPlaying() {
		return this._isPlaying;
	}
	isStarted() {
		return this._onStartCallbackFired;
	}
	reverse() {

		const {
			_reversed
		} = this;

		this._reversed = !_reversed;

		return this;
	}
	reversed() {
		return this._reversed;
	}
	off(name, fn) {
		if (this._events[name] === undefined) {
			return this;
		}
		if (name !== undefined && fn !== undefined) {
			let eventsList = this._events[name],
			i = 0;
			while (i < eventsList.length) {
				if (eventsList[i] === fn) {
					eventsList.splice(i, 1);
				}
				i++;
			}
		} else if (name !== undefined && fn === undefined) {
			this._events[name] = [];
		}
		return this;
	}
	on(name, fn) {
		if (this._events[name] === undefined) {
			this._events[name] = [];
		}
		this._events[name].push(fn);
		return this;
	}
	once(name, fn) {
		if (this._events[name] === undefined) {
			this._events[name] = [];
		}
		return this.on(name, (...args) => {
			fn.call(this, ...args);
			this.off(name);
		});
	}
	emit(name, a, b, c, d, e) {

		let {
			_events
		} = this;

		let eventFn = _events[name];

		if (!eventFn) {
			return this;
		}

		let i = eventFn.length;
		while (i--) {
			eventFn[i].call(this, a, b, c, d, e);
		}
		return this;

	}
	pause() {

		if (!this._isPlaying) {
			return this;
		}

		this._isPlaying = false;

		remove(this);
		this._pausedTime = now();

		return this.emit('pause', this.object);
	}
	play() {

		if (this._isPlaying) {
			return this;
		}

		this._isPlaying = true;

		this._startTime += now() - this._pausedTime;
		add(this);
		this._pausedTime = now();

		return this.emit('play', this.object);
	}
	restart(noDelay) {

		this._repeat = this._r;
		this._startTime = now() + (noDelay ? 0 : this._delayTime);

		if (!this._isPlaying) {
			add(this);
		}

		return this.emit('restart', this._object);

	}
	seek(time, keepPlaying) {

		this._startTime = now() + Math.max(0, Math.min(
					time, this._duration));

		this.emit('seek', time, this._object);

		return keepPlaying ? this : this.pause();

	}
	duration(amount) {

		this._duration = typeof(amount) === "function" ? amount(this._duration) : amount;

		return this;
	}
	to(properties = {}, duration = 1000) {

		if (typeof properties === "number") {
			let _vE = {
				Number: properties
			};
			this._valuesEnd = _vE;
		} else {
			this._valuesEnd = properties;
		}

		if (typeof duration === "number") {
			this._duration = typeof(duration) === "function" ? duration(this._duration) : duration;
		} else if (typeof duration === "object") {
			for (let prop in duration) {
				if (this[prop]) {
				this[prop](typeof duration[prop] === "function" ? duration[prop](this._duration) : duration);
				}
			}
		}

		return this;

	}
	start(time) {

		let {
			_startTime,
			_delayTime,
			_valuesEnd,
			_valuesStart,
			object
		} = this;

		_startTime = time !== undefined ? time : now();
		_startTime += _delayTime;

		this._startTime = _startTime;

		for (let property in _valuesEnd) {

			if (typeof _valuesEnd[property] === "object") {
				if (Array.isArray(_valuesEnd[property])) {
					if (typeof object[property] === "number") {
						this._valuesEnd[property] = [object[property]].concat(_valuesEnd[property]);
					} else {
						let clonedTween = cloneTween(this, {
								object: object[property],
								_valuesEnd: _valuesEnd[property],
								_events: {}
							})
							.start()
							.stop();

						this._valuesEnd[property] = clonedTween;
					}
				} else {
					let clonedTween = cloneTween(this, {
							object: object[property],
							_valuesEnd: _valuesEnd[property],
							_events: {}
						})
						.start()
						.stop();

					this._valuesStart[property] = 1;
					this._valuesEnd[property] = clonedTween;
				}
			} else if (typeof _valuesEnd[property] === "string" && typeof object[property] === "string" && Number_Match_RegEx.test(object[property]) && Number_Match_RegEx.test(_valuesEnd[property])) {

				let __get__Start = object[property].match(Number_Match_RegEx);
				__get__Start = __get__Start.map(toNumber);
				let __get__End = _valuesEnd[property].match(Number_Match_RegEx);
				__get__End = __get__End.map(toNumber);
				let clonedTween = cloneTween(this, {
						object: __get__Start,
						_valuesEnd: __get__End,
						_events: {}
					})
					.start()
					.stop();

				clonedTween.join = true; // For string tweening
				this._valuesStart[property] = 1;
				this._valuesEnd[property] = clonedTween;

			}

			// If value presented as function,
			// we should convert to value again by passing function
			if (typeof object[property] === "function") {
				object[property] = this.object[property] = object[property](this);
			}

			if (typeof _valuesEnd[property] === "function") {
				this._valuesEnd[property] = _valuesEnd[property](this);
			}

			// If `to()` specifies a property that doesn't exist in the source object,
			// we should not set that property in the object
			if (Tween.checkValidness(object[property]) === false) {
				continue;
			}

			// If duplicate or non-tweening numerics matched,
			// we should skip from adding to _valuesStart
			if (object[property] === _valuesEnd[property]) {
				continue;
			}

			this._valuesStart[property] = object[property];

		}

		add(this);

		this._isPlaying = true;

		return this;

	}
	stop() {

		let {
			_isPlaying,
			object
		} = this;

		if (!_isPlaying) {
			return this;
		}

		remove(this);
		this._isPlaying = false;

		this.stopChainedTweens();
		return this.emit('stop', object);

	}
	end() {

		const {
			_startTime,
			_duration
		} = this;

		return this.update(_startTime + _duration);

	}
	stopChainedTweens() {

		let {
			_chainedTweens
		} = this;

		_chainedTweens.map(item => item.stop());

		return this;

	}
	delay(amount) {

		this._delayTime = typeof(amount) === "function" ? amount(this._delayTime) : amount;

		return this;

	}
	repeat(amount) {

		this._repeat = typeof(amount) === "function" ? amount(this._repeat) : amount;
		this._r = this._repeat;

		return this;

	}
	repeatDelay(amount) {

		this._repeatDelayTime = typeof(amount) === "function" ? amount(this._repeatDelayTime) : amount;

		return this;

	}
	reverseDelay(amount) {

		this._reverseDelayTime = typeof(amount) === "function" ? amount(this._reverseDelayTime) : amount;

		return this;

	}
	yoyo(state) {

		this._yoyo = typeof(state) === "function" ? state(this._yoyo) : state;

		return this;

	}
	easing(fn) {

		this._easingFunction = fn;

		return this;

	}
	interpolation(fn) {

		this._interpolationFunction = fn;

		return this;

	}
	chain(...args) {

		this._chainedTweens = args;

		return this;

	}
	get(time) {
		this.update(time);
		return this.object;
	}
	update(time) {

		let {
			_onStartCallbackFired,
			_chainedTweens,
			_easingFunction,
			_interpolationFunction,
			_repeat,
			_repeatDelayTime,
			_reverseDelayTime,
			_delayTime,
			_yoyo,
			_reversed,
			_startTime,
			_duration,
			_valuesStart,
			_valuesEnd,
			object
		} = this;

		let property;
		let elapsed;
		let value;

		time = time !== undefined ? time : now();

		if (time < _startTime) {
			return true;
		}

		if (!_onStartCallbackFired) {

			this.emit('start', object);

			this._onStartCallbackFired = true;
		}

		elapsed = (time - _startTime) / _duration;
		elapsed = elapsed > 1 ? 1 : elapsed;
		elapsed = _reversed ? 1 - elapsed : elapsed;

		value = _easingFunction(elapsed);

		for (property in _valuesEnd) {

			// Don't update properties that do not exist in the source object
			if (_valuesStart[property] === undefined) {
				continue;
			}

			let start = _valuesStart[property];
			let end = _valuesEnd[property];

			if (end instanceof Tween) {

				let getValue = end.get(time);

				if (end.join) {

					object[property] = joinToString(getValue);

				} else {

				object[property] = getValue;

				}

			} else if (Array.isArray(end)) {

				object[property] = _interpolationFunction(end, value);

			} else if (typeof(end) === 'string') {

				if (end.charAt(0) === '+' || end.charAt(0) === '-') {
					end = start + parseFloat(end);
				} else {
					end = parseFloat(end);
				}

				// Protect against non numeric properties.
				if (typeof(end) === 'number') {
					object[property] = start + (end - start) * value;
				}
			} else if (typeof(end) === 'number') {
				object[property] = start + (end - start) * value;
			}

		}

		this.emit('update', object, value, elapsed);

		if (elapsed === 1 || (_reversed && elapsed === 0)) {

			if (_repeat) {

				if (isFinite(_repeat)) {
					this._repeat--;
				}

				for (property in _valuesEnd) {

					if (typeof(_valuesEnd[property]) === 'string' && typeof(_valuesStart[property]) === 'number') {
						this._valuesStart[property] = _valuesStart[property] + parseFloat(_valuesEnd[property]);
					}

				}

				// Reassign starting values, restart by making startTime = now
				this.emit(_reversed ? 'reverse' : 'repeat', object);

				if (_yoyo) {
					this._reversed = !_reversed;
				}

				if (!_reversed && _repeatDelayTime) {
					this._startTime += _duration + _repeatDelayTime;
				} else if (_reversed && _reverseDelayTime) {
					this._startTime += _duration + _reverseDelayTime;
				} else {
					this._startTime += _duration;
				}

				return true;

			} else {

				this.emit('complete', object);

				_chainedTweens.map(tween => tween.start(_startTime + _duration));

				return false;

			}
		}
		return true;
	}
}

export default Tween;
<|endoftext|>


<commit_before>var fs = require('fs'),
    async = require('async'),
    assert = require('assert'),
    gm = require('gm'),
    exporters = {
      'png': function canvasPngExporter (cb) {
        var canvas = this.canvas;
        canvas.stream(function (err, stdout, stderr) {
          // If there was an error, callback with it
          if (err) {
            return cb(err);
          }

          // Otherwise, create placeholder items
          var imgData = [],
              err;

          // On data, add it to imgData
          // Note: We must save in 'binary' since utf8 strings don't support any possible character that a file might use
          stdout.on('data', function (chunk) {
            var binaryStr = chunk.toString('binary');
            imgData.push(binaryStr);
          });

          // On error, save it
          stderr.on('data', function (_err) {
            err = _err;
          });

          // When complete
          stdout.on('end', function () {
            // If there was an error, callback with it
            if (err) {
              cb(err);
            } else {
            // Otherwise, join together image data, put it into the retObj
              var retStr = imgData.join('');

              // Callback with no error
              cb(null, retStr);
            }
          });
        });
      }
    },
    engine = {};

function Canvas(file) {
  var canvas = gm(file);
  this.canvas = canvas;
}
Canvas.prototype = {
  'addImage': function addImage (img, x, y, cb) {
    // Add the im
console.log(img.file);
    var canvas = this.canvas;
    canvas.out('-page');
    canvas.out('+' + x + '+' + y);
    canvas.out(img.file);
  },
  'export': function exportFn (format, cb) {
    // Grab the exporter
    var exporter = exporters[format];
this.canvas.flatten();
    // Assert it exists
    assert(exporter, 'Exporter ' + format + ' does not exist for spritesmith\'s canvas engine');
console.log(this.canvas);

    // Render the item
    exporter.call(this, cb);
  }
};

// Expose Canvas to engine
engine.Canvas = Canvas;

function createCanvas(width, height, cb) {
  // TODO: Use path
  // TODO: Use a legit tmp file
  var tmpfile = __dirname + '/../../src-test/actual_files/sprite_base.png';
  async.waterfall([
    function generateCanvas (cb) {
      // TODO: Get it working without transparent.png (i.e. use the next line)
      // var canvas = gm(525, 110, "#00ff55aa");
      var base = gm(__dirname + '/transparent.png').extent(width, height);

      // Write out the base file
      base.write(tmpfile, cb);
    },
    function loadBackCanvas (x, y, z, cb) {
      // Create a canvas
      var canvas = new Canvas(tmpfile);

      // Callback with it
      cb(null, canvas);
    }
  ], cb);
}

// Expose createCanvas to engine
engine.createCanvas = createCanvas;

// Write out Image as a static property of Canvas
/**
 * @param {String} file File path to load in
 * @param {Function} callback Error first callback to retrun the image from
 * @prop {Number} image.width
 * @prop {Number} image.height
 * @note Must be guaranteed to integrate into own library via .addImage
 */
function createImage(file, cb) {
  // Create the image
  var img = gm(file);

  // In series...
  async.waterfall([
    // Grab the size
    function getImgSize (cb) {
      img.size(cb);
    },
    function saveImgSize (size, cb) {
      // Create a structure for preserving the height and width of the image
      var imgFile = {
        'height': size.height,
        'width': size.width,
        'file': file
      };

      // Callback with the imgFile
      cb(null, imgFile);
    }
  ], cb);
}
engine.createImage = createImage;

// Expose the exporters
engine.exporters = exporters;

// Export the canvas
module.exports = engine;<commit_msg>Stream attempt failed =(<commit_after>var fs = require('fs'),
    async = require('async'),
    assert = require('assert'),
    gm = require('gm'),
    exporters = {
      'png': function canvasPngExporter (cb) {
        var canvas = this.canvas;
        canvas.stream(function (err, stdout, stderr) {
          // If there was an error, callback with it
          if (err) {
            return cb(err);
          }

          // Otherwise, create placeholder items
          var imgData = [],
              err;

          // On data, add it to imgData
          // Note: We must save in 'binary' since utf8 strings don't support any possible character that a file might use
          stdout.on('data', function (chunk) {
            var binaryStr = chunk.toString('binary');
            imgData.push(binaryStr);
          });

          // On error, save it
          stderr.on('data', function (_err) {
            err = _err;
          });

          // When complete
          stdout.on('end', function () {
            // If there was an error, callback with it
            if (err) {
              cb(err);
            } else {
            // Otherwise, join together image data, put it into the retObj
              var retStr = imgData.join('');

              // Callback with no error
              cb(null, retStr);
            }
          });
        });
      }
    },
    engine = {};

function Canvas() {
  var canvas = gm.apply({}, arguments);
  this.canvas = canvas;
}
Canvas.prototype = {
  'addImage': function addImage (img, x, y, cb) {
    // Add the image
    var canvas = this.canvas;

    // TODO: Pull request this in
    canvas.out('-page');
    canvas.out('+' + x + '+' + y);
    canvas.out(img.file);
  },
  'export': function exportFn (format, cb) {
    // Grab the exporter
    var exporter = exporters[format];

    // Assert it exists
    assert(exporter, 'Exporter ' + format + ' does not exist for spritesmith\'s canvas engine');

    // Flatten the image
    this.canvas.flatten();
console.log(this.canvas);
    // Render the item
    exporter.call(this, cb);
  }
};

// Expose Canvas to engine
engine.Canvas = Canvas;

function createCanvas(width, height, cb) {
  // TODO: Use path
  // TODO: Use a legit tmp file
  // TODO: Either use scratch file *or* attempt to get that streamimg awesome
  var tmpfile = __dirname + '/../../src-test/actual_files/sprite_base.png';
  async.waterfall([
    function generateCanvas (cb) {
      // TODO: Get it working without transparent.png (i.e. use the next line)
      // var canvas = gm(525, 110, "#00ff55aa");
      var base = gm(__dirname + '/transparent.png').extent(width, height);

      // Write out the base as a stream
      base.stream(cb);
    },
    function loadBackCanvas (stdout, stderr, cmd, cb) {
      // Make a proper stream out of stdout and stderr
      var events = require('events'),
          EE = events.EventEmitter,
          stream = new EE;

      stdout.on('data', function (buffer) {
        stream.emit('data', buffer);
      });

      stderr.on('data', function (buffer) {
        stream.emit('error', buffer);
      });

      stdout.on('close', function (buffer) {
        stream.emit('close', buffer);
      });

      // Create a canvas
      var canvas = new Canvas(stream, 'base.png');

      // Callback with it
      cb(null, canvas);
    }
  ], cb);
}

// Expose createCanvas to engine
engine.createCanvas = createCanvas;

// Write out Image as a static property of Canvas
/**
 * @param {String} file File path to load in
 * @param {Function} callback Error first callback to retrun the image from
 * @prop {Number} image.width
 * @prop {Number} image.height
 * @note Must be guaranteed to integrate into own library via .addImage
 */
function createImage(file, cb) {
  // Create the image
  var img = gm(file);

  // In series...
  async.waterfall([
    // Grab the size
    function getImgSize (cb) {
      img.size(cb);
    },
    function saveImgSize (size, cb) {
      // Create a structure for preserving the height and width of the image
      var imgFile = {
        'height': size.height,
        'width': size.width,
        'file': file
      };

      // Callback with the imgFile
      cb(null, imgFile);
    }
  ], cb);
}
engine.createImage = createImage;

// Expose the exporters
engine.exporters = exporters;

// Export the canvas
module.exports = engine;<|endoftext|>


<commit_before>var logger = require('./logger')
var ipfsAPI = require('ipfs-api')

exports = module.exports = fetchIPNS

function fetchIPNS (config) {
  if (!config.clone && config.blobStore) {
    var apiCtl = ipfsAPI('/ip4/127.0.0.1/tcp/5001')

    var castorAddr = '/ip4/37.59.33.238/tcp/4001/ipfs/QmdNc4B89DxVeiuDKRN5bWdKsAPCmekgmJMkRSdUNa7x9z'
    apiCtl.swarm.connect(castorAddr, function (err) {
      if (err) {
        return logger.err('Could not connect to Castor', err)
      }

      apiCtl.files.stat('/npm-registry', function (err) {
        if (err && err.code === 0) {
          return copyNpmRegistry()
        }

        apiCtl.files.mv(['/npm-registry', '/npm-registry' + Date.now().toString()], function (err) {
          if (err) {
            return logger.err('Failed to backup current /npm-registry', err)
          }

          copyNpmRegistry()
        })

        function copyNpmRegistry () {
          apiCtl.name.resolve('/ipns/QmdNc4B89DxVeiuDKRN5bWdKsAPCmekgmJMkRSdUNa7x9z', function (err, res) {
            if (err) {
              return logger.err('Could not resolve IPNS name', err)
            }

            logger.info('New /npm-registry mDAG node:', res.Path)
            apiCtl.files.cp([res.Path, '/npm-registry'], function (err) {
              if (err) {
                return logger.err('Failed to clone /npm-registry mDAG node', err)
              }
              logger.info('Updated directory listing, good to go :)')
            })
          })
        }
      })
    })
  }
}
<commit_msg>add fetch-ipns with cb<commit_after>var logger = require('./logger')
var ipfsAPI = require('ipfs-api')

exports = module.exports = fetchIPNS

function fetchIPNS (config, callback) {
  if (!config.clone && config.blobStore) {
    var apiCtl = ipfsAPI('/ip4/127.0.0.1/tcp/5001')

    var castorAddr = '/ip4/37.59.33.238/tcp/4001/ipfs/QmdNc4B89DxVeiuDKRN5bWdKsAPCmekgmJMkRSdUNa7x9z'
    apiCtl.swarm.connect(castorAddr, function (err) {
      if (err) {
        return logger.err('Could not connect to Castor', err)
      }

      apiCtl.files.stat('/npm-registry', function (err) {
        if (err && err.code === 0) {
          return copyNpmRegistry()
        }

        apiCtl.files.mv(['/npm-registry', '/npm-registry' + Date.now().toString()], function (err) {
          if (err) {
            return logger.err('Failed to backup current /npm-registry', err)
          }

          copyNpmRegistry()
        })

        function copyNpmRegistry () {
          apiCtl.name.resolve('/ipns/QmdNc4B89DxVeiuDKRN5bWdKsAPCmekgmJMkRSdUNa7x9z', function (err, res) {
            if (err) {
              return logger.err('Could not resolve IPNS name', err)
            }

            logger.info('New /npm-registry mDAG node:', res.Path)
            apiCtl.files.cp([res.Path, '/npm-registry'], function (err) {
              if (err) {
                return logger.err('Failed to clone /npm-registry mDAG node', err)
              }
              logger.info('Updated directory listing, good to go :)')
              if (callback) {
                callback()
              }
            })
          })
        }
      })
    })
  }
}
<|endoftext|>


<commit_before>/**
 * React Static Boilerplate
 * https://github.com/kriasoft/react-static-boilerplate
 *
 * Copyright © 2015-present Kriasoft, LLC. All rights reserved.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE.txt file in the root directory of this source tree.
 */

import React, { PropTypes } from 'react';
import Layout from '../../components/Layout';
import Footer from '../../components/Footer';
import s from './styles.css';
import { title, html } from './index.md';

class HomePage extends React.Component {

  static propTypes = {
    articles: PropTypes.arrayOf(PropTypes.shape({
      url: PropTypes.string.isRequired,
      title: PropTypes.string.isRequired,
      author: PropTypes.string.isRequired,
    }).isRequired).isRequired,
  };

  componentDidMount() {
    document.title = title;
  }

  render() {
    let styleSkillSymfony = {
      width: '90%'
    };
    let styleSkillAngular = {
      width: '70%'
    };
    let styleSkillReact = {
      width: '25%'
    };

    let styleSkillMySQL = {
      width: '90%'
    };
    let styleSkillElasticSearch = {
      width: '60%'
    };
    let styleSkillRedis = {
      width: '70%'
    };
    let styleSkillMongoDB = {
      width: '50%'
    };

    let styleSkillOOP = {
      width: '80%'
    };
    let styleSkillSolid = {
      width: '80%'
    };
    let styleSkillDesignPattern = {
      width: '70%'
    };
    let styleSkillDDD = {
      width: '80%'
    };
    let styleSkillSOA = {
      width: '70%'
    };

    return (
      <Layout className={s.content}>

                                Humility

Always something to learn

                                Team Management

Growing TeamPlay

                                Coaching

Knowledge sharing

                                Quality Assurance

Unit/Functional Testing

                                REST API

Aiming for Interoperability

                                Software Architecture

Reducing technical debt

                                DevOps

AdminSys / Docker / Linux

                                M.V.P.

Minimum Viable Product

                                Disruptive

Using technology to thrive

Web Framework

Symfony 4 PHP7

Angular 4 (AoT/Redux)Javascript

ReactJavascript

Database

MySQL MariaDB

ElasticSearch NoSQL

Redis NoSQL

Mongo DB NoSQL

Architecture

Object-Oriented Programming

S.O.L.I.D.

Design Pattern

Domain Driven Design DDD

Service Oriented Architecture SOA

Location : Marseille (France)

Currently Learning : Event Storming

      </Layout>
    );
  }

}

export default HomePage;
<commit_msg>Rephrase MVP<commit_after>/**
 * React Static Boilerplate
 * https://github.com/kriasoft/react-static-boilerplate
 *
 * Copyright © 2015-present Kriasoft, LLC. All rights reserved.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE.txt file in the root directory of this source tree.
 */

import React, { PropTypes } from 'react';
import Layout from '../../components/Layout';
import Footer from '../../components/Footer';
import s from './styles.css';
import { title, html } from './index.md';

class HomePage extends React.Component {

  static propTypes = {
    articles: PropTypes.arrayOf(PropTypes.shape({
      url: PropTypes.string.isRequired,
      title: PropTypes.string.isRequired,
      author: PropTypes.string.isRequired,
    }).isRequired).isRequired,
  };

  componentDidMount() {
    document.title = title;
  }

  render() {
    let styleSkillSymfony = {
      width: '90%'
    };
    let styleSkillAngular = {
      width: '70%'
    };
    let styleSkillReact = {
      width: '25%'
    };

    let styleSkillMySQL = {
      width: '90%'
    };
    let styleSkillElasticSearch = {
      width: '60%'
    };
    let styleSkillRedis = {
      width: '70%'
    };
    let styleSkillMongoDB = {
      width: '50%'
    };

    let styleSkillOOP = {
      width: '80%'
    };
    let styleSkillSolid = {
      width: '80%'
    };
    let styleSkillDesignPattern = {
      width: '70%'
    };
    let styleSkillDDD = {
      width: '80%'
    };
    let styleSkillSOA = {
      width: '70%'
    };

    return (
      <Layout className={s.content}>

                                Humility

Always something to learn

                                Team Management

Growing TeamPlay

                                Coaching

Knowledge sharing

                                Quality Assurance

Unit/Functional Testing

                                REST API

Aiming for Interoperability

                                Software Architecture

Reducing technical debt

                                DevOps

AdminSys / Docker / Linux

                                Min Viable Product

So business can experiment

                                Disruptive

Using technology to thrive

Web Framework

Symfony 4 PHP7

Angular 4 (AoT/Redux)Javascript

ReactJavascript

Database

MySQL MariaDB

ElasticSearch NoSQL

Redis NoSQL

Mongo DB NoSQL

Architecture

Object-Oriented Programming

S.O.L.I.D.

Design Pattern

Domain Driven Design DDD

Service Oriented Architecture SOA

Location : Marseille (France)

Currently Learning : Event Storming

      </Layout>
    );
  }

}

export default HomePage;
<|endoftext|>


<commit_before>/* global document, chrome, open */

const injectInFrameInput = document.getElementById("injectInFrameInput");
const addContextMenuInput = document.getElementById("addContextMenuInput");
document.getElementById("openEditorButton").addEventListener("click", event => {
	open("css-editor.html", "jsonvue-css-editor");
	event.stopPropagation();
}, false);

chrome.runtime.sendMessage({ getSettings: true }, settings => {
	const options = settings.options;
	injectInFrameInput.checked = options.injectInFrame;
	addContextMenuInput.checked = options.addContextMenu;
	injectInFrameInput.addEventListener("change", () => {
		options.injectInFrame = injectInFrameInput.checked;
		chrome.runtime.sendMessage({ setSetting: true, name: "options", value: options });
	});
	addContextMenuInput.addEventListener("change", () => {
		options.addContextMenu = addContextMenuInput.checked;
		chrome.runtime.sendMessage({ setSetting: true, refreshMenuEntry: true, name: "options", value: options });
	});
});
<commit_msg>format code<commit_after>/* global document, chrome, open */

const injectInFrameInput = document.getElementById("injectInFrameInput");
const addContextMenuInput = document.getElementById("addContextMenuInput");
document.getElementById("openEditorButton").addEventListener("click", event => {
	open("css-editor.html", "jsonvue-css-editor");
	event.stopPropagation();
}, false);
chrome.runtime.sendMessage({ getSettings: true }, settings => {
	const options = settings.options;
	injectInFrameInput.checked = options.injectInFrame;
	addContextMenuInput.checked = options.addContextMenu;
	injectInFrameInput.addEventListener("change", () => {
		options.injectInFrame = injectInFrameInput.checked;
		chrome.runtime.sendMessage({ setSetting: true, name: "options", value: options });
	});
	addContextMenuInput.addEventListener("change", () => {
		options.addContextMenu = addContextMenuInput.checked;
		chrome.runtime.sendMessage({ setSetting: true, refreshMenuEntry: true, name: "options", value: options });
	});
});
<|endoftext|>


<commit_before>/**
	The MIT License (MIT)
	Copyright (c) 2014 MyChannel-Apps.de
	Permission is hereby granted, free of charge, to any person obtaining a copy
	of this software and associated documentation files (the "Software"), to deal
	in the Software without restriction, including without limitation the rights
	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
	copies of the Software, and to permit persons to whom the Software is
	furnished to do so, subject to the following conditions:
	The above copyright notice and this permission notice shall be included in
	all copies or substantial portions of the Software.
	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
	THE SOFTWARE.

	@author		Adrian Preuß, Bizarrus
*/

var KCODE_GROUPS_INSTANCES = 0;

function KGroup() {
	var _groups 		= [ undefined ];
	var _show			= 0;
	var _layout_box		= false;

	this.add = function(content) {
		_groups.push(content);
		return this;
	};

	this.remove = function(index) {
		delete _groups[index];
		return this;
	};

	this.update = function(index, content) {
		_groups[index] = content;
		return this;
	};

	this.show = function(index) {
		_show = index;
		return this;
	};

	this.enableBoxLayout = function(state) {
		_layout_box = state;
		return this;
	};

	this.getNavigation = function(titles) {
		titles		= (titles == undefined ? [] : titles);
		var buffer	= new StringBuffer();
		var size	= _groups.size();
		buffer.append('°12BB+0000°_°>LEFT<°');

		_groups.each(function(content, index) {
			if(content == undefined) {
				return;
			}

			var entry	= parseInt(index) + 1;
			var title	= (titles[entry - 2] == undefined ? 'Tab ' + entry : titles[entry  - 2]);

			if(_layout_box) {
				// @ToDo Use KLink + KImage
				var left	= 'layout/tab_i_l...w_8.mx_-1.png';
				var middle	= 'layout/tab_i_c...label_' + title + '.mw_' + (title.length * 1.12) + '.png'; // xrepeat
				var right	= 'layout/tab_i_r.png';

				buffer.append('°>' + left + '<°').append('°>' + middle + '|' + middle + '<>--<>|/tp-showgrp ' + entry + '<°');
				// >{noxrep}<
				buffer.append('°>' + right + '<°');
			} else {
				buffer.append('°>' + title + '|/tp-showgrp ' + entry + '<°');

				if(entry < size) {
					buffer.append(' - ');
				}
			}
		});

		buffer.append('°>LEFT<°_°r##°');

		return buffer.toString();
	};

	this.getTabCommand = function(index) {
		return '/tp-showgrp ' + index;
	};

	this.switchTab = function(index) {
		return '°>{setdisplaygroup}' + index + '<°';
	};

	this.toString = function() {
		var buffer = new StringBuffer();

		buffer.append('°>{addDisplayGroup}').append(_show).append('<°');

		_groups.each(function(content, index) {
			if(content == undefined) {
				return;
			}

			buffer.append('°>{displayGroup}').append(parseInt(index)).append('<°').append(content).append('°>{displayGroupEnd}<°');
		});

		return buffer.toString();
	};
};<commit_msg>KGroup: Docs<commit_after>/**
	The MIT License (MIT)
	Copyright (c) 2014 MyChannel-Apps.de
	Permission is hereby granted, free of charge, to any person obtaining a copy
	of this software and associated documentation files (the "Software"), to deal
	in the Software without restriction, including without limitation the rights
	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
	copies of the Software, and to permit persons to whom the Software is
	furnished to do so, subject to the following conditions:
	The above copyright notice and this permission notice shall be included in
	all copies or substantial portions of the Software.
	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
	THE SOFTWARE.

	@author		Adrian Preuß <Bizarrus>
	@docs		http://www.mychannel-apps.de/documentation/ui/group
*/

var KCODE_GROUPS_INSTANCES = 0;

function KGroup() {
	var _groups 		= [ undefined ];
	var _show			= 0;
	var _layout_box		= false;

	/*
		@docs		http://www.mychannel-apps.de/documentation/KGroup_add
	*/
	this.add = function(content) {
		_groups.push(content);
		return this;
	};

	/*
		@docs		http://www.mychannel-apps.de/documentation/KGroup_remove
	*/
	this.remove = function(index) {
		delete _groups[index];
		return this;
	};

	/*
		@docs		http://www.mychannel-apps.de/documentation/KGroup_update
	*/
	this.update = function(index, content) {
		_groups[index] = content;
		return this;
	};

	/*
		@docs		http://www.mychannel-apps.de/documentation/KGroup_show
	*/
	this.show = function(index) {
		_show = index;
		return this;
	};

	/*
		@docs		http://www.mychannel-apps.de/documentation/KGroup_enableBoxLayout
	*/
	this.enableBoxLayout = function(state) {
		_layout_box = state;
		return this;
	};

	/*
		@docs		http://www.mychannel-apps.de/documentation/KGroup_getNavigation
	*/
	this.getNavigation = function(titles) {
		titles		= (titles == undefined ? [] : titles);
		var buffer	= new StringBuffer();
		var size	= _groups.size();
		buffer.append('°12BB+0000°_°>LEFT<°');

		_groups.each(function(content, index) {
			if(content == undefined) {
				return;
			}

			var entry	= parseInt(index) + 1;
			var title	= (titles[entry - 2] == undefined ? 'Tab ' + entry : titles[entry  - 2]);

			if(_layout_box) {
				// @ToDo Use KLink + KImage
				var left	= 'layout/tab_i_l...w_8.mx_-1.png';
				var middle	= 'layout/tab_i_c...label_' + title + '.mw_' + (title.length * 1.12) + '.png'; // xrepeat
				var right	= 'layout/tab_i_r.png';

				buffer.append('°>' + left + '<°').append('°>' + middle + '|' + middle + '<>--<>|/tp-showgrp ' + entry + '<°');
				// >{noxrep}<
				buffer.append('°>' + right + '<°');
			} else {
				buffer.append('°>' + title + '|/tp-showgrp ' + entry + '<°');

				if(entry < size) {
					buffer.append(' - ');
				}
			}
		});

		buffer.append('°>LEFT<°_°r##°');

		return buffer.toString();
	};

	/*
		@docs		http://www.mychannel-apps.de/documentation/KGroup_getTabCommand
	*/
	this.getTabCommand = function(index) {
		return '/tp-showgrp ' + index;
	};

	/*
		@docs		http://www.mychannel-apps.de/documentation/KGroup_switchTab
	*/
	this.switchTab = function(index) {
		return '°>{setdisplaygroup}' + index + '<°';
	};

	/*
		@docs		http://www.mychannel-apps.de/documentation/KGroup_
	*/
	this.toString = function() {
		var buffer = new StringBuffer();

		buffer.append('°>{addDisplayGroup}').append(_show).append('<°');

		_groups.each(function(content, index) {
			if(content == undefined) {
				return;
			}

			buffer.append('°>{displayGroup}').append(parseInt(index)).append('<°').append(content).append('°>{displayGroupEnd}<°');
		});

		return buffer.toString();
	};
};<|endoftext|>