<commit_before>/*
 * Copyright (C) 2012 B3Partners B.V.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
/**
 * DataSelection and Filter component
 * Creates a dialog where filter and selection settings can be set.
 * A dataselectionfilter contains 1..n filters, a filter contains 1..n attributefilters.
 * @author Meine Toonen
 */
Ext.define ("viewer.components.DataSelection",{
    extend: "viewer.components.Component",
    dataTab : null,
    filterTab : null,
    attributes:null,
    layerSelector:null,
    appLayer: null,
    filters:null,
    filterActive:null,
    config: {
        layers:null,
        title:null,
        iconUrl:null,
        tooltip:null,
        details:{
            width: null,
            height:null
        }
    },
    constructor: function (conf){
        this.attributes =[];
        viewer.components.DataSelection.superclass.constructor.call(this, conf);
        this.filters = new Array();
        this.initConfig(conf);
        var me = this;
        this.renderButton({
            handler: function(){
                me.showWindow();
            },
            text: me.title,
            icon: me.iconUrl,
            tooltip: me.tooltip
        });
        this.loadWindow();
        return this;
    },
    showWindow : function (){
        this.layerSelector.initLayers();
        this.popup.show();
    },
    /** ???
     * @param layer the application Layer
     */
    showAndForceLayer : function (layer){
        this.layerSelector.addForcedLayer(layer);
        this.showWindow();
    },
    removeForcedLayer : function (layer){
        this.layerSelector.removeForcedLayer(layer);
        this.layerSelector.initLayers();
    },
    loadWindow : function(){
        var config = {
            viewerController : this.viewerController,
            div: this.getContentDiv(),
            layers : this.layers
        };
        this.layerSelector = Ext.create("viewer.components.LayerSelector",config);
        this.layerSelector.addListener(viewer.viewercontroller.controller.Event.ON_LAYERSELECTOR_CHANGE,this.layerChanged,this);

        // Make the tabs
        this.tabpanel = Ext.create('Ext.tab.Panel', {
            height: parseInt(this.details.height) - 100,
            width: parseInt(this.details.width)-40,
            hideMode: 'offsets',
            autoScroll:true,
            layout: {
                type: 'fit'
            },
            tabBar:{
                style: 'background:#fff;'
            },
            items: [
            {
                id   : 'filterTab',
                title: 'Filter',// TODO Do renaming of variables dataselection-->filter
                hideMode: 'offsets',
                autoScroll:true,
                html: "

"
            },
            {
                id : "dataTab",
                title: 'Dataselectie',// TODO Do renaming of variables filter->dataselection
                hideMode: 'offsets',
                autoScroll:true,
                html: "

"
            }
            ],
            activeTab : "dataTab",
            renderTo : this.getContentDiv()
        });

        // Make panels in tabs and save them
        this.dataTab = Ext.create('Ext.panel.Panel', {
            autoScroll: true,
            renderTo: 'dataTabDiv'
        });

        this.filterTab = Ext.create('Ext.panel.Panel', {
            autoScroll: true,
            renderTo: 'filterTabDiv'
        });

        // Add the button to the dataselectiontab
        var addFilter = Ext.create('Ext.Button', {
            text : 'Voeg filter toe',
            listeners: {
                click:{
                    scope: this,
                    fn: this.addFilter
                }
            }
        });
        this.filterTab.add(addFilter);
        this.filterActive = Ext.create ("Ext.form.field.Checkbox",{
            boxLabel  : 'Filter is actief',
            name      : 'filterActive',
            inputValue: true,
            checked   : false

        });
        this.filterTab.add(this.filterActive);
        // Add the first filter
        this.addFilter();
        // Make lower buttons
        this.button1 = Ext.create('Ext.Button', {
            text : 'Toepassen',
            renderTo: this.getContentDiv(),
            listeners: {
                click:{
                    scope: this,
                    fn: this.applyFilter
                }
            }
        });

        this.button2 = Ext.create('Ext.Button', {
            text : 'Annuleren',
            renderTo: this.getContentDiv(),
            listeners: {
                click:{
                    scope: this,
                    fn: this.cancel
                }
            }
        });
    },
    createDataTab : function (appLayer){
        var attributes = appLayer.attributes;
        var dataSelectieAttributes = new Array();
        for(var i= 0 ; i < attributes.length ;i++){
            var attribute = attributes[i];
            if(attribute.selectable){
                var defaultVal = "";
                if(attribute.defaultValue != undefined){
                    defaultVal = attribute.defaultValue;
                }
                dataSelectieAttributes.push({
                    xtype: "textfield",
                    id: attribute.name,
                    dataType: attribute.type,
                    name: attribute.name,
                    fieldLabel: attribute.alias || attribute.name,
                    labelWidth:200,
                    value : defaultVal
                });
            }
        }

        this.dataTab.removeAll();
        this.dataTab.add(dataSelectieAttributes);
    },
    /**
     *  Add a filter to the current filterlist.
     */
    addFilter : function (){
        var logicOperator = null;
        if(this.filters.length != 0){
            var logicStore = Ext.create('Ext.data.Store', {
                fields: ['id','title'],
                data : [{
                    id:"OR",
                    title:"of"
                }, {
                    id:"AND",
                    title:"en"
                }]
            });

            logicOperator = Ext.create('Ext.form.ComboBox', {
                fieldLabel: '',
                store: logicStore,
                queryMode: 'local',
                displayField: 'title',
                width:50,
                value:'OR',
                valueField: 'id'
            });
            // Insert before the checkbox
            this.filterTab.insert(this.filterTab.items.length - 1,logicOperator);

        }
        var config = {
            width: parseInt(this.details.width),
            height: parseInt(this.details.height),
            attributes:this.attributes,
            logicOperator:logicOperator
        };
        var filter = Ext.create("viewer.components.Filter",config);
        this.filters.push(filter);
        // Insert before the checkbox
        this.filterTab.insert(this.filterTab.items.length - 1,filter.getUI());
    },
    applyFilter : function (){
        var cql = "";

        cql += this.getDataTabCQL();
        if(this.filterActive.getValue()){
            if(cql != ""){
                cql += " AND ";
            }
            for ( var i = 0 ; i < this.filters.length;i++){
                var filter = this.filters[i];
                cql += filter.getCQL();
            }

        }
        if(cql != ""){
            cql = "(" + cql + ")";
        }
        var layer = this.layerSelector.getValue();

        var filterWrapper =  Ext.create("viewer.components.CQLFilterWrapper",{
            id: this.name + this.layerSelector.getValue(),
            cql: cql,
            operator : "AND"
        });

        this.viewerController.setFilter(filterWrapper,layer);

    //console.log("CQL: " + layer.filter.getCQL());
    },
    getDataTabCQL : function (){
        var items = this.dataTab.items.items;
        var cql = "";
        for ( var i = 0 ; i < items.length;i++){
            var item = items[i];
            if(item.getValue() != ""){
                if(i != 0 ){
                    cql += " AND ";
                }
                cql += "\"" +item.id + "\"=";
                var attributeType = item.dataType;
                if(attributeType && attributeType.toLowerCase() == "string"){
                    cql += "\'";
                }
                cql += item.getValue();
                if(attributeType && attributeType.toLowerCase() == "string"){
                    cql += "\'";
                }
            }
        }
        return cql;
    },
    cancel : function (){
        this.popup.hide();
    },
    /**
     *  Reset all comboboxes when a different layer is selected
     */
    layerChanged : function (item,prev){
        this.appLayer = item;

        if(this.appLayer != null){
            this.featureService = this.viewerController.getAppLayerFeatureService(this.appLayer);
            var me = this;
            // check if featuretype was loaded
            if(this.appLayer.attributes == undefined) {
                this.featureService.loadAttributes(me.appLayer, function(attributes) {
                    me.changeAttributes(me.appLayer);
                });
            } else {
                this.changeAttributes(me.appLayer);
            }
        }

        if(prev != undefined){
            var prevLayer = this.viewerController.getLayer(this.appLayer);
            prevLayer.setQuery(null);
        }
    },
    // Change the comboboxes of the attributefilters. Happens when a new layer is chosen.
    changeAttributes : function (appLayer){
        var attributes = appLayer.attributes;
        var attributeList = new Array();
        for(var i= 0 ; i < attributes.length ;i++){
            var attribute = attributes[i];
            if(attribute.filterable){
                attributeList.push({
                    id: attribute.id,
                    title: attribute.alias || attribute.name,
                    value: attribute.name,
                    type: attribute.type
                });
            }
        }
        this.attributes = attributeList;
        for (var j = 0 ; j < this.filters.length ;j++){
            var filter = this.filters[j];
            filter.setNewAttributeList(attributeList);
        }
        this.createDataTab(appLayer);
    },
    getExtComponents: function() {
        return Ext.Array.merge(
            this.layerSelector.getExtComponents(),
            [
            this.tabpanel.getId(),
            this.dataTab.getId(),
            this.filterTab.getId(),
            this.button1.getId(),
            this.button2.getId()
            ]
            );
    }
});
<commit_msg>Description by dataselection  For ticket #302<commit_after>/*
 * Copyright (C) 2012 B3Partners B.V.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
/**
 * DataSelection and Filter component
 * Creates a dialog where filter and selection settings can be set.
 * A dataselectionfilter contains 1..n filters, a filter contains 1..n attributefilters.
 * @author Meine Toonen
 */
Ext.define ("viewer.components.DataSelection",{
    extend: "viewer.components.Component",
    dataTab : null,
    filterTab : null,
    attributes:null,
    layerSelector:null,
    appLayer: null,
    filters:null,
    filterActive:null,
    config: {
        layers:null,
        title:null,
        iconUrl:null,
        tooltip:null,
        details:{
            width: null,
            height:null
        }
    },
    constructor: function (conf){
        this.attributes =[];
        viewer.components.DataSelection.superclass.constructor.call(this, conf);
        this.filters = new Array();
        this.initConfig(conf);
        var me = this;
        this.renderButton({
            handler: function(){
                me.showWindow();
            },
            text: me.title,
            icon: me.iconUrl,
            tooltip: me.tooltip
        });
        this.loadWindow();
        return this;
    },
    showWindow : function (){
        this.layerSelector.initLayers();
        this.popup.show();
    },
    /** ???
     * @param layer the application Layer
     */
    showAndForceLayer : function (layer){
        this.layerSelector.addForcedLayer(layer);
        this.showWindow();
    },
    removeForcedLayer : function (layer){
        this.layerSelector.removeForcedLayer(layer);
        this.layerSelector.initLayers();
    },
    loadWindow : function(){
        var config = {
            viewerController : this.viewerController,
            div: this.getContentDiv(),
            layers : this.layers
        };
        this.layerSelector = Ext.create("viewer.components.LayerSelector",config);
        this.layerSelector.addListener(viewer.viewercontroller.controller.Event.ON_LAYERSELECTOR_CHANGE,this.layerChanged,this);

        // Make the tabs
        this.tabpanel = Ext.create('Ext.tab.Panel', {
            height: parseInt(this.details.height) - 100,
            width: parseInt(this.details.width)-40,
            hideMode: 'offsets',
            autoScroll:true,
            layout: {
                type: 'fit'
            },
            tabBar:{
                style: 'background:#fff;'
            },
            items: [
            {
                id   : 'filterTab',
                title: 'Filter',// TODO Do renaming of variables dataselection-->filter
                hideMode: 'offsets',
                autoScroll:true,
                html: "

"
            },
            {
                id : "dataTab",
                title: 'Dataselectie',// TODO Do renaming of variables filter->dataselection
                hideMode: 'offsets',
                autoScroll:true,
                html: "

"
            }
            ],
            activeTab : "dataTab",
            renderTo : this.getContentDiv()
        });

        // Make panels in tabs and save them
        this.dataTab = Ext.create('Ext.panel.Panel', {
            autoScroll: true,
            renderTo: 'dataTabDiv'
        });

        this.filterTab = Ext.create('Ext.panel.Panel', {
            autoScroll: true,
            renderTo: 'filterTabDiv'
        });

        // Add the button to the dataselectiontab
        var addFilter = Ext.create('Ext.Button', {
            text : 'Voeg filter toe',
            listeners: {
                click:{
                    scope: this,
                    fn: this.addFilter
                }
            }
        });
        this.filterTab.add(addFilter);
        this.filterActive = Ext.create ("Ext.form.field.Checkbox",{
            boxLabel  : 'Filter is actief',
            name      : 'filterActive',
            inputValue: true,
            checked   : false

        });
        this.filterTab.add(this.filterActive);
        // Add the first filter
        this.addFilter();
        // Make lower buttons
        this.button1 = Ext.create('Ext.Button', {
            text : 'Toepassen',
            renderTo: this.getContentDiv(),
            listeners: {
                click:{
                    scope: this,
                    fn: this.applyFilter
                }
            }
        });

        this.button2 = Ext.create('Ext.Button', {
            text : 'Annuleren',
            renderTo: this.getContentDiv(),
            listeners: {
                click:{
                    scope: this,
                    fn: this.cancel
                }
            }
        });
    },
    createDataTab : function (appLayer){
        var attributes = appLayer.attributes;
        var dataSelectieAttributes = new Array();
        for(var i= 0 ; i < attributes.length ;i++){
            var attribute = attributes[i];
            if(attribute.selectable){
                var defaultVal = "";
                if(attribute.defaultValue != undefined){
                    defaultVal = attribute.defaultValue;
                }
                dataSelectieAttributes.push({
                    xtype: "textfield",
                    id: attribute.name,
                    dataType: attribute.type,
                    name: attribute.name,
                    fieldLabel: attribute.alias || attribute.name,
                    labelWidth:200,
                    value : defaultVal
                });
            }
        }

        this.dataTab.removeAll();
        this.dataTab.add({
            xtype : 'label',
            text: 'Kaart wordt pas zichtbaar na het toepassen van een dataselectie'
        });
        this.dataTab.add(dataSelectieAttributes);
    },
    /**
     *  Add a filter to the current filterlist.
     */
    addFilter : function (){
        var logicOperator = null;
        if(this.filters.length != 0){
            var logicStore = Ext.create('Ext.data.Store', {
                fields: ['id','title'],
                data : [{
                    id:"OR",
                    title:"of"
                }, {
                    id:"AND",
                    title:"en"
                }]
            });

            logicOperator = Ext.create('Ext.form.ComboBox', {
                fieldLabel: '',
                store: logicStore,
                queryMode: 'local',
                displayField: 'title',
                width:50,
                value:'OR',
                valueField: 'id'
            });
            // Insert before the checkbox
            this.filterTab.insert(this.filterTab.items.length - 1,logicOperator);

        }
        var config = {
            width: parseInt(this.details.width),
            height: parseInt(this.details.height),
            attributes:this.attributes,
            logicOperator:logicOperator
        };
        var filter = Ext.create("viewer.components.Filter",config);
        this.filters.push(filter);
        // Insert before the checkbox
        this.filterTab.insert(this.filterTab.items.length - 1,filter.getUI());
    },
    applyFilter : function (){
        var cql = "";

        cql += this.getDataTabCQL();
        if(this.filterActive.getValue()){
            if(cql != ""){
                cql += " AND ";
            }
            for ( var i = 0 ; i < this.filters.length;i++){
                var filter = this.filters[i];
                cql += filter.getCQL();
            }

        }
        if(cql != ""){
            cql = "(" + cql + ")";
        }
        var layer = this.layerSelector.getValue();

        var filterWrapper =  Ext.create("viewer.components.CQLFilterWrapper",{
            id: this.name + this.layerSelector.getValue(),
            cql: cql,
            operator : "AND"
        });

        this.viewerController.setFilter(filterWrapper,layer);

    //console.log("CQL: " + layer.filter.getCQL());
    },
    getDataTabCQL : function (){
        var items = this.dataTab.items.items;
        var cql = "";
        for ( var i = 0 ; i < items.length;i++){
            var item = items[i];
            if(item.getValue() != ""){
                if(i != 0 ){
                    cql += " AND ";
                }
                cql += "\"" +item.id + "\"=";
                var attributeType = item.dataType;
                if(attributeType && attributeType.toLowerCase() == "string"){
                    cql += "\'";
                }
                cql += item.getValue();
                if(attributeType && attributeType.toLowerCase() == "string"){
                    cql += "\'";
                }
            }
        }
        return cql;
    },
    cancel : function (){
        this.popup.hide();
    },
    /**
     *  Reset all comboboxes when a different layer is selected
     */
    layerChanged : function (item,prev){
        this.appLayer = item;

        if(this.appLayer != null){
            this.featureService = this.viewerController.getAppLayerFeatureService(this.appLayer);
            var me = this;
            // check if featuretype was loaded
            if(this.appLayer.attributes == undefined) {
                this.featureService.loadAttributes(me.appLayer, function(attributes) {
                    me.changeAttributes(me.appLayer);
                });
            } else {
                this.changeAttributes(me.appLayer);
            }
        }

        if(prev != undefined){
            var prevLayer = this.viewerController.getLayer(this.appLayer);
            prevLayer.setQuery(null);
        }
    },
    // Change the comboboxes of the attributefilters. Happens when a new layer is chosen.
    changeAttributes : function (appLayer){
        var attributes = appLayer.attributes;
        var attributeList = new Array();
        for(var i= 0 ; i < attributes.length ;i++){
            var attribute = attributes[i];
            if(attribute.filterable){
                attributeList.push({
                    id: attribute.id,
                    title: attribute.alias || attribute.name,
                    value: attribute.name,
                    type: attribute.type
                });
            }
        }
        this.attributes = attributeList;
        for (var j = 0 ; j < this.filters.length ;j++){
            var filter = this.filters[j];
            filter.setNewAttributeList(attributeList);
        }
        this.createDataTab(appLayer);
    },
    getExtComponents: function() {
        return Ext.Array.merge(
            this.layerSelector.getExtComponents(),
            [
            this.tabpanel.getId(),
            this.dataTab.getId(),
            this.filterTab.getId(),
            this.button1.getId(),
            this.button2.getId()
            ]
            );
    }
});
<|endoftext|>


<commit_before>Elm.Native.Json = {};
Elm.Native.Json.make = function(elm) {

    elm.Native = elm.Native || {};
    elm.Native.Json = elm.Native.Json || {};
    if (elm.Native.Json.values) return elm.Native.Json.values;

    var Maybe = Elm.Maybe.make(elm);
    var Dict = Elm.Dict.make(elm);
    var List = Elm.List.make(elm);
    var Utils = Elm.Native.Utils.make(elm);

    function toJS(v) {
        switch (v.ctor) {
        case 'Null'   : return null;
        case 'String' : return v._0;
        case 'Number' : return v._0;
        case 'Boolean': return v._0;
        case 'Object' :
            var obj = {};
            var array = List.toArray(Dict.toList(v._0));
            for (var i = array.length; i--; ) {
                var entry = array[i];
                obj[entry._0] = toJS(entry._1);
            }
            return obj;
        case 'Array'  :
            var array = List.toArray(v._0);
            for (var i = array.length; i--; ) {
	        array[i] = toJS(array[i]);
            }
            return array;
        }
    }

    function toString(sep, value) {
        return JSON.stringify(toJS(value), null, sep);
    }

    function fromJS(v) {
        switch (typeof v) {
        case 'string' : return { ctor:"String" , _0: v };
        case 'number' : return { ctor:"Number" , _0: v };
        case 'boolean': return { ctor:"Boolean", _0: v };
        case 'object' :
            if (v === null) return { ctor:"Null" };
            if (v instanceof Array) {
                for (var i = v.length; i--; ) { v[i] = fromJS(v[i]); }
	        return { ctor:"Array", _0: List.fromArray(v) };
            }
            var array = [];
            for (var k in v) array.push(Utils.Tuple2(k, fromJS(v[k])));
            return { ctor:"Object", _0: Dict.fromList(List.fromArray(array)) };
        }
    }

    function fromString(str) {
        try {
	    return Maybe.Just(fromJS(JSON.parse(str)));
        } catch (e) {
	    return Maybe.Nothing;
        }
    }

    return elm.Native.Json.values = {
        toString   : F2(toString),
        fromString : fromString,
        fromJS     : fromJS,
        toJS       : toJS,
    };

};
<commit_msg>Use Native.List instead of List and make minor cosmetic changes<commit_after>Elm.Native.Json = {};
Elm.Native.Json.make = function(elm) {

    elm.Native = elm.Native || {};
    elm.Native.Json = elm.Native.Json || {};
    if (elm.Native.Json.values) return elm.Native.Json.values;

    var Maybe = Elm.Maybe.make(elm);
    var Dict = Elm.Dict.make(elm);
    var List = Elm.Native.List.make(elm);
    var Utils = Elm.Native.Utils.make(elm);

    function toJS(v) {
        switch (v.ctor) {
        case 'Null'   : return null;
        case 'String' : return v._0;
        case 'Number' : return v._0;
        case 'Boolean': return v._0;
        case 'Object' :
            var obj = {};
            var array = List.toArray(Dict.toList(v._0));
            for (var i = array.length; i--; ) {
                var entry = array[i];
                obj[entry._0] = toJS(entry._1);
            }
            return obj;
        case 'Array'  :
            var array = List.toArray(v._0);
            for (var i = array.length; i--; ) {
	        array[i] = toJS(array[i]);
            }
            return array;
        }
    }

    function toString(sep, value) {
        return JSON.stringify(toJS(value), null, sep);
    }

    function fromJS(v) {
        switch (typeof v) {
        case 'string' : return { ctor:"String" , _0: v };
        case 'number' : return { ctor:"Number" , _0: v };
        case 'boolean': return { ctor:"Boolean", _0: v };
        case 'object' :
            if (v === null) return { ctor:"Null" };
            if (v instanceof Array) {
                for (var i = v.length; i--; ) {
                    v[i] = fromJS(v[i]);
                }
	        return {
                    ctor:"Array",
                    _0: List.fromArray(array)
                };
            }
            var array = [];
            for (var key in v) {
                var value = fromJS(v[key]);
                array.push(Utils.Tuple2(key, value));
            }
            var list = List.fromArray(array);
            return {
                ctor:"Object",
                _0: Dict.fromList(list)
            };
        }
    }

    function fromString(str) {
        try {
	    return Maybe.Just(fromJS(JSON.parse(str)));
        } catch (e) {
	    return Maybe.Nothing;
        }
    }

    return elm.Native.Json.values = {
        toString   : F2(toString),
        fromString : fromString,
        fromJS     : fromJS,
        toJS       : toJS,
    };

};
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import 'isomorphic-fetch'
import DescriptionTerm from './DescriptionTerm'
import { createStore } from 'redux'
import Map from '../components/Map'
import Loading from './Loading'

export default ({ segment }) => (

      <DescriptionTerm term="Name" value={ segment.name || '...' } unit="" />
      <DescriptionTerm term="Length" value={ (segment.distance / 1000).toFixed(1) || '...' } unit="km" />
      <DescriptionTerm term="Elevation" value={ segment.total_elevation_gain || '...' } unit="m" />
      <DescriptionTerm term="Avg. Gradient" value={ segment.average_grade || '...' } unit="%" />
      <DescriptionTerm term="Max. Gradient" value={ segment.maximum_grade || '...' } unit="%" />
      <DescriptionTerm term="Category" value={ segment.climb_category == 5 ? 'HC' : segment.climb_category } unit="" />
      <a className="f6 link orange i" href={`https://www.strava.com/segments/${segment.id}`}>Link to Strava »

)
<commit_msg>Removing unused imports<commit_after>import React, { Component } from 'react';
import DescriptionTerm from './DescriptionTerm'

export default ({ segment }) => (

      <DescriptionTerm term="Name" value={ segment.name || '...' } unit="" />
      <DescriptionTerm term="Length" value={ (segment.distance / 1000).toFixed(1) || '...' } unit="km" />
      <DescriptionTerm term="Elevation" value={ segment.total_elevation_gain || '...' } unit="m" />
      <DescriptionTerm term="Avg. Gradient" value={ segment.average_grade || '...' } unit="%" />
      <DescriptionTerm term="Max. Gradient" value={ segment.maximum_grade || '...' } unit="%" />
      <DescriptionTerm term="Category" value={ segment.climb_category == 5 ? 'HC' : segment.climb_category } unit="" />
      <a className="f6 link orange i" href={`https://www.strava.com/segments/${segment.id}`}>Link to Strava »

)
<|endoftext|>


<commit_before>(function( window, document, undefined ) {
  'use strict';

  var body = document.getElementsByClassName( 'body' )[0],
      bodyTransition = window.getComputedStyle( body ).transition;

  // Offset the transform origin so rotateY revolves around
  // an axis outside of the body.
  var transformOrigin = '50% 50% 0';
  body.style.webkitTransformOrigin = transformOrigin;
  body.style.transformOrigin = transformOrigin;

  function onMouseMove( event ) {
    var rx =   ( 0.5 - ( event.clientY / window.innerHeight ) ) * 180,
        ry =  -( 0.5 - ( event.clientX / window.innerWidth  ) ) * 180;

    var transform = 'rotateX( ' + rx + 'deg) rotateY( ' + ry + 'deg)';
    body.style.webkitTransform = transform;
    body.style.transform = transform;
  }

  // Toggle on/off the mouse-controlled rotating camera.
  document.addEventListener( 'keydown', function( event ) {
    // Space.
    if ( event.which === 32 ) {
      if ( window.getComputedStyle( body ).transitionProperty !== 'none' ) {
        body.style.transition = 'none';

        transformOrigin = '0 0 0';
        body.style.webkitTransformOrigin = transformOrigin;
        body.style.transformOrigin = transformOrigin;

        document.addEventListener( 'mousemove', onMouseMove );
      } else {
        body.style.transition = bodyTransition;

        // Reset transform and transform origin.
        body.style.webkitTransform = '';
        body.style.transform = '';

        transformOrigin = '50% 50% 0';
        body.style.webkitTransformOrigin = transformOrigin;
        body.style.transformOrigin = transformOrigin;

        document.removeEventListener( 'mousemove', onMouseMove );
      }
    }
  });

}) ( window, document );
<commit_msg>illustrations[robot-3d]: Remove extra spaces.<commit_after>(function( window, document, undefined ) {
  'use strict';

  var body = document.getElementsByClassName( 'body' )[0],
      bodyTransition = window.getComputedStyle( body ).transition;

  // Offset the transform origin so rotateY revolves around
  // an axis outside of the body.
  var transformOrigin = '50% 50% 0';
  body.style.webkitTransformOrigin = transformOrigin;
  body.style.transformOrigin = transformOrigin;

  function onMouseMove( event ) {
    var rx =   ( 0.5 - ( event.clientY / window.innerHeight ) ) * 180,
        ry =  -( 0.5 - ( event.clientX / window.innerWidth  ) ) * 180;

    var transform = 'rotateX(' + rx + 'deg) rotateY(' + ry + 'deg)';
    body.style.webkitTransform = transform;
    body.style.transform = transform;
  }

  // Toggle on/off the mouse-controlled rotating camera.
  document.addEventListener( 'keydown', function( event ) {
    // Space.
    if ( event.which === 32 ) {
      if ( window.getComputedStyle( body ).transitionProperty !== 'none' ) {
        body.style.transition = 'none';

        transformOrigin = '0 0 0';
        body.style.webkitTransformOrigin = transformOrigin;
        body.style.transformOrigin = transformOrigin;

        document.addEventListener( 'mousemove', onMouseMove );
      } else {
        body.style.transition = bodyTransition;

        // Reset transform and transform origin.
        body.style.webkitTransform = '';
        body.style.transform = '';

        transformOrigin = '50% 50% 0';
        body.style.webkitTransformOrigin = transformOrigin;
        body.style.transformOrigin = transformOrigin;

        document.removeEventListener( 'mousemove', onMouseMove );
      }
    }
  });

}) ( window, document );
<|endoftext|>


<commit_before>/**
  Copyright 2011 Christian Iversen <ci@sikkerhed.org>

  Permission is hereby granted, free of charge, to any person
  obtaining a copy of this software and associated documentation
  files (the "Software"), to deal in the Software without
  restriction, including without limitation the rights to use,
  copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the
  Software is furnished to do so, subject to the following
  conditions:

  The above copyright notice and this permission notice shall be
  included in all copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  OTHER DEALINGS IN THE SOFTWARE.
**/

var float = __inherit(number, "float");

$PY.float = float;

float.numbertype = "PY$__float__";
float.numberclass = float;

float.PY$__init__ = function(value) {
    var s = value.toString();
    if (s.match(/^[-+]?[0-9]+(\.[0-9]*)?(e[-+]?[0-9]+)?$/)) {
        this.obj = parseFloat(value);
    } else {
        throw py_builtins.ValueError("Invalid float: " + s);
    }
};

var __float_real__ = float.PY$__create__;

float.PY$__create__ = function(cls, obj) {
    if (js($PY.isinstance(obj, object)) && (obj.PY$__float__ !== undefined)) {
        return obj.PY$__float__();
    } else {
        return __float_real__(cls, obj);
    }
};

float.PY$__float__ = function () {
    return this;
};

float.PY$__int__ = function () {
    return int(parseInt(this.obj));
};

float.PY$__str__ = function () {
    if (this.obj - Math.floor(this.obj) < 1e-6) {
        var res = sprintf("%g", this);
        if (res.indexOf('e') === -1) {
            return str(res + ".0");
        } else {
            return str(res);
        }
    } else {
        return sprintf("%.10g", this);
    }
};

float.PY$__repr__ = float.PY$__str__;

float.PY$__hash__ = function () {
    return this.obj;
};

float.PY$__div__ = function(x) {
    if (!x.numbertype)
        throw py_builtins.TypeError("Cannot divide number and non-number");
    if (x.obj === 0)
        throw py_builtins.ZeroDivisionError("float division by zero");
    return float((0.0 + this.obj) / (0.0 + x.obj));
};

float.PY$__pow__ = function(x) {
    if (!x.numbertype)
        throw py_builtins.TypeError("Cannot exponentiate number and non-number");
    return float(Math.pow(this.obj, x.obj));
};

float.PY$__floordiv__ = float.PY$__div__;
float.PY$__ifloordiv__ = float.PY$__div__;
<commit_msg> * Make sure result of float.PY$__str__ is always wrapped in str()<commit_after>/**
  Copyright 2011 Christian Iversen <ci@sikkerhed.org>

  Permission is hereby granted, free of charge, to any person
  obtaining a copy of this software and associated documentation
  files (the "Software"), to deal in the Software without
  restriction, including without limitation the rights to use,
  copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the
  Software is furnished to do so, subject to the following
  conditions:

  The above copyright notice and this permission notice shall be
  included in all copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  OTHER DEALINGS IN THE SOFTWARE.
**/

var float = __inherit(number, "float");

$PY.float = float;

float.numbertype = "PY$__float__";
float.numberclass = float;

float.PY$__init__ = function(value) {
    var s = value.toString();
    if (s.match(/^[-+]?[0-9]+(\.[0-9]*)?(e[-+]?[0-9]+)?$/)) {
        this.obj = parseFloat(value);
    } else {
        throw py_builtins.ValueError("Invalid float: " + s);
    }
};

var __float_real__ = float.PY$__create__;

float.PY$__create__ = function(cls, obj) {
    if (js($PY.isinstance(obj, object)) && (obj.PY$__float__ !== undefined)) {
        return obj.PY$__float__();
    } else {
        return __float_real__(cls, obj);
    }
};

float.PY$__float__ = function () {
    return this;
};

float.PY$__int__ = function () {
    return int(parseInt(this.obj));
};

float.PY$__str__ = function () {
    if (this.obj - Math.floor(this.obj) < 1e-6) {
        var res = sprintf("%g", this);
        if (res.indexOf('e') === -1) {
            return str(res + ".0");
        } else {
            return str(res);
        }
    } else {
        return str(sprintf("%.10g", this));
    }
};

float.PY$__repr__ = float.PY$__str__;

float.PY$__hash__ = function () {
    return this.obj;
};

float.PY$__div__ = function(x) {
    if (!x.numbertype)
        throw py_builtins.TypeError("Cannot divide number and non-number");
    if (x.obj === 0)
        throw py_builtins.ZeroDivisionError("float division by zero");
    return float((0.0 + this.obj) / (0.0 + x.obj));
};

float.PY$__pow__ = function(x) {
    if (!x.numbertype)
        throw py_builtins.TypeError("Cannot exponentiate number and non-number");
    return float(Math.pow(this.obj, x.obj));
};

float.PY$__floordiv__ = float.PY$__div__;
float.PY$__ifloordiv__ = float.PY$__div__;
<|endoftext|>


<commit_before>Package.describe({
  name: "grove:less",
  summary: "Import all of your Less files in one step, in the order you want",
  version: "0.1.1",
  git: 'https://github.com/grovelabs/meteor-less.git'
});

Package.registerBuildPlugin({
  name: 'less-build-plugin',
  use: [],
  sources: [
    'plugin.js',
  ],
  npmDependencies: {
    "less": "2.4.0",
    "less-plugin-autoprefix": "1.4.1"
  }
});

Package.onTest(function (api) {
  api.use(['grove:less',
           'practicalmeteor:munit',
           'templating'
          ]);
  api.addFiles(['tests/foo.html',
                'tests/foo.less',
                'tests/tests.js',
                ], 'client');
});<commit_msg>Changed description<commit_after>Package.describe({
  name: "grove:less",
  summary: "A better Less package. Everything the original does plus ordered imports and Autoprefixer",
  version: "0.1.1",
  git: 'https://github.com/grovelabs/meteor-less.git'
});

Package.registerBuildPlugin({
  name: 'less-build-plugin',
  use: [],
  sources: [
    'plugin.js',
  ],
  npmDependencies: {
    "less": "2.4.0",
    "less-plugin-autoprefix": "1.4.1"
  }
});

Package.onTest(function (api) {
  api.use(['grove:less',
           'practicalmeteor:munit',
           'templating'
          ]);
  api.addFiles(['tests/foo.html',
                'tests/foo.less',
                'tests/tests.js',
                ], 'client');
});
<|endoftext|>


<commit_before>// Package metadata for Meteor.js web platform (https://www.meteor.com/)
// This file is defined within the Meteor documentation at
//
//   http://docs.meteor.com/#/full/packagejs
//
// and it is needed to define a Meteor package
'use strict';

Package.describe({
  name: 'useraccounts:flow-routing',
  summary: 'UserAccounts package providing routes configuration capability via kadira:flow-router.',
  version: '1.12.1',
  git: 'https://github.com/meteor-useraccounts/flow-routing.git'
});

Package.onUse(function(api) {
  api.versionsFrom('METEOR@1.0.3');

  api.use([
    'check',
    'kadira:blaze-layout',
    'kadira:flow-router',
    'underscore',
    'useraccounts:core'
  ], ['client', 'server']);

  api.imply([
    'kadira:blaze-layout@2.0.0',
    'kadira:flow-router@2.1.1',
    'useraccounts:core@1.12.1'
  ], ['client', 'server']);

  api.addFiles([
    'lib/core.js',
  ], ['client', 'server']);

  api.addFiles([
    'lib/client/client.js',
    'lib/client/templates_helpers/at_input.js'
  ], ['client']);
});
<commit_msg>patch release - Bump to version 1.12.2<commit_after>// Package metadata for Meteor.js web platform (https://www.meteor.com/)
// This file is defined within the Meteor documentation at
//
//   http://docs.meteor.com/#/full/packagejs
//
// and it is needed to define a Meteor package
'use strict';

Package.describe({
  name: 'useraccounts:flow-routing',
  summary: 'UserAccounts package providing routes configuration capability via kadira:flow-router.',
  version: '1.12.2',
  git: 'https://github.com/meteor-useraccounts/flow-routing.git'
});

Package.onUse(function(api) {
  api.versionsFrom('METEOR@1.0.3');

  api.use([
    'check',
    'kadira:blaze-layout',
    'kadira:flow-router',
    'underscore',
    'useraccounts:core'
  ], ['client', 'server']);

  api.imply([
    'kadira:blaze-layout@2.0.0',
    'kadira:flow-router@2.1.1',
    'useraccounts:core@1.12.2'
  ], ['client', 'server']);

  api.addFiles([
    'lib/core.js',
  ], ['client', 'server']);

  api.addFiles([
    'lib/client/client.js',
    'lib/client/templates_helpers/at_input.js'
  ], ['client']);
});
<|endoftext|>


<commit_before>Package.describe({
	name:"lepozepo:cloudinary",
	summary: "Upload files to Cloudinary",
	version:"4.2.0",
	git:"https://github.com/Lepozepo/cloudinary"
});

Npm.depends({
	cloudinary: "1.3.1",
	"cloudinary-jquery": "2.0.9"
});

Package.on_use(function (api){
	api.versionsFrom('METEOR@1.0');

	// Core Packages
	api.use(["meteor-base@1.0.1","coffeescript","mongo"], ["client", "server"]);
	api.use(["templating"], "client");
	api.imply(["check","random","reactive-var"], ["client","server"]);

	// External Packages
	api.use(["matb33:collection-hooks@0.7.3"], ["client", "server"],{weak:true});

	// Cloudinary Client Side
	api.add_files(".npm/package/node_modules/cloudinary-jquery/cloudinary-jquery.min.js","client");

	// Core Files
	api.add_files("server/configuration.coffee", "server");
	api.add_files("server/signature.coffee", "server");

	api.add_files("client/functions.coffee", "client");

	api.export && api.export("Cloudinary",["server","client"]);
	api.export && api.export("lilcloudinary", ["client"]);

});

<commit_msg>Make sure we require meteor/underscore as well<commit_after>Package.describe({
	name:"lepozepo:cloudinary",
	summary: "Upload files to Cloudinary",
	version:"4.2.0",
	git:"https://github.com/Lepozepo/cloudinary"
});

Npm.depends({
	cloudinary: "1.3.1",
	"cloudinary-jquery": "2.0.9"
});

Package.on_use(function (api){
	api.versionsFrom('METEOR@1.0');

	// Core Packages
	api.use(["meteor-base@1.0.1","coffeescript","mongo","underscore"], ["client", "server"]);
	api.use(["templating"], "client");
	api.imply(["check","random","reactive-var"], ["client","server"]);

	// External Packages
	api.use(["matb33:collection-hooks@0.7.3"], ["client", "server"],{weak:true});

	// Cloudinary Client Side
	api.add_files(".npm/package/node_modules/cloudinary-jquery/cloudinary-jquery.min.js","client");

	// Core Files
	api.add_files("server/configuration.coffee", "server");
	api.add_files("server/signature.coffee", "server");

	api.add_files("client/functions.coffee", "client");

	api.export && api.export("Cloudinary",["server","client"]);
	api.export && api.export("lilcloudinary", ["client"]);

});

<|endoftext|>


<commit_before>var fs = require('fs');
var path = require('path');
var yaml = require('yaml-front-matter');
var _ = require('lodash');

/*
 * export
 */
module.exports = function(collectionRoot, playlistFolder){
  // windows: replace / with \
  if (path.sep !== '/') {
    collectionRoot = collectionRoot.split('/').join(path.sep);
    playlistFolder = playlistFolder.split('/').join(path.sep);
  }
  // return playlists found in collectionRoot/playlistFolder
  var playlistRoot = path.join(collectionRoot, playlistFolder);

  if (!fs.existsSync(playlistRoot)) {
    return [];
  }

  // create a list of playlists
  var playlistFiles = fs.readdirSync(playlistRoot);
  playlistFiles = _.map(playlistFiles, withPath, {root: playlistRoot});
  playlistFiles = _.filter(playlistFiles, isPlaylist);

  var playlists = _.map(playlistFiles, getPlaylist, {root: collectionRoot});

  return playlists;
};

/*
 * helper functions
 */
function withPath(filename) {
  // add path to filename
  return path.join(this.root, filename);
}

function isPlaylist(filename) {
  // if not directory and ends with .txt
  return filename.match(/\.txt$/) &&
         !fs.statSync(filename).isDirectory();
}

function playlistId(name){
  // replace chars in playlist-name, so that it can be used as id or class
  var id = name.replace(/ /g, '_');
  id = id.replace(/[\,\.\-\?]/g, '');
  return id;
}

function getLink(root, filename) {
  var link = filename.replace('.md', '.html');
  link = path.relative(root, link);
  link = path.join(path.basename(root), link);
  return link;
}

function getPlaylist(filename) {
  var lessonFiles = fs.readFileSync(filename, {encoding: 'utf8'})
                      .replace(/\r/g, '')
                      .split('\n');
  lessonFiles = _.compact(lessonFiles); // omit empty lines
  lessonFiles = _.map(lessonFiles, withPath, {root: this.root});

  var playlist = {};
  playlist.name = path.basename(filename).replace('.txt', '').replace(/_/g, ' ');
  playlist.id = playlistId(playlist.name);
  playlist.lessons = _.map(lessonFiles, getFrontMatter, {root: this.root});

  return playlist;
}

function getFrontMatter(filename){
  // return front matter of file, its filename and link
  var content = fs.readFileSync(filename);

  var frontMatter = yaml.loadFront(content);
  frontMatter = _.omit(frontMatter, '__content');
  frontMatter.filename = filename;
  frontMatter.link = getLink(this.root, filename);

  return frontMatter;
}
<commit_msg>playlist: read playlist folder directly from config<commit_after>var fs = require('fs');
var path = require('path');
var yaml = require('yaml-front-matter');
var _ = require('lodash');
var config = require('./config.js');

/*
 * export
 */
module.exports = function(collectionRoot){
  // windows: replace / with \
  if (path.sep !== '/') {
    collectionRoot = collectionRoot.split('/').join(path.sep);
  }
  // return playlists found in collectionRoot/playlistFolder
  var playlistRoot = path.join(collectionRoot, config.playlistFolder);

  if (!fs.existsSync(playlistRoot)) {
    return [];
  }

  // create a list of playlists
  var playlistFiles = fs.readdirSync(playlistRoot);
  playlistFiles = _.map(playlistFiles, withPath, {root: playlistRoot});
  playlistFiles = _.filter(playlistFiles, isPlaylist);

  var playlists = _.map(playlistFiles, getPlaylist, {root: collectionRoot});

  return playlists;
};

/*
 * helper functions
 */
function withPath(filename) {
  // add path to filename
  return path.join(this.root, filename);
}

function isPlaylist(filename) {
  // if not directory and ends with .txt
  return filename.match(/\.txt$/) &&
         !fs.statSync(filename).isDirectory();
}

function playlistId(name){
  // replace chars in playlist-name, so that it can be used as id or class
  var id = name.replace(/ /g, '_');
  id = id.replace(/[\,\.\-\?]/g, '');
  return id;
}

function getLink(root, filename) {
  var link = filename.replace('.md', '.html');
  link = path.relative(root, link);
  link = path.join(path.basename(root), link);
  return link;
}

function getPlaylist(filename) {
  var lessonFiles = fs.readFileSync(filename, {encoding: 'utf8'})
                      .replace(/\r/g, '')
                      .split('\n');
  lessonFiles = _.compact(lessonFiles); // omit empty lines
  lessonFiles = _.map(lessonFiles, withPath, {root: this.root});

  var playlist = {};
  playlist.name = path.basename(filename).replace('.txt', '').replace(/_/g, ' ');
  playlist.id = playlistId(playlist.name);
  playlist.lessons = _.map(lessonFiles, getFrontMatter, {root: this.root});

  return playlist;
}

function getFrontMatter(filename){
  // return front matter of file, its filename and link
  var content = fs.readFileSync(filename);

  var frontMatter = yaml.loadFront(content);
  frontMatter = _.omit(frontMatter, '__content');
  frontMatter.filename = filename;
  frontMatter.link = getLink(this.root, filename);

  return frontMatter;
}
<|endoftext|>


<commit_before>Package.describe({
  name: 'manuel:viewmodel',
  summary: "MVVM, two-way data binding, and components for Meteor. Similar to Angular and Knockout.",
  version: "2.1.0",
  git: "https://github.com/ManuelDeLeon/viewmodel"
});

var CLIENT = 'client';

Package.onUse(function(api) {
  api.use([
    'coffeescript@1.0.10',
    'blaze@2.1.3',
    'blaze-html-templates@1.0.1',
    'jquery@1.11.4',
    'underscore@1.0.4',
    'tracker@1.0.9',
    'reload@1.1.4',
    'sha@1.0.4',
    'reactive-dict@1.1.3',
    'manuel:reactivearray@1.0.5',
    'manuel:viewmodel-debug@2.0.0'
  ], CLIENT);

  api.addFiles([
    'lib/viewmodel.coffee',
    'lib/viewmodel-parseBind.coffee',
    'lib/bindings.coffee',
    'lib/template.coffee',
    'lib/migration.coffee',
    'lib/viewmodel-onUrl.coffee',
    'lib/lzstring.js'
  ], CLIENT);

  api.export([
    'ViewModel'
  ], CLIENT);
});

Package.onTest(function(api) {

  api.use([
    'coffeescript',
    'blaze',
    'blaze-html-templates',
    'jquery',
    'underscore',
    'tracker',
    'reload',
    'sha',
    'reactive-dict',
    'manuel:reactivearray',
    'practicalmeteor:mocha',
    'practicalmeteor:sinon'

  ], CLIENT);

  api.addFiles([
    'lib/viewmodel.coffee',
    'lib/viewmodel-parseBind.coffee',
    'lib/bindings.coffee',
    'lib/template.coffee',
    'lib/migration.coffee',
    'tests/jquery-patch.js',
    'tests/sinon-restore.js',
    'tests/bindings.coffee',
    'tests/viewmodel.coffee',
    'tests/viewmodel-instance.coffee',
    'tests/viewmodel-check.coffee',
    'tests/viewmodel-parseBind.coffee',
    'tests/template.coffee'
  ], CLIENT);

  api.export([
    'ViewModel'
  ], CLIENT);
});<commit_msg>Update debug version<commit_after>Package.describe({
  name: 'manuel:viewmodel',
  summary: "MVVM, two-way data binding, and components for Meteor. Similar to Angular and Knockout.",
  version: "2.1.0",
  git: "https://github.com/ManuelDeLeon/viewmodel"
});

var CLIENT = 'client';

Package.onUse(function(api) {
  api.use([
    'coffeescript@1.0.10',
    'blaze@2.1.3',
    'blaze-html-templates@1.0.1',
    'jquery@1.11.4',
    'underscore@1.0.4',
    'tracker@1.0.9',
    'reload@1.1.4',
    'sha@1.0.4',
    'reactive-dict@1.1.3',
    'manuel:reactivearray@1.0.5',
    'manuel:viewmodel-debug@2.1.0'
  ], CLIENT);

  api.addFiles([
    'lib/viewmodel.coffee',
    'lib/viewmodel-parseBind.coffee',
    'lib/bindings.coffee',
    'lib/template.coffee',
    'lib/migration.coffee',
    'lib/viewmodel-onUrl.coffee',
    'lib/lzstring.js'
  ], CLIENT);

  api.export([
    'ViewModel'
  ], CLIENT);
});

Package.onTest(function(api) {

  api.use([
    'coffeescript',
    'blaze',
    'blaze-html-templates',
    'jquery',
    'underscore',
    'tracker',
    'reload',
    'sha',
    'reactive-dict',
    'manuel:reactivearray',
    'practicalmeteor:mocha',
    'practicalmeteor:sinon'

  ], CLIENT);

  api.addFiles([
    'lib/viewmodel.coffee',
    'lib/viewmodel-parseBind.coffee',
    'lib/bindings.coffee',
    'lib/template.coffee',
    'lib/migration.coffee',
    'tests/jquery-patch.js',
    'tests/sinon-restore.js',
    'tests/bindings.coffee',
    'tests/viewmodel.coffee',
    'tests/viewmodel-instance.coffee',
    'tests/viewmodel-check.coffee',
    'tests/viewmodel-parseBind.coffee',
    'tests/template.coffee'
  ], CLIENT);

  api.export([
    'ViewModel'
  ], CLIENT);
});<|endoftext|>


<commit_before>var H5AppFS = function (system, props, updateUrl) {

    this._system = null;
    this._config = null;
    this._cacheName = 'cache';
    this._updateUrl = updateUrl;
    this.mustBeUpdated = props ? props.mustBeUpdated || false : false; //Not realized now
    this._path = {
        root: '',
        cache: ''
    };

    this._init(system)
};

//init
H5AppFS.prototype._init = function(system) {
    //alert('init');
    this._system = system;
    this._path.root = system.root.fullPath;
    this._path.cache = system.root.fullPath + this._cacheName;
    var _self = this;
    this.loadConfig();
};

H5AppFS.prototype.loadConfig = function() {
    //alert('load config');
    var _self = this;
    var request = new XMLHttpRequest();
    request.open('GET', this._updateUrl +'config.json'+ '?nocache=' + new Date().getTime());
    request.onreadystatechange = function(e) {
        if (this.readyState == 4) {
            if (this.status == 200) {
                try {
                    _self._config = JSON.parse(this.responseText);
                    _self.startUpdate();
                }
                catch (e) {
                    navigator.notification.alert('', _self.loadConfig.bind(_self), 'Something is wrong', 'Retry');
                }
            }
            else {
                navigator.notification.alert('', _self.loadConfig.bind(_self), 'No Network Connection', 'Retry');
            }
        }
    };
    request.send(null);
};

H5AppFS.prototype.startUpdate = function(callback){
    //alert('start update');
    this.check(function(err, link){
        if (!err){
            window.location.href = this._system.root.toURL() + 'cache/www/' + this._config.start;
        } else
            this.cleanCache(function(err){
                if (err){
                    navigator.notification.alert('', this.startUpdate.bind(this), 'Something is wrong', 'Retry');
                } else {
                    navigator.notification.alert('', this.startUpdate.bind(this), 'No Network Connection', 'Retry');
                }
            }.bind(this));
    }.bind(this));
};

H5AppFS.prototype.getConfig = function(){
    return this._config;
};

H5AppFS.prototype.check = function(callback){
    //alert('checkVersion');
    this.checkCache(function(entry) {
            this.checkVersion(entry,
                function(err, isUpToDate){
                    if ((err)&&(err!=null)){
                        //alert(err.code);
                        callback(true);
                    } else {
                        if (isUpToDate){
                            callback();
                        } else {
                            this.clearAndUpdate(function(err){
                                callback(err);
                            }.bind(this));
                        }
                    }
                }.bind(this)
            )}.bind(this),
        function() {
            this.copyFilesToCache(function(err){
                if ((err)&&(err!= null)){
                    callback(err)
                } else{
                    //alert('first copy succes');
                    this.check(callback);
                }
            }.bind(this));
        }.bind(this));

};

H5AppFS.prototype.clearAndUpdate = function(callback){
    this.cleanCache(function(err){
        if (err){
            callback(err);
        } else {
            this.copyFilesToCache(function(err){
                if ((err)&&(err!=null))
                    callback(err)
                else
                    this.update(callback);
            }.bind(this));
        }
    }.bind(this));
};

H5AppFS.prototype.checkVersion = function(cacheEntry, callback){
    this.checkCache(function(entry){
            //alert('check cached config');
            entry.getFile('www/config.json', {create:false}, function(fileEntry){
                    fileEntry.file(function(file){
                            var reader = new FileReader();
                            reader.onloadend = function(evt) {
                                try {
                                    callback(null, JSON.parse(evt.target.result).version === this._config.version);
                                } catch(er){
                                    //alert(er);
                                    callback({error:'json parseFail', code:111})
                                }
                            }.bind(this);
                            reader.readAsText(file);
                        }.bind(this),
                        function(err){
                            callback(err);
                        })
                }.bind(this),
                function(err){
                    callback(err);
                })
        }.bind(this),
        function(err){
            callback(err);
        });
};

H5AppFS.prototype.copyFilesToCache = function(callback){
    new _H5AppCopyer(this, callback)
};

H5AppFS.prototype.update = function(callback){
    //alert('Update');
    new _H5AppUpdater(this, callback)
};

H5AppFS.prototype.cleanCache = function(callback){
    //alert('clean cache');
    this.checkCache(function(B) {
        B.removeRecursively(function() {
            callback && callback();
        }, function(err) {
            callback && callback(err);
        })
    }, function(err) {
        callback && callback(err);
    })
};

H5AppFS.prototype.checkCache = function(callback1, callback2){
    this._system.root.getDirectory(this._cacheName, {
        create: false
    }, function(B) {
        console.log('cache file exist!');
        callback1 && callback1(B)
    }, function(err) {
        console.log('cache file not found!(clear)');
        callback2 && callback2(err)
    })
};

H5AppFS.prototype.getSystem = function() {
    return this._system
};

H5AppFS.prototype.getPath = function(key) {
    return this._path[key]
};

H5AppFS.prototype.getCacheName = function() {
    return this._cacheName
};

/*
 * Для копирования файлов
 */
var _H5AppCopyer = function(fs, callback){
    this._init(fs, callback)
};

_H5AppCopyer.prototype._init = function(fs, callback){
    this._fs = fs;
    this._callback = callback;

    var _self = this;
    _self._tryCreateCacheFile(function(err, entry){
        if ((err)&&(err != null))
            _self._callback(err);
        else
            _self._copy(entry);
    })
};

// Если нет, то папка кэша первого поколения
_H5AppCopyer.prototype._tryCreateCacheFile = function(callback){
    //alert('try create');
    var _self = this;
    _self._fs.getSystem().root.getDirectory('cache', {
        create: true
    }, function(entry) {
        callback && callback(null, entry);
    }, function(err) {
        callback && callback(err);
    })
};

_H5AppCopyer.prototype._copy = function(entry, callback){
    var _self = this;
    //alert('Try copy');
    window.resolveLocalFileSystemURI(cordova.file.applicationDirectory, function(applicationEntry){
        applicationEntry.getDirectory('www', {create:false}, function(wwwEntry){
            var oldName = 'www';
            wwwEntry.copyTo(entry, oldName, function() {
                _self._end();
            }, function(err) {
                //alert('copy file fail! err:' + err.code);
                callback(err);
            });
        }, function(err) {
            //alert('fail get application www Directory' + err.code);
            callback(err);
        });
    }, function(err){
        //alert('fail get applicationDirectory' + err.code);
        callback(err);
    })
};

_H5AppCopyer.prototype._end = function() {
    //alert('_end');
    var _self = this;
    _self._callback && _self._callback();
};

/*
 * Используется для обновления файла
 */
var _H5AppUpdater = function(fs, callback){
    this._init(fs, callback)
};

_H5AppUpdater.prototype._init = function(fs, callback) {
    this._fs = fs;
    this._callback = callback;

    this._updateUrl = fs._updateUrl;

    this._counter = 0;

    this._files = fs.getConfig().files;
    this._updateloop();
};

_H5AppUpdater.prototype._updateloop = function(){
    if (typeof this._files[this._counter] != "undefined") {
        this._write(this._files[this._counter]);
    } else {
        this._end();
    }
};

_H5AppUpdater.prototype._write = function(file_path) {

    var online_path = this._updateUrl + file_path  + '?nochache=' + Date.now();// Интернет Адрес
    var offline_path = "/cache/www/" + file_path;// Локальный путь
    //alert(offline_path);
    //alert(online_path);
    var _self = this;
    var c = function(){
        _self._fs.getSystem().root.getDirectory(_self._fs.getCacheName()+ '/www', {
            create: true
        }, function(entry) {
            _self._realWrite(online_path, entry.toURL()  + file_path, function(err){
                if (!err){
                    _self._counter++;
                    _self._updateloop();
                } else {
                    _self._end(err);
                }
            });
        }, function(err){
            //alert("cache file not found!");
            _self._end(err);
        })
    };

    _self._fs.getSystem().root.getFile(offline_path, {create:false}, function(file) {
        file.remove(function() { //Удаляем фаил если он есть
                c();
            },
            function(err){
                _self._end(err);
            });
    }, function() {
        c();
    });
};

_H5AppUpdater.prototype._realWrite = function(online_path, local_path, callback) {
    //alert('real write ' + local_path);
    var _self = this;
    var filetransfer = new FileTransfer();
    filetransfer.download(online_path, local_path, function(c) { //Скачать файл
        callback && callback();
    }, function(err){
        //alert('real write error ' + err.code);
        callback && callback(err);
    })
};

_H5AppUpdater.prototype._end = function(err) {
    //alert('end');
    if (!err) {
        this._fs.getSystem().root.getFile(this._fs.getCacheName()+ '/www/config.json', {create: false}, function(fileEntry) {
            fileEntry.createWriter(function (writer) {
                writer.onwriteend = function(evt) {
                    //alert(evt);
                    this._callback && this._callback();
                }.bind(this);
                writer.write(JSON.stringify(this._fs.getConfig()));
            }.bind(this), function(err){
                this._callback && this._callback(err);
            }.bind(this));

        }.bind(this), function(err) {
            //alert('error open config file');
            this._callback && this._callback(err);
        }.bind(this));
    } else {
        this._callback && this._callback(err);
    }
};
<commit_msg>Fix comments<commit_after>var H5AppFS = function (system, props, updateUrl) {

    this._system = null;
    this._config = null;
    this._cacheName = 'cache';
    this._updateUrl = updateUrl;
    this.mustBeUpdated = props ? props.mustBeUpdated || false : false; //Not realized now
    this._path = {
        root: '',
        cache: ''
    };

    this._init(system)
};

//init
H5AppFS.prototype._init = function(system) {
    //alert('init');
    this._system = system;
    this._path.root = system.root.fullPath;
    this._path.cache = system.root.fullPath + this._cacheName;
    var _self = this;
    this.loadConfig();
};

H5AppFS.prototype.loadConfig = function() {
    //alert('load config');
    var _self = this;
    var request = new XMLHttpRequest();
    request.open('GET', this._updateUrl +'config.json'+ '?nocache=' + new Date().getTime());
    request.onreadystatechange = function(e) {
        if (this.readyState == 4) {
            if (this.status == 200) {
                try {
                    _self._config = JSON.parse(this.responseText);
                    _self.startUpdate();
                }
                catch (e) {
                    navigator.notification.alert('', _self.loadConfig.bind(_self), 'Something is wrong', 'Retry');
                }
            }
            else {
                navigator.notification.alert('', _self.loadConfig.bind(_self), 'No Network Connection', 'Retry');
            }
        }
    };
    request.send(null);
};

H5AppFS.prototype.startUpdate = function(callback){
    //alert('start update');
    this.check(function(err, link){
        if (!err){
            window.location.href = this._system.root.toURL() + 'cache/www/' + this._config.start;
        } else
            this.cleanCache(function(err){
                if (err){
                    navigator.notification.alert('', this.startUpdate.bind(this), 'Something is wrong', 'Retry');
                } else {
                    navigator.notification.alert('', this.startUpdate.bind(this), 'No Network Connection', 'Retry');
                }
            }.bind(this));
    }.bind(this));
};

H5AppFS.prototype.getConfig = function(){
    return this._config;
};

H5AppFS.prototype.check = function(callback){
    //alert('checkVersion');
    this.checkCache(function(entry) {
            this.checkVersion(entry,
                function(err, isUpToDate){
                    if ((err)&&(err!=null)){
                        //alert(err.code);
                        callback(true);
                    } else {
                        if (isUpToDate){
                            callback();
                        } else {
                            this.clearAndUpdate(function(err){
                                callback(err);
                            }.bind(this));
                        }
                    }
                }.bind(this)
            )}.bind(this),
        function() {
            this.copyFilesToCache(function(err){
                if ((err)&&(err!= null)){
                    callback(err)
                } else{
                    //alert('first copy succes');
                    this.check(callback);
                }
            }.bind(this));
        }.bind(this));

};

H5AppFS.prototype.clearAndUpdate = function(callback){
    this.cleanCache(function(err){
        if (err){
            callback(err);
        } else {
            this.copyFilesToCache(function(err){
                if ((err)&&(err!=null))
                    callback(err)
                else
                    this.update(callback);
            }.bind(this));
        }
    }.bind(this));
};

H5AppFS.prototype.checkVersion = function(cacheEntry, callback){
    this.checkCache(function(entry){
            //alert('check cached config');
            entry.getFile('www/config.json', {create:false}, function(fileEntry){
                    fileEntry.file(function(file){
                            var reader = new FileReader();
                            reader.onloadend = function(evt) {
                                try {
                                    callback(null, JSON.parse(evt.target.result).version === this._config.version);
                                } catch(er){
                                    //alert(er);
                                    callback({error:'json parseFail', code:111})
                                }
                            }.bind(this);
                            reader.readAsText(file);
                        }.bind(this),
                        function(err){
                            callback(err);
                        })
                }.bind(this),
                function(err){
                    callback(err);
                })
        }.bind(this),
        function(err){
            callback(err);
        });
};

H5AppFS.prototype.copyFilesToCache = function(callback){
    new _H5AppCopyer(this, callback)
};

H5AppFS.prototype.update = function(callback){
    //alert('Update');
    new _H5AppUpdater(this, callback)
};

H5AppFS.prototype.cleanCache = function(callback){
    //alert('clean cache');
    this.checkCache(function(B) {
        B.removeRecursively(function() {
            callback && callback();
        }, function(err) {
            callback && callback(err);
        })
    }, function(err) {
        callback && callback(err);
    })
};

H5AppFS.prototype.checkCache = function(callback1, callback2){
    this._system.root.getDirectory(this._cacheName, {
        create: false
    }, function(B) {
        console.log('cache file exist!');
        callback1 && callback1(B)
    }, function(err) {
        console.log('cache file not found!(clear)');
        callback2 && callback2(err)
    })
};

H5AppFS.prototype.getSystem = function() {
    return this._system
};

H5AppFS.prototype.getPath = function(key) {
    return this._path[key]
};

H5AppFS.prototype.getCacheName = function() {
    return this._cacheName
};

/*
 * Files copier. Copy local files to cache.
 */
var _H5AppCopyer = function(fs, callback){
    this._init(fs, callback)
};

_H5AppCopyer.prototype._init = function(fs, callback){
    this._fs = fs;
    this._callback = callback;

    var _self = this;
    _self._tryCreateCacheFile(function(err, entry){
        if ((err)&&(err != null))
            _self._callback(err);
        else
            _self._copy(entry);
    })
};

// Try create cache folder
_H5AppCopyer.prototype._tryCreateCacheFile = function(callback){
    //alert('try create');
    var _self = this;
    _self._fs.getSystem().root.getDirectory('cache', {
        create: true
    }, function(entry) {
        callback && callback(null, entry);
    }, function(err) {
        callback && callback(err);
    })
};

_H5AppCopyer.prototype._copy = function(entry, callback){
    var _self = this;
    //alert('Try copy');
    window.resolveLocalFileSystemURI(cordova.file.applicationDirectory, function(applicationEntry){
        applicationEntry.getDirectory('www', {create:false}, function(wwwEntry){
            var oldName = 'www';
            wwwEntry.copyTo(entry, oldName, function() {
                _self._end();
            }, function(err) {
                //alert('copy file fail! err:' + err.code);
                callback(err);
            });
        }, function(err) {
            //alert('fail get application www Directory' + err.code);
            callback(err);
        });
    }, function(err){
        //alert('fail get applicationDirectory' + err.code);
        callback(err);
    })
};

_H5AppCopyer.prototype._end = function() {
    //alert('_end');
    var _self = this;
    _self._callback && _self._callback();
};

/*
 * Files updater. Copy new files from internet source to cache
 */
var _H5AppUpdater = function(fs, callback){
    this._init(fs, callback)
};

_H5AppUpdater.prototype._init = function(fs, callback) {
    this._fs = fs;
    this._callback = callback;

    this._updateUrl = fs._updateUrl;

    this._counter = 0;

    this._files = fs.getConfig().files;
    this._updateloop();
};

_H5AppUpdater.prototype._updateloop = function(){
    if (typeof this._files[this._counter] != "undefined") {
        this._write(this._files[this._counter]);
    } else {
        this._end();
    }
};

_H5AppUpdater.prototype._write = function(file_path) {

    var online_path = this._updateUrl + file_path  + '?nochache=' + Date.now();// interner path
    var offline_path = "/cache/www/" + file_path;//Local path
    //alert(offline_path);
    //alert(online_path);
    var _self = this;
    var c = function(){
        _self._fs.getSystem().root.getDirectory(_self._fs.getCacheName()+ '/www', {
            create: true
        }, function(entry) {
            _self._realWrite(online_path, entry.toURL()  + file_path, function(err){
                if (!err){
                    _self._counter++;
                    _self._updateloop();
                } else {
                    _self._end(err);
                }
            });
        }, function(err){
            //alert("cache file not found!");
            _self._end(err);
        })
    };

    _self._fs.getSystem().root.getFile(offline_path, {create:false}, function(file) {
        file.remove(function() { //remove file if exist
                c();
            },
            function(err){
                _self._end(err);
            });
    }, function() {
        c();
    });
};

_H5AppUpdater.prototype._realWrite = function(online_path, local_path, callback) {
    //alert('real write ' + local_path);
    var _self = this;
    var filetransfer = new FileTransfer();
    filetransfer.download(online_path, local_path, function(c) { //Download file
        callback && callback();
    }, function(err){
        //alert('real write error ' + err.code);
        callback && callback(err);
    })
};

_H5AppUpdater.prototype._end = function(err) {
    //alert('end');
    if (!err) {
        this._fs.getSystem().root.getFile(this._fs.getCacheName()+ '/www/config.json', {create: false}, function(fileEntry) {
            fileEntry.createWriter(function (writer) {
                writer.onwriteend = function(evt) {
                    //alert(evt);
                    this._callback && this._callback();
                }.bind(this);
                writer.write(JSON.stringify(this._fs.getConfig()));
            }.bind(this), function(err){
                this._callback && this._callback(err);
            }.bind(this));

        }.bind(this), function(err) {
            //alert('error open config file');
            this._callback && this._callback(err);
        }.bind(this));
    } else {
        this._callback && this._callback(err);
    }
};
<|endoftext|>