<commit_before>constructor(){
  super({
    requiresPageReload: true
  })
}

enabled(){
  // elements & data
  this.css = null;
  this.htmlModal = null;
  this.config = null;

  this.defaultConfig = {
    columnWidth: "310px",
    fontSize: "12px",
    hideTweetActions: true,
    moveTweetActionsToRight: true,
    revertReplies: false,
    roundedScrollBars: false,
    smallComposeTextSize: false,
    optimizeAnimations: true,
    avatarRadius: 10
  };

  // modal dialog loading
  $TDP.readFileRoot(this.$token, "modal.html").then(contents => {
    this.htmlModal = contents;
  }).catch(err => {
    $TD.alert("error", "Problem loading data for the design edit plugin: "+err.message);
  });

  // configuration
  const configFile = "config.json";
  this.tmpConfig = null;

  var loadConfigObject = obj => {
    this.tmpConfig = obj || {};

    if (window.TD_APP_READY){
      this.onAppReady();
    }

    this.injectDeciderReplyHook(this.tmpConfig.revertReplies);
  };

  this.onAppReady = () => {
    if (this.tmpConfig !== null){
      this.config = $.extend(this.defaultConfig, this.tmpConfig);
      this.tmpConfig = null;
      this.reinjectAll();
    }
  };

  $TDP.checkFileExists(this.$token, configFile).then(exists => {
    if (!exists){
      loadConfigObject(null);
    }
    else{
      $TDP.readFile(this.$token, configFile, true).then(contents => {
        try{
          loadConfigObject(JSON.parse(contents));
        }catch(err){
          loadConfigObject(null);
        }
      }).catch(err => {
        loadConfigObject(null);
        $TD.alert("error", "Problem loading configuration for the design edit plugin: "+err.message);
      });
    }
  });

  this.saveConfig = () => {
    $TDP.writeFile(this.$token, configFile, JSON.stringify(this.config)).catch(err => {
      $TD.alert("error", "Problem saving configuration for the design edit plugin: "+err.message);
    });
  };

  // settings click event
  this.onSettingsMenuClickedEvent = () => {
    if (this.htmlModal === null || this.config === null){
      return;
    }

    setTimeout(() => {
      let menu = $(".js-dropdown-content").children("ul").first();
      if (menu.length === 0)return;

      let itemTD = menu.children("[data-std]").first();
      if (itemTD.length === 0)return;

      if (!itemTD.prev().hasClass("drp-h-divider")){
        itemTD.before('

');
      }

      let itemEditDesign = $('
Edit layout & design
');
      itemTD.after(itemEditDesign);

      itemEditDesign.on("click", "a", function(){
        new customDesignModal();
      });

      itemEditDesign.hover(function(){
        $(this).addClass("is-selected");
      }, function(){
        $(this).removeClass("is-selected");
      });
    }, 1);
  };

  // modal dialog setup
  var me = this;

  var updateKey = function(key, value){
    me.config[key] = value;

    setTimeout(function(){
      me.saveConfig();
      me.reinjectAll();
    }, 1); // delays the slight lag caused by saving and reinjection
  };

  var customDesignModal = TD.components.BaseModal.extend(function(){
    let modal = $("#td-design-plugin-modal");
    this.setAndShowContainer(modal, false);

    // RELOAD
    this.reloadPage = false;
    modal.find("[data-td-reload]").click(() => this.reloadPage = true);

    // UI EVENTS
    let getTextForCustom = function(key){
      return "Custom ("+me.config[key]+")";
    };

    modal.find("[data-td-key]").each(function(){
      let item = $(this);
      let tag = item.prop("tagName");
      let key = item.attr("data-td-key");

      // INPUTS
      if (tag === "INPUT"){
        let type = item.attr("type");

        if (type === "checkbox"){
          item.prop("checked", me.config[key]);

          item.change(function(){
            updateKey(key, item.prop("checked"));
          });
        }
      }
      // SELECTS
      else if (tag === "SELECT"){
        if (!item.val(me.config[key]).val()){
          let custom = item.find("option[value='custom']");

          if (custom.length === 1){
            item.val("custom");
            custom.text(getTextForCustom(key));
          }
        }

        item.change(function(){ // TODO change doesn't fire when Custom is already selected
          let val = item.val();

          if (val === "custom"){
            val = prompt("Enter custom value:");

            if (val){
              updateKey(key, val);
              item.find("option[value='custom']").text(getTextForCustom(key));
            }
          }
          else{
            updateKey(key, item.val());
          }
        });
      }
      // CUSTOM ELEMENTS
      else{
        let value = item.attr("data-td-value");

        if (value == me.config[key]){
          item.addClass("selected");
        }

        item.click(function(){
          modal.find("[data-td-key='"+key+"']").removeClass("selected");
          item.addClass("selected");
          updateKey(key, value);
        });
      }
    });

    // THEMES
    modal.find("[data-td-theme='"+TD.settings.getTheme()+"']").prop("checked", true);

    modal.find("[data-td-theme]").change(function(){
      setTimeout(function(){
        TD.settings.setTheme($(this).attr("data-td-theme"));
        $(document).trigger("uiToggleTheme");
      }, 1);
    });
  }).methods({
    _render: () => $(this.htmlModal),
    destroy: function(){
      if (this.reloadPage){
        location.reload();
        return;
      }

      $("#td-design-plugin-modal").hide();
      this.supr();
    }
  });

  // decider injections
  this.injectDeciderReplyHook = enable => {
    let prevFunc = TD.decider.updateFromBackend;

    TD.decider.updateFromBackend = function(data){
      data["simplified_replies"] = !enable;
      return prevFunc.apply(this, arguments);
    };

    TD.decider.updateForGuestId();
    this.$pluginSettings.requiresPageReload = enable;
  };

  // css and layout injection
  this.resetDesign = () => {
    if (this.css){
      this.css.remove();
    }

    this.css = window.TDPF_createCustomStyle(this);
  };

  this.reinjectAll = () => {
    this.resetDesign();

    this.css.insert(".txt-base-smallest:not(.icon), .txt-base-largest:not(.icon) { font-size: "+this.config.fontSize+" !important }");
    this.css.insert(".avatar { border-radius: "+this.config.avatarRadius+"% !important }");

    if (this.config.hideTweetActions){
      this.css.insert(".tweet-action { opacity: 0; }");
      this.css.insert(".is-favorite .tweet-action, .is-retweet .tweet-action { opacity: 0.5; visibility: visible !important }");
      this.css.insert(".tweet:hover .tweet-action, .is-favorite .tweet-action[rel='favorite'], .is-retweet .tweet-action[rel='retweet'] { opacity: 1; visibility: visible !important }");
    }

    if (this.config.moveTweetActionsToRight){
      this.css.insert(".tweet-actions { float: right !important; width: auto !important }");
      this.css.insert(".tweet-actions > li:nth-child(4) { margin-right: 2px !important }");
    }

    if (this.config.smallComposeTextSize){
      this.css.insert(".compose-text { font-size: 12px !important; height: 120px !important }");
    }

    if (!this.config.roundedScrollBars){
      this.css.insert(".scroll-styled-v:not(.antiscroll-inner)::-webkit-scrollbar { width: 8px }");
      this.css.insert(".scroll-styled-h:not(.antiscroll-inner)::-webkit-scrollbar { height: 8px }");
      this.css.insert(".scroll-styled-v::-webkit-scrollbar-thumb { border-radius: 0 }");
      this.css.insert(".scroll-styled-h::-webkit-scrollbar-thumb { border-radius: 0 }");
    }

    if (this.config.optimizeAnimations){
      this.css.insert(".app-content { will-change: transform }");
      this.css.insert(".column-holder { will-change: transform }");
    }

    if (this.config.columnWidth[0] === '/'){
      let cols = this.config.columnWidth.slice(1);

      this.css.insert(".column { width: calc((100vw - 205px) / "+cols+" - 8px) !important }");
      this.css.insert(".is-condensed .column { width: calc((100vw - 55px) / "+cols+" - 8px) !important }");
    }
    else{
      this.css.insert(".column { width: "+this.config.columnWidth+" !important }");
    }

    switch(this.config.columnWidth){
      case "/6":
        TD.settings.setColumnWidth("narrow");
        break;

      case "310px":
      case "/5":
        TD.settings.setColumnWidth("medium");
        break;

      default:
        TD.settings.setColumnWidth(parseInt(this.config.columnWidth, 10) < 310 ? "narrow" : "wide"); // NaN will give "wide"
        break;
    }

    switch(this.config.fontSize){
      case "13px": TD.settings.setFontSize("small"); break;
      case "14px": TD.settings.setFontSize("medium"); break;
      case "15px": TD.settings.setFontSize("large"); break;
      default: TD.settings.setFontSize(parseInt(this.config.fontSize, 10) >= 16 ? "largest" : "smallest"); break;
    }

    $TDP.injectIntoNotificationsBefore(this.$token, "css", "", [
      ""
    ].join(""));
  };

  this.uiShowActionsMenuEvent = () => {
    if (this.config.moveTweetActionsToRight){
      $(".js-dropdown.pos-r").toggleClass("pos-r pos-l");
    }
  };
}

ready(){
  // configuration
  switch(TD.settings.getColumnWidth()){
    case "wide": this.defaultConfig.columnWidth = "350px"; break;
    case "narrow": this.defaultConfig.columnWidth = "270px"; break;
  }

  switch(TD.settings.getFontSize()){
    case "small": this.defaultConfig.fontSize = "13px"; break;
    case "medium": this.defaultConfig.fontSize = "14px"; break;
    case "large": this.defaultConfig.fontSize = "15px"; break;
    case "largest": this.defaultConfig.fontSize = "16px"; break;
  }

  this.onAppReady();

  // layout events
  $(document).on("uiShowActionsMenu", this.uiShowActionsMenuEvent);

  // modal
  $("[data-action='settings-menu']").on("click", this.onSettingsMenuClickedEvent);
  $(".js-app").append('

');
}

disabled(){
  if (this.css){
    this.css.remove();
  }

  $(document).off("uiShowActionsMenu", this.uiShowActionsMenuEvent);

  $("[data-action='settings-menu']").off("click", this.onSettingsMenuClickedEvent);
  $("#td-design-plugin-modal").remove();
}
<commit_msg>Fix missing border-radius style on some scrollbars in edit-design plugin<commit_after>constructor(){
  super({
    requiresPageReload: true
  })
}

enabled(){
  // elements & data
  this.css = null;
  this.htmlModal = null;
  this.config = null;

  this.defaultConfig = {
    columnWidth: "310px",
    fontSize: "12px",
    hideTweetActions: true,
    moveTweetActionsToRight: true,
    revertReplies: false,
    roundedScrollBars: false,
    smallComposeTextSize: false,
    optimizeAnimations: true,
    avatarRadius: 10
  };

  // modal dialog loading
  $TDP.readFileRoot(this.$token, "modal.html").then(contents => {
    this.htmlModal = contents;
  }).catch(err => {
    $TD.alert("error", "Problem loading data for the design edit plugin: "+err.message);
  });

  // configuration
  const configFile = "config.json";
  this.tmpConfig = null;

  var loadConfigObject = obj => {
    this.tmpConfig = obj || {};

    if (window.TD_APP_READY){
      this.onAppReady();
    }

    this.injectDeciderReplyHook(this.tmpConfig.revertReplies);
  };

  this.onAppReady = () => {
    if (this.tmpConfig !== null){
      this.config = $.extend(this.defaultConfig, this.tmpConfig);
      this.tmpConfig = null;
      this.reinjectAll();
    }
  };

  $TDP.checkFileExists(this.$token, configFile).then(exists => {
    if (!exists){
      loadConfigObject(null);
    }
    else{
      $TDP.readFile(this.$token, configFile, true).then(contents => {
        try{
          loadConfigObject(JSON.parse(contents));
        }catch(err){
          loadConfigObject(null);
        }
      }).catch(err => {
        loadConfigObject(null);
        $TD.alert("error", "Problem loading configuration for the design edit plugin: "+err.message);
      });
    }
  });

  this.saveConfig = () => {
    $TDP.writeFile(this.$token, configFile, JSON.stringify(this.config)).catch(err => {
      $TD.alert("error", "Problem saving configuration for the design edit plugin: "+err.message);
    });
  };

  // settings click event
  this.onSettingsMenuClickedEvent = () => {
    if (this.htmlModal === null || this.config === null){
      return;
    }

    setTimeout(() => {
      let menu = $(".js-dropdown-content").children("ul").first();
      if (menu.length === 0)return;

      let itemTD = menu.children("[data-std]").first();
      if (itemTD.length === 0)return;

      if (!itemTD.prev().hasClass("drp-h-divider")){
        itemTD.before('

');
      }

      let itemEditDesign = $('
Edit layout & design
');
      itemTD.after(itemEditDesign);

      itemEditDesign.on("click", "a", function(){
        new customDesignModal();
      });

      itemEditDesign.hover(function(){
        $(this).addClass("is-selected");
      }, function(){
        $(this).removeClass("is-selected");
      });
    }, 1);
  };

  // modal dialog setup
  var me = this;

  var updateKey = function(key, value){
    me.config[key] = value;

    setTimeout(function(){
      me.saveConfig();
      me.reinjectAll();
    }, 1); // delays the slight lag caused by saving and reinjection
  };

  var customDesignModal = TD.components.BaseModal.extend(function(){
    let modal = $("#td-design-plugin-modal");
    this.setAndShowContainer(modal, false);

    // RELOAD
    this.reloadPage = false;
    modal.find("[data-td-reload]").click(() => this.reloadPage = true);

    // UI EVENTS
    let getTextForCustom = function(key){
      return "Custom ("+me.config[key]+")";
    };

    modal.find("[data-td-key]").each(function(){
      let item = $(this);
      let tag = item.prop("tagName");
      let key = item.attr("data-td-key");

      // INPUTS
      if (tag === "INPUT"){
        let type = item.attr("type");

        if (type === "checkbox"){
          item.prop("checked", me.config[key]);

          item.change(function(){
            updateKey(key, item.prop("checked"));
          });
        }
      }
      // SELECTS
      else if (tag === "SELECT"){
        if (!item.val(me.config[key]).val()){
          let custom = item.find("option[value='custom']");

          if (custom.length === 1){
            item.val("custom");
            custom.text(getTextForCustom(key));
          }
        }

        item.change(function(){ // TODO change doesn't fire when Custom is already selected
          let val = item.val();

          if (val === "custom"){
            val = prompt("Enter custom value:");

            if (val){
              updateKey(key, val);
              item.find("option[value='custom']").text(getTextForCustom(key));
            }
          }
          else{
            updateKey(key, item.val());
          }
        });
      }
      // CUSTOM ELEMENTS
      else{
        let value = item.attr("data-td-value");

        if (value == me.config[key]){
          item.addClass("selected");
        }

        item.click(function(){
          modal.find("[data-td-key='"+key+"']").removeClass("selected");
          item.addClass("selected");
          updateKey(key, value);
        });
      }
    });

    // THEMES
    modal.find("[data-td-theme='"+TD.settings.getTheme()+"']").prop("checked", true);

    modal.find("[data-td-theme]").change(function(){
      setTimeout(function(){
        TD.settings.setTheme($(this).attr("data-td-theme"));
        $(document).trigger("uiToggleTheme");
      }, 1);
    });
  }).methods({
    _render: () => $(this.htmlModal),
    destroy: function(){
      if (this.reloadPage){
        location.reload();
        return;
      }

      $("#td-design-plugin-modal").hide();
      this.supr();
    }
  });

  // decider injections
  this.injectDeciderReplyHook = enable => {
    let prevFunc = TD.decider.updateFromBackend;

    TD.decider.updateFromBackend = function(data){
      data["simplified_replies"] = !enable;
      return prevFunc.apply(this, arguments);
    };

    TD.decider.updateForGuestId();
    this.$pluginSettings.requiresPageReload = enable;
  };

  // css and layout injection
  this.resetDesign = () => {
    if (this.css){
      this.css.remove();
    }

    this.css = window.TDPF_createCustomStyle(this);
  };

  this.reinjectAll = () => {
    this.resetDesign();

    this.css.insert(".txt-base-smallest:not(.icon), .txt-base-largest:not(.icon) { font-size: "+this.config.fontSize+" !important }");
    this.css.insert(".avatar { border-radius: "+this.config.avatarRadius+"% !important }");

    if (this.config.hideTweetActions){
      this.css.insert(".tweet-action { opacity: 0; }");
      this.css.insert(".is-favorite .tweet-action, .is-retweet .tweet-action { opacity: 0.5; visibility: visible !important }");
      this.css.insert(".tweet:hover .tweet-action, .is-favorite .tweet-action[rel='favorite'], .is-retweet .tweet-action[rel='retweet'] { opacity: 1; visibility: visible !important }");
    }

    if (this.config.moveTweetActionsToRight){
      this.css.insert(".tweet-actions { float: right !important; width: auto !important }");
      this.css.insert(".tweet-actions > li:nth-child(4) { margin-right: 2px !important }");
    }

    if (this.config.smallComposeTextSize){
      this.css.insert(".compose-text { font-size: 12px !important; height: 120px !important }");
    }

    if (!this.config.roundedScrollBars){
      this.css.insert(".scroll-styled-v:not(.antiscroll-inner)::-webkit-scrollbar { width: 8px }");
      this.css.insert(".scroll-styled-h:not(.antiscroll-inner)::-webkit-scrollbar { height: 8px }");
      this.css.insert(".scroll-styled-v::-webkit-scrollbar-thumb { border-radius: 0 }");
      this.css.insert(".scroll-styled-h::-webkit-scrollbar-thumb { border-radius: 0 }");
      this.css.insert(".antiscroll-scrollbar { border-radius: 0 }");
      this.css.insert(".antiscroll-scrollbar-vertical { margin-top: 0 }");
      this.css.insert(".antiscroll-scrollbar-horizontal { margin-left: 0 }");
    }

    if (this.config.optimizeAnimations){
      this.css.insert(".app-content { will-change: transform }");
      this.css.insert(".column-holder { will-change: transform }");
    }

    if (this.config.columnWidth[0] === '/'){
      let cols = this.config.columnWidth.slice(1);

      this.css.insert(".column { width: calc((100vw - 205px) / "+cols+" - 8px) !important }");
      this.css.insert(".is-condensed .column { width: calc((100vw - 55px) / "+cols+" - 8px) !important }");
    }
    else{
      this.css.insert(".column { width: "+this.config.columnWidth+" !important }");
    }

    switch(this.config.columnWidth){
      case "/6":
        TD.settings.setColumnWidth("narrow");
        break;

      case "310px":
      case "/5":
        TD.settings.setColumnWidth("medium");
        break;

      default:
        TD.settings.setColumnWidth(parseInt(this.config.columnWidth, 10) < 310 ? "narrow" : "wide"); // NaN will give "wide"
        break;
    }

    switch(this.config.fontSize){
      case "13px": TD.settings.setFontSize("small"); break;
      case "14px": TD.settings.setFontSize("medium"); break;
      case "15px": TD.settings.setFontSize("large"); break;
      default: TD.settings.setFontSize(parseInt(this.config.fontSize, 10) >= 16 ? "largest" : "smallest"); break;
    }

    $TDP.injectIntoNotificationsBefore(this.$token, "css", "", [
      ""
    ].join(""));
  };

  this.uiShowActionsMenuEvent = () => {
    if (this.config.moveTweetActionsToRight){
      $(".js-dropdown.pos-r").toggleClass("pos-r pos-l");
    }
  };
}

ready(){
  // configuration
  switch(TD.settings.getColumnWidth()){
    case "wide": this.defaultConfig.columnWidth = "350px"; break;
    case "narrow": this.defaultConfig.columnWidth = "270px"; break;
  }

  switch(TD.settings.getFontSize()){
    case "small": this.defaultConfig.fontSize = "13px"; break;
    case "medium": this.defaultConfig.fontSize = "14px"; break;
    case "large": this.defaultConfig.fontSize = "15px"; break;
    case "largest": this.defaultConfig.fontSize = "16px"; break;
  }

  this.onAppReady();

  // layout events
  $(document).on("uiShowActionsMenu", this.uiShowActionsMenuEvent);

  // modal
  $("[data-action='settings-menu']").on("click", this.onSettingsMenuClickedEvent);
  $(".js-app").append('

');
}

disabled(){
  if (this.css){
    this.css.remove();
  }

  $(document).off("uiShowActionsMenu", this.uiShowActionsMenuEvent);

  $("[data-action='settings-menu']").off("click", this.onSettingsMenuClickedEvent);
  $("#td-design-plugin-modal").remove();
}
<|endoftext|>


<commit_before>var ContentType = require('../constants/ContentType');
var MultipleMessages = require('./MultipleMessages.js');

exports.buildText = function(text) {
  return {
    contentType: ContentType.TEXT,
    text: text
  };
};

exports.buildImage = function(imageUrl, previewUrl) {
  return {
    contentType: ContentType.IMAGE,
    originalContentUrl: imageUrl,
    previewImageUrl: previewUrl
  };
};

exports.buildVideo = function(videoUrl, previewImageUrl) {
  return {
    contentType: ContentType.VIDEO,
    originalContentUrl: videoUrl,
    previewImageUrl: previewImageUrl
  };
};

exports.buildAudio = function(audioUrl, durationMillis) {
  return {
    contentType: ContentType.AUDIO,
    originalContentUrl: audioUrl,
    contentMetadata: { AUDLEN: durationMillis.toString() }
  };
};

exports.buildLocation = function(text, latitude, longitude) {
  return {
    contentType: ContentType.LOCATION,
    text: text,
    location: {
      title: text,
      latitude: latitude,
      longitude: longitude
    }
  };
};

exports.buildSticker = function(stkid, stkpkgid, stkver) {
  return {
    contentType: ContentType.STICKER,
    contentMetadata: [stkver].reduce((meta, stkver) => {
      if (stkver) meta.STKVER = stkver.toString();
      return meta;
    }, { STKID: stkid.toString(), STKPKGID: stkpkgid.toString() })
  };
};

exports.buildRichMessage = function(imageUrl, altText, markup) {
  return {
    contentType: ContentType.RICH_MESSAGE,
    contentMetadata: {
      SPEC_REV: '1',
      DOWNLOAD_URL: imageUrl,
      ALT_TEXT: altText,
      MARKUP_JSON: markup
    }
  };
};

exports.buildMultipleMessages = function(multipleMessages, messageNotified) {
  if (!(multipleMessages instanceof MultipleMessages)) throw new Error('Invalid multipleMessages');

  return {
    messages: multipleMessages.getMessages(),
    messageNotified: messageNotified
  }
};
<commit_msg>Fix buildSticker<commit_after>var ContentType = require('../constants/ContentType');
var MultipleMessages = require('./MultipleMessages.js');

exports.buildText = function(text) {
  return {
    contentType: ContentType.TEXT,
    text: text
  };
};

exports.buildImage = function(imageUrl, previewUrl) {
  return {
    contentType: ContentType.IMAGE,
    originalContentUrl: imageUrl,
    previewImageUrl: previewUrl
  };
};

exports.buildVideo = function(videoUrl, previewImageUrl) {
  return {
    contentType: ContentType.VIDEO,
    originalContentUrl: videoUrl,
    previewImageUrl: previewImageUrl
  };
};

exports.buildAudio = function(audioUrl, durationMillis) {
  return {
    contentType: ContentType.AUDIO,
    originalContentUrl: audioUrl,
    contentMetadata: { AUDLEN: durationMillis.toString() }
  };
};

exports.buildLocation = function(text, latitude, longitude) {
  return {
    contentType: ContentType.LOCATION,
    text: text,
    location: {
      title: text,
      latitude: latitude,
      longitude: longitude
    }
  };
};

exports.buildSticker = function(stkid, stkpkgid, stkver) {
  var meta = { STKID: stkid.toString(), STKPKGID: stkpkgid.toString() }
  if(stkver){
    meta.STKVER = stkver.toString();
  }

  return {
    contentType: ContentType.STICKER,
    contentMetadata: meta
  };
};

exports.buildRichMessage = function(imageUrl, altText, markup) {
  return {
    contentType: ContentType.RICH_MESSAGE,
    contentMetadata: {
      SPEC_REV: '1',
      DOWNLOAD_URL: imageUrl,
      ALT_TEXT: altText,
      MARKUP_JSON: markup
    }
  };
};

exports.buildMultipleMessages = function(multipleMessages, messageNotified) {
  if (!(multipleMessages instanceof MultipleMessages)) throw new Error('Invalid multipleMessages');

  return {
    messages: multipleMessages.getMessages(),
    messageNotified: messageNotified
  }
};
<|endoftext|>


<commit_before>/*
 * Copyright 2015-2016 OpenCB
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import {LitElement, html} from "/web_modules/lit-element.js";
import UtilsNew from "../../utilsNew.js";
import {NotificationQueue} from "../Notification.js";
import {RestResponse} from "../../clients/rest-response.js";

export default class OpencgaLogin extends LitElement {

    constructor() {
        super();

        this._init();
    }
    createRenderRoot() {
        return this;
    }

    static get properties() {
        return {
            opencgaSession: {
                type: Object
            },
            buttonText: {
                type: String
            },
            userName: {
                type: String
            },
            password: {
                type: String
            },
            notifyEventMessage: {
                type: String
            }
        };
    }

    _init() {
        this.userName = "";
        this.password = "";
        this.buttonText = "Sign in";
        this.signingIn = false;
    }

    firstUpdated(changedProperties) {
        $("#formLogin").validator("update");
        $("#formLogin").validator().on("submit", e => this.submitLogin(e));
    }

    submitLogin(e) {
        // console.log("e", e);
        if (e.isDefaultPrevented()) {
            console.error("submitLogin() Error", e);
            // handle the invalid form...
            // this._clearHtmlDom(true);
        } else {
            // everything looks good!
            e.preventDefault();
            // this.dispatchEvent(new CustomEvent("signingIn"));

            const user = this.querySelector("#opencgaUser").value;
            const pass = this.querySelector("#opencgaPassword").value;

            try {
                // in case a previous error has prevented the creation of opencgaSession object (in opencgaClient.createSession()), this would be undefined
                if (this.opencgaSession) {
                    this.opencgaSession.opencgaClient.login(user, pass)
                        .then(restResponse => {

                            if (restResponse instanceof RestResponse) {
                                if (restResponse.getEvents?.("ERROR")?.length) {
                                    this.errorState = restResponse.getEvents("ERROR");
                                    new NotificationQueue().push(this.errorState[0].name, this.errorState[0].message, "error");
                                } else if (restResponse) {
                                    this.querySelector("#opencgaUser").value = "";
                                    this.querySelector("#opencgaPassword").value = "";
                                    //console.log("response", restResponse);
                                    const token = restResponse.getResult(0).token;
                                    const decoded = jwt_decode(token); // TODO expose as module
                                    const dateExpired = new Date(decoded.exp * 1000);
                                    const validTimeSessionId = moment(dateExpired, "YYYYMMDDHHmmss").format("D MMM YY HH:mm:ss"); // TODO expose as module
                                    this.dispatchEvent(new CustomEvent("login", {
                                        detail: {
                                            userId: user,
                                            token: token
                                        },
                                        bubbles: true,
                                        composed: true
                                    }));
                                    new NotificationQueue().push("Welcome, " + user, "Your session is valid until " + validTimeSessionId, UtilsNew.MESSAGE_SUCCESS);

                                }
                            } else {
                                this.errorState = [{name: "Generic Server Error", message: "Unexpected response format. Please check your host is up and running."}];
                                new NotificationQueue().push(this.errorState[0].name, this.errorState[0].message, "error");
                            }
                        })
                        .catch(response => {
                            // response isn't necessarily a restResponse instance
                            if (response instanceof RestResponse) {
                                if (response.getEvents?.("ERROR")?.length) {
                                    this.errorState = response.getEvents("ERROR");
                                    this.errorState.forEach(error => new NotificationQueue().push(error.name, error.message, "ERROR"));
                                } else {
                                    this.errorState = [{name: "Generic Server Error", message: JSON.stringify(response)}];
                                    new NotificationQueue().push(this.errorState[0].name, this.errorState[0].message, "error");
                                }
                            } else if (response instanceof Error) {
                                this.errorState = [{name: response.name, message: response.message}];
                                new NotificationQueue().push(this.errorState[0].name, this.errorState[0].message, "error");
                            } else {
                                this.errorState = [{name: "Generic Error", message: JSON.JSON.stringify(response)}];
                                new NotificationQueue().push(this.errorState[0].name, this.errorState[0].message, "error");
                            }
                        }).finally(() => this.requestUpdate());
                } else {
                    new NotificationQueue().push("Error retrieving OpencgaSession", null, "ERROR");
                }
            } catch (e) {
                this.errorState = [{name: "Generic Error", message: "Please contact your administrator."}];

            }

        }

    }

    checkEnterKey(e) {
        if (e.keyCode === 13) {
            // this.login();
        }
    }

    render() {
        return html`

                    <form id="formLogin" data-toggle="validator" class="form-horizontal" role="form">

                            User ID

                                <input id="opencgaUser" value="${this.userName}" type="text" pattern="^[_\\-A-z0-9@\\.]+$" class="form-control input-login"
                                       placeholder="User ID (case sensitive)" aria-label="Recipient's username" aria-describedby="username" required data-required-error="This field is required">

                            Password

                                <input id="opencgaPassword" value="${this.password}" type="password" maxlength="30" class="form-control input-login"
                                       placeholder="Password" aria-describedby="password" required>

                            <button type="submit" class="btn btn-lg btn-primary btn-block ripple">${this.buttonText}</button>

                    </form>

        ${this.errorState?.length ? html`

                ${this.errorState.map(error => html`<p><strong>${error.name}</strong></p><p>${error.message}</p>`)}

        ` : null}
        `;
    }

}

customElements.define("opencga-login", OpencgaLogin);

<commit_msg>opencga-login: Redirect fixed #226<commit_after>/*
 * Copyright 2015-2016 OpenCB
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import {LitElement, html} from "/web_modules/lit-element.js";
import UtilsNew from "../../utilsNew.js";
import {NotificationQueue} from "../Notification.js";
import {RestResponse} from "../../clients/rest-response.js";

export default class OpencgaLogin extends LitElement {

    constructor() {
        super();

        this._init();
    }
    createRenderRoot() {
        return this;
    }

    static get properties() {
        return {
            opencgaSession: {
                type: Object
            },
            buttonText: {
                type: String
            },
            userName: {
                type: String
            },
            password: {
                type: String
            },
            notifyEventMessage: {
                type: String
            }
        };
    }

    _init() {
        this.userName = "";
        this.password = "";
        this.buttonText = "Sign in";
        this.signingIn = false;
    }

    firstUpdated(changedProperties) {
        $("#formLogin").validator("update");
        $("#formLogin").validator().on("submit", e => this.submitLogin(e));
        this.redirect();
    }

    updated(changedProperties) {
        if (changedProperties.has("opencgaSession")) {
            this.redirect();
        }
    }

    redirect() {
        if (this.opencgaSession?.study) {
            // window.location.hash = "#home";
            this.dispatchEvent(new CustomEvent("redirect", {
                detail: {
                    hash: "#home"
                }
            }));
        }
    }

    submitLogin(e) {
        // console.log("e", e);
        if (e.isDefaultPrevented()) {
            console.error("submitLogin() Error", e);
            // handle the invalid form...
            // this._clearHtmlDom(true);
        } else {
            // everything looks good!
            e.preventDefault();
            // this.dispatchEvent(new CustomEvent("signingIn"));

            const user = this.querySelector("#opencgaUser").value;
            const pass = this.querySelector("#opencgaPassword").value;

            try {
                // in case a previous error has prevented the creation of opencgaSession object (in opencgaClient.createSession()), this would be undefined
                if (this.opencgaSession) {
                    this.opencgaSession.opencgaClient.login(user, pass)
                        .then(restResponse => {

                            if (restResponse instanceof RestResponse) {
                                if (restResponse.getEvents?.("ERROR")?.length) {
                                    this.errorState = restResponse.getEvents("ERROR");
                                    new NotificationQueue().push(this.errorState[0].name, this.errorState[0].message, "error");
                                } else if (restResponse) {
                                    this.querySelector("#opencgaUser").value = "";
                                    this.querySelector("#opencgaPassword").value = "";
                                    const token = restResponse.getResult(0).token;
                                    const decoded = jwt_decode(token); // TODO expose as module
                                    const dateExpired = new Date(decoded.exp * 1000);
                                    const validTimeSessionId = moment(dateExpired, "YYYYMMDDHHmmss").format("D MMM YY HH:mm:ss"); // TODO expose as module
                                    this.dispatchEvent(new CustomEvent("login", {
                                        detail: {
                                            userId: user,
                                            token: token
                                        },
                                        bubbles: true,
                                        composed: true
                                    }));
                                    new NotificationQueue().push("Welcome, " + user, "Your session is valid until " + validTimeSessionId, UtilsNew.MESSAGE_SUCCESS);

                                }
                            } else {
                                this.errorState = [{name: "Generic Server Error", message: "Unexpected response format. Please check your host is up and running."}];
                                new NotificationQueue().push(this.errorState[0].name, this.errorState[0].message, "error");
                            }
                        })
                        .catch(response => {
                            // response isn't necessarily a restResponse instance
                            if (response instanceof RestResponse) {
                                if (response.getEvents?.("ERROR")?.length) {
                                    this.errorState = response.getEvents("ERROR");
                                    this.errorState.forEach(error => new NotificationQueue().push(error.name, error.message, "ERROR"));
                                } else {
                                    this.errorState = [{name: "Generic Server Error", message: JSON.stringify(response)}];
                                    new NotificationQueue().push(this.errorState[0].name, this.errorState[0].message, "error");
                                }
                            } else if (response instanceof Error) {
                                this.errorState = [{name: response.name, message: response.message}];
                                new NotificationQueue().push(this.errorState[0].name, this.errorState[0].message, "error");
                            } else {
                                this.errorState = [{name: "Generic Error", message: JSON.JSON.stringify(response)}];
                                new NotificationQueue().push(this.errorState[0].name, this.errorState[0].message, "error");
                            }
                        }).finally(() => this.requestUpdate());
                } else {
                    new NotificationQueue().push("Error retrieving OpencgaSession", null, "ERROR");
                }
            } catch (e) {
                this.errorState = [{name: "Generic Error", message: "Please contact your administrator."}];

            }

        }

    }

    checkEnterKey(e) {
        if (e.keyCode === 13) {
            // this.login();
        }
    }

    render() {
        return html`

                    <form id="formLogin" data-toggle="validator" class="form-horizontal" role="form">

                            User ID

                                <input id="opencgaUser" value="${this.userName}" type="text" pattern="^[_\\-A-z0-9@\\.]+$" class="form-control input-login"
                                       placeholder="User ID (case sensitive)" aria-label="Recipient's username" aria-describedby="username" required data-required-error="This field is required">

                            Password

                                <input id="opencgaPassword" value="${this.password}" type="password" maxlength="30" class="form-control input-login"
                                       placeholder="Password" aria-describedby="password" required>

                            <button type="submit" class="btn btn-lg btn-primary btn-block ripple">${this.buttonText}</button>

                    </form>

        ${this.errorState?.length ? html`

                ${this.errorState.map(error => html`<p><strong>${error.name}</strong></p><p>${error.message}</p>`)}

        ` : null}
        `;
    }

}

customElements.define("opencga-login", OpencgaLogin);

<|endoftext|>


<commit_before>/**
 *module to create message
 */
var url = require('url');
var logger = require('./logger');
var zenithMessage = require('./zenith_message');
var pjson = require('../package.json');

exports.buildMessage = buildMessage;
exports.buildResponse = buildResponse;

/**
 * build the message from the request
 * @param req request obj from the client
 * @param callback
 */
function buildMessage(req, callback){

	//things in the request object
	var parsedURL = url.parse(req.url, true);
	//every thing should be passed to the option from the request
    var transportHeaders = {

    		method: req.method,
    		headers: req.headers,
    		url : parsedURL

    };

    //set the headers from the transport to the message object
    zenithMessage.transportHeaders = transportHeaders;
    //set the content type
    if(req.headers['content-type'] != null){
    	 var contentType = req.headers['content-type'].split(';');
    	  //@TODO check whether charset value is needed
    	    zenithMessage.contentType = contentType[0];
    }

	//extract the body of the message
	var body = '';      /////////////////////might not work for every type
    req.on('data', function (chunk) {
    	//set the message body with the request's body
    	body = body + chunk;

    });

    req.on('end', function(){
    	logger.debug('MessageBuilder', 'Request : ' + body + '');
    	zenithMessage.body = body;

    	process(zenithMessage, function(result){
    		callback(result);
    	});
    });

    req.on('error', function(err){
    	callback(err, null);
    });

	return zenithMessage;
}

/**
 * build response to send to the requester
 * @param ZenithMessage
 * @param request
 * @param response
 * @param callback
 */
function buildResponse(zenithMessage, request, response, callback){
	//check the content type of the Zenith message and request
	/*
	var reqContentType = request.headers['content-type'].split(';');

	if(zenithMessage.contentType === reqContentType[0]) {
	logger.debug('MessageBuilder','similar content type : ' +
			request.headers['content-type']);

	//response.writeHead(proxy_response.statusCode, proxy_response.headers);
	response.writeHead(200+' OK', {'content-type':request.headers['content-type'],
		'server': pjson.name+'/'+pjson.version});
	response.write(zenithMessage.body);
	callback(null, response);

	} else {
	logger.debug('MessageBuilder','different content type. req : '
			+ reqContentType[0] + ' message : '
			+ zenithMessage.contentType);
		//convert the content type to suit the request
		//temperary
		response.write(zenithMessage.body);
		callback(null, response);
	}
	*/
	//////////////////TODO///////////////////////////
	//
	//	  handle the situation where err is passed.
	//	  build a default error message using request's
	//	  data (content type, etc) and build response
	//
	////////////////////////////////////////////////
	var requestContentType = request.headers['content-type'];
	var responseAcceptType = request.headers['accept'];
	var responseContentType = zenithMessage.contentType;
	logger.debug('MessageBuilder', 'Respose status: ' +
			zenithMessage.transportHeaders.statusCode + ' content-type: ' +
			responseContentType);

	zenithMessage.transportHeaders.headers['server'] = pjson.name+'/'+pjson.version;

	response.writeHead(zenithMessage.transportHeaders.statusCode,
				zenithMessage.transportHeaders.headers);
	response.write(zenithMessage.body);
	callback(null, response);

}
/**
 * method to do any additional processing after receiving
 * full message body
 * @param message
 * @param callback
 */
function process(message, callback){

	//no modification at the moment
	callback(message);
};
<commit_msg>default error handling method<commit_after>/**
 *module to create message
 */
var url = require('url');
var logger = require('./logger');
var zenithMessage = require('./zenith_message');
var pjson = require('../package.json');

exports.buildMessage = buildMessage;
exports.buildResponse = buildResponse;

/**
 * build the message from the request
 * @param req request obj from the client
 * @param callback
 */
function buildMessage(req, callback){

	//things in the request object
	var parsedURL = url.parse(req.url, true);
	//every thing should be passed to the option from the request
    var transportHeaders = {

    		method: req.method,
    		headers: req.headers,
    		url : parsedURL

    };

    //set the headers from the transport to the message object
    zenithMessage.transportHeaders = transportHeaders;
    //set the content type
    if(req.headers['content-type'] != null){
    	 var contentType = req.headers['content-type'].split(';');
    	  //@TODO check whether charset value is needed
    	    zenithMessage.contentType = contentType[0];
    }

	//extract the body of the message
	var body = '';      /////////////////////might not work for every type
    req.on('data', function (chunk) {
    	//set the message body with the request's body
    	body = body + chunk;

    });

    req.on('end', function(){
    	logger.debug('MessageBuilder', 'Request : ' + body + '');
    	zenithMessage.body = body;

    	process(zenithMessage, function(result){
    		callback(result);
    	});
    });

    req.on('error', function(err){
    	callback(err, null);
    });

	return zenithMessage;
}

/**
 * build response to send to the requester
 * @param ZenithMessage
 * @param request
 * @param response
 * @param callback
 */
function buildResponse(zenithMessage, request, response, callback){
	//check the content type of the Zenith message and request
	/*
	var reqContentType = request.headers['content-type'].split(';');

	if(zenithMessage.contentType === reqContentType[0]) {
	logger.debug('MessageBuilder','similar content type : ' +
			request.headers['content-type']);

	//response.writeHead(proxy_response.statusCode, proxy_response.headers);
	response.writeHead(200+' OK', {'content-type':request.headers['content-type'],
		'server': pjson.name+'/'+pjson.version});
	response.write(zenithMessage.body);
	callback(null, response);

	} else {
	logger.debug('MessageBuilder','different content type. req : '
			+ reqContentType[0] + ' message : '
			+ zenithMessage.contentType);
		//convert the content type to suit the request
		//temperary
		response.write(zenithMessage.body);
		callback(null, response);
	}
	*/
	//////////////////TODO///////////////////////////
	//
	//	  handle the situation where err is passed.
	//	  build a default error message using request's
	//	  data (content type, etc) and build response
	//
	////////////////////////////////////////////////
	//var requestContentType = request.headers['content-type'];
	//var responseAcceptType = request.headers['accept'];
	var responseContentType = zenithMessage.contentType;
	logger.debug('MessageBuilder', 'Respose status: ' +
			zenithMessage.transportHeaders.statusCode + ' content-type: ' +
			responseContentType);

	zenithMessage.transportHeaders.headers['server'] = pjson.name+'/'+pjson.version;

	response.writeHead(zenithMessage.transportHeaders.statusCode,
				zenithMessage.transportHeaders.headers);
	response.write(zenithMessage.body);
	callback(null, response);

}

function buildDefaultErrorResponse(zenithMessage, request, response, callback){
	response.writeHead(500, {'Content-Type': request.headers['content-type'],
						'Server': pjson.name+'/'+pjson.version
						});
	callback(null, response);

}
/**
 * method to do any additional processing after receiving
 * full message body
 * @param message
 * @param callback
 */
function process(message, callback){

	//no modification at the moment
	callback(message);
};
<|endoftext|>


<commit_before>import React, {Component} from 'react';
import {AppRegistry, StyleSheet, Alert, Text, View, Slider, TouchableOpacity, PixelRatio, Switch, ActivityIndicator, ScrollView, Platform} from 'react-native';

import SystemSetting from 'react-native-system-setting'

export default class SystemSettingExample extends Component {

    isAndroid = Platform.OS === 'android'

    volumeListener = null;

    volTypes = ['music', 'system', 'call', 'ring', 'alarm', 'notification']
    volIndex = 0

    constructor(props){
        super(props)
        this.state = {
            volume: 0,
            volType: this.volTypes[this.volIndex],
            brightness: 0,
            wifiEnable: false,
            wifiStateLoading: false,
            locationEnable: false,
            locationStateLoading: false,
            bluetoothEnable: false,
			bluetoothStateLoading: false,
			airplaneEnable: false,
			airplaneStateLoading: false,
        }
    }

    async componentDidMount(){
        this.setState({
            volume: await SystemSetting.getVolume(this.state.volType),
            brightness: await SystemSetting.getBrightness(),
            wifiEnable: await SystemSetting.isWifiEnabled(),
            locationEnable: await SystemSetting.isLocationEnabled(),
            bluetoothEnable: await SystemSetting.isBluetoothEnabled(),
            airplaneEnable: await SystemSetting.isAirplaneEnabled(),
        })
        // just init slider value directly
        this._changeSliderNativeVol(this.sliderVol, this.state.volume)
        this._changeSliderNativeVol(this.sliderBri, this.state.brightness)

        this.volumeListener = SystemSetting.addVolumeListener((data) => {
            const volume = this.isAndroid ? data[this.state.volType] : data.value
            this._changeSliderNativeVol(this.sliderVol, volume)
            this.setState({
                volume: volume
            })
        })
    }

    _changeSliderNativeVol(slider, value){
        slider.setNativeProps({
            value: value
        })
    }

    componentWillUnmount(){
        SystemSetting.removeVolumeListener(volumeListener)
    }

    _changeVol(value){
        SystemSetting.setVolume(value, this.state.volType)
        this.setState({
            volume: value
        })
    }

    _changeVolType = async () => {
        this.volIndex = ++this.volIndex % this.volTypes.length
        const volType = this.volTypes[this.volIndex]
        const vol = await SystemSetting.getVolume(volType)
        this._changeSliderNativeVol(this.sliderVol, vol)
        this.setState({
            volType: volType,
            volume: vol
        })
    }

    _changeBrightness = async (value) => {
		const result = await SystemSetting.setBrightnessForce(value)
		if(!result){
			Alert.alert('Permission Deny', 'You have no permission changing settings',[
				{'text': 'Ok', style: 'cancel'},
				{'text': 'Open Setting', onPress:()=>SystemSetting.grantWriteSettingPremission()}
			])
			return
		}
        this.setState({
            brightness: value,
        })
	}

    _restoreBrightness(){
        const saveBrightnessVal = SystemSetting.restoreBrightness()
        if(saveBrightnessVal > -1){
            // success
            this.setState({
                brightness: saveBrightnessVal
            })
            this._changeSliderNativeVol(this.sliderBri, saveBrightnessVal)
        }
    }

    _switchWifi(){
        this.setState({
            wifiStateLoading: true
        })
        SystemSetting.switchWifi(async () => {
            this.setState({
                wifiEnable: await SystemSetting.isWifiEnabled(),
                wifiStateLoading: false
            })
        })
    }

    _switchLocation(){
        this.setState({
            locationStateLoading: true
        })
        SystemSetting.switchLocation(async () => {
            this.setState({
                locationEnable: await SystemSetting.isLocationEnabled(),
                locationStateLoading: false
            })
        })
    }

    _switchBluetooth(){
        this.setState({
            bluetoothStateLoading: true
        })
        SystemSetting.switchBluetooth(async () => {
            this.setState({
                bluetoothEnable: await SystemSetting.isBluetoothEnabled(),
                bluetoothStateLoading: false
            })
        })
    }

    _switchAirplane(){
        this.setState({
            airplaneStateLoading: true
        })
        SystemSetting.switchAirplane(async () => {
            this.setState({
                airplaneEnable: await SystemSetting.isAirplaneEnabled(),
                airplaneStateLoading: false
            })
        })
    }

    render() {
		const {volume, brightness,
			wifiEnable, wifiStateLoading,
			locationEnable, locationStateLoading,
			bluetoothEnable, bluetoothStateLoading,
			airplaneEnable, airplaneStateLoading,
		} = this.state
        return (
            <ScrollView style={styles.container}>
                <View style={styles.head}>
                </View>
                <ValueView
                    title='Volume'
                    btn={this.isAndroid && {
                        title: this.state.volType,
                        onPress: this._changeVolType
                    }}
                    value={volume}
                    changeVal={(val)=>this._changeVol(val)}
                    refFunc={(sliderVol)=>this.sliderVol = sliderVol}
                />
                <ValueView
                    title='Brightness'
                    value={brightness}
                    changeVal={(val)=>this._changeBrightness(val)}
                    refFunc={(sliderBri)=>this.sliderBri = sliderBri}
                />
                <View style={styles.card}>
                    <View style={styles.row}>
                        <Text style={styles.title}>Brightness save & restore
                        </Text>
                    </View>
                    <View style={styles.row}>
                        <TouchableOpacity style={{marginRight:32}} onPress={SystemSetting.saveBrightness}>
                            <Text style={styles.btn}>Save
                            </Text>
                        </TouchableOpacity>
                        <TouchableOpacity onPress={this._restoreBrightness.bind(this)}>
                            <Text style={styles.btn}>Restore
                            </Text>
                        </TouchableOpacity>
                    </View>
                </View>
                <StatusView
                    title='Wifi'
                    value={wifiEnable}
                    loading={wifiStateLoading}
                    switchFunc={(value) => this._switchWifi()}/>
                <StatusView
                    title='Location'
                    value={locationEnable}
                    loading={locationStateLoading}
                    switchFunc={(value) => this._switchLocation()}/>
                <StatusView
                    title='Bluetooth'
                    value={bluetoothEnable}
                    loading={bluetoothStateLoading}
                    switchFunc={(value) => this._switchBluetooth()}/>
                <StatusView
                    title='Airplane'
                    value={airplaneEnable}
                    loading={airplaneStateLoading}
                    switchFunc={(value) => this._switchAirplane()}/>
            </ScrollView>
        );
    }
}

const ValueView = (props)=>{
    const {title, value, changeVal, refFunc, btn} = props
    return(
        <View style={styles.card}>
            <View style={styles.row}>
                <Text style={styles.title}>{title}</Text>
                {btn && <TouchableOpacity onPress={btn.onPress}>
                            <Text style={styles.btn}>{btn.title}
                            </Text>
                        </TouchableOpacity>}
                <Text style={styles.value}>{value}</Text>
            </View>
            <Slider
                ref={refFunc}
                style={styles.slider}
                onValueChange={changeVal} />
        </View>
    )
}

const StatusView = (props)=>{
    const {title, switchFunc, value, loading} = props
    return(
        <View style={styles.card}>
            <View style={styles.row}>
                <Text style={styles.title}>{title}
                </Text>
            </View>
            <View style={styles.row}>
                <Text>Current status is { loading ? 'switching': (value ? 'On' : 'Off')}
                </Text>
                {
                    loading&&<ActivityIndicator animating={loading}/>
                }
                <View style={{flex:1, alignItems:'flex-end'}}>
                    <Switch
                        onValueChange={switchFunc}
                        value={value} />
                </View>
            </View>
        </View>
    )
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
        backgroundColor: '#E5E7E8'
    },
    head:{
        justifyContent: 'center',
        alignItems: 'center',
        height: 64,
    },
    headline:{
        fontSize: 22,
        color: '#666'
    },
    card:{
        padding:8,
        backgroundColor: '#fff',
        marginTop:4,
        marginBottom:4,
    },
    row:{
        flexDirection:'row',
        alignItems:'center',
        paddingTop:8,
        paddingBottom:8,
    },
    title:{
        fontSize: 16,
        color: '#6F6F6F'
    },
    value:{
        fontSize: 14,
        flex:1,
        textAlign:'right',
        color: '#904ED9'
    },
    split:{
        marginVertical: 16,
        height: 1,
        backgroundColor: '#ccc',
    },
    btn:{
        fontSize: 16,
        padding: 8,
        paddingVertical: 8,
        color: '#405EFF'
    }
});

AppRegistry.registerComponent('SystemSettingExample', () => SystemSettingExample);
<commit_msg>setVolume(val, config)<commit_after>import React, {Component} from 'react';
import {AppRegistry, StyleSheet, Alert, Text, View, Slider, TouchableOpacity, PixelRatio, Switch, ActivityIndicator, ScrollView, Platform} from 'react-native';

import SystemSetting from 'react-native-system-setting'

export default class SystemSettingExample extends Component {

    isAndroid = Platform.OS === 'android'

    volumeListener = null;

    volTypes = ['music', 'system', 'call', 'ring', 'alarm', 'notification']
    volIndex = 0

    constructor(props){
        super(props)
        this.state = {
            volume: 0,
            volType: this.volTypes[this.volIndex],
            brightness: 0,
            wifiEnable: false,
            wifiStateLoading: false,
            locationEnable: false,
            locationStateLoading: false,
            bluetoothEnable: false,
			bluetoothStateLoading: false,
			airplaneEnable: false,
			airplaneStateLoading: false,
        }
    }

    async componentDidMount(){
        this.setState({
            volume: await SystemSetting.getVolume(this.state.volType),
            brightness: await SystemSetting.getBrightness(),
            wifiEnable: await SystemSetting.isWifiEnabled(),
            locationEnable: await SystemSetting.isLocationEnabled(),
            bluetoothEnable: await SystemSetting.isBluetoothEnabled(),
            airplaneEnable: await SystemSetting.isAirplaneEnabled(),
        })
        // just init slider value directly
        this._changeSliderNativeVol(this.sliderVol, this.state.volume)
        this._changeSliderNativeVol(this.sliderBri, this.state.brightness)

        this.volumeListener = SystemSetting.addVolumeListener((data) => {
            const volume = this.isAndroid ? data[this.state.volType] : data.value
            this._changeSliderNativeVol(this.sliderVol, volume)
            this.setState({
                volume: volume
            })
        })
    }

    _changeSliderNativeVol(slider, value){
        slider.setNativeProps({
            value: value
        })
    }

    componentWillUnmount(){
        SystemSetting.removeVolumeListener(volumeListener)
    }

    _changeVol(value){
        SystemSetting.setVolume(value, {
            type: this.state.volType,
            playSound: false,
            showUI: false
        })
        this.setState({
            volume: value
        })
    }

    _changeVolType = async () => {
        this.volIndex = ++this.volIndex % this.volTypes.length
        const volType = this.volTypes[this.volIndex]
        const vol = await SystemSetting.getVolume(volType)
        this._changeSliderNativeVol(this.sliderVol, vol)
        this.setState({
            volType: volType,
            volume: vol
        })
    }

    _changeBrightness = async (value) => {
		const result = await SystemSetting.setBrightnessForce(value)
		if(!result){
			Alert.alert('Permission Deny', 'You have no permission changing settings',[
				{'text': 'Ok', style: 'cancel'},
				{'text': 'Open Setting', onPress:()=>SystemSetting.grantWriteSettingPremission()}
			])
			return
		}
        this.setState({
            brightness: value,
        })
	}

    _restoreBrightness(){
        const saveBrightnessVal = SystemSetting.restoreBrightness()
        if(saveBrightnessVal > -1){
            // success
            this.setState({
                brightness: saveBrightnessVal
            })
            this._changeSliderNativeVol(this.sliderBri, saveBrightnessVal)
        }
    }

    _switchWifi(){
        this.setState({
            wifiStateLoading: true
        })
        SystemSetting.switchWifi(async () => {
            this.setState({
                wifiEnable: await SystemSetting.isWifiEnabled(),
                wifiStateLoading: false
            })
        })
    }

    _switchLocation(){
        this.setState({
            locationStateLoading: true
        })
        SystemSetting.switchLocation(async () => {
            this.setState({
                locationEnable: await SystemSetting.isLocationEnabled(),
                locationStateLoading: false
            })
        })
    }

    _switchBluetooth(){
        this.setState({
            bluetoothStateLoading: true
        })
        SystemSetting.switchBluetooth(async () => {
            this.setState({
                bluetoothEnable: await SystemSetting.isBluetoothEnabled(),
                bluetoothStateLoading: false
            })
        })
    }

    _switchAirplane(){
        this.setState({
            airplaneStateLoading: true
        })
        SystemSetting.switchAirplane(async () => {
            this.setState({
                airplaneEnable: await SystemSetting.isAirplaneEnabled(),
                airplaneStateLoading: false
            })
        })
    }

    render() {
		const {volume, brightness,
			wifiEnable, wifiStateLoading,
			locationEnable, locationStateLoading,
			bluetoothEnable, bluetoothStateLoading,
			airplaneEnable, airplaneStateLoading,
		} = this.state
        return (
            <ScrollView style={styles.container}>
                <View style={styles.head}>
                </View>
                <ValueView
                    title='Volume'
                    btn={this.isAndroid && {
                        title: this.state.volType,
                        onPress: this._changeVolType
                    }}
                    value={volume}
                    changeVal={(val)=>this._changeVol(val)}
                    refFunc={(sliderVol)=>this.sliderVol = sliderVol}
                />
                <ValueView
                    title='Brightness'
                    value={brightness}
                    changeVal={(val)=>this._changeBrightness(val)}
                    refFunc={(sliderBri)=>this.sliderBri = sliderBri}
                />
                <View style={styles.card}>
                    <View style={styles.row}>
                        <Text style={styles.title}>Brightness save & restore
                        </Text>
                    </View>
                    <View style={styles.row}>
                        <TouchableOpacity style={{marginRight:32}} onPress={SystemSetting.saveBrightness}>
                            <Text style={styles.btn}>Save
                            </Text>
                        </TouchableOpacity>
                        <TouchableOpacity onPress={this._restoreBrightness.bind(this)}>
                            <Text style={styles.btn}>Restore
                            </Text>
                        </TouchableOpacity>
                    </View>
                </View>
                <StatusView
                    title='Wifi'
                    value={wifiEnable}
                    loading={wifiStateLoading}
                    switchFunc={(value) => this._switchWifi()}/>
                <StatusView
                    title='Location'
                    value={locationEnable}
                    loading={locationStateLoading}
                    switchFunc={(value) => this._switchLocation()}/>
                <StatusView
                    title='Bluetooth'
                    value={bluetoothEnable}
                    loading={bluetoothStateLoading}
                    switchFunc={(value) => this._switchBluetooth()}/>
                <StatusView
                    title='Airplane'
                    value={airplaneEnable}
                    loading={airplaneStateLoading}
                    switchFunc={(value) => this._switchAirplane()}/>
            </ScrollView>
        );
    }
}

const ValueView = (props)=>{
    const {title, value, changeVal, refFunc, btn} = props
    return(
        <View style={styles.card}>
            <View style={styles.row}>
                <Text style={styles.title}>{title}</Text>
                {btn && <TouchableOpacity onPress={btn.onPress}>
                            <Text style={styles.btn}>{btn.title}
                            </Text>
                        </TouchableOpacity>}
                <Text style={styles.value}>{value}</Text>
            </View>
            <Slider
                ref={refFunc}
                style={styles.slider}
                onValueChange={changeVal} />
        </View>
    )
}

const StatusView = (props)=>{
    const {title, switchFunc, value, loading} = props
    return(
        <View style={styles.card}>
            <View style={styles.row}>
                <Text style={styles.title}>{title}
                </Text>
            </View>
            <View style={styles.row}>
                <Text>Current status is { loading ? 'switching': (value ? 'On' : 'Off')}
                </Text>
                {
                    loading&&<ActivityIndicator animating={loading}/>
                }
                <View style={{flex:1, alignItems:'flex-end'}}>
                    <Switch
                        onValueChange={switchFunc}
                        value={value} />
                </View>
            </View>
        </View>
    )
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
        backgroundColor: '#E5E7E8'
    },
    head:{
        justifyContent: 'center',
        alignItems: 'center',
        height: 64,
    },
    headline:{
        fontSize: 22,
        color: '#666'
    },
    card:{
        padding:8,
        backgroundColor: '#fff',
        marginTop:4,
        marginBottom:4,
    },
    row:{
        flexDirection:'row',
        alignItems:'center',
        paddingTop:8,
        paddingBottom:8,
    },
    title:{
        fontSize: 16,
        color: '#6F6F6F'
    },
    value:{
        fontSize: 14,
        flex:1,
        textAlign:'right',
        color: '#904ED9'
    },
    split:{
        marginVertical: 16,
        height: 1,
        backgroundColor: '#ccc',
    },
    btn:{
        fontSize: 16,
        padding: 8,
        paddingVertical: 8,
        color: '#405EFF'
    }
});

AppRegistry.registerComponent('SystemSettingExample', () => SystemSettingExample);
<|endoftext|>


<commit_before>define(["utils", "Zepto"], function(Utils) {

var ResizeImages = {}

  , absolutify = document.createElement('a')

    // A regex for detecting http(s) URLs.
  , httpRe = /^https?/

    // A protocol relative URL for the host ir0.mobify.com.
  , PROTOCOL_AND_HOST = '//ir0.mobify.com'

    /**
     * Returns a URL suitable for use with the 'ir' service.
     */
  , getImageURL = ResizeImages.getImageURL = function(url, options) {
        options = options || {}

        var bits = [PROTOCOL_AND_HOST];

        if (defaults.projectName) {
            var projectId = "project-" + defaults.projectName;
            bits.push(projectId);
        }

        if (options.format) {
            bits.push(options.format + (options.quality || ''));
        }

        if (options.maxWidth) {
            bits.push(options.maxWidth)

            if (options.maxHeight) {
                bits.push(options.maxHeight);
            }
        }

        bits.push(url);
        return bits.join('/');
    }

    /**
     * Searches the collection for image elements and modifies them to use
     * the Image Resize service. Pass `options` to modify how the images are
     * resized.
     */
  , resizeImages = ResizeImages.resize = function(document, options) {
        var opts;
        if (typeof options == 'object') {
            opts = Utils.extend(defaults, options);
        } else {
            opts = defaults;
        }
        var dpr = window.devicePixelRatio;
        var imgs = document.querySelectorAll(opts.selector);
        var attr;

        if (typeof options == 'number') {
            opts.maxWidth = Math.floor(options);
        }

        if (dpr) {
            if (opts.maxWidth) {
                opts.maxWidth = Math.ceil(opts.maxWidth * dpr);
            }

            if (opts.maxHeight) {
                opts.maxHeight = Math.ceil(opts.maxHeight * dpr);
            }
        }

        for(var i=0; i<imgs.length; i++) {
            var img = imgs[i];
            if (attr = img.getAttribute(opts.attribute)) {
                absolutify.href = attr;
                var url = absolutify.href;
                if (httpRe.test(url)) {
                    img.setAttribute('x-src', getImageURL(url, opts));
                }
            }
        }
        return imgs;
    }

  , defaults = resizeImages.defaults = {
        selector: 'img'
      , attribute: 'x-src'
      , projectName: ''
    };

  return ResizeImages;

});
<commit_msg>Removed forgotten Zepto dependancy in resizeImages. Reduced full library size by 60%!<commit_after>define(["utils"], function(Utils) {

var ResizeImages = {}

  , absolutify = document.createElement('a')

    // A regex for detecting http(s) URLs.
  , httpRe = /^https?/

    // A protocol relative URL for the host ir0.mobify.com.
  , PROTOCOL_AND_HOST = '//ir0.mobify.com'

    /**
     * Returns a URL suitable for use with the 'ir' service.
     */
  , getImageURL = ResizeImages.getImageURL = function(url, options) {
        options = options || {}

        var bits = [PROTOCOL_AND_HOST];

        if (defaults.projectName) {
            var projectId = "project-" + defaults.projectName;
            bits.push(projectId);
        }

        if (options.format) {
            bits.push(options.format + (options.quality || ''));
        }

        if (options.maxWidth) {
            bits.push(options.maxWidth)

            if (options.maxHeight) {
                bits.push(options.maxHeight);
            }
        }

        bits.push(url);
        return bits.join('/');
    }

    /**
     * Searches the collection for image elements and modifies them to use
     * the Image Resize service. Pass `options` to modify how the images are
     * resized.
     */
  , resizeImages = ResizeImages.resize = function(document, options) {
        var opts;
        if (typeof options == 'object') {
            opts = Utils.extend(defaults, options);
        } else {
            opts = defaults;
        }
        var dpr = window.devicePixelRatio;
        var imgs = document.querySelectorAll(opts.selector);
        var attr;

        if (typeof options == 'number') {
            opts.maxWidth = Math.floor(options);
        }

        if (dpr) {
            if (opts.maxWidth) {
                opts.maxWidth = Math.ceil(opts.maxWidth * dpr);
            }

            if (opts.maxHeight) {
                opts.maxHeight = Math.ceil(opts.maxHeight * dpr);
            }
        }

        for(var i=0; i<imgs.length; i++) {
            var img = imgs[i];
            if (attr = img.getAttribute(opts.attribute)) {
                absolutify.href = attr;
                var url = absolutify.href;
                if (httpRe.test(url)) {
                    img.setAttribute('x-src', getImageURL(url, opts));
                }
            }
        }
        return imgs;
    }

  , defaults = resizeImages.defaults = {
        selector: 'img'
      , attribute: 'x-src'
      , projectName: ''
    };

  return ResizeImages;

});
<|endoftext|>


<commit_before>var State = require('../state')
  , utils = require('../utils');

/**
 * Load state.
 *
 * This middleware is used to load state associated with a request.  The state
 * will be made available at `req.state`.
 *
 * HTTP is a stateless protocol.  In order to support stateful interactions, the
 * client and server need to operate in coordination.  The server is responsible
 * for persisting state associated with a request.  The client is responsible for
 * indicating that state in subsequent requests to the server (via a `state`
 * parameter in the query or body, by default).  The server then loads the
 * previously persisted state in order to continue processing the transaction.
 *
 * Options:
 *
 *     name   set req.state only if the state name is equal to the option value
 *     required   require state, failing otherwise (default: false)
 *
 * Examples:
 *
 *     app.get('/login',
 *       flowstate.loadState(),
 *       function(req, res, next) {
 *         res.locals.failureCount = req.state.failureCount;
 *         res.render('login');
 *       });
 *
 *     app.get('/login/callback',
 *       flowstate.loadState({ name: 'oauth2-redirect', required: true }),
 *       function(req, res, next) {
 *         // ...
 *       });
 *
 * @return {Function}
 * @api public
 */
module.exports = function(store, options) {
  if (typeof options == 'string') {
    options = { name: options };
  }
  options = options || {};

  // FIXME: remvoe uses of name variable
  var name = undefined;
  var required = options.required !== undefined ? options.required : false;
  var getHandle = options.getHandle || function(req) {
    return (req.query && req.query.state) || (req.body && req.body.state);
  }

  return function loadState(req, res, next) {
    console.log('!!! LOADING!!!');

    var h = getHandle(req);
    if (!h) {
      if (required) {
        // TODO: Should this be a client error?
        return next(new Error("Failed to load required state" + (name ? " '" + name + "'" : "")));
      }
      return next();
    }

    function loaded(err, state) {
      console.log('LOADED STATE &&&');
      console.log(state)

      //err = new Error('wtf')
      //err.state = state

      if (err) {
        if (err.state) {
          if (!name) {
            req.state = err.state;
          } else if (err.state.name == name) {
            req.state = err.state;
          }
        }
        return next(err);
      }

      if (!state) {
        return required ? next(new Error("Failed to load required state" + (name ? " '" + name + "'" : "")))
                        : next();
      }

      state = new State(req, state, h);

      if (state.location && state.location !== utils.originalURLWithoutQuery(req)) {
        req.state = new State(req, { state: h });
      } else if (!name) {
        // TODO: Remove this
        req.state = state;
      } else if (state && state.name == name) {
        // TODO: remove this
        req.state = state;
      } else {
        // The loaded state is not the expected state.  Save what was loaded,
        // as an optimization to avoid re-loading later if the state is resumed.
        req._state = state;
      }

      if (required && !req.state) {
        return next(new Error("Failed to load required state" + (name ? " '" + name + "'" : "")));
      }
      next();
    }

    console.log('LOADING, WITH OPTIONS');
    console.log(options);

    if (options.get) {
      options.get(req, h, loaded);

      return;
    }

    store.load(req, h, loaded);
  };
};
<commit_msg>Silence verbose logging.<commit_after>var State = require('../state')
  , utils = require('../utils');

/**
 * Load state.
 *
 * This middleware is used to load state associated with a request.  The state
 * will be made available at `req.state`.
 *
 * HTTP is a stateless protocol.  In order to support stateful interactions, the
 * client and server need to operate in coordination.  The server is responsible
 * for persisting state associated with a request.  The client is responsible for
 * indicating that state in subsequent requests to the server (via a `state`
 * parameter in the query or body, by default).  The server then loads the
 * previously persisted state in order to continue processing the transaction.
 *
 * Options:
 *
 *     name   set req.state only if the state name is equal to the option value
 *     required   require state, failing otherwise (default: false)
 *
 * Examples:
 *
 *     app.get('/login',
 *       flowstate.loadState(),
 *       function(req, res, next) {
 *         res.locals.failureCount = req.state.failureCount;
 *         res.render('login');
 *       });
 *
 *     app.get('/login/callback',
 *       flowstate.loadState({ name: 'oauth2-redirect', required: true }),
 *       function(req, res, next) {
 *         // ...
 *       });
 *
 * @return {Function}
 * @api public
 */
module.exports = function(store, options) {
  if (typeof options == 'string') {
    options = { name: options };
  }
  options = options || {};

  // FIXME: remvoe uses of name variable
  var name = undefined;
  var required = options.required !== undefined ? options.required : false;
  var getHandle = options.getHandle || function(req) {
    return (req.query && req.query.state) || (req.body && req.body.state);
  }

  return function loadState(req, res, next) {
    var h = getHandle(req);
    if (!h) {
      if (required) {
        // TODO: Should this be a client error?
        return next(new Error("Failed to load required state" + (name ? " '" + name + "'" : "")));
      }
      return next();
    }

    function loaded(err, state) {
      //err = new Error('wtf')
      //err.state = state

      if (err) {
        if (err.state) {
          if (!name) {
            req.state = err.state;
          } else if (err.state.name == name) {
            req.state = err.state;
          }
        }
        return next(err);
      }

      if (!state) {
        return required ? next(new Error("Failed to load required state" + (name ? " '" + name + "'" : "")))
                        : next();
      }

      state = new State(req, state, h);

      if (state.location && state.location !== utils.originalURLWithoutQuery(req)) {
        req.state = new State(req, { state: h });
      } else if (!name) {
        // TODO: Remove this
        req.state = state;
      } else if (state && state.name == name) {
        // TODO: remove this
        req.state = state;
      } else {
        // The loaded state is not the expected state.  Save what was loaded,
        // as an optimization to avoid re-loading later if the state is resumed.
        req._state = state;
      }

      if (required && !req.state) {
        return next(new Error("Failed to load required state" + (name ? " '" + name + "'" : "")));
      }
      next();
    }

    if (options.get) {
      options.get(req, h, loaded);

      return;
    }

    store.load(req, h, loaded);
  };
};
<|endoftext|>


<commit_before>'use strict';

/**
 * Extend the `file` object with Assemble's default
 * template properties.
 */

module.exports = function(file, next) {
  file.data.page = file.data || {};
  next();
};
<commit_msg>missing .page in page middleware<commit_after>'use strict';

/**
 * Extend the `file` object with Assemble's default
 * template properties.
 */

module.exports = function(file, next) {
  file.data.page = file.data.page || {};
  next();
};
<|endoftext|>


<commit_before>var _ = require('lodash');
var utils = require('./utils');

module.exports = {

    run: function (carrier) {

        carrier.pickupEnergyInRange();

        if (_.sum(carrier.carry) === carrier.carryCapacity || carrier.ticksToLive < 50) {
            carrier.memory.inDeliveryMode = true;
        } else if (_.sum(carrier.carry) === 0) {
            carrier.memory.inDeliveryMode = false;
        }

        this.transferEnergyToAdjacentBuilders(carrier);

        if (carrier.memory.inDeliveryMode) {
            var dropOff = utils.findClosestEnergyDropOff(carrier.pos);
            if (dropOff) {
                if (!carrier.pos.isNearTo(dropOff)) {
                    carrier.moveTo(dropOff);
                }

                if (carrier.pos.isNearTo(dropOff)) {
                    carrier.transfer(dropOff, RESOURCE_ENERGY);
                }
            }
        } else {
            var miner = this.getMiner(carrier);
            if (miner) {
                if (!carrier.pos.isNearTo(miner)) {
                    // It's enough to get close to the miner. The miner will realize this
                    // and transfer its energy on its own. If the miner has dropped energy
                    // on the ground, that will get picked up by pickupEnergyInRange()
                    carrier.moveTo(miner);
                }
            } else {
                // No miners in the room, check for energy piles
                var energy = carrier.pos.findClosestByPath(FIND_DROPPED_ENERGY);
                if (energy && !carrier.pos.isNearTo(energy) && !carrier.fatigue) {
                    carrier.moveTo(energy);
                }
            }
        }

        // In case we moved. Energy pickups are free!
        carrier.pickupEnergyInRange();
    },

    getBody: function (energy) {
        if (energy < BODYPART_COST[CARRY] + BODYPART_COST[MOVE]) {
            return null;
        }

        var carry = [], move = [];
        var cheapestPart = _.min([BODYPART_COST[CARRY], BODYPART_COST[MOVE]]);

        while (energy >= cheapestPart) {
            if (energy >= BODYPART_COST[MOVE] &&
                    (!move.length || move.length * 2 < carry.length || energy < BODYPART_COST[CARRY])) {
                energy = this.addPart(energy, move, MOVE);
            } else if (energy >= BODYPART_COST[CARRY]) {
                energy = this.addPart(energy, carry, CARRY);
            } else {
                // Should never end up here, but just to make sure we avoid an infinite loop
                break;
            }
        }

        return carry.concat(move);
    },

    transferEnergyToAdjacentBuilders: function (carrier) {
        if (carrier.carry.energy > 0) {
            var adjacentNonFullBuilders = carrier.pos.findInRange(FIND_MY_CREEPS, 1, {
                filter: creep => creep.memory.role === ROLE_BUILDER && creep.carry.energy < creep.carryCapacity
            });
            _.forEach(adjacentNonFullBuilders, function (builder) {
                if (carrier.carry.energy > 0) {
                    carrier.transfer(builder, RESOURCE_ENERGY);
                }
            })
        }

    },

    getMiner: function (carrier) {
        var miner = Game.getObjectById(carrier.memory.minerId);

        if (miner) {
            if (!miner.memory.carrierId) {
                miner.memory.carrierId = carrier.id;
            }
            return miner;
        } else {
            // Miner not found, maybe destroyed in a fight, or broke down due to aging.

            var miners = carrier.room.find(FIND_MY_CREEPS, {
                filter: creep => creep.memory.role == ROLE_MINER
            });

            if (!miners.length) {
                // No miners available, just wait until some are made
                carrier.memory.minerId = null;
                carrier.memory.sourceId = null;
                return null;
            }

            _.forEach(miners, function (creep) {
                if (!Game.getObjectById(creep.memory.carrierId)) {
                    miner = creep;
                    return false;
                }
            });

            if (miner) {
                carrier.memory.minerId = miner.id;
                carrier.memory.sourceId = miner.memory.sourceId;
                miner.memory.carrierId = carrier.id;
                return miner;
            }

            // Link to an existing miner
            miner = carrier.pos.findClosestByPath(miners);
            // Don't override the carrier reference in the miner, as the current one is still valid
            carrier.memory.minerId = miner.id;
            carrier.memory.sourceId = miner.memory.sourceId;

            return miner;
        }
    },

    addPart: function (energy, parts, part) {
        parts.push(part);
        return energy - BODYPART_COST[part];
    }
};<commit_msg>Carriers now pick up energy from the container under the miner and deliver it to spawns and extensions<commit_after>var _ = require('lodash');
var utils = require('./utils');

module.exports = {

    run: function (carrier) {

        carrier.pickupEnergyInRange();

        if (_.sum(carrier.carry) === carrier.carryCapacity || carrier.ticksToLive < 50) {
            carrier.memory.inDeliveryMode = true;
        } else if (_.sum(carrier.carry) === 0) {
            carrier.memory.inDeliveryMode = false;
        }

        this.transferEnergyToAdjacentBuilders(carrier);

        if (carrier.memory.inDeliveryMode) {
            var dropOff = utils.findClosestEnergyDropOff(carrier.pos);
            if (dropOff) {
                if (!carrier.pos.isNearTo(dropOff)) {
                    carrier.moveTo(dropOff);
                }

                if (carrier.pos.isNearTo(dropOff)) {
                    carrier.transfer(dropOff, RESOURCE_ENERGY);
                }
            }
        } else {
            var miner = this.getMiner(carrier);
            if (miner) {
                if (!carrier.pos.isNearTo(miner)) {
                    // It's enough to get close to the miner. The miner will realize this
                    // and transfer its energy on its own. If the miner has dropped energy
                    // on the ground, that will get picked up by pickupEnergyInRange()
                    carrier.moveTo(miner);
                } else {
                    // Pick up energy from the container under the miner
                    var container = _.head(_.filter(miner.pos.lookFor(LOOK_STRUCTURES),
                            {'structureType': STRUCTURE_CONTAINER}));
                    if (container && container.store[RESOURCE_ENERGY] > 0) {
                        container.transfer(carrier, RESOURCE_ENERGY);
                    }
                }
            } else {
                // No miners in the room, check for energy piles
                var energy = carrier.pos.findClosestByPath(FIND_DROPPED_ENERGY);
                if (energy && !carrier.pos.isNearTo(energy) && !carrier.fatigue) {
                    carrier.moveTo(energy);
                }
            }
        }

        // In case we moved. Energy pickups are free!
        carrier.pickupEnergyInRange();
    },

    getBody: function (energy) {
        if (energy < BODYPART_COST[CARRY] + BODYPART_COST[MOVE]) {
            return null;
        }

        var carry = [], move = [];
        var cheapestPart = _.min([BODYPART_COST[CARRY], BODYPART_COST[MOVE]]);

        while (energy >= cheapestPart) {
            if (energy >= BODYPART_COST[MOVE] &&
                    (!move.length || move.length * 2 < carry.length || energy < BODYPART_COST[CARRY])) {
                energy = this.addPart(energy, move, MOVE);
            } else if (energy >= BODYPART_COST[CARRY]) {
                energy = this.addPart(energy, carry, CARRY);
            } else {
                // Should never end up here, but just to make sure we avoid an infinite loop
                break;
            }
        }

        return carry.concat(move);
    },

    transferEnergyToAdjacentBuilders: function (carrier) {
        if (carrier.carry.energy > 0) {
            var adjacentNonFullBuilders = carrier.pos.findInRange(FIND_MY_CREEPS, 1, {
                filter: creep => creep.memory.role === ROLE_BUILDER && creep.carry.energy < creep.carryCapacity
            });
            _.forEach(adjacentNonFullBuilders, function (builder) {
                if (carrier.carry.energy > 0) {
                    carrier.transfer(builder, RESOURCE_ENERGY);
                }
            })
        }

    },

    getMiner: function (carrier) {
        var miner = Game.getObjectById(carrier.memory.minerId);

        if (miner) {
            if (!miner.memory.carrierId) {
                miner.memory.carrierId = carrier.id;
            }
            return miner;
        } else {
            // Miner not found, maybe destroyed in a fight, or broke down due to aging.

            var miners = carrier.room.find(FIND_MY_CREEPS, {
                filter: creep => creep.memory.role == ROLE_MINER
            });

            if (!miners.length) {
                // No miners available, just wait until some are made
                carrier.memory.minerId = null;
                carrier.memory.sourceId = null;
                return null;
            }

            _.forEach(miners, function (creep) {
                if (!Game.getObjectById(creep.memory.carrierId)) {
                    miner = creep;
                    return false;
                }
            });

            if (miner) {
                carrier.memory.minerId = miner.id;
                carrier.memory.sourceId = miner.memory.sourceId;
                miner.memory.carrierId = carrier.id;
                return miner;
            }

            // Link to an existing miner
            miner = carrier.pos.findClosestByPath(miners);
            // Don't override the carrier reference in the miner, as the current one is still valid
            carrier.memory.minerId = miner.id;
            carrier.memory.sourceId = miner.memory.sourceId;

            return miner;
        }
    },

    addPart: function (energy, parts, part) {
        parts.push(part);
        return energy - BODYPART_COST[part];
    }
};<|endoftext|>


<commit_before>import { parse, stringify } from "query-string";

export function syncLocationToStore(store, mountPoints) {
  store.syncedLocationToStore = true;
  const rawQuery = parse(window.location.search, {
    arrayFormat: "bracket"
  });

  const query = {};
  if (rawQuery.storeData) {
    let parsed = {};
    try {
      parsed = JSON.parse(rawQuery.storeData);
    } catch (e) {
      //ignore
    }
    const mountPointsSet = new Set(mountPoints);
    Object.entries(parsed).forEach(([key, data]) => {
      if (mountPointsSet.has(key)) query[key] = data;
    });
  }

  const location = {
    href: window.location.href,
    pathname: window.location.pathname,
    queryString: window.location.search
  };

  store.setAll({ location, ...query });
  store.syncedLocationToStore = false;
}

const stringifyStoreData = store => {
  if (!store.syncLocationToStore || store.syncToLocations.length == 0)
    return null;

  const storeData = JSON.stringify(store.getAll(store.syncToLocations));

  const rawQuery = Object.assign(
    parse(window.location.search, {
      arrayFormat: "bracket"
    }),
    { storeData }
  );

  return stringify(rawQuery, {
    arrayFormat: "bracket"
  });
};

const getQueryStringFromStore = (store, newPath) => {
  const storeLocation = { ...store.get("location") };
  const query = stringifyStoreData(store);
  const path = newPath || storeLocation.pathname;
  return query ? `${path}?${query}` : path;
};

export function updateHistory(store, newPath) {
  store.syncedLocationToStore = true;
  history.pushState(null, null, getQueryStringFromStore(store, newPath));
  store.set("location", {
    href: window.location.href,
    pathname: window.location.pathname,
    queryString: window.location.search
  });
}

const hasChanged = (store, mountPoints) => {
  const props = store.getAll(mountPoints);
  let changed = true;
  if (store.lastState)
    changed = mountPoints.some(
      mountPoint => props[mountPoint] !== store.lastState[mountPoint]
    );

  store.lastState = props;
  return changed;
};

export const debounce = (time, fn) => {
  let timer = null;
  return (...args) => {
    if (timer) clearTimeout(timer);
    timer = setTimeout(() => fn(...args), time);
  };
};

const defaultOptions = {
  debounceTime: 500
};

export function enableHistory(
  store,
  pushStateMountPoints = [],
  replaceStateMountPoints = [],
  options
) {
  const { debounceTime } = {
    ...defaultOptions,
    ...(options || {})
  };

  store.syncToLocations = pushStateMountPoints.concat(replaceStateMountPoints);

  const update = () => syncLocationToStore(store, pushStateMountPoints);

  window.addEventListener("popstate", update);

  syncLocationToStore(store, store.syncToLocations);

  const debouncedReplaceState = debounce(debounceTime, (store, location) => {
    store.set("location", location);
    history.replaceState(null, null, getQueryStringFromStore(store));
  });

  store.addUpdateIntercept(s => {
    if (store.syncedLocationToStore) {
      store.syncedLocationToStore = false;
      return;
    }

    const location = {
      href: window.location.href,
      pathname: window.location.pathname,
      queryString: window.location.search
    };

    if (hasChanged(store, pushStateMountPoints)) {
      s.set("location", location);
      history.pushState(null, null, getQueryStringFromStore(s));
    } else debouncedReplaceState(s, location);
  });
  return () => window.removeEventListener("popstate", update);
}

export { default as Match } from "./Match";
export { default as Link } from "./Link";
<commit_msg>Better check for extracting location from store<commit_after>import { parse, stringify } from "query-string";

export function syncLocationToStore(store, mountPoints) {
  store.syncedLocationToStore = true;
  const rawQuery = parse(window.location.search, {
    arrayFormat: "bracket"
  });

  const query = {};
  if (rawQuery.storeData) {
    let parsed = {};
    try {
      parsed = JSON.parse(rawQuery.storeData);
    } catch (e) {
      //ignore
    }
    const mountPointsSet = new Set(mountPoints);
    Object.entries(parsed).forEach(([key, data]) => {
      if (mountPointsSet.has(key)) query[key] = data;
    });
  }

  const location = {
    href: window.location.href,
    pathname: window.location.pathname,
    queryString: window.location.search
  };

  store.setAll({ location, ...query });
  store.syncedLocationToStore = false;
}

const stringifyStoreData = store => {
  if (!store.syncToLocations || store.syncToLocations.length == 0) return null;

  const storeData = JSON.stringify(store.getAll(store.syncToLocations));

  const rawQuery = Object.assign(
    parse(window.location.search, {
      arrayFormat: "bracket"
    }),
    { storeData }
  );

  return stringify(rawQuery, {
    arrayFormat: "bracket"
  });
};

const getQueryStringFromStore = (store, newPath) => {
  const storeLocation = { ...store.get("location") };
  const query = stringifyStoreData(store);
  const path = newPath || storeLocation.pathname;
  return query ? `${path}?${query}` : path;
};

export function updateHistory(store, newPath) {
  store.syncedLocationToStore = true;
  history.pushState(null, null, getQueryStringFromStore(store, newPath));
  store.set("location", {
    href: window.location.href,
    pathname: window.location.pathname,
    queryString: window.location.search
  });
}

const hasChanged = (store, mountPoints) => {
  const props = store.getAll(mountPoints);
  let changed = true;
  if (store.lastState)
    changed = mountPoints.some(
      mountPoint => props[mountPoint] !== store.lastState[mountPoint]
    );

  store.lastState = props;
  return changed;
};

export const debounce = (time, fn) => {
  let timer = null;
  return (...args) => {
    if (timer) clearTimeout(timer);
    timer = setTimeout(() => fn(...args), time);
  };
};

const defaultOptions = {
  debounceTime: 500
};

export function enableHistory(
  store,
  pushStateMountPoints = [],
  replaceStateMountPoints = [],
  options
) {
  const { debounceTime } = {
    ...defaultOptions,
    ...(options || {})
  };

  store.syncToLocations = pushStateMountPoints.concat(replaceStateMountPoints);

  const update = () => syncLocationToStore(store, pushStateMountPoints);

  window.addEventListener("popstate", update);

  syncLocationToStore(store, store.syncToLocations);

  const debouncedReplaceState = debounce(debounceTime, (store, location) => {
    store.set("location", location);
    history.replaceState(null, null, getQueryStringFromStore(store));
  });

  store.addUpdateIntercept(s => {
    if (store.syncedLocationToStore) {
      store.syncedLocationToStore = false;
      return;
    }

    const location = {
      href: window.location.href,
      pathname: window.location.pathname,
      queryString: window.location.search
    };

    if (hasChanged(store, pushStateMountPoints)) {
      s.set("location", location);
      history.pushState(null, null, getQueryStringFromStore(s));
    } else debouncedReplaceState(s, location);
  });
  return () => window.removeEventListener("popstate", update);
}

export { default as Match } from "./Match";
export { default as Link } from "./Link";
<|endoftext|>