Spaces:
Paused
Paused
epii-1
commited on
Commit
·
64fee2d
1
Parent(s):
5112131
修改node
Browse files- Dockerfile +57 -7
- README.md +1 -3
- app.py +0 -162
- login.js +161 -0
- package.json +14 -0
- requirements.txt +0 -6
- server.js +116 -0
- shared.py +0 -6
- styles.css +0 -12
- tips.csv +0 -245
Dockerfile
CHANGED
|
@@ -1,13 +1,63 @@
|
|
| 1 |
-
FROM
|
| 2 |
|
| 3 |
-
WORKDIR /
|
| 4 |
|
| 5 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6 |
|
| 7 |
-
|
|
|
|
| 8 |
|
| 9 |
-
|
|
|
|
| 10 |
|
| 11 |
-
|
| 12 |
|
| 13 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
FROM node:20-slim
|
| 2 |
|
| 3 |
+
WORKDIR /app
|
| 4 |
|
| 5 |
+
RUN apt-get update && apt-get install -y \
|
| 6 |
+
wget \
|
| 7 |
+
gnupg \
|
| 8 |
+
ca-certificates \
|
| 9 |
+
libgconf-2-4 \
|
| 10 |
+
libxss1 \
|
| 11 |
+
libappindicator1 \
|
| 12 |
+
libasound2 \
|
| 13 |
+
libatk1.0-0 \
|
| 14 |
+
libc6 \
|
| 15 |
+
libcairo2 \
|
| 16 |
+
libcups2 \
|
| 17 |
+
libdbus-1-3 \
|
| 18 |
+
libexpat1 \
|
| 19 |
+
libfontconfig1 \
|
| 20 |
+
libgcc1 \
|
| 21 |
+
libgdk-pixbuf2.0-0 \
|
| 22 |
+
libglib2.0-0 \
|
| 23 |
+
libgtk-3-0 \
|
| 24 |
+
libnspr4 \
|
| 25 |
+
libpango-1.0-0 \
|
| 26 |
+
libpangocairo-1.0-0 \
|
| 27 |
+
libstdc++6 \
|
| 28 |
+
libx11-6 \
|
| 29 |
+
libx11-xcb1 \
|
| 30 |
+
libxcb1 \
|
| 31 |
+
libxcomposite1 \
|
| 32 |
+
libxcursor1 \
|
| 33 |
+
libxdamage1 \
|
| 34 |
+
libxext6 \
|
| 35 |
+
libxfixes3 \
|
| 36 |
+
libxi6 \
|
| 37 |
+
libxrandr2 \
|
| 38 |
+
libxrender1 \
|
| 39 |
+
libxss1 \
|
| 40 |
+
libxtst6 \
|
| 41 |
+
lsb-release \
|
| 42 |
+
xdg-utils \
|
| 43 |
+
&& wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | gpg --dearmor -o /usr/share/keyrings/google-chrome.gpg \
|
| 44 |
+
&& echo "deb [arch=amd64 signed-by=/usr/share/keyrings/google-chrome.gpg] http://dl.google.com/linux/chrome/deb/ stable main" > /etc/apt/sources.list.d/google-chrome.list \
|
| 45 |
+
&& apt-get update \
|
| 46 |
+
&& apt-get install -y google-chrome-stable \
|
| 47 |
+
&& rm -rf /var/lib/apt/lists/*
|
| 48 |
|
| 49 |
+
# 创建 logs 目录并更改其权限
|
| 50 |
+
RUN mkdir -p /app/logs && chown -R node:node /app
|
| 51 |
|
| 52 |
+
# 切换到非 root 用户
|
| 53 |
+
USER node
|
| 54 |
|
| 55 |
+
COPY --chown=node:node package*.json ./
|
| 56 |
|
| 57 |
+
RUN npm install
|
| 58 |
+
|
| 59 |
+
COPY --chown=node:node . .
|
| 60 |
+
|
| 61 |
+
EXPOSE 8080
|
| 62 |
+
|
| 63 |
+
CMD ["node", "server.js"]
|
README.md
CHANGED
|
@@ -6,6 +6,7 @@ colorTo: indigo
|
|
| 6 |
sdk: docker
|
| 7 |
pinned: false
|
| 8 |
license: apache-2.0
|
|
|
|
| 9 |
---
|
| 10 |
|
| 11 |
This is a templated Space for [Shiny for Python](https://shiny.rstudio.com/py/).
|
|
@@ -13,8 +14,5 @@ This is a templated Space for [Shiny for Python](https://shiny.rstudio.com/py/).
|
|
| 13 |
|
| 14 |
To get started with a new app do the following:
|
| 15 |
|
| 16 |
-
1) Install Shiny with `pip install shiny`
|
| 17 |
-
2) Create a new app with `shiny create`
|
| 18 |
-
3) Then run the app with `shiny run --reload`
|
| 19 |
|
| 20 |
To learn more about this framework please see the [Documentation](https://shiny.rstudio.com/py/docs/overview.html).
|
|
|
|
| 6 |
sdk: docker
|
| 7 |
pinned: false
|
| 8 |
license: apache-2.0
|
| 9 |
+
app_port: 8080
|
| 10 |
---
|
| 11 |
|
| 12 |
This is a templated Space for [Shiny for Python](https://shiny.rstudio.com/py/).
|
|
|
|
| 14 |
|
| 15 |
To get started with a new app do the following:
|
| 16 |
|
|
|
|
|
|
|
|
|
|
| 17 |
|
| 18 |
To learn more about this framework please see the [Documentation](https://shiny.rstudio.com/py/docs/overview.html).
|
app.py
DELETED
|
@@ -1,162 +0,0 @@
|
|
| 1 |
-
import faicons as fa
|
| 2 |
-
import plotly.express as px
|
| 3 |
-
|
| 4 |
-
# Load data and compute static values
|
| 5 |
-
from shared import app_dir, tips
|
| 6 |
-
from shinywidgets import render_plotly
|
| 7 |
-
|
| 8 |
-
from shiny import reactive, render
|
| 9 |
-
from shiny.express import input, ui
|
| 10 |
-
|
| 11 |
-
bill_rng = (min(tips.total_bill), max(tips.total_bill))
|
| 12 |
-
|
| 13 |
-
# Add page title and sidebar
|
| 14 |
-
ui.page_opts(title="Restaurant tipping", fillable=True)
|
| 15 |
-
|
| 16 |
-
with ui.sidebar(open="desktop"):
|
| 17 |
-
ui.input_slider(
|
| 18 |
-
"total_bill",
|
| 19 |
-
"Bill amount",
|
| 20 |
-
min=bill_rng[0],
|
| 21 |
-
max=bill_rng[1],
|
| 22 |
-
value=bill_rng,
|
| 23 |
-
pre="$",
|
| 24 |
-
)
|
| 25 |
-
ui.input_checkbox_group(
|
| 26 |
-
"time",
|
| 27 |
-
"Food service",
|
| 28 |
-
["Lunch", "Dinner"],
|
| 29 |
-
selected=["Lunch", "Dinner"],
|
| 30 |
-
inline=True,
|
| 31 |
-
)
|
| 32 |
-
ui.input_action_button("reset", "Reset filter")
|
| 33 |
-
|
| 34 |
-
# Add main content
|
| 35 |
-
ICONS = {
|
| 36 |
-
"user": fa.icon_svg("user", "regular"),
|
| 37 |
-
"wallet": fa.icon_svg("wallet"),
|
| 38 |
-
"currency-dollar": fa.icon_svg("dollar-sign"),
|
| 39 |
-
"ellipsis": fa.icon_svg("ellipsis"),
|
| 40 |
-
}
|
| 41 |
-
|
| 42 |
-
with ui.layout_columns(fill=False):
|
| 43 |
-
with ui.value_box(showcase=ICONS["user"]):
|
| 44 |
-
"Total tippers"
|
| 45 |
-
|
| 46 |
-
@render.express
|
| 47 |
-
def total_tippers():
|
| 48 |
-
tips_data().shape[0]
|
| 49 |
-
|
| 50 |
-
with ui.value_box(showcase=ICONS["wallet"]):
|
| 51 |
-
"Average tip"
|
| 52 |
-
|
| 53 |
-
@render.express
|
| 54 |
-
def average_tip():
|
| 55 |
-
d = tips_data()
|
| 56 |
-
if d.shape[0] > 0:
|
| 57 |
-
perc = d.tip / d.total_bill
|
| 58 |
-
f"{perc.mean():.1%}"
|
| 59 |
-
|
| 60 |
-
with ui.value_box(showcase=ICONS["currency-dollar"]):
|
| 61 |
-
"Average bill"
|
| 62 |
-
|
| 63 |
-
@render.express
|
| 64 |
-
def average_bill():
|
| 65 |
-
d = tips_data()
|
| 66 |
-
if d.shape[0] > 0:
|
| 67 |
-
bill = d.total_bill.mean()
|
| 68 |
-
f"${bill:.2f}"
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
with ui.layout_columns(col_widths=[6, 6, 12]):
|
| 72 |
-
with ui.card(full_screen=True):
|
| 73 |
-
ui.card_header("Tips data")
|
| 74 |
-
|
| 75 |
-
@render.data_frame
|
| 76 |
-
def table():
|
| 77 |
-
return render.DataGrid(tips_data())
|
| 78 |
-
|
| 79 |
-
with ui.card(full_screen=True):
|
| 80 |
-
with ui.card_header(class_="d-flex justify-content-between align-items-center"):
|
| 81 |
-
"Total bill vs tip"
|
| 82 |
-
with ui.popover(title="Add a color variable", placement="top"):
|
| 83 |
-
ICONS["ellipsis"]
|
| 84 |
-
ui.input_radio_buttons(
|
| 85 |
-
"scatter_color",
|
| 86 |
-
None,
|
| 87 |
-
["none", "sex", "smoker", "day", "time"],
|
| 88 |
-
inline=True,
|
| 89 |
-
)
|
| 90 |
-
|
| 91 |
-
@render_plotly
|
| 92 |
-
def scatterplot():
|
| 93 |
-
color = input.scatter_color()
|
| 94 |
-
return px.scatter(
|
| 95 |
-
tips_data(),
|
| 96 |
-
x="total_bill",
|
| 97 |
-
y="tip",
|
| 98 |
-
color=None if color == "none" else color,
|
| 99 |
-
trendline="lowess",
|
| 100 |
-
)
|
| 101 |
-
|
| 102 |
-
with ui.card(full_screen=True):
|
| 103 |
-
with ui.card_header(class_="d-flex justify-content-between align-items-center"):
|
| 104 |
-
"Tip percentages"
|
| 105 |
-
with ui.popover(title="Add a color variable"):
|
| 106 |
-
ICONS["ellipsis"]
|
| 107 |
-
ui.input_radio_buttons(
|
| 108 |
-
"tip_perc_y",
|
| 109 |
-
"Split by:",
|
| 110 |
-
["sex", "smoker", "day", "time"],
|
| 111 |
-
selected="day",
|
| 112 |
-
inline=True,
|
| 113 |
-
)
|
| 114 |
-
|
| 115 |
-
@render_plotly
|
| 116 |
-
def tip_perc():
|
| 117 |
-
from ridgeplot import ridgeplot
|
| 118 |
-
|
| 119 |
-
dat = tips_data()
|
| 120 |
-
dat["percent"] = dat.tip / dat.total_bill
|
| 121 |
-
yvar = input.tip_perc_y()
|
| 122 |
-
uvals = dat[yvar].unique()
|
| 123 |
-
|
| 124 |
-
samples = [[dat.percent[dat[yvar] == val]] for val in uvals]
|
| 125 |
-
|
| 126 |
-
plt = ridgeplot(
|
| 127 |
-
samples=samples,
|
| 128 |
-
labels=uvals,
|
| 129 |
-
bandwidth=0.01,
|
| 130 |
-
colorscale="viridis",
|
| 131 |
-
colormode="row-index",
|
| 132 |
-
)
|
| 133 |
-
|
| 134 |
-
plt.update_layout(
|
| 135 |
-
legend=dict(
|
| 136 |
-
orientation="h", yanchor="bottom", y=1.02, xanchor="center", x=0.5
|
| 137 |
-
)
|
| 138 |
-
)
|
| 139 |
-
|
| 140 |
-
return plt
|
| 141 |
-
|
| 142 |
-
|
| 143 |
-
ui.include_css(app_dir / "styles.css")
|
| 144 |
-
|
| 145 |
-
# --------------------------------------------------------
|
| 146 |
-
# Reactive calculations and effects
|
| 147 |
-
# --------------------------------------------------------
|
| 148 |
-
|
| 149 |
-
|
| 150 |
-
@reactive.calc
|
| 151 |
-
def tips_data():
|
| 152 |
-
bill = input.total_bill()
|
| 153 |
-
idx1 = tips.total_bill.between(bill[0], bill[1])
|
| 154 |
-
idx2 = tips.time.isin(input.time())
|
| 155 |
-
return tips[idx1 & idx2]
|
| 156 |
-
|
| 157 |
-
|
| 158 |
-
@reactive.effect
|
| 159 |
-
@reactive.event(input.reset)
|
| 160 |
-
def _():
|
| 161 |
-
ui.update_slider("total_bill", value=bill_rng)
|
| 162 |
-
ui.update_checkbox_group("time", selected=["Lunch", "Dinner"])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
login.js
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const puppeteer = require('puppeteer');
|
| 2 |
+
const axios = require('axios');
|
| 3 |
+
|
| 4 |
+
// Telegram 配置
|
| 5 |
+
let telegramConfig;
|
| 6 |
+
try {
|
| 7 |
+
telegramConfig = JSON.parse(process.env.TELEGRAM_JSON || '{}');
|
| 8 |
+
} catch (error) {
|
| 9 |
+
console.error('Error parsing TELEGRAM_JSON:', error);
|
| 10 |
+
}
|
| 11 |
+
|
| 12 |
+
function formatToISO(date) {
|
| 13 |
+
return date.toISOString().replace('T', ' ').replace('Z', '').replace(/\.\d{3}Z/, '');
|
| 14 |
+
}
|
| 15 |
+
|
| 16 |
+
async function delayTime(ms) {
|
| 17 |
+
return new Promise(resolve => setTimeout(resolve, ms));
|
| 18 |
+
}
|
| 19 |
+
|
| 20 |
+
async function sendTelegramMessage(message) {
|
| 21 |
+
if (!telegramConfig || !telegramConfig.cloudflareWorkerUrl || !telegramConfig.telegramBotToken || !telegramConfig.telegramBotUserId || !telegramConfig.customAuthKey) {
|
| 22 |
+
console.log('Telegram configuration not set or incomplete, skipping notification');
|
| 23 |
+
return;
|
| 24 |
+
}
|
| 25 |
+
|
| 26 |
+
console.log('Attempting to send Telegram message...');
|
| 27 |
+
const url = `${telegramConfig.cloudflareWorkerUrl}/${telegramConfig.telegramBotToken}/sendMessage`;
|
| 28 |
+
try {
|
| 29 |
+
const response = await axios.post(url, {
|
| 30 |
+
chat_id: telegramConfig.telegramBotUserId,
|
| 31 |
+
text: message
|
| 32 |
+
}, {
|
| 33 |
+
headers: {
|
| 34 |
+
'X-Custom-Auth': telegramConfig.customAuthKey
|
| 35 |
+
}
|
| 36 |
+
});
|
| 37 |
+
console.log('Telegram notification sent successfully');
|
| 38 |
+
} catch (error) {
|
| 39 |
+
console.error('Error sending Telegram notification:', error.response ? error.response.data : error.message);
|
| 40 |
+
}
|
| 41 |
+
}
|
| 42 |
+
|
| 43 |
+
async function loginAccount(account, browser) {
|
| 44 |
+
const { username, password, panelnum, type } = account;
|
| 45 |
+
const page = await browser.newPage();
|
| 46 |
+
|
| 47 |
+
let url = type === 'ct8'
|
| 48 |
+
? 'https://panel.ct8.pl/login/?next=/'
|
| 49 |
+
: `https://panel${panelnum}.serv00.com/login/?next=/`;
|
| 50 |
+
|
| 51 |
+
try {
|
| 52 |
+
// 设置自定义 headers 来绕过 Cloudflare
|
| 53 |
+
await page.setExtraHTTPHeaders({
|
| 54 |
+
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
|
| 55 |
+
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
|
| 56 |
+
'Accept-Language': 'en-US,en;q=0.5',
|
| 57 |
+
'Accept-Encoding': 'gzip, deflate, br',
|
| 58 |
+
'Connection': 'keep-alive',
|
| 59 |
+
'Upgrade-Insecure-Requests': '1',
|
| 60 |
+
'Sec-Fetch-Dest': 'document',
|
| 61 |
+
'Sec-Fetch-Mode': 'navigate',
|
| 62 |
+
'Sec-Fetch-Site': 'none',
|
| 63 |
+
'Sec-Fetch-User': '?1',
|
| 64 |
+
'Cache-Control': 'max-age=0',
|
| 65 |
+
});
|
| 66 |
+
|
| 67 |
+
await page.goto(url, { waitUntil: 'networkidle0' });
|
| 68 |
+
|
| 69 |
+
const usernameInput = await page.$('#id_username');
|
| 70 |
+
if (usernameInput) {
|
| 71 |
+
await usernameInput.click({ clickCount: 3 });
|
| 72 |
+
await usernameInput.press('Backspace');
|
| 73 |
+
}
|
| 74 |
+
|
| 75 |
+
await page.type('#id_username', username);
|
| 76 |
+
await page.type('#id_password', password);
|
| 77 |
+
|
| 78 |
+
const loginButton = await page.$('#submit');
|
| 79 |
+
if (loginButton) {
|
| 80 |
+
await loginButton.click();
|
| 81 |
+
} else {
|
| 82 |
+
throw new Error('无法找到登录按钮');
|
| 83 |
+
}
|
| 84 |
+
|
| 85 |
+
await page.waitForNavigation({ timeout: 30000 });
|
| 86 |
+
|
| 87 |
+
const isLoggedIn = await page.evaluate(() => {
|
| 88 |
+
const logoutButton = document.querySelector('a[href="/logout/"]');
|
| 89 |
+
return logoutButton !== null;
|
| 90 |
+
});
|
| 91 |
+
|
| 92 |
+
const nowUtc = formatToISO(new Date());
|
| 93 |
+
const nowBeijing = formatToISO(new Date(new Date().getTime() + 8 * 60 * 60 * 1000));
|
| 94 |
+
|
| 95 |
+
if (isLoggedIn) {
|
| 96 |
+
const message = `账号 ${username} (${type}) 于北京时间 ${nowBeijing}(UTC时间 ${nowUtc})登录成功!`;
|
| 97 |
+
console.log(message);
|
| 98 |
+
await sendTelegramMessage(`${type}, [${nowBeijing.split(' ')[1].split('.')[0]}]\n${message}`);
|
| 99 |
+
return { success: true, message };
|
| 100 |
+
} else {
|
| 101 |
+
const message = `账号 ${username} (${type}) 登录失败,请检查账号和密码是否正确。`;
|
| 102 |
+
console.error(message);
|
| 103 |
+
await sendTelegramMessage(`${type}, [${nowBeijing.split(' ')[1].split('.')[0]}]\n${message}`);
|
| 104 |
+
return { success: false, message };
|
| 105 |
+
}
|
| 106 |
+
} catch (error) {
|
| 107 |
+
const message = `账号 ${username} (${type}) 登录时出现错误: ${error}`;
|
| 108 |
+
console.error(message);
|
| 109 |
+
await sendTelegramMessage(`${type}, [${formatToISO(new Date()).split(' ')[1].split('.')[0]}]\n${message}`);
|
| 110 |
+
return { success: false, message };
|
| 111 |
+
} finally {
|
| 112 |
+
await page.close();
|
| 113 |
+
}
|
| 114 |
+
}
|
| 115 |
+
|
| 116 |
+
(async () => {
|
| 117 |
+
const accountsJson = process.env.ACCOUNTS_JSON;
|
| 118 |
+
const accounts = JSON.parse(accountsJson);
|
| 119 |
+
|
| 120 |
+
const browser = await puppeteer.launch({
|
| 121 |
+
headless: true,
|
| 122 |
+
args: ['--no-sandbox', '--disable-setuid-sandbox'],
|
| 123 |
+
executablePath: '/usr/bin/google-chrome-stable'
|
| 124 |
+
});
|
| 125 |
+
|
| 126 |
+
const results = [];
|
| 127 |
+
for (const account of accounts) {
|
| 128 |
+
const result = await loginAccount(account, browser);
|
| 129 |
+
results.push({ ...account, ...result });
|
| 130 |
+
|
| 131 |
+
const delay = Math.floor(Math.random() * 8000) + 1000;
|
| 132 |
+
await delayTime(delay);
|
| 133 |
+
}
|
| 134 |
+
|
| 135 |
+
await browser.close();
|
| 136 |
+
|
| 137 |
+
const successfulLogins = results.filter(r => r.success);
|
| 138 |
+
const failedLogins = results.filter(r => !r.success);
|
| 139 |
+
|
| 140 |
+
// 生成表格形式的输出
|
| 141 |
+
console.log('\n登录结果汇总:');
|
| 142 |
+
console.log('| 账号 | 类型 | 状态 | 消息 |');
|
| 143 |
+
console.log('|------|------|------|------|');
|
| 144 |
+
results.forEach(({ username, type, success, message }) => {
|
| 145 |
+
console.log(`| ${username} | ${type} | ${success ? '成功' : '失败'} | ${message} |`);
|
| 146 |
+
});
|
| 147 |
+
|
| 148 |
+
let summaryMessage = '\n登录结果统计:\n';
|
| 149 |
+
summaryMessage += `成功登录的账号:${successfulLogins.length}\n`;
|
| 150 |
+
summaryMessage += `登录失败的账号:${failedLogins.length}\n`;
|
| 151 |
+
|
| 152 |
+
if (failedLogins.length > 0) {
|
| 153 |
+
summaryMessage += '\n登录失败的账号列表:\n';
|
| 154 |
+
failedLogins.forEach(({ username, type }) => {
|
| 155 |
+
summaryMessage += `- ${username} (${type})\n`;
|
| 156 |
+
});
|
| 157 |
+
}
|
| 158 |
+
|
| 159 |
+
console.log(summaryMessage);
|
| 160 |
+
await sendTelegramMessage(`${accounts[0].type}, [${formatToISO(new Date()).split(' ')[1].split('.')[0]}]\n${summaryMessage}`);
|
| 161 |
+
})();
|
package.json
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "account-keep-alive",
|
| 3 |
+
"version": "1.0.0",
|
| 4 |
+
"description": "Auto-login account keep-alive script",
|
| 5 |
+
"main": "server.js",
|
| 6 |
+
"dependencies": {
|
| 7 |
+
"puppeteer": "^10.0.0",
|
| 8 |
+
"express": "^4.17.1",
|
| 9 |
+
"axios": "^0.21.1"
|
| 10 |
+
},
|
| 11 |
+
"scripts": {
|
| 12 |
+
"start": "node server.js"
|
| 13 |
+
}
|
| 14 |
+
}
|
requirements.txt
DELETED
|
@@ -1,6 +0,0 @@
|
|
| 1 |
-
faicons
|
| 2 |
-
shiny
|
| 3 |
-
shinywidgets
|
| 4 |
-
plotly
|
| 5 |
-
pandas
|
| 6 |
-
ridgeplot
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
server.js
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const express = require('express');
|
| 2 |
+
const { exec } = require('child_process');
|
| 3 |
+
const fs = require('fs');
|
| 4 |
+
const path = require('path');
|
| 5 |
+
const app = express();
|
| 6 |
+
const port = process.env.PORT || 8080;
|
| 7 |
+
|
| 8 |
+
// 使用 HOME 环境变量来创建日志目录
|
| 9 |
+
const logDir = path.join(process.env.HOME, 'logs');
|
| 10 |
+
if (!fs.existsSync(logDir)) {
|
| 11 |
+
fs.mkdirSync(logDir, { recursive: true });
|
| 12 |
+
}
|
| 13 |
+
|
| 14 |
+
let lastRunTime = null;
|
| 15 |
+
let nextRunTime = null;
|
| 16 |
+
let lastRunResults = null;
|
| 17 |
+
|
| 18 |
+
function log(message) {
|
| 19 |
+
const timestamp = new Date().toISOString();
|
| 20 |
+
const logMessage = `${timestamp}: ${message}\n`;
|
| 21 |
+
console.log(logMessage);
|
| 22 |
+
fs.appendFileSync(path.join(logDir, 'app.log'), logMessage);
|
| 23 |
+
}
|
| 24 |
+
|
| 25 |
+
app.get('/', (req, res) => {
|
| 26 |
+
let tableHtml = '';
|
| 27 |
+
let summaryHtml = '';
|
| 28 |
+
|
| 29 |
+
if (lastRunResults) {
|
| 30 |
+
tableHtml = '<h2>上次登录结果:</h2>';
|
| 31 |
+
tableHtml += '<table border="1"><tr><th>账号</th><th>类型</th><th>状态</th><th>消息</th></tr>';
|
| 32 |
+
lastRunResults.forEach(result => {
|
| 33 |
+
tableHtml += `<tr><td>${result.username}</td><td>${result.type}</td><td>${result.success ? '成功' : '失败'}</td><td>${result.message}</td></tr>`;
|
| 34 |
+
});
|
| 35 |
+
tableHtml += '</table>';
|
| 36 |
+
|
| 37 |
+
const successfulLogins = lastRunResults.filter(r => r.success);
|
| 38 |
+
const failedLogins = lastRunResults.filter(r => !r.success);
|
| 39 |
+
|
| 40 |
+
summaryHtml = '<h2>登录结果统计:</h2>';
|
| 41 |
+
summaryHtml += `<p>成功登录的账号:${successfulLogins.length}</p>`;
|
| 42 |
+
summaryHtml += `<p>登录失败的账号:${failedLogins.length}</p>`;
|
| 43 |
+
|
| 44 |
+
if (failedLogins.length > 0) {
|
| 45 |
+
summaryHtml += '<h3>登录失败的账号列表:</h3><ul>';
|
| 46 |
+
failedLogins.forEach(({ username, type }) => {
|
| 47 |
+
summaryHtml += `<li>${username} (${type})</li>`;
|
| 48 |
+
});
|
| 49 |
+
summaryHtml += '</ul>';
|
| 50 |
+
}
|
| 51 |
+
}
|
| 52 |
+
|
| 53 |
+
res.send(`
|
| 54 |
+
<h1>登录脚本状态</h1>
|
| 55 |
+
<p>上次执行时间:${lastRunTime || '尚未执行'}</p>
|
| 56 |
+
<p>下次执行时间:${nextRunTime || '未设置'}</p>
|
| 57 |
+
<a href="/run">立即执行脚本</a>
|
| 58 |
+
<br><br>
|
| 59 |
+
<a href="/logs">查看日志</a>
|
| 60 |
+
${tableHtml}
|
| 61 |
+
${summaryHtml}
|
| 62 |
+
`);
|
| 63 |
+
});
|
| 64 |
+
|
| 65 |
+
app.get('/logs', (req, res) => {
|
| 66 |
+
const logPath = path.join(logDir, 'app.log');
|
| 67 |
+
fs.readFile(logPath, 'utf8', (err, data) => {
|
| 68 |
+
if (err) {
|
| 69 |
+
res.status(500).send('无法读取日志文件');
|
| 70 |
+
return;
|
| 71 |
+
}
|
| 72 |
+
res.send(`<pre>${data}</pre>`);
|
| 73 |
+
});
|
| 74 |
+
});
|
| 75 |
+
|
| 76 |
+
function runLoginScript() {
|
| 77 |
+
log('开始执行登录脚本');
|
| 78 |
+
exec('node login.js', (error, stdout, stderr) => {
|
| 79 |
+
if (error) {
|
| 80 |
+
log(`执行错误: ${error.message}`);
|
| 81 |
+
return;
|
| 82 |
+
}
|
| 83 |
+
if (stderr) {
|
| 84 |
+
log(`脚本错误输出: ${stderr}`);
|
| 85 |
+
return;
|
| 86 |
+
}
|
| 87 |
+
log(`脚本输出:\n${stdout}`);
|
| 88 |
+
|
| 89 |
+
// 解析输出以获取结果
|
| 90 |
+
const lines = stdout.split('\n');
|
| 91 |
+
const resultStartIndex = lines.findIndex(line => line.includes('| 账号 | 类型 | 状态 | 消息 |'));
|
| 92 |
+
if (resultStartIndex !== -1) {
|
| 93 |
+
lastRunResults = lines.slice(resultStartIndex + 2)
|
| 94 |
+
.filter(line => line.trim().startsWith('|'))
|
| 95 |
+
.map(line => {
|
| 96 |
+
const [, username, type, status, message] = line.split('|').map(item => item.trim());
|
| 97 |
+
return { username, type, success: status === '成功', message };
|
| 98 |
+
});
|
| 99 |
+
}
|
| 100 |
+
});
|
| 101 |
+
lastRunTime = new Date().toISOString();
|
| 102 |
+
nextRunTime = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString();
|
| 103 |
+
}
|
| 104 |
+
|
| 105 |
+
app.get('/run', (req, res) => {
|
| 106 |
+
runLoginScript();
|
| 107 |
+
res.send('脚本执行已启动,请稍后刷新页面查看结果。');
|
| 108 |
+
});
|
| 109 |
+
|
| 110 |
+
// 每7天自动运行一次脚本
|
| 111 |
+
setInterval(runLoginScript, 7 * 24 * 60 * 60 * 1000);
|
| 112 |
+
|
| 113 |
+
app.listen(port, () => {
|
| 114 |
+
log(`服务器运行在 http://localhost:${port}`);
|
| 115 |
+
runLoginScript(); // 启动时立即运行一次
|
| 116 |
+
});
|
shared.py
DELETED
|
@@ -1,6 +0,0 @@
|
|
| 1 |
-
from pathlib import Path
|
| 2 |
-
|
| 3 |
-
import pandas as pd
|
| 4 |
-
|
| 5 |
-
app_dir = Path(__file__).parent
|
| 6 |
-
tips = pd.read_csv(app_dir / "tips.csv")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
styles.css
DELETED
|
@@ -1,12 +0,0 @@
|
|
| 1 |
-
:root {
|
| 2 |
-
--bslib-sidebar-main-bg: #f8f8f8;
|
| 3 |
-
}
|
| 4 |
-
|
| 5 |
-
.popover {
|
| 6 |
-
--bs-popover-header-bg: #222;
|
| 7 |
-
--bs-popover-header-color: #fff;
|
| 8 |
-
}
|
| 9 |
-
|
| 10 |
-
.popover .btn-close {
|
| 11 |
-
filter: var(--bs-btn-close-white-filter);
|
| 12 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
tips.csv
DELETED
|
@@ -1,245 +0,0 @@
|
|
| 1 |
-
total_bill,tip,sex,smoker,day,time,size
|
| 2 |
-
16.99,1.01,Female,No,Sun,Dinner,2
|
| 3 |
-
10.34,1.66,Male,No,Sun,Dinner,3
|
| 4 |
-
21.01,3.5,Male,No,Sun,Dinner,3
|
| 5 |
-
23.68,3.31,Male,No,Sun,Dinner,2
|
| 6 |
-
24.59,3.61,Female,No,Sun,Dinner,4
|
| 7 |
-
25.29,4.71,Male,No,Sun,Dinner,4
|
| 8 |
-
8.77,2.0,Male,No,Sun,Dinner,2
|
| 9 |
-
26.88,3.12,Male,No,Sun,Dinner,4
|
| 10 |
-
15.04,1.96,Male,No,Sun,Dinner,2
|
| 11 |
-
14.78,3.23,Male,No,Sun,Dinner,2
|
| 12 |
-
10.27,1.71,Male,No,Sun,Dinner,2
|
| 13 |
-
35.26,5.0,Female,No,Sun,Dinner,4
|
| 14 |
-
15.42,1.57,Male,No,Sun,Dinner,2
|
| 15 |
-
18.43,3.0,Male,No,Sun,Dinner,4
|
| 16 |
-
14.83,3.02,Female,No,Sun,Dinner,2
|
| 17 |
-
21.58,3.92,Male,No,Sun,Dinner,2
|
| 18 |
-
10.33,1.67,Female,No,Sun,Dinner,3
|
| 19 |
-
16.29,3.71,Male,No,Sun,Dinner,3
|
| 20 |
-
16.97,3.5,Female,No,Sun,Dinner,3
|
| 21 |
-
20.65,3.35,Male,No,Sat,Dinner,3
|
| 22 |
-
17.92,4.08,Male,No,Sat,Dinner,2
|
| 23 |
-
20.29,2.75,Female,No,Sat,Dinner,2
|
| 24 |
-
15.77,2.23,Female,No,Sat,Dinner,2
|
| 25 |
-
39.42,7.58,Male,No,Sat,Dinner,4
|
| 26 |
-
19.82,3.18,Male,No,Sat,Dinner,2
|
| 27 |
-
17.81,2.34,Male,No,Sat,Dinner,4
|
| 28 |
-
13.37,2.0,Male,No,Sat,Dinner,2
|
| 29 |
-
12.69,2.0,Male,No,Sat,Dinner,2
|
| 30 |
-
21.7,4.3,Male,No,Sat,Dinner,2
|
| 31 |
-
19.65,3.0,Female,No,Sat,Dinner,2
|
| 32 |
-
9.55,1.45,Male,No,Sat,Dinner,2
|
| 33 |
-
18.35,2.5,Male,No,Sat,Dinner,4
|
| 34 |
-
15.06,3.0,Female,No,Sat,Dinner,2
|
| 35 |
-
20.69,2.45,Female,No,Sat,Dinner,4
|
| 36 |
-
17.78,3.27,Male,No,Sat,Dinner,2
|
| 37 |
-
24.06,3.6,Male,No,Sat,Dinner,3
|
| 38 |
-
16.31,2.0,Male,No,Sat,Dinner,3
|
| 39 |
-
16.93,3.07,Female,No,Sat,Dinner,3
|
| 40 |
-
18.69,2.31,Male,No,Sat,Dinner,3
|
| 41 |
-
31.27,5.0,Male,No,Sat,Dinner,3
|
| 42 |
-
16.04,2.24,Male,No,Sat,Dinner,3
|
| 43 |
-
17.46,2.54,Male,No,Sun,Dinner,2
|
| 44 |
-
13.94,3.06,Male,No,Sun,Dinner,2
|
| 45 |
-
9.68,1.32,Male,No,Sun,Dinner,2
|
| 46 |
-
30.4,5.6,Male,No,Sun,Dinner,4
|
| 47 |
-
18.29,3.0,Male,No,Sun,Dinner,2
|
| 48 |
-
22.23,5.0,Male,No,Sun,Dinner,2
|
| 49 |
-
32.4,6.0,Male,No,Sun,Dinner,4
|
| 50 |
-
28.55,2.05,Male,No,Sun,Dinner,3
|
| 51 |
-
18.04,3.0,Male,No,Sun,Dinner,2
|
| 52 |
-
12.54,2.5,Male,No,Sun,Dinner,2
|
| 53 |
-
10.29,2.6,Female,No,Sun,Dinner,2
|
| 54 |
-
34.81,5.2,Female,No,Sun,Dinner,4
|
| 55 |
-
9.94,1.56,Male,No,Sun,Dinner,2
|
| 56 |
-
25.56,4.34,Male,No,Sun,Dinner,4
|
| 57 |
-
19.49,3.51,Male,No,Sun,Dinner,2
|
| 58 |
-
38.01,3.0,Male,Yes,Sat,Dinner,4
|
| 59 |
-
26.41,1.5,Female,No,Sat,Dinner,2
|
| 60 |
-
11.24,1.76,Male,Yes,Sat,Dinner,2
|
| 61 |
-
48.27,6.73,Male,No,Sat,Dinner,4
|
| 62 |
-
20.29,3.21,Male,Yes,Sat,Dinner,2
|
| 63 |
-
13.81,2.0,Male,Yes,Sat,Dinner,2
|
| 64 |
-
11.02,1.98,Male,Yes,Sat,Dinner,2
|
| 65 |
-
18.29,3.76,Male,Yes,Sat,Dinner,4
|
| 66 |
-
17.59,2.64,Male,No,Sat,Dinner,3
|
| 67 |
-
20.08,3.15,Male,No,Sat,Dinner,3
|
| 68 |
-
16.45,2.47,Female,No,Sat,Dinner,2
|
| 69 |
-
3.07,1.0,Female,Yes,Sat,Dinner,1
|
| 70 |
-
20.23,2.01,Male,No,Sat,Dinner,2
|
| 71 |
-
15.01,2.09,Male,Yes,Sat,Dinner,2
|
| 72 |
-
12.02,1.97,Male,No,Sat,Dinner,2
|
| 73 |
-
17.07,3.0,Female,No,Sat,Dinner,3
|
| 74 |
-
26.86,3.14,Female,Yes,Sat,Dinner,2
|
| 75 |
-
25.28,5.0,Female,Yes,Sat,Dinner,2
|
| 76 |
-
14.73,2.2,Female,No,Sat,Dinner,2
|
| 77 |
-
10.51,1.25,Male,No,Sat,Dinner,2
|
| 78 |
-
17.92,3.08,Male,Yes,Sat,Dinner,2
|
| 79 |
-
27.2,4.0,Male,No,Thur,Lunch,4
|
| 80 |
-
22.76,3.0,Male,No,Thur,Lunch,2
|
| 81 |
-
17.29,2.71,Male,No,Thur,Lunch,2
|
| 82 |
-
19.44,3.0,Male,Yes,Thur,Lunch,2
|
| 83 |
-
16.66,3.4,Male,No,Thur,Lunch,2
|
| 84 |
-
10.07,1.83,Female,No,Thur,Lunch,1
|
| 85 |
-
32.68,5.0,Male,Yes,Thur,Lunch,2
|
| 86 |
-
15.98,2.03,Male,No,Thur,Lunch,2
|
| 87 |
-
34.83,5.17,Female,No,Thur,Lunch,4
|
| 88 |
-
13.03,2.0,Male,No,Thur,Lunch,2
|
| 89 |
-
18.28,4.0,Male,No,Thur,Lunch,2
|
| 90 |
-
24.71,5.85,Male,No,Thur,Lunch,2
|
| 91 |
-
21.16,3.0,Male,No,Thur,Lunch,2
|
| 92 |
-
28.97,3.0,Male,Yes,Fri,Dinner,2
|
| 93 |
-
22.49,3.5,Male,No,Fri,Dinner,2
|
| 94 |
-
5.75,1.0,Female,Yes,Fri,Dinner,2
|
| 95 |
-
16.32,4.3,Female,Yes,Fri,Dinner,2
|
| 96 |
-
22.75,3.25,Female,No,Fri,Dinner,2
|
| 97 |
-
40.17,4.73,Male,Yes,Fri,Dinner,4
|
| 98 |
-
27.28,4.0,Male,Yes,Fri,Dinner,2
|
| 99 |
-
12.03,1.5,Male,Yes,Fri,Dinner,2
|
| 100 |
-
21.01,3.0,Male,Yes,Fri,Dinner,2
|
| 101 |
-
12.46,1.5,Male,No,Fri,Dinner,2
|
| 102 |
-
11.35,2.5,Female,Yes,Fri,Dinner,2
|
| 103 |
-
15.38,3.0,Female,Yes,Fri,Dinner,2
|
| 104 |
-
44.3,2.5,Female,Yes,Sat,Dinner,3
|
| 105 |
-
22.42,3.48,Female,Yes,Sat,Dinner,2
|
| 106 |
-
20.92,4.08,Female,No,Sat,Dinner,2
|
| 107 |
-
15.36,1.64,Male,Yes,Sat,Dinner,2
|
| 108 |
-
20.49,4.06,Male,Yes,Sat,Dinner,2
|
| 109 |
-
25.21,4.29,Male,Yes,Sat,Dinner,2
|
| 110 |
-
18.24,3.76,Male,No,Sat,Dinner,2
|
| 111 |
-
14.31,4.0,Female,Yes,Sat,Dinner,2
|
| 112 |
-
14.0,3.0,Male,No,Sat,Dinner,2
|
| 113 |
-
7.25,1.0,Female,No,Sat,Dinner,1
|
| 114 |
-
38.07,4.0,Male,No,Sun,Dinner,3
|
| 115 |
-
23.95,2.55,Male,No,Sun,Dinner,2
|
| 116 |
-
25.71,4.0,Female,No,Sun,Dinner,3
|
| 117 |
-
17.31,3.5,Female,No,Sun,Dinner,2
|
| 118 |
-
29.93,5.07,Male,No,Sun,Dinner,4
|
| 119 |
-
10.65,1.5,Female,No,Thur,Lunch,2
|
| 120 |
-
12.43,1.8,Female,No,Thur,Lunch,2
|
| 121 |
-
24.08,2.92,Female,No,Thur,Lunch,4
|
| 122 |
-
11.69,2.31,Male,No,Thur,Lunch,2
|
| 123 |
-
13.42,1.68,Female,No,Thur,Lunch,2
|
| 124 |
-
14.26,2.5,Male,No,Thur,Lunch,2
|
| 125 |
-
15.95,2.0,Male,No,Thur,Lunch,2
|
| 126 |
-
12.48,2.52,Female,No,Thur,Lunch,2
|
| 127 |
-
29.8,4.2,Female,No,Thur,Lunch,6
|
| 128 |
-
8.52,1.48,Male,No,Thur,Lunch,2
|
| 129 |
-
14.52,2.0,Female,No,Thur,Lunch,2
|
| 130 |
-
11.38,2.0,Female,No,Thur,Lunch,2
|
| 131 |
-
22.82,2.18,Male,No,Thur,Lunch,3
|
| 132 |
-
19.08,1.5,Male,No,Thur,Lunch,2
|
| 133 |
-
20.27,2.83,Female,No,Thur,Lunch,2
|
| 134 |
-
11.17,1.5,Female,No,Thur,Lunch,2
|
| 135 |
-
12.26,2.0,Female,No,Thur,Lunch,2
|
| 136 |
-
18.26,3.25,Female,No,Thur,Lunch,2
|
| 137 |
-
8.51,1.25,Female,No,Thur,Lunch,2
|
| 138 |
-
10.33,2.0,Female,No,Thur,Lunch,2
|
| 139 |
-
14.15,2.0,Female,No,Thur,Lunch,2
|
| 140 |
-
16.0,2.0,Male,Yes,Thur,Lunch,2
|
| 141 |
-
13.16,2.75,Female,No,Thur,Lunch,2
|
| 142 |
-
17.47,3.5,Female,No,Thur,Lunch,2
|
| 143 |
-
34.3,6.7,Male,No,Thur,Lunch,6
|
| 144 |
-
41.19,5.0,Male,No,Thur,Lunch,5
|
| 145 |
-
27.05,5.0,Female,No,Thur,Lunch,6
|
| 146 |
-
16.43,2.3,Female,No,Thur,Lunch,2
|
| 147 |
-
8.35,1.5,Female,No,Thur,Lunch,2
|
| 148 |
-
18.64,1.36,Female,No,Thur,Lunch,3
|
| 149 |
-
11.87,1.63,Female,No,Thur,Lunch,2
|
| 150 |
-
9.78,1.73,Male,No,Thur,Lunch,2
|
| 151 |
-
7.51,2.0,Male,No,Thur,Lunch,2
|
| 152 |
-
14.07,2.5,Male,No,Sun,Dinner,2
|
| 153 |
-
13.13,2.0,Male,No,Sun,Dinner,2
|
| 154 |
-
17.26,2.74,Male,No,Sun,Dinner,3
|
| 155 |
-
24.55,2.0,Male,No,Sun,Dinner,4
|
| 156 |
-
19.77,2.0,Male,No,Sun,Dinner,4
|
| 157 |
-
29.85,5.14,Female,No,Sun,Dinner,5
|
| 158 |
-
48.17,5.0,Male,No,Sun,Dinner,6
|
| 159 |
-
25.0,3.75,Female,No,Sun,Dinner,4
|
| 160 |
-
13.39,2.61,Female,No,Sun,Dinner,2
|
| 161 |
-
16.49,2.0,Male,No,Sun,Dinner,4
|
| 162 |
-
21.5,3.5,Male,No,Sun,Dinner,4
|
| 163 |
-
12.66,2.5,Male,No,Sun,Dinner,2
|
| 164 |
-
16.21,2.0,Female,No,Sun,Dinner,3
|
| 165 |
-
13.81,2.0,Male,No,Sun,Dinner,2
|
| 166 |
-
17.51,3.0,Female,Yes,Sun,Dinner,2
|
| 167 |
-
24.52,3.48,Male,No,Sun,Dinner,3
|
| 168 |
-
20.76,2.24,Male,No,Sun,Dinner,2
|
| 169 |
-
31.71,4.5,Male,No,Sun,Dinner,4
|
| 170 |
-
10.59,1.61,Female,Yes,Sat,Dinner,2
|
| 171 |
-
10.63,2.0,Female,Yes,Sat,Dinner,2
|
| 172 |
-
50.81,10.0,Male,Yes,Sat,Dinner,3
|
| 173 |
-
15.81,3.16,Male,Yes,Sat,Dinner,2
|
| 174 |
-
7.25,5.15,Male,Yes,Sun,Dinner,2
|
| 175 |
-
31.85,3.18,Male,Yes,Sun,Dinner,2
|
| 176 |
-
16.82,4.0,Male,Yes,Sun,Dinner,2
|
| 177 |
-
32.9,3.11,Male,Yes,Sun,Dinner,2
|
| 178 |
-
17.89,2.0,Male,Yes,Sun,Dinner,2
|
| 179 |
-
14.48,2.0,Male,Yes,Sun,Dinner,2
|
| 180 |
-
9.6,4.0,Female,Yes,Sun,Dinner,2
|
| 181 |
-
34.63,3.55,Male,Yes,Sun,Dinner,2
|
| 182 |
-
34.65,3.68,Male,Yes,Sun,Dinner,4
|
| 183 |
-
23.33,5.65,Male,Yes,Sun,Dinner,2
|
| 184 |
-
45.35,3.5,Male,Yes,Sun,Dinner,3
|
| 185 |
-
23.17,6.5,Male,Yes,Sun,Dinner,4
|
| 186 |
-
40.55,3.0,Male,Yes,Sun,Dinner,2
|
| 187 |
-
20.69,5.0,Male,No,Sun,Dinner,5
|
| 188 |
-
20.9,3.5,Female,Yes,Sun,Dinner,3
|
| 189 |
-
30.46,2.0,Male,Yes,Sun,Dinner,5
|
| 190 |
-
18.15,3.5,Female,Yes,Sun,Dinner,3
|
| 191 |
-
23.1,4.0,Male,Yes,Sun,Dinner,3
|
| 192 |
-
15.69,1.5,Male,Yes,Sun,Dinner,2
|
| 193 |
-
19.81,4.19,Female,Yes,Thur,Lunch,2
|
| 194 |
-
28.44,2.56,Male,Yes,Thur,Lunch,2
|
| 195 |
-
15.48,2.02,Male,Yes,Thur,Lunch,2
|
| 196 |
-
16.58,4.0,Male,Yes,Thur,Lunch,2
|
| 197 |
-
7.56,1.44,Male,No,Thur,Lunch,2
|
| 198 |
-
10.34,2.0,Male,Yes,Thur,Lunch,2
|
| 199 |
-
43.11,5.0,Female,Yes,Thur,Lunch,4
|
| 200 |
-
13.0,2.0,Female,Yes,Thur,Lunch,2
|
| 201 |
-
13.51,2.0,Male,Yes,Thur,Lunch,2
|
| 202 |
-
18.71,4.0,Male,Yes,Thur,Lunch,3
|
| 203 |
-
12.74,2.01,Female,Yes,Thur,Lunch,2
|
| 204 |
-
13.0,2.0,Female,Yes,Thur,Lunch,2
|
| 205 |
-
16.4,2.5,Female,Yes,Thur,Lunch,2
|
| 206 |
-
20.53,4.0,Male,Yes,Thur,Lunch,4
|
| 207 |
-
16.47,3.23,Female,Yes,Thur,Lunch,3
|
| 208 |
-
26.59,3.41,Male,Yes,Sat,Dinner,3
|
| 209 |
-
38.73,3.0,Male,Yes,Sat,Dinner,4
|
| 210 |
-
24.27,2.03,Male,Yes,Sat,Dinner,2
|
| 211 |
-
12.76,2.23,Female,Yes,Sat,Dinner,2
|
| 212 |
-
30.06,2.0,Male,Yes,Sat,Dinner,3
|
| 213 |
-
25.89,5.16,Male,Yes,Sat,Dinner,4
|
| 214 |
-
48.33,9.0,Male,No,Sat,Dinner,4
|
| 215 |
-
13.27,2.5,Female,Yes,Sat,Dinner,2
|
| 216 |
-
28.17,6.5,Female,Yes,Sat,Dinner,3
|
| 217 |
-
12.9,1.1,Female,Yes,Sat,Dinner,2
|
| 218 |
-
28.15,3.0,Male,Yes,Sat,Dinner,5
|
| 219 |
-
11.59,1.5,Male,Yes,Sat,Dinner,2
|
| 220 |
-
7.74,1.44,Male,Yes,Sat,Dinner,2
|
| 221 |
-
30.14,3.09,Female,Yes,Sat,Dinner,4
|
| 222 |
-
12.16,2.2,Male,Yes,Fri,Lunch,2
|
| 223 |
-
13.42,3.48,Female,Yes,Fri,Lunch,2
|
| 224 |
-
8.58,1.92,Male,Yes,Fri,Lunch,1
|
| 225 |
-
15.98,3.0,Female,No,Fri,Lunch,3
|
| 226 |
-
13.42,1.58,Male,Yes,Fri,Lunch,2
|
| 227 |
-
16.27,2.5,Female,Yes,Fri,Lunch,2
|
| 228 |
-
10.09,2.0,Female,Yes,Fri,Lunch,2
|
| 229 |
-
20.45,3.0,Male,No,Sat,Dinner,4
|
| 230 |
-
13.28,2.72,Male,No,Sat,Dinner,2
|
| 231 |
-
22.12,2.88,Female,Yes,Sat,Dinner,2
|
| 232 |
-
24.01,2.0,Male,Yes,Sat,Dinner,4
|
| 233 |
-
15.69,3.0,Male,Yes,Sat,Dinner,3
|
| 234 |
-
11.61,3.39,Male,No,Sat,Dinner,2
|
| 235 |
-
10.77,1.47,Male,No,Sat,Dinner,2
|
| 236 |
-
15.53,3.0,Male,Yes,Sat,Dinner,2
|
| 237 |
-
10.07,1.25,Male,No,Sat,Dinner,2
|
| 238 |
-
12.6,1.0,Male,Yes,Sat,Dinner,2
|
| 239 |
-
32.83,1.17,Male,Yes,Sat,Dinner,2
|
| 240 |
-
35.83,4.67,Female,No,Sat,Dinner,3
|
| 241 |
-
29.03,5.92,Male,No,Sat,Dinner,3
|
| 242 |
-
27.18,2.0,Female,Yes,Sat,Dinner,2
|
| 243 |
-
22.67,2.0,Male,Yes,Sat,Dinner,2
|
| 244 |
-
17.82,1.75,Male,No,Sat,Dinner,2
|
| 245 |
-
18.78,3.0,Female,No,Thur,Dinner,2
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|