Hi I have a google app script that I need to run every weekday only between 09:30 AM to 15:45 PM. I am not being able to add the minutes. I have a code that has the hours in it. My code is given below. I tried to add minutes with && but that is giving funny results.
function Record() {
var today = new Date();
var day = today.getDay();
var days = ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday']
if(day == 6 || day == 0) {
return;
} else {
var hour = today.getHours();
var minute = today.getMinutes();
if(hour < 10 || hour > 15) {
return;
}
var ss1 = SpreadsheetApp.getActiveSpreadsheet();
var source1 = ss1.getRange("Nifty!C28:K28");
var destSheet1 = ss1.getSheetByName("Record 1");
destSheet1.appendRow(source1.getValues()[0]);
var ss2 = SpreadsheetApp.getActiveSpreadsheet();
var source2 = ss2.getRange("Bank Nifty!C28:K28");
var destSheet2 = ss2.getSheetByName("Record 2");
destSheet2.appendRow(source2.getValues()[0]);
}
}
Can anyone help me out?
This is not exactly the time but it's pretty close
function Record(e) {
if (e['day-of-week'] < 6 && e.hour > 9 && e.hour < 16) {
const ss1 = SpreadsheetApp.getActive();
const src1 = ss1.getRange("Nifty!C28:K28");
var dsh1 = ss1.getSheetByName("Record 1");
dsh1.appendRow(src1.getValues()[0]);
var ss2 = SpreadsheetApp.getActiveSpreadsheet();
var src2 = ss2.getRange("Bank Nifty!C28:K28");
var dsh2 = ss2.getSheetByName("Record 2");
dsh2.appendRow(src2.getValues()[0]);
}
}
//only creates one trigger for the handlerfunction
function createTimeBasedTrigger() {
if (ScriptApp.getProjectTriggers().filter(t => t.getHandlerFunction() == "Record").length == 0) {
ScriptApp.newTrigger("Record").timeBased().everyMinutes(15).create();
}
}
I'm loading file with nlapiLoadFile. It's binary file so when I'm getting the data with getValue() I see it's base64 encoded. How can I convert the data to string?
Currently I'm using this, and it's working like a charm:
var Base64 = {
_keyStr: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=", encode: function (e) {
var t = "";
var n, r, i, s, o, u, a;
var f = 0;
e = Base64._utf8_encode(e);
while (f < e.length) {
n = e.charCodeAt(f++);
r = e.charCodeAt(f++);
i = e.charCodeAt(f++);
s = n >> 2;
o = (n & 3) << 4 | r >> 4;
u = (r & 15) << 2 | i >> 6;
a = i & 63;
if (isNaN(r)) {
u = a = 64
} else if (isNaN(i)) {
a = 64
}
t = t + this._keyStr.charAt(s) + this._keyStr.charAt(o) + this._keyStr.charAt(u) + this._keyStr.charAt(a)
}
return t
}, decode: function (e) {
var t = "";
var n, r, i;
var s, o, u, a;
var f = 0;
e = e.replace(/[^A-Za-z0-9+/=]/g, "");
while (f < e.length) {
s = this._keyStr.indexOf(e.charAt(f++));
o = this._keyStr.indexOf(e.charAt(f++));
u = this._keyStr.indexOf(e.charAt(f++));
a = this._keyStr.indexOf(e.charAt(f++));
n = s << 2 | o >> 4;
r = (o & 15) << 4 | u >> 2;
i = (u & 3) << 6 | a;
t = t + String.fromCharCode(n);
if (u != 64) {
t = t + String.fromCharCode(r)
}
if (a != 64) {
t = t + String.fromCharCode(i)
}
}
t = Base64._utf8_decode(t);
return t
}, _utf8_encode: function (e) {
e = e.replace(/rn/g, "n");
var t = "";
for (var n = 0; n < e.length; n++) {
var r = e.charCodeAt(n);
if (r < 128) {
t += String.fromCharCode(r)
} else if (r > 127 && r < 2048) {
t += String.fromCharCode(r >> 6 | 192);
t += String.fromCharCode(r & 63 | 128)
} else {
t += String.fromCharCode(r >> 12 | 224);
t += String.fromCharCode(r >> 6 & 63 | 128);
t += String.fromCharCode(r & 63 | 128)
}
}
return t
}, _utf8_decode: function (e) {
var t = "";
var n = 0;
var r = c1 = c2 = 0;
while (n < e.length) {
r = e.charCodeAt(n);
if (r < 128) {
t += String.fromCharCode(r);
n++
} else if (r > 191 && r < 224) {
c2 = e.charCodeAt(n + 1);
t += String.fromCharCode((r & 31) << 6 | c2 & 63);
n += 2
} else {
c2 = e.charCodeAt(n + 1);
c3 = e.charCodeAt(n + 2);
t += String.fromCharCode((r & 15) << 12 | (c2 & 63) << 6 | c3 & 63);
n += 3
}
}
return t
}
}
For example, you can decode base64 encoded string like this:
var decodedString = Base64.decode(encodedstring);
There are a lot of resources on this but this should help https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/Base64_encoding_and_decoding.
The short and sweet answer:
var str = atob('stringOfBase64');
console.log(str);
I have been trying to get sqlite to order a set of entries by name in the following order
AaBbCcDd......Zz
but the closest I've gotten is using COLLATE NOCASE to get a case insensitive sort.
The entries I have are
Addy|2000-01-22T16:06:14.155Z
alice|2000-01-22T16:06:20.514Z
billyRay|2000-01-22T16:06:36.175Z
Bobby|2000-01-22T16:06:26.868Z
claus|2000-01-22T16:06:52.531Z
CoffinLLC|2000-01-22T15:33:11.235Z
Default|2000-01-22T15:55:12.168Z
I have tried the following select statements in the sqlite3 command line to achieve my goal without success.
select * from t1 order by name COLLATE NOCASE asc;
select * from t1 order by name COLLATE NOCASE, name asc;
select * from t1 order by lower(name), name asc;
select * from t1 order by name, lower(name) asc;
Based on #Griddoor's initial comment, I tried some variations and the following appears to work
select * from t1 order by lower(substr(name,1,1)), name;
const CHAR_CODE_a = 'a'.charCodeAt(0); // 97
const CHAR_CODE_A = 'A'.charCodeAt(0); // 65
const CHAR_CODE_z = 'z'.charCodeAt(0); // 112
const CHAR_CODE_Z = 'Z'.charCodeAt(0); // 90
const diffLowerUpper = CHAR_CODE_a - CHAR_CODE_A;
const isLower = (charCode) => {
return CHAR_CODE_a <= charCode && charCode <= CHAR_CODE_z;
};
const isUpper = (charCode) => {
return CHAR_CODE_A <= charCode && charCode <= CHAR_CODE_Z;
};
const ORDER = {
KEEP : 1,
EXCHANGE : -1,
EQUAL : 0,
}
const A1Bigger = (isAsc) => {
// 以降序的角度考虑,A1大,那么保持即可
return isAsc ? ORDER.EXCHANGE : ORDER.KEEP;
};
const A2Bigger = (isAsc) => {
// 以降序的角度考虑,A2大,那么需要跟A1交换位置
return isAsc ? ORDER.KEEP : ORDER.EXCHANGE;
};
/**
* 比较 A2 字符串与 A1 字符串在第index位谁更大
* 这里的排序规则为: a < A < b < B < c < C 与OfficeExcel保持一致
* #param A2
* #param A1
* #param isAsc
* #param index
*/
const excelStringCompare = (A2, A1, isAsc, index = 0) => {
if(A2 === A1) {
return ORDER.EQUAL
}
const charCodeA1 = A1.charCodeAt(index), charCodeA2 = A2.charCodeAt(index)
// 两个字串相等情况以及处理,会有NaN一定是有一个长度大于另一个,而charCodeAt(index)等于NaN的就说明他的长度更短
if(isNaN(charCodeA1)) {
return A2Bigger(isAsc);
} else if(isNaN(charCodeA2)) {
return A1Bigger(isAsc);
}
// 都是小写或都是大写
if ((isLower(charCodeA1) && isLower(charCodeA2)) || (isUpper(charCodeA1) && isUpper(charCodeA2))) {
if (charCodeA2 < charCodeA1) {
return A1Bigger(isAsc);
}
if (charCodeA2 > charCodeA1) {
return A2Bigger(isAsc);
}
// 当两个字符串这个位相等的时候再比较下个位
return excelStringCompare(A2, A1, isAsc, index + 1 )
}
// A1 小写 A2 大写
else if (isLower(charCodeA1) && isUpper(charCodeA2)) {
// a - A
if (charCodeA1 - charCodeA2 === diffLowerUpper) {
return A1Bigger(isAsc);
} else {
// c - (a - A) < D 即 (c - a = 2) < (D - A = 3)
if (charCodeA1 - diffLowerUpper < charCodeA2) {
return A2Bigger(isAsc);
} else {
return A1Bigger(isAsc);
}
}
}
// A1 大写 A2 小写
else {
// A - a === - (a - A)
if (charCodeA1 - charCodeA2 === -diffLowerUpper) {
return A2Bigger(isAsc);
} else {
// C + (a - A) < d 即 (C - A = 2) < (d - a = 3)
if (charCodeA1 + diffLowerUpper < charCodeA2) {
return A2Bigger(isAsc);
} else {
return A1Bigger(isAsc);
}
}
}
};
const isAsc = true;// 升降序
let strArr = ['a','Ab', 'b', 'aB', 'A', 'B', 'ab', 'AB', 'c', 'D', 'd', 'C']
strArr.sort((a, b) => {
return excelStringCompare(a, b, isAsc)
})
console.log(strArr)
I am storing the data to the Firebase when the user starts typing in the ACE editor with the help of firepad.
The data is stored in the Firebase like an Array. Each character in array index.
I just typed "Hi Its" then "Hi Its Nithi" then inserted "Hi Its Me Nithi"
It's really hard to read the data with key, value, array, index with -ve value.
Is there any plugin to convert handle the index?
Data:
B11
o
0: 7
1: -1
B12
o
0: 7
1: "N"
B13
o
0: 8
1: "ithi"
B14
o
0: 7
1: "M"
2: 5
B15
o
0: 8
1: "e"
2: 5
Am really tired by constructing a code like :
Which grow and getting more complex.
codeTimeFirebaseRef.on('value', function(snapshot) {
var data = snapshot.val();
var i = 1;
var jsonData = {};
var jsonDataArray = {};
async.forEach(Object.keys(data), function(key) {
var code = data[key];
if (code.o.length === 1) {
if (jsonDataArray.length > 1) {
jsonData.answer = jsonDataArray;
codes.push(jsonData);
i++;
jsonData = {};
jsonDataArray = {};
} else {
jsonData.index = i;
jsonData.time = code.t;
if (typeof code.o[0] === 'string') {
jsonDataArray = code.o[0];
} else if (typeof code.o[0] === 'number') {
jsonDataArray = jsonDataArray.substring(0, code.o[0]);
}
}
} else {
if (typeof code.o[1] === 'string') {
jsonDataArray += '' + code.o[1];
} else if (typeof code.o[1] === 'number') {
jsonDataArray = jsonDataArray.substring(code.o[0], code.o[1]);
}
}
Please help to get through.
How to get the co-ordinates of the outline shape formed using smaller grid blocks.
For example, If I used 32x32 unit blocks for construct a shape (any shape).
Then how can I get overall co-ordinates of the shape, including the negative spaces.
For example:
One could arrange the blocks like this:
(each block is 32x32 and coordinates refer to bottom left corner of the block)
Block 1 - (0,0)
BLock 2 - (32,0)
Block 3 - 64,0)
Block 4 - (64,32)
Block 5 - (64, 64)
BLock 6 - (32, 64)
BLock 6 - (0 64)
Block 7 - (0, 32)
Now you can see this will create an empty space in the middle.
So what I would like to know is, how to get the coordinates of the above shape such that I get:
Main Block = (0,0), (96,0), (0,96)
Empty space = (32,32), (64,32), (64,64), (32,64)
Is there any mathematical solution to this?
Eventually I will be doing complex shapes.
thanks
******** edit ****
Hi,
How to deal with this condition?
<------------------^<----^
| || |
V------------------>| |
<------^ /^| |
| |<------^ / || |
| || |/ || |
V------>V------>V-->V---->
i would like the result to be like this
<-------------------<----^
| |
V ^-----------> |
| | / |
| <-------^ / |
| |/ |
V------>------->--->----->
Think of each square as an outline comprised of four vectors going in a counter-clockwise chain.
<-----^
| |
| |
V----->
So for all the squares in your shape, take the union of their outline vectors. If two outline vectors in the union are identical but go in opposite directions, they cancel each other out and are removed from the union.
For example, for two squares that are side by side the union is 8 vectors
<-----^<-----^
| || |
| || |
V----->V----->
which reduces to 6 vectors because the two vertical vectors in the middle cancel:
<-----<-----^
| |
| |
V----->----->
For the example you gave, the result of this will be (after cancellations):
<-----<-----<-----^
| |
| |
V ^-----> ^
| | | |
| | | |
V <-----V ^
| |
| |
V----->----->----->
You just have to connect up the vectors in the final reduced union to read off the outline paths. Note that the inner outline ("the hole") runs clockwise.
You would probably need to focus on Boolean Polygon Operations, unions in your case. There are plenty of papers covering the 2D boolean polygon operations and constructive planar geometry, see the Wikipedia: http://en.wikipedia.org/wiki/Boolean_operations_on_polygons.
I know this is very late to the discussion, but I recently had to deal with the same problem, and came up with the following algorithm, described in a somewhat high level here.
First, some terminology. As seen in the picture, we label the top left cell "r0c0" (i.e. row 0 column 0), and the one to the right "r0c1" and so on. We say that the edge to the left of rxcy starts at x,y and goes to x,(y+1) and so on.
The idea is to first find the points at which the outline should change direction.
That is the corners of the shape. I did this by first making a 2d array of numbers where the number was 1 if there was a cell in that place, and 0 otherwise.
Then I looped over the 2d array, and found that the top left point of a cell should be included if either the cell above and the cell to the right were both not there, or if they were both there and the cell above and to the left was not there. Similarly for the three other corners of the cell. We also remember to label the points according to what intercardinal direction they are in their cell (north west, north east and so on)
After this we have a list of points. We then start by finding the top left point of those and traversing. We know to start going right after the top left point. Using the image, we go right from a north west point. We then find the point that has the same y coordinate, but an x-coordinate larger, but the least largest of the points to the right. We also know that the next corner we hit should have an intercardinal direction of north west or north east, as we can't go from north to west by going right.
In the picture we would hit the north east point at r3c6. We then know to go down after that, because going to a north east point from the right means going down afterwards. We continue like this until we can find no more points.
There might still be points left after all this. This means we have disjoint cells, or that there is a hole. So just do the whole thing again.
I get that this wall of text is quite difficult to follow along with, so here is some typescript code, that will hopefully make it a bit simpler (sorry, don't know php). If you have any questions, please reach out. Also, this code can probably be optimized.
The main function is the createOutlines function
type Position = {row: number; column: number};
type Dimensions = { rows: number; columns: number };
type Point = {
x: number;
y: number;
};
type Direction = 'up' | 'left' | 'right' | 'down';
type InterCardinal = 'nw' | 'ne' | 'sw' | 'se';
type OutlinePoint = {
point: Point;
interCardinal: InterCardinal;
};
function findOutlinePoints(
positions: Position[],
dimensions: Dimensions
): OutlinePoint[] {
// Essentially a grid of 1 and undefined where it is 1 if there is a cell in that position
// The JSON.parse(JSON.stringify()) part is just a deep copy, as javascript is quite weird
const matrixOfPoints: (number | undefined)[][] = JSON.parse(JSON.stringify(Array(dimensions.rows).fill([])));
positions.forEach(({ row, column }) => {
matrixOfPoints[row][column] = 1;
});
const points: OutlinePoint[] = [];
for (let rowIndex = 0; rowIndex < dimensions.rows; rowIndex++) {
const row = matrixOfPoints[rowIndex];
if (row.length === 0) {
continue;
}
for (let columnIndex = 0; columnIndex < dimensions.columns; columnIndex++) {
const cell = row[columnIndex];
if (!cell) {
continue;
}
// Find the values of cells around the center cell
const nw = matrixOfPoints[rowIndex - 1]?.[columnIndex - 1];
const n = matrixOfPoints[rowIndex - 1]?.[columnIndex];
const ne = matrixOfPoints[rowIndex - 1]?.[columnIndex + 1];
const w = matrixOfPoints[rowIndex]?.[columnIndex - 1];
const e = matrixOfPoints[rowIndex]?.[columnIndex + 1];
const sw = matrixOfPoints[rowIndex + 1]?.[columnIndex - 1];
const s = matrixOfPoints[rowIndex + 1]?.[columnIndex];
const se = matrixOfPoints[rowIndex + 1]?.[columnIndex + 1];
// Add the points
// Top left point
if ((n == null && w == null) || (n != null && nw == null && w != null)) {
// The north west point of this cell is a corner point, so add this point and specify that it is a north west (nw) point
points.push({
point: { x: columnIndex, y: rowIndex },
interCardinal: 'nw'
});
}
// Top right point
if ((n == null && e == null) || (n != null && ne == null && e != null)) {
points.push({
point: { x: columnIndex + 1, y: rowIndex },
interCardinal: 'ne'
});
}
// Bottom left
if ((w == null && s == null) || (w != null && sw == null && s != null)) {
points.push({
point: { x: columnIndex, y: rowIndex + 1 },
interCardinal: 'sw'
});
}
// Bottom right
if ((e == null && s == null) || (e != null && se == null && s != null)) {
points.push({
point: { x: columnIndex + 1, y: rowIndex + 1 },
interCardinal: 'se'
});
}
}
}
return points;
}
// Finds the point that is left most, and of the left most points, the one that is highest. Also finds the index of that point in the list
function findTopLeftOutlinePoint(
outlinePoints: OutlinePoint[]
): [OutlinePoint | undefined, number] {
let topLeftPoint: OutlinePoint | undefined = undefined;
let index = -1;
outlinePoints.forEach((p, i) => {
if (topLeftPoint == null) {
topLeftPoint = p;
index = i;
return;
}
if (
p.point.x < topLeftPoint.point.x ||
(p.point.x <= topLeftPoint.point.x &&
p.point.y < topLeftPoint.point.y)
) {
index = i;
topLeftPoint = p;
}
});
return [topLeftPoint, index];
}
/** E.g. going, "up", coming to "nw", one has to go "right" */
const NextDirection: Record<Direction, Record<InterCardinal, Direction>> = {
up: {
nw: 'right',
ne: 'left',
sw: 'left',
se: 'right'
},
down: {
nw: 'left',
ne: 'right',
sw: 'right',
se: 'left'
},
right: {
nw: 'up',
ne: 'down',
sw: 'down',
se: 'up'
},
left: {
nw: 'down',
ne: 'up',
sw: 'up',
se: 'down'
}
};
// Given the previous point, and the direction, find the next point from the list of points
function findNextPoint(
previousPointInPath: OutlinePoint,
points: OutlinePoint[],
direction: Direction
): [OutlinePoint, number] | undefined {
// e.g. if coming from nw going right, we should find a point that has the same y coordinates, and has an interCardinal of ne or se
let nextPointIndex: number | undefined;
let nextPoint: OutlinePoint | undefined;
switch (direction) {
case 'right':
// We are going "right"
points.forEach((p, i) => {
if (
// The next point should have the same y coordinate
p.point.y === previousPointInPath.point.y &&
// The next point should have a larger x coordinate
p.point.x > previousPointInPath.point.x &&
// If the previous point is north, then the next point should be north as well. Similar for south
p.interCardinal[0] === previousPointInPath.interCardinal[0]
) {
if (nextPoint == null) {
nextPoint = p;
nextPointIndex = i;
return;
} else if (p.point.x < nextPoint.point.x) {
// This is closer to the previous point than the one we already found
nextPoint = p;
nextPointIndex = i;
return;
}
}
});
break;
case 'left':
points.forEach((p, i) => {
if (
p.point.y === previousPointInPath.point.y &&
p.point.x < previousPointInPath.point.x &&
p.interCardinal[0] === previousPointInPath.interCardinal[0]
) {
if (nextPoint == null) {
nextPoint = p;
nextPointIndex = i;
return;
} else if (p.point.x > nextPoint.point.x) {
nextPoint = p;
nextPointIndex = i;
return;
}
}
});
break;
case 'up':
points.forEach((p, i) => {
if (
p.point.x === previousPointInPath.point.x &&
p.point.y < previousPointInPath.point.y &&
p.interCardinal[1] === previousPointInPath.interCardinal[1]
) {
if (nextPoint == null) {
nextPoint = p;
nextPointIndex = i;
return;
} else if (p.point.y > nextPoint.point.y) {
nextPoint = p;
nextPointIndex = i;
return;
}
}
});
break;
case 'down':
points.forEach((p, i) => {
if (
p.point.x === previousPointInPath.point.x &&
p.point.y > previousPointInPath.point.y &&
p.interCardinal[1] === previousPointInPath.interCardinal[1]
) {
if (nextPoint == null) {
nextPoint = p;
nextPointIndex = i;
return;
} else if (p.point.y < nextPoint.point.y) {
nextPoint = p;
nextPointIndex = i;
return;
}
}
});
break;
}
// If we didn't find anything, we should close the loop
if (nextPoint == null || nextPointIndex == null) return undefined;
return [nextPoint, nextPointIndex];
}
// Find the oultine of cells in a grid.
function createOutlines(
positions: Position[],
dimensions: Dimensions
): OutlinePoint[][] {
const points = findOutlinePoints(positions, dimensions);
const paths: OutlinePoint[][] = [];
while (points.length > 0) {
// This loop creates new outlines until there are no points left
const pathPoints: OutlinePoint[] = [];
const [topLeftPoint, index] = findTopLeftOutlinePoint(points);
if (topLeftPoint == null) return [];
// Remove the top left point
points.splice(index, 1);
// And add it to the path
pathPoints.push(topLeftPoint);
let direction: Direction = 'up';
while (true) {
const previousPointInPath = pathPoints[pathPoints.length - 1];
direction = NextDirection[direction][previousPointInPath.interCardinal];
const nextPointInfo = findNextPoint(previousPointInPath, points, direction);
if (nextPointInfo == null) {
// We have reached the end
pathPoints.push(topLeftPoint); // Add the first point to the end to make a loop
paths.push(pathPoints);
break;
}
const [nextPoint, nextPointIndex] = nextPointInfo;
points.splice(nextPointIndex, 1);
pathPoints.push(nextPoint);
}
}
return paths;
}