作者归档:tpu01yzx@gmail.com

戴尔R730xd调整风扇转速

为了增加工作效率,特地从某宝上淘了一台洋垃圾,戴尔R730xd,内存和CPU都是加大了配置,显卡则一般,硬盘留空自己填坑。具体配置如下:

E5-2696V42/DDR4 768G内存/SAS 300G1/H730P 阵列卡/1050TI 4G*1/满盘架/双电750W

硬盘是自己单独买的三个硬盘:

1. WD 6T蓝盘 WD60EZAZ 只有 OEM 680
2. WD 2T 金盘 WD2005VBYZ 908
3. WD 2T SSD固态绿盘2.5寸 SATA 865

本来一切都还算顺利,开机之后,那个杀猪一样的噪声把我震惊了。只要想办法调整风扇的转速,正常来说机器温度不高的时候,风扇不应该转这么快。于是首先想到的是这样调整,其中0x0A表示风扇最大转速的百分比[1]:

ipmitool raw 0x30 0x30 0x01 0x00
ipmitool raw 0x30 0x30 0x02 0xff 0x0A

但是后来发现原来根本原因是由于加装了PCIE显卡的原因,导致主板自作聪明高估了热量,因此要求风扇高速运转。最好禁用掉这个自作聪明的功能[2]:

ipmitool raw 0x30 0xce 0x00 0x16 0x05 0x00 0x00 0x00 0x05 0x00 0x01 0x00 0x00

如果是Windows Server用户,可以用[3]这里下载这个ipmitool的工具。

参考文献:
[1] Dell ENG is taking away fan speed control away from users ( iDrac >= 3.34.34.34)
[2] DELL R730xd 加装PCIE固态硬盘 风扇问题? – Dell Community
[3] Dell EMC iDRAC Tools for Microsoft Windows Server®,v9.4.0

Актуальное зеркало Vavada для азартных игр уже доступно



Актуальное зеркало Vavada для азартных игр доступно сейчас


Актуальное зеркало Vavada для азартных игр уже доступно

Ищете надежный способ доступа к мир азартных игр? Наше актуальное зеркало Vavada предлагает вам уникальную возможность наслаждаться любимыми играми без ограничений. Мы предоставляем стабильный и безопасный доступ к платформе, позволяя вам играть в любое время и в любом месте.

С Vavada вы получаете:

  • Высокое качество обслуживания: Надежность и безопасность ваших данных – наш приоритет.
  • Широкий выбор игр: Исследуйте разнообразные слоты, настольные игры и live-казино.
  • Щедрые бонусы: Участвуйте в акциях и получайте дополнительные выигрыши.

Не дайте себе упустить возможность! Пользуйтесь актуальным зеркалом Vavada и открывайте для себя новый уровень азартных игр!

Как легко получить доступ к зеркалу Vavada для стабильной игры

Первым шагом к получению доступа к зеркалу Vavada является регулярная проверка обновлений на официальном сайте или в социальных сетях казино. Часто администрация информирует игроков о новых зеркалах и изменениях в доменных именах. Также вы можете подписаться на рассылку, чтобы получать уведомления напрямую на ваш email.

Второй способ – обратиться к проверенным источникам, где публикуются актуальные ссылки на зеркала. На специализированных форумах и сайтах, посвященных азартным играм, можно найти актуальную информацию от других игроков и экспертов. Убедитесь, что используете надежные источники, чтобы избежать фишинга и мошеннических сайтов.

Кроме того, для быстрого доступа можно использовать специальные приложения или менеджеры, которые позволяют сохранять и автоматически обновлять ссылки на зеркала Vavada. Это значительно упростит процесс входа и сделает его более безопасным.

Некоторые игроки выбирают использование VPN-сервисов для обхода блокировок. Это дает возможность не только получить доступ к зеркалам, но и обеспечить дополнительную защиту личных данных во время игры на платформе.

Не забывайте также про вавада онлайн казино, где вы найдете всю необходимую информацию о доступных зеркалах и игровых предложениях. Следуя этим простым рекомендациям, вы сможете легко и безопасно получить доступ к зеркалу Vavada и наслаждаться азартными играми без перебоев.

Преимущества использования актуального зеркала Vavada в азартных играх

Актуальное зеркало Vavada предлагает множество преимуществ для пользователей, желающих получить доступ к азартным играм. Рассмотрим ключевые из них:

  • Доступность: Зеркала обеспечивают постоянный доступ к сайту, даже если основной ресурс временно заблокирован. Пользователи могут играть без перерывов, что особенно важно для азартных игр.
  • Безопасность: Использование актуального зеркала гарантирует защиту персональных данных и финансовых транзакций благодаря современным технологиям шифрования и защиты.
  • Обновленный контент: Зеркала часто обновляются и содержат актуальную информацию о новых играх, акциях и бонусах, что позволяет игрокам быть в курсе всех нововведений.
  • Удобный интерфейс: Aктуальное зеркало Vavada сохраняет оригинальный интерфейс, что облегчает навигацию и делает процесс игры более комфортным для пользователей.
  • Быстрая регистрация: Процесс регистрации на зеркале такой же прост и быстрый, как и на основном сайте, что позволяет новым пользователям легко присоединиться к азартной игре.
  • Кроссплатформенная совместимость: Зеркала работают на различных устройствах, включая мобильные телефоны и компьютеры, что обеспечивает гибкость в выборе способа игры.

Воспользуйтесь преимуществами актуального зеркала Vavada и наслаждайтесь безопасным и беспрепятственным доступом к вашим любимым азартным играм!

Рекомендации по безопасному доступу к зеркалам Vavada

Для обеспечения безопасного доступа к зеркалам Vavada важно следовать определенным рекомендациям. Первое, на что стоит обратить внимание, это использование официальных источников для получения актуальных ссылок. Избегайте непроверенных веб-сайтов и ссылок из сомнительных источников, чтобы не стать жертвой мошенничества.

Вторым аспектом является использование VPN-сервисов. Они обеспечивают дополнительный уровень защиты, скрывая ваш IP-адрес и шифруя интернет-трафик. Использование качественного VPN поможет обойти блокировки и защитит ваши данные от постороннего доступа.

Не забывайте о важности регулярного обновления программного обеспечения на ваших устройствах. Устаревшие версии браузеров или антивирусов могут содержать уязвимости, которые злоумышленники могут использовать для атак.

Рекомендуется также включить двухфакторную аутентификацию для своей учетной записи на Vavada. Это добавит еще один уровень безопасности, требуя подтверждения входа через другой источник, такой как мобильный телефон.

Наконец, следите за своей активностью в сети. Будьте осторожны с тем, какие личные данные вы предоставляете и каким сайтам доверяете. Проверяйте адресную строку браузера на наличие защищенного соединения (https://) перед вводом личной информации.


Как использовать бонусы в мостбет



Максимально выгодное использование бонусов в мостбет


Как использовать бонусы в мостбет

Мостбет предлагает своим клиентам уникальные возможности для максимизации выигрышей благодаря щедрой бонусной программе. Используйте бонусы на депозит и бесплатные ставки для повышения своих шансов на успех. Чем больше вы играете, тем больше бонусов получаете! При регистрации на сайте вам доступен приветственный пакет, который поможет легко стартовать в мире ставок.

Не упустите шанс воспользоваться ежедневными акциями и турнирами, которые не только добавят интерес к игре, но и подарят дополнительные средства для ставок. Подписывайтесь на новости, чтобы первыми узнавать о новых предложениях и повышать свои шансы на успех!

Как получить максимальное количество бонусов при регистрации и первых ставках

Чтобы воспользоваться всеми привилегиями бонусной программы в Мостбет, нужно внимательно следовать нескольким простым шагам. Во-первых, начните с регистрации на сайте. Заполните все необходимые поля и убедитесь, что указали актуальные данные. Это позволит вам получить приветственный пакет бонусов.

Во-вторых, не забудьте активировать промокод, если он у вас есть. Промокоды часто предлагают дополнительные бонусы, которые могут значительно увеличить ваш стартовый капитал. Вводите их в специальное поле при регистрации или в разделе “Ваш профиль”.

После успешной регистрации сделайте первые ставки. Мостбет предоставляет бонусы на разные виды ставок. Чтобы максимизировать свои преимущества, следите за акциями и бонусными предложениями, которые меняются регулярно. Выбирайте события с хорошими коэффициентами, это увеличит шансы на получение дополнительных бонусов за выигрышные ставки.

Также рекомендуется ознакомиться с условиями отыгрыша бонусов. Различные предложения могут иметь свои требования по ставкам. Например, может потребоваться заключить ставки на определенные суммы или коэффициенты. Внимательно изучив эти условия, вы сможете грамотно спланировать свои действия и избежать неожиданных сложностей.

Не забывайте о программе лояльности. Часто пользователи, активно ставящие на платформе, получают дополнительные преференции. Следите за своим статусом и используйте все доступные возможности для получения бонусов.

Стратегии использования бонусов для увеличения выигрышей на ставках

Эффективное использование бонусов, предоставляемых букмекерами, такими как mostbet официальный сайт, может значительно увеличить ваши шансы на выигрыш. Однако для максимизации прибыли необходимо применять определенные стратегии.

1. Изучение условий бонуса. Перед тем как начать использовать бонус, важно внимательно ознакомиться с его условиями. Проверьте минимальные ставки, сроки действия и требования по обороту. Это поможет избежать неприятных ситуаций и максимизировать выгоду.

2. Использование бонусов на спортивные события с высокой вероятностью. Направляйте свои бонусные средства на ставки, вероятность исхода которых анализируется. Исследуйте статистику команд и игроков, чтобы повысить шансы на успех.

3. Комбинирование ставок. Рассмотрите возможность комбинирования нескольких событий в одном купоне. Это может увеличить общую выплату, однако учитывайте риски, так как все события должны сыграть.

4. Следите за акциями. Многие букмекеры проводят постоянные акции и предлагают дополнительные бонусы. Участвуйте в них для увеличения вашего банка и возможностей для ставок.

5. Установка лимитов. Установите для себя лимиты на использование бонусов, чтобы избежать излишнего риска. Это поможет контролировать ваш бюджет и сохранять дисциплину в ставках.

Следуя этим стратегиями, вы сможете более эффективно использовать свои бонусы и увеличить шансы на успех в ставках. Начните свой путь к выигрышам с изучения предложений на mostbet официальный сайт и применяйте выгодные стратегии для достижения ваших целей.

Ошибки, которых следует избегать при использовании бонусных предложений в мостбет

При использовании бонусных предложений в мостбет важно избегать распространенных ошибок, которые могут снизить вашу выгоду. Вот основные из них:

1. Неправильное чтение условий бонуса. Перед тем как активировать бонус, тщательно ознакомьтесь с его условиями. У каждого бонуса могут быть свои требования по ставкам, минимальным депозитам и срокам действия. Игнорирование этих деталей может привести к тому, что вы не сможете вывести выигрыш.

2. Пренебрежение сроками действия бонусов. Большинство бонусных предложений имеют ограниченный срок действия. Важно использовать их в пределах установленного времени, иначе они могут просто исчезнуть, оставив вас без дополнительных средств.

3. Необоснованные ставки. Использование бонусных средств не означает, что можно делать необоснованные или слишком рискованные ставки. Следует продолжать анализировать игры и делать ставки, основываясь на стратегии, а не на эмоциях.

5. Использование нескольких аккаунтов. Создание нескольких аккаунтов для получения бонусов может привести к блокировке всех ваших учетных записей. Мостбет строго наказывает за подобные действия, поэтому лучше играть честно.

6. Неучет акций и дополнительных предложений. Иногда мостбет предлагает дополнительные акции для пользователей. Не игнорируйте их, так как они могут существенно увеличить ваши шансы на выигрыш.

Избегая этих ошибок, вы сможете более эффективно использовать бонусные предложения в мостбет и повысить свои шансы на успешные ставки.


Вход в Joycasino азартные игры с крупными выигрышами



Вход в Joycasino крупные выигрыши азартных игр


Вход в Joycasino азартные игры с крупными выигрышами

Тебе нужно просто зарегистрироваться и воспользоваться щедрыми предложениями. Никаких долгих ожиданий и сложных процедур – всё продумано для твоего удобства. Каждого нового игрока ждёт приятный стартовый бонус!

Главное – не упустить шанс на выгодные акции и турниры с реальными денежными призами. Посмотри на выгодные условия по кэшбэку и игровые турниры – это твое время блеснуть удачей! Проверяй регулярные обновления, чтобы поймать самые горячие предложения.

Приступай к игре и получай возможность заработать на любимых развлечениях. Здесь каждый раунд может принести тебе отличные вознаграждения! Не забудь изучить правила – это значительно повысит шансы на успех.

Вход в Joycasino: крупные выигрыши азартных игр

Для достижения успеха стоит обратить внимание на стратегии ставок и внимательно изучить правила выбранных развлечений. Попробуйте вначале освоить несколько простых, но прибыльных вариаций. Не забывайте, что разные игровые автоматы и карточные варианты имеют свои особенности. Это крайне важно при выборе, ведь зачастую шансы определяются именно этим аспектом.

Рекомендуется следить за обновлениями и участвовать в акциях, которые могут предлагать дополнительные бонусы и фриспины. Такие предложения существенно увеличивают шансы на вознаграждение. Чтобы не потерять из виду прибыльные возможности, следует пользоваться джойказино зеркало сегодня официальное, чтобы всегда быть в игре.

Обратите внимание на отзывы игроков о стратегиях, которые они применяли. Это даст понимание, какие методы срабатывают лучше всего. Ищите информацию о популярных подходах, которые использовали успешные участники.

Не забывайте о бюджетировании – уместно заранее определить лимиты и придерживаться их, чтобы избежать ненужных потерь. Управление финансами поможет дольше наслаждаться процессом и лучше контролировать ситуацию.

Следите за рекомендациями профессионалов, которые делятся своим опытом и методами, повышающими уровень удачи. Главное – наслаждаться игрой и использовать все доступные ресурсы для достижения позитивного результата. Возьмите на заметку ключевые аспекты и играйте с умом!

Как зарегистрироваться и получить приветственный бонус в Joycasino

Перейдите на сайт и найдите кнопку «Регистрация» в правом верхнем углу. Нажмите на неё.

Заполните форму с личными данными:

  • Электронная почта
  • Пароль
  • Имя и фамилия
  • Дата рождения

После ввода информации согласитесь с условиями и нажмите на кнопку «Зарегистрироваться». Придёт письмо с подтверждением, перейдите по ссылке в нём для активации аккаунта.

Теперь вам доступно получение приветственного бонуса. Для этого:

  1. Войдите в личный кабинет.
  2. Перейдите в раздел «Касса» или «Бонусы».
  3. Выберите бонус, который хотите активировать.
  4. Внесите первый депозит, следуя указанным условиям.

Бонус будет зачислен на ваш баланс, как только депозит будет успешно обработан. Теперь вы готовы начать свои приключения и испытать удачу!

Стратегии для увеличения шансов на крупные выигрыши в азартных играх

Изучайте таблицы выплаты. Чем более информированным вы будете о правилах и коэффициентах, тем лучше сможете корректировать свою стратегию в зависимости от особенностей выбранной платформы.

Рассмотрите возможность использования системы управления банкроллом. Определите заранее, сколько готовы потратить и придерживайтесь этого лимита. Это поможет избежать эмоциональных решений и сохранить контроль над финансами.

Выбирайте игры с высокой отдачей. Внимательно изучите проценты возврата игроку (RTP) – выбирайте варианты, которые предлагают лучший шанс на успех. Обычно, слоты с RTP от 96% и выше считаются выгодными.

Практикуйтесь на бесплатных моделях. Пробуйте свои силы на демо версиях, чтобы понять механизмы работы. Это позволит вам отработать тактики и найти лучшие подходы без риска потери средств.

Используйте стратегии ставок. Например, система Мартингейла или Фибоначчи могут помочь вам в управлении ставками и увеличении шансов на получение прибыли.

Обращайтесь к бонусам и акциями. Многие платформы предлагают приветственные предложения и кэшбэк, которые могут значительно повысить ваш баланс и давать дополнительные шансы на успех.

Не забывайте о времени. Установите временные рамки для своих сессий. Это поможет избежать утомления и не позволит принимать импульсивные решения. Лучше делать паузы и возвращаться с ясной головой.

Следите за статистикой. Анализируйте свои результаты, чтобы выявить выигрышные моменты и корректировать игру. Понимание своих слабых и сильных сторон может повысить вероятность успеха.

И, наконец, играйте на удовольствие. Ожидание выигрыша иногда может затмить истинную суть процесса. Наслаждайтесь игрой, и, возможно, удача улыбнется вам в самый неожиданный момент.

Обзор популярных игр с высоким потенциалом выигрыша в Joycasino

Не обойтись и без настольных развлечений. Рулетка всегда вызывает интерес благодаря простоте и разнообразию ставок. Есть варианты с низким преимуществом для казино, что делает её идеальной для игроков, искушённых в стратегии.

Покер – ещё один захватывающий вариант. Здесь больше всего лицензированных версий, каждая из которых имеет свои правила и тактики. Участие в турнирах открывает двери к большим призам и захватывающим баталиям с противниками.

Классические карточные развлечения также не теряют своей популярности. Блэкджек со сниженным преимуществом завлекает игроков, предлагая возможность за счёт навыков и стратегий увеличить свои шансы на успех.

Обратите внимание на новые поступления. Разработчики постоянно запускают уникальные проекты с интересными механиками и современными графическими решениями. Это шанс испытать что-то свежее и, возможно, найти любимое развлечение.

Важный момент – изучите таблицы выплат и бонусные функции. Часто именно они дают подсказки о потенциале устройств. Опасайтесь автомата с высокой волатильностью, если не готовы рисковать большими суммами.

Ставьте разумно, выбирайте качественные игры и анализируйте свой опыт для максимизации наслаждения и выигрышей.


UOJ自动配置题目数据

计划未来几个星期进行线上测试,所以最近就挑了 UOJ (https://github.com/UniversalOJ/UOJ-System )来部署。用 Docker 倒是简单,就是题目数据有些难。虽然之前在其他 OJ 上有过数据和代码,但要逐个导入也是麻烦。目前的方法大概是这样的:1)通过 Docker 的配置把 UOJ 的题库数据目录 (/opt/uoj_data ) 外挂到主机目录;2)执行下面的脚本,根据标程和 input,自动生成 output 和配置problem.conf

注:由于我是在 WSL2 通过网络驱动器(SMB)的形式访问题库数据目录。居然默认不支持,需要执行下面的命令手动挂载 WSL2 主机的网络驱动器。

sudo mkdir /mnt/y
sudo mount -t drvfs Y: /mnt/y

下面的是Linux下的Bash脚本代码:

#!/bin/bash

cur_pwd=$PWD

input_name=input
output_name=output
ext_name=txt
problem_conf=problem.conf
uoj_data_dir=/mnt/y/opt-uoj.tpu01yzx.me/uoj_data/upload/

echo "UOJ_DATA_DIR: $uoj_data_dir"

#sudo mkdir /mnt/y
#sudo mount -t drvfs Y: /mnt/y

i=0
while [ true ]; do
  i=$(($i + 1));
  if [ ! -d "$uoj_data_dir/$i" ]; then
	break;
  fi;
done;
problem_id=$(($i - 1));

echo "Found Problem ID: $problem_id"

(
cd $uoj_data_dir/$problem_id ;
std_src=$(ls std*.cpp | head -n 1) 
if [ ! -e $std_src ]; then
	echo "No Standard Source File was Found."
	exit;
fi;
exe_name=main_$problem_id
gcc $std_src -Wall -o $exe_name
if [ ! -e "$exe_name" ]; then
	echo "Compile Standard Source Failed."
	exit;
fi;
for p in "ex_"  "" ; do
	echo "p: $p"
	i=0
	while [ true ]; do
	  i=$(($i + 1));
	  input_file=${p}${input_name}${i}.${ext_name}
	  if [ ! -e "$input_file" ]; then
		break;
	  fi;
	  echo "$input_file is found."
	  output_file=${p}${output_name}${i}.${ext_name}
	  ./$exe_name < "$input_file" > "$output_file"
	  if [ ! -e "$output_file" ]; then
		echo "$output_file is NOT generated. "
	  else
		echo "$output_file is generated. "
	  fi;	  
	done;
	i=$(($i - 1));
	echo "Total $i tests."
	conf_key="n_${p}tests"
	sed -E 's/'"${conf_key}"'[[:blank:]]+[[:digit:]]+/'"${conf_key} ${i}"'/' $problem_conf > ${problem_conf}.new
	rm -f $problem_conf
	mv ${problem_conf}.new $problem_conf
done;
rm -f $exe_name
cat $problem_conf
)

AKS素性检测算法的C语言实现

按道理说这个算法提出之后,应该是有很多语言的实现版本。但是对于多项式的方幂运算,C语言版本总感觉缺少点什么。以前在其他地方见过,但多项式方幂的实现算法复杂度较高。因此自己也实现一个版本。但目前遇到一个问题,就是64bit的两个整数相乘,会溢出。虽然是在模n(也是64bit的)下运算的,但为了避免溢出,好好的乘法非要改用加法实现。希望在这方面可以有改进的地方( Mul64Mod )。

备注:2022年11月1日修订。根据文献[3]的提示,GNU G++17可以使用 unsigned __int128 数据类型,虽然我的编译器( g++.exe (MinGW-W64 x86_64-ucrt-posix-seh, built by Brecht Sanders) 12.2.0 )提示使用的数据类型应该为 __uint128_t 。但起码目前模乘法的速度问题算是基本解决了。另外,我将当前版本保存了一份在网上:https://onlinegdb.com/dFtGoQgL6 或者 https://gist.github.com/tpu01yzx/172c65d3003bb3a09a941e69bc6c370b

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <memory.h>
#include <math.h>

#define N 100
#define MAX_FACTORS 32
#define MAXR 320

typedef unsigned long long int uint64;
typedef unsigned int uint32;
typedef unsigned char uint8;

uint64 gcd(uint64 a, uint64 b) {
    uint64 c = a;
    while(b) {
        c = a % b;
        a = b;
        b = c;
    }
    return a;
}

uint8 BitCount(uint64 n) {
    uint8 ans = 0;
    while(n) {
        n>>=1;
        ans++;
    }
    return ans;
}

uint32 SquareRoot(uint64 x) {
    if(x < (1ULL<<32)) {
        return (uint32)sqrt((uint32)x);
    }
    uint8 logx = BitCount(x);    
    uint32 l = pow(2.0, (double)(logx-1) / 2);
    uint32 r = pow(2.0, (double)(logx) / 2);
    uint32 m = l;
    uint64 m2 = x;

    while(l <= r) {        
        m = (l + r ) / 2;        
        m2 = m * m;
        
        if(m2 == x) return m;
        if(m2 < x) {
            l = m + 1;
        } else {
            r = m - 1;
        }
    }
    return m;
}

uint64 Power(uint32 a, uint8 k) {
    if(k == 0) return 1;

    uint64 ans = 1;
    uint64 a2 = a;
    while(k > 1) {
        if(k & 0x01) {
            ans *= a2;
        }
        a2 = a2 * a2;
        k>>=1;
    }
    ans *= a2;
    return ans;
}

uint32 PowerMod(uint32 a, uint8 k, uint32 mod) {
    if(k == 0) return 1;

    uint64 ans = 1;
    uint64 a2 = a % mod;    
    while(k > 1) {
        if(k & 0x01) {
            ans = (ans * a2) % mod;            
        }
        a2 = (a2 * a2) % mod;        
        k>>=1;
    }
    ans = (ans * a2) % mod; 
    return (uint32)ans;
}

uint64 Mul64Mod(uint64 a, uint64 b, uint64 mod) {
    return (__uint128_t)a * b % mod;
}

void MulPoly(uint64 *p1, uint64 *p2, uint64 n, uint32 r) {
    uint64 ans[MAXR];
    int i, j;

    memset(ans, 0, sizeof(uint64) * r);
    for(i = 0; i < r; i++) {
        for(j = 0; j <= i; j++) {
            ans[i] += Mul64Mod(p1[j], p2[i - j], n);
            if(ans[i] >= n) ans[i] -= n;
        }
        for(j = i + 1; j < r; j++) {
            ans[i] += Mul64Mod(p1[j], p2[r + i - j], n);
            if(ans[i] >= n) ans[i] -= n;
        }        
    }    
    memcpy(p1, ans, sizeof(uint64) * r);
}

void PowerPoly(uint64 *coff, uint64 n, uint32 r) {
    if(n == 0) {
        memset(coff, 0, sizeof(uint64) * r);
        coff[0] = 1ULL;
        return;
    }
    uint64 n0 = n;
    uint64 ans[MAXR];
    uint64 coff2[MAXR];
    memset(ans, 0, sizeof(uint64) * r);    ans[0] = 1ULL; 
    memcpy(coff2, coff, sizeof(uint64) * r);

    while(n > 1) {
        if(n & 0x01) {
            MulPoly(ans, coff2, n0, r);
        }
        MulPoly(coff2, coff2, n0, r);
        n>>=1;
    }
    MulPoly(ans, coff2, n0, r);
    
    memcpy(coff, ans, sizeof(uint64) * r);
}

int CheckPoly(uint64 *p, uint64 a, uint64 n, uint32 r) {
    uint64 n0 = n % r;
    uint32 i;
    if(p[0] != a) return 0;    
    for(i = 1; i < n0; i++) {
        if(p[i] != 0) return 0;
    }
    if(p[n0] != 1ULL) return 0;
    for(i = n0 + 1; i < r; i++) {
        if(p[i] != 0) return 0;
    }
    return 1;
}

uint32 PerfectRoot(uint8 a, uint64 n, uint8 logn) {    
    if(a == 1) return n;
    uint32 l = pow(2.0, (double)(logn-1) / a);;
    uint32 r = pow(2.0, ((double)(logn) / a));
    uint32 m;
    uint64 mp;
    while(l <= r) {
        m = (l + r) / 2;
        mp = Power(m, a);
        if(mp == n) return m;
        if(mp < n) {
            l = m + 1;
        } else {
            r = m - 1;
        }
    }
    return 0;
}

int IsPower(uint64 n) {
    uint8 i, j;
    uint8 cnt = BitCount(n);
    for(i = 2; i < cnt; i++) {
        if(PerfectRoot(i, n, cnt)) return 1;
    }
    return 0;
}

uint8 SmallFactors(uint32 r, uint32 *factors, uint32 *exponents) {
  uint32 i;
  uint32 sqrtr = SquareRoot(r);
  uint8 p = 0;
  for(i = 2; i <= sqrtr; i++) {
      if(r % i == 0) {
          factors[p] = i;
          exponents[p] = 0;
          while(r % i == 0) {
              r /= i;
              exponents[p]++;
          }
          p++;
          sqrtr = SquareRoot(r);
      }
  }
  if(r > 1) {
      factors[p] = r;
      exponents[p] = 1;
      p++;
  }
  return p;
}

uint32 SmallOrder(uint32 n, uint32 r) {
  uint32 i;
  uint32 factors[MAX_FACTORS];
  uint32 exponents[MAX_FACTORS];
  uint32 p;    
  uint32 ans;
  
  ans = 1;
  p = SmallFactors(r, factors, exponents);
  for(i = 0; i < p; i++) {
    if(exponents[i] > 1) {
      ans *= Power(factors[i], exponents[i] - 1);    
    }
    ans *= factors[i] - 1;
  }
  
  p = SmallFactors(ans, factors, exponents);
  for(i = 0; i < p; i++) {
    while(ans % factors[i] == 0) {
      if(PowerMod(n, ans, r) == 1) {
        ans /= factors[i];
      } else {
        break;
      }
    }
    if(ans % factors[i] == 0) {
      ans *= factors[i];
    }
  }
  return ans;
}


uint32 FindR(uint64 n) {
    uint32 r, k;    
    uint8 logn = BitCount(n);
    uint32 maxr = Power(logn, 5);
    uint32 maxk = Power(logn, 2);
    if(maxr < 3) maxr = 3;    
    for(r = 2; r <= maxr; r++) {
        if(gcd(n, r) > 1) continue;   
        k = SmallOrder(n % r, r);
        if(k > maxk) break;
    }
    return r;
}


uint32 SmallPhi(uint32 r) {
    uint32 ans;
    uint32 i;    
    uint32 factors[MAX_FACTORS];
    uint32 exponents[MAX_FACTORS];
    uint32 p;    
    p = SmallFactors(r, factors, exponents);
    ans = 1;
    for(i = 0; i < p; i++) {
        if(exponents[i] > 1) {
          ans *= Power(factors[i], exponents[i] - 1);    
        }
        ans *= factors[i] - 1;
    }
    return ans;
}

int IsPrimeAKS(uint64 n) {
    uint64 i = 0;
    uint32 r = 0;
    uint64 t = 0;
    uint32 logn = 0;
    uint64 maxa = 0;
    uint64 poly[MAXR];

    if(IsPower(n)) return 0;    

    r = FindR(n);

    for(i = 2; i <= r; i++) {
        t = gcd(n, i);
        if(t > 1 && t < n) return 0;
    }

    if(n <= r) return 1;

    logn = BitCount(n);
    maxa = ((uint64)logn) * SquareRoot(SmallPhi(r));
    if(maxa >= n) maxa = n - 1;


    for(i = 1; i <= maxa; i++) {      
        memset(poly, 0, sizeof(uint64) * r);
        poly[0] = i; poly[1] = 1;                
        PowerPoly(poly, n, r);
        if(!CheckPoly(poly, i, n, r)) return 0;
    }

    return 1;
}


int main()
{  
    uint64 n;
    while(scanf("%"SCNu64, &n) != EOF) {
        printf("%s\n", IsPrimeAKS(n) ? "Yes" : "No");
    }
    return 0;
}


参考文献:

MathType和Office整合的方法

本文主要讨论的是MathType和Office正常使用之后,由于某些其他原因导致两者之间的集成出现各种问题的应对方法。

MathType的版本建议采用6.9b,高于这个版本的似乎不支持Office 2003,低于这个版本的似乎不支持Office 2016。而我的电脑上恰好都安装了Office 2003和Office 2016,所以只能选择MathType 6.9b这个版本。

零、相关约定
为了描述方便,对几个常用的文件夹做个变量:

  • MT_HOME表示MathType的安装路径,例如我的电脑上是 E:\Green\MathType
  • O2003_PG_DIR表示Office 2003的主目录(不是安装目录),例如我的电脑上是 C:\Program Files (x86)\Microsoft Office\OFFICE11\
  • O2016_PG_DIR表示Office 2016的主目录(不是安装目录),例如我的电脑上是 C:\Program Files (x86)\Microsoft Office\OFFICE16\
  • O_USER_DIR表示用户目录下的Office配置目录,例如我的电脑上是 C:\Users\{UserName}\AppData\Roaming\Microsoft\Word\ , 其中 {UserName} 表示的是当前系统的登陆用户名。
  • OBITS表示Office的版本,这里特指32位或者64位。

一、MathPage的整合
MathType.wll其实是dll文件,可以被Office加载,这个文件位于 $MT_HOME\MathPage\$OBITS\MathPage.wll 。主要用于Office界面中插入显示MathType的工具界面。
对于Office 2003,把这个文件复制到 $O2003_PG_DIR ;对于Office 2016,似乎并不需要。

二、MathType Commands的整合
MathType Commands文件其实是Word的宏文件。对于Office 2003来说,文件名为 MathType Commands 6 For Word.dot (似乎不在安装目录中,我是从其他地方复制过来的,在文章的附件里有打包。),对于Office 2016来说,这个文件在 $MT_HOME\Office Support\$OBITS\MathType Commands 6 For Word 2016.dotm 。整合的时候,复制到 $O_USER_DIR\STARTUP

三、后续
经过一段时间使用后,为了方便,Office 2016也安装了32位的版本(Office 2003只有32位的版本),这就导致Office 2016会加载到为Office 2013准备的MathType Commands文件,从而引起冲突。具体的症状就是无法使用Ctrl+C和Ctrl+V复制粘帖功能。解决办法是,把 $MT_HOME\MathPage\$OBITS\MathPage.wll 也复制一份到$O2016_PG_DIR , 用来代替之前为Office 2016准备的MathType Commands文件(如果有,则删除 $O_USER_DIR\STARTUP\MathType Commands 6 For Word 2016.dotm )。

注:如果复制到其他加载目录中,可能会出现各种警告,但也不影响使用。本文附带一个附件以备不时之需:MathType和Office整合的所需文件打包

两种纯文本终端行下”录屏”的方法

方法一: script & scriptreplay
https://aws.amazon.com/cn/premiumsupport/knowledge-center/record-linux-terminal-or-ssh-session/
记录开始: script -a -t timingfile.txt typescript.txt
记录结束: exit
记录重放: scriptreplay --timing=timingfile.txt typescript.txt

方法二: ttyrec & ttyrec2video
https://github.com/jwodder/ttyrec2video
安装: sudo apt-get install ttyrec ffmpeg python3-pip
记录开始: ttyrec record.log
记录结束: exit
记录重放: ttyplay record.log

记录转视频需要用到 ttyrec2video
安装: sudo python3 -m pip install git+https://github.com/jwodder/ttyrec2video.git
修复Bug: sudo pip3 install imageio==2.4.1
转换: ttyrec2video record.log record.mp4

注:pip默认的源在国外很慢, 可以设置使用清华大学的源
sudo pip3 config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple

继续教育自动刷视频的脚本

这个脚本需要使用Firefox浏览器,安装TamperMonkey插件,然后在插件中安装如下脚本(或者从这个URL下载:https://raw.githubusercontent.com/tpu01yzx/AutoPlayVideo_jsglpt/main/AutoPlayVideo_jsglpt.js )。注意:自动播放视频可能会被Firefox禁止,请在地址栏的左边小图标中启用自动播放视频权限。

继续教育里的这个人工智能的课讲得一般,反正我是有认真看完的啦。这个脚本主要做了三件事情:
1)禁用看视频中途出现的回答问题动作,实现不间断播放视频。
2)定时刷新播放器状态,实现自动播放。
3)定时检测看视频状态,如果已经完成,则自动转到下一个视频的页面。

// ==UserScript==
// @name         继续教育自动刷视频
// @namespace    http://tampermonkey.net/
// @version      0.2
// @description  auto play videos!
// @author       tpu01yzx
// @match        https://jsglpt.gdedu.gov.cn/ncts/*
// @icon         https://www.google.com/s2/favicons?domain=gdedu.gov.cn
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    //var ajaxHook = function() {
    //    var $ = $ || window.$;
    //    $.ajaxSetup({beforeSend: function(xhr, settings) {
    //        //fix a error in updateLastViewTime for the old version.
    //        settings.url = settings.url.replace("/nctsa_", "/ncts/a_");
    //    }});
    //};
    //setTimeout(ajaxHook,1000);

    var main_func = function() {
        var $ = $ || window.$;

        var times = $('input[id^="time_"]');
        if(times && times.length > 0) {
            times.each(function(){ this.remove(); });
        }

        var player = player || window.player;
        var isComplete = isComplete || window.isComplete;

        if(isComplete && $('a[class="btn next crt"]')) {
            $('a[class="btn next crt"]').click();
        }
        if(player && player.V && player.loaded && !player.V.ended) {
            if(player.V.paused) player.videoPlay();
        }
        setTimeout(main_func, 1000);
    }
    if(window.player) setTimeout(main_func,1000);

    // Your code here...
})();

那个充满激情的岁月

那些年,我们一些为了BBS(网上论坛)而疯狂。为此,曾经刷在线时间(类似QQ刷太阳等级),动手在服务器上写了一个程序。作为留念,现决定低调开源。

#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <time.h>

#include <sys/stat.h>
#include <signal.h>
#include <unistd.h>
#include <fcntl.h>
#include <getopt.h>
//#include <iconv.h>

#define LOCKFILE "/var/run/bbs4gzhu.pid"

#define LOCKMODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)


int                 lockfile;                  /* 锁文件的描述字 */
int 		    exit_flag = 0;


#define BUFFER_SIZE	409600
#define FORMHASH_SIZE	16
#define USERNAME_SIZE	128
#define PASSWORD_SIZE	128
#define SID_SIZE	64
#define AUTH_SIZE	128

int		    background = 0;
int 		    interval = 15;
char 		   *cookiepath = "";
char 		   username[USERNAME_SIZE] = "";
char 		   password[PASSWORD_SIZE] = "";
char		   *host = "bbs.gzhu.edu.cn";
short 		   port = 80;


static void
flock_reg ()
{
    char buf[16];
    struct flock fl;
    fl.l_start = 0;
    fl.l_whence = SEEK_SET;
    fl.l_len = 0;
    fl.l_type = F_WRLCK;
    fl.l_pid = getpid();
 
    //阻塞式的加锁
    if (fcntl (lockfile, F_SETLKW, &fl) < 0){
        perror ("fcntl_reg");
        exit(EXIT_FAILURE);
    }
 
    //把pid写入锁文件
    ftruncate (lockfile, 0);    
    sprintf (buf, "%ld", (long)getpid());
    write (lockfile, buf, strlen(buf) + 1);
}

void
daemon_init(void)
{
	pid_t	pid;
    	int     fd0;

	if ( (pid = fork()) < 0)
	    perror ("Fork");
	else if (pid != 0) {
        	fprintf(stdout, "bbs4gzhu&&Info: Forked background with PID: [%d]\n\n", pid);
		exit(EXIT_SUCCESS);
    	}
	setsid();	/* become session leader */
	chdir("/tmp");		/* change working directory */
	umask(0);		/* clear our file mode creation mask */
    flock_reg ();

    fd0 = open ("/dev/null", O_RDWR);
    dup2 (fd0, STDIN_FILENO);
    dup2 (fd0, STDERR_FILENO);
    dup2 (fd0, STDOUT_FILENO);
    close (fd0);
}


static int 
is_running()
{
    struct flock fl;
    fl.l_start = 0;
    fl.l_whence = SEEK_SET;
    fl.l_len = 0;
    fl.l_type = F_WRLCK;
 
    //尝试获得文件锁
    if (fcntl (lockfile, F_GETLK, &fl) < 0){
        perror ("fcntl_get");
        exit(EXIT_FAILURE);
    }

    if (exit_flag) {
        if (fl.l_type != F_UNLCK) {
            if ( kill (fl.l_pid, SIGINT) == -1 )
            perror("kill");
            fprintf (stdout, "bbs4gzhu&&Info: Kill Signal Sent to PID %d.\n", fl.l_pid);
        }
        else 
            fprintf (stderr, "bbs4gzhu&&Info: Program not running.\n");
        exit (EXIT_FAILURE);
    }


    //没有锁,则给文件加锁,否则返回锁着文件的进程pid
    if (fl.l_type == F_UNLCK) {
        flock_reg ();
        return 0;
    }

    return fl.l_pid;
}
static void
signal_interrupted (int signo)
{
    exit (EXIT_SUCCESS);
    exit_flag = 1;
    fprintf(stdout,"\nbbs4gzhu&&Info: Interrupted. \n");
}
static void show_usage()
{
	printf("auto online for bbs.gzhu.edu.cn \n\
options: \n \
	-b --background. run in background. mostly this is for service mode. \n\
	-e --exit. quit the running program in background \n\
	-i --interval value(in second). interval time between online request. default value is 15 seconds. \n\
	-h --help. show this usage message. \n\
	-c --cookiepath. specifies the file containing the cookies for online request. \n\
	-u --username. username for login in the bbs. \n\
	-p --password. md5 of the password, used for login in the bbs. \n\
	--host. host for auto online. default value is \"bbs.gzhu.edu.cn\" \n\
	--port. the port with site. default value is 80. \n");


}

static void 
init_arguments(int *argc, char ***argv)
{
    /* Option struct for progrm run arguments */
    static struct option long_options[] =
        {
        {"background",  no_argument,        &background,    'b'},       
        {"exit",      no_argument,  &exit_flag,              'e'},
        {"interval",         required_argument,  &interval,              'i'},
        {"help",         no_argument,  0,              'h'},
        {"cookiepath",         required_argument,  NULL,              'c'},
	{"username", required_argument, NULL, 'u'},
	{"password", required_argument, NULL, 'p'},
	{"host", required_argument, NULL, 2},
	{"port", required_argument, NULL, 1},
        {0, 0, 0, 0}
        };

    int c;
    while (1) {

        /* getopt_long stores the option index here. */
        int option_index = 0;
        c = getopt_long ((*argc), (*argv), "bei:hc:u:p:",
                        long_options, &option_index);
        if (c == -1)
            break;
        switch (c) {
            case 0:
               break;
            case 'b':
                background = 1;
                break;
            case 'e':
                exit_flag = 1;
                break;
	    case 'i':
                interval = atoi(optarg);
                break;
            case 'h':
                show_usage();
                exit(EXIT_SUCCESS);
                break;
	    case 'c':
		cookiepath = optarg;
		break;
	    case 'u':
		strncpy(username, optarg, USERNAME_SIZE);
		break;
	    case 'p':
		strncpy(password, optarg, PASSWORD_SIZE);
		break;
	    case 2:
		host = optarg;
		break;
	    case 1:
		port = atoi(optarg);
		break;
            case '?':               
                exit(EXIT_FAILURE);
                break;
            default:
                fprintf (stderr,"Unknown option character `\\x%x'.\n", c);
                exit(EXIT_FAILURE);
        }
    }
}

void PANIC(char *msg);
#define PANIC(msg)  {perror(msg); abort();}
int getitem(const char *str, char *buffer, const int size, const char *start, const char end);

int tcp_connect(const char *host, const short port);
struct sockaddr_in getaddr(const char *host, const short port);
void loadcookies(const char *filename, char *buffer, const int size);
int 
code_convert(char *from_charset, char *to_charset,
             char *inbuf, size_t inlen, char *outbuf, size_t outlen);

int parse_username(const char *str, char *buffer, const int size);
int parse_formhash(const char *str, char *buffer, const int size);
int parse_sid(const char *str, char *buffer, const int size);
int parse_auth(const char *str, char *buffer, const int size);
int parse_parse_cookies(const char *str, char *buffer, const int size);
int parse_welcome_msg(const char *str, char *buffer, const int size);
int parse_return_msg(const char *str, char *buffer, const int size);
int parse_error_msg(const char *str, char *buffer, const int size);

int login(const char *username, const char *password, char *cookies, const int size);
int send_request(const int sockfd, const char *url, const char *header, const char *data, char *buffer, const int size);
int check_http(const char *response, const int size);
int online(const char *cookies);
char *gettime();

int
main(int argc, char *argv[])
{
	int ins_pid;
	char cookies[BUFFER_SIZE];

	init_arguments(&argc, &argv);

	lockfile = open (LOCKFILE, O_RDWR | O_CREAT , LOCKMODE);
	if (lockfile < 0){
		perror ("Lockfile");
		exit(EXIT_FAILURE);
	}

	if ( (ins_pid = is_running()) ) {
		fprintf(stderr,"bbs4gzhu@@ERROR: Program already "
				    "running with PID %d\n", ins_pid);
		exit(EXIT_SUCCESS);
	}

	signal (SIGINT, signal_interrupted);
	signal (SIGTERM, signal_interrupted);

	bzero(cookies, sizeof(cookies));
	if(strlen(cookiepath) > 0) {
		loadcookies(cookiepath, cookies, sizeof(cookies));
		if(strlen(username) <= 0) {
			if(parse_username(cookies, username, sizeof(username)) <= 0) {
				if(parse_sid(cookies, username, sizeof(username)) <= 0) {
					strcpy(username, "unknown");
				}
			}
		}
	} else {
		if(strlen(username) <= 0) {
			strcpy(username, "nobody");
		}
	}

	printf("current username: %s \n", username);

	if(background)    daemon_init();

	while(1) {
		printf("%s logging...", gettime());
		fflush(stdout);
		if(!login(username, password, cookies, sizeof(cookies))) {
			sleep(interval);
			continue;
		}
		printf("\n");
		while(online(cookies)) {
			printf("%s online...\r", gettime()); fflush(stdout);
			sleep(interval);
		}
		printf("%s offline...it will auto retrying!\n", gettime());
	}

	return 0;
}/* ----------  end of function main  ---------- */
char *gettime()
{
	static char str[64];
	struct tm *local;
	time_t t;
	t = time(NULL);
	local=localtime(&t);
	sprintf(str, "%02d:%02d:%02d", local->tm_hour, local->tm_min, local->tm_sec);
	return str;
}
int check_http(const char *response, const int size)
{
	char buffer[16];
	if(size <= 16) return 0;
	if(strstr(response, "HTTP/1.1 200 OK\r\n") == NULL) {
		strncpy(buffer, response, 15);
		buffer[15] = 0;
		printf("%s bad status:%s\n", username, buffer);
		return 0;
	}
	return 1;
}

void loadcookies(const char *filename, char *buffer, const int size)
{
	int bytes_read;
	FILE *fd = fopen(filename, "r");
	if(fd == NULL) {
		PANIC("loadcookies");
	}
	bytes_read = fread(buffer, 1, size, fd);
	buffer[bytes_read - 1] = 0;
	
	while(bytes_read--) {
		if(buffer[bytes_read] == '\r') buffer[bytes_read] = ' ';
		if(buffer[bytes_read] == '\n') buffer[bytes_read] = ' ';
	}
	
	fclose(fd);
}

int send_request(const int sockfd, const char *url, const char *header, const char *data, char *buffer, const int size) 
{
	int bytes_read = 0;
	char request_buffer[BUFFER_SIZE];
	if(data != NULL) {
		sprintf(request_buffer, "POST %s HTTP/1.1\r\nHost: %s:%d\r\nReferer: http://%s\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: %d\r\n%s\r\n\r\n%s", url, host, port, host, strlen(data), header, data);
	} else {
		sprintf(request_buffer, "GET %s HTTP/1.1\r\nHost: %s:%d\r\nReferer: http://%s\r\n%s\r\n", url, host, port, host, header);
	}

	//printf("%s\n", request_buffer);

	/* 发送数据 */
	send(sockfd, request_buffer, strlen(request_buffer), 0);

	/* 接收缓存 */
	bzero(buffer, sizeof(size));

	/* 接收 */
	bytes_read = recv(sockfd, buffer, size, 0);

	//printf("%s\n", buffer);

	return bytes_read;
}

int login(const char *username, const char *password, char *cookies, const int size) 
{
	int sockfd;
	int bytes_read;
	char buffer[BUFFER_SIZE];
	char header[BUFFER_SIZE];
	char formhash[FORMHASH_SIZE];
	char formdata[BUFFER_SIZE];
	char sid[SID_SIZE];
	char auth[AUTH_SIZE];
	char msg[BUFFER_SIZE];

	/* 先获取登录页面 */
	sockfd = tcp_connect(host, port);
	bytes_read = send_request(sockfd, "/logging.php?action=login&inajax=1", "", NULL, buffer, sizeof(buffer));	
	close(sockfd);
	if(check_http(buffer, bytes_read) == 0) return 0;
//	printf("%s\n", buffer);
	
	/* 若被列入黑名单,则等待3分钟后再试 */
	if(strlen(strstr(buffer, "\r\n\r\n")+4) <= 120) {//这个值一般在99左右。
		bytes_read = parse_error_msg(buffer, msg, sizeof(msg));
		if(bytes_read > 0 && strstr(msg, "\n") == NULL) {
			printf("Error:%s . Try 15m later..\r", msg);	
		} else {
			printf("Error:unknown. Try 3 minute later..\r", msg);
		}
		fflush(stdout);
		sleep(3*60);
		return 0;
	}
	/* 解析formhash */
	bytes_read = parse_formhash(buffer, formhash, sizeof(formhash));
	if(bytes_read <= 0) return 0;

	/* 解析SID */
	bytes_read = parse_sid(buffer, sid, sizeof(sid));
	if(bytes_read <= 0) return 0;

	strcat(cookies, "hLR_sid=");	strcat(cookies, sid);	strcat(cookies, ";");

	/* 构造header */
	sprintf(header, "Cookie: %s\r\n", cookies);

	/* 构造登录表单 */
	sprintf(formdata, "formhash=%s&loginfield=username&username=%s&password=%s&questionid=0&answer=&cookietime=2592000", formhash, username, password);

//	printf("%s %s\n", header, formdata);
	
	/* 提交登录请求 */
	sockfd = tcp_connect(host, port);
	bytes_read = send_request(sockfd, "/logging.php?action=login&loginsubmit=yes&inajax=1", header, formdata, buffer, sizeof(buffer));
	close(sockfd);
	if(check_http(buffer, bytes_read) == 0) return 0;

	/* 解析欢迎消息 */
	bytes_read = parse_welcome_msg(buffer, msg, sizeof(msg));
	if(bytes_read <= 0)  {
		/* 解析登录返回信息 */
		bytes_read = parse_return_msg(buffer, msg, sizeof(msg));
		if(bytes_read > 0) printf("Failed Info:%s\r", msg);
		return 0;
	}
	printf("Login Info:%s\r", msg);
	fflush(stdout);

	/* 解析auth */
	bytes_read = parse_auth(buffer, auth, sizeof(auth));
	if(bytes_read <= 0) return 0;	
	strcat(cookies, "hLR_auth=");	strcat(cookies, auth);	strcat(cookies, ";");

	/* 有效时间 */
	strcat(cookies, "hLR_cookietime=2592000;");

	return strlen(cookies);
}

int online(const char *cookies)
{
	int sockfd;
	int bytes_read;
	char buffer[BUFFER_SIZE];
	char header[BUFFER_SIZE];

	/* 构造header */
	sprintf(header, "Cookie: %s\r\n", cookies);

	/* 刷新页面保持在线 */
	sockfd = tcp_connect(host, port);
	bytes_read = send_request(sockfd, "/search.php", header, NULL, buffer, sizeof(buffer));	
	close(sockfd);
	if(check_http(buffer, bytes_read) == 0) return 0;
	
	/* 检测用户凭据是否到期 */
	if(strstr(buffer, "logging.php?action=logout") == NULL) return 0;

	return 1;
}

int parse_error_msg(const char *str, char *buffer, const int size)
{
	return	getitem(str, buffer, size, "![CDATA[", ']');
}

int parse_username(const char *str, char *buffer, const int size)
{
	return	getitem(str, buffer, size, "uchome_loginuser=", ';');
}

int parse_formhash(const char *str, char *buffer, const int size)
{
	return	getitem(str, buffer, size, "name=\"formhash\" value=\"", '\"');
}

int parse_sid(const char *str, char *buffer, const int size)
{
	return	getitem(str, buffer, size, "hLR_sid=", ';');
}

int parse_auth(const char *str, char *buffer, const int size)
{
	return	getitem(str, buffer, size, "hLR_auth=", ';');
}

int parse_cookies(const char *str, char *buffer, const int size)
{
	return	getitem(str, buffer, size, "Set-Cookie: ", ';');	
}

int parse_welcome_msg(const char *str, char *buffer, const int size)
{
	return getitem(str, buffer, size, "$('messageleft').innerHTML = '", '\'');	
}


int parse_return_msg(const char *str, char *buffer, const int size)
{
	return getitem(str, buffer, size, "<em id=\"returnmessage\">", '<');	
}


int getitem(const char *str, char *buffer, const int size, const char *start, const char end)
{
	int i;
	char *p = strstr(str, start);
	if(p == NULL) return 0;

	for(i = 0, p+= strlen(start); p[i] &&  i < (size - 1); i++) {
		if(p[i] == end) break;
		buffer[i] = p[i];
	}
	buffer[i] = '\0';
	return i;
}



struct sockaddr_in getaddr(const char *host, const short port)
{
    struct sockaddr_in sin;
    struct hostent *hosts = NULL;

    bzero(&sin, sizeof(struct sockaddr_in));
    sin.sin_family = AF_INET;
    sin.sin_port = htons(port);
    if(inet_addr(host) == INADDR_NONE) {
        hosts = gethostbyname(host);
	if(hosts != NULL) {
	    sin.sin_addr = *((struct in_addr*)hosts->h_addr);
	}
    } else {
	sin.sin_addr.s_addr = inet_addr(host);
    }
    return sin;
}

int
tcp_connect(const char *host, const short port)
{

    int     sockfd;
    struct sockaddr_in endpoint;

    endpoint = getaddr(host, port);
  
    sockfd = socket(AF_INET, SOCK_STREAM, 0);

    if (sockfd < 0) return 0;

    if (connect(sockfd, (struct sockaddr*)&endpoint, sizeof(struct sockaddr_in)) != 0) {
	close(sockfd); 
	return 0;
    }

    return (sockfd);
}

/* 
 * ===  FUNCTION  ======================================================================
 *         Name:  code_convert
 *  Description:  字符串编码转换
 * =====================================================================================
 */
int 
code_convert(char *from_charset, char *to_charset,
             char *inbuf, size_t inlen, char *outbuf, size_t outlen)
{
    memcpy(outbuf, inbuf, inlen < outlen ? inlen : outlen);
/*
    iconv_t cd;

    cd = iconv_open(to_charset,from_charset);

    if (cd==0) 
      return -1;
    memset(outbuf,0,outlen);

    if (iconv (cd, &inbuf, &inlen, &outbuf, &outlen)==-1) 
      return -1;
    iconv_close(cd);
*/
    return 0;
}