<commit_before>define(function () {	// model
    "use strict";
    var ctx = new AudioContext();
    var osc = null;
    var gain = null;
    var env = null;
    var bqf = null;

    var chordDegree = {
        perfect1: 0,
        minor2: 1,
        major2: 2,
        minor3: 3,
        major3: 4,
        perfect4: 5,
        aug4: 6,
        dim5: 6,
        perfect5: 7,
        aug5: 8,
        minor6: 8,
        major6: 9,
        minor7: 10,
        major7: 11,
        C: -9,
        D: -7,
        E: -5,
        F: -4,
        G: -2,
        A: 0,
        B: 2
    };

    //
    // local functions

    // 1. utility functions
    var map = Array.prototype.map;

    function mapcar(fn, lists) // ad-hock: assume all list lengths are the same. maybe fixed after.
    {
        var r = [];
        for (var i = 0; i < lists[0].length; i++) {
            var tr = [];
            for (var j = 0; j < lists.length; j++) {
                tr.push(lists[j][i]);
            }
            r.push(fn.apply(null, tr));
        }

        return r;
    }

    function compose(f, g) {
        return function () {
            return f.call(this, g.apply(this, arguments));
        };
    }

    Function.prototype.method = function (name, func) {
        if (!this.prototype[name]) {
            this.prototype[name] = func;
            return this;
        } else {
            throw new Error("method error.");
        }
    };

    Number.method('integer', function () {
        return Math[this < 0 ? 'ceil' : 'floor'](this);
    });

    // 3. specific functions
    var parseChord = function (chord) {
        var st = 0; // state
        var pos = 0;

        var root;
        var third = "major3";   // ad-hock: to be fixed
        var fifth = "perfect5"; // ad-hock: to be fixed
        var seventh;

        while (pos < chord.length) {
            switch (st) {
                case 0:     // root note
                    root = chord[pos++];
                    st = 1; // to 3rd
                    break;

                case 1: // 3rd
                    if (chord[pos] == "m") {    // minor
                        pos++;
                        third = "minor3";
                    } else {
                        third = "major3";
                    }
                    st = 2; // to 7th
                    break;
                case 2: // 7th
                    if (chord[pos] == "M") {    // maybe major 7th
                        pos++;
                        st = 3; // check if it is major 7th
                    } else if (chord[pos] == "7") {  // minor 7th
                        pos++;
                        seventh = "minor7";
                        st = 4; // check sus4
                    } else if (chord[pos] == "6") {  // major 6th
                        pos++;
                        seventh = "major6";
                        st = 4; // check sus4
                    } else {
                        st = 4; // check sus4
                    }
                    break;
                case 3: // major 7th
                    if (chord[pos] == "7") {    // major 7th
                        pos++;
                        seventh = "major7";
                    } else {
                        throw new Error("parse error.");
                    }
                    st = 4;     // check sus4
                    break;
                case 4: // sus4-1:s
                    if (chord[pos] == "s") {
                        pos++;
                        st = 5;     // sus4-2:u
                    } else {
                        st = 8;     // 5th
                    }
                    break;
                case 5: // sus4-2:u
                    if (chord[pos] == "u") {
                        pos++;
                        st = 6;
                    } else {
                        throw new Error("parse error.");
                    }
                    break;
                case 6: // sus4-2:s
                    if (chord[pos] == "s") {
                        pos++;
                        st = 7;
                    } else {
                        throw new Error("parse error.");
                    }
                    break;
                case 7: // sus4-2:4
                    if (chord[pos] == "4") {
                        pos++;
                        third = "perfect4";
                        st = 8;
                    } else {
                        throw new Error("parse error.");
                    }
                    break;
                case 8: // 5th
                    if (chord[pos] == "(") {    // 5th, 9th, 11th exists
                        pos++;
                        st = 9;
                    } else {
                        fifth = "perfetc5";
                        st = 13;                // on-code
                    }
                    break;
                case 9: // aug or dim
                    if (chord[pos] == "+") {    // aug
                        pos++;
                        st = 10;
                    } else if (chord[pos] == "-") { // dim
                        pos++;
                        st = 11;
                    } else {    // 7th
                        throw new Error("7th, 9th is not implemented yet.");
                    }
                    break;
                case 10: // aug
                    if (chord[pos] == "5") { // aug5
                        pos++;
                        fifth = "aug5";
                        st = 12;  // ")"
                    } else {    // maybe aug7
                        fifth = "perfect5";
                        st = 12;  // ")"
                    }
                    break;
                case 11: // dim
                    if (chord[pos] == "5") { // dim7
                        pos++;
                        fifth = "dim5";
                        st = 12;  // 7th
                    } else {
                        throw new Error("7th, 9th is not implemented yet.");
                        fifth = "perfect5";
                        st = 12;
                    }
                    break;
                case 12: // ")"
                    if (chord[pos] == ")") {
                        pos++;
                        st = 13;
                    } else {
                        throw new Error("parse error");
                    }
                    break;
                case 13: // on-code
                    throw new Error("on-code is not implemented yet.");
                    break;
                default:
                    throw new Error("parser internal error.");
                    break;

            }
        }

        return { "root": root, offset: ["perfect1", third, fifth, seventh] };
    };

    var noteToFreq = function (n) {
        return Math.pow(2,(n - 33) / 12) * 440;
    };

    var closedVoicing = function (chord) {
        var root = chordDegree[chord.root];
        return chord.offset.map(function (x) {
            if (x === undefined) {
                return null;
            } else {
                var cd = chordDegree[x].integer() + 33 + root;
                if (cd > 35) {
                    cd -= 12;
                }
                return noteToFreq(cd);
            }
        });
    };

    var chordToSequence = function (chords, voicing) {
        return mapcar(function () { return arguments; }, map.call(chords, compose(voicing, parseChord)));
    };

    //
    // model constructor
    return function () {
        this.build = function (v, f, q) {
            gain = ctx.createGain();
            this.setGain(v);
            gain.connect(ctx.destination);

            env = ctx.createGain();
            env.connect(gain);

            bqf = ctx.createBiquadFilter();
            this.setBQFFreq(f);
            this.setBQFQ(q);
            bqf.connect(env);

            osc = new Array(4);
            for (var j = 0; j < osc.length; j++) {
                osc[j] = ctx.createOscillator();
                osc[j].type = "sawtooth";
                osc[j].connect(bqf);
            }
        };

        this.playChord = function (c) {
            var ca = c.split(/\s/);
            var seq = chordToSequence(ca, closedVoicing);

            var attack = 0.001;
            var decay = 0.4;
            var sustain = 0.4;
            var release = 0.2;
            var noteoff = 0.6;

	    var i;
	    var j;
            for (i = 0; i < seq[0].length; i++) {
                env.gain.setValueAtTime(0, ctx.currentTime + i);    // zero
                env.gain.linearRampToValueAtTime(1, ctx.currentTime + i + attack); // attack
                env.gain.setTargetAtTime(sustain, ctx.currentTime + i + attack, decay); // decay, sustain
                env.gain.setTargetAtTime(0, ctx.currentTime + i + noteoff, release);    // release
            }

            for (j = 0; j < osc.length; j++) {
                for (i = 0; i < seq[j].length; i++) {
                    osc[j].frequency.setValueAtTime(seq[j][i] === null ? 0 : seq[j][i], ctx.currentTime + i);
                }
            }

            for (j = 0; j < osc.length; j++) {
                osc[j].start(ctx.currentTime);
                osc[j].stop(ctx.currentTime + seq[j].length);
            }
        };

        this.stop = function () {
            for (j = 0; j < osc.length; j++) {
                osc[j].stop(ctx.currentTime);
            }
	};

        this.clear = function () {
            for (var i = 0; i < osc.length; i++) {
                osc[i].disconnect();
            }
            bqf.disconnect();
            gain.disconnect();
            osc = null;
            bqf = null;
            gain = null;
        };

        this.setGain = function (g) {
            if (gain)
                gain.gain.value = g * 0.25;
        };

        this.setBQFQ = function (q) {
            if(bqf)
                bqf.Q.value = q;
        };

        this.setBQFFreq = function (f) {
            if(bqf)
                bqf.frequency.value = f;
        };
    };
});
<commit_msg>bugs in start(), stop() is fixed.<commit_after>define(function () {	// model
    "use strict";
    var ctx = new AudioContext();
    var osc = null;
    var gain = null;
    var env = null;
    var bqf = null;

    var chordDegree = {
        perfect1: 0,
        minor2: 1,
        major2: 2,
        minor3: 3,
        major3: 4,
        perfect4: 5,
        aug4: 6,
        dim5: 6,
        perfect5: 7,
        aug5: 8,
        minor6: 8,
        major6: 9,
        minor7: 10,
        major7: 11,
        C: -9,
        D: -7,
        E: -5,
        F: -4,
        G: -2,
        A: 0,
        B: 2
    };

    //
    // local functions

    // 1. utility functions
    var map = Array.prototype.map;

    function mapcar(fn, lists) // ad-hock: assume all list lengths are the same. maybe fixed after.
    {
        var r = [];
        for (var i = 0; i < lists[0].length; i++) {
            var tr = [];
            for (var j = 0; j < lists.length; j++) {
                tr.push(lists[j][i]);
            }
            r.push(fn.apply(null, tr));
        }

        return r;
    }

    function compose(f, g) {
        return function () {
            return f.call(this, g.apply(this, arguments));
        };
    }

    Function.prototype.method = function (name, func) {
        if (!this.prototype[name]) {
            this.prototype[name] = func;
            return this;
        } else {
            throw new Error("method error.");
        }
    };

    Number.method('integer', function () {
        return Math[this < 0 ? 'ceil' : 'floor'](this);
    });

    // 3. specific functions
    var parseChord = function (chord) {
        var st = 0; // state
        var pos = 0;

        var root;
        var third = "major3";   // ad-hock: to be fixed
        var fifth = "perfect5"; // ad-hock: to be fixed
        var seventh;

        while (pos < chord.length) {
            switch (st) {
                case 0:     // root note
                    root = chord[pos++];
                    st = 1; // to 3rd
                    break;

                case 1: // 3rd
                    if (chord[pos] == "m") {    // minor
                        pos++;
                        third = "minor3";
                    } else {
                        third = "major3";
                    }
                    st = 2; // to 7th
                    break;
                case 2: // 7th
                    if (chord[pos] == "M") {    // maybe major 7th
                        pos++;
                        st = 3; // check if it is major 7th
                    } else if (chord[pos] == "7") {  // minor 7th
                        pos++;
                        seventh = "minor7";
                        st = 4; // check sus4
                    } else if (chord[pos] == "6") {  // major 6th
                        pos++;
                        seventh = "major6";
                        st = 4; // check sus4
                    } else {
                        st = 4; // check sus4
                    }
                    break;
                case 3: // major 7th
                    if (chord[pos] == "7") {    // major 7th
                        pos++;
                        seventh = "major7";
                    } else {
                        throw new Error("parse error.");
                    }
                    st = 4;     // check sus4
                    break;
                case 4: // sus4-1:s
                    if (chord[pos] == "s") {
                        pos++;
                        st = 5;     // sus4-2:u
                    } else {
                        st = 8;     // 5th
                    }
                    break;
                case 5: // sus4-2:u
                    if (chord[pos] == "u") {
                        pos++;
                        st = 6;
                    } else {
                        throw new Error("parse error.");
                    }
                    break;
                case 6: // sus4-2:s
                    if (chord[pos] == "s") {
                        pos++;
                        st = 7;
                    } else {
                        throw new Error("parse error.");
                    }
                    break;
                case 7: // sus4-2:4
                    if (chord[pos] == "4") {
                        pos++;
                        third = "perfect4";
                        st = 8;
                    } else {
                        throw new Error("parse error.");
                    }
                    break;
                case 8: // 5th
                    if (chord[pos] == "(") {    // 5th, 9th, 11th exists
                        pos++;
                        st = 9;
                    } else {
                        fifth = "perfetc5";
                        st = 13;                // on-code
                    }
                    break;
                case 9: // aug or dim
                    if (chord[pos] == "+") {    // aug
                        pos++;
                        st = 10;
                    } else if (chord[pos] == "-") { // dim
                        pos++;
                        st = 11;
                    } else {    // 7th
                        throw new Error("7th, 9th is not implemented yet.");
                    }
                    break;
                case 10: // aug
                    if (chord[pos] == "5") { // aug5
                        pos++;
                        fifth = "aug5";
                        st = 12;  // ")"
                    } else {    // maybe aug7
                        fifth = "perfect5";
                        st = 12;  // ")"
                    }
                    break;
                case 11: // dim
                    if (chord[pos] == "5") { // dim7
                        pos++;
                        fifth = "dim5";
                        st = 12;  // 7th
                    } else {
                        throw new Error("7th, 9th is not implemented yet.");
                        fifth = "perfect5";
                        st = 12;
                    }
                    break;
                case 12: // ")"
                    if (chord[pos] == ")") {
                        pos++;
                        st = 13;
                    } else {
                        throw new Error("parse error");
                    }
                    break;
                case 13: // on-code
                    throw new Error("on-code is not implemented yet.");
                    break;
                default:
                    throw new Error("parser internal error.");
                    break;

            }
        }

        return { "root": root, offset: ["perfect1", third, fifth, seventh] };
    };

    var noteToFreq = function (n) {
        return Math.pow(2,(n - 33) / 12) * 440;
    };

    var closedVoicing = function (chord) {
        var root = chordDegree[chord.root];
        return chord.offset.map(function (x) {
            if (x === undefined) {
                return null;
            } else {
                var cd = chordDegree[x].integer() + 33 + root;
                if (cd > 35) {
                    cd -= 12;
                }
                return noteToFreq(cd);
            }
        });
    };

    var chordToSequence = function (chords, voicing) {
        return mapcar(function () { return arguments; }, map.call(chords, compose(voicing, parseChord)));
    };

    //
    // model constructor
    return function () {
        this.build = function (v, f, q) {
            gain = ctx.createGain();
            this.setGain(v);
            gain.connect(ctx.destination);

            env = ctx.createGain();
            env.connect(gain);

            bqf = ctx.createBiquadFilter();
            this.setBQFFreq(f);
            this.setBQFQ(q);
            bqf.connect(env);
        };

        this.playChord = function (c) {
            var ca = c.split(/\s/);
            var seq = chordToSequence(ca, closedVoicing);

            var attack = 0.001;
            var decay = 0.4;
            var sustain = 0.4;
            var release = 0.2;
            var noteoff = 0.6;

            var i;
            var j;
            for (i = 0; i < seq[0].length; i++) {
                env.gain.setValueAtTime(0, ctx.currentTime + i);    // zero
                env.gain.linearRampToValueAtTime(1, ctx.currentTime + i + attack); // attack
                env.gain.setTargetAtTime(sustain, ctx.currentTime + i + attack, decay); // decay, sustain
                env.gain.setTargetAtTime(0, ctx.currentTime + i + noteoff, release);    // release
            }

            osc = new Array(4);
            for (j = 0; j < osc.length; j++) {
                osc[j] = ctx.createOscillator();
                osc[j].type = "sawtooth";
                osc[j].connect(bqf);

                for (i = 0; i < seq[j].length; i++) {
                    osc[j].frequency.setValueAtTime(seq[j][i] === null ? 0 : seq[j][i], ctx.currentTime + i);
                }
            }

            for (j = 0; j < osc.length; j++) {
                osc[j].start(ctx.currentTime);
                osc[j].stop(ctx.currentTime + seq[j].length);
            }
        };

        this.stop = function () {
            for (var j = 0; j < osc.length; j++) {
                osc[j].stop(ctx.currentTime);
                osc[j].disconnect();
                osc[j] = null;
            }
            env.gain.cancelScheduledValues(ctx.currentTime);
        };

        this.clear = function () {
            for (var i = 0; i < osc.length; i++) {
                osc[i].disconnect();
            }
            bqf.disconnect();
            gain.disconnect();
            osc = null;
            bqf = null;
            gain = null;
        };

        this.setGain = function (g) {
            if (gain)
                gain.gain.value = g * 0.25;
        };

        this.setBQFQ = function (q) {
            if (bqf)
                bqf.Q.value = q;
        };

        this.setBQFFreq = function (f) {
            if (bqf)
                bqf.frequency.value = f;
        };
    };
});
<|endoftext|>


<commit_before>'use strict';

function FullScreenImage(){
  var self = this;

  this.container = e({
    class: 'fs-container',
  });
  this.container.style.display = "none";
  this.container.setAttribute('tabindex', -1);

  this.container.addEventListener('keydown', function(e){
    var nextKeys = [76, 68, 74, 83, 9];
    var prevKeys = [65, 72, 75, 87];
    var exitCodes;
    if(e.keyCode === 39 ){
      self.next();
    }
    else if(e.keyCode === 37){
      self.prev();
    }
    else if(e.keyCode === 13){
      self.next();
    }
    else if(e.keyCode === 27){
      self.hide();
    }
    else if(e.keyCode === 32){
      self.next();
    }
    else if(e.keyCode === 8){
      self.prev();
    }
    else if(nextKeys.indexOf(e.keyCode) !== -1){
      self.next();
    }
    else if(prevKeys.indexOf(e.keyCode) !== -1){
      self.prev();
    }
    else{
      return;
    }
    e.preventDefault();
    e.stopPropagation();
  });

  this.toolbar = e({
    class: 'fs-toolbar',
    parent: this.container,
  });

  this.body = e({
    class: 'fs-body',
    parent: this.container,
  });

  this.navigation = e({
    class: 'fs-navigation',
    parent: this.container,
  });

  this.prevButton = e({
    class:'fs-button',
    tag:'button',
    parent:this.navigation,
    content:'<svg xmlns="http://www.w3.org/2000/svg" height="32" viewBox="0 0 24 24" width="32">\
      <path d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z"/></svg>',
    action: function(e){
      self.prev();
    }
  });

  this.nextButton = e({
    class:'fs-button',
    tag:'button',
    parent:this.navigation,
    content:'<svg xmlns="http://www.w3.org/2000/svg" height="32" viewBox="0 0 24 24" width="32">\
      <path d="M12 4l-1.41 1.41L16.17 11H4v2h12.17l-5.58 5.59L12 20l8-8z"/></svg>',
    action: function(e){
      self.next();
    }
  });

  this.gallery = e({
    tag:'div',
    class:'fs-gallery',
    parent: this.container,
    action: function(e){
      self.setImage(e.target.src);
    }
  });

  this.closeButton = e({
    class:'fs-button fs-close',
    tag:'button',
    parent:this.toolbar,
    content:'<svg xmlns="http://www.w3.org/2000/svg" fill="white" height="32" viewBox="0 0 24 24" width="32">\
      <path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/>\
      </svg>',
    action: function(e){
      self.hide();
    }
  });

  // Centering active thumbnail on resize.
  var resizeRunning = false;
  window.addEventListener('resize', function(){
    if(resizeRunning){
      return;
    }

    resizeRunning = true;

    window.requestAnimationFrame(function(){
      self.fixGalleryPosition();
      resizeRunning = false;
    });
  });

  // Properties
  this.images = {};
  this.imageKeys = [];
  this.currentKeyIndex;
  this.current; // Current image object

  document.body.appendChild(this.container);

}

FullScreenImage.prototype.show = function(target){
  if(target instanceof HTMLElement){
    document.body.style.overflow = 'hidden';
    this.container.style.zIndex = 100;
    this.container.style.opacity = 0;
    this.container.style.display = 'block';
    this.setImage(target.src);
    this.container.focus();
    this.container.style.opacity = 1;
  }
}

FullScreenImage.prototype.hide = function(){
  document.body.style.overflow = null;
  this.container.style.opacity = 0;
  this.container.style.zIndex = -100;
}

FullScreenImage.prototype.getImageObj = function(arg){
  if(typeof arg === "string"){
    return this.images[arg];
  }
  else if(typeof arg === "number"){
    if(arg >= this.imageKeys.length){
      return this.getImageObj(arg - this.imageKeys.length);
    }
    else if(arg < 0){
      return this.getImageObj(arg + this.imageKeys.length);
    }
    else{
      return this.getImageObj(this.imageKeys[arg]);
    }
  }
  else if(arg === this.images[arg.src]){
    return arg;
  }
}

FullScreenImage.prototype.prepareImage = function(obj){
  obj = this.getImageObj(obj);
  if (obj == null){
    return;
  }
  if(obj.big == null){
    obj.big = e({
      tag: 'img',
      class: 'fs-image',
    });
    obj.big.src = obj.src;
    obj.big.style.opacity = 0; // 0.01
    //obj.big.style.visibility = 'hidden';
    obj.big.style.zIndex = 0;
    this.body.appendChild(obj.big);
  }
}

FullScreenImage.prototype.fixGalleryPosition = function(){
  var contWidth = window.innerWidth;
  var imgWidth = this.current.elem.clientWidth;
  var elemPos = this.current.elem.offsetLeft;
  var galleryPos = this.gallery.offsetLeft;
  var elemAbsPos = elemPos + galleryPos;
  var desiredPos = ( contWidth / 2 ) - ( imgWidth / 2 );

  var shift = elemAbsPos - desiredPos;

  this.gallery.style.transform = 'translateX('+ (galleryPos - shift) +'px)';
}

FullScreenImage.prototype.setImage = function(img){
  var self = this;
  if(typeof img === "string"){
    var old = this.current;
    this.currentKeyIndex = this.images[img].i;
    var obj = this.images[img];
    this.current = obj;
    this.current.elem.classList.add('fs-active');
    self.prepareImage(obj);
    this.fixGalleryPosition();

    self.prepareImage(obj.i + 1);
    self.prepareImage(obj.i - 1);

    if(old != null){

      old.elem.classList.remove('fs-active');
      old.big.style.opacity = 0;
      //old.big.style.visibility = 'hidden';
      old.big.style.zIndex = 0;
    }
    this.current.big.style.opacity = 1;
    this.current.big.style.visibility = null;
    this.current.big.style.zIndex = 1;
  }
  else if(typeof img === "number"){
    if(img >= this.imageKeys.length){
      this.setImage(img - this.imageKeys.length);
    }
    else if(img < 0){
      this.setImage(img + this.imageKeys.length);
    }
    else{
      this.setImage(this.imageKeys[img]);
    }
  }

}

FullScreenImage.prototype.next = function(){
  this.setImage(this.currentKeyIndex + 1);
}

FullScreenImage.prototype.prev = function(){
  this.setImage(this.currentKeyIndex - 1);
}

FullScreenImage.prototype.setGallery = function(images){
  var self = this;
  this.gallery.innerHTML = '';
  this.images = {};
  this.imageKeys = [];

  images.each(function(i,v){
    if( self.images[v.src] !== undefined){
      return;
    }
    var dest = e({
      tag: 'img',
      parent: self.gallery,
    });
    dest.src = v.src;
    self.imageKeys.push(dest.src);
    var obj = {
      src: dest.src,
      elem: dest,
      desc: v.alt,
      i: self.imageKeys.length - 1,
    };
    self.images[dest.src] = obj;
  });
}

function e(args){
  args = args || {};

  var element = document.createElement( args.tag || 'div' );
  if(typeof args.class === "string"){
    args.class.split(" ").forEach(function(className){
      element.classList.add(className);
    });
  }

  if(typeof args.content === "string" || typeof args.content === "number"){
    element.innerHTML = args.content;
  }

  if(args.parent instanceof HTMLElement){
    args.parent.appendChild(element);
  }

  if(typeof args.action === "function"){
    // TODO: Touch events
    element.addEventListener('click', args.action);
  }

  return element;
}<commit_msg>Fix deactivation of active image on reopening it<commit_after>'use strict';

function FullScreenImage(){
  var self = this;

  this.container = e({
    class: 'fs-container',
  });
  this.container.style.display = "none";
  this.container.setAttribute('tabindex', -1);

  this.container.addEventListener('keydown', function(e){
    var nextKeys = [76, 68, 74, 83, 9];
    var prevKeys = [65, 72, 75, 87];
    var exitCodes;
    if(e.keyCode === 39 ){
      self.next();
    }
    else if(e.keyCode === 37){
      self.prev();
    }
    else if(e.keyCode === 13){
      self.next();
    }
    else if(e.keyCode === 27){
      self.hide();
    }
    else if(e.keyCode === 32){
      self.next();
    }
    else if(e.keyCode === 8){
      self.prev();
    }
    else if(nextKeys.indexOf(e.keyCode) !== -1){
      self.next();
    }
    else if(prevKeys.indexOf(e.keyCode) !== -1){
      self.prev();
    }
    else{
      return;
    }
    e.preventDefault();
    e.stopPropagation();
  });

  this.toolbar = e({
    class: 'fs-toolbar',
    parent: this.container,
  });

  this.body = e({
    class: 'fs-body',
    parent: this.container,
  });

  this.navigation = e({
    class: 'fs-navigation',
    parent: this.container,
  });

  this.prevButton = e({
    class:'fs-button',
    tag:'button',
    parent:this.navigation,
    content:'<svg xmlns="http://www.w3.org/2000/svg" height="32" viewBox="0 0 24 24" width="32">\
      <path d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z"/></svg>',
    action: function(e){
      self.prev();
    }
  });

  this.nextButton = e({
    class:'fs-button',
    tag:'button',
    parent:this.navigation,
    content:'<svg xmlns="http://www.w3.org/2000/svg" height="32" viewBox="0 0 24 24" width="32">\
      <path d="M12 4l-1.41 1.41L16.17 11H4v2h12.17l-5.58 5.59L12 20l8-8z"/></svg>',
    action: function(e){
      self.next();
    }
  });

  this.gallery = e({
    tag:'div',
    class:'fs-gallery',
    parent: this.container,
    action: function(e){
      self.setImage(e.target.src);
    }
  });

  this.closeButton = e({
    class:'fs-button fs-close',
    tag:'button',
    parent:this.toolbar,
    content:'<svg xmlns="http://www.w3.org/2000/svg" fill="white" height="32" viewBox="0 0 24 24" width="32">\
      <path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/>\
      </svg>',
    action: function(e){
      self.hide();
    }
  });

  // Centering active thumbnail on resize.
  var resizeRunning = false;
  window.addEventListener('resize', function(){
    if(resizeRunning){
      return;
    }

    resizeRunning = true;

    window.requestAnimationFrame(function(){
      self.fixGalleryPosition();
      resizeRunning = false;
    });
  });

  // Properties
  this.images = {};
  this.imageKeys = [];
  this.currentKeyIndex;
  this.current; // Current image object

  document.body.appendChild(this.container);

}

FullScreenImage.prototype.show = function(target){
  if(target instanceof HTMLElement){
    document.body.style.overflow = 'hidden';
    this.container.style.zIndex = 100;
    this.container.style.opacity = 0;
    this.container.style.display = 'block';
    this.setImage(target.src);
    this.container.focus();
    this.container.style.opacity = 1;
  }
}

FullScreenImage.prototype.hide = function(){
  document.body.style.overflow = null;
  this.container.style.opacity = 0;
  this.container.style.zIndex = -100;
}

FullScreenImage.prototype.getImageObj = function(arg){
  if(typeof arg === "string"){
    return this.images[arg];
  }
  else if(typeof arg === "number"){
    if(arg >= this.imageKeys.length){
      return this.getImageObj(arg - this.imageKeys.length);
    }
    else if(arg < 0){
      return this.getImageObj(arg + this.imageKeys.length);
    }
    else{
      return this.getImageObj(this.imageKeys[arg]);
    }
  }
  else if(arg === this.images[arg.src]){
    return arg;
  }
}

FullScreenImage.prototype.prepareImage = function(obj){
  obj = this.getImageObj(obj);
  if (obj == null){
    return;
  }
  if(obj.big == null){
    obj.big = e({
      tag: 'img',
      class: 'fs-image',
    });
    obj.big.src = obj.src;
    obj.big.style.opacity = 0; // 0.01
    //obj.big.style.visibility = 'hidden';
    obj.big.style.zIndex = 0;
    this.body.appendChild(obj.big);
  }
}

FullScreenImage.prototype.fixGalleryPosition = function(){
  var contWidth = window.innerWidth;
  var imgWidth = this.current.elem.clientWidth;
  var elemPos = this.current.elem.offsetLeft;
  var galleryPos = this.gallery.offsetLeft;
  var elemAbsPos = elemPos + galleryPos;
  var desiredPos = ( contWidth / 2 ) - ( imgWidth / 2 );

  var shift = elemAbsPos - desiredPos;

  this.gallery.style.transform = 'translateX('+ (galleryPos - shift) +'px)';
}

FullScreenImage.prototype.setImage = function(img){
  var self = this;
  if(typeof img === "string"){
    var old = this.current;
    this.currentKeyIndex = this.images[img].i;
    var obj = this.images[img];
    this.current = obj;
    this.current.elem.classList.add('fs-active');
    self.prepareImage(obj);
    this.fixGalleryPosition();

    self.prepareImage(obj.i + 1);
    self.prepareImage(obj.i - 1);

    if(old != null && old != this.current){

      old.elem.classList.remove('fs-active');
      old.big.style.opacity = 0;
      //old.big.style.visibility = 'hidden';
      old.big.style.zIndex = 0;
    }
    this.current.big.style.opacity = 1;
    this.current.big.style.visibility = null;
    this.current.big.style.zIndex = 1;
  }
  else if(typeof img === "number"){
    if(img >= this.imageKeys.length){
      this.setImage(img - this.imageKeys.length);
    }
    else if(img < 0){
      this.setImage(img + this.imageKeys.length);
    }
    else{
      this.setImage(this.imageKeys[img]);
    }
  }

}

FullScreenImage.prototype.next = function(){
  this.setImage(this.currentKeyIndex + 1);
}

FullScreenImage.prototype.prev = function(){
  this.setImage(this.currentKeyIndex - 1);
}

FullScreenImage.prototype.setGallery = function(images){
  var self = this;
  this.gallery.innerHTML = '';
  this.images = {};
  this.imageKeys = [];

  images.each(function(i,v){
    if( self.images[v.src] !== undefined){
      return;
    }
    var dest = e({
      tag: 'img',
      parent: self.gallery,
    });
    dest.src = v.src;
    self.imageKeys.push(dest.src);
    var obj = {
      src: dest.src,
      elem: dest,
      desc: v.alt,
      i: self.imageKeys.length - 1,
    };
    self.images[dest.src] = obj;
  });
}

function e(args){
  args = args || {};

  var element = document.createElement( args.tag || 'div' );
  if(typeof args.class === "string"){
    args.class.split(" ").forEach(function(className){
      element.classList.add(className);
    });
  }

  if(typeof args.content === "string" || typeof args.content === "number"){
    element.innerHTML = args.content;
  }

  if(args.parent instanceof HTMLElement){
    args.parent.appendChild(element);
  }

  if(typeof args.action === "function"){
    // TODO: Touch events
    element.addEventListener('click', args.action);
  }

  return element;
}<|endoftext|>


<commit_before>const contents = {
  title: `Brocessing`,
  description: `Angry creative tech bureau based between Paris and Strasbourg`,
  email: `b0ss@brocessing.men`,
  url: `brocessing.men`,
  thumbnail: `thumbnail.png`,
  message: 'Angry creative tech bureau\nBased between Paris and Strasbourg',
  contact: [
    {
      name: `Github`,
      url: `https://github.com/brocessing`
    },
    {
      name: `Twitter`,
      url: `https://twitter.com/brocessing_men`
    },
    {
      name: `Mail`,
      url: `mailto:b0ss@brocessing.men`
    }
  ]
}

const links = {
  title: `Projets sous stéroïdes`,

  links: [
    {
      name: `Eyebro`,
      url: `https://brocessing.github.io/eyebro/`,
      caption: `Un runner game qui se joue avec les sourcils`,
      img: `previews/eyebro.png`,
      alt: `Preview du jeu Eyebro`
    },
    {
      name: `AR Music Experiment`,
      url: ` https://twitter.com/hugopiquemal/status/892807824908136449`,
      caption: `Générateur de boucles musicales via réalité augmentée`,
      img: `previews/armusic.jpg`,
      alt: `Preview de l'AR Music Experiment`
    },
    {
      name: `Arnaud Juracek [Portfolio]`,
      url: `http://arnaudjuracek.fr`,
      caption: `Un portfolio à contrôler à plusieurs en même temps`,
      img: `previews/rno.jpg`,
      alt: `Preview de arnaudjuracek.fr`
    },
    {
      name: `Superflux`,
      url: `https://antoine.cool/projects/superflux`,
      caption: `Des objets commandés avec le visage`,
      img: `previews/superflux.jpg`,
      alt: `Preview du projet Superflux`
    },
    {
      name: `Three.js Neon Experiment`,
      url: `neon01.mp4`,
      caption: `Effet néon reproduit dans le navigateur`,
      video: `previews/neon01.mp4`,
      video_img: ``,
      alt: `Vidéo de néon`
    }
  ]
}

const pages = [
  {
    output: 'index.html',
    content: contents,
    layout: 'layouts/index.hbs'
  },
  {
    output: 'growcessing.html',
    content: links,
    layout: 'layouts/growcessing.hbs'
  }
]

module.exports = pages
<commit_msg>Update description<commit_after>const contents = {
  title: `Brocessing`,
  description: `Angry creative tech bureau based between Paris and Strasbourg`,
  email: `b0ss@brocessing.men`,
  url: `brocessing.men`,
  thumbnail: `thumbnail.png`,
  message: 'Angry creative tech bureau\nBased between Paris and Strasbourg',
  contact: [
    {
      name: `Github`,
      url: `https://github.com/brocessing`
    },
    {
      name: `Twitter`,
      url: `https://twitter.com/brocessing_men`
    },
    {
      name: `Mail`,
      url: `mailto:b0ss@brocessing.men`
    }
  ]
}

const links = {
  title: `Projets sous stéroïdes`,

  links: [
    {
      name: `Eyebro`,
      url: `https://brocessing.github.io/eyebro/`,
      caption: `Un runner game qui se joue avec les sourcils`,
      img: `previews/eyebro.png`,
      alt: `Preview du jeu Eyebro`
    },
    {
      name: `AR Music Experiment`,
      url: ` https://twitter.com/hugopiquemal/status/892807824908136449`,
      caption: `Générateur de boucles musicales via réalité augmentée`,
      img: `previews/armusic.jpg`,
      alt: `Preview de l'AR Music Experiment`
    },
    {
      name: `Arnaud Juracek [Portfolio]`,
      url: `http://arnaudjuracek.fr`,
      caption: `Un portfolio à contrôler à plusieurs en même temps`,
      img: `previews/rno.jpg`,
      alt: `Preview de arnaudjuracek.fr`
    },
    {
      name: `Superflux`,
      url: `https://antoine.cool/projects/superflux`,
      caption: `Des objets commandés avec le visage`,
      img: `previews/superflux.jpg`,
      alt: `Preview du projet Superflux`
    },
    {
      name: `Three.js Neon Experiment`,
      url: `neon01.mp4`,
      caption: `Paths SVG convertis en néon 3D dans le navigateur`,
      video: `previews/neon01.mp4`,
      video_img: ``,
      alt: `Vidéo de three.js Neon Experiment`
    }
  ]
}

const pages = [
  {
    output: 'index.html',
    content: contents,
    layout: 'layouts/index.hbs'
  },
  {
    output: 'growcessing.html',
    content: links,
    layout: 'layouts/growcessing.hbs'
  }
]

module.exports = pages
<|endoftext|>


<commit_before>// function to load static resources with Promise
function loadResourcesDynamically(id, url, success, failure) {
       var scriptPromise = new Promise(function(resolve, reject) {
         // Create a new script tag
         var script = document.createElement('script');
         // Use the url argument as source attribute
         script.src = url;
         script.id = id;

         // Call resolve when it’s loaded
         script.addEventListener('load', function() {
           resolve(url);
         }, false);

         // Reject the promise if there’s an error
         script.addEventListener('error', function() {
           reject(url);
         }, false);

         // Add it to the body
         document.head.appendChild(script);
       });

       return scriptPromise;
}
//function to define Chart
function createChart(chartsType, JSONData, valueField, categoryField, divId) {
          switch (chartsType) {
            case 'bar':
            var chart = AmCharts.makeChart(divId, {
                "type": "serial",
                "theme": "light",
                "dataProvider": JSONData,
                "valueAxes": [{
                    "gridColor": "#FFFFFF",
                    "gridAlpha": 0.2,
                    "dashLength": 0
                }],
                "gridAboveGraphs": true,
                "startDuration": 1,
                "graphs": [{
                    "balloonText": "[[category]]: [[value]]",
                    "fillAlphas": 0.8,
                    "lineAlpha": 0.2,
                    "type": "column",
                    "valueField": valueField
                }],
                "chartCursor": {
                    "categoryBalloonEnabled": false,
                    "cursorAlpha": 0,
                    "zoomable": false
                },
                "categoryField": categoryField,
                "categoryAxis": {
                    "gridPosition": "start",
                    "gridAlpha": 0,
                    "tickPosition": "start",
                    "tickLength": 20
                },
                "export": {
                    "enabled": true
                }
            });
            break;
            case 'bar3D':
            var chart = AmCharts.makeChart(divId, {
                "theme": "light",
                "type": "serial",
                "startDuration": 2,
                "dataProvider": JSONData,
                "graphs": [{
                    "balloonText": "[[category]]: [[value]]",
                    "fillColorsField": "color",
                    "fillAlphas": 1,
                    "lineAlpha": 0.1,
                    "type": "column",
                    "valueField": valueField
                }],
                "depth3D": 20,
                "angle": 30,
                "chartCursor": {
                    "categoryBalloonEnabled": false,
                    "cursorAlpha": 0,
                    "zoomable": false
                },
                "categoryField": categoryField,
                "categoryAxis": {
                    "gridPosition": "start",
                    "labelRotation": 90
                },
                "export": {
                    "enabled": true
                }
            });
            jQuery('.chart-input').off().on('input change',function() {
              var property  = jQuery(this).data('property');
              var target    = chart;
              chart.startDuration = 0;

              if ( property == 'topRadius') {
                target = chart.graphs[0];
                if ( this.value == 0 ) {
                  this.value = undefined;
                }
              }
              target[property] = this.value;
              chart.validateNow();
            });
            break;
            case 'pie' :
            var chart = AmCharts.makeChart( divId, {
                "type": "pie",
                "theme": "light",
                "dataProvider": JSONData,
                "valueField": valueField,
                "titleField": categoryField,
                "balloon":{
                    "fixedPosition":true
                },
                "export": {
                    "enabled": true
                }
            } );
            break;
            case 'pie3D' :
            var chart = AmCharts.makeChart( divId, {
                "type": "pie",
                "theme": "light",
                "dataProvider": JSONData,
                "valueField": valueField,
                "titleField": categoryField,
                "outlineAlpha": 0.4,
                "depth3D": 15,
                "balloonText": "[[title]]
[[value]] ([[percents]]%)",
                "angle": 30,
                "export": {
                    "enabled": true
                }
            });
            jQuery( '.chart-input' ).off().on( 'input change', function() {
              var property = jQuery( this ).data( 'property' );
              var target = chart;
              var value = Number( this.value );
              chart.startDuration = 0;
              if ( property == 'innerRadius' ) {
                value += "%";
              }
              target[ property ] = value;
              chart.validateNow();
            });
            break;
            case 'donut' :
            var chart = AmCharts.makeChart( divId, {
                "type": "pie",
                "theme": "light",
                "dataProvider": JSONData,
                "valueField": valueField,
                "titleField": categoryField,
                "balloon":{
                    "fixedPosition":true
                },
                "export": {
                    "enabled": true
                }
            });
            break;
            case 'donut3D' :
            var chart = AmCharts.makeChart( divId, {
                "type": "pie",
                "theme": "light",
                "titles": JSONData,
                "valueField": valueField,
                "titleField": categoryField,
                "startEffect": "elastic",
                "startDuration": 2,
                "labelRadius": 15,
                "innerRadius": "50%",
                "depth3D": 10,
                "balloonText": "[[title]]
[[value]] ([[percents]]%)",
                "angle": 15,
                "export": {
                    "enabled": true
                }
            });
            jQuery( '.chart-input' ).off().on( 'input change', function() {
              var property = jQuery( this ).data( 'property' );
              var target = chart;
              var value = Number( this.value );
              chart.startDuration = 0;
              if ( property == 'innerRadius' ) {
                value += "%";
              }
              target[ property ] = value;
              chart.validateNow();
            });
            break;
            case 'pieLegend' :
            var chart = AmCharts.makeChart(divId, {
                "type": "pie",
                "startDuration": 0,
                "theme": "light",
                "addClassNames": true,
                "legend":{
                    "position":"right",
                    "marginRight":100,
                    "autoMargins":false
                },
                "innerRadius": "30%",
                "defs": {
                    "filter": [{
                        "id": "shadow",
                        "width": "200%",
                        "height": "200%",
                        "feOffset": {
                            "result": "offOut",
                            "in": "SourceAlpha",
                            "dx": 0,
                            "dy": 0
                        },
                        "feGaussianBlur": {
                            "result": "blurOut",
                            "in": "offOut",
                            "stdDeviation": 5
                        },
                        "feBlend": {
                            "in": "SourceGraphic",
                            "in2": "blurOut",
                            "mode": "normal"
                        }
                    }]
                },
                "dataProvider": JSONData,
                "valueField": valueField,
                "titleField": categoryField,
                "export": {
                    "enabled": true
                }
            });
            chart.addListener("init", handleInit);
            chart.addListener("rollOverSlice", function(e) {
              handleRollOver(e);
            });
            function handleInit(){
              chart.legend.addListener("rollOverItem", handleRollOver);
            }
            function handleRollOver(e){
              var wedge = e.dataItem.wedge.node;
              wedge.parentNode.appendChild(wedge);
            }
            break;
            case 'donutGradient' :
            var chart = AmCharts.makeChart(divId, {
                "type": "pie",
                "theme": "light",
                "innerRadius": "40%",
                "gradientRatio": [-0.4, -0.4, -0.4, -0.4, -0.4, -0.4, 0, 0.1, 0.2, 0.1, 0, -0.2, -0.5],
                "dataProvider": JSONData,
                "balloonText": "[[value]]",
                "valueField": valueField,
                "titleField": categoryField,
                "balloon": {
                    "drop": true,
                    "adjustBorderColor": false,
                    "color": "#FFFFFF",
                    "fontSize": 16
                },
                "export": {
                    "enabled": true
                }
            });
            default:
          }
        }

// Method to Inject Required Resource to build the Charts
function injectStaticResources(){
          loadScript('jquery', 'https://cdnjs.cloudflare.com/ajax/libs/jquery/3.0.0-alpha1/jquery.min.js').then(function() {
          return loadScript('amcharts', '//www.amcharts.com/lib/3/amcharts.js');
        }).then(function() {
          return loadScript('dark', '//www.amcharts.com/lib/3/themes/dark.js');
        }).then(function() {
          return loadScript('light', '//www.amcharts.com/lib/3/themes/light.js');
        }).then(function() {
          return loadScript('pie', 'https://www.amcharts.com/lib/3/pie.js');
        }).then(function() {
          return loadScript('serial', '//www.amcharts.com/lib/3/serial.js');
        }).then(function() {
          console.log('Loaded!');
        });
      }
//Method to Create UserPrefrence Record
function createUserPreferenceRecord() {
    // This remoting call will use the page's timeout value
    var deviceType='';
    var applicationType='';
    var browserType='';
    var profileName='';

    if (!isMobile.any){
        deviceType = 'Desktop';
    }
    else if(isMobile.phone){
        deviceType = 'Phone';
    }
    else if(isMobile.tablet){
        deviceType = 'Tablet';
    }
    if(ForceUI.isSalesforce1()){
        applicationType = 'Salesforce1';
    }
    else {
        applicationType = 'Salesforce Classic';
    }
    browserType = ForceUI.browserType();
    Visualforce.remoting.Manager.invokeAction(
        '{!$RemoteAction.UserPreferenceFeedController.createRecord}',
        applicationType,
        browserType,
        deviceType,
        '',
        function(result, event){
            if(event.status) {
                console.log(result.Id);
            }
        },
        {escape: true}
    );
}

//Method to load all require resource for injecting data
function getUserPreferenceRecords(){
    loadScript('jquery', 'https://rawgit.com/mailtoharshit/ForceSniffer.Js/master/js/forcesniffer.js').then(function() {
    return createUserPreferenceRecord();
  })
}
<commit_msg>Fixed names<commit_after>// function to load static resources with Promise
function loadResourcesDynamically(id, url, success, failure) {
       var scriptPromise = new Promise(function(resolve, reject) {
         // Create a new script tag
         var script = document.createElement('script');
         // Use the url argument as source attribute
         script.src = url;
         script.id = id;

         // Call resolve when it’s loaded
         script.addEventListener('load', function() {
           resolve(url);
         }, false);

         // Reject the promise if there’s an error
         script.addEventListener('error', function() {
           reject(url);
         }, false);

         // Add it to the body
         document.head.appendChild(script);
       });

       return scriptPromise;
}
//function to define Chart
function createChart(chartsType, JSONData, valueField, categoryField, divId) {
          switch (chartsType) {
            case 'bar':
            var chart = AmCharts.makeChart(divId, {
                "type": "serial",
                "theme": "light",
                "dataProvider": JSONData,
                "valueAxes": [{
                    "gridColor": "#FFFFFF",
                    "gridAlpha": 0.2,
                    "dashLength": 0
                }],
                "gridAboveGraphs": true,
                "startDuration": 1,
                "graphs": [{
                    "balloonText": "[[category]]: [[value]]",
                    "fillAlphas": 0.8,
                    "lineAlpha": 0.2,
                    "type": "column",
                    "valueField": valueField
                }],
                "chartCursor": {
                    "categoryBalloonEnabled": false,
                    "cursorAlpha": 0,
                    "zoomable": false
                },
                "categoryField": categoryField,
                "categoryAxis": {
                    "gridPosition": "start",
                    "gridAlpha": 0,
                    "tickPosition": "start",
                    "tickLength": 20
                },
                "export": {
                    "enabled": true
                }
            });
            break;
            case 'bar3D':
            var chart = AmCharts.makeChart(divId, {
                "theme": "light",
                "type": "serial",
                "startDuration": 2,
                "dataProvider": JSONData,
                "graphs": [{
                    "balloonText": "[[category]]: [[value]]",
                    "fillColorsField": "color",
                    "fillAlphas": 1,
                    "lineAlpha": 0.1,
                    "type": "column",
                    "valueField": valueField
                }],
                "depth3D": 20,
                "angle": 30,
                "chartCursor": {
                    "categoryBalloonEnabled": false,
                    "cursorAlpha": 0,
                    "zoomable": false
                },
                "categoryField": categoryField,
                "categoryAxis": {
                    "gridPosition": "start",
                    "labelRotation": 90
                },
                "export": {
                    "enabled": true
                }
            });
            jQuery('.chart-input').off().on('input change',function() {
              var property  = jQuery(this).data('property');
              var target    = chart;
              chart.startDuration = 0;

              if ( property == 'topRadius') {
                target = chart.graphs[0];
                if ( this.value == 0 ) {
                  this.value = undefined;
                }
              }
              target[property] = this.value;
              chart.validateNow();
            });
            break;
            case 'pie' :
            var chart = AmCharts.makeChart( divId, {
                "type": "pie",
                "theme": "light",
                "dataProvider": JSONData,
                "valueField": valueField,
                "titleField": categoryField,
                "balloon":{
                    "fixedPosition":true
                },
                "export": {
                    "enabled": true
                }
            } );
            break;
            case 'pie3D' :
            var chart = AmCharts.makeChart( divId, {
                "type": "pie",
                "theme": "light",
                "dataProvider": JSONData,
                "valueField": valueField,
                "titleField": categoryField,
                "outlineAlpha": 0.4,
                "depth3D": 15,
                "balloonText": "[[title]]
[[value]] ([[percents]]%)",
                "angle": 30,
                "export": {
                    "enabled": true
                }
            });
            jQuery( '.chart-input' ).off().on( 'input change', function() {
              var property = jQuery( this ).data( 'property' );
              var target = chart;
              var value = Number( this.value );
              chart.startDuration = 0;
              if ( property == 'innerRadius' ) {
                value += "%";
              }
              target[ property ] = value;
              chart.validateNow();
            });
            break;
            case 'donut' :
            var chart = AmCharts.makeChart( divId, {
                "type": "pie",
                "theme": "light",
                "dataProvider": JSONData,
                "valueField": valueField,
                "titleField": categoryField,
                "balloon":{
                    "fixedPosition":true
                },
                "export": {
                    "enabled": true
                }
            });
            break;
            case 'donut3D' :
            var chart = AmCharts.makeChart( divId, {
                "type": "pie",
                "theme": "light",
                "titles": JSONData,
                "valueField": valueField,
                "titleField": categoryField,
                "startEffect": "elastic",
                "startDuration": 2,
                "labelRadius": 15,
                "innerRadius": "50%",
                "depth3D": 10,
                "balloonText": "[[title]]
[[value]] ([[percents]]%)",
                "angle": 15,
                "export": {
                    "enabled": true
                }
            });
            jQuery( '.chart-input' ).off().on( 'input change', function() {
              var property = jQuery( this ).data( 'property' );
              var target = chart;
              var value = Number( this.value );
              chart.startDuration = 0;
              if ( property == 'innerRadius' ) {
                value += "%";
              }
              target[ property ] = value;
              chart.validateNow();
            });
            break;
            case 'pieLegend' :
            var chart = AmCharts.makeChart(divId, {
                "type": "pie",
                "startDuration": 0,
                "theme": "light",
                "addClassNames": true,
                "legend":{
                    "position":"right",
                    "marginRight":100,
                    "autoMargins":false
                },
                "innerRadius": "30%",
                "defs": {
                    "filter": [{
                        "id": "shadow",
                        "width": "200%",
                        "height": "200%",
                        "feOffset": {
                            "result": "offOut",
                            "in": "SourceAlpha",
                            "dx": 0,
                            "dy": 0
                        },
                        "feGaussianBlur": {
                            "result": "blurOut",
                            "in": "offOut",
                            "stdDeviation": 5
                        },
                        "feBlend": {
                            "in": "SourceGraphic",
                            "in2": "blurOut",
                            "mode": "normal"
                        }
                    }]
                },
                "dataProvider": JSONData,
                "valueField": valueField,
                "titleField": categoryField,
                "export": {
                    "enabled": true
                }
            });
            chart.addListener("init", handleInit);
            chart.addListener("rollOverSlice", function(e) {
              handleRollOver(e);
            });
            function handleInit(){
              chart.legend.addListener("rollOverItem", handleRollOver);
            }
            function handleRollOver(e){
              var wedge = e.dataItem.wedge.node;
              wedge.parentNode.appendChild(wedge);
            }
            break;
            case 'donutGradient' :
            var chart = AmCharts.makeChart(divId, {
                "type": "pie",
                "theme": "light",
                "innerRadius": "40%",
                "gradientRatio": [-0.4, -0.4, -0.4, -0.4, -0.4, -0.4, 0, 0.1, 0.2, 0.1, 0, -0.2, -0.5],
                "dataProvider": JSONData,
                "balloonText": "[[value]]",
                "valueField": valueField,
                "titleField": categoryField,
                "balloon": {
                    "drop": true,
                    "adjustBorderColor": false,
                    "color": "#FFFFFF",
                    "fontSize": 16
                },
                "export": {
                    "enabled": true
                }
            });
            default:
          }
        }

// Method to Inject Required Resource to build the Charts
function injectStaticResources(){
          loadScript('jquery', 'https://cdnjs.cloudflare.com/ajax/libs/jquery/3.0.0-alpha1/jquery.min.js').then(function() {
          return loadScript('amcharts', '//www.amcharts.com/lib/3/amcharts.js');
        }).then(function() {
          return loadScript('dark', '//www.amcharts.com/lib/3/themes/dark.js');
        }).then(function() {
          return loadScript('light', '//www.amcharts.com/lib/3/themes/light.js');
        }).then(function() {
          return loadScript('pie', 'https://www.amcharts.com/lib/3/pie.js');
        }).then(function() {
          return loadScript('serial', '//www.amcharts.com/lib/3/serial.js');
        }).then(function() {
          console.log('Loaded!');
        });
      }
//Method to Create UserPrefrence Record
function setUserPreferenceRecord() {
    // This remoting call will use the page's timeout value
    var deviceType='';
    var applicationType='';
    var browserType='';
    var profileName='';

    if (!isMobile.any){
        deviceType = 'Desktop';
    }
    else if(isMobile.phone){
        deviceType = 'Phone';
    }
    else if(isMobile.tablet){
        deviceType = 'Tablet';
    }
    if(ForceUI.isSalesforce1()){
        applicationType = 'Salesforce1';
    }
    else {
        applicationType = 'Salesforce Classic';
    }
    browserType = ForceUI.browserType();
    Visualforce.remoting.Manager.invokeAction(
        '{!$RemoteAction.UserPreferenceFeedController.createRecord}',
        applicationType,
        browserType,
        deviceType,
        '',
        function(result, event){
            if(event.status) {
                console.log(result.Id);
            }
        },
        {escape: true}
    );
}

//Method to load all require resource for injecting data
function createUserPreferenceRecords(){
    loadScript('forcesniffer.js', 'https://rawgit.com/mailtoharshit/ForceSniffer.Js/master/js/forcesniffer.js').then(function() {
    return setUserPreferenceRecord();
  })
}
<|endoftext|>


<commit_before>/* @flow weak */

import Promise from 'bluebird'
import PouchDB from 'pouchdb'
import async from 'async'
import fs from 'fs-extra'
import isEqual from 'lodash.isequal'

import Config from './config'
import logger from './logger'

import type { Metadata } from './metadata'
import type { Callback } from './utils/func'

const log = logger({
  prefix: 'Pouch         ',
  date: true
})

// Pouchdb is used to store all the metadata about files and folders.
// These metadata can come from the local filesystem or the remote cozy instance.
//
// Best practices from:
// http://pouchdb.com/2014/06/17/12-pro-tips-for-better-code-with-pouchdb.html
// http://docs.ehealthafrica.org/couchdb-best-practices/
//
// For naming conventions, we kept those used on cozy and its couchdb. So, it's
// creationDate and lastModification instead of created_at and updated_at. And
// views name are in camelcase (byChecksum, not by-checksum).
class Pouch {
  config: Config
  db: PouchDB
  updater: any

  constructor (config) {
    this.config = config
    this.db = new PouchDB(this.config.dbPath)
    this.db.setMaxListeners(100)
    this.db.on('error', err => log.warn(err))
    this.updater = async.queue((task, callback) => {
      return this.db.get(task._id, (err, doc) => {
        if (err && err.status === 404) {
          return this.db.put(task, callback)
        } else if (err) {
          return callback(err)
        } else {
          task._rev = doc._rev
          return this.db.put(task, callback)
        }
      })
    })

    Promise.promisifyAll(this)
  }

  // Create database and recreate all filters
  resetDatabase (callback) {
    this.db.destroy(() => {
      fs.ensureDirSync(this.config.dbPath)
      this.db = new PouchDB(this.config.dbPath)
      this.db.setMaxListeners(100)
      this.db.on('error', err => log.warn(err))
      return this.addAllViews(callback)
    })
  }

  /* Mini ODM */

  put (doc: Metadata, callback?: Callback) {
    log.debug('Saving metadata:')
    log.inspect(doc)
    return this.db.put(doc).asCallback(callback)
  }

  bulkDocs (docs: Metadata[], callback?: Callback) {
    log.debug('Saving bulk metadata:')
    log.inspect(docs)
    return this.db.bulkDocs(docs).asCallback(callback)
  }

  // Run a query and get all the results
  getAll (query, params, callback) {
    if (typeof params === 'function') {
      callback = params
      params = {include_docs: true}
    }
    // XXX Pouchdb does sometimes send us undefined values in docs.
    // It's rare and we didn't find a way to extract a proper test case.
    // So, we keep a workaround and hope that this bug will be fixed.
    this.db.query(query, params, function (err, res) {
      if (err) {
        return callback(err)
      } else {
        let docs = (Array.from(res.rows).filter((row) => (row.doc != null)).map((row) => row.doc))
        return callback(null, docs)
      }
    })
  }

  // Return all the files with this checksum
  byChecksum (checksum, callback) {
    let params = {
      key: checksum,
      include_docs: true
    }
    return this.getAll('byChecksum', params, callback)
  }

  // Return all the files and folders in this path, only at first level
  byPath (path, callback) {
    let params = {
      key: path,
      include_docs: true
    }
    return this.getAll('byPath', params, callback)
  }

  // Return all the files and folders in this path, even in subfolders
  byRecursivePath (path, callback) {
    let params
    if (path === '') {
      params =
                {include_docs: true}
    } else {
      params = {
        startkey: `${path}`,
        endkey: `${path}/\ufff0`,
        include_docs: true
      }
    }
    return this.getAll('byPath', params, callback)
  }

  byRecursivePathAsync: (string) => Promise<*>

  // Return the file/folder with this remote id
  byRemoteId (id, callback) {
    let params = {
      key: id,
      include_docs: true
    }
    this.db.query('byRemoteId', params, function (err, res) {
      if (err) {
        return callback(err)
      } else if (res.rows.length === 0) {
        return callback({status: 404, message: 'missing'})
      } else {
        return callback(null, res.rows[0].doc)
      }
    })
  }

  byRemoteIdMaybe (id, callback) {
    this.byRemoteId(id, (err, was) => {
      if (err && (err.status !== 404)) {
        callback(err)
      } else {
        callback(null, was)
      }
    })
  }

  byRemoteIdMaybeAsync: (id: string) => Promise<*>

  /* Views */

  // Create all required views in the database
  addAllViews (callback) {
    return async.series([
      this.addByPathView,
      this.addByChecksumView,
      this.addByRemoteIdView
    ], err => callback(err))
  }

  // Create a view to list files and folders inside a path
  // The path for a file/folder in root will be '',
  // not '.' as with node's path.dirname
  addByPathView (callback) {
    /* !pragma no-coverage-next */
    /* istanbul ignore next */
    let query =
      function (doc) {
        if ('docType' in doc) {
          let parts = doc._id.split('/')
          parts.pop()
          // $FlowFixMe
          return emit(parts.join('/'), {_id: doc._id}) // eslint-disable-line no-undef
        }
      }.toString()
    return this.createDesignDoc('byPath', query, callback)
  }

  // Create a view to find files by their checksum
  addByChecksumView (callback) {
    /* !pragma no-coverage-next */
    /* istanbul ignore next */
    let query =
      function (doc) {
        if ('checksum' in doc) {
          // $FlowFixMe
          return emit(doc.checksum) // eslint-disable-line no-undef
        }
      }.toString()
    return this.createDesignDoc('byChecksum', query, callback)
  }

  // Create a view to find file/folder by their _id on a remote cozy
  addByRemoteIdView (callback) {
    /* !pragma no-coverage-next */
    /* istanbul ignore next */
    let query =
      function (doc) {
        if ('remote' in doc) {
          // $FlowFixMe
          return emit(doc.remote._id) // eslint-disable-line no-undef
        }
      }.toString()
    return this.createDesignDoc('byRemoteId', query, callback)
  }

  // Create or update given design doc
  createDesignDoc (name, query, callback) {
    let doc = {
      _id: `_design/${name}`,
      views: {}
    }
    doc.views[name] = {map: query}
    this.db.get(doc._id, (_, designDoc) => {
      if (designDoc != null) {
        doc._rev = designDoc._rev
        if (isEqual(doc, designDoc)) { return callback() }
      }
      return this.db.put(doc, function (err) {
        if (!err) { log.debug(`Design document created: ${name}`) }
        return callback(err)
      })
    })
  }

  // Remove a design document for a given docType
  removeDesignDoc (docType, callback) {
    let id = `_design/${docType}`
    this.db.get(id, (err, designDoc) => {
      if (designDoc != null) {
        return this.db.remove(id, designDoc._rev, callback)
      } else {
        return callback(err)
      }
    })
  }

  /* Helpers */

  // Retrieve a previous doc revision from its id
  getPreviousRev (id, shortRev, callback) {
    let options = {
      revs: true,
      revs_info: true,
      open_revs: 'all'
    }
    this.db.get(id, options, (err, infos) => {
      if (err) {
        return callback(err)
      } else {
        let { ids } = infos[0].ok._revisions
        let { start } = infos[0].ok._revisions
        let revId = ids[start - shortRev]
        let rev = `${shortRev}-${revId}`
        return this.db.get(id, {rev}, function (err, doc) {
          if (err) { log.debug(infos[0].doc) }
          return callback(err, doc)
        })
      }
    })
  }

  getPreviousRevAsync: (id: string, shortRev: string) => Promise<string>

  /* Sequence numbers */

  // Get last local replication sequence,
  // ie the last change from pouchdb that have been applied
  getLocalSeq (callback) {
    this.db.get('_local/localSeq', function (err, doc) {
      if (err && err.status === 404) {
        callback(null, 0)
      } else {
        callback(err, doc && doc.seq)
      }
    })
  }

  // Set last local replication sequence
  // It is saved in PouchDB as a local document
  // See http://pouchdb.com/guides/local-documents.html
  setLocalSeq (seq, callback) {
    let task = {
      _id: '_local/localSeq',
      seq
    }
    return this.updater.push(task, callback)
  }

  // Get last remote replication sequence,
  // ie the last change from couchdb that have been saved in pouch
  getRemoteSeq (callback) {
    this.db.get('_local/remoteSeq', function (err, doc) {
      if (err && err.status === 404) {
        callback(null, 0)
      } else {
        callback(err, doc && doc.seq)
      }
    })
  }

  getRemoteSeqAsync: () => number

  // Set last remote replication sequence
  // It is saved in PouchDB as a local document
  // See http://pouchdb.com/guides/local-documents.html
  setRemoteSeq (seq, callback) {
    let task = {
      _id: '_local/remoteSeq',
      seq
    }
    return this.updater.push(task, callback)
  }

  setRemoteSeqAsync: (seq: number) => Promise<*>
}

export default Pouch
<commit_msg>pouch: Add path prefix in logs<commit_after>/* @flow weak */

import Promise from 'bluebird'
import PouchDB from 'pouchdb'
import async from 'async'
import fs from 'fs-extra'
import isEqual from 'lodash.isequal'

import Config from './config'
import logger from './logger'

import type { Metadata } from './metadata'
import type { Callback } from './utils/func'

const log = logger({
  prefix: 'Pouch         ',
  date: true
})

// Pouchdb is used to store all the metadata about files and folders.
// These metadata can come from the local filesystem or the remote cozy instance.
//
// Best practices from:
// http://pouchdb.com/2014/06/17/12-pro-tips-for-better-code-with-pouchdb.html
// http://docs.ehealthafrica.org/couchdb-best-practices/
//
// For naming conventions, we kept those used on cozy and its couchdb. So, it's
// creationDate and lastModification instead of created_at and updated_at. And
// views name are in camelcase (byChecksum, not by-checksum).
class Pouch {
  config: Config
  db: PouchDB
  updater: any

  constructor (config) {
    this.config = config
    this.db = new PouchDB(this.config.dbPath)
    this.db.setMaxListeners(100)
    this.db.on('error', err => log.warn(err))
    this.updater = async.queue((task, callback) => {
      return this.db.get(task._id, (err, doc) => {
        if (err && err.status === 404) {
          return this.db.put(task, callback)
        } else if (err) {
          return callback(err)
        } else {
          task._rev = doc._rev
          return this.db.put(task, callback)
        }
      })
    })

    Promise.promisifyAll(this)
  }

  // Create database and recreate all filters
  resetDatabase (callback) {
    this.db.destroy(() => {
      fs.ensureDirSync(this.config.dbPath)
      this.db = new PouchDB(this.config.dbPath)
      this.db.setMaxListeners(100)
      this.db.on('error', err => log.warn(err))
      return this.addAllViews(callback)
    })
  }

  /* Mini ODM */

  put (doc: Metadata, callback?: Callback) {
    log.debug(`${doc.path}: Saving metadata:`)
    log.inspect(doc)
    return this.db.put(doc).asCallback(callback)
  }

  bulkDocs (docs: Metadata[], callback?: Callback) {
    for (const doc of docs) {
      log.debug(`${doc.path}: Saving bulk metadata:`)
      log.inspect(doc)
    }
    return this.db.bulkDocs(docs).asCallback(callback)
  }

  // Run a query and get all the results
  getAll (query, params, callback) {
    if (typeof params === 'function') {
      callback = params
      params = {include_docs: true}
    }
    // XXX Pouchdb does sometimes send us undefined values in docs.
    // It's rare and we didn't find a way to extract a proper test case.
    // So, we keep a workaround and hope that this bug will be fixed.
    this.db.query(query, params, function (err, res) {
      if (err) {
        return callback(err)
      } else {
        let docs = (Array.from(res.rows).filter((row) => (row.doc != null)).map((row) => row.doc))
        return callback(null, docs)
      }
    })
  }

  // Return all the files with this checksum
  byChecksum (checksum, callback) {
    let params = {
      key: checksum,
      include_docs: true
    }
    return this.getAll('byChecksum', params, callback)
  }

  // Return all the files and folders in this path, only at first level
  byPath (path, callback) {
    let params = {
      key: path,
      include_docs: true
    }
    return this.getAll('byPath', params, callback)
  }

  // Return all the files and folders in this path, even in subfolders
  byRecursivePath (path, callback) {
    let params
    if (path === '') {
      params =
                {include_docs: true}
    } else {
      params = {
        startkey: `${path}`,
        endkey: `${path}/\ufff0`,
        include_docs: true
      }
    }
    return this.getAll('byPath', params, callback)
  }

  byRecursivePathAsync: (string) => Promise<*>

  // Return the file/folder with this remote id
  byRemoteId (id, callback) {
    let params = {
      key: id,
      include_docs: true
    }
    this.db.query('byRemoteId', params, function (err, res) {
      if (err) {
        return callback(err)
      } else if (res.rows.length === 0) {
        return callback({status: 404, message: 'missing'})
      } else {
        return callback(null, res.rows[0].doc)
      }
    })
  }

  byRemoteIdMaybe (id, callback) {
    this.byRemoteId(id, (err, was) => {
      if (err && (err.status !== 404)) {
        callback(err)
      } else {
        callback(null, was)
      }
    })
  }

  byRemoteIdMaybeAsync: (id: string) => Promise<*>

  /* Views */

  // Create all required views in the database
  addAllViews (callback) {
    return async.series([
      this.addByPathView,
      this.addByChecksumView,
      this.addByRemoteIdView
    ], err => callback(err))
  }

  // Create a view to list files and folders inside a path
  // The path for a file/folder in root will be '',
  // not '.' as with node's path.dirname
  addByPathView (callback) {
    /* !pragma no-coverage-next */
    /* istanbul ignore next */
    let query =
      function (doc) {
        if ('docType' in doc) {
          let parts = doc._id.split('/')
          parts.pop()
          // $FlowFixMe
          return emit(parts.join('/'), {_id: doc._id}) // eslint-disable-line no-undef
        }
      }.toString()
    return this.createDesignDoc('byPath', query, callback)
  }

  // Create a view to find files by their checksum
  addByChecksumView (callback) {
    /* !pragma no-coverage-next */
    /* istanbul ignore next */
    let query =
      function (doc) {
        if ('checksum' in doc) {
          // $FlowFixMe
          return emit(doc.checksum) // eslint-disable-line no-undef
        }
      }.toString()
    return this.createDesignDoc('byChecksum', query, callback)
  }

  // Create a view to find file/folder by their _id on a remote cozy
  addByRemoteIdView (callback) {
    /* !pragma no-coverage-next */
    /* istanbul ignore next */
    let query =
      function (doc) {
        if ('remote' in doc) {
          // $FlowFixMe
          return emit(doc.remote._id) // eslint-disable-line no-undef
        }
      }.toString()
    return this.createDesignDoc('byRemoteId', query, callback)
  }

  // Create or update given design doc
  createDesignDoc (name, query, callback) {
    let doc = {
      _id: `_design/${name}`,
      views: {}
    }
    doc.views[name] = {map: query}
    this.db.get(doc._id, (_, designDoc) => {
      if (designDoc != null) {
        doc._rev = designDoc._rev
        if (isEqual(doc, designDoc)) { return callback() }
      }
      return this.db.put(doc, function (err) {
        if (!err) { log.debug(`Design document created: ${name}`) }
        return callback(err)
      })
    })
  }

  // Remove a design document for a given docType
  removeDesignDoc (docType, callback) {
    let id = `_design/${docType}`
    this.db.get(id, (err, designDoc) => {
      if (designDoc != null) {
        return this.db.remove(id, designDoc._rev, callback)
      } else {
        return callback(err)
      }
    })
  }

  /* Helpers */

  // Retrieve a previous doc revision from its id
  getPreviousRev (id, shortRev, callback) {
    let options = {
      revs: true,
      revs_info: true,
      open_revs: 'all'
    }
    this.db.get(id, options, (err, infos) => {
      if (err) {
        return callback(err)
      } else {
        let { ids } = infos[0].ok._revisions
        let { start } = infos[0].ok._revisions
        let revId = ids[start - shortRev]
        let rev = `${shortRev}-${revId}`
        return this.db.get(id, {rev}, function (err, doc) {
          if (err) { log.debug(infos[0].doc) }
          return callback(err, doc)
        })
      }
    })
  }

  getPreviousRevAsync: (id: string, shortRev: string) => Promise<string>

  /* Sequence numbers */

  // Get last local replication sequence,
  // ie the last change from pouchdb that have been applied
  getLocalSeq (callback) {
    this.db.get('_local/localSeq', function (err, doc) {
      if (err && err.status === 404) {
        callback(null, 0)
      } else {
        callback(err, doc && doc.seq)
      }
    })
  }

  // Set last local replication sequence
  // It is saved in PouchDB as a local document
  // See http://pouchdb.com/guides/local-documents.html
  setLocalSeq (seq, callback) {
    let task = {
      _id: '_local/localSeq',
      seq
    }
    return this.updater.push(task, callback)
  }

  // Get last remote replication sequence,
  // ie the last change from couchdb that have been saved in pouch
  getRemoteSeq (callback) {
    this.db.get('_local/remoteSeq', function (err, doc) {
      if (err && err.status === 404) {
        callback(null, 0)
      } else {
        callback(err, doc && doc.seq)
      }
    })
  }

  getRemoteSeqAsync: () => number

  // Set last remote replication sequence
  // It is saved in PouchDB as a local document
  // See http://pouchdb.com/guides/local-documents.html
  setRemoteSeq (seq, callback) {
    let task = {
      _id: '_local/remoteSeq',
      seq
    }
    return this.updater.push(task, callback)
  }

  setRemoteSeqAsync: (seq: number) => Promise<*>
}

export default Pouch
<|endoftext|>


<commit_before>var subnodes = require('./subnodes');

function attr(node, attr) {
	if (attr in node)
		return node[attr];
	return null;
}

// function members(node) {
// 	var list = [];
// 	for (var i in node) {
// 		if (node.hasOwnProperty(i))
// 			list.push(i);
// 	}
// 	// console.log('members()', node, list);
// 	return list;
// }

var factory = require('cssauron')({
	tag: 'type',
	id: 'id',
	children: subnodes,
	parent : 'parent',
	attr: attr,
	// class: members,
	// contents: 'name'
});

function all(node, selector, matches) {
	if (!matches)
		matches = [];
	if (selector(node))
		matches.push(node);

	var nodes = subnodes(node);
	if (nodes) {
		for (var i=0; i<nodes.length; i++) {
			all(nodes[i], selector, matches);
		}
	}

	return matches;
}

function first(node, selector) {
	if (selector(node))
		return node;

	var nodes = subnodes(node);
	if (nodes) {
		for (var i=0; i<nodes.length; i++) {
			var selected = first(nodes[i], selector);
			if (selected !== false)
				return selected;
		}
	}
	return false;
}

function children(node, selector) {
	var matches = [];
	var nodes = subnodes(node);
	if (!nodes)
		return matches;
	for (var i=0; i<nodes.length; i++) {
		var child = nodes[i];
		if (selector(child))
			matches.push(child);
	}
	return matches;
}

function firstChild(node, selector) {
	var nodes = subnodes(node);
	if (!nodes)
		return null;
	for (var i=0; i<nodes.length; i++) {
		var child = nodes[i];
		if (selector(child))
			return child;
	}
	return null;
}

module.exports = {
	subnodes: subnodes,
	selector: factory,
	all: all,
	first: first,
	children: children,
	firstChild: firstChild
};
<commit_msg>Fix: children() query did not accept matches list argument<commit_after>var subnodes = require('./subnodes');

function attr(node, attr) {
	if (attr in node)
		return node[attr];
	return null;
}

var factory = require('cssauron')({
	tag: 'type',
	id: 'id',
	children: subnodes,
	parent : 'parent',
	attr: attr
});

function all(node, selector, matches) {
	if (!matches)
		matches = [];
	if (selector(node))
		matches.push(node);

	var nodes = subnodes(node);
	if (nodes) {
		for (var i=0; i<nodes.length; i++) {
			all(nodes[i], selector, matches);
		}
	}

	return matches;
}

function first(node, selector) {
	if (selector(node))
		return node;

	var nodes = subnodes(node);
	if (nodes) {
		for (var i=0; i<nodes.length; i++) {
			var selected = first(nodes[i], selector);
			if (selected !== false)
				return selected;
		}
	}
	return false;
}

function children(node, selector, matches) {
	if (!matches)
		matches = [];
	var nodes = subnodes(node);
	if (!nodes)
		return matches;
	for (var i=0; i<nodes.length; i++) {
		var child = nodes[i];
		if (selector(child))
			matches.push(child);
	}
	return matches;
}

function firstChild(node, selector) {
	var nodes = subnodes(node);
	if (!nodes)
		return null;
	for (var i=0; i<nodes.length; i++) {
		var child = nodes[i];
		if (selector(child))
			return child;
	}
	return null;
}

module.exports = {
	subnodes: subnodes,
	selector: factory,
	all: all,
	first: first,
	children: children,
	firstChild: firstChild
};
<|endoftext|>