messagesoverlay - Use const where possible
parent
d45cf2548e
commit
724be3637e
|
|
@ -1,7 +1,7 @@
|
||||||
let lockListener;
|
let lockListener;
|
||||||
let quiet;
|
let quiet;
|
||||||
|
|
||||||
let toSemantic = function (espruinoVersion){
|
const toSemantic = function (espruinoVersion){
|
||||||
return {
|
return {
|
||||||
major: espruinoVersion.substring(0,espruinoVersion.indexOf("v")),
|
major: espruinoVersion.substring(0,espruinoVersion.indexOf("v")),
|
||||||
minor: espruinoVersion.substring(espruinoVersion.indexOf("v") + 1, espruinoVersion.includes(".") ? espruinoVersion.indexOf(".") : espruinoVersion.length),
|
minor: espruinoVersion.substring(espruinoVersion.indexOf("v") + 1, espruinoVersion.includes(".") ? espruinoVersion.indexOf(".") : espruinoVersion.length),
|
||||||
|
|
@ -9,16 +9,16 @@ let toSemantic = function (espruinoVersion){
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
let isNewer = function(espruinoVersion, baseVersion){
|
const isNewer = function(espruinoVersion, baseVersion){
|
||||||
let s = toSemantic(espruinoVersion);
|
const s = toSemantic(espruinoVersion);
|
||||||
let b = toSemantic(baseVersion);
|
const b = toSemantic(baseVersion);
|
||||||
|
|
||||||
return s.major >= b.major &&
|
return s.major >= b.major &&
|
||||||
s.minor >= b.major &&
|
s.minor >= b.major &&
|
||||||
s.patch > b.patch;
|
s.patch > b.patch;
|
||||||
};
|
};
|
||||||
|
|
||||||
var settings = Object.assign(
|
let settings = Object.assign(
|
||||||
require('Storage').readJSON("messagesoverlay.default.json", true) || {},
|
require('Storage').readJSON("messagesoverlay.default.json", true) || {},
|
||||||
require('Storage').readJSON("messagesoverlay.json", true) || {}
|
require('Storage').readJSON("messagesoverlay.json", true) || {}
|
||||||
);
|
);
|
||||||
|
|
@ -27,8 +27,7 @@ settings = Object.assign({
|
||||||
fontSmall:"6x8",
|
fontSmall:"6x8",
|
||||||
fontMedium:"6x15",
|
fontMedium:"6x15",
|
||||||
fontBig: "12x20",
|
fontBig: "12x20",
|
||||||
fontLarge:"Vector:30",
|
fontLarge:"Vector:30"
|
||||||
reemit: true
|
|
||||||
}, settings);
|
}, settings);
|
||||||
|
|
||||||
const ovrx = settings.border;
|
const ovrx = settings.border;
|
||||||
|
|
@ -36,10 +35,10 @@ const ovry = ovrx;
|
||||||
const ovrw = g.getWidth()-2*ovrx;
|
const ovrw = g.getWidth()-2*ovrx;
|
||||||
const ovrh = g.getHeight()-2*ovry;
|
const ovrh = g.getHeight()-2*ovry;
|
||||||
|
|
||||||
let LOG=()=>{};
|
const LOG=()=>{};
|
||||||
//LOG = function() { print.apply(null, arguments);};
|
//LOG = function() { print.apply(null, arguments);};
|
||||||
|
|
||||||
let isQuiet = function(){
|
const isQuiet = function(){
|
||||||
if (quiet == undefined) quiet = (require('Storage').readJSON('setting.json', 1) || {}).quiet;
|
if (quiet == undefined) quiet = (require('Storage').readJSON('setting.json', 1) || {}).quiet;
|
||||||
return quiet;
|
return quiet;
|
||||||
};
|
};
|
||||||
|
|
@ -48,17 +47,17 @@ let eventQueue = [];
|
||||||
let callInProgress = false;
|
let callInProgress = false;
|
||||||
let buzzing = false;
|
let buzzing = false;
|
||||||
|
|
||||||
let show = function(ovr){
|
const show = function(ovr){
|
||||||
let img = ovr;
|
let img = ovr;
|
||||||
LOG("show", img.getBPP());
|
LOG("show", img.getBPP());
|
||||||
if (ovr.getBPP() == 1) {
|
if (ovr.getBPP() == 1) {
|
||||||
img = ovr.asImage();
|
img = ovr.asImage();
|
||||||
img.palette = new Uint16Array([g.theme.fg,g.theme.bg]);
|
img.paconstte = new Uint16Array([g.theme.fg,g.theme.bg]);
|
||||||
}
|
}
|
||||||
Bangle.setLCDOverlay(img, ovrx, ovry);
|
Bangle.setLCDOverlay(img, ovrx, ovry);
|
||||||
};
|
};
|
||||||
|
|
||||||
let manageEvent = function(ovr, event) {
|
const manageEvent = function(ovr, event) {
|
||||||
event.new = true;
|
event.new = true;
|
||||||
|
|
||||||
LOG("manageEvent");
|
LOG("manageEvent");
|
||||||
|
|
@ -102,7 +101,7 @@ let manageEvent = function(ovr, event) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let roundedRect = function(ovr, x,y,w,h,filled){
|
const roundedRect = function(ovr, x,y,w,h,filled){
|
||||||
var poly = [
|
var poly = [
|
||||||
x,y+4,
|
x,y+4,
|
||||||
x+4,y,
|
x+4,y,
|
||||||
|
|
@ -118,7 +117,7 @@ let roundedRect = function(ovr, x,y,w,h,filled){
|
||||||
if (filled) ovr.fillPoly(poly,true);
|
if (filled) ovr.fillPoly(poly,true);
|
||||||
};
|
};
|
||||||
|
|
||||||
let drawScreen = function(ovr, title, titleFont, src, iconcolor, icon){
|
const drawScreen = function(ovr, title, titleFont, src, iconcolor, icon){
|
||||||
ovr.setColor(ovr.theme.fg);
|
ovr.setColor(ovr.theme.fg);
|
||||||
ovr.setBgColor(ovr.theme.bg);
|
ovr.setBgColor(ovr.theme.bg);
|
||||||
ovr.clearRect(2,2,ovr.getWidth()-3,37);
|
ovr.clearRect(2,2,ovr.getWidth()-3,37);
|
||||||
|
|
@ -127,7 +126,7 @@ let drawScreen = function(ovr, title, titleFont, src, iconcolor, icon){
|
||||||
ovr.setFont(settings.fontSmall);
|
ovr.setFont(settings.fontSmall);
|
||||||
ovr.setFontAlign(0,-1);
|
ovr.setFontAlign(0,-1);
|
||||||
|
|
||||||
let textCenter = (ovr.getWidth()+35-26)/2;
|
const textCenter = (ovr.getWidth()+35-26)/2;
|
||||||
|
|
||||||
if (src) {
|
if (src) {
|
||||||
let shortened = src;
|
let shortened = src;
|
||||||
|
|
@ -153,7 +152,7 @@ let drawScreen = function(ovr, title, titleFont, src, iconcolor, icon){
|
||||||
ovr.drawImage(icon,8,8);
|
ovr.drawImage(icon,8,8);
|
||||||
};
|
};
|
||||||
|
|
||||||
let showMessage = function(ovr, msg) {
|
const showMessage = function(ovr, msg) {
|
||||||
LOG("showMessage");
|
LOG("showMessage");
|
||||||
|
|
||||||
// Normal text message display
|
// Normal text message display
|
||||||
|
|
@ -161,7 +160,7 @@ let showMessage = function(ovr, msg) {
|
||||||
titleFont = settings.fontLarge,
|
titleFont = settings.fontLarge,
|
||||||
lines;
|
lines;
|
||||||
if (title) {
|
if (title) {
|
||||||
let w = ovr.getWidth() - 35 - 26;
|
const w = ovr.getWidth() - 35 - 26;
|
||||||
if (ovr.setFont(titleFont).stringWidth(title) > w)
|
if (ovr.setFont(titleFont).stringWidth(title) > w)
|
||||||
titleFont = settings.fontMedium;
|
titleFont = settings.fontMedium;
|
||||||
if (ovr.setFont(titleFont).stringWidth(title) > w) {
|
if (ovr.setFont(titleFont).stringWidth(title) > w) {
|
||||||
|
|
@ -184,7 +183,7 @@ let showMessage = function(ovr, msg) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let drawBorder = function(img) {
|
const drawBorder = function(img) {
|
||||||
LOG("drawBorder", isQuiet());
|
LOG("drawBorder", isQuiet());
|
||||||
ovr.setBgColor(ovr.theme.bg);
|
ovr.setBgColor(ovr.theme.bg);
|
||||||
if (img) ovr=img;
|
if (img) ovr=img;
|
||||||
|
|
@ -198,7 +197,7 @@ let drawBorder = function(img) {
|
||||||
show(ovr);
|
show(ovr);
|
||||||
};
|
};
|
||||||
|
|
||||||
let showCall = function(ovr, msg) {
|
const showCall = function(ovr, msg) {
|
||||||
LOG("showCall");
|
LOG("showCall");
|
||||||
LOG(msg);
|
LOG(msg);
|
||||||
|
|
||||||
|
|
@ -214,7 +213,7 @@ let showCall = function(ovr, msg) {
|
||||||
titleFont = settings.fontLarge,
|
titleFont = settings.fontLarge,
|
||||||
lines;
|
lines;
|
||||||
if (title) {
|
if (title) {
|
||||||
let w = ovr.getWidth() - 35 -26;
|
const w = ovr.getWidth() - 35 -26;
|
||||||
if (ovr.setFont(titleFont).stringWidth(title) > w)
|
if (ovr.setFont(titleFont).stringWidth(title) > w)
|
||||||
titleFont = settings.fontMedium;
|
titleFont = settings.fontMedium;
|
||||||
if (ovr.setFont(titleFont).stringWidth(title) > w) {
|
if (ovr.setFont(titleFont).stringWidth(title) > w) {
|
||||||
|
|
@ -240,7 +239,7 @@ let showCall = function(ovr, msg) {
|
||||||
drawMessage(ovr, msg);
|
drawMessage(ovr, msg);
|
||||||
};
|
};
|
||||||
|
|
||||||
let next = function(ovr) {
|
const next = function(ovr) {
|
||||||
LOG("next");
|
LOG("next");
|
||||||
stopCallBuzz();
|
stopCallBuzz();
|
||||||
|
|
||||||
|
|
@ -259,24 +258,24 @@ let next = function(ovr) {
|
||||||
};
|
};
|
||||||
|
|
||||||
let callBuzzTimer = null;
|
let callBuzzTimer = null;
|
||||||
let stopCallBuzz = function() {
|
const stopCallBuzz = function() {
|
||||||
if (callBuzzTimer) {
|
if (callBuzzTimer) {
|
||||||
clearInterval(callBuzzTimer);
|
clearInterval(callBuzzTimer);
|
||||||
callBuzzTimer = undefined;
|
callBuzzTimer = undefined;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let drawTriangleUp = function(ovr) {
|
const drawTriangleUp = function(ovr) {
|
||||||
ovr.fillPoly([ovr.getWidth()-9, 46,ovr.getWidth()-14, 56,ovr.getWidth()-4, 56]);
|
ovr.fillPoly([ovr.getWidth()-9, 46,ovr.getWidth()-14, 56,ovr.getWidth()-4, 56]);
|
||||||
};
|
};
|
||||||
|
|
||||||
let drawTriangleDown = function(ovr) {
|
const drawTriangleDown = function(ovr) {
|
||||||
ovr.fillPoly([ovr.getWidth()-9, ovr.getHeight()-6, ovr.getWidth()-14, ovr.getHeight()-16, ovr.getWidth()-4, ovr.getHeight()-16]);
|
ovr.fillPoly([ovr.getWidth()-9, ovr.getHeight()-6, ovr.getWidth()-14, ovr.getHeight()-16, ovr.getWidth()-4, ovr.getHeight()-16]);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
let scrollUp = function(ovr) {
|
const scrollUp = function(ovr) {
|
||||||
let msg = eventQueue[0];
|
const msg = eventQueue[0];
|
||||||
LOG("up", msg);
|
LOG("up", msg);
|
||||||
|
|
||||||
if (!msg.CanscrollUp) return;
|
if (!msg.CanscrollUp) return;
|
||||||
|
|
@ -285,8 +284,8 @@ let scrollUp = function(ovr) {
|
||||||
drawMessage(ovr, msg);
|
drawMessage(ovr, msg);
|
||||||
};
|
};
|
||||||
|
|
||||||
let scrollDown = function(ovr) {
|
const scrollDown = function(ovr) {
|
||||||
let msg = eventQueue[0];
|
const msg = eventQueue[0];
|
||||||
LOG("down", msg);
|
LOG("down", msg);
|
||||||
|
|
||||||
if (!msg.CanscrollDown) return;
|
if (!msg.CanscrollDown) return;
|
||||||
|
|
@ -295,10 +294,10 @@ let scrollDown = function(ovr) {
|
||||||
drawMessage(ovr, msg);
|
drawMessage(ovr, msg);
|
||||||
};
|
};
|
||||||
|
|
||||||
let drawMessage = function(ovr, msg) {
|
const drawMessage = function(ovr, msg) {
|
||||||
let getStringHeight = function(str){
|
const getStringHeight = function(str){
|
||||||
"jit";
|
"jit";
|
||||||
let metrics = ovr.stringMetrics(str);
|
const metrics = ovr.stringMetrics(str);
|
||||||
if (isNewer("2v21.13", process.version)){
|
if (isNewer("2v21.13", process.version)){
|
||||||
if (metrics.maxImageHeight > 16)
|
if (metrics.maxImageHeight > 16)
|
||||||
metrics.maxImageHeight = metrics.height;
|
metrics.maxImageHeight = metrics.height;
|
||||||
|
|
@ -306,11 +305,11 @@ let drawMessage = function(ovr, msg) {
|
||||||
return Math.max(metrics.height, metrics.maxImageHeight);
|
return Math.max(metrics.height, metrics.maxImageHeight);
|
||||||
};
|
};
|
||||||
|
|
||||||
let wrapString = function(str, maxWidth) {
|
const wrapString = function(str, maxWidth) {
|
||||||
str = str.replace("\r\n", "\n").replace("\r", "\n");
|
str = str.replace("\r\n", "\n").replace("\r", "\n");
|
||||||
return ovr.wrapString(str, maxWidth);
|
return ovr.wrapString(str, maxWidth);
|
||||||
};
|
};
|
||||||
let wrappedStringHeight = function(strArray){
|
const wrappedStringHeight = function(strArray){
|
||||||
let r = 0;
|
let r = 0;
|
||||||
strArray.forEach((line, i) => {
|
strArray.forEach((line, i) => {
|
||||||
r += getStringHeight(line);
|
r += getStringHeight(line);
|
||||||
|
|
@ -323,12 +322,12 @@ let drawMessage = function(ovr, msg) {
|
||||||
|
|
||||||
if (msg.FirstLine === undefined) msg.FirstLine = 0;
|
if (msg.FirstLine === undefined) msg.FirstLine = 0;
|
||||||
|
|
||||||
let padding = eventQueue.length > 1 ? (eventQueue.length > 3 ? 7 : 5) : 3;
|
const padding = eventQueue.length > 1 ? (eventQueue.length > 3 ? 7 : 5) : 3;
|
||||||
|
|
||||||
let yText = 40;
|
const yText = 40;
|
||||||
let yLine = yText + 3;
|
let yLine = yText + 3;
|
||||||
|
|
||||||
let maxTextHeight = ovr.getHeight() - yLine - padding;
|
const maxTextHeight = ovr.getHeight() - yLine - padding;
|
||||||
|
|
||||||
if (!msg.lines) {
|
if (!msg.lines) {
|
||||||
let bodyFont = settings.fontBig;
|
let bodyFont = settings.fontBig;
|
||||||
|
|
@ -370,7 +369,7 @@ let drawMessage = function(ovr, msg) {
|
||||||
let drawnHeight = 0;
|
let drawnHeight = 0;
|
||||||
|
|
||||||
while(drawnHeight < maxTextHeight) {
|
while(drawnHeight < maxTextHeight) {
|
||||||
let lineHeight = msg.lineHeights[currentLine];
|
const lineHeight = msg.lineHeights[currentLine];
|
||||||
if (drawnHeight + lineHeight < maxTextHeight) {
|
if (drawnHeight + lineHeight < maxTextHeight) {
|
||||||
ovr.drawString(msg.lines[currentLine], xText, yLine + drawnHeight);
|
ovr.drawString(msg.lines[currentLine], xText, yLine + drawnHeight);
|
||||||
drawnHeight += lineHeight;
|
drawnHeight += lineHeight;
|
||||||
|
|
@ -405,7 +404,7 @@ let drawMessage = function(ovr, msg) {
|
||||||
show(ovr);
|
show(ovr);
|
||||||
};
|
};
|
||||||
|
|
||||||
let getDragHandler = function(ovr){
|
const getDragHandler = function(ovr){
|
||||||
return (e) => {
|
return (e) => {
|
||||||
if (e.dy > 0) {
|
if (e.dy > 0) {
|
||||||
scrollUp(ovr);
|
scrollUp(ovr);
|
||||||
|
|
@ -415,7 +414,7 @@ let getDragHandler = function(ovr){
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
let getTouchHandler = function(ovr){
|
const getTouchHandler = function(ovr){
|
||||||
return (_, xy) => {
|
return (_, xy) => {
|
||||||
if (xy.y < ovry + 40){
|
if (xy.y < ovry + 40){
|
||||||
next(ovr);
|
next(ovr);
|
||||||
|
|
@ -427,8 +426,8 @@ const EVENTS=["touch", "drag", "swipe"];
|
||||||
|
|
||||||
let hasBackup = false;
|
let hasBackup = false;
|
||||||
|
|
||||||
let origOn = Bangle.on;
|
const origOn = Bangle.on;
|
||||||
let backupOn = function(event, handler){
|
const backupOn = function(event, handler){
|
||||||
if (EVENTS.includes(event)){
|
if (EVENTS.includes(event)){
|
||||||
if (!backup[event])
|
if (!backup[event])
|
||||||
backup[event] = [];
|
backup[event] = [];
|
||||||
|
|
@ -437,8 +436,8 @@ let backupOn = function(event, handler){
|
||||||
else origOn.call(Bangle, event, handler);
|
else origOn.call(Bangle, event, handler);
|
||||||
};
|
};
|
||||||
|
|
||||||
let origRemove = Bangle.removeListener;
|
const origRemove = Bangle.removeListener;
|
||||||
let backupRemove = function(event, handler){
|
const backupRemove = function(event, handler){
|
||||||
if (EVENTS.includes(event) && backup[event]){
|
if (EVENTS.includes(event) && backup[event]){
|
||||||
LOG("backup for " + event + ": " + backup[event]);
|
LOG("backup for " + event + ": " + backup[event]);
|
||||||
backup[event] = backup[event].filter(e=>e!==handler);
|
backup[event] = backup[event].filter(e=>e!==handler);
|
||||||
|
|
@ -446,20 +445,20 @@ let backupRemove = function(event, handler){
|
||||||
else origRemove.call(Bangle, event, handler);
|
else origRemove.call(Bangle, event, handler);
|
||||||
};
|
};
|
||||||
|
|
||||||
let origRemoveAll = Bangle.removeAllListeners;
|
const origRemoveAll = Bangle.removeAllListeners;
|
||||||
let backupRemoveAll = function(event){
|
const backupRemoveAll = function(event){
|
||||||
if (backup[event])
|
if (backup[event])
|
||||||
backup[event] = undefined;
|
backup[event] = undefined;
|
||||||
origRemoveAll.call(Bangle);
|
origRemoveAll.call(Bangle);
|
||||||
};
|
};
|
||||||
|
|
||||||
let restoreHandlers = function(){
|
const restoreHandlers = function(){
|
||||||
if (!hasBackup){
|
if (!hasBackup){
|
||||||
LOG("No backup available");
|
LOG("No backup available");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let event of EVENTS){
|
for (const event of EVENTS){
|
||||||
LOG("Restore", backup[event]);
|
LOG("Restore", backup[event]);
|
||||||
origRemoveAll.call(Bangle, event);
|
origRemoveAll.call(Bangle, event);
|
||||||
if (backup[event] && backup[event].length == 1)
|
if (backup[event] && backup[event].length == 1)
|
||||||
|
|
@ -475,13 +474,13 @@ let restoreHandlers = function(){
|
||||||
hasBackup = false;
|
hasBackup = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
let backupHandlers = function(){
|
const backupHandlers = function(){
|
||||||
if (hasBackup){
|
if (hasBackup){
|
||||||
LOG("Backup already exists");
|
LOG("Backup already exists");
|
||||||
return false; // do not backup, overlay is already up
|
return false; // do not backup, overlay is already up
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let event of EVENTS){
|
for (const event of EVENTS){
|
||||||
backup[event] = Bangle["#on" + event];
|
backup[event] = Bangle["#on" + event];
|
||||||
if (typeof backup[event] == "function")
|
if (typeof backup[event] == "function")
|
||||||
backup[event] = [ backup[event] ];
|
backup[event] = [ backup[event] ];
|
||||||
|
|
@ -498,7 +497,7 @@ let backupHandlers = function(){
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
let cleanup = function(){
|
const cleanup = function(){
|
||||||
if (lockListener) {
|
if (lockListener) {
|
||||||
Bangle.removeListener("lock", lockListener);
|
Bangle.removeListener("lock", lockListener);
|
||||||
lockListener = undefined;
|
lockListener = undefined;
|
||||||
|
|
@ -510,11 +509,11 @@ let cleanup = function(){
|
||||||
quiet = undefined;
|
quiet = undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
let backup = {};
|
const backup = {};
|
||||||
|
|
||||||
let main = function(ovr, event) {
|
const main = function(ovr, event) {
|
||||||
LOG("Main", event.t);
|
LOG("Main", event.t);
|
||||||
let didBackup = backupHandlers();
|
const didBackup = backupHandlers();
|
||||||
|
|
||||||
if (!lockListener) {
|
if (!lockListener) {
|
||||||
lockListener = function (e){
|
lockListener = function (e){
|
||||||
|
|
@ -543,7 +542,7 @@ let main = function(ovr, event) {
|
||||||
let ovr;
|
let ovr;
|
||||||
let clearingTimeout;
|
let clearingTimeout;
|
||||||
|
|
||||||
let updateClearingTimeout = ()=>{
|
const updateClearingTimeout = ()=>{
|
||||||
LOG("updateClearingTimeout");
|
LOG("updateClearingTimeout");
|
||||||
if (settings.autoclear <= 0)
|
if (settings.autoclear <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
@ -553,7 +552,7 @@ let updateClearingTimeout = ()=>{
|
||||||
LOG("Set new clearing timeout");
|
LOG("Set new clearing timeout");
|
||||||
clearingTimeout = setTimeout(()=>{
|
clearingTimeout = setTimeout(()=>{
|
||||||
LOG("setNewTimeout");
|
LOG("setNewTimeout");
|
||||||
let event = eventQueue.pop();
|
const event = eventQueue.pop();
|
||||||
if (event)
|
if (event)
|
||||||
drawMessage(ovr, event);
|
drawMessage(ovr, event);
|
||||||
if (eventQueue.length > 0){
|
if (eventQueue.length > 0){
|
||||||
|
|
@ -581,7 +580,7 @@ exports.message = function(type, event) {
|
||||||
bpp = 1;
|
bpp = 1;
|
||||||
|
|
||||||
while (process.memory().free < settings.minfreemem && eventQueue.length > 0){
|
while (process.memory().free < settings.minfreemem && eventQueue.length > 0){
|
||||||
let dropped = eventQueue.pop();
|
const dropped = eventQueue.pop();
|
||||||
print("Dropped message because of memory constraints", dropped);
|
print("Dropped message because of memory constraints", dropped);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue