WME SlackNotifier

Posts lock, unlock and closure requests to waze slack. Based on original by davidakachaos

当前为 2019-09-21 提交的版本,查看 最新版本

// ==UserScript==
// @name           WME SlackNotifier
// @description    Posts lock, unlock and closure requests to waze slack. Based on original by davidakachaos
// @namespace      [email protected]
// @grant          none
// @grant          GM_info
// @version        0.2.0
// @match          https://beta.waze.com/*editor*
// @match          https://www.waze.com/*editor*
// @exclude        https://www.waze.com/*user/*editor/*
// @author         Abel Vieira
// @license        Creative Commons Attribution-ShareAlike 4.0 International License
// ==/UserScript==
/* global W, $, JSON, OL*/
var WME_SN_Version = GM_info.script.version,
    WME_SN_Name = GM_info.script.name,
    WME_SN_UA = [],
    WME_SN_user=null,
    WME_SN_country=null,
    WME_SN_CS={
        PO: {
            SlackURL:"https://wazept.slack.com/messages/C3NMDCP34",
            LockURL:"https://hooks.slack.com/services/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",
            UnLockURL:"https://hooks.slack.com/services/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",
            ClosureURL:"https://hooks.slack.com/services/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",
            1:":one:",
            2:":two:",
            3:":three:",
            4:":four:",
            5:":five:",
            6:":six:",
            7:":seven:",
            8:":eight:",
            9:":nine:",
            0:":zero:",
            SNDivlabel:'<i class=\"fa fa-slack\"></i> Slack do WazePT',
            BTNLock:String.fromCodePoint(0x1F513)+' Solictiar bloqueio',
            BTNUnLock:String.fromCodePoint(0x1F512)+' Solicitar desbloqueio',
            BTNClosure:String.fromCodePoint(0x1F6A7)+' Comunicar corte de estrada',
            btnSend: "Enviar",
            OptToLock: "... para nível: ",
            UnlockReasonMessage: "Para melhor avaliarmos o teu pedido de desbloqueio, por favor, indica-nos o(s) motivo(s): ",
            UnlockReasons: {
                'join_segments': "Ligar segmento(s)",
                'fix_address': "Corrigir endereço",
                'fix_arrows': "Corrigir setas / direcções",
                'fix_speed': "Corrigir velocidade",
                'geometry': "Ajustar a geometria da via",
                'fix_segment_type': "Alterar o tipo de via",
                'fix_segment_level': "Alterar elevação da via",
                'restrictions': "Criar / Alterar restrições",
                'other': "Outros (especifico abaixo)",
            },
            ClosureReasonMessage: "Para melhor avaliarmos o teu pedido de corte de estrada, por favor, indica-nos o(s) motivo(s), e se possivél a duração: ",
            ClosureReasons: {
                'construction': "Obras na via",
                'event': "Evento",
                'fire': "Incêndio",
                'accident': "Acidente",
                '1_day': "1 dia",
                '3_days': "3 dias",
                '7_days': "1 semana",
                '14_days': "2 semanas",
                '30_days': "1 mês",
                '30_days_more': "mais de 1 mês",
                'other': "Outros (especifico abaixo)",
            },
            PTitleLock:":lock:",
            PTitleUnLock:":unlock:",
            PTitleClosure:":construction:",
            PTitleSeparator:"→",
            PFallbackLock:"Bloqueio solicitado no mapa: ",
            PFallbackUnLock:"Desloqueio solicitado no mapa: ",
            PFallbackClosure:"Corte de estrada solicitado no mapa: ",
            PColorLock:"#59013a",
            PColorUnLock:"#0d8044",
            PColorClosure:"#f55702",
            OkSentLock:"<p><b>O pedido de bloqueio foi enviado com sucesso para a nossa comunidade,</b><br>e o mesmo vai agora ser avaliado pelos editores</p><p>Para saberes mais, convidamos-te a juntar ao nosso slack em <a href=\"https://wazept.slack.com\" target=\"_black\">https://wazept.slack.com</a>",
            OkSentUnLock:"<p><b>O pedido de desbloqueio foi enviado com sucesso para a nossa comunidade,</b><br>e o mesmo vai agora ser avaliado pelos editores, pelo que terás de aguardar pela revisão...</p><p>Para saberes mais, convidamos-te a juntar ao nosso slack em <a href=\"https://wazept.slack.com\" target=\"_black\">https://wazept.slack.com</a>",
            OkSentClosure:"<p><b>O pedido de corte de estrada foi enviado com sucesso para a nossa comunidade,</b><br>e o mesmo vai agora ser avaliado pelos editores</p><p>Para saberes mais, convidamos-te a juntar ao nosso slack em <a href=\"https://wazept.slack.com\" target=\"_black\">https://wazept.slack.com</a>",
        }
    };

function initUnlock(e) {
  log('initUnlock()');
  if (typeof W === 'undefined' ||
      typeof W.loginManager === 'undefined') {
    setTimeout(initUnlock, 100);
    return;
  }
  if (typeof I18n === 'undefined') {
    log('No internationalisation object found yet, snoozing');
    setTimeout(initUnlock, 300);
    return;
  }
  if (!W.loginManager.user) {
    log('Not logedIn '+W.loginManager);
    setTimeout(initUnlock, 3000);
    return;
  }
  if (typeof W.loginManager.user === 'undefined' ||
      typeof W.loginManager.user.areas === 'undefined') {
    log('Waiting for user areas....');
    setTimeout(initUnlock, 300);
    return;
  }
  log('Initalizing settings...');
  initSettings();
}

function initSettings() {
  log('initSettings()');
  WME_SN_user=W.loginManager.user.userName;
  var prefsTab = document.querySelector('#sidepanel-prefs');
  if (!prefsTab) {
    log('No settings tab found yet, snoozing');
    setTimeout(initSettings, 400);
    return;
  }
  if(W.loginManager.user.areas)
  log('registering selection changed handler');
  W.selectionManager.events.register('selectionchanged', null, checkLock);
  getUserAreas();
}

function postLockToSlack(locked_to){
  let place = $('.location-info').text().replace(/\,.+$/i, '');
  let perma = getPermalink();
  let locked = getLockedAt();
  let user_level = 1 + W.loginManager.getUserRank();

  let reason = '';

  let payload = {
    "attachments": [
        {
            "title": WME_SN_CS[WME_SN_country].PTitleLock+" "+WME_SN_CS[WME_SN_country][locked]+" "+WME_SN_CS[WME_SN_country].PTitleSeparator+" "+WME_SN_CS[WME_SN_country][locked_to],
            "text" : "at *"+place+"* by <https://www.waze.com/pt-PT/user/editor/"+WME_SN_user+"|"+WME_SN_user+" ("+user_level+")>\n PermaLink: <"+perma+"|here>"+(reason!=""?", Reason: _"+reason+"_":""),
            "fallback": WME_SN_CS[WME_SN_country].PFallbackLock+" L"+locked+" → L"+locked_to+" : "+perma,
            "color": WME_SN_CS[WME_SN_country].PColorLock,
            "attachment_type": "default",
            "mrkdwn_in": ["text"]
        }
    ]
  }
  let posting = $.post(WME_SN_CS[WME_SN_country].LockURL, JSON.stringify(payload) );
  posting.done(function(data){
    showMessage('success',WME_SN_CS[WME_SN_country].OkSentLock);
  });
}

function postUnlockToSlack(reason){
  let place = $('.location-info').text().replace(/\,.+$/i, '');
  let perma = getPermalink();
  let locked = getLockedAt();
  let user_level = 1 + W.loginManager.getUserRank();

  let payload = {
    "attachments": [
        {
            "title": WME_SN_CS[WME_SN_country].PTitleUnLock+" "+WME_SN_CS[WME_SN_country][locked]+" "+WME_SN_CS[WME_SN_country].PTitleSeparator+" "+WME_SN_CS[WME_SN_country][user_level],
            "text" : "at *"+place+"* by <https://www.waze.com/pt-PT/user/editor/"+WME_SN_user+"|"+WME_SN_user+" ("+user_level+")>\n PermaLink: <"+perma+"|here>"+(reason!=""?", Reason: _"+reason+"_":""),
            "fallback": WME_SN_CS[WME_SN_country].PFallbackUnLock+" L"+locked+" → L"+user_level+" : "+perma,
            "color": WME_SN_CS[WME_SN_country].PColorUnLock,
            "attachment_type": "default",
            "mrkdwn_in": ["text"]
        }
    ]
  }
  let posting = $.post(WME_SN_CS[WME_SN_country].UnLockURL, JSON.stringify(payload) );
  posting.done(function(data){
    showMessage('success',WME_SN_CS[WME_SN_country].OkSentUnLock);
  });
}

function postClosureToSlack(reason){
  let place = $('.location-info').text().replace(/\,.+$/i, '');
  let perma = getPermalink();
  let locked = getLockedAt();
  let user_level = 1 + W.loginManager.getUserRank();

  let payload = {
    "attachments": [
        {
            "title": WME_SN_CS[WME_SN_country].PTitleClosure+" "+WME_SN_CS[WME_SN_country][locked],
            "text" : "at *"+place+"* by <https://www.waze.com/pt-PT/user/editor/"+WME_SN_user+"|"+WME_SN_user+" ("+user_level+")>\n PermaLink: <"+perma+"|here>"+(reason!=""?", Reason: _"+reason+"_":""),
            "fallback": WME_SN_CS[WME_SN_country].PFallbackClosure+" L"+locked+" → L"+user_level+" : "+perma,
            "color": WME_SN_CS[WME_SN_country].PColorClosure,
            "attachment_type": "default",
            "mrkdwn_in": ["text"]
        }
    ]
  }
  let posting = $.post(WME_SN_CS[WME_SN_country].ClosureURL, JSON.stringify(payload) );
  posting.done(function(data){
    showMessage('success',WME_SN_CS[WME_SN_country].OkSentClosure);
  });
}

function hasClosures(){
  // check if a selected segment contains a closure
  let closures = [];
  $.each(W.model.roadClosures.objects, function(indx, closure){
    closures.push(closure.segID);
  });
  if (closures === []){
    return false;
  }
  $.each(W.selectionManager.getSelectedFeatures(), function(indx, section){
    let segID = section.model.attributes.id;
    if (closures.includes(segID)){
      return true;
    }
  });
  return false;
}

function getLockedAt(){
  var max_level = 0;
  $.each(W.selectionManager.getSelectedFeatures(), function(indx, section){
    var seg_rank = 1 + section.model.attributes.lockRank;
    if (seg_rank > max_level){
      max_level = seg_rank;
    }
  });
  return max_level;
}

function getSelectedIds(segments){
  let ids = [];
  $.each(segments, function(indx, section){
    ids.push(section.model.attributes.id);
  });
  return ids.join(",");
}

function getLonLat(segment){
  let bounds = segment.model.geometry.bounds;
  return new OL.LonLat(bounds.left, bounds.bottom)
      .transform(W.map.projection, W.map.displayProjection)
}

// returns permalink
function getPermalink() {
  let PL = "";
  let selectedSegments = W.selectionManager.getSelectedFeatures();
  let selectedLength = selectedSegments.length;
  let middleSegment = selectedSegments[Math.round((selectedLength - 1) / 2)];
  let latlon = getLonLat(middleSegment);
  let z = 5;
  if (50 > selectedLength)
    z = 6;
  else if (500 > selectedLength) {
    if (6 > z) z += 1;
  }
  else
    z = 4;
  PL += window.location.origin;
  PL += window.location.pathname;
  PL += '?zoom=';
  PL += z;
  PL += '&lat=';
  PL += latlon.lat;
  PL += '&lon=';
  PL += latlon.lon;
  PL += '&env=';
  PL += W.app.getAppRegionCode();
  PL += '&segments=';
  PL += getSelectedIds(selectedSegments);
  return PL;
}

function getUserAreas(){
  log('Loading editable areas for user');
  for (var a = 0; a < W.loginManager.user.areas.length; a++) {
    for (var c = 0; c < W.loginManager.user.areas[a].geometry.components.length; c++) {
      W.loginManager.user.areas[a].geometry.components[c].calculateBounds();
      WME_SN_UA.push(W.loginManager.user.areas[a].geometry.components[c]);
    }
  }
}

function determinCountry(){
  let selectedSegments = W.selectionManager.getSelectedFeatures();
  let middleSegment = selectedSegments[Math.round((selectedSegments.length - 1) / 2)];
  let country = middleSegment.model.getAddress().attributes.country.abbr;
  if(!WME_SN_CS[country]){
      showMessage('danger',"There is no hook set for " + country + "!");
      return;
  }
  return country;
}

function isInsideEdiableArea(lon, lat) {
  let lonlat = OL.Layer.SphericalMercator.forwardMercator(lon, lat);
  let xy = new OL.Geometry.Point(lonlat.lon, lonlat.lat);
  let inside = false;
  {
    for (var a = 0; a < WME_SN_UA.length; a++) {
      if (xy.x >= WME_SN_UA[a].bounds.left
        && xy.x <= WME_SN_UA[a].bounds.right
        && xy.y >= WME_SN_UA[a].bounds.bottom
        && xy.y <= WME_SN_UA[a].bounds.top
        && WME_SN_UA[a].containsPoint(xy)) {
        return true;
      }
    }
  }
  return false;
};


function checkEditableArea(){
  let editable = false;
  let selectedSegments = W.selectionManager.getSelectedFeatures();
  for (var i = selectedSegments.length - 1; i >= 0; i--) {
    let segment = selectedSegments[i];
    let lonlat = getLonLat(segment);
    editable = isInsideEdiableArea(lonlat.lon, lonlat.lat);
  }
  return editable;
}

function checkLock(){
  if (!checkEditableArea()) {
    //log('Segment not in editable area of user!');
    return;
  }
  var max_level = getLockedAt();
  var user_level = 1 + W.loginManager.getUserRank();
  $('#unlockDiv').remove();
  if (user_level >= 6) {
      return;
  }
  WME_SN_country = determinCountry();
  if (!WME_SN_country || !WME_SN_CS[WME_SN_country]) { return; }
  let unlockDiv = document.createElement("div");
  unlockDiv.id = 'unlockDiv';
  unlockDiv.className = 'form-group';
  $('.lock-edit-view').append(unlockDiv);
  let unlockDiv_label=document.createElement("label");
  unlockDiv_label.innerHTML = WME_SN_CS[WME_SN_country].SNDivlabel+" <a href=\""+WME_SN_CS[WME_SN_country].SlackURL+"\" target=\"_black\"><i class=\"fa fa-external-link\"></i></a>" ;
  unlockDiv_label.className = "control-label";
  $('#unlockDiv').append(unlockDiv_label);
  let unlockDiv_fc=document.createElement("div");
  unlockDiv_fc.id = 'unlockDiv_fc';
  //unlockDiv_fc.className = 'btn-group';
  $('#unlockDiv').append(unlockDiv_fc);

  if (user_level < max_level) {
    log('User level lower then the locks, adding unlock/closure.');
    addReasonField();
    createUnlockBtn()
    createClosureRequestBtn();
  }
  if (user_level >= max_level){
    log('User level higher then the locks, adding lock request.');
    createLockRequestForm();
  }
  if (user_level < 4 && user_level >= max_level){
    log('Level < 4 editor, add closure request.')
    // Reason field is already added above.
    createClosureRequestBtn();
  }
  if (hasClosures()){
    // TODO: Add closure removal request
  }
}

function addReasonField(){
  let iinputReason = document.createElement("input");
  iinputReason.id = 'reason';
  iinputReason.type = 'hidden';
  $('#unlockDiv').append(iinputReason);
    return
  let mesgReason = document.createElement("div");
  let inputReason = document.createElement("input");
  let labelReason = document.createElement("label");
  mesgReason.className = 'form-group';
  labelReason.innerHTML = 'Give a (short) reason:';
  labelReason.for = 'reason'
  labelReason.className = 'control-label';
  inputReason.id = 'reason';
  inputReason.type = 'text';
  inputReason.className = 'form-control';

  mesgReason.appendChild(labelReason);
  mesgReason.appendChild(inputReason);
  $('#unlockDiv').append(mesgReason);
}

function createUnlockBtn () {
  let btnPostRequest = document.createElement("button");
  btnPostRequest.innerHTML = WME_SN_CS[WME_SN_country].BTNUnLock;
  btnPostRequest.id = "clickUnlockToSlack";
  btnPostRequest.className = 'action-button waze-btn waze-btn-small waze-btn-white';
  $('#unlockDiv_fc').append(btnPostRequest);
  $("#clickUnlockToSlack").click(function() {
      let message = '<p>'+WME_SN_CS[WME_SN_country].UnlockReasonMessage+'</p><div class="controls-container form-group">';
      $.each(WME_SN_CS[WME_SN_country].UnlockReasons, function(indx, value){
          message += '<div class="service-checkbox"><input id="WME_SN_CS_Reasons_'+indx+'" type="checkbox" class="WME_SN_CS_Reasons" value="'+indx+'"><label for="WME_SN_CS_Reasons_'+indx+'">'+value+'</label></div>';
      });
      message += '</div>';
      ezBSAlert({
          type: 'prompt',
          headerText: WME_SN_CS[WME_SN_country].BTNUnLock,
          messageText: message,
          okButtonText: WME_SN_CS[WME_SN_country].btnSend,
      }).done(function (e) {
          postUnlockToSlack(e);
      });;
  });
}

function createLockRequestForm(){
  let user_level = 1 + W.loginManager.getUserRank();

  let divLock = document.createElement("div");
  divLock.className = 'btn-group btn-block';
  let btnPostRequest = document.createElement("button");
  btnPostRequest.innerHTML = WME_SN_CS[WME_SN_country].BTNLock+" <span class=\"caret\"></span>";
  btnPostRequest.className = 'action-button waze-btn waze-btn-small waze-btn-white dropdown-toggle';
  btnPostRequest.dataset.toggle = 'dropdown';
  divLock.appendChild(btnPostRequest);
  let divLockOptions = document.createElement("ul");
  divLockOptions.className = "dropdown-menu";
  for (var i = user_level + 1; i < 7; i++) {
    let liopt = document.createElement("li");
    let opt = document.createElement("a");
    opt.innerHTML = WME_SN_CS[WME_SN_country].OptToLock+" <b>"+i+"</b>";
    opt.href = "#";
    opt.dataset.level = i;
    opt.className = "postLockToSlack";
    liopt.appendChild(opt);
    divLockOptions.appendChild(liopt);
  }
  divLock.appendChild(divLockOptions)
  $('#unlockDiv_fc').append(divLock);
  $("#unlockDiv").on('click','.postLockToSlack',function(e){
    let level = e.target.dataset.level;
    postLockToSlack(level);
 });
}

function createClosureRequestBtn(){
  let btnPostRequest = document.createElement("button");
  btnPostRequest.innerHTML = WME_SN_CS[WME_SN_country].BTNClosure;
  btnPostRequest.id = "clickClosureToSlack";
  btnPostRequest.className = 'action-button waze-btn waze-btn-small waze-btn-white';
  btnPostRequest.style.cssText = 'margin-top:4px;'
  $('#unlockDiv_fc').append(btnPostRequest);

  $("#clickClosureToSlack").click(function() {
      let message = '<p>'+WME_SN_CS[WME_SN_country].ClosureReasonMessage+'</p><div class="controls-container form-group">';
      $.each(WME_SN_CS[WME_SN_country].ClosureReasons, function(indx, value){
          message += '<div class="service-checkbox"><input id="WME_SN_CS_Reasons_'+indx+'" type="checkbox" class="WME_SN_CS_Reasons" value="'+indx+'"><label for="WME_SN_CS_Reasons_'+indx+'">'+value+'</label></div>';
      });
      message += '</div>';
      ezBSAlert({
          type: 'prompt',
          headerText: WME_SN_CS[WME_SN_country].BTNClosure,
          messageText: message,
          okButtonText: WME_SN_CS[WME_SN_country].btnSend,
      }).done(function (e) {
          postClosureToSlack(e);
      });;
  });
}

function ezBSAlert (options) {
	var deferredObject = $.Deferred();
	var defaults = {
		type: "alert", //alert, prompt,confirm
		modalSize: 'modal-sm', //modal-sm, modal-lg
		okButtonText: 'Ok',
		cancelButtonText: 'Cancel',
		yesButtonText: 'Yes',
		noButtonText: 'No',
		headerText: 'WME SlackNotifier',
		messageText: 'Message',
		alertType: 'default', //default, primary, success, info, warning, danger
		inputFieldType: 'text', //could ask for number,email,etc
	}
	$.extend(defaults, options);

	var _show = function(){
		var headClass = "navbar-default";
		switch (defaults.alertType) {
			case "primary":
				headClass = "alert-primary";
				break;
			case "success":
				headClass = "alert-success";
				break;
			case "info":
				headClass = "alert-info";
				break;
			case "warning":
				headClass = "alert-warning";
				break;
			case "danger":
				headClass = "alert-danger";
				break;
        }
		$('BODY').append(
			'<div id="ezAlerts" class="modal fade">' +
			'<div class="modal-dialog" class="' + defaults.modalSize + '">' +
			'<div class="modal-content">' +
			'<div id="ezAlerts-header" class="modal-header ' + headClass + '">' +
			'<button id="close-button" type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button>' +
			'<h4 id="ezAlerts-title" class="modal-title">Modal title</h4>' +
			'</div>' +
			'<div id="ezAlerts-body" class="modal-body">' +
			'<div id="ezAlerts-message" ></div>' +
			'</div>' +
			'<div id="ezAlerts-footer" class="modal-footer">' +
			'</div>' +
			'</div>' +
			'</div>' +
			'</div>'
		);

		$('.modal-header').css({
			'padding': '15px 15px',
			'-webkit-border-top-left-radius': '5px',
			'-webkit-border-top-right-radius': '5px',
			'-moz-border-radius-topleft': '5px',
			'-moz-border-radius-topright': '5px',
			'border-top-left-radius': '5px',
			'border-top-right-radius': '5px'
		});

		$('#ezAlerts-title').html(defaults.headerText);
		$('#ezAlerts-message').html(defaults.messageText);

		var keyb = "false", backd = "static";
		var calbackParam = "";
		switch (defaults.type) {
			case 'alert':
				keyb = "true";
				backd = "true";
				$('#ezAlerts-footer').html('<button class="btn btn-' + defaults.alertType + '">' + defaults.okButtonText + '</button>').on('click', ".btn", function () {
					calbackParam = true;
					$('#ezAlerts').modal('hide');
				});
				break;
			case 'confirm':
				var btnhtml = '<button id="ezok-btn" class="btn btn-primary">' + defaults.yesButtonText + '</button>';
				if (defaults.noButtonText && defaults.noButtonText.length > 0) {
					btnhtml += '<button id="ezclose-btn" class="btn btn-default">' + defaults.noButtonText + '</button>';
				}
				$('#ezAlerts-footer').html(btnhtml).on('click', 'button', function (e) {
						if (e.target.id === 'ezok-btn') {
							calbackParam = true;
							$('#ezAlerts').modal('hide');
						} else if (e.target.id === 'ezclose-btn') {
							calbackParam = false;
							$('#ezAlerts').modal('hide');
						}
					});
				break;
			case 'prompt':
				$('#ezAlerts-message').html(defaults.messageText + '<br /><br /><div class="form-group"><input type="' + defaults.inputFieldType + '" class="form-control" id="prompt" /></div>');
				$('#ezAlerts-footer').html('<button class="btn btn-primary">' + defaults.okButtonText + '</button>').on('click', ".btn", function () {
					calbackParam = $('#prompt').val();
					$('#ezAlerts').modal('hide');
				});
				break;
		}

		$('#ezAlerts').modal({
          show: false,
          backdrop: backd,
          keyboard: keyb
        }).on('hidden.bs.modal', function (e) {
			$('#ezAlerts').remove();
			deferredObject.resolve(calbackParam);
		}).on('shown.bs.modal', function (e) {
			if ($('#prompt').length > 0) {
				$('#prompt').focus();
			}
		}).modal('show');
	}

  _show();
  return deferredObject.promise();
}

$("body").on('click','.WME_SN_CS_Reasons',function(e){
    let checked_Reasons=[];
    $('.WME_SN_CS_Reasons:checkbox:checked').each(function () {
        checked_Reasons.push(this.value);
    });
    if (checked_Reasons.includes("other")) {
        $("#prompt").show();
    } else {
        $("#prompt").hide();
    }
    $("#prompt").val(checked_Reasons.join(", "));
});

function openSlack(){
  window.open(WME_SN_CS[WME_SN_country].SlackURL, "_blank");
}

function showMessage(severity,message) {
    ezBSAlert({
        messageText: message,
        alertType: severity
    })
}

function log(message) {
  if (console.log) {
    console.log('%c '+WME_SN_Name+': %c' + message, 'color:black', 'color:#d97e00');
  }
}

log(WME_SN_Name+' - version ' + WME_SN_Version);
initUnlock();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址