<commit_before>/**
 * ui module
 *
 * dependencies:
 *  config - site wide JS configuration file
 *  obs
 *  webix - webix UI
 */

define("ui", ["config", "obs", "zoomer", "aperio", "jquery", "webix"], function(config, obs, zoomer, aperio, $){

    /**
     * build()
     *
     * Create Webix UI components and create the final layout
     * which is binded into the main_layout div in index.html
     *
     * @param  {OpenSeaDragon} zoomer
     * @return {} None
     */

    var slide = null;
    var currentSlideSet = null;
    var viewer = zoomer.viewer;
    var currentItemId = null;

    function build(){
        //Thumbnail panel that contains list of thumbnails for a slide group
        thumbnailsPanel = {
            view: "dataview",
            id: "thumbnails_panel",
            select: true,
            pager: "thumbPager",
            datafetch: 10,
            loadahead: 10,
            template: "
#fileName#
",
            datatype: "json",
            type: { height: 170, width: 200},
            on: {
                "onItemClick": function(id, e, node) {
                    currentItemId = id;
                    slide = this.getItem(id);
                    $$("macro_image").refresh();
                    $$("label_image").refresh();
                    initSlide();
                },
                "onAfterLoad": function() {
                    //slide = $$("thumbnails_panel").getItem($$("thumbnails_panel").getFirstId());
                    //initSlide();
                }
            }
        };

        //dropdown for slide groups
        //Data is pulled from DAS webservice
        dropdown = {
            view:"combo",
            placeholder:"Select Slide Set",
            id: "slideset_list",
            options: config.BASE_URL +"/slidesetlist",
            value: "",
            on:{
                "onChange": function(){
                    currentSlideSet = this.getText();
                    $$("thumbnails_panel").clearAll();
                    $$("thumbnails_panel").load(config.BASE_URL +"/slideset/" + currentSlideSet);
                    $$("thumbnails_panel").setPage(0);
                }
            }
        };

        //filter slides
        filter = {
            view: "search",
            placeholder: "Search",
            on: {"onChange": filterSlides}
        };

        thumbPager = {
            view:"pager",
            id: "thumbPager",
            animate:true,
            size:10,
            group:4
        }

        //slides panel is the left panel, contains two rows
        //containing the slide group dropdown and the thumbnails panel
        slidesPanel = { header: "Slide Controls",
                        body:{rows: [
                            dropdown, filter, thumbPager, thumbnailsPanel
                        ]},
                        width: 220
                       };

        //info panel is right panel
        infoPanel = {
                    header: "Slide Info", borderless:true,
                    body:{
                        rows:[
                            {view: "template", content: "slide_info_obj", borderless:true},
                            {id: "macro_image", view: "template", borderless:true, template:
                                function(){
                                    str = "Macro image:
";
                                    if(slide != null){
                                        $.ajax({
                                            url: config.BASE_URL + "/macroimage/" + slide.id,
                                            async: false,
                                            type: "GET",
                                            success: function(){
                                                str += "";
                                            },
                                            error: function(jqXHR){
                                                resp = JSON.parse(jqXHR.responseText);
                                                str += resp.message;
                                            }
                                        });
                                    }
                                    else{
                                        str += "Macro image not loaded!";
                                    }

                                    return str;
                                }
                            },
                            {id: "label_image", view: "template", borderless:true, template:
                                function(){
                                    str = "Label image:
";
                                    if(slide != null){
                                        $.ajax({
                                            url: config.BASE_URL + "/labelimage/" + slide.id,
                                            async: false,
                                            type: "GET",
                                            success: function(){
                                                str += "";
                                            },
                                            error: function(jqXHR){
                                                resp = JSON.parse(jqXHR.responseText);
                                                str += resp.message;
                                            }
                                        });
                                    }
                                    else{
                                        str += "Label image not loaded!";
                                    }

                                    return str;
                                }
                            },
                            {view: "template", template: "",  borderless:true}
                        ]
                    },
                    width:250};

        //slide button that appear on the top if the slide
        buttons = {
            view: "segmented",
            value: "nothing",
            options:[
                { id: "apply_filter_btn", value: "Apply Filters"},
                { id: "report_img_butn", value: "Report Bad Image"},
                { id: "show_debug_btn", value: "Show Debug Info"},
                { id: "draw_tools_btn", value: "Draw Tools"},
                { id: "comment_btn", value: "Comment"},
                { id: "aperio_import_btn", value: "AperioXML"}
            ],
            on:{
                onAfterTabClick: function(id){
                    switch(id){
                        case "apply_filter_btn":
                            initFiltersWindow();
                            break;
                        case "report_img_butn":
                            reportImage();
                            break;
                        case "comment_btn":
                            initCommentWindow();
                            break;
                        case "aperio_import_btn":
                            importAperioAnnotations();
                            break;
                    }
                }
            }
        };

        //openseadragon viewer
        viewerPanel = {rows:[buttons, {view: "template", content: "image_viewer"}]};

        var menu = {
            view:"menu",
            width: 300,
            data: [
                { id:"1",value:"TCGA Resources", submenu:[
                    {value:"TCGA Analytical Tools", href: "https://tcga-data.nci.nih.gov/docs/publications/tcga/", target:"_blank"},
                ]},
                { id:"2",value:"Slide List", href: "slidelist.html", target:"_blank"},
                { id:"3",value:"Help", submenu:[
                    {value:"About the CDSA"},
                    {value:"Repository Stats"}
                ]}
            ],
            type:{height:55},
            css: "menu"
        };

        header = {borderless: true, cols: [{
            view:"toolbar", height:66, css: "toolbar",
                cols:[
                    {view: "template", borderless:true, template: "", width: 200},
                    {},
                    menu,
                    {view: "template", borderless:true, template: "", width: 160},
                ]
            }]
        };

        //the main body, below the header, contain three columns
        body = {cols:[slidesPanel,  { view: "resizer" }, viewerPanel, { view: "resizer" }, infoPanel]};

        //render the layout
        webix.ui({
            container: "main_layout",
            rows:[header, body]
        });

        //Window for inserting and viewing slide comments
        webix.ui({
            view:"window",
            head: "Slide Comments",
            position: "center",
            id: "comments_window",
            body:{
                view: "form",
                width: 400,
                elements:[
                    { view:"textarea", label:"Comment", labelAlign:"top", height: 50},
                    { margin:5, cols:[
                        { view:"button", value:"Save"},
                        { view:"button", value:"Cancel", click: ("$$('comments_window').hide();")}
                    ]}
                ]
            }
        });

        //Window for slide filters
        var contrastSlider = {
            view:"slider",
            type: "alt",
            label:"Contrast",
            value: 100,
            max: 100,
            id:"contrast_slider",
            title:webix.template("Selected: #value#"),
            on: {"onSliderDrag": applyImageFilters, "onChange": applyImageFilters}
        };

        var brightnessSlider = {
            view:"slider",
            type: "alt",
            label:"Brightness",
            value: 100,
            max: 100,
            id: "brightness_slider",
            title:webix.template("Selected: #value#"),
            on: {"onSliderDrag": applyImageFilters, "onChange": applyImageFilters}
        };

        var saturationSlider = {
            view:"slider",
            type: "alt",
            label:"Saturation",
            value: 100,
            max: 100,
            id: "saturation_slider",
            title:webix.template("Selected: #value#"),
            on: {"onSliderDrag": applyImageFilters, "onChange": applyImageFilters}
        };

        var hueSlider = {
            view:"slider",
            type: "alt",
            label:"Hue Rotate",
            value: 0,
            max: 360,
            id: "hue_rotate_slider",
            title:webix.template("Selected: #value#"),
            on: {"onSliderDrag": applyImageFilters, "onChange": applyImageFilters}
        };

        var invertSlider = {
            view:"slider",
            type: "alt",
            label:"Invert",
            value: 0,
            max: 100,
            id: "invert_slider",
            title:webix.template("Selected: #value#"),
            on: {"onSliderDrag": applyImageFilters, "onChange": applyImageFilters}
        };

        var blurSlider = {
            view:"slider",
            type: "alt",
            label:"Blur",
            value: 0,
            max: 10,
            id:"blur_slider",
            title:webix.template("Selected: #value#"),
            on: {"onSliderDrag": applyImageFilters, "onChange": applyImageFilters}
        };

        var grayscaleSlider = {
            view:"slider",
            type: "alt",
            label:"Grayscale",
            value: 0,
            max: 100,
            id:"grayscale_slider",
            title:webix.template("Selected: #value#"),
            on: {"onSliderDrag": applyImageFilters, "onChange": applyImageFilters}
        };

        webix.ui({
            view:"window",
            move:true,
            head: "Slide Filters",
            position: "center",
            id: "filters_window",
            body:{
                view: "form",
                width: 400,
                elements:[
                    contrastSlider, brightnessSlider, saturationSlider, hueSlider, invertSlider, blurSlider, grayscaleSlider,
                    { margin:5, cols:[
                        { view:"button", value:"Reset All", click: resetSliders},
                        { view:"button", value:"Close", click: ("$$('filters_window').hide();")}
                    ]}
                ]
            }
        });
    }

    function initSlide(){
        //set observable variables
        obs.slideInfoObj.name(slide.fileName);
        obs.slideInfoObj.label(slide.fileName);
        obs.slideInfoObj.slideSet(slide.slideSet);
        obs.slideInfoObj.originalResolution(slide.orig_resolution);
        obs.slideInfoObj.fileSize(slide.fileSize);

        //activate buttons
        //slide.HasAperioXML ? $$("aperio_import_btn").enable() : $$("aperio_import_btn").disable();

        tileSource = {
            width: slide.width,
            height: slide.height,
            tileWidth: 256,
            tileHeight: 256,
            getTileUrl: function(level, x, y){
                return config.BASE_URL +"/tile/"+ slide.id + "/" + level + "/" + x + "/" + y;
            }
        }

        viewer.open(tileSource);
    }

    function filterSlides(keyword){
        $$("thumbnails_panel").clearAll();
        $$("thumbnails_panel").load(config.BASE_URL +"/slideset/" + currentSlideSet + "?filter[fileName]=" + keyword);
        $$("thumbnails_panel").setPage(0);
    }

    function resetSliders(){
        $$("contrast_slider").setValue(100);
        $$("brightness_slider").setValue(100);
        $$("saturation_slider").setValue(100);
        $$("hue_rotate_slider").setValue(0);
        $$("invert_slider").setValue(0);
        $$("blur_slider").setValue(0);
        $$("grayscale_slider").setValue(0);

        applyImageFilters();
    }

    function applyImageFilters(){
        var css = 'contrast(' + $$("contrast_slider").getValue() + '%) ' +
                  'brightness(' + $$("brightness_slider").getValue() + '%) ' +
                  'hue-rotate(' + $$("hue_rotate_slider").getValue() + ') ' +
                  'saturate(' + $$("saturation_slider").getValue() + '%) ' +
                  'invert(' + $$("invert_slider").getValue() + '%) ' +
                  'grayscale(' + $$("grayscale_slider").getValue() + '%) ' +
                  'blur(' + $$("blur_slider").getValue() + 'px)';

        $('.magic').css('-webkit-filter', css);
        $('.openseadragon-canvas').css('-webkit-filter', css);
    }

    function initFiltersWindow(){
        $$("filters_window").show();
    }

    function initCommentWindow(){
        $$("comments_window").show();
    }

    function importAperioAnnotations(){
        aperio.importMarkups("http://node15.cci.emory.edu/LGG_LiveDev/XML_FILES/TCGA-06-0137-01A-01-BS1.xml");
    }

    function reportImage(){
        data = JSON.stringify({"bad": true});
        url = config.BASE_URL + "/slide/" + slide.id;
        $.ajax({
            url: url,
            type: "PUT",
            contentType: "application/json",
            dataType: "json",
            data: data,
            success: function(response) {
                slide = response;
                $$("thumbnails_panel").remove(currentItemId);
            }
        });
    }

    return{
        build: build
    }
});
<commit_msg>remove slide from thumbnail view if marked as bad<commit_after>/**
 * ui module
 *
 * dependencies:
 *  config - site wide JS configuration file
 *  obs
 *  webix - webix UI
 */

define("ui", ["config", "obs", "zoomer", "aperio", "jquery", "webix"], function(config, obs, zoomer, aperio, $){

    /**
     * build()
     *
     * Create Webix UI components and create the final layout
     * which is binded into the main_layout div in index.html
     *
     * @param  {OpenSeaDragon} zoomer
     * @return {} None
     */

    var slide = null;
    var currentSlideSet = null;
    var viewer = zoomer.viewer;
    var currentItemId = null;

    function build(){
        //Thumbnail panel that contains list of thumbnails for a slide group
        thumbnailsPanel = {
            view: "dataview",
            id: "thumbnails_panel",
            select: true,
            pager: "thumbPager",
            datafetch: 10,
            loadahead: 10,
            template: "
#fileName#
",
            datatype: "json",
            type: { height: 170, width: 200},
            on: {
                "onItemClick": function(id, e, node) {
                    currentItemId = id;
                    slide = this.getItem(id);
                    $$("macro_image").refresh();
                    $$("label_image").refresh();
                    initSlide();
                },
                "onAfterLoad": function() {
                    //slide = $$("thumbnails_panel").getItem($$("thumbnails_panel").getFirstId());
                    //initSlide();
                }
            }
        };

        //dropdown for slide groups
        //Data is pulled from DAS webservice
        dropdown = {
            view:"combo",
            placeholder:"Select Slide Set",
            id: "slideset_list",
            options: config.BASE_URL +"/slidesetlist",
            value: "",
            on:{
                "onChange": function(){
                    currentSlideSet = this.getText();
                    $$("thumbnail_search").setValue("");
                    $$("thumbnails_panel").clearAll();
                    $$("thumbnails_panel").load(config.BASE_URL +"/slideset/" + currentSlideSet);
                    $$("thumbnails_panel").setPage(0);
                }
            }
        };

        //filter slides
        filter = {
            view: "search",
            id: "thumbnail_search",
            placeholder: "Search",
            on: {"onChange": filterSlides}
        };

        thumbPager = {
            view:"pager",
            id: "thumbPager",
            animate:true,
            size:10,
            group:4
        }

        //slides panel is the left panel, contains two rows
        //containing the slide group dropdown and the thumbnails panel
        slidesPanel = { header: "Slide Controls",
                        body:{rows: [
                            dropdown, filter, thumbPager, thumbnailsPanel
                        ]},
                        width: 220
                       };

        //info panel is right panel
        infoPanel = {
                    header: "Slide Info", borderless:true,
                    body:{
                        rows:[
                            {view: "template", content: "slide_info_obj", borderless:true},
                            {id: "macro_image", view: "template", borderless:true, template:
                                function(){
                                    str = "Macro image:
";
                                    if(slide != null){
                                        $.ajax({
                                            url: config.BASE_URL + "/macroimage/" + slide.id,
                                            async: false,
                                            type: "GET",
                                            success: function(){
                                                str += "";
                                            },
                                            error: function(jqXHR){
                                                resp = JSON.parse(jqXHR.responseText);
                                                str += resp.message;
                                            }
                                        });
                                    }
                                    else{
                                        str += "Macro image not loaded!";
                                    }

                                    return str;
                                }
                            },
                            {id: "label_image", view: "template", borderless:true, template:
                                function(){
                                    str = "Label image:
";
                                    if(slide != null){
                                        $.ajax({
                                            url: config.BASE_URL + "/labelimage/" + slide.id,
                                            async: false,
                                            type: "GET",
                                            success: function(){
                                                str += "";
                                            },
                                            error: function(jqXHR){
                                                resp = JSON.parse(jqXHR.responseText);
                                                str += resp.message;
                                            }
                                        });
                                    }
                                    else{
                                        str += "Label image not loaded!";
                                    }

                                    return str;
                                }
                            },
                            {view: "template", template: "",  borderless:true}
                        ]
                    },
                    width:250};

        //slide button that appear on the top if the slide
        buttons = {
            view: "segmented",
            value: "nothing",
            options:[
                { id: "apply_filter_btn", value: "Apply Filters"},
                { id: "report_img_butn", value: "Report Bad Image"},
                { id: "show_debug_btn", value: "Show Debug Info"},
                { id: "draw_tools_btn", value: "Draw Tools"},
                { id: "comment_btn", value: "Comment"},
                { id: "aperio_import_btn", value: "AperioXML"}
            ],
            on:{
                onAfterTabClick: function(id){
                    switch(id){
                        case "apply_filter_btn":
                            initFiltersWindow();
                            break;
                        case "report_img_butn":
                            reportImage();
                            break;
                        case "comment_btn":
                            initCommentWindow();
                            break;
                        case "aperio_import_btn":
                            importAperioAnnotations();
                            break;
                    }
                }
            }
        };

        //openseadragon viewer
        viewerPanel = {rows:[buttons, {view: "template", content: "image_viewer"}]};

        var menu = {
            view:"menu",
            width: 300,
            data: [
                { id:"1",value:"TCGA Resources", submenu:[
                    {value:"TCGA Analytical Tools", href: "https://tcga-data.nci.nih.gov/docs/publications/tcga/", target:"_blank"},
                ]},
                { id:"2",value:"Slide List", href: "slidelist.html", target:"_blank"},
                { id:"3",value:"Help", submenu:[
                    {value:"About the CDSA"},
                    {value:"Repository Stats"}
                ]}
            ],
            type:{height:55},
            css: "menu"
        };

        header = {borderless: true, cols: [{
            view:"toolbar", height:66, css: "toolbar",
                cols:[
                    {view: "template", borderless:true, template: "", width: 200},
                    {},
                    menu,
                    {view: "template", borderless:true, template: "", width: 160},
                ]
            }]
        };

        //the main body, below the header, contain three columns
        body = {cols:[slidesPanel,  { view: "resizer" }, viewerPanel, { view: "resizer" }, infoPanel]};

        //render the layout
        webix.ui({
            container: "main_layout",
            rows:[header, body]
        });

        //Window for inserting and viewing slide comments
        webix.ui({
            view:"window",
            head: "Slide Comments",
            position: "center",
            id: "comments_window",
            body:{
                view: "form",
                width: 400,
                elements:[
                    { view:"textarea", label:"Comment", labelAlign:"top", height: 50},
                    { margin:5, cols:[
                        { view:"button", value:"Save"},
                        { view:"button", value:"Cancel", click: ("$$('comments_window').hide();")}
                    ]}
                ]
            }
        });

        //Window for slide filters
        var contrastSlider = {
            view:"slider",
            type: "alt",
            label:"Contrast",
            value: 100,
            max: 100,
            id:"contrast_slider",
            title:webix.template("Selected: #value#"),
            on: {"onSliderDrag": applyImageFilters, "onChange": applyImageFilters}
        };

        var brightnessSlider = {
            view:"slider",
            type: "alt",
            label:"Brightness",
            value: 100,
            max: 100,
            id: "brightness_slider",
            title:webix.template("Selected: #value#"),
            on: {"onSliderDrag": applyImageFilters, "onChange": applyImageFilters}
        };

        var saturationSlider = {
            view:"slider",
            type: "alt",
            label:"Saturation",
            value: 100,
            max: 100,
            id: "saturation_slider",
            title:webix.template("Selected: #value#"),
            on: {"onSliderDrag": applyImageFilters, "onChange": applyImageFilters}
        };

        var hueSlider = {
            view:"slider",
            type: "alt",
            label:"Hue Rotate",
            value: 0,
            max: 360,
            id: "hue_rotate_slider",
            title:webix.template("Selected: #value#"),
            on: {"onSliderDrag": applyImageFilters, "onChange": applyImageFilters}
        };

        var invertSlider = {
            view:"slider",
            type: "alt",
            label:"Invert",
            value: 0,
            max: 100,
            id: "invert_slider",
            title:webix.template("Selected: #value#"),
            on: {"onSliderDrag": applyImageFilters, "onChange": applyImageFilters}
        };

        var blurSlider = {
            view:"slider",
            type: "alt",
            label:"Blur",
            value: 0,
            max: 10,
            id:"blur_slider",
            title:webix.template("Selected: #value#"),
            on: {"onSliderDrag": applyImageFilters, "onChange": applyImageFilters}
        };

        var grayscaleSlider = {
            view:"slider",
            type: "alt",
            label:"Grayscale",
            value: 0,
            max: 100,
            id:"grayscale_slider",
            title:webix.template("Selected: #value#"),
            on: {"onSliderDrag": applyImageFilters, "onChange": applyImageFilters}
        };

        webix.ui({
            view:"window",
            move:true,
            head: "Slide Filters",
            position: "center",
            id: "filters_window",
            body:{
                view: "form",
                width: 400,
                elements:[
                    contrastSlider, brightnessSlider, saturationSlider, hueSlider, invertSlider, blurSlider, grayscaleSlider,
                    { margin:5, cols:[
                        { view:"button", value:"Reset All", click: resetSliders},
                        { view:"button", value:"Close", click: ("$$('filters_window').hide();")}
                    ]}
                ]
            }
        });
    }

    function initSlide(){
        //set observable variables
        obs.slideInfoObj.name(slide.fileName);
        obs.slideInfoObj.label(slide.fileName);
        obs.slideInfoObj.slideSet(slide.slideSet);
        obs.slideInfoObj.originalResolution(slide.orig_resolution);
        obs.slideInfoObj.fileSize(slide.fileSize);

        //activate buttons
        //slide.HasAperioXML ? $$("aperio_import_btn").enable() : $$("aperio_import_btn").disable();

        tileSource = {
            width: slide.width,
            height: slide.height,
            tileWidth: 256,
            tileHeight: 256,
            getTileUrl: function(level, x, y){
                return config.BASE_URL +"/tile/"+ slide.id + "/" + level + "/" + x + "/" + y;
            }
        }

        viewer.open(tileSource);
    }

    function filterSlides(keyword){
        $$("thumbnails_panel").clearAll();
        $$("thumbnails_panel").load(config.BASE_URL +"/slideset/" + currentSlideSet + "?filter[fileName]=" + keyword);
        $$("thumbnails_panel").setPage(0);
    }

    function resetSliders(){
        $$("contrast_slider").setValue(100);
        $$("brightness_slider").setValue(100);
        $$("saturation_slider").setValue(100);
        $$("hue_rotate_slider").setValue(0);
        $$("invert_slider").setValue(0);
        $$("blur_slider").setValue(0);
        $$("grayscale_slider").setValue(0);

        applyImageFilters();
    }

    function applyImageFilters(){
        var css = 'contrast(' + $$("contrast_slider").getValue() + '%) ' +
                  'brightness(' + $$("brightness_slider").getValue() + '%) ' +
                  'hue-rotate(' + $$("hue_rotate_slider").getValue() + ') ' +
                  'saturate(' + $$("saturation_slider").getValue() + '%) ' +
                  'invert(' + $$("invert_slider").getValue() + '%) ' +
                  'grayscale(' + $$("grayscale_slider").getValue() + '%) ' +
                  'blur(' + $$("blur_slider").getValue() + 'px)';

        $('.magic').css('-webkit-filter', css);
        $('.openseadragon-canvas').css('-webkit-filter', css);
    }

    function initFiltersWindow(){
        $$("filters_window").show();
    }

    function initCommentWindow(){
        $$("comments_window").show();
    }

    function importAperioAnnotations(){
        aperio.importMarkups("http://node15.cci.emory.edu/LGG_LiveDev/XML_FILES/TCGA-06-0137-01A-01-BS1.xml");
    }

    function reportImage(){
        data = JSON.stringify({"bad": true});
        url = config.BASE_URL + "/slide/" + slide.id;
        $.ajax({
            url: url,
            type: "PUT",
            contentType: "application/json",
            dataType: "json",
            data: data,
            success: function(response) {
                slide = response;
                $$("thumbnails_panel").remove(currentItemId);
            }
        });
    }

    return{
        build: build
    }
});
<|endoftext|>


<commit_before>angular.module('copayApp.controllers').controller('paperWalletController',
  function($scope, $http, $timeout, $log, configService, profileService, go, addressService, bitcore) {
    self = this;
    var fc = profileService.focusedClient;
    var rawTx;

    self.onQrCodeScanned = function(data) {
      $scope.inputData = data;
      self.onData(data);
    }

    self.onData = function(data) {
      self.error = '';
      self.scannedKey = data;
      self.isPkEncrypted = (data.charAt(0) == '6');
    }

    self._scanFunds = function(cb) {
      function getPrivateKey(scannedKey, isPkEncrypted, passphrase, cb) {
        if (!isPkEncrypted) return cb(null, scannedKey);
        fc.decryptBIP38PrivateKey(scannedKey, passphrase, null, cb);
      };

      function getBalance(privateKey, cb) {
        fc.getBalanceFromPrivateKey(privateKey, cb);
      };

      function checkPrivateKey(privateKey) {
        try {
          new bitcore.PrivateKey(privateKey, 'livenet');
        } catch (err) {
          return false;
        }
        return true;
      }

      getPrivateKey(self.scannedKey, self.isPkEncrypted, $scope.passphrase, function(err, privateKey) {
        if (err) return cb(err);
        if (!checkPrivateKey(privateKey)) return cb(new Error('Invalid private key'));

        getBalance(privateKey, function(err, balance) {
          if (err) return cb(err);
          return cb(null, privateKey, balance);
        });
      });
    }

    self.scanFunds = function() {
      self.scanning = true;
      self.privateKey = '';
      self.balanceSat = 0;
      self.error = '';

      $timeout(function() {
        self._scanFunds(function(err, privateKey, balance) {
          if (err) {
            $log.error(err);
            self.error = err.message || err.toString();
          } else {
            self.privateKey = privateKey;
            self.balanceSat = balance;
            var config = configService.getSync().wallet.settings;
            self.balance = profileService.formatAmount(balance) + ' ' + config.unitName;
          }

          self.scanning = false;
          $timeout(function() {
            $scope.$apply();
          }, 1);
        });
      }, 100);
    }

    self._sweepWallet = function(cb) {
      addressService.getAddress(fc.credentials.walletId, true, function(err, destinationAddress) {
        if (err) return cb(err);

        fc.buildTxFromPrivateKey(self.privateKey, destinationAddress, null, function(err, tx) {
          if (err) return cb(err);

          fc.broadcastRawTx({
            rawTx: tx.serialize(),
            network: 'livenet'
          }, function(err, txid) {
            if (err) return cb(err);
            return cb(null, destinationAddress, txid);
          });
        });
      });
    };

    self.sweepWallet = function() {
      self.sending = true;
      self.error = '';

      $timeout(function() {
        self._sweepWallet(function(err, destinationAddress, txid) {
          if (err) {
            self.error = err.message || err.toString();
            $log.error(err);
          }
          self.sending = false;
          $timeout(function() {
            $scope.$apply();
            if (!err) go.walletHome();
          }, 1);
        });
      }, 100);
    }
  });
<commit_msg>add feedback print after sweep funds<commit_after>angular.module('copayApp.controllers').controller('paperWalletController',
  function($scope, $http, $timeout, $log, configService, profileService, go, addressService, txStatus, bitcore) {
    self = this;
    var fc = profileService.focusedClient;
    var rawTx;

    self.onQrCodeScanned = function(data) {
      $scope.inputData = data;
      self.onData(data);
    }

    self.onData = function(data) {
      self.error = '';
      self.scannedKey = data;
      self.isPkEncrypted = (data.charAt(0) == '6');
    }

    self._scanFunds = function(cb) {
      function getPrivateKey(scannedKey, isPkEncrypted, passphrase, cb) {
        if (!isPkEncrypted) return cb(null, scannedKey);
        fc.decryptBIP38PrivateKey(scannedKey, passphrase, null, cb);
      };

      function getBalance(privateKey, cb) {
        fc.getBalanceFromPrivateKey(privateKey, cb);
      };

      function checkPrivateKey(privateKey) {
        try {
          new bitcore.PrivateKey(privateKey, 'livenet');
        } catch (err) {
          return false;
        }
        return true;
      }

      getPrivateKey(self.scannedKey, self.isPkEncrypted, $scope.passphrase, function(err, privateKey) {
        if (err) return cb(err);
        if (!checkPrivateKey(privateKey)) return cb(new Error('Invalid private key'));

        getBalance(privateKey, function(err, balance) {
          if (err) return cb(err);
          return cb(null, privateKey, balance);
        });
      });
    }

    self.scanFunds = function() {
      self.scanning = true;
      self.privateKey = '';
      self.balanceSat = 0;
      self.error = '';

      $timeout(function() {
        self._scanFunds(function(err, privateKey, balance) {
          self.scanning = false;
          if (err) {
            $log.error(err);
            self.error = err.message || err.toString();
          } else {
            self.privateKey = privateKey;
            self.balanceSat = balance;
            var config = configService.getSync().wallet.settings;
            self.balance = profileService.formatAmount(balance) + ' ' + config.unitName;
          }

          $scope.$apply();
        });
      }, 100);
    }

    self._sweepWallet = function(cb) {
      addressService.getAddress(fc.credentials.walletId, true, function(err, destinationAddress) {
        if (err) return cb(err);

        fc.buildTxFromPrivateKey(self.privateKey, destinationAddress, null, function(err, tx) {
          if (err) return cb(err);

          fc.broadcastRawTx({
            rawTx: tx.serialize(),
            network: 'livenet'
          }, function(err, txid) {
            if (err) return cb(err);
            return cb(null, destinationAddress, txid);
          });
        });
      });
    };

    self.sweepWallet = function() {
      self.sending = true;
      self.error = '';

      $timeout(function() {
        self._sweepWallet(function(err, destinationAddress, txid) {
          self.sending = false;

          if (err) {
            self.error = err.message || err.toString();
            $log.error(err);
          } else {
            txStatus.notify({
              status: 'broadcasted'
            }, function() {
              go.walletHome();
            });
          }

          $scope.$apply();
        });
      }, 100);
    }
  });
<|endoftext|>


<commit_before>if (typeof define !== 'function') { var define = require('amdefine')(module) }

define([
  'react',
  'moment',
  './nicknamelist',
  './color',
  './inputbox'
], function(React, moment, NicknameList, Color, InputBox, undefined) {

  // TODO: transform opacity when adding a new buffer line

  var Buffer = React.createClass({

    displayName: 'Buffer',

    getInitialState: function () {
      return {messages: this.props.buffer.messages,
              nicknamelist: []};
    },

    // see http://blog.vjeux.com/2013/javascript/scroll-position-with-react.html
    componentWillUpdate: function() {
      var node = this.getDOMNode().getElementsByClassName('buffer-messages')[0];
      this.shouldScrollBottom = node.scrollTop + node.offsetHeight === node.scrollHeight;
    },

    componentDidUpdate: function() {
      if (this.shouldScrollBottom) {
        var node = this.getDOMNode().getElementsByClassName('buffer-messages')[0];
        node.scrollTop = node.scrollHeight;
      }
    },

    render: function() {
      var buffer = this.props.buffer,
          self = this,
          name = buffer.info.short_name;
      // TODO: when updating topic, short_name has a funny name
      return React.DOM.div({ className: this.props.isActive ? " buffer-active" : "buffer-unactive" }, [
          React.DOM.div({className: "list-group col-lg-10"}, [
            React.DOM.h3({key: 'title',
                          className: 'buffer-title',
                          style: this.props.layout.bufferTitle || {},
                          dangerouslySetInnerHTML: {__html: Color.format(name + ": " + buffer.info.title)}}),
            React.DOM.ul({key: "listgroup",
                          className: 'buffer-messages',
                          style: this.props.layout.buffer || {}},
               buffer.messages.map(function (message) {
                   return React.DOM.li({className: "list-group-item row" + (message.highlight === 1 ? " list-group-item-info" : ""),
                                        key: message.pointers.join(" ")}, [
                       React.DOM.div({className: "col-xs-6 col-sm-1 message-date text-muted", key: "date"},
                                     moment.unix(message.date).format('hh:mm:ss')),
                       React.DOM.div({className: "col-xs-6 col-sm-2 message-prefix " + (message.tags_array.indexOf("irc_privmsg") === -1 ? "text-muted" : "text-primary"),
                                      key: "prefix",
                                      dangerouslySetInnerHTML: {__html: Color.format(message.prefix)}}),
                       React.DOM.div({className: "col-xs-12 col-sm-9 message-text " + (message.tags_array.indexOf("irc_privmsg") === -1 ? "text-muted" : ""),
                                      key: "message",
                                      dangerouslySetInnerHTML: {__html: Color.format(message.message)}}
                       )
                   ]);
               })
            ),
            InputBox({nicklist: this.props.buffer.nicklist,
                      layout: this.props.layout,
                      handleSubmit: this.props.sendInputConstructor(this.props.buffer.info.pointers[0])})
          ]),
          NicknameList({
            nicklist: this.props.buffer.nicklist,
            layout: this.props.layout
          })
        ]);
    }

  });

  return Buffer;

});
<commit_msg>missing line<commit_after>if (typeof define !== 'function') { var define = require('amdefine')(module) }

define([
  'react',
  'moment',
  './nicknamelist',
  './color',
  './inputbox'
], function(React, moment, NicknameList, Color, InputBox, undefined) {

  // TODO: transform opacity when adding a new buffer line

  var Buffer = React.createClass({

    displayName: 'Buffer',

    getInitialState: function () {
      return {messages: this.props.buffer.messages,
              nicknamelist: []};
    },

    // see http://blog.vjeux.com/2013/javascript/scroll-position-with-react.html
    componentWillUpdate: function() {
      var node = this.getDOMNode().getElementsByClassName('buffer-messages')[0];
      this.shouldScrollBottom = node.scrollTop + node.offsetHeight === node.scrollHeight;
    },

    componentDidUpdate: function() {
      if (this.shouldScrollBottom) {
        var node = this.getDOMNode().getElementsByClassName('buffer-messages')[0];
        node.scrollTop = node.scrollHeight;
      }
    },

    render: function() {
      var buffer = this.props.buffer,
          self = this,
          name = buffer.info.short_name;
      // TODO: when updating topic, short_name has a funny name
      return React.DOM.div({ className: this.props.isActive ? " buffer-active" : "buffer-unactive" }, [
          React.DOM.div({className: "list-group col-lg-10"}, [
            React.DOM.h3({key: 'title',
                          className: 'buffer-title',
                          style: this.props.layout.bufferTitle || {},
                          dangerouslySetInnerHTML: {__html: Color.format(name + ": " + buffer.info.title)}}),
            React.DOM.ul({key: "listgroup",
                          className: 'buffer-messages',
                          style: this.props.layout.buffer || {}},
               buffer.messages.map(function (message) {
                   return React.DOM.li({className: "list-group-item row" + (message.highlight === 1 ? " list-group-item-info" : ""),
                                        key: message.pointers.join(" ")}, [
                       React.DOM.div({className: "col-xs-6 col-sm-1 message-date text-muted", key: "date"},
                                     moment.unix(message.date).format('hh:mm:ss')),
                       React.DOM.div({className: "col-xs-6 col-sm-2 message-prefix " + (message.tags_array.indexOf("irc_privmsg") === -1 ? "text-muted" : "text-primary"),
                                      key: "prefix",
                                      dangerouslySetInnerHTML: {__html: Color.format(message.prefix)}}),
                       React.DOM.div({className: "col-xs-12 col-sm-9 message-text " + (message.tags_array.indexOf("irc_privmsg") === -1 ? "text-muted" : ""),
                                      key: "message",
                                      dangerouslySetInnerHTML: {__html: Color.format(message.message)}}
                       )
                   ]);
               })
            ),
            InputBox({nicklist: this.props.buffer.nicklist,
                      layout: this.props.layout,
                      handleSubmit: this.props.sendInputConstructor(this.props.buffer.info.pointers[0])})
          ]),
          NicknameList({
            nicklist: this.props.buffer.nicklist,
            layout: this.props.layout,
            sendInput: this.props.sendInputConstructor(this.props.buffer.info.pointers[0])
          })
        ]);
    }

  });

  return Buffer;

});
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2013-2017 Memba Sarl. All rights reserved.
 * Sources at https://github.com/Memba
 */

/* jshint browser: true, jquery: true */
/* globals define: false */

(function (f, define) {
    'use strict';
    define([
        './vendor/markdown-it/markdown-it',
        './vendor/markdown-it/markdown-it-katex', // This loads katex
        './vendor/markdown-it/markdown-it-emoji',
        './vendor/highlight/highlight.pack',
        './vendor/markdown-it/twemoji.amd',
        // Keep the above at the top considering function parameters below
        './window.assert',
        './window.logger',
        './vendor/kendo/kendo.binder'
    ], f);
})(function (markdown, katex, emoji, highlight, twemo) {

    'use strict';

    (function ($, undefined) {

        var kendo = window.kendo;
        var Widget = kendo.ui.Widget;
        var MarkdownIt = window.markdownit || markdown;
        var markdownItKatex = window.markdownItKatex || katex;
        var markdownitEmoji = window.markdownitEmoji || emoji;
        var hljs = window.hljs || highlight;
        var twemoji = window.twemoji || twemo;
        var assert = window.assert;
        var logger = new window.Logger('kidoju.widgets.markdown');
        var STRING = 'string';
        var NULL = 'null';
        var UNDEFINED = 'undefined';
        var EMPTY = '';
        var WIDGET_CLASS = 'kj-markdown'; // 'k-widget kj-markdown';
        var RX_YML = /^---\n([\s\S]*)\n---/;
        var RX_KEYVAL = /([^:\n]+):([^\n]+)/g;
        var KEY_BLACKLIST = /[-\s]/g;
        var SCRIPT_SELECTOR = 'script[type="text/plain"]';
        var SCRIPT_TAG = '';
        var WRAP_TAG = '<wrap></wrap>';

        /*********************************************************************************
         * Helpers
         * See https://github.com/Memba/Memba-Blog/blob/master/webapp/lib/markdown.js#L60
         *********************************************************************************/

        /**
         * Return the yml metadata in value
         * @param content
         */
        function head(content) {
            var yml = {};
            var ymlMatches = content.match(RX_YML);
            if ($.isArray(ymlMatches) && ymlMatches.length > 1) {
                var keyvalMatches = ymlMatches[1].match(RX_KEYVAL);
                if ($.isArray(keyvalMatches) && keyvalMatches.length) {
                    for (var i = 0; i < keyvalMatches.length; i++) {
                        var keyval = keyvalMatches[i];
                        var pos = keyval.indexOf(':');
                        var key = keyval.substr(0, pos).trim().replace(KEY_BLACKLIST, '_');
                        var val = keyval.substr(pos + 1).trim();
                        yml[key] = val;
                    }
                }
            }
            return yml;
        }

        /**
         * Returns the markdown content in value
         * @param content
         */
        function body(content) {
            return content.replace(RX_YML, EMPTY).trim();
        }

        /*********************************************************************************
         * Widget
         *********************************************************************************/

        /**
         * Markdown
         * @class Markdown Widget (kendoMarkdown)
         */
        var Markdown = Widget.extend({

            /**
             * Initializes the widget
             * @param element
             * @param options
             */
            init: function (element, options) {
                var that = this;
                options = options || {};
                Widget.fn.init.call(that, element, options);
                logger.debug({ method: 'init', message: 'widget initialized' });
                that._initMarkdownIt();
                that._layout();
                kendo.notify(that);
            },

            /**
             * Widget options
             * @property options
             */
            options: {
                name: 'Markdown',
                url: null,
                value: null,
                schemes: {}
            },

            /**
             * Value for MVVM binding
             * Returns either a JS function as a string or a library formula name prefixed as a Javascript comment
             * @param value
             */
            value: function (value) {
                var that = this;
                if ($.type(value) === STRING || $.type(value) === NULL) {
                    if (that._value !== value) {
                        that._value = value;
                        that.refresh();
                    }
                } else if ($.type(value) === UNDEFINED) {
                    if ($.type(that._value) === STRING || $.type(that._value) === NULL) {
                        return that._value;
                    } else {
                        return undefined;
                    }
                } else {
                    throw new TypeError('`value` is expected to be a string if not undefined');
                }
            },

            /**
             * Initialize markdown-it
             * @private
             */
            _initMarkdownIt: function () {
                var that = this;

                // Initialize MarkdownIt
                that.md = new MarkdownIt({
                    html: false,
                    linkify: true,
                    typographer: true,
                    // See https://github.com/markdown-it/markdown-it#syntax-highlighting
                    highlight: function (code, lang) {
                        try {
                            return hljs.highlight(lang, code).value;
                        } catch (err) {
                            return hljs.highlightAuto(code).value;
                        }
                    }
                });

                // Initialize renderers
                that._initHljs();
                that._initLinkOpener();
                that._initImageRule();
                that._initKatex();
                that._initEmojis();
            },

            /**
             * Init Highligh.js
             * Adds hljs class to the pre tag
             * @see https://github.com/markdown-it/markdown-it/blob/88c6e0f8e6fd567c70ffabbc1e9ce7b980d2e3a9/support/demo_template/index.js#L94
             * @private
             */
            _initHljs: function () {
                var that = this;
                that.md.renderer.rules.fence = function (tokens, idx, options, env, self) {
                    var escapeHtml = that.md.utils.escapeHtml;
                    var unescapeAll = that.md.utils.unescapeAll;
                    var token = tokens[idx];
                    var info = token.info ? unescapeAll(token.info).trim() : '';
                    var langName = '';
                    var highlighted;
                    if (info) {
                        langName = info.split(/\s+/g)[0];
                        token.attrPush(['class', options.langPrefix + langName]);
                    }
                    if (options.highlight) {
                        highlighted = options.highlight(token.content, langName) || escapeHtml(token.content);
                    } else {
                        highlighted = escapeHtml(token.content);
                    }
                    return '
' + highlighted  + '
\n';
                };
            },

            /**
             * Initialize link opener to open links in new window
             * @see https://github.com/markdown-it/markdown-it/blob/master/docs/architecture.md#renderer
             * @private
             */
            _initLinkOpener: function () {
                var that = this;
                /* jscs: disable requireCamelCaseOrUpperCaseIdentifiers */
                var defaultRender = that.md.renderer.rules.link_open || function (tokens, idx, options, env, self) {
                        return self.renderToken(tokens, idx, options);
                    };
                that.md.renderer.rules.link_open = function (tokens, idx, options, env, self) {
                    // If you are sure other plugins can't add `target` - drop check below
                    var targetIndex = tokens[idx].attrIndex('target');
                    if (targetIndex < 0) {
                        // @see https://cordova.apache.org/docs/en/3.1.0/cordova/inappbrowser/window.open.html
                        tokens[idx].attrPush(['target', window.cordova ? '_system' : '_blank']); // add new attribute
                    } else {
                        tokens[idx].attrs[targetIndex][1] = window.cordova ? '_system' : '_blank'; // replace value of existing attr
                    }
                    // same with rel - see https://mathiasbynens.github.io/rel-noopener/
                    var relIndex = tokens[idx].attrIndex('rel');
                    if (relIndex < 0) {
                        tokens[idx].attrPush(['rel', 'noopener']); // add new attribute
                    } else {
                        tokens[idx].attrs[relIndex][1] = 'noopener'; // replace value of existing attr
                    }
                    // pass token to default renderer.
                    return defaultRender(tokens, idx, options, env, self);
                };
                /* jscs: enable requireCamelCaseOrUpperCaseIdentifiers */
            },

            /**
             * Init the image rule
             * Adds the .img-responsive class to all images
             * @see https://github.com/markdown-it/markdown-it/blob/master/docs/architecture.md
             * @private
             */
            _initImageRule: function () {
                var that = this;
                var defaultRender = that.md.renderer.rules.image || function (tokens, idx, options, env, self) {
                        return self.renderToken(tokens, idx, options);
                    };
                that.md.renderer.rules.image = function (tokens, idx, options, env, slf) {
                    // Replace schemes
                    var srcIndex = tokens[idx].attrIndex('src');
                    var src = tokens[idx].attrs[srcIndex][1];
                    var schemes = that.options.schemes;
                    for (var scheme in (schemes || {})) {
                        if (schemes.hasOwnProperty(scheme) && (new RegExp('^' + scheme + '://')).test(src)) {
                            src = src.replace(scheme + '://', schemes[scheme]);
                            break;
                        }
                    }
                    tokens[idx].attrs[srcIndex][1] = src;

                    // Add img-responsive class
                    var classIndex = tokens[idx].attrIndex('class');
                    // If you are sure other plugins can't add `class` - drop check below
                    if (classIndex < 0) {
                        tokens[idx].attrPush(['class', 'img-responsive']); // add new attribute
                    } else {
                        tokens[idx].attrs[classIndex][1] = 'img-responsive'; // replace value of existing attr
                    }
                    // pass token to default renderer.
                    return defaultRender(tokens, idx, options, env, slf);
                };
            },

            /**
             * Init Katex
             * @private
             */
            _initKatex: function () {
                if (markdownItKatex) {
                    this.md.use(markdownItKatex);
                }
            },

            /**
             * Init Emojis
             * @private
             */
            _initEmojis: function () {
                if (markdownitEmoji) {
                    this.md.use(markdownitEmoji);
                }
                // use much nicer twemojis
                if (twemoji) {
                    this.md.renderer.rules.emoji = function(token, idx) {
                        return twemoji.parse(token[idx].content);
                    };
                }
            },

            /**
             * Builds the widget layout
             * @private
             */
            _layout: function () {
                var that = this;
                var options = that.options;
                that.wrapper = that.element;
                that.element.addClass(WIDGET_CLASS);
                if ($.type(options.url) === STRING) {
                    that.url(options.url);
                } else if ($.type(options.value) === STRING) {
                    that.value(options.value);
                } else {
                    that.inline();
                }
            },

            /**
             * Reads the markdown text in an inline script
             * @method _inline
             * @private
             */
            inline: function () {
                var that = this;
                var element = that.element;
                var inline = element.find(SCRIPT_SELECTOR);
                if (inline.length) {
                    that.value(inline.text());
                }
            },

            /**
             * Reads the markdown text from a url
             * @param url
             */
            url: function (url) {
                var that = this;
                if ($.type(url) === NULL) {
                    return;
                } else if ($.type(url) === STRING) {
                    $.get(url)
                        .done(function (data) {
                            that.value(data);
                        })
                        .fail(function () {
                            that.value(null);
                        });
                } else {
                    throw new TypeError('`url` is expected to be a string');
                }
            },

            /**
             * Returns yml metadata
             */
            metadata: function () {
                return head((this.value() || '').trim());
            },

            /**
             * Html displayed
             * @method html
             * @returns {*}
             */
            html: function () {
                var markdown = body((this.value() || '').trim());
                return this.md.render(markdown);
            },

            /**
             * Refresh the display (especially after changing the value)
             */
            refresh: function () {
                var that = this;
                var element = that.element;
                var inline = element.find(SCRIPT_SELECTOR);
                var script = EMPTY;
                if (inline.length) {
                    script = $(SCRIPT_TAG).text(inline.text()).wrapAll(WRAP_TAG).parent().html();
                }
                element.html(script + that.html());
            },

            /**
             * Destroys the widget including all DOM modifications
             * @method destroy
             */
            destroy: function () {
                var that = this;
                var wrapper = that.wrapper;
                // Unbind events
                kendo.unbind(wrapper);
                // Clear references
                this.md = undefined;
                // Destroy widget
                Widget.fn.destroy.call(that);
                kendo.destroy(wrapper);
                // Remove widget class
                // wrapper.removeClass(WIDGET_CLASS);
            }

        });

        kendo.ui.plugin(Markdown);

    }(window.jQuery));

    return window.kendo;

}, typeof define === 'function' && define.amd ? define : function (_, f) { 'use strict'; f(); });
<commit_msg>Fixed jscs and jshint errors<commit_after>/**
 * Copyright (c) 2013-2017 Memba Sarl. All rights reserved.
 * Sources at https://github.com/Memba
 */

/* jshint browser: true, jquery: true */
/* globals define: false */

(function (f, define) {
    'use strict';
    define([
        './vendor/markdown-it/markdown-it',
        './vendor/markdown-it/markdown-it-katex', // This loads katex
        './vendor/markdown-it/markdown-it-emoji',
        './vendor/highlight/highlight.pack',
        './vendor/markdown-it/twemoji.amd',
        // Keep the above at the top considering function parameters below
        './window.assert',
        './window.logger',
        './vendor/kendo/kendo.binder'
    ], f);
})(function (markdown, katex, emoji, highlight, twemo) {

    'use strict';

    (function ($, undefined) {

        var kendo = window.kendo;
        var Widget = kendo.ui.Widget;
        var MarkdownIt = window.markdownit || markdown;
        var markdownItKatex = window.markdownItKatex || katex;
        var markdownitEmoji = window.markdownitEmoji || emoji;
        var hljs = window.hljs || highlight;
        var twemoji = window.twemoji || twemo;
        var assert = window.assert;
        var logger = new window.Logger('kidoju.widgets.markdown');
        var STRING = 'string';
        var NULL = 'null';
        var UNDEFINED = 'undefined';
        var EMPTY = '';
        var WIDGET_CLASS = 'kj-markdown'; // 'k-widget kj-markdown';
        var RX_YML = /^---\n([\s\S]*)\n---/;
        var RX_KEYVAL = /([^:\n]+):([^\n]+)/g;
        var KEY_BLACKLIST = /[-\s]/g;
        var SCRIPT_SELECTOR = 'script[type="text/plain"]';
        var SCRIPT_TAG = '';
        var WRAP_TAG = '<wrap></wrap>';

        /*********************************************************************************
         * Helpers
         * See https://github.com/Memba/Memba-Blog/blob/master/webapp/lib/markdown.js#L60
         *********************************************************************************/

        /**
         * Return the yml metadata in value
         * @param content
         */
        function head(content) {
            var yml = {};
            var ymlMatches = content.match(RX_YML);
            if ($.isArray(ymlMatches) && ymlMatches.length > 1) {
                var keyvalMatches = ymlMatches[1].match(RX_KEYVAL);
                if ($.isArray(keyvalMatches) && keyvalMatches.length) {
                    for (var i = 0; i < keyvalMatches.length; i++) {
                        var keyval = keyvalMatches[i];
                        var pos = keyval.indexOf(':');
                        var key = keyval.substr(0, pos).trim().replace(KEY_BLACKLIST, '_');
                        var val = keyval.substr(pos + 1).trim();
                        yml[key] = val;
                    }
                }
            }
            return yml;
        }

        /**
         * Returns the markdown content in value
         * @param content
         */
        function body(content) {
            return content.replace(RX_YML, EMPTY).trim();
        }

        /*********************************************************************************
         * Widget
         *********************************************************************************/

        /**
         * Markdown
         * @class Markdown Widget (kendoMarkdown)
         */
        var Markdown = Widget.extend({

            /**
             * Initializes the widget
             * @param element
             * @param options
             */
            init: function (element, options) {
                var that = this;
                options = options || {};
                Widget.fn.init.call(that, element, options);
                logger.debug({ method: 'init', message: 'widget initialized' });
                that._initMarkdownIt();
                that._layout();
                kendo.notify(that);
            },

            /**
             * Widget options
             * @property options
             */
            options: {
                name: 'Markdown',
                url: null,
                value: null,
                schemes: {}
            },

            /**
             * Value for MVVM binding
             * Returns either a JS function as a string or a library formula name prefixed as a Javascript comment
             * @param value
             */
            value: function (value) {
                var that = this;
                if ($.type(value) === STRING || $.type(value) === NULL) {
                    if (that._value !== value) {
                        that._value = value;
                        that.refresh();
                    }
                } else if ($.type(value) === UNDEFINED) {
                    if ($.type(that._value) === STRING || $.type(that._value) === NULL) {
                        return that._value;
                    } else {
                        return undefined;
                    }
                } else {
                    throw new TypeError('`value` is expected to be a string if not undefined');
                }
            },

            /**
             * Initialize markdown-it
             * @private
             */
            _initMarkdownIt: function () {
                var that = this;

                // Initialize MarkdownIt
                that.md = new MarkdownIt({
                    html: false,
                    linkify: true,
                    typographer: true,
                    // See https://github.com/markdown-it/markdown-it#syntax-highlighting
                    highlight: function (code, lang) {
                        try {
                            return hljs.highlight(lang, code).value;
                        } catch (err) {
                            return hljs.highlightAuto(code).value;
                        }
                    }
                });

                // Initialize renderers
                that._initHljs();
                that._initLinkOpener();
                that._initImageRule();
                that._initKatex();
                that._initEmojis();
            },

            /**
             * Init Highligh.js
             * Adds hljs class to the pre tag
             * @see https://github.com/markdown-it/markdown-it/blob/88c6e0f8e6fd567c70ffabbc1e9ce7b980d2e3a9/support/demo_template/index.js#L94
             * @private
             */
            _initHljs: function () {
                var that = this;
                that.md.renderer.rules.fence = function (tokens, idx, options, env, self) {
                    var escapeHtml = that.md.utils.escapeHtml;
                    var unescapeAll = that.md.utils.unescapeAll;
                    var token = tokens[idx];
                    var info = token.info ? unescapeAll(token.info).trim() : '';
                    var langName = '';
                    var highlighted;
                    if (info) {
                        langName = info.split(/\s+/g)[0];
                        token.attrPush(['class', options.langPrefix + langName]);
                    }
                    if (options.highlight) {
                        highlighted = options.highlight(token.content, langName) || escapeHtml(token.content);
                    } else {
                        highlighted = escapeHtml(token.content);
                    }
                    return '
' + highlighted  + '
\n';
                };
            },

            /**
             * Initialize link opener to open links in new window
             * @see https://github.com/markdown-it/markdown-it/blob/master/docs/architecture.md#renderer
             * @private
             */
            _initLinkOpener: function () {
                var that = this;
                /* jscs: disable requireCamelCaseOrUpperCaseIdentifiers */
                var defaultRender = that.md.renderer.rules.link_open || function (tokens, idx, options, env, self) {
                        return self.renderToken(tokens, idx, options);
                    };
                that.md.renderer.rules.link_open = function (tokens, idx, options, env, self) {
                    // If you are sure other plugins can't add `target` - drop check below
                    var targetIndex = tokens[idx].attrIndex('target');
                    if (targetIndex < 0) {
                        // @see https://cordova.apache.org/docs/en/3.1.0/cordova/inappbrowser/window.open.html
                        tokens[idx].attrPush(['target', window.cordova ? '_system' : '_blank']); // add new attribute
                    } else {
                        tokens[idx].attrs[targetIndex][1] = window.cordova ? '_system' : '_blank'; // replace value of existing attr
                    }
                    // same with rel - see https://mathiasbynens.github.io/rel-noopener/
                    var relIndex = tokens[idx].attrIndex('rel');
                    if (relIndex < 0) {
                        tokens[idx].attrPush(['rel', 'noopener']); // add new attribute
                    } else {
                        tokens[idx].attrs[relIndex][1] = 'noopener'; // replace value of existing attr
                    }
                    // pass token to default renderer.
                    return defaultRender(tokens, idx, options, env, self);
                };
                /* jscs: enable requireCamelCaseOrUpperCaseIdentifiers */
            },

            /**
             * Init the image rule
             * Adds the .img-responsive class to all images
             * @see https://github.com/markdown-it/markdown-it/blob/master/docs/architecture.md
             * @private
             */
            _initImageRule: function () {
                var that = this;
                var defaultRender = that.md.renderer.rules.image || function (tokens, idx, options, env, self) {
                        return self.renderToken(tokens, idx, options);
                    };
                that.md.renderer.rules.image = function (tokens, idx, options, env, slf) {
                    // Replace schemes
                    var srcIndex = tokens[idx].attrIndex('src');
                    var src = tokens[idx].attrs[srcIndex][1];
                    var schemes = that.options.schemes;
                    for (var scheme in (schemes || {})) {
                        if (schemes.hasOwnProperty(scheme) && (new RegExp('^' + scheme + '://')).test(src)) {
                            src = src.replace(scheme + '://', schemes[scheme]);
                            break;
                        }
                    }
                    tokens[idx].attrs[srcIndex][1] = src;

                    // Add img-responsive class
                    var classIndex = tokens[idx].attrIndex('class');
                    // If you are sure other plugins can't add `class` - drop check below
                    if (classIndex < 0) {
                        tokens[idx].attrPush(['class', 'img-responsive']); // add new attribute
                    } else {
                        tokens[idx].attrs[classIndex][1] = 'img-responsive'; // replace value of existing attr
                    }
                    // pass token to default renderer.
                    return defaultRender(tokens, idx, options, env, slf);
                };
            },

            /**
             * Init Katex
             * @private
             */
            _initKatex: function () {
                if (markdownItKatex) {
                    this.md.use(markdownItKatex);
                }
            },

            /**
             * Init Emojis
             * @private
             */
            _initEmojis: function () {
                if (markdownitEmoji) {
                    this.md.use(markdownitEmoji);
                }
                // use much nicer twemojis
                if (twemoji) {
                    this.md.renderer.rules.emoji = function (token, idx) {
                        return twemoji.parse(token[idx].content);
                    };
                }
            },

            /**
             * Builds the widget layout
             * @private
             */
            _layout: function () {
                var that = this;
                var options = that.options;
                that.wrapper = that.element;
                that.element.addClass(WIDGET_CLASS);
                if ($.type(options.url) === STRING) {
                    that.url(options.url);
                } else if ($.type(options.value) === STRING) {
                    that.value(options.value);
                } else {
                    that.inline();
                }
            },

            /**
             * Reads the markdown text in an inline script
             * @method _inline
             * @private
             */
            inline: function () {
                var that = this;
                var element = that.element;
                var inline = element.find(SCRIPT_SELECTOR);
                if (inline.length) {
                    that.value(inline.text());
                }
            },

            /**
             * Reads the markdown text from a url
             * @param url
             */
            url: function (url) {
                var that = this;
                if ($.type(url) === NULL) {
                    return;
                } else if ($.type(url) === STRING) {
                    $.get(url)
                        .done(function (data) {
                            that.value(data);
                        })
                        .fail(function () {
                            that.value(null);
                        });
                } else {
                    throw new TypeError('`url` is expected to be a string');
                }
            },

            /**
             * Returns yml metadata
             */
            metadata: function () {
                return head((this.value() || '').trim());
            },

            /**
             * Html displayed
             * @method html
             * @returns {*}
             */
            html: function () {
                var markdown = body((this.value() || '').trim());
                return this.md.render(markdown);
            },

            /**
             * Refresh the display (especially after changing the value)
             */
            refresh: function () {
                var that = this;
                var element = that.element;
                var inline = element.find(SCRIPT_SELECTOR);
                var script = EMPTY;
                if (inline.length) {
                    script = $(SCRIPT_TAG).text(inline.text()).wrapAll(WRAP_TAG).parent().html();
                }
                element.html(script + that.html());
            },

            /**
             * Destroys the widget including all DOM modifications
             * @method destroy
             */
            destroy: function () {
                var that = this;
                var wrapper = that.wrapper;
                // Unbind events
                kendo.unbind(wrapper);
                // Clear references
                this.md = undefined;
                // Destroy widget
                Widget.fn.destroy.call(that);
                kendo.destroy(wrapper);
                // Remove widget class
                // wrapper.removeClass(WIDGET_CLASS);
            }

        });

        kendo.ui.plugin(Markdown);

    }(window.jQuery));

    return window.kendo;

}, typeof define === 'function' && define.amd ? define : function (_, f) { 'use strict'; f(); });
<|endoftext|>


<commit_before>import lodash from 'lodash';

import BrowserWindow from 'browser-window';
import EventEmitter from 'events';

class AppWindow extends EventEmitter {

  /**
   * Create a browser window based off of some default settings.
   *
   * @param {Object} options
   * @return {AppWindow}
   */
  constructor(options) {
    super();

    const defaults = {
      width: 800,
      height: 600,
      'web-preferences': {
        'webaudio': true,
        'web-security': false,
        'use-content-size': true,
        'subpixel-font-scaling': true,
        'direct-write': true,
        'plugins': true
      }
    };

    this.settings = lodash.extend(defaults, options);
    this.window = this.createBrowserWindow(this.settings);
  }

  /**
   * Create a BrowserWindow with the given settings and handle some events.
   *
   * @param {Object} settings
   * @return {BrowserWindow}
   */
  createBrowserWindow(settings) {
    const browserWindow = new BrowserWindow(settings);

    browserWindow.on('closed', (e) => {
      this.emit('closed', e);
    });

    browserWindow.on('devtools-opened', () => {
      browserWindow.webContents.send('window:toggle-dev-tools', true);
    });

    browserWindow.on('devtools-closed', () => {
      browserWindow.webContents.send('window:toggle-dev-tools', false);
    });

    return browserWindow;
  }

  /**
   * Load the target url inside the window.
   *
   * @param {String} targetUrl
   */
  loadUrl(targetUrl) {
    this.window.loadUrl(targetUrl);
  }

  /**
   * Make the window visible and focus it.
   */
  show() {
    this.window.show();
  }

  /**
   * Close the window.
   */
  close() {
    this.window.close();
    this.window = null;
  }

}

export default AppWindow;
<commit_msg>Makes AppWindow open urls externally<commit_after>import lodash from 'lodash';
import shell from 'shell';

import BrowserWindow from 'browser-window';
import EventEmitter from 'events';

class AppWindow extends EventEmitter {

  /**
   * Create a browser window based off of some default settings.
   *
   * @param {Object} options
   * @return {AppWindow}
   */
  constructor(options) {
    super();

    const defaults = {
      width: 800,
      height: 600,
      'web-preferences': {
        'webaudio': true,
        'web-security': false,
        'use-content-size': true,
        'subpixel-font-scaling': true,
        'direct-write': true,
        'plugins': true
      }
    };

    this.settings = lodash.extend(defaults, options);
    this.window = this.createBrowserWindow(this.settings);
  }

  /**
   * Create a BrowserWindow with the given settings and handle some events.
   *
   * @param {Object} settings
   * @return {BrowserWindow}
   */
  createBrowserWindow(settings) {
    const browserWindow = new BrowserWindow(settings);

    browserWindow.webContents.on('new-window', function(event, url) {
      event.preventDefault();
      shell.openExternal(url);
    });

    browserWindow.on('closed', (e) => {
      this.emit('closed', e);
    });

    browserWindow.on('devtools-opened', () => {
      browserWindow.webContents.send('window:toggle-dev-tools', true);
    });

    browserWindow.on('devtools-closed', () => {
      browserWindow.webContents.send('window:toggle-dev-tools', false);
    });

    return browserWindow;
  }

  /**
   * Load the target url inside the window.
   *
   * @param {String} targetUrl
   */
  loadUrl(targetUrl) {
    this.window.loadUrl(targetUrl);
  }

  /**
   * Make the window visible and focus it.
   */
  show() {
    this.window.show();
  }

  /**
   * Close the window.
   */
  close() {
    this.window.close();
    this.window = null;
  }

}

export default AppWindow;
<|endoftext|>


<commit_before>/* eslint-disable react/jsx-filename-extension */
/* eslint-disable no-console */
import App from 'component/app';
import SnackBar from 'component/snackBar';
import SplashScreen from 'component/splash';
import moment from 'moment';
import * as ACTIONS from 'constants/action_types';
import * as MODALS from 'constants/modal_types';
import { ipcRenderer, remote, shell } from 'electron';
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import {
  doConditionalAuthNavigate,
  doDaemonReady,
  doAutoUpdate,
  doOpenModal,
} from 'redux/actions/app';
import { doToast, doBlackListedOutpointsSubscribe, isURIValid } from 'lbry-redux';
import { doNavigate } from 'redux/actions/navigation';
import { doDownloadLanguages, doUpdateIsNightAsync } from 'redux/actions/settings';
import { doUserEmailVerify, doAuthenticate, Lbryio, rewards } from 'lbryinc';
import 'scss/all.scss';
import store from 'store';
import pjson from 'package.json';
import app from './app';
import analytics from './analytics';
import doLogWarningConsoleMessage from './logWarningConsoleMessage';

const { autoUpdater } = remote.require('electron-updater');
const APPPAGEURL = 'lbry://?';

autoUpdater.logger = remote.require('electron-log');

// We need to override Lbryio for getting/setting the authToken
// We interect with ipcRenderer to get the auth key from a users keyring
let authToken;
Lbryio.setOverride('setAuthToken', status => {
  Lbryio.call(
    'user',
    'new',
    {
      auth_token: '',
      language: 'en',
      app_id: status.installation_id,
    },
    'post'
  ).then(response => {
    if (!response.auth_token) {
      throw new Error(__('auth_token is missing from response'));
    }

    const newAuthToken = response.auth_token;
    authToken = newAuthToken;
    ipcRenderer.send('set-auth-token', authToken);
  });
});

Lbryio.setOverride(
  'getAuthToken',
  () =>
    new Promise(resolve => {
      if (authToken) {
        resolve(authToken);
      } else {
        ipcRenderer.once('auth-token-response', (event, token) => {
          Lbryio.authToken = token;
          resolve(token);
        });

        ipcRenderer.send('get-auth-token');
      }
    })
);

rewards.setCallback('claimFirstRewardSuccess', () => {
  app.store.dispatch(doOpenModal(MODALS.FIRST_REWARD));
});

rewards.setCallback('rewardApprovalRequired', () => {
  app.store.dispatch(doOpenModal(MODALS.REWARD_APPROVAL_REQUIRED));
});

ipcRenderer.on('open-uri-requested', (event, uri, newSession) => {
  if (uri && uri.startsWith('lbry://')) {
    if (uri.startsWith('lbry://?verify=')) {
      let verification = {};
      try {
        verification = JSON.parse(atob(uri.substring(15)));
      } catch (error) {
        console.log(error);
      }
      if (verification.token && verification.recaptcha) {
        app.store.dispatch(doConditionalAuthNavigate(newSession));
        app.store.dispatch(doUserEmailVerify(verification.token, verification.recaptcha));
      } else {
        app.store.dispatch(
          doToast({
            message: 'Invalid Verification URI',
          })
        );
      }
    } else if (uri.startsWith(APPPAGEURL)) {
      const navpage = uri.replace(APPPAGEURL, '').toLowerCase();
      app.store.dispatch(doNavigate(`/${navpage}`));
    } else if (isURIValid(uri)) {
      app.store.dispatch(doNavigate('/show', { uri }));
    } else {
      app.store.dispatch(
        doToast({
          message: __('Invalid LBRY URL requested'),
        })
      );
    }
  }
});

ipcRenderer.on('open-menu', (event, uri) => {
  if (uri && uri.startsWith('/help')) {
    app.store.dispatch(doNavigate('/help'));
  }
});

const { dock } = remote.app;

ipcRenderer.on('window-is-focused', () => {
  if (!dock) return;
  app.store.dispatch({ type: ACTIONS.WINDOW_FOCUSED });
  dock.setBadge('');
});

ipcRenderer.on('devtools-is-opened', () => {
  const logOnDevelopment = false;
  doLogWarningConsoleMessage(logOnDevelopment);
});

document.addEventListener('dragover', event => {
  event.preventDefault();
});
document.addEventListener('drop', event => {
  event.preventDefault();
});
document.addEventListener('click', event => {
  let { target } = event;

  while (target && target !== document) {
    if (target.matches('a') || target.matches('button')) {
      // TODO: Look into using accessiblity labels (this would also make the app more accessible)
      const hrefParts = window.location.href.split('#');

      // Buttons that we want to track should use `data-id`
      // This prevents multiple buttons being grouped together if they have the same text
      const element =
        target.dataset.id || target.title || (target.textContent && target.textContent.trim());
      if (element) {
        analytics.track('CLICK', {
          target: element,
          location: hrefParts.length > 1 ? hrefParts[hrefParts.length - 1] : '/',
        });
      } else {
        analytics.track('UNMARKED_CLICK', {
          location: hrefParts.length > 1 ? hrefParts[hrefParts.length - 1] : '/',
          source: target.outerHTML,
        });
      }
    }
    if (target.matches('a[href^="http"]') || target.matches('a[href^="mailto"]')) {
      event.preventDefault();
      shell.openExternal(target.href);
      return;
    }
    target = target.parentNode;
  }
});

const init = () => {
  moment.locale(remote.app.getLocale());

  autoUpdater.on('error', error => {
    // eslint-disable-next-line no-console
    console.error(error.message);
  });

  if (['win32', 'darwin'].includes(process.platform)) {
    autoUpdater.on('update-available', () => {
      console.log('Update available');
    });
    autoUpdater.on('update-not-available', () => {
      console.log('Update not available');
    });
    autoUpdater.on('update-downloaded', () => {
      console.log('Update downloaded');
      app.store.dispatch(doAutoUpdate());
    });
  }

  app.store.dispatch(doUpdateIsNightAsync());
  app.store.dispatch(doDownloadLanguages());
  app.store.dispatch(doBlackListedOutpointsSubscribe());

  function onDaemonReady() {
    window.sessionStorage.setItem('loaded', 'y'); // once we've made it here once per session, we don't need to show splash again
    app.store.dispatch(doDaemonReady());

    ReactDOM.render(
      <Provider store={store}>

          <App />
          <SnackBar />

      </Provider>,
      document.getElementById('app')
    );
  }

  if (window.sessionStorage.getItem('loaded') === 'y') {
    onDaemonReady();
  } else {
    ReactDOM.render(
      <Provider store={store}>
        <SplashScreen
          authenticate={() => app.store.dispatch(doAuthenticate(pjson.version))}
          onReadyToLaunch={onDaemonReady}
        />
      </Provider>,
      document.getElementById('app')
    );
  }
};

init();

/* eslint-enable react/jsx-filename-extension */
/* eslint-enable no-console */
<commit_msg>use promise for setAuthToken so we only continue after the auth token has been set<commit_after>/* eslint-disable react/jsx-filename-extension */
/* eslint-disable no-console */
import App from 'component/app';
import SnackBar from 'component/snackBar';
import SplashScreen from 'component/splash';
import moment from 'moment';
import * as ACTIONS from 'constants/action_types';
import * as MODALS from 'constants/modal_types';
import { ipcRenderer, remote, shell } from 'electron';
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import {
  doConditionalAuthNavigate,
  doDaemonReady,
  doAutoUpdate,
  doOpenModal,
} from 'redux/actions/app';
import { doToast, doBlackListedOutpointsSubscribe, isURIValid } from 'lbry-redux';
import { doNavigate } from 'redux/actions/navigation';
import { doDownloadLanguages, doUpdateIsNightAsync } from 'redux/actions/settings';
import { doUserEmailVerify, doAuthenticate, Lbryio, rewards } from 'lbryinc';
import 'scss/all.scss';
import store from 'store';
import pjson from 'package.json';
import app from './app';
import analytics from './analytics';
import doLogWarningConsoleMessage from './logWarningConsoleMessage';

const { autoUpdater } = remote.require('electron-updater');
const APPPAGEURL = 'lbry://?';

autoUpdater.logger = remote.require('electron-log');

// We need to override Lbryio for getting/setting the authToken
// We interect with ipcRenderer to get the auth key from a users keyring
// We keep a local variable for authToken beacuse `ipcRenderer.send` does not
// contain a response, so there is no way to know when it's been set
let authToken;
Lbryio.setOverride(
  'setAuthToken',
  status =>
    new Promise(resolve => {
      Lbryio.call(
        'user',
        'new',
        {
          auth_token: '',
          language: 'en',
          app_id: status.installation_id,
        },
        'post'
      ).then(response => {
        if (!response.auth_token) {
          throw new Error(__('auth_token is missing from response'));
        }

        const newAuthToken = response.auth_token;
        authToken = newAuthToken;
        ipcRenderer.send('set-auth-token', authToken);
        resolve();
      });
    })
);

Lbryio.setOverride(
  'getAuthToken',
  () =>
    new Promise(resolve => {
      if (authToken) {
        resolve(authToken);
      } else {
        ipcRenderer.once('auth-token-response', (event, token) => {
          Lbryio.authToken = token;
          resolve(token);
        });

        ipcRenderer.send('get-auth-token');
      }
    })
);

rewards.setCallback('claimFirstRewardSuccess', () => {
  app.store.dispatch(doOpenModal(MODALS.FIRST_REWARD));
});

rewards.setCallback('rewardApprovalRequired', () => {
  app.store.dispatch(doOpenModal(MODALS.REWARD_APPROVAL_REQUIRED));
});

ipcRenderer.on('open-uri-requested', (event, uri, newSession) => {
  if (uri && uri.startsWith('lbry://')) {
    if (uri.startsWith('lbry://?verify=')) {
      let verification = {};
      try {
        verification = JSON.parse(atob(uri.substring(15)));
      } catch (error) {
        console.log(error);
      }
      if (verification.token && verification.recaptcha) {
        app.store.dispatch(doConditionalAuthNavigate(newSession));
        app.store.dispatch(doUserEmailVerify(verification.token, verification.recaptcha));
      } else {
        app.store.dispatch(
          doToast({
            message: 'Invalid Verification URI',
          })
        );
      }
    } else if (uri.startsWith(APPPAGEURL)) {
      const navpage = uri.replace(APPPAGEURL, '').toLowerCase();
      app.store.dispatch(doNavigate(`/${navpage}`));
    } else if (isURIValid(uri)) {
      app.store.dispatch(doNavigate('/show', { uri }));
    } else {
      app.store.dispatch(
        doToast({
          message: __('Invalid LBRY URL requested'),
        })
      );
    }
  }
});

ipcRenderer.on('open-menu', (event, uri) => {
  if (uri && uri.startsWith('/help')) {
    app.store.dispatch(doNavigate('/help'));
  }
});

const { dock } = remote.app;

ipcRenderer.on('window-is-focused', () => {
  if (!dock) return;
  app.store.dispatch({ type: ACTIONS.WINDOW_FOCUSED });
  dock.setBadge('');
});

ipcRenderer.on('devtools-is-opened', () => {
  const logOnDevelopment = false;
  doLogWarningConsoleMessage(logOnDevelopment);
});

document.addEventListener('dragover', event => {
  event.preventDefault();
});
document.addEventListener('drop', event => {
  event.preventDefault();
});
document.addEventListener('click', event => {
  let { target } = event;

  while (target && target !== document) {
    if (target.matches('a') || target.matches('button')) {
      // TODO: Look into using accessiblity labels (this would also make the app more accessible)
      const hrefParts = window.location.href.split('#');

      // Buttons that we want to track should use `data-id`
      // This prevents multiple buttons being grouped together if they have the same text
      const element =
        target.dataset.id || target.title || (target.textContent && target.textContent.trim());
      if (element) {
        analytics.track('CLICK', {
          target: element,
          location: hrefParts.length > 1 ? hrefParts[hrefParts.length - 1] : '/',
        });
      } else {
        analytics.track('UNMARKED_CLICK', {
          location: hrefParts.length > 1 ? hrefParts[hrefParts.length - 1] : '/',
          source: target.outerHTML,
        });
      }
    }
    if (target.matches('a[href^="http"]') || target.matches('a[href^="mailto"]')) {
      event.preventDefault();
      shell.openExternal(target.href);
      return;
    }
    target = target.parentNode;
  }
});

const init = () => {
  moment.locale(remote.app.getLocale());

  autoUpdater.on('error', error => {
    // eslint-disable-next-line no-console
    console.error(error.message);
  });

  if (['win32', 'darwin'].includes(process.platform)) {
    autoUpdater.on('update-available', () => {
      console.log('Update available');
    });
    autoUpdater.on('update-not-available', () => {
      console.log('Update not available');
    });
    autoUpdater.on('update-downloaded', () => {
      console.log('Update downloaded');
      app.store.dispatch(doAutoUpdate());
    });
  }

  app.store.dispatch(doUpdateIsNightAsync());
  app.store.dispatch(doDownloadLanguages());
  app.store.dispatch(doBlackListedOutpointsSubscribe());

  function onDaemonReady() {
    window.sessionStorage.setItem('loaded', 'y'); // once we've made it here once per session, we don't need to show splash again
    app.store.dispatch(doDaemonReady());

    ReactDOM.render(
      <Provider store={store}>

          <App />
          <SnackBar />

      </Provider>,
      document.getElementById('app')
    );
  }

  if (window.sessionStorage.getItem('loaded') === 'y') {
    onDaemonReady();
  } else {
    ReactDOM.render(
      <Provider store={store}>
        <SplashScreen
          authenticate={() => app.store.dispatch(doAuthenticate(pjson.version))}
          onReadyToLaunch={onDaemonReady}
        />
      </Provider>,
      document.getElementById('app')
    );
  }
};

init();

/* eslint-enable react/jsx-filename-extension */
/* eslint-enable no-console */
<|endoftext|>