<commit_before>var wxs3 = wxs3 || {};

var camera, scene, renderer,  controls,  geomGroup;

//check WebGL
(function () {
    if (!window.WebGLRenderingContext) {
        // the browser doesn't even know what WebGL is
        window.location = "ttp://get.webgl.org";
    }
    /*
     else {
     var canvas = document.getElementById("myCanvas");
     ^   var context = canvas.getContext("webgl");
     if (!context) {
     // browser supports WebGL but initialization failed.
     window.location = "http://get.webgl.org/troubleshooting";
     }
     }
     */

})();

// extraction for URL parameters
function getQueryVariable(variable) {
    var pair,
        i,
        vars,
        query;
    console.log("getQueryVariable :" + variable);

    query = window.location.search.substring(1);
    vars = query.split("&");
    for (i = 0; i < vars.length; i++) {
        pair = vars[i].split("=");
        if (pair[0].toUpperCase() == variable) {
            return pair[1];
        }
    }
    return(false);
}

var dim = {
    width: window.innerWidth,
    height: window.innerHeight,
    demWidth: getQueryVariable("WIDTH") || 50,
    demHeight: getQueryVariable("HEIGHT") || 50,
    bbox: getQueryVariable("BBOX") || '161244,6831251,171526,6837409',
    metersWidth: 0,
    metersHeight: 0,
    minx: 0,
    maxx: 0,
    miny: 0,
    maxy: 0,
    tilesFinished: 0,
    tilesTotal: 4,
    init: function () {
        this.metersWidth = this.bbox.split(',')[2] - this.bbox.split(',')[0];
        this.metersHeight = this.bbox.split(',')[3] - this.bbox.split(',')[1];
        this.minx=parseInt(this.bbox.split(',')[0]);
        this.maxx=parseInt(this.bbox.split(',')[2]);
        this.miny=parseInt(this.bbox.split(',')[1]);
        this.maxy=parseInt(this.bbox.split(',')[3]);
        return this;
    },
    crs: getQueryVariable("CRS") || getQueryVariable("SRS") || 'EPSG:32633',
    coverage: getQueryVariable("COVERAGE") || 'land_utm33_10m',
    wms: getQueryVariable("WMS") || 'http://openwms.statkart.no/skwms1/wms.topo2',
    wmsMult: getQueryVariable("WMSMULT") || 5,
    wmsFormat: getQueryVariable("WMSFORMAT") || "image/png",
    wmsFormatMode: "",
    zInv: getQueryVariable("ZINV") || false,
    zMult: getQueryVariable("ZMULT")
    //x: getQueryVariable("X") || -dim.demHeight / 2,
    //y: getQueryVariable("Y") || -dim.demWidth / 2
}.init();

wxs3.init = function () {
    var plane, cameraHeight, fov, proportionAverage, proportionHeight, proportionWidth;

    if (dim.metersWidth > dim.metersHeight) {
        dim.demWidth = parseInt((dim.metersWidth / dim.metersHeight) * dim.demWidth);
    } else if (dim.metersWidth < dim.metersHeight) {
        dim.demHeight = parseInt((dim.metersHeight / dim.metersWidth) * dim.demHeight);
    }

    proportionWidth = dim.metersWidth / dim.demWidth; // mapunits between vertexes in x-dimention
    proportionHeight = dim.metersHeight / dim.demHeight; // mapunits between vertexes in y-dimention
    proportionAverage = ((proportionWidth + proportionHeight) / 2); // average mapunits between vertexes

    if (dim.zInv) {
        proportionAverage *= -1;
    }
    if (dim.zMult) {
        dim.zMult = proportionAverage / dim.zMult;
    } else {
        dim.zMult = proportionAverage;
    }

    if (getQueryVariable("WMSFORMATMODE")) {
        dim.wmsFormatMode = '; mode=' + getQueryVariable("WMSFORMATMODE");
    }

    // We've defined some standardlayers for the default wms-service in topo2.layers.js. Overwrite them if defined in url.
    layers = getQueryVariable("LAYERS") || layers;

    renderer = new THREE.WebGLRenderer();
    renderer.setSize(dim.width, dim.height);

    scene = new THREE.Scene();
    scene.add(new THREE.AmbientLight(0xeeeeee));

    fov = 45;
    camera = new THREE.PerspectiveCamera(fov, dim.width / dim.height, 0.1, 20000);
    // Some trig to find height for camera
    cameraHeight = getQueryVariable("Z") || (dim.metersHeight / 2) / Math.tan((fov / 2) * Math.PI / 180);
    // Place camera in middle of bbox
    camera.position.set((dim.minx+dim.maxx)/2, (dim.miny+dim.maxy)/2, cameraHeight);
    controls = new THREE.TrackballControls(camera);
    // Point camera directly down
    controls.target=new THREE.Vector3((dim.minx+dim.maxx)/2, (dim.miny+dim.maxy)/2,0);
    // For future reference
    /*
    materials=[];
    geometryMain = new THREE.PlaneGeometry(dim.maxx-dim.minx, dim.maxy-dim.miny, (dim.demWidth - 1) , (dim.demHeight - 1));
    planeMain=new THREE.Mesh(geometryMain,new THREE.MeshFaceMaterial(materials));
    planeMain.position.y=(dim.miny+dim.maxy)/2;
    planeMain.position.x=(dim.minx+dim.maxx)/2;
    */
    // Generate tiles and boundingboxes
    bbox2tiles(dim.minx,dim.miny,dim.maxx,dim.maxy);
    //scene.add(planeMain);

 document.getElementById('webgl').appendChild(renderer.domElement);
}();

function bbox2tiles(minx,miny,maxx,maxy){
    //TODO: generic tilematrix-parsing

    // Proof of concept with 2 subdivision in each dimention:
    //0,0
    addTile(1,minx,miny,(minx+maxx)/2,(miny+maxy)/2);
    //1,0
    addTile(2,(minx+maxx)/2,miny,maxx,(miny+maxy)/2);
    //0,1
    addTile(3,minx,(miny+maxy)/2,(minx+maxx)/2,maxy);
    //1,1
    addTile(4,(minx+maxx)/2,(miny+maxy)/2,maxx,maxy);

    //addTile(1,minx,miny,maxx,maxy);

}

function render() {
    controls.update();
    requestAnimationFrame(render);
    renderer.render(scene, camera);
}

function addTile(tileNr,minx,miny,maxx,maxy){
    /*
    geometry = new THREE.PlaneGeometry(maxx-minx+100, maxy-miny+100, (dim.demWidth - 1) + 100, (dim.demHeight - 1)+100);
    bbox=parseInt(minx+50)+','+parseInt(miny+50)+','+parseInt(maxx+50)+','+parseInt(maxy+50);
    */

    var bbox=parseInt(minx)+','+parseInt(miny)+','+parseInt(maxx)+','+parseInt(maxy);
    var dem = new XMLHttpRequest();
    dem.open('GET', 'http://openwms.statkart.no/skwms1/wcs.dtm?SERVICE=WCS&VERSION=1.0.0&REQUEST=GetCoverage&FORMAT=XYZ&COVERAGE=' + dim.coverage +
        '&bbox=' + bbox +
        '&CRS=' + dim.crs +
        '&RESPONSE_CRS=' + dim.crs +
        /*
        '&WIDTH=' + parseInt(dim.demWidth +100)+
        '&HEIGHT=' + parseInt(dim.demHeight + 100),false);
        */
        '&WIDTH=' + parseInt(dim.demWidth)+
        '&HEIGHT=' + parseInt(dim.demHeight),true);

    dem.onreadystatechange = function () {
        var i, l, lines;
 var geometry;
        if (this.readyState == 4) {
             var geometry = new THREE.PlaneGeometry(maxx-minx, maxy-miny, (dim.demWidth - 1) , (dim.demHeight - 1));
            lines = this.responseText.split("\n");
            for (i = 0, l = geometry.vertices.length; i < l; i++) {
                //geometry.vertices[i].z = (lines[i].split(' ')[2] / dim.zMult);
                geometry.vertices[i].z = lines[i].split(' ')[2];
                //console.log(geometry.vertices[i].z)
            }
            /*material = new THREE.MeshPhongMaterial({ map: THREE.ImageUtils.loadTexture(dim.wms + '?service=wms&version=1.3.0&request=getmap&crs=' +
        dim.crs + '&srs=' + dim.crs + '&WIDTH=' + dim.demWidth * dim.wmsMult + '&HEIGHT=' + dim.demHeight * dim.wmsMult + '&bbox=' + bbox +
      '&layers=' + layers + '&format=' + dim.wmsFormat + dim.wmsFormatMode)});
            */
      material = new THREE.MeshPhongMaterial({ map: THREE.ImageUtils.loadTexture(dim.wms + '?service=wms&version=1.3.0&request=getmap&crs=' +
        dim.crs + '&srs=' + dim.crs + '&WIDTH=' + dim.demWidth * dim.wmsMult + '&HEIGHT=' + dim.demHeight * dim.wmsMult + '&bbox=' + bbox +
      '&layers=' + layers + '&format=' + dim.wmsFormat + dim.wmsFormatMode,
      new THREE.UVMapping()
      )});
      //materials.push(material);

    //material.needsUpdate=true;
    //material.map.needsUpdate=true;
    var plane = new THREE.Mesh(geometry, material);
    // Move plane to coordinates

    plane.position.y=(miny+maxy)/2;
    plane.position.x=(minx+maxx)/2;
    scene.add(plane);

    // For future reference
    /*
    planeMain.position.y=(miny+maxy)/2;
    planeMain.position.x=(minx+maxx)/2;
    */
    //THREE.GeometryUtils.merge(geometryMain,geometry);
    //planeMain.add(plane);
            dim.tilesFinished+=1;
            window.render();
            /*plane.scale.z=0;
            while (plane.scale.z<1){
                plane.scale.z+=0.001;
                window.render();
            }
            */
            /*
            if (dim.tilesFinished==dim.tilesTotal){
            //document.getElementById('webgl').children[tilenr].
                window.render();
            }
            */
        //}
        //geometry.needsUpdate=true;
            console.log('rendering bbox ' + bbox);
            console.log('nr of finished geom: ' + dim.tilesFinished);
    }};
    dem.send();

    //material = new THREE.MeshPhongMaterial({ map: THREE.ImageUtils.loadTexture('http://opencache.statkart.no/gatekeeper/gk/gk.open_wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=topo2&STYLE=default&TILEMATRIXSET=EPSG%3A32633&TILEMATRIX=EPSG%3A32633%3A9&TILEROW=147&TILECOL=275&FORMAT=image%2Fpng')

//To here
}

<commit_msg>tiles v2<commit_after>var wxs3 = wxs3 || {};

var camera, scene, renderer,  controls,  geomGroup;

//check WebGL
(function () {
    if (!window.WebGLRenderingContext) {
        // the browser doesn't even know what WebGL is
        window.location = "ttp://get.webgl.org";
    }
    /*
     else {
     var canvas = document.getElementById("myCanvas");
     ^   var context = canvas.getContext("webgl");
     if (!context) {
     // browser supports WebGL but initialization failed.
     window.location = "http://get.webgl.org/troubleshooting";
     }
     }
     */

})();

// extraction for URL parameters
function getQueryVariable(variable) {
    var pair,
        i,
        vars,
        query;
    console.log("getQueryVariable :" + variable);

    query = window.location.search.substring(1);
    vars = query.split("&");
    for (i = 0; i < vars.length; i++) {
        pair = vars[i].split("=");
        if (pair[0].toUpperCase() == variable) {
            return pair[1];
        }
    }
    return(false);
}

var dim = {
    width: window.innerWidth,
    height: window.innerHeight,
    demWidth: getQueryVariable("WIDTH") || 50,
    demHeight: getQueryVariable("HEIGHT") || 50,
    bbox: getQueryVariable("BBOX") || '161244,6831251,171526,6837409',
    metersWidth: 0,
    metersHeight: 0,
    minx: 0,
    maxx: 0,
    miny: 0,
    maxy: 0,
    tilesFinished: 0,
    tilesTotal: 4,
    init: function () {
        this.metersWidth = this.bbox.split(',')[2] - this.bbox.split(',')[0];
        this.metersHeight = this.bbox.split(',')[3] - this.bbox.split(',')[1];
        this.minx=parseInt(this.bbox.split(',')[0]);
        this.maxx=parseInt(this.bbox.split(',')[2]);
        this.miny=parseInt(this.bbox.split(',')[1]);
        this.maxy=parseInt(this.bbox.split(',')[3]);
        return this;
    },
    crs: getQueryVariable("CRS") || getQueryVariable("SRS") || 'EPSG:32633',
    coverage: getQueryVariable("COVERAGE") || 'land_utm33_10m',
    wms: getQueryVariable("WMS") || 'http://openwms.statkart.no/skwms1/wms.topo2',
    wmsMult: getQueryVariable("WMSMULT") || 1,
    wmsFormat: getQueryVariable("WMSFORMAT") || "image/png",
    wmsFormatMode: "",
    zInv: getQueryVariable("ZINV") || false,
    zMult: getQueryVariable("ZMULT"),
    proportionWidth: 0,
    proportionHeight: 0
    //x: getQueryVariable("X") || -dim.demHeight / 2,
    //y: getQueryVariable("Y") || -dim.demWidth / 2
}.init();

wxs3.init = function () {
    var plane, cameraHeight, fov, proportionAverage, proportionHeight, proportionWidth;

    if (dim.metersWidth > dim.metersHeight) {
        dim.demWidth = parseInt((dim.metersWidth / dim.metersHeight) * dim.demWidth);
    } else if (dim.metersWidth < dim.metersHeight) {
        dim.demHeight = parseInt((dim.metersHeight / dim.metersWidth) * dim.demHeight);
    }

    dim.proportionWidth = dim.metersWidth / dim.demWidth; // mapunits between vertexes in x-dimention
    dim.proportionHeight = dim.metersHeight / dim.demHeight; // mapunits between vertexes in y-dimention
    proportionAverage = ((dim.proportionWidth + dim.proportionHeight) / 2); // average mapunits between vertexes

    if (dim.zInv) {
        proportionAverage *= -1;
    }
    if (dim.zMult) {
        dim.zMult = proportionAverage / dim.zMult;
    } else {
        dim.zMult = proportionAverage;
    }

    if (getQueryVariable("WMSFORMATMODE")) {
        dim.wmsFormatMode = '; mode=' + getQueryVariable("WMSFORMATMODE");
    }

    // We've defined some standardlayers for the default wms-service in topo2.layers.js. Overwrite them if defined in url.
    layers = getQueryVariable("LAYERS") || layers;

    renderer = new THREE.WebGLRenderer();
    renderer.setSize(dim.width, dim.height);

    scene = new THREE.Scene();
    scene.add(new THREE.AmbientLight(0xeeeeee));

    fov = 45;
    camera = new THREE.PerspectiveCamera(fov, dim.width / dim.height, 0.1, 20000);
    // Some trig to find height for camera
    cameraHeight = getQueryVariable("Z") || (dim.metersHeight / 2) / Math.tan((fov / 2) * Math.PI / 180);
    // Place camera in middle of bbox
    camera.position.set((dim.minx+dim.maxx)/2, (dim.miny+dim.maxy)/2, cameraHeight);
    controls = new THREE.TrackballControls(camera);
    // Point camera directly down
    controls.target=new THREE.Vector3((dim.minx+dim.maxx)/2, (dim.miny+dim.maxy)/2,0);
   // For future reference

    materials=[];
    //geometryMain = new THREE.PlaneGeometry(dim.maxx-dim.minx, dim.maxy-dim.miny, (dim.demWidth - 1) , (dim.demHeight - 1));
    geometryMain = new THREE.Geometry();
    //planeMain=new THREE.Mesh(geometryMain,new THREE.MeshFaceMaterial(materials));
    dummy=new THREE.Mesh();
    //planeMain.position.y=(dim.miny+dim.maxy)/2;
    //planeMain.position.x=(dim.minx+dim.maxx)/2;

    // Generate tiles and boundingboxes
    bbox2tiles(dim.minx,dim.miny,dim.maxx,dim.maxy);
    //scene.add(planeMain);

 document.getElementById('webgl').appendChild(renderer.domElement);
}();

function bbox2tiles(minx,miny,maxx,maxy){
    //TODO: generic tilematrix-parsing

    // Proof of concept with 2 subdivision in each dimention:
    //0,0
    addTile('x0_y0',minx,miny,(minx+maxx)/2,(miny+maxy)/2);
    //1,0
    addTile('x1_y0',(minx+maxx)/2,miny,maxx,(miny+maxy)/2);
    //0,1
    addTile('x0_y1',minx,(miny+maxy)/2,(minx+maxx)/2,maxy);
    //1,1
    addTile('x1_y1',(minx+maxx)/2,(miny+maxy)/2,maxx,maxy);

    //addTile(1,minx,miny,maxx,maxy);

}

function render() {
    controls.update();
    requestAnimationFrame(render);
    renderer.render(scene, camera);
}

function addTile(tileNr,minx,miny,maxx,maxy){
    /*
    geometry = new THREE.PlaneGeometry(maxx-minx+100, maxy-miny+100, (dim.demWidth - 1) + 100, (dim.demHeight - 1)+100);
    bbox=parseInt(minx+50)+','+parseInt(miny+50)+','+parseInt(maxx+50)+','+parseInt(maxy+50);
    */

    var bboxWCS=parseInt(minx)+','+parseInt(miny-dim.proportionHeight)+','+parseInt(maxx+dim.proportionWidth)+','+parseInt(maxy);
    //var bboxWCS=parseInt(minx)+','+parseInt(miny)+','+parseInt(maxx)+','+parseInt(maxy);

    var dem = new XMLHttpRequest();
    dem.open('GET', 'http://openwms.statkart.no/skwms1/wcs.dtm?SERVICE=WCS&VERSION=1.0.0&REQUEST=GetCoverage&FORMAT=XYZ'+
        '&COVERAGE=' + dim.coverage +
        '&bbox=' + bboxWCS +
        '&CRS=' + dim.crs +
        '&RESPONSE_CRS=' + dim.crs +
        /*
        '&WIDTH=' + parseInt(dim.demWidth +2)+
        '&HEIGHT=' + parseInt(dim.demHeight + 2),
        */
        '&WIDTH=' + parseInt(dim.demWidth+1)+
        '&HEIGHT=' + parseInt(dim.demHeight+1), // +
        //'&INTERPOLATION=bilinear',
        true
        );

    dem.onreadystatechange = function () {
        var i, l, lines;
 var geometry, bboxWMS, minxWMS, minyWMS,maxxWMS,maxyWMS;

        if (this.readyState == 4) {

       //var geometry = new THREE.PlaneGeometry(maxx-minx, maxy-miny, (dim.demWidth - 1) , (dim.demHeight - 1));
       var geometry = new THREE.PlaneGeometry(maxx-minx, maxy-miny, (dim.demWidth ) , (dim.demHeight ));
            lines = this.responseText.split("\n");
            for (i = 0, l = geometry.vertices.length; i < l; i++) {
                //geometry.vertices[i].z = (lines[i].split(' ')[2] / dim.zMult);
                /*
                if( i<dim.demWidth){
                    continue;
                }
                */
                geometry.vertices[i].x = lines[i].split(' ')[0];
                geometry.vertices[i].y = lines[i].split(' ')[1];
                geometry.vertices[i].z = lines[i].split(' ')[2];
                if (i==0){
                    minxWMS=geometry.vertices[i].x;
                    maxyWMS=geometry.vertices[i].y;
                }
                if (i==l-1){
                    maxxWMS=geometry.vertices[i].x;
                    minyWMS=geometry.vertices[i].y;
                }
                //console.log(geometry.vertices[i].z)
            }
            bboxWMS=minxWMS+','+minyWMS+','+maxxWMS+','+maxyWMS;
            /*material = new THREE.MeshPhongMaterial({ map: THREE.ImageUtils.loadTexture(dim.wms + '?service=wms&version=1.3.0&request=getmap&crs=' +
        dim.crs + '&srs=' + dim.crs + '&WIDTH=' + dim.demWidth * dim.wmsMult + '&HEIGHT=' + dim.demHeight * dim.wmsMult + '&bbox=' + bbox +
      '&layers=' + layers + '&format=' + dim.wmsFormat + dim.wmsFormatMode)});
            */

      material = new THREE.MeshPhongMaterial(
          {
          map: THREE.ImageUtils.loadTexture(
            dim.wms + '?service=wms&version=1.3.0&request=getmap'+
            '&crs=' + dim.crs +
            '&srs=' + dim.crs +
            '&WIDTH=' + dim.demWidth * dim.wmsMult +
            '&HEIGHT=' + dim.demHeight * dim.wmsMult +
            '&bbox=' + bboxWMS +
            '&layers=' + layers +
            '&format=' + dim.wmsFormat + dim.wmsFormatMode,
            new THREE.UVMapping())
        }
      );
      material.name='material_'+tileNr;
      //materials.push(material);

    //material.needsUpdate=true;
    //material.map.needsUpdate=true;
    var plane = new THREE.Mesh(geometry, material);
    plane.name='tile_'+tileNr;
    // Move plane to coordinates

    //plane.position.y=(miny+maxy)/2;
    //plane.position.x=(minx+maxx)/2;
    scene.add(plane);
        // For future reference
    /*
    //dummy.position.y=(miny+maxy)/2;
    //dummy.position.x=(minx+maxx)/2;
    dummy.geometry=geometry;
    //dummy.map=material;
    THREE.GeometryUtils.merge(geometryMain,dummy);
    */
    // For future reference
    /*
    planeMain.position.y=(miny+maxy)/2;
    planeMain.position.x=(minx+maxx)/2;
    */
    //THREE.GeometryUtils.merge(geometryMain,plane);

    //planeMain.add(plane);
            dim.tilesFinished+=1;
            window.render();
            /*plane.scale.z=0;
            while (plane.scale.z<1){
                plane.scale.z+=0.001;
                window.render();
            }
            */

          // When all tiles are loaded, generate single mesh containing all
          //
          /*
            if (dim.tilesFinished==dim.tilesTotal){
            //document.getElementById('webgl').children[tilenr].

            geometryMain.computeFaceNormals();
            geometryMain.computeVertexNormals();
            geometryMain.elementsNeedUpdate=true;
            geometryMain.mergeVertices();
            THREE.GeometryUtils.triangulateQuads( geometryMain );

             geometryMain.mergeVertices();

             geometryFinal=new THREE.PlaneGeometry(dim.maxx-dim.minx, dim.maxy-dim.miny, ((dim.demWidth *(dim.tilesTotal/2)) - 1) , ((dim.demHeight * (dim.tilesTotal/2))- 1));
             var i2, l2;
             for (i2 = 0, l2 = geometryMain.vertices.length; i2 < l2; i2++) {
                //geometry.vertices[i].z = (lines[i].split(' ')[2] / dim.zMult);

                geometryFinal.vertices[i2].x = geometryMain.vertices[i2].x;
                geometryFinal.vertices[i2].y = geometryMain.vertices[i2].y;
                geometryFinal.vertices[i2].z = geometryMain.vertices[i2].z;
             }

                var mesh = new THREE.Mesh( geometryMain,new THREE.MeshBasicMaterial( { color: 0x000000, depthTest: true, polygonOffset: true, polygonOffsetFactor: 1, polygonOffsetUnits: 1, wireframe: true } ));
                //var mesh = new THREE.Mesh( geometryMain, THREE.MeshFaceMaterial(materials) );
                //mesh.position.y=(dim.miny+dim.maxy)/2;
                //mesh.position.x=(dim.minx+dim.maxx)/2;

				scene.add( mesh );
                window.render();
            }
          */
        //}
        //geometry.needsUpdate=true;
            console.log('rendering bbox ' + bboxWMS);
            console.log('nr of finished geom: ' + dim.tilesFinished);
    }};
    dem.send();

    //material = new THREE.MeshPhongMaterial({ map: THREE.ImageUtils.loadTexture('http://opencache.statkart.no/gatekeeper/gk/gk.open_wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=topo2&STYLE=default&TILEMATRIXSET=EPSG%3A32633&TILEMATRIX=EPSG%3A32633%3A9&TILEROW=147&TILECOL=275&FORMAT=image%2Fpng')

//To here
}

<|endoftext|>


<commit_before>/*
 * webstore-upload
 *
 *
 * Copyright (c) 2014 Anton Sivolapov
 * Licensed under the MIT license.
 */

'use strict';

module.exports = function (grunt) {
    var Q = require('q'),
        https = require('https'),
        path = require('path'),
        url = require('url'),
        fs = require('fs'),
        http = require('http'),
        util = require('util');

    var isWin = /^win/.test(process.platform);
    var isLinux = /^linux$/.test(process.platform);

    // Please see the Grunt documentation for more information regarding task
    // creation: http://gruntjs.com/creating-tasks
    grunt.registerTask('webstore_upload',
                       'Automate uploading uploading process of the new versions of Chrome Extension to Chrome Webstore',
    function ( taskName ) {
        var
            _task = this,
            _ = require('lodash'),
            extensionsConfigPath = _task.name + '.extensions',
            accountsConfigPath = _task.name + '.accounts',
            browserConfigPath = _task.name + '.browser_path',
            browserPath,
            accounts,
            extensions;

        if(isLinux){
            grunt.config.requires(browserConfigPath);
        }
        grunt.config.requires(extensionsConfigPath);
        grunt.config.requires(accountsConfigPath);

        extensions = grunt.config(extensionsConfigPath);
        accounts = grunt.config(accountsConfigPath);
        browserPath = grunt.config(browserConfigPath);

        grunt.registerTask( 'get_account_token', 'Get token for account',
            function(accountName){
                //prepare account for inner function
                var account = accounts[ accountName ];
                account["name"] = accountName;
                account["browser_path"] = browserPath;

                var done = this.async();

                getTokenForAccount(account, function (error, token) {
                    if(error !== null){
                        console.log('Error');
                        throw error;
                    }
                    //set token for provided account
                    accounts[ accountName ].token = token;
                    done();
                });
            });

        grunt.registerTask( 'uploading', 'uploading with token',
            function( extensionName ){
                var done = this.async();
                var promisses = [];
                var uploadConfig;
                var accountName;

                if(extensionName){
                    uploadConfig = extensions[extensionName];
                    accountName = uploadConfig.account || "default";

                    uploadConfig["name"] = extensionName;
                    uploadConfig["account"] = accounts[accountName];
                    promisses.push(handleUpload(uploadConfig));
                }else{
                    _.each(extensions, function (extension, extensionName) {
                        var extensionConfigPath = extensionsConfigPath + '.' + extensionName;

                        grunt.config.requires(extensionConfigPath);
                        grunt.config.requires(extensionConfigPath + '.appID');
                        grunt.config.requires(extensionConfigPath + '.zip');

                        var uploadConfig = extension;
                        var accountName = extension.account || "default";

                        uploadConfig["name"] = extensionName;
                        uploadConfig["account"] = accounts[accountName];
                        var p = handleUpload(uploadConfig);
                        promisses.push(p);
                    });
                }

                Q.allSettled(promisses).then(function (results) {
                    var isError = false;
                    results.forEach(function (result) {
                        if (result.state === "fulfilled") {
                            var value = result.value;
                        } else {
                            isError = result.reason;
                        }
                    });
                    if( isError ){
                        grunt.log.writeln('================');
                        grunt.log.writeln(' ');
                        grunt.log.writeln('Error while uploading: ', isError);
                        grunt.log.writeln(' ');
                        done(new Error('Error while uploading'));
                    }else{
                        done();
                    }
                });
            });

        if(taskName){
            //upload specific extension
            var extensionConfigPath = extensionsConfigPath + '.' + taskName;

            grunt.config.requires(extensionConfigPath);
            grunt.config.requires(extensionConfigPath + '.appID');
            grunt.config.requires(extensionConfigPath + '.zip');

            var extensionConfig = grunt.config(extensionConfigPath);
            var accountName = extensionConfig.account || "default";

            grunt.task.run( [ "get_account_token:" + accountName, "uploading:" + taskName ] );

        }else{
            //upload all available extensions
            var tasks = [];

            //callculate tasks for accounts that we want to use
            var accountsTasksToUse = _.uniq( _.map( extensions, function (extension) {
                return "get_account_token:" + (extension.account || "default");
            }) );

            accountsTasksToUse.push('uploading');
            grunt.task.run( accountsTasksToUse );
        }
    });

        //upload zip
    function handleUpload( options ){
        var d = Q.defer();
        var doPublish = false;
        if( typeof options.publish !== 'undefined' ){
            doPublish = options.publish;
        }else if( typeof options.account.publish !== 'undefined' ){
            doPublish = options.account.publish;
        }
        //updating existing
        grunt.log.writeln('================');
        grunt.log.writeln(' ');
        grunt.log.writeln('Updating app ('+ options.name +'): ', options.appID);
        grunt.log.writeln(' ');

        var filePath, readStream, zip,
            req = https.request({
                method: 'PUT',
                host: 'www.googleapis.com',
                path: util.format('/upload/chromewebstore/v1.1/items/%s', options.appID),
                headers: {
                    'Authorization': 'Bearer ' + options.account.token,
                    'x-goog-api-version': '2'
                }
            }, function(res) {
                res.setEncoding('utf8');
                var response = '';
                res.on('data', function (chunk) {
                    response += chunk;
                });
                res.on('end', function () {
                    var hasError = false;
                    var error = {};
                    var obj = JSON.parse(response);
                    if( obj.uploadState !== "SUCCESS" ){
                        // console.log('Error while uploading ZIP', obj);
                        hasError = true;
                        error[obj.id] = obj.itemError;
                    }else{
                        grunt.log.writeln(' ');
                        grunt.log.writeln('Uploading done ('+ options.name +')' );
                        grunt.log.writeln(' ');
                    }

                    if( hasError ){
                        d.reject(error);
                    }else{
                        if( doPublish ){
                            publishItem( options ).then(function () {
                                d.resolve();
                            });
                        }else{
                            d.resolve();
                        }
                    }
                });
            });

        req.on('error', function(e){
            grunt.log.error('Something went wrong ('+ options.name +')', e.message);
            d.resolve();
        });

        zip = options.zip;
        if( fs.statSync( zip ).isDirectory() ){
            zip = getRecentFile( zip );
        }

        filePath = path.resolve(zip);
        grunt.log.writeln('Path to ZIP ('+ options.name +'): ', filePath);
        grunt.log.writeln(' ');
        grunt.log.writeln('Uploading '+ options.name +'..');
        readStream = fs.createReadStream(filePath);

        readStream.on('end', function(){
            req.end();
        });

        readStream.pipe(req);

        return d.promise;
    }

    //make item published
    function publishItem(options){
        var d = Q.defer();
        grunt.log.writeln('Publishing ('+ options.name +') ' + options.appID + '..');

        var req = https.request({
            method: 'POST',
            host: 'www.googleapis.com',
            path: util.format('/chromewebstore/v1.1/items/%s/publish', options.appID),
            headers: {
                'Authorization': 'Bearer ' + options.account.token,
                'x-goog-api-version': '2',
                'Content-Length': '0'
            }
        }, function(res) {
            res.setEncoding('utf8');
            var response = '';
            res.on('data', function (chunk) {
                response += chunk;
            });
            res.on('end', function () {
                var obj = JSON.parse(response);
                if( obj.error ){
                    console.log('Error while publishing ('+ options.name +'). Please check configuration at Developer Dashboard', obj);
                }else{
                    grunt.log.writeln('Publishing done ('+ options.name +')');
                    grunt.log.writeln(' ');
                }
                d.resolve();
            });
        });

        req.on('error', function(e){
            grunt.log.error('Something went wrong ('+ options.name +')', e.message);
            d.resolve();
        });
        req.end();

        return d.promise;
    }

    //return most recent chenged file in directory
    function getRecentFile( dirName ){
        var files = grunt.file.expand( { filter: 'isFile' }, dirName + '/*.zip'),
            mostRecentFile,
            currentFile;

        if( files.length ){
            for( var i = 0; i < files.length; i++ ){
                currentFile = files[i];
                if( !mostRecentFile ){
                    mostRecentFile = currentFile;
                }else{
                    if( fs.statSync( currentFile ).mtime > fs.statSync( mostRecentFile ).mtime ){
                        mostRecentFile = currentFile;
                    }
                }
            }
            return mostRecentFile;
        }else{
            return false;
        }
    }

    //get OAuth token
    function getTokenForAccount( account, cb ){
        var exec = require('child_process').exec,
            token = null,
            port = 8090,
            callbackURL = util.format('http://localhost:%s', port),
            server = http.createServer(),
            codeUrl = util.format('https://accounts.google.com/o/oauth2/auth?response_type=code&scope=https://www.googleapis.com/auth/chromewebstore&client_id=%s&redirect_uri=%s', account.client_id, callbackURL);

        grunt.log.writeln(' ');
        grunt.log.writeln('Authorization for account: ' + account.name);
        grunt.log.writeln('================');

        //due user interaction is required, we creating server to catch response and opening browser to ask user privileges
        server.on('connection', function(socket) {
            //reset Keep-Alive connetions in order to quick close server
            socket.setTimeout(1000);
        });
        server.on('request', function(req, res){
            var code = url.parse(req.url, true).query['code'];  //user browse back, so code in url string
            if( code ){
                res.end('Got it! Authorizations for account "' + account.name + '" done. \
                        Check your console for new details. Tab now can be closed.');
                server.close(function () {
                    requestToken( code );
                });
            }else{
                res.end('Please click here and allow access for account "' + account.name + '", \
to continue uploading..');
            }
        });
        server.listen( port, 'localhost' );

        grunt.log.writeln(' ');
        grunt.log.writeln('Opening browser for authorization.. Please confirm privileges to continue..');
        grunt.log.writeln(' ');
        grunt.log.writeln(util.format('If browser doesnt opened in a minute, please check options.browserPath or visit manually %s to continue', callbackURL));
        grunt.log.writeln(' ');

        if (isWin && !account.browser_path) {
            exec( util.format('rundll32.exe url.dll,FileProtocolHandler "%s"', codeUrl), function(error, stdout, stderr ){
            });
        }

        else {
            exec( util.format('"%s" "%s"', account.browser_path, codeUrl), function(error, stdout, stderr ){
            });
        }

        function requestToken( code ){
            console.log('code', code);
            var post_data = util.format('client_id=%s&client_secret=%s&code=%s&grant_type=authorization_code&redirect_uri=%s', account.client_id, account.client_secret, code, callbackURL),
                req = https.request({
                    host: 'accounts.google.com',
                    path: '/o/oauth2/token',
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/x-www-form-urlencoded',
                        'Content-Length': post_data.length
                    }
                }, function(res) {

                    res.setEncoding('utf8');
                    var response = '';
                    res.on('data', function (chunk) {
                        response += chunk;
                    });
                    res.on('end', function () {
                        var obj = JSON.parse(response);
                        if(obj.error){
                            grunt.log.writeln('Error: during access token request');
                            grunt.log.writeln( response );
                            cb( new Error() );
                        }else{
                            token = obj.access_token;
                            cb(null, token);
                        }
                    });
                });

            req.on('error', function(e){
                console.log('Something went wrong', e.message);
                cb( e );
            });

            req.write( post_data );
            req.end();
        }
    }
};

<commit_msg>Fix Google response error<commit_after>/*
 * webstore-upload
 *
 *
 * Copyright (c) 2014 Anton Sivolapov
 * Licensed under the MIT license.
 */

'use strict';

module.exports = function (grunt) {
    var Q = require('q'),
        https = require('https'),
        path = require('path'),
        url = require('url'),
        fs = require('fs'),
        http = require('http'),
        util = require('util');

    var isWin = /^win/.test(process.platform);
    var isLinux = /^linux$/.test(process.platform);

    // Please see the Grunt documentation for more information regarding task
    // creation: http://gruntjs.com/creating-tasks
    grunt.registerTask('webstore_upload',
                       'Automate uploading uploading process of the new versions of Chrome Extension to Chrome Webstore',
    function ( taskName ) {
        var
            _task = this,
            _ = require('lodash'),
            extensionsConfigPath = _task.name + '.extensions',
            accountsConfigPath = _task.name + '.accounts',
            browserConfigPath = _task.name + '.browser_path',
            browserPath,
            accounts,
            extensions;

        if(isLinux){
            grunt.config.requires(browserConfigPath);
        }
        grunt.config.requires(extensionsConfigPath);
        grunt.config.requires(accountsConfigPath);

        extensions = grunt.config(extensionsConfigPath);
        accounts = grunt.config(accountsConfigPath);
        browserPath = grunt.config(browserConfigPath);

        grunt.registerTask( 'get_account_token', 'Get token for account',
            function(accountName){
                //prepare account for inner function
                var account = accounts[ accountName ];
                account["name"] = accountName;
                account["browser_path"] = browserPath;

                var done = this.async();

                getTokenForAccount(account, function (error, token) {
                    if(error !== null){
                        console.log('Error');
                        throw error;
                    }
                    //set token for provided account
                    accounts[ accountName ].token = token;
                    done();
                });
            });

        grunt.registerTask( 'uploading', 'uploading with token',
            function( extensionName ){
                var done = this.async();
                var promisses = [];
                var uploadConfig;
                var accountName;

                if(extensionName){
                    uploadConfig = extensions[extensionName];
                    accountName = uploadConfig.account || "default";

                    uploadConfig["name"] = extensionName;
                    uploadConfig["account"] = accounts[accountName];
                    promisses.push(handleUpload(uploadConfig));
                }else{
                    _.each(extensions, function (extension, extensionName) {
                        var extensionConfigPath = extensionsConfigPath + '.' + extensionName;

                        grunt.config.requires(extensionConfigPath);
                        grunt.config.requires(extensionConfigPath + '.appID');
                        grunt.config.requires(extensionConfigPath + '.zip');

                        var uploadConfig = extension;
                        var accountName = extension.account || "default";

                        uploadConfig["name"] = extensionName;
                        uploadConfig["account"] = accounts[accountName];
                        var p = handleUpload(uploadConfig);
                        promisses.push(p);
                    });
                }

                Q.allSettled(promisses).then(function (results) {
                    var isError = false;
                    results.forEach(function (result) {
                        if (result.state === "fulfilled") {
                            var value = result.value;
                        } else {
                            isError = result.reason;
                        }
                    });
                    if( isError ){
                        grunt.log.writeln('================');
                        grunt.log.writeln(' ');
                        grunt.log.writeln('Error while uploading: ', isError);
                        grunt.log.writeln(' ');
                        done(new Error('Error while uploading'));
                    }else{
                        done();
                    }
                });
            });

        if(taskName){
            //upload specific extension
            var extensionConfigPath = extensionsConfigPath + '.' + taskName;

            grunt.config.requires(extensionConfigPath);
            grunt.config.requires(extensionConfigPath + '.appID');
            grunt.config.requires(extensionConfigPath + '.zip');

            var extensionConfig = grunt.config(extensionConfigPath);
            var accountName = extensionConfig.account || "default";

            grunt.task.run( [ "get_account_token:" + accountName, "uploading:" + taskName ] );

        }else{
            //upload all available extensions
            var tasks = [];

            //callculate tasks for accounts that we want to use
            var accountsTasksToUse = _.uniq( _.map( extensions, function (extension) {
                return "get_account_token:" + (extension.account || "default");
            }) );

            accountsTasksToUse.push('uploading');
            grunt.task.run( accountsTasksToUse );
        }
    });

        //upload zip
    function handleUpload( options ){
        var d = Q.defer();
        var doPublish = false;
        if( typeof options.publish !== 'undefined' ){
            doPublish = options.publish;
        }else if( typeof options.account.publish !== 'undefined' ){
            doPublish = options.account.publish;
        }
        //updating existing
        grunt.log.writeln('================');
        grunt.log.writeln(' ');
        grunt.log.writeln('Updating app ('+ options.name +'): ', options.appID);
        grunt.log.writeln(' ');

        var filePath, readStream, zip,
            req = https.request({
                method: 'PUT',
                host: 'www.googleapis.com',
                path: util.format('/upload/chromewebstore/v1.1/items/%s', options.appID),
                headers: {
                    'Authorization': 'Bearer ' + options.account.token,
                    'x-goog-api-version': '2'
                }
            }, function(res) {
                res.setEncoding('utf8');
                var response = '';
                res.on('data', function (chunk) {
                    response += chunk;
                });
                res.on('end', function () {
                    var obj = JSON.parse(response);
                    if( obj.uploadState !== "SUCCESS" ) {
                        // console.log('Error while uploading ZIP', obj);
                        d.reject(obj.error.message);
                    }else{
                        grunt.log.writeln(' ');
                        grunt.log.writeln('Uploading done ('+ options.name +')' );
                        grunt.log.writeln(' ');
                        if( doPublish ){
                            publishItem( options ).then(function () {
                                d.resolve();
                            });
                        }else{
                            d.resolve();
                        }
                    }
                });
            });

        req.on('error', function(e){
            grunt.log.error('Something went wrong ('+ options.name +')', e.message);
            d.resolve();
        });

        zip = options.zip;
        if( fs.statSync( zip ).isDirectory() ){
            zip = getRecentFile( zip );
        }

        filePath = path.resolve(zip);
        grunt.log.writeln('Path to ZIP ('+ options.name +'): ', filePath);
        grunt.log.writeln(' ');
        grunt.log.writeln('Uploading '+ options.name +'..');
        readStream = fs.createReadStream(filePath);

        readStream.on('end', function(){
            req.end();
        });

        readStream.pipe(req);

        return d.promise;
    }

    //make item published
    function publishItem(options){
        var d = Q.defer();
        grunt.log.writeln('Publishing ('+ options.name +') ' + options.appID + '..');

        var req = https.request({
            method: 'POST',
            host: 'www.googleapis.com',
            path: util.format('/chromewebstore/v1.1/items/%s/publish', options.appID),
            headers: {
                'Authorization': 'Bearer ' + options.account.token,
                'x-goog-api-version': '2',
                'Content-Length': '0'
            }
        }, function(res) {
            res.setEncoding('utf8');
            var response = '';
            res.on('data', function (chunk) {
                response += chunk;
            });
            res.on('end', function () {
                var obj = JSON.parse(response);
                if( obj.error ){
                    console.log('Error while publishing ('+ options.name +'). Please check configuration at Developer Dashboard', obj);
                }else{
                    grunt.log.writeln('Publishing done ('+ options.name +')');
                    grunt.log.writeln(' ');
                }
                d.resolve();
            });
        });

        req.on('error', function(e){
            grunt.log.error('Something went wrong ('+ options.name +')', e.message);
            d.resolve();
        });
        req.end();

        return d.promise;
    }

    //return most recent chenged file in directory
    function getRecentFile( dirName ){
        var files = grunt.file.expand( { filter: 'isFile' }, dirName + '/*.zip'),
            mostRecentFile,
            currentFile;

        if( files.length ){
            for( var i = 0; i < files.length; i++ ){
                currentFile = files[i];
                if( !mostRecentFile ){
                    mostRecentFile = currentFile;
                }else{
                    if( fs.statSync( currentFile ).mtime > fs.statSync( mostRecentFile ).mtime ){
                        mostRecentFile = currentFile;
                    }
                }
            }
            return mostRecentFile;
        }else{
            return false;
        }
    }

    //get OAuth token
    function getTokenForAccount( account, cb ){
        var exec = require('child_process').exec,
            token = null,
            port = 8090,
            callbackURL = util.format('http://localhost:%s', port),
            server = http.createServer(),
            codeUrl = util.format('https://accounts.google.com/o/oauth2/auth?response_type=code&scope=https://www.googleapis.com/auth/chromewebstore&client_id=%s&redirect_uri=%s', account.client_id, callbackURL);

        grunt.log.writeln(' ');
        grunt.log.writeln('Authorization for account: ' + account.name);
        grunt.log.writeln('================');

        //due user interaction is required, we creating server to catch response and opening browser to ask user privileges
        server.on('connection', function(socket) {
            //reset Keep-Alive connetions in order to quick close server
            socket.setTimeout(1000);
        });
        server.on('request', function(req, res){
            var code = url.parse(req.url, true).query['code'];  //user browse back, so code in url string
            if( code ){
                res.end('Got it! Authorizations for account "' + account.name + '" done. \
                        Check your console for new details. Tab now can be closed.');
                server.close(function () {
                    requestToken( code );
                });
            }else{
                res.end('Please click here and allow access for account "' + account.name + '", \
to continue uploading..');
            }
        });
        server.listen( port, 'localhost' );

        grunt.log.writeln(' ');
        grunt.log.writeln('Opening browser for authorization.. Please confirm privileges to continue..');
        grunt.log.writeln(' ');
        grunt.log.writeln(util.format('If browser doesnt opened in a minute, please check options.browserPath or visit manually %s to continue', callbackURL));
        grunt.log.writeln(' ');

        if (isWin && !account.browser_path) {
            exec( util.format('rundll32.exe url.dll,FileProtocolHandler "%s"', codeUrl), function(error, stdout, stderr ){
            });
        }

        else {
            exec( util.format('"%s" "%s"', account.browser_path, codeUrl), function(error, stdout, stderr ){
            });
        }

        function requestToken( code ){
            console.log('code', code);
            var post_data = util.format('client_id=%s&client_secret=%s&code=%s&grant_type=authorization_code&redirect_uri=%s', account.client_id, account.client_secret, code, callbackURL),
                req = https.request({
                    host: 'accounts.google.com',
                    path: '/o/oauth2/token',
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/x-www-form-urlencoded',
                        'Content-Length': post_data.length
                    }
                }, function(res) {

                    res.setEncoding('utf8');
                    var response = '';
                    res.on('data', function (chunk) {
                        response += chunk;
                    });
                    res.on('end', function () {
                        var obj = JSON.parse(response);
                        if(obj.error){
                            grunt.log.writeln('Error: during access token request');
                            grunt.log.writeln( response );
                            cb( new Error() );
                        }else{
                            token = obj.access_token;
                            cb(null, token);
                        }
                    });
                });

            req.on('error', function(e){
                console.log('Something went wrong', e.message);
                cb( e );
            });

            req.write( post_data );
            req.end();
        }
    }
};

<|endoftext|>


<commit_before>// Copyright 2018-2021, University of Colorado Boulder

/**
 * Displays a beaker graphic
 *
 * @author Jonathan Olson <jonathan.olson@colorado.edu>
 */

import Shape from '../../../../../kite/js/Shape.js';
import merge from '../../../../../phet-core/js/merge.js';
import Node from '../../../../../scenery/js/nodes/Node.js';
import Path from '../../../../../scenery/js/nodes/Path.js';
import LinearGradient from '../../../../../scenery/js/util/LinearGradient.js';
import fractionsCommonColorProfile from '../../../common/view/fractionsCommonColorProfile.js';
import fractionsCommon from '../../../fractionsCommon.js';

// constants
const EMPTY_BEAKER_COLOR = fractionsCommonColorProfile.emptyBeakerProperty;
const WATER_COLOR = fractionsCommonColorProfile.waterProperty;
const BEAKER_SHINE_COLOR = fractionsCommonColorProfile.beakerShineProperty;

class BeakerNode extends Node {
  /**
   * @param {number} numerator
   * @param {number} denominator
   * @param {Object} [options]
   */
  constructor( numerator, denominator, options ) {
    assert && assert( typeof numerator === 'number' && numerator >= 0 && numerator % 1 === 0 );
    assert && assert( typeof denominator === 'number' && denominator >= 1 && denominator % 1 === 0 );

    options = merge( {
      // {number}
      fullHeight: BeakerNode.DEFAULT_BEAKER_HEIGHT,
      xRadius: 40,
      yRadius: 12,

      // {ColorDef} - If non-null, it will override the given color for the water
      colorOverride: null
    }, options );

    const height = options.fullHeight * numerator / denominator;
    const xRadius = options.xRadius;
    const yRadius = options.yRadius;
    const numTicks = denominator;

    const glassGradient = new LinearGradient( -xRadius, 0, xRadius, 0 )
      .addColorStop( 0, EMPTY_BEAKER_COLOR )
      .addColorStop( 0.666, BEAKER_SHINE_COLOR )
      .addColorStop( 0.782, BEAKER_SHINE_COLOR )
      .addColorStop( 1, EMPTY_BEAKER_COLOR );

    const centerTop = -options.fullHeight / 2;
    const centerBottom = options.fullHeight / 2;
    const centerLiquidY = centerBottom - height;

    const bucketFrontShape = new Shape()
      .ellipticalArc( 0, centerBottom, xRadius, yRadius, 0, 0, Math.PI, false )
      .ellipticalArc( 0, centerTop, xRadius, yRadius, 0, Math.PI, 0, true )
      .close();
    const bucketBackShape = new Shape()
      .ellipticalArc( 0, centerTop, xRadius, yRadius, 0, Math.PI, 0, false )
      .ellipticalArc( 0, centerBottom, xRadius, yRadius, 0, 0, Math.PI, true )
      .close();
    const bucketBottomShape = new Shape()
      .ellipticalArc( 0, centerBottom, xRadius, yRadius, 0, 0, 2 * Math.PI, false );
    const waterTopShape = new Shape()
      .ellipticalArc( 0, centerLiquidY, xRadius, yRadius, 0, 0, Math.PI * 2, false )
      .close();
    const waterSideShape = new Shape()
      .ellipticalArc( 0, centerLiquidY, xRadius, yRadius, 0, Math.PI, 0, true )
      .ellipticalArc( 0, centerBottom, xRadius, yRadius, 0, 0, Math.PI, false )
      .close();

    const ticksShape = new Shape();
    let y = centerBottom;
    for ( let i = 0; i < numTicks - 1; i++ ) {
      y -= options.fullHeight / numTicks;
      const centralAngle = Math.PI * 0.83;
      const offsetAngle = Math.PI * ( i % 2 === 0 ? 0.07 : 0.1 );
      ticksShape.ellipticalArc( 0, y, xRadius, yRadius, 0, centralAngle + offsetAngle, centralAngle - offsetAngle, true ).newSubpath();
    }

    const waterColor = options.colorOverride ? options.colorOverride : WATER_COLOR;

    const bucketFront = new Path( bucketFrontShape, {
      stroke: 'grey',
      fill: glassGradient
    } );
    const bucketBack = new Path( bucketBackShape, {
      stroke: 'grey',
      fill: glassGradient
    } );
    bucketBack.setScaleMagnitude( -1, 1 );
    const bucketBottom = new Path( bucketBottomShape, {
      stroke: 'grey',
      fill: EMPTY_BEAKER_COLOR,
      pickable: false
    } );
    const waterSide = new Path( waterSideShape, {
      stroke: 'black',
      fill: waterColor,
      pickable: false
    } );
    const waterTop = new Path( waterTopShape, {
      fill: waterColor,
      pickable: false
    } );
    const ticks = new Path( ticksShape, {
      stroke: 'black',
      lineWidth: 1.5,
      pickable: false
    } );

    super( {
      children: [
        bucketBack,
        bucketBottom,
        ...( numerator > 0 ? [
          waterSide,
          waterTop
        ] : [] ),
        bucketFront,
        ticks
      ]
    } );

    this.mutate( options );
  }
}

// @public {number} - The normal height of a beaker
BeakerNode.DEFAULT_BEAKER_HEIGHT = 150;

fractionsCommon.register( 'BeakerNode', BeakerNode );
export default BeakerNode;<commit_msg>Rename from simColorProfileProperty to SimColors.js, see https://github.com/phetsims/scenery-phet/issues/686<commit_after>// Copyright 2018-2021, University of Colorado Boulder

/**
 * Displays a beaker graphic
 *
 * @author Jonathan Olson <jonathan.olson@colorado.edu>
 */

import Shape from '../../../../../kite/js/Shape.js';
import merge from '../../../../../phet-core/js/merge.js';
import Node from '../../../../../scenery/js/nodes/Node.js';
import Path from '../../../../../scenery/js/nodes/Path.js';
import LinearGradient from '../../../../../scenery/js/util/LinearGradient.js';
import FractionsCommonColors from '../../../common/view/FractionsCommonColors.js';
import fractionsCommon from '../../../fractionsCommon.js';

// constants
const EMPTY_BEAKER_COLOR = FractionsCommonColors.emptyBeakerProperty;
const WATER_COLOR = FractionsCommonColors.waterProperty;
const BEAKER_SHINE_COLOR = FractionsCommonColors.beakerShineProperty;

class BeakerNode extends Node {
  /**
   * @param {number} numerator
   * @param {number} denominator
   * @param {Object} [options]
   */
  constructor( numerator, denominator, options ) {
    assert && assert( typeof numerator === 'number' && numerator >= 0 && numerator % 1 === 0 );
    assert && assert( typeof denominator === 'number' && denominator >= 1 && denominator % 1 === 0 );

    options = merge( {
      // {number}
      fullHeight: BeakerNode.DEFAULT_BEAKER_HEIGHT,
      xRadius: 40,
      yRadius: 12,

      // {ColorDef} - If non-null, it will override the given color for the water
      colorOverride: null
    }, options );

    const height = options.fullHeight * numerator / denominator;
    const xRadius = options.xRadius;
    const yRadius = options.yRadius;
    const numTicks = denominator;

    const glassGradient = new LinearGradient( -xRadius, 0, xRadius, 0 )
      .addColorStop( 0, EMPTY_BEAKER_COLOR )
      .addColorStop( 0.666, BEAKER_SHINE_COLOR )
      .addColorStop( 0.782, BEAKER_SHINE_COLOR )
      .addColorStop( 1, EMPTY_BEAKER_COLOR );

    const centerTop = -options.fullHeight / 2;
    const centerBottom = options.fullHeight / 2;
    const centerLiquidY = centerBottom - height;

    const bucketFrontShape = new Shape()
      .ellipticalArc( 0, centerBottom, xRadius, yRadius, 0, 0, Math.PI, false )
      .ellipticalArc( 0, centerTop, xRadius, yRadius, 0, Math.PI, 0, true )
      .close();
    const bucketBackShape = new Shape()
      .ellipticalArc( 0, centerTop, xRadius, yRadius, 0, Math.PI, 0, false )
      .ellipticalArc( 0, centerBottom, xRadius, yRadius, 0, 0, Math.PI, true )
      .close();
    const bucketBottomShape = new Shape()
      .ellipticalArc( 0, centerBottom, xRadius, yRadius, 0, 0, 2 * Math.PI, false );
    const waterTopShape = new Shape()
      .ellipticalArc( 0, centerLiquidY, xRadius, yRadius, 0, 0, Math.PI * 2, false )
      .close();
    const waterSideShape = new Shape()
      .ellipticalArc( 0, centerLiquidY, xRadius, yRadius, 0, Math.PI, 0, true )
      .ellipticalArc( 0, centerBottom, xRadius, yRadius, 0, 0, Math.PI, false )
      .close();

    const ticksShape = new Shape();
    let y = centerBottom;
    for ( let i = 0; i < numTicks - 1; i++ ) {
      y -= options.fullHeight / numTicks;
      const centralAngle = Math.PI * 0.83;
      const offsetAngle = Math.PI * ( i % 2 === 0 ? 0.07 : 0.1 );
      ticksShape.ellipticalArc( 0, y, xRadius, yRadius, 0, centralAngle + offsetAngle, centralAngle - offsetAngle, true ).newSubpath();
    }

    const waterColor = options.colorOverride ? options.colorOverride : WATER_COLOR;

    const bucketFront = new Path( bucketFrontShape, {
      stroke: 'grey',
      fill: glassGradient
    } );
    const bucketBack = new Path( bucketBackShape, {
      stroke: 'grey',
      fill: glassGradient
    } );
    bucketBack.setScaleMagnitude( -1, 1 );
    const bucketBottom = new Path( bucketBottomShape, {
      stroke: 'grey',
      fill: EMPTY_BEAKER_COLOR,
      pickable: false
    } );
    const waterSide = new Path( waterSideShape, {
      stroke: 'black',
      fill: waterColor,
      pickable: false
    } );
    const waterTop = new Path( waterTopShape, {
      fill: waterColor,
      pickable: false
    } );
    const ticks = new Path( ticksShape, {
      stroke: 'black',
      lineWidth: 1.5,
      pickable: false
    } );

    super( {
      children: [
        bucketBack,
        bucketBottom,
        ...( numerator > 0 ? [
          waterSide,
          waterTop
        ] : [] ),
        bucketFront,
        ticks
      ]
    } );

    this.mutate( options );
  }
}

// @public {number} - The normal height of a beaker
BeakerNode.DEFAULT_BEAKER_HEIGHT = 150;

fractionsCommon.register( 'BeakerNode', BeakerNode );
export default BeakerNode;<|endoftext|>


<commit_before>/*
 * grunt-yaml-to-swagger
 *
 *
 * Copyright (c) 2014 Cyril GIACOPINO
 * Licensed under the MIT license.
 */

'use strict';

module.exports = function (grunt) {

    // Please see the Grunt documentation for more information regarding task
    // creation: http://gruntjs.com/creating-tasks
    Array.prototype.getUnique = function () {
        var u = {}, a = [];
        for (var i = 0, l = this.length; i < l; ++i) {
            if (u.hasOwnProperty(this[i])) {
                continue;
            }
            a.push(this[i]);
            u[this[i]] = 1;
        }
        return a;
    }

    var primitives = [
        "array",
        "boolean",
        "integer",
        "number",
        "null",
        "object",
        "string"
    ];

    function contains(a, obj) {
        var i = a.length;
        while (i--) {
            if (a[i] === obj) {
                return true;
            }
        }
        return false;
    }

    function extend(target) {
        var sources = [].slice.call(arguments, 1);
        sources.forEach(function (source) {
            for (var prop in source) {
                target[prop] = source[prop];
            }
        });
        return target;
    }

    function isEmpty(obj) {
        for (var prop in obj) {
            if (obj.hasOwnProperty(prop))
                return false;
        }

        return true;
    }

    function execSync(cmd, args, callback) {
        var options = {
            // The command to execute. It should be in the system path.
            cmd: cmd,
            args: args
        };
        grunt.util.spawn(options, callback)
    }

    function parseFiles(files, options, callback) {
        var fs = require('fs');
        var path = require('path').resolve(options.route_path + '/');
        var working = false;
        var interval = setInterval(function () {
            if (files.length > 0) {
                if (working == false) {
                    working = true;
                    var file = files[0];
                    var file_path = require('path').resolve(path + '/' + file);
                    try {
                        var route_definitions = require('yamljs').load(file_path);
                    } catch (e) {
                        console.log("error");
                        grunt.fatal(e.message);
                    }

                    var base_filename = file.split(".yml")[0];
                    var outputFilename = options.output_docs_path + "/" + base_filename + ".json";

                    var returnData = {};
                    //console.log(JSON.stringify(route_definitions));
                    var models = [];
                    for (var j = 0; j < route_definitions.apis.length; j++) {
                        var operations = route_definitions.apis[j].operations;
                        for (var i = 0; i < operations.length; i++) {
                            if (!contains(primitives, operations[i].type)) {
                                models.push(operations[i].type);
                            }

                        }
                    }
                    models = models.getUnique();
                    parseModels(models, options, function (data) {
                        route_definitions.models = data;
                        var pretty_route_definitions = JSON.stringify(route_definitions, undefined, 2);
                        fs.writeFileSync(outputFilename, pretty_route_definitions);
                        grunt.log.ok(base_filename + ".json created");
                        files.splice(0, 1);
                        working = false;
                    });

                }
            } else {
                clearInterval(interval);
            }
        }, 100);
    }

    function parseModels(models, options, callback) {
        var fs = require('fs');
        var returnData = {};
        var working = false;
        var interval = setInterval(function () {
            if (models.length > 0) {
                if (working == false) {
                    working = true;
                    var args = ['schema', require("path").resolve(options.models_path + '/' + models[0] + '.ts')];
                    execSync('typson', args, function (error, result, code) {
                        if (error == null) {
                            var pretty_schema = JSON.stringify(JSON.parse(result), undefined, 2);
                            fs.writeFileSync(options.models_path + 'schema/' + models[0] + '.json', pretty_schema);
                            returnData = extend(returnData, JSON.parse(result));
                            models.splice(0, 1);
                            working = false;
                        } else {
                            grunt.log.error('typson ' + args.join(" "));
                            grunt.fatal(error);
                        }

                    });

                }
            } else {
                clearInterval(interval);
                callback(returnData);
            }
        }, 100);

    }

    grunt.registerMultiTask('yaml_to_swagger', 'Convert YAML files into swagger compatible JSON Schema format', function () {

        var fs = require('fs');
        var options = this.options();

        var done = this.async();

        var path_api = require('path').resolve(options.route_path + '/api.yml');
        var api_definitions = require('yamljs').load(path_api);
        var files = [];
        for (var i = 0; i < api_definitions.apis.length; i++) {
            var path = api_definitions.apis[i].path.split("/").join("");
            files.push(api_definitions.apis[i].path + '.yml');
        }
        var outputFilename = options.output_docs_path + "/api.json";
        var pretty_route_definitions = JSON.stringify(api_definitions, undefined, 2);
        fs.writeFileSync(outputFilename, pretty_route_definitions);
        grunt.log.ok("api.json created");
        parseFiles(files, options, function () {
            done();
        });
    });

};
<commit_msg>Replace mocktype in documentation<commit_after>/*
 * grunt-yaml-to-swagger
 *
 *
 * Copyright (c) 2014 Cyril GIACOPINO
 * Licensed under the MIT license.
 */

'use strict';

module.exports = function (grunt) {

    // Please see the Grunt documentation for more information regarding task
    // creation: http://gruntjs.com/creating-tasks
    Array.prototype.getUnique = function () {
        var u = {}, a = [];
        for (var i = 0, l = this.length; i < l; ++i) {
            if (u.hasOwnProperty(this[i])) {
                continue;
            }
            a.push(this[i]);
            u[this[i]] = 1;
        }
        return a;
    }

    var primitives = [
        "array",
        "boolean",
        "integer",
        "number",
        "null",
        "object",
        "string"
    ];

    function contains(a, obj) {
        var i = a.length;
        while (i--) {
            if (a[i] === obj) {
                return true;
            }
        }
        return false;
    }

    function extend(target) {
        var sources = [].slice.call(arguments, 1);
        sources.forEach(function (source) {
            for (var prop in source) {
                target[prop] = source[prop];
            }
        });
        return target;
    }

    function isEmpty(obj) {
        for (var prop in obj) {
            if (obj.hasOwnProperty(prop))
                return false;
        }

        return true;
    }

    function execSync(cmd, args, callback) {
        var options = {
            // The command to execute. It should be in the system path.
            cmd: cmd,
            args: args
        };
        grunt.util.spawn(options, callback)
    }

    function parseFiles(files, options, callback) {
        var fs = require('fs');
        var path = require('path').resolve(options.route_path + '/');
        var working = false;
        var interval = setInterval(function () {
            if (files.length > 0) {
                if (working == false) {
                    working = true;
                    var file = files[0];
                    var file_path = require('path').resolve(path + '/' + file);
                    try {
                        var route_definitions = require('yamljs').load(file_path);
                    } catch (e) {
                        console.log("error");
                        grunt.fatal(e.message);
                    }

                    var base_filename = file.split(".yml")[0];
                    var outputFilename = options.output_docs_path + "/" + base_filename + ".json";

                    var returnData = {};
                    //console.log(JSON.stringify(route_definitions));
                    var models = [];
                    for (var j = 0; j < route_definitions.apis.length; j++) {
                        var operations = route_definitions.apis[j].operations;
                        for (var i = 0; i < operations.length; i++) {
                            if (!contains(primitives, operations[i].type)) {
                                models.push(operations[i].type);
                            }

                        }
                    }
                    models = models.getUnique();
                    parseModels(models, options, function (data) {
                        route_definitions.models = data;
                        var pretty_route_definitions = JSON.stringify(route_definitions, undefined, 2);
                        fs.writeFileSync(outputFilename, pretty_route_definitions);
                        grunt.log.ok(base_filename + ".json created");
                        files.splice(0, 1);
                        working = false;
                    });

                }
            } else {
                clearInterval(interval);
            }
        }, 100);
    }

    function parseModels(models, options, callback) {
        var fs = require('fs');
        var returnData = {};
        var working = false;
        var interval = setInterval(function () {
            if (models.length > 0) {
                if (working == false) {
                    working = true;
                    var args = ['schema', require("path").resolve(options.models_path + '/' + models[0] + '.ts')];
                    execSync('typson', args, function (error, result, code) {
                        if (error == null) {
                            var pretty_schema = JSON.stringify(JSON.parse(result), undefined, 2);
                            fs.writeFileSync(options.models_path + 'schema/' + models[0] + '.json', pretty_schema);

                            var result = JSON.stringify(JSON.parse(result));
                            var pattern = new RegExp('\[MockType=(\w)+\]', "g");
                            var matches = result.match(/\[MockType=(\w)+\]/g);
                            if (matches.length > 0) {
                                for(var replace=0;replace<matches.length;replace++)
                                {
                                    result = result.split(matches[replace]).join("");
                                }
                            }
                            returnData = extend(returnData, JSON.parse(result));
                            models.splice(0, 1);
                            working = false;
                        } else {
                            grunt.log.error('typson ' + args.join(" "));
                            grunt.fatal(error);
                        }

                    });

                }
            } else {
                clearInterval(interval);
                callback(returnData);
            }
        }, 100);

    }

    grunt.registerMultiTask('yaml_to_swagger', 'Convert YAML files into swagger compatible JSON Schema format', function () {

        var fs = require('fs');
        var options = this.options();

        var done = this.async();

        var path_api = require('path').resolve(options.route_path + '/api.yml');
        var api_definitions = require('yamljs').load(path_api);
        var files = [];
        for (var i = 0; i < api_definitions.apis.length; i++) {
            var path = api_definitions.apis[i].path.split("/").join("");
            files.push(api_definitions.apis[i].path + '.yml');
        }
        var outputFilename = options.output_docs_path + "/api.json";
        var pretty_route_definitions = JSON.stringify(api_definitions, undefined, 2);
        fs.writeFileSync(outputFilename, pretty_route_definitions);
        grunt.log.ok("/api.json created");
        parseFiles(files, options, function () {
            done();
        });
    });

};
<|endoftext|>


<commit_before>import _ from 'lodash';
import cuid from 'cuid';

export const normalizeStripAds = (ad, baseURL = '') => ({
  name: ad.name || '',
  type: ad.type || '',
  src: `${baseURL}${ad.path || ''}`,
  duration: Number(ad.timeout || 0) / 1000,
  adSize: ad.adSize || '',
});
// const isSoldout = () => _.random(1, 5) === 5;
const isSoldout = (qty) => qty === 0;
const randomQty = () => _.random(0, 5);
/*
product: {
  Po_ID: 'PO0001',
  Po_Name: {
    th: 'แบรนด์ Gen U',
    en: 'แบรนด์ Gen U',
  },
  Po_Price: '45',
  Po_Img: 'images/product-20170819110019.png',
  Po_Imgbig: 'images/product-bg-20170819110019.png',
  Row: '1',
  Column: '1',
},
*/
export const convertToAppProduct = (product, baseURL = '') => {
  const ads = _.isArray(product.Po_ImgAd || '')
  ? product.Po_ImgAd || ''
  : [{ Ad_Url: product.Po_ImgAd || '', Ad_Second: '5' }];
  return {
    cuid: cuid(),
    id: product.Po_ID || '',
    name: product.Po_Name || '',
    price: Number(product.Po_Price || ''),
    isSoldout: isSoldout(product.Po_Qty || randomQty()),
    image: product.Po_Img || '',
    imageBig: product.Po_Imgbig || '',
    row: product.Row || '',
    col: product.Column || '',
    isDropped: false,
    ads: _.map(ads, ad => normalizeStripAds(convertToAppAd(ad), baseURL)),
  };
};

export const convertToAppPromotion = (promotion, baseURL) => {
  const ads = _.isArray(promotion.Pro_ImgAd)
  ? promotion.Pro_ImgAd
  : [{ Ad_Url: promotion.Pro_ImgAd, Ad_Second: '5' }];
  const products = _.map(promotion.Product_List || [], (product) => convertToAppProduct(product));
  return {
    cuid: cuid(),
    id: promotion.Pro_ID,
    products,
    price: _.sumBy(products, product => Number(product.price)) - Number(promotion.Discount_Price),
    image: '',
    ads: _.map(ads, ad => normalizeStripAds(convertToAppAd(ad), baseURL)),
  };
};

/*
{
  "Topup_ID": "1",
  "Topup_Name": {
      "th": "เอไอเอส",
      "en": "เอไอเอส"
  },
  "Topup_ServiceCode": "1001",
  "Topup_Img": "/uploads/images/topup-20170418141424.png",
  "Topup_Imgbig": "/uploads/images/topup-bg-20170819134443.png"
},
*/
export const convertToAppMobileTopupProvider = (mobileTopupProvider, baseURL) => {
  const ads = _.isArray(mobileTopupProvider.Topup_ImgAd)
  ? mobileTopupProvider.Topup_ImgAd
  : [{ Ad_Url: mobileTopupProvider.Topup_ImgAd, Ad_Second: '5' }];
  return {
    cuid: cuid(),
    id: mobileTopupProvider.Topup_ID,
    banner: mobileTopupProvider.Topup_Imgbig,
    src: mobileTopupProvider.Topup_Img,
    serviceCode: mobileTopupProvider.Topup_ServiceCode,
    name: mobileTopupProvider.Topup_Name.en,
    names: mobileTopupProvider.Topup_Name,
    ads: _.map(ads, ad => normalizeStripAds(convertToAppAd(ad), baseURL)),
  };
};

/*
{
  "status": "SUCCESSFUL",
  "trx-id": "20171109194928",
  "response-data": [
      {
          "Ad_ID": "AD002",
          "Ad_Type": "V",
          "Ad_Point": 50,
          "Ad_Second": 15,
          "Ad_Display": "F",
          "Ad_Url": "/uploads/banner/advertise-20170412095354.mp4"
      }
  ]
}
*/
export const convertToAppAd = (ad) => {
  const isVideo = (ad.Ad_Url || '').indexOf('.mp4') >= 0;
  return {
    id: ad.Ad_ID || cuid(),
    type: ad.Ad_Type || '' === 'V' || isVideo ? 'video' : 'image',
    name: ad.Ad_ID || '',
    path: ad.Ad_Url || '',
    filename: ad.Ad_ID || '',
    expire: '', // '2026-11-21',
    timeout: Number(ad.Ad_Second) * 1000,
    checksum: '', // '47e93aec13f7c9115ebbcfaacb309ccd',
    adSize: 'STRIP', // ad.Ad_Display === 'F' ? 'FULLSCREEN' : 'STRIP',
  };
  // return {
  //   cuid: cuid(),
  //   id: product.Po_ID || '',
  //   name: product.Po_Name || '',
  //   price: product.Po_Price || '',
  //   isSoldout: isSoldout() || true,
  //   image: product.Po_Img || '',
  //   imageBig: product.Po_Imgbig || '',
  //   row: product.Row || '',
  //   col: product.Column || '',
  //   isDropped: false,
  // };
};

export const convertToAppEvent = (event, baseURL) => {
  console.log('convertToAppEvent', event);
  const eventInputActivities = _.filter(event.eventActivities || [], activity => activity.type === 'input');
  const eventWatchActivities = _.filter(event.eventActivities || [], activity => activity.type === 'watch');
  const ads = [];
  // _.isArray(mobileTopupProvider.Topup_ImgAd)
  // ? mobileTopupProvider.Topup_ImgAd
  // : [{ Ad_Url: mobileTopupProvider.Topup_ImgAd, Ad_Second: '5' }];
  return {
    eventId: event.id,
    tag: _.head(event.tags),
    product: convertToAppProduct(_.get(event, 'products.0', _.get(event, 'product', {}))),
    howTo: _.map(event.howTo, (instruction) => instruction),
    inputs: _.map(eventInputActivities || [], (eventInputActivity) => {
      return {
        ...eventInputActivity,
        completed: false
      };
    }),
    watches: _.map(eventWatchActivities, (eventWatchActivity) => {
      return {
        ...eventWatchActivity,
        completed: false
      };
    }),
    rewards: _.map(event.rewards || [], (reward) => {
      return {
        ...reward,
        completed: false
      };
    }),
    remarks: _.map(event.remarks || [], (remark) => {
      return {
        ...remark,
        completed: false
      };
    }),
    ads,
  };
};
<commit_msg>Handle key error in activities product<commit_after>import _ from 'lodash';
import cuid from 'cuid';

export const normalizeStripAds = (ad, baseURL = '') => ({
  name: ad.name || '',
  type: ad.type || '',
  src: `${baseURL}${ad.path || ''}`,
  duration: Number(ad.timeout || 0) / 1000,
  adSize: ad.adSize || '',
});
// const isSoldout = () => _.random(1, 5) === 5;
const isSoldout = (qty) => qty === 0;
const randomQty = () => _.random(0, 5);
/*
product: {
  Po_ID: 'PO0001',
  Po_Name: {
    th: 'แบรนด์ Gen U',
    en: 'แบรนด์ Gen U',
  },
  Po_Price: '45',
  Po_Img: 'images/product-20170819110019.png',
  Po_Imgbig: 'images/product-bg-20170819110019.png',
  Row: '1',
  Column: '1',
},
*/
export const convertToAppProduct = (product, baseURL = '') => {
  const ads = _.isArray(product.Po_ImgAd || '')
  ? product.Po_ImgAd || ''
  : [{ Ad_Url: product.Po_ImgAd || '', Ad_Second: '5' }];
  return {
    cuid: cuid(),
    id: product.Po_ID || '',
    name: product.Po_Name || '',
    price: Number(product.Po_Price || ''),
    isSoldout: isSoldout(product.Po_Qty || randomQty()),
    image: product.Po_Img || '',
    imageBig: product.Po_Imgbig || '',
    row: product.Row || '',
    col: product.Column || '',
    isDropped: false,
    ads: _.map(ads, ad => normalizeStripAds(convertToAppAd(ad), baseURL)),
  };
};

export const convertToAppPromotion = (promotion, baseURL) => {
  const ads = _.isArray(promotion.Pro_ImgAd)
  ? promotion.Pro_ImgAd
  : [{ Ad_Url: promotion.Pro_ImgAd, Ad_Second: '5' }];
  const products = _.map(promotion.Product_List || [], (product) => convertToAppProduct(product));
  return {
    cuid: cuid(),
    id: promotion.Pro_ID,
    products,
    price: _.sumBy(products, product => Number(product.price)) - Number(promotion.Discount_Price),
    image: '',
    ads: _.map(ads, ad => normalizeStripAds(convertToAppAd(ad), baseURL)),
  };
};

/*
{
  "Topup_ID": "1",
  "Topup_Name": {
      "th": "เอไอเอส",
      "en": "เอไอเอส"
  },
  "Topup_ServiceCode": "1001",
  "Topup_Img": "/uploads/images/topup-20170418141424.png",
  "Topup_Imgbig": "/uploads/images/topup-bg-20170819134443.png"
},
*/
export const convertToAppMobileTopupProvider = (mobileTopupProvider, baseURL) => {
  const ads = _.isArray(mobileTopupProvider.Topup_ImgAd)
  ? mobileTopupProvider.Topup_ImgAd
  : [{ Ad_Url: mobileTopupProvider.Topup_ImgAd, Ad_Second: '5' }];
  return {
    cuid: cuid(),
    id: mobileTopupProvider.Topup_ID,
    banner: mobileTopupProvider.Topup_Imgbig,
    src: mobileTopupProvider.Topup_Img,
    serviceCode: mobileTopupProvider.Topup_ServiceCode,
    name: mobileTopupProvider.Topup_Name.en,
    names: mobileTopupProvider.Topup_Name,
    ads: _.map(ads, ad => normalizeStripAds(convertToAppAd(ad), baseURL)),
  };
};

/*
{
  "status": "SUCCESSFUL",
  "trx-id": "20171109194928",
  "response-data": [
      {
          "Ad_ID": "AD002",
          "Ad_Type": "V",
          "Ad_Point": 50,
          "Ad_Second": 15,
          "Ad_Display": "F",
          "Ad_Url": "/uploads/banner/advertise-20170412095354.mp4"
      }
  ]
}
*/
export const convertToAppAd = (ad) => {
  const isVideo = (ad.Ad_Url || '').indexOf('.mp4') >= 0;
  return {
    id: ad.Ad_ID || cuid(),
    type: ad.Ad_Type || '' === 'V' || isVideo ? 'video' : 'image',
    name: ad.Ad_ID || '',
    path: ad.Ad_Url || '',
    filename: ad.Ad_ID || '',
    expire: '', // '2026-11-21',
    timeout: Number(ad.Ad_Second) * 1000,
    checksum: '', // '47e93aec13f7c9115ebbcfaacb309ccd',
    adSize: 'STRIP', // ad.Ad_Display === 'F' ? 'FULLSCREEN' : 'STRIP',
  };
  // return {
  //   cuid: cuid(),
  //   id: product.Po_ID || '',
  //   name: product.Po_Name || '',
  //   price: product.Po_Price || '',
  //   isSoldout: isSoldout() || true,
  //   image: product.Po_Img || '',
  //   imageBig: product.Po_Imgbig || '',
  //   row: product.Row || '',
  //   col: product.Column || '',
  //   isDropped: false,
  // };
};

export const convertToAppEvent = (event, baseURL) => {
  console.log('convertToAppEvent', event);
  const eventInputActivities = _.filter(event.eventActivities || [], activity => activity.type === 'input');
  const eventWatchActivities = _.filter(event.eventActivities || [], activity => activity.type === 'watch');
  const ads = [];
  // _.isArray(mobileTopupProvider.Topup_ImgAd)
  // ? mobileTopupProvider.Topup_ImgAd
  // : [{ Ad_Url: mobileTopupProvider.Topup_ImgAd, Ad_Second: '5' }];
  return {
    eventId: event.id,
    tag: _.head(event.tags),
    product: convertToAppProduct(_.get(event, 'products.0', _.get(event, 'product.0', {}), _.get(event, 'product', {}))),
    howTo: _.map(event.howTo, (instruction) => instruction),
    inputs: _.map(eventInputActivities || [], (eventInputActivity) => {
      return {
        ...eventInputActivity,
        completed: false
      };
    }),
    watches: _.map(eventWatchActivities, (eventWatchActivity) => {
      return {
        ...eventWatchActivity,
        completed: false
      };
    }),
    rewards: _.map(event.rewards || [], (reward) => {
      return {
        ...reward,
        completed: false
      };
    }),
    remarks: _.map(event.remarks || [], (remark) => {
      return {
        ...remark,
        completed: false
      };
    }),
    ads,
  };
};
<|endoftext|>


<commit_before>// Copyright 2018-2021, University of Colorado Boulder

/**
 * Displays a beaker graphic
 *
 * @author Jonathan Olson <jonathan.olson@colorado.edu>
 */

import Shape from '../../../../../kite/js/Shape.js';
import merge from '../../../../../phet-core/js/merge.js';
import { Node } from '../../../../../scenery/js/imports.js';
import { Path } from '../../../../../scenery/js/imports.js';
import { LinearGradient } from '../../../../../scenery/js/imports.js';
import FractionsCommonColors from '../../../common/view/FractionsCommonColors.js';
import fractionsCommon from '../../../fractionsCommon.js';

// constants
const EMPTY_BEAKER_COLOR = FractionsCommonColors.emptyBeakerProperty;
const WATER_COLOR = FractionsCommonColors.waterProperty;
const BEAKER_SHINE_COLOR = FractionsCommonColors.beakerShineProperty;

class BeakerNode extends Node {
  /**
   * @param {number} numerator
   * @param {number} denominator
   * @param {Object} [options]
   */
  constructor( numerator, denominator, options ) {
    assert && assert( typeof numerator === 'number' && numerator >= 0 && numerator % 1 === 0 );
    assert && assert( typeof denominator === 'number' && denominator >= 1 && denominator % 1 === 0 );

    options = merge( {
      // {number}
      fullHeight: BeakerNode.DEFAULT_BEAKER_HEIGHT,
      xRadius: 40,
      yRadius: 12,

      // {ColorDef} - If non-null, it will override the given color for the water
      colorOverride: null
    }, options );

    const height = options.fullHeight * numerator / denominator;
    const xRadius = options.xRadius;
    const yRadius = options.yRadius;
    const numTicks = denominator;

    const glassGradient = new LinearGradient( -xRadius, 0, xRadius, 0 )
      .addColorStop( 0, EMPTY_BEAKER_COLOR )
      .addColorStop( 0.666, BEAKER_SHINE_COLOR )
      .addColorStop( 0.782, BEAKER_SHINE_COLOR )
      .addColorStop( 1, EMPTY_BEAKER_COLOR );

    const centerTop = -options.fullHeight / 2;
    const centerBottom = options.fullHeight / 2;
    const centerLiquidY = centerBottom - height;

    const bucketFrontShape = new Shape()
      .ellipticalArc( 0, centerBottom, xRadius, yRadius, 0, 0, Math.PI, false )
      .ellipticalArc( 0, centerTop, xRadius, yRadius, 0, Math.PI, 0, true )
      .close();
    const bucketBackShape = new Shape()
      .ellipticalArc( 0, centerTop, xRadius, yRadius, 0, Math.PI, 0, false )
      .ellipticalArc( 0, centerBottom, xRadius, yRadius, 0, 0, Math.PI, true )
      .close();
    const bucketBottomShape = new Shape()
      .ellipticalArc( 0, centerBottom, xRadius, yRadius, 0, 0, 2 * Math.PI, false );
    const waterTopShape = new Shape()
      .ellipticalArc( 0, centerLiquidY, xRadius, yRadius, 0, 0, Math.PI * 2, false )
      .close();
    const waterSideShape = new Shape()
      .ellipticalArc( 0, centerLiquidY, xRadius, yRadius, 0, Math.PI, 0, true )
      .ellipticalArc( 0, centerBottom, xRadius, yRadius, 0, 0, Math.PI, false )
      .close();

    const ticksShape = new Shape();
    let y = centerBottom;
    for ( let i = 0; i < numTicks - 1; i++ ) {
      y -= options.fullHeight / numTicks;
      const centralAngle = Math.PI * 0.83;
      const offsetAngle = Math.PI * ( i % 2 === 0 ? 0.07 : 0.1 );
      ticksShape.ellipticalArc( 0, y, xRadius, yRadius, 0, centralAngle + offsetAngle, centralAngle - offsetAngle, true ).newSubpath();
    }

    const waterColor = options.colorOverride ? options.colorOverride : WATER_COLOR;

    const bucketFront = new Path( bucketFrontShape, {
      stroke: 'grey',
      fill: glassGradient
    } );
    const bucketBack = new Path( bucketBackShape, {
      stroke: 'grey',
      fill: glassGradient
    } );
    bucketBack.setScaleMagnitude( -1, 1 );
    const bucketBottom = new Path( bucketBottomShape, {
      stroke: 'grey',
      fill: EMPTY_BEAKER_COLOR,
      pickable: false
    } );
    const waterSide = new Path( waterSideShape, {
      stroke: 'black',
      fill: waterColor,
      pickable: false
    } );
    const waterTop = new Path( waterTopShape, {
      fill: waterColor,
      pickable: false
    } );
    const ticks = new Path( ticksShape, {
      stroke: 'black',
      lineWidth: 1.5,
      pickable: false
    } );

    super( {
      children: [
        bucketBack,
        bucketBottom,
        ...( numerator > 0 ? [
          waterSide,
          waterTop
        ] : [] ),
        bucketFront,
        ticks
      ]
    } );

    this.mutate( options );
  }
}

// @public {number} - The normal height of a beaker
BeakerNode.DEFAULT_BEAKER_HEIGHT = 150;

fractionsCommon.register( 'BeakerNode', BeakerNode );
export default BeakerNode;<commit_msg>import kite files from imports.ts, https://github.com/phetsims/kite/issues/96<commit_after>// Copyright 2018-2021, University of Colorado Boulder

/**
 * Displays a beaker graphic
 *
 * @author Jonathan Olson <jonathan.olson@colorado.edu>
 */

import { Shape } from '../../../../../kite/js/imports.js';
import merge from '../../../../../phet-core/js/merge.js';
import { Node } from '../../../../../scenery/js/imports.js';
import { Path } from '../../../../../scenery/js/imports.js';
import { LinearGradient } from '../../../../../scenery/js/imports.js';
import FractionsCommonColors from '../../../common/view/FractionsCommonColors.js';
import fractionsCommon from '../../../fractionsCommon.js';

// constants
const EMPTY_BEAKER_COLOR = FractionsCommonColors.emptyBeakerProperty;
const WATER_COLOR = FractionsCommonColors.waterProperty;
const BEAKER_SHINE_COLOR = FractionsCommonColors.beakerShineProperty;

class BeakerNode extends Node {
  /**
   * @param {number} numerator
   * @param {number} denominator
   * @param {Object} [options]
   */
  constructor( numerator, denominator, options ) {
    assert && assert( typeof numerator === 'number' && numerator >= 0 && numerator % 1 === 0 );
    assert && assert( typeof denominator === 'number' && denominator >= 1 && denominator % 1 === 0 );

    options = merge( {
      // {number}
      fullHeight: BeakerNode.DEFAULT_BEAKER_HEIGHT,
      xRadius: 40,
      yRadius: 12,

      // {ColorDef} - If non-null, it will override the given color for the water
      colorOverride: null
    }, options );

    const height = options.fullHeight * numerator / denominator;
    const xRadius = options.xRadius;
    const yRadius = options.yRadius;
    const numTicks = denominator;

    const glassGradient = new LinearGradient( -xRadius, 0, xRadius, 0 )
      .addColorStop( 0, EMPTY_BEAKER_COLOR )
      .addColorStop( 0.666, BEAKER_SHINE_COLOR )
      .addColorStop( 0.782, BEAKER_SHINE_COLOR )
      .addColorStop( 1, EMPTY_BEAKER_COLOR );

    const centerTop = -options.fullHeight / 2;
    const centerBottom = options.fullHeight / 2;
    const centerLiquidY = centerBottom - height;

    const bucketFrontShape = new Shape()
      .ellipticalArc( 0, centerBottom, xRadius, yRadius, 0, 0, Math.PI, false )
      .ellipticalArc( 0, centerTop, xRadius, yRadius, 0, Math.PI, 0, true )
      .close();
    const bucketBackShape = new Shape()
      .ellipticalArc( 0, centerTop, xRadius, yRadius, 0, Math.PI, 0, false )
      .ellipticalArc( 0, centerBottom, xRadius, yRadius, 0, 0, Math.PI, true )
      .close();
    const bucketBottomShape = new Shape()
      .ellipticalArc( 0, centerBottom, xRadius, yRadius, 0, 0, 2 * Math.PI, false );
    const waterTopShape = new Shape()
      .ellipticalArc( 0, centerLiquidY, xRadius, yRadius, 0, 0, Math.PI * 2, false )
      .close();
    const waterSideShape = new Shape()
      .ellipticalArc( 0, centerLiquidY, xRadius, yRadius, 0, Math.PI, 0, true )
      .ellipticalArc( 0, centerBottom, xRadius, yRadius, 0, 0, Math.PI, false )
      .close();

    const ticksShape = new Shape();
    let y = centerBottom;
    for ( let i = 0; i < numTicks - 1; i++ ) {
      y -= options.fullHeight / numTicks;
      const centralAngle = Math.PI * 0.83;
      const offsetAngle = Math.PI * ( i % 2 === 0 ? 0.07 : 0.1 );
      ticksShape.ellipticalArc( 0, y, xRadius, yRadius, 0, centralAngle + offsetAngle, centralAngle - offsetAngle, true ).newSubpath();
    }

    const waterColor = options.colorOverride ? options.colorOverride : WATER_COLOR;

    const bucketFront = new Path( bucketFrontShape, {
      stroke: 'grey',
      fill: glassGradient
    } );
    const bucketBack = new Path( bucketBackShape, {
      stroke: 'grey',
      fill: glassGradient
    } );
    bucketBack.setScaleMagnitude( -1, 1 );
    const bucketBottom = new Path( bucketBottomShape, {
      stroke: 'grey',
      fill: EMPTY_BEAKER_COLOR,
      pickable: false
    } );
    const waterSide = new Path( waterSideShape, {
      stroke: 'black',
      fill: waterColor,
      pickable: false
    } );
    const waterTop = new Path( waterTopShape, {
      fill: waterColor,
      pickable: false
    } );
    const ticks = new Path( ticksShape, {
      stroke: 'black',
      lineWidth: 1.5,
      pickable: false
    } );

    super( {
      children: [
        bucketBack,
        bucketBottom,
        ...( numerator > 0 ? [
          waterSide,
          waterTop
        ] : [] ),
        bucketFront,
        ticks
      ]
    } );

    this.mutate( options );
  }
}

// @public {number} - The normal height of a beaker
BeakerNode.DEFAULT_BEAKER_HEIGHT = 150;

fractionsCommon.register( 'BeakerNode', BeakerNode );
export default BeakerNode;<|endoftext|>


<commit_before>module.exports = {
  verifyConditions: ['condition-circle'],
  plugins: [
    '@semantic-release/commit-analyzer',
    '@semantic-release/release-notes-generator',
    [
      '@semantic-release/exec',
      {prepareCmd: 'VERSION=${nextRelease.version} npm run build'},
    ],
    ['@semantic-release/exec', {publishCmd: 'shipit chrome dist'}],
    [
      '@semantic-release/exec',
      {
        publishCmd: [
          'web-ext',
          'sign',
          '--source-dir',
          'dist',
          '--api-key',
          process.env.WEXT_SHIPIT_FIREFOX_JWT_ISSUER,
          '--api-secret',
          process.env.WEXT_SHIPIT_FIREFOX_JWT_SECRET,
        ].join(' '),
      },
    ],
    ['@semantic-release/github'],
  ],
};
<commit_msg>fix: add explicit firefox extension id<commit_after>module.exports = {
  verifyConditions: ['condition-circle'],
  plugins: [
    '@semantic-release/commit-analyzer',
    '@semantic-release/release-notes-generator',
    [
      '@semantic-release/exec',
      {prepareCmd: 'VERSION=${nextRelease.version} npm run build'},
    ],
    ['@semantic-release/exec', {publishCmd: 'shipit chrome dist'}],
    [
      '@semantic-release/exec',
      {
        publishCmd: [
          'web-ext',
          'sign',
          '--source-dir',
          'dist',
          '--api-key',
          process.env.WEXT_SHIPIT_FIREFOX_JWT_ISSUER,
          '--api-secret',
          process.env.WEXT_SHIPIT_FIREFOX_JWT_SECRET,
          '--id',
          process.env.WEXT_SHIPIT_FIREFOX_ID,
        ].join(' '),
      },
    ],
    ['@semantic-release/github'],
  ],
};
<|endoftext|>


<commit_before>// Initialise column show/hide control
;var qcode = qcode || {};
qcode.columnsShowHideControl = function(targets) {
    "use strict";
    return qcode.each(targets, target => {
        const checkbox = target.querySelector('[type=checkbox]');
        const tableSelector = getData(checkbox, 'table_selector');
        const colSelector = getData(checkbox, 'col_selector');
        const tables = document.querySelectorAll(tableSelector);
        const sticky = parseBoolean(getData(checkbox,'sticky'));
        const stickyUrl = getData(checkbox,'sticky_url');

        target.addEventListener('click', onClick);
        checkbox.addEventListener('change', onCheckBoxChange);
        target.addEventListener('mouseenter', onMouseEnter);
        target.addEventListener('mouseleave', onMouseLeave);
        update();

        function update() {
            if ( checkbox.checked ) {
                target.classList.add('checked');
                qcode.columnsShowHide(tables, colSelector, 'show');
            } else {
                target.classList.remove('checked');
                qcode.columnsShowHide(tables, colSelector, 'hide');
            }
        }

        function onClick(event) {
            if ( event.target == checkbox || event.target.matches('label') ) {
                return
            }
            event.preventDefault();
            checkbox.checked = ! checkbox.checked;
            checkbox.dispatchEvent(
                new Event('change', {
                    "bubbles": true,
                    "composed": true
                })
            );
        }

        function onCheckBoxChange(event) {
            update()
            if ( ! sticky ) {
                return
            }
            const data = {}
            data[checkbox.getAttribute('name')] = checkbox.checked;
            if ( stickyURL ) {
                data['sticky_url'] = stickyURL;
            }
            httpPost('/sticky_save.html',
                     data,
                     function(){},
                     function(){});
        }

        function onMouseEnter(event) {
            target.classList.add('hover');
            const cols = Array.from(table.querySelectorAll(colSelector));
            for ( const col of cols ) {
                col.classList.add('highlight');
            }
        }

        function onMouseLeave(event) {
            target.classList.remove('hover');
            const cols = Array.from(table.querySelectorAll(colSelector));
            for ( const col of cols ) {
                col.classList.add('highlight');
            }
        }
    });

    function getData(element, key) {
        if ( element.hasAttribute(key) ) {
            return element.getAttribute(key);
        }
        key = qcode.underscore2camelCase(key);
        if ( element.dataset[key] !== undefined ) {
            return element.dataset[key];
        }
        return ""
    }
};
<commit_msg>columnsShowHideControl bugfixes<commit_after>// Initialise column show/hide control
;var qcode = qcode || {};
qcode.columnsShowHideControl = function(targets) {
    "use strict";
    return qcode.each(targets, target => {
        const checkbox = target.querySelector('[type=checkbox]');
        const tableSelector = getData(checkbox, 'table_selector');
        const colSelector = getData(checkbox, 'col_selector');
        const tables = document.querySelectorAll(tableSelector);
        const sticky = parseBoolean(getData(checkbox,'sticky'));
        const stickyUrl = getData(checkbox,'sticky_url');

        target.addEventListener('click', onClick);
        checkbox.addEventListener('change', onCheckBoxChange);
        target.addEventListener('mouseenter', onMouseEnter);
        target.addEventListener('mouseleave', onMouseLeave);
        update();

        function update() {
            if ( checkbox.checked ) {
                target.classList.add('checked');
                qcode.columnsShowHide(tables, colSelector, 'show');
            } else {
                target.classList.remove('checked');
                qcode.columnsShowHide(tables, colSelector, 'hide');
            }
        }

        function onClick(event) {
            if ( event.target == checkbox || event.target.matches('label') ) {
                return
            }
            event.preventDefault();
            checkbox.checked = ! checkbox.checked;
            checkbox.dispatchEvent(
                new Event('change', {
                    "bubbles": true,
                    "composed": true
                })
            );
        }

        function onCheckBoxChange(event) {
            update()
            if ( ! sticky ) {
                return
            }
            const data = {}
            data[checkbox.getAttribute('name')] = checkbox.checked;
            if ( stickyUrl ) {
                data['sticky_url'] = stickyUrl;
            }
            httpPost('/sticky_save.html',
                     data,
                     function(){},
                     function(){});
        }

        function onMouseEnter(event) {
            target.classList.add('hover');
            const cols = Array.from(table.querySelectorAll(colSelector));
            for ( const col of cols ) {
                col.classList.add('highlight');
            }
        }

        function onMouseLeave(event) {
            target.classList.remove('hover');
            const cols = Array.from(table.querySelectorAll(colSelector));
            for ( const col of cols ) {
                col.classList.remove('highlight');
            }
        }
    });

    function getData(element, key) {
        if ( element.hasAttribute(key) ) {
            return element.getAttribute(key);
        }
        key = qcode.underscore2camelCase(key);
        if ( element.dataset[key] !== undefined ) {
            return element.dataset[key];
        }
        return ""
    }
};
<|endoftext|>