Author Archive

Карточная игра «Верю — не верю»

В 2003 году первой моей курсовой по программированию была карточная игра "Верю - не верю". Эта игра мне очень нравилась с детства. Впервый раз я увидел как в нее играли "старшаки" на соседней улице, было очень весело. Они играли колодой из 52 карт + 2 джокера, играли очень профессионально, с одного захода куча проходила несколько кругов. Правила можно посмотреть в Википедии Я сделал упрощенную версию из 36 карта без джокеров. Игра написана на Visual Basic 6.0 более 10 лет назад и с тех пор не поддерживалась. Выкладывают приложение как есть. В Windows 8 местами появилась проблема с кодировкой. В игре три соперника: вы и два компьютера, причем каждый играет только за себя. Что очень важно: компьютер не смотрит ваши карты! Скачать Верю-не верю Сперва появится окно, где нужно указать свое имя: 01 login Далее откроется главное окно: 02 main page На рисунке изображена ситуация, когда ход дошел до вас, и вы можете либо доложить карты, либо попытать угадать обманул ли вас предыдущий игрок. Выкладываю также исходный код. Ценности он, может, ни какой и не представляет, но все же... Скачать исходный код

Перебор всех подмножеств заданного множества (Java)

Пусть дано множество, состоящее из четырех элементов: {a,b,c,d}. Необходимо перебрать все возможные подмножества данного множества: 1) {} - пустое множество 2) {a} 3) {b} 4) {a,b} 5) {c} 6) {a,c} 7) {b,c} 8) {a,b,c} 9) {d} 10) {a,d} 11) {b,d} 12) {a,b,d} 13) {c,d} 14) {a,c,d} 15) {b,c,d} 16) {a,b,c,d} Причем подмножества {a,b} и {b,a} считаются одним и тем же подмножеством. Данную задачу будем решать с использованием битовых масок и битовых операций. Сразу приведу реализацию:
char arr[] = new char[]{'a','b','c','d'};
int N = arr.length;
for (int mask = 0; mask < (1 << N); mask++) {//перебор масок			
	for (int j = 0; j < N; j++) {//перебор индексов массива
		if((mask & (1 << j)) != 0){//поиск индекса в маске
			System.out.print(arr[j] + " ");//вывод элемента
		}
	}
	System.out.println();//перевод строки для вывод следующего подмножества
}
А теперь пояснения. 1 << N - побитовый сдвиг единицы на N позиций влево. В двоичном виде единица выглядит так 00000001. В нашем случае N = 4. После сдвига на 4 позиции влево появится новое число, двоичный вид которого 00010000. Теперь, если вычесть из этого числа единицу получим: 00001111. Если опустить ведущие нули, то получим 1111. Четыре единицы - это состояние, когда в подмножество попадают все элементы, 0000 - пустое множество, 1010 - подмножество состоит из первого и третьего элемента множества (нумерация с нуля, отсчет ведется справа) и т.д. Т.е. мы перебираем числа, двоичное представление которых от 0000 до 1111. После того как мы получили маску (mask), необходимо узнать в каких позициях стоят единицы. Проверять будем следующим образом. Например, на каком-то шаге цикла программы маска равна 1100, мы перебираем все позиции путем сдвига единицы: 0001, 0010, 0100 и 1000. Для проверки воспользуемся операцией побитового И (если в одинаковых позициях стоят единицы, то результат единица, иначе ноль). В Java обозначается как & В нашем случае: 1100 & 0001 = 0000 1100 & 0010 = 0000 1100 & 0100 = 0100 1100 & 1000 = 1000 Т.е. если в итоге получилось число отличное от нуля, то включаем элемент в множество. 0100 - включаем в множество элемент с индексом 2 1000 - включаем в множество элемент с индексом 3 Нумерация с нуля и справа. Результат работы программы (первая строка пустая - это пустое множество):

a 
b 
a b 
c 
a c 
b c 
a b c 
d 
a d 
b d 
a b d 
c d 
a c d 
b c d 
a b c d 
В данной реализации мы хранили маски в типе int. (1 << 30) равно 1 073 741 824 Безопасное значение N для типа int: 30. Свыше 30 будет переполнение переменных типа int, поэтому нужно использовать long. При N > 30 перебор будет ощутимо все медленнее и медленнее. Если будете делать реализацию с long, то при сдвиге единицы нужно писать так:
1L << j
Т.е. нужно к единице приписать L, и тогда результат операции будет long, в противном случае будет int с переполнением.

Музыка для программирования

Музыка для программирования || Музыка для кодинга || Хакерская музыка || Программистский транс
  1. Blue_Stahli_-_Contre_Strike-CS-GO.mp3
  2. DJ-Velocity-Exposure.mp3
  3. dj_slyter_-_kazantip.mp3
  4. glide_-_extasy_(mf_remix).mp3
  5. KaZantip.mp3
  6. Na_igre_2_prodoljenie_-_Gamers.mp3
  7. nobody.one-Trapper.mp3
  8. Quake3track2.mp3
  9. Quake3track5.mp3
  10. RedAlertTrack9.mp3
  11. The_Prodigy_-_Youll_Be_Under_My_Wheels.mp3
  12. TheAlgorithm-Null.mp3
  13. Vibrasphere-ForestFuel.mp3
  14. StreetHacker Music - Traction 4 Heavy

Замена и удаление повторяющихся символов в строке

В данной статье будет рассмотрена замена и удаление повторяющихся символов в строке с помощью регулярных выражений Java. Заменять и удалять повторяющиеся символы будет через функции замены класса String. У класса String есть четыре метода для замены символов. Вот их сигнатуры:
  1. replace(char oldChar, char newChar):String
  2. replace(CharSequence target, CharSequence replacement):String
  3. replaceAll(String regex,String replacement):String
  4. replaceFirst(String regex,String replacement):String
Первые два метода в нашем случае не пригодятся, т.к. они нужны для замены одного символа (char) на другой символ или последовательности символов (CharSequence) на другую последовательность. CharSequence - это интерфейс, который реализуют классы: String, StringBuilder и StringBuffer. Остановимся на двух последних методах: replaceAll и replaceFirst. Оба метода первым параметром принимают регулярное выражение (regex), а вторым параметром текст замены (replacement). replaceAll- заменяет все совпадения, а replaceFirst заменяет только первое совпадение. В данной статье будет использоваться только replaceAll.
  1. Представим себе следующую задачу: требуется удалить из строки все стоящие рядом два одинаковых символа. Например, из строки "keeshh" должна в итоге получиться строка "ks"
    String text = "keeshh";
    String result = text.replaceAll("([a-z])\\1", "");
    System.out.println(result);//"ks"
    
    replaceAll - функция для замены всех совпадений [a-z] - выражение говорит о том, что на этом месте должен быть символ в диапазоне от a до z. () - круглые скобки означают группировку, сослаться на которую можно по номеру, причем нумерация начинается с единицы \1 - указывает на то, что в этом месте должен быть такой же текст, как в группировке под номером 1. Обратный слэш "\" необходимо экранировать, поэтому в выражении два слэша "\\"
  2. После удаление двух повторных символов, могут снова образоваться повторные символы. Например, если в строке "keeshhs" заменить два подряд повторяющихся символа, то получится "kss", но подстроку "ss" также можно удалить. Поместим описанный выше код в цикл, который будет повторяться до тех пор, пока не будут заменены все повторные символы. В данной реализации будем пытаться удалять повторения, пока меняется (укорачивается) длина строки
    String text = "keeshhs";
    int len;		
    do{
    	len = text.length();//сохраняем длину строки
    	text = text.replaceAll("([a-z])\\1", "");
    }while(len != text.length());//сравниваем новую длину строки с сохраненной длиной
    System.out.println(text);//"k"
    
  3. Рассмотрим следующий пример. Нужно удалить все повторяющиеся подряд символы. Например, для строки "keeeshh" результат должен быть "ks". Реализация:
    String text = "keeeeshh";
    text = text.replaceAll("([a-z])\\1+", "");
    System.out.println(text);//"ks"
    
    Как вы, наверное, заметили после единички добавился символ +. Плюс в регулярных означает, что предшествующий плюсу символ или группировка должна встретиться от одного раза и более. Можно также включить этот код в цикл, чтобы снова заменить появившиеся повторения.
  4. Теперь рассмотрим замену. Задача: имеется строка, необходимо из двух подряд идущих одинаковых символов оставить только один. Пример: из строки "kkeesshh" получится строка "kesh". Реализация:
    String text = "kkeesshh";
    text = text.replaceAll("([a-z])\\1", "$1");
    System.out.println(text);//"kesh"
    
    Для замены мы использовали выражение $1, которое говорит о том, что текст, соответствующий регулярному выражению, необходимо заменить на текст, соответствующий группировке с номером 1. В нашем случае группировка с номером - это текст, соответствующий шаблону [a-z]. Можно переписать код, используя группу с номером 2 для замены:
    String text = "kkeesshh";
    text = text.replaceAll("([a-z])(\\1)", "$2");
    System.out.println(text);//"kesh"
    
    Вторая группа соответствует шаблону \\1
  5. И напоследок заменим в строке все подряд повторяющиеся символы одним символом. Например, строка "keeeeessshh" преобразуется в "kesh". Реализация:
    String text = "keeeeessshh";
    text = text.replaceAll("([a-z])\\1+", "$1");
    System.out.println(text);//"kesh"
    
Использование регулярных выражений позволяет писать более компактный код и, возможно, сэкономить время на наборе кода, если хорошо освоить регулярные выражения.

org.apache.http.NoHttpResponseException: The target server failed to respond

Случилось так, что в двух моих Android-приложениях перестала работать статистика. Хотя приложения уже работали более года без обновлений, да и сервис статистики я не трогал. Запустив одно из приложений под отладкой, обнаружил ошибку:
org.apache.http.NoHttpResponseException: The target server failed to respond
Потом локализовал ошибку. Вот фрагмент проблемного кода:
HttpParams httpParams = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(httpParams, 5000);//тайм-аут подключения
HttpConnectionParams.setSoTimeout(httpParams, 10000);//тайм-аут сокета
HttpClient httpClient = new DefaultHttpClient(httpParams);
HttpGet httpGet = new HttpGet(url);
HttpResponse httpResponse = httpClient.execute(httpGet);//тут выбрасывается Exception
Попробовал переписать код так (без HTTP-параметров).:
HttpClient httpClient = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(url);
HttpResponse httpResponse = httpClient.execute(httpGet);
Статистика в приложении начала работать. Т.е. дело оказалось в передаваемых параметрах. Мне кажется, провайдер хостинга что-то обновил, и теперь сервер перестал понимать передаваемые запросы. Погуглив, нашел другой способ передачи параметров, способ - работает!
HttpClient httpClient = new DefaultHttpClient();
httpClient.getParams().setParameter(HttpConnectionParams.CONNECTION_TIMEOUT, 5000);
httpClient.getParams().setParameter(HttpConnectionParams.SO_TIMEOUT, 10000);
HttpGet httpGet = new HttpGet(url);
HttpResponse httpResponse = httpClient.execute(httpGet);
Как видно из приведенного выше кода:
  1. Нужно создать объект HttpClient, используя конструктор без параметров DefaultHttpClient()
  2. С помощью httpClient.getParams().setParameter(String name,Object value) установить необходимые параметры
Надеюсь, этот код прослужит долго!

Создание резервной копии директорий (WinRAR)

Иногда возникает необходимость в создании полной резервной копии какой-нибудь директории. Можно, конечно, каждый раз вручную архивировать папку, присваивая название архиву и проставляя номер или дату резервной копии. Но это быстро надоедает. Предлагаю написать скрипт(bat), который будет автоматизировать эту работу. Допустим, есть директория D:\Projects\ProjectX, для которой нужно сделать резервную копию, заархивировав WinRAR'ом. Название архива будет содержать, кроме названия, еще и дату создания. Для этого нужно выполнить следующие шаги:
  1. Создадим любым текстовым редактором файл с названием projectx.bat. Желательно создать специальную директорию для хранения подобных скриптов (Например, D:\Scripts\backups)
  2. Вставьте следующий код в файл
    cls
    set rar="C:\Program Files\WinRAR\Rar.exe"
    set source_dir="D:\Projects\ProjectX"
    set backup_dir="D:\Backup\ProjectX\projectx_"
    %rar% a -r -ep1 -agYYYY-MM-DD[HHMM] %backup_dir% %source_dir%
    
    cls - необязательная команда, которая очищает консоль
  3. Переменная rar хранит полный путь к утилите rar.exe Переменная source_dir хранит полный путь к директории, для которой создается резервная копия Переменная backup_dir содержит путь до директории, где хранятся резерный копии(D:\Backup\), поддиректории (ProjectX) и префикса названия файла архива (projectx_) Теперь рассмотрим параметры архивирования, которые мы передаем утилите rar.exe: a - команда, указывающая на добавление файлов в архив -ep1 - опция, которая позволяет исключить базовый путь из имен файлов, но сохраняет внутреннюю иерархию директории -agYYYY-MM-DD[HHMM] - генерирует название файла на основе текущей даты и времени Последние два параметра передаваемые утилите - это путь до архива (backup_dir) и архивируемая директория (source_dir).
Теперь рассмотрим все в картинках: Директория для архивирования: pic1 Запускаемый скрипт: pic2 Директория с резервными копиями: pic3 Содержимое архива: pic4 Содержимое директории: pic5 Почему лучше использовать абсолютные пути в скрипте? Во-первых, это позволит хранить скрипты в одном месте, а резервные копии в другом. Во-вторых, можно запускать скрипты из любого места, не заботясь о текущей директории. Созданный нами скрипт можно запускать по мере необходимости или запускать планировщиком по расписанию. Если всё же решили использовать в скрипте относительные пути, то при создании задания в планировщике не забудьте указать рабочую директорию скрипта.

Пишем свой сборщик писем на PHP (3 часть из 3)

Описание использованных функций (func.php):
";
}

//вывод содержимого объекта на экран
function debugObj($obj){
	echo "<";
    echo "pre style='color:green'>";
	print_r($obj);
	echo "";
}

//получение заголовка письма в виде объекта
function getHeader($mbox,$uid){
    return imap_rfc822_parse_headers(getHeaderRaw($mbox,$uid));
}

//получение заголовка письма
function getHeaderRaw($mbox,$uid){
    return imap_fetchbody($mbox, $uid, '0', FT_UID);
}

//раскодировка заголовка
function getDecodedHeader($text){
    //imap_mime_header_decode - декодирует элементы MIME-шапки в виде массива
    //У каждого элемента указана кодировка(charset) и сам текст(text)
    $elements = imap_mime_header_decode($text);
    $ret = "";
    //перебираем элементы
    for ($i=0; $icharset;//кодировка
        $text = $elements[$i]->text;//закодированный текст
        if($charset == 'default'){
            //если элемент не кодирован, то значение кодировки default
            $ret .= $text;
        }else{
            //приводим всё кодировке к UTF-8
            $ret .= iconv($charset,"UTF-8",$text);
        }
    }
    return $ret;
}

//получение содержимого письма в виде простого текста
function getTextBody($imap,$uid){
    return getPart($imap, $uid, "TEXT/PLAIN");
}

//получение содержимого письма в виде формате html
function getHtmlBody($imap,$uid){
    return getPart($imap, $uid, "TEXT/HTML");
}

//получение части письма
function getPart($imap, $uid, $mimetype) {
    //получение структуры письма
    $structure = imap_fetchstructure($imap, $uid, FT_UID);
    if ($structure) {
        if ($mimetype == getMimeType($structure)) {
            $partNumber = 1;
            //imap_fetchbody - извлекает определённый раздел тела сообщения
            $text = imap_fetchbody($imap, $uid, $partNumber, FT_UID);

            $charset = $structure->parameters[0]->value;//кодировка символов

            //0 - 7BIT; 1 - 8BIT; 2 - BINARY; 3 - BASE64; 4 - QUOTED-PRINTABLE; 5 - OTHER
            switch ($structure->encoding) {
                case 3:
                    //imap_base64 - декодирует BASE64-кодированный текст
                    $text = imap_base64($text);
                    break;
                case 4:
                    //imap_qprint - конвертирует закавыченную строку в 8-битную строку
                    $text = imap_qprint($text);
                    break;
            }

            if($mimetype == 'TEXT/PLAIN'){
                $text = iconv($charset,"UTF-8",$text);
            }

            if($mimetype == 'TEXT/HTML'){
                $text = iconv($charset,"UTF-8",$text);
            }

            return $text;
        }
    }
    return false;
}

//MIME-тип передается числом, а подтип - текстом.
//Функция приводит все в текстовый вид.
//Например: если type = 0 и subtype = "PLAIN",
//то функция вернет "TEXT/PLAIN".
//TEXT - 0, MULTIPART - 1, .. , APPLICATION - 3 и т.д.
function getMimeType($structure) {
    $primaryMimetype = array("TEXT", "MULTIPART", "MESSAGE", "APPLICATION", 
        "AUDIO", "IMAGE", "VIDEO", "OTHER");
    if ($structure->subtype) {
        return $primaryMimetype[(int)$structure->type] . "/" . $structure->subtype;
    }
    return "TEXT/PLAIN";
}

//перевести текст в дату MySQL
function strToMysqlDate($text){
    $unixTimestamp=strtotime($text);
    return date("Y-m-d H:i:s", $unixTimestamp);
}

//заполняем ассоциативный массив, где ключом является тип адреса,
//а значение массив адресов
function getAddress($header,$type,&$map){
    //проверка существования типа в заголовке
    if(property_exists($header,$type)){
        $arr = $header->$type;
        if(is_array($arr) && count($arr) > 0){
            $map[$type] = $arr;
        }
    }
}

//загрузка вложений
function loadAttaches($mbox,$uid,$message_id){
    //получаем структуру сообщения
    $struct = imap_fetchstructure($mbox,$uid,FT_UID);
    $attachCount = 0;
    if(!$struct->parts) return $attachCount;
    //перебираем части сообщения
    foreach($struct->parts as $number => $part){
        //ищем части, у которых ifdisposition равно 1 и disposition равно ATTACHMENT,
        //все остальные части игнорируем. Также стоит заметить, что значение поля
        //disposition может быть как в верхнем, так и в нижнем регистрах,
        //т.е. может быть "attachment" и "ATTACHMENT". Поэтому в коде всё приведено
        //к верхнему регистру
        if(!$part->ifdisposition 
            || strtoupper($part->disposition) != "ATTACHMENT")continue;
        //получаем название файла
        $filename = getDecodedHeader($part->dparameters[0]->value);
        //получаем содержимое файла в закодированном виде
        $text = imap_fetchbody($mbox, $uid, $number + 1, FT_UID);
        //декодирование содержимого файла
        switch ($part->encoding) {
            case 3:
                $text = imap_base64($text);
                break;
            case 4:
                $text = imap_qprint($text);
                break;
        }
        //оригинальное название файла будем сохранять в базе данных.
        //Разные письма могут иметь вложения с одинаковыми названиями,
        //поэтому в файловой системе будем сохранять файла с уникальным именем,
        //сохранив при этом расширение файла
        $file_path = getStoreDirectory() . getUid() . getFileExtension($filename);
        file_put_contents($file_path,$text);

        $content_type = getMimeType($part);//MIME-тип файла
        $filesize = strlen($text);//размер файла

        //записываем информацию о файле в базу данных. Напомню, что в
        //базу сохраняется не сам файл, а относительный путь к файлу
        $sql = "INSERT INTO attachments(message_id,file_name,mime_type,
            file_size,location)" .
            "VALUES('$message_id',
            '" . mysql_real_escape_string($filename) . "',
            '" . mysql_real_escape_string($content_type) . "',
            $filesize,
            '" . mysql_real_escape_string($file_path) . "')";
        $res_ins = mysql_query($sql) or die(mysql_error());
        $attachCount++;
    }
    return $attachCount;
}

//Функция для получения пути к директории, где будут храниться файлы.
//Файлы будут сохраняться в поддиректории, созданной по
//текущей дате. Например, 2014-07-31. Это позволит
//не держать файлы в одной директории. Много файлом в
//одной директории замедляет чтение директории
function getStoreDirectory(){
    global $FILES;
    $date_folder = "$FILES/" . date('Y-m-d') . "/";
    if(!file_exists($date_folder)) mkdir($date_folder);
    return $date_folder;
}

//генерация уникального идентификатора
function getUid(){
    if (function_exists('com_create_guid')){
        return str_replace("}", "", str_replace("{", "", com_create_guid()));
    } else {
        mt_srand((double)microtime()*10000);//optional for php 4.2.0 and up.
        $charid = strtoupper(md5(uniqid(rand(), true)));
        $hyphen = chr(45);// "-"
        $uuid =
            substr($charid, 0, 8).$hyphen
            .substr($charid, 8, 4).$hyphen
            .substr($charid,12, 4).$hyphen
            .substr($charid,16, 4).$hyphen
            .substr($charid,20,12);

    }
    return strtolower($uuid);
}

//получаем расширение файла
function getFileExtension($filename){
    $arr = explode(".",$filename);
    return count($arr) > 1 ? "." . end($arr) : "";
}
?>
Файл для подключения к базе данных (connect.php):


Исходный код можно скачать здесь

Пишем свой сборщик писем на PHP (2 часть из 3)

Скрипт для скачивания писем (loader.php)
subject);//тема письма
            $headerDate = strToMysqlDate($header->date);//дата письма
            $body_text = getTextBody($mail,$message_uid);//содержимое письма в виде простого текста
            $body_html = getHtmlBody($mail,$message_uid);//содержимое письма в формате html

            //получение адресов из заголовка письма
            $address_map = array();
            $address_types = array('to','from','reply_to','sender','cc','bcc');
            foreach($address_types as $address_type){
                getAddress($header,$address_type,$address_map);
            }

            foreach($address_map as $key => $arr){
                foreach($arr as $obj){
                    $type = $key;
                    $address = "$obj->mailbox@$obj->host";//склеиваем email
                    $sql = "INSERT INTO addresses(message_id,type,email)
                            VALUES($message_id,
                            '" . mysql_real_escape_string($type) . "',
                            '" . mysql_real_escape_string($address) . "')";
                    mysql_query($sql) or wr(mysql_error());
                }
            }

            //считываем вложения и получаем кол-во вложений,
            //которое записываем в базу данных
            $attachCount = loadAttaches($mail,$message_uid,$message_id);

            $sql = "UPDATE messages
                    SET subject = '" . mysql_real_escape_string($subject) . "',
                        body_text = '" . mysql_real_escape_string($body_text) . "',
                        body_html = '" . mysql_real_escape_string($body_html) . "',
                        header = '" . mysql_real_escape_string($headerRaw) . "',
                        message_date = '" . mysql_real_escape_string($headerDate) . "',
                        attachment_count = $attachCount,
                        modify_date = now(),
                        is_ready = true
                    WHERE id = $message_id";
            mysql_query($sql) or wr(mysql_error());
            mysql_query("COMMIT");
        }

    }

}
?>

Пишем свой сборщик писем на PHP (1 часть из 3)

В данной статье будет описано создание сборщика писем на PHP. Если в один прекрасный день у вас возникла необходимость забирать письма с почтового (почтовых) ящиков и куда-то складывать (скорее всего, в базу данных), то добро пожаловать. Очень надеюсь, что статья вам пригодиться и облегчит жизнь. В третьей части статьи будут приложены все необходимые коды. И так поехали... Сначала определимся с требованиями: 1) Реализация на PHP 2) Чтение писем по протоколу IMAP 3) Запись содержимого писем в базу MySQL 4) Сохранение вложений к письмам в файловой системе 5) Будет реализовано два скрипта: первый проверяет новые письма, а второй закачивает письма 6) Будет таблица, содержащая список почтовых ящик, с которых собираются письма 7) Также будет сохраняться информация о том: от кого письмо, кому письмо, кому переадресовано, кто в копии и кто в скрытой копии Почему именно такой выбор? Письма можно читать с почтового сервера по протоколам IMAP и POP3. Реализация сборщика будет построена с использованием протокола IMAP, т.к. он имеет ряд преимуществ. Не знаю как в реализациях POP3 на других языках, но в PHP мне не удалось получить UID письма, можно получить только порядковый номер письма среди новых. Также минусом при использовании POP3 является то, что письма нужно считывать с первого раза. А у нас будет другая реализация: письма сперва проверяются, а только потом закачиваются, что возможно благодаря IMAP. Вложения к письмам будем хранить в файловой системе, а в базе данных будут храниться только пути к этим файлам (хотя вам никто не запрещает записывать файлы в базу данных) ПРОЕКТИРОВАНИЕ ТАБЛИЦ Таблица почтовых ящиков Создадим в MySQL новую базу данных mail_collector с кодировкой UTF-8 по умолчанию:
CREATE DATABASE mail_collector DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci; 
Создадим таблицу mailboxes, которая будет хранить необходимую информацию для подключения к почтовому ящику.
CREATE TABLE mailboxes
(
	id int PRIMARY KEY NOT NULL AUTO_INCREMENT,
	email varchar(50) NOT NULL,
	password varchar(50) NOT NULL, 
	host varchar(50) NOT NULL, 
	port varchar(50) NOT NULL, 	
	is_ssl bit NOT NULL,   
	is_deleted bit NOT NULL,
	last_message_uid int NOT NULL	
);
Назначение полей: email - почтовый ящик password - пароль от ящика host - адрес почтового сервера. Например, imap.gmail.com или 173.194.71.108 port - порт, по которому работает почтовый сервер is_ssl - если флаг установлен, то подключение будет по SSL is_deleted - если флаг установлен, то почтовый ящик считается удаленным и не участвует в сборке писем last_message_uid - поле используется для хранения UID последнего считанного сообщения Заполним таблицу mailboxes данными трех почтовых ящиков, созданных на разных почтовых серверах: gmail, yandex и mail.ru. В качестве примера к почтовым ящикам на gmail и yandex будем подключаться через SSL, а на mail.ru - без SSL.
INSERT INTO mailboxes(email,password,host,port,is_ssl,is_deleted) VALUES
('mail.collector.kz@gmail.com','mail.collector','imap.gmail.com','993',1,0,0),
('mail.collector.kz@mail.ru','mail.collector','imap.mail.ru','143',0,0,0),
('mail.collector.kz@yandex.ru','mail.collector','imap.yandex.ru','993',1,0,0)
Таблица сообщений Создадим таблицу messages для хранения сообщений:
CREATE TABLE messages
(
	id int PRIMARY KEY NOT NULL AUTO_INCREMENT,
	mailbox_id int NOT NULL,
	uid int NOT NULL,
	subject varchar(255),
	body_text text,
	body_html text,
	attachment_count int,
	header text,
	message_date datetime,
	create_date datetime NOT NULL,
	modify_date datetime,	
	is_ready bit NOT NULL 	
);
Так же создадим внешний ключ на таблицу mailboxes:
ALTER TABLE messages ADD CONSTRAINT fk_messages_user_id 
FOREIGN KEY (mailbox_id) REFERENCES mailboxes(id); 
Назначение полей: mailbox_id - ссылка на почтовый ящик, к которому относится письмо uid - уникальный номер письма в почтовом ящике subject - тема письма body_text и body_html - письмо храниться на сервере в виде обычного текста и html-версии attachment_count - кол-во вложений письма header - технический заголовок письма message_date - дата письма create_date - дата создания записи modify_date - дата изменения записи is_ready - письмо полностью загружено Таблица адресов Создадим таблицу addresses для хранения адресов: адрес отправителя, адреса получателей, адреса получателей скрытой копии и т.д.
CREATE TABLE addresses
(
	id int PRIMARY KEY NOT NULL AUTO_INCREMENT,
	message_id int NOT NULL,
	type varchar(10) NOT NULL,
	email varchar(50) NOT NULL
);
И создадим внешний ключ для связи с таблицей messages:
ALTER TABLE addresses ADD CONSTRAINT fk_addresses_message_id 
FOREIGN KEY (message_id) REFERENCES messages(id); 
Назначение полей: message_id - ссылка на сообщение, к которому относится данный адрес type - тип адресата: "from" (отправитель), "to"(получатель), "cc" (скрытая копия) и т.д. email - адрес электронной почты Таблица вложений Создадим таблицу attachments для хранения информации о файлах прикрепленных к письму:
CREATE TABLE attachments
(
	id int PRIMARY KEY NOT NULL AUTO_INCREMENT,
	message_id int NOT NULL,
	file_name varchar(255) NOT NULL,
	mime_type varchar(255) NOT NULL,
	file_size int NOT NULL,
	location varchar(255) NOT NULL	
);
Создадим внешний ключ для связи с таблицей messages:
ALTER TABLE attachments ADD CONSTRAINT fk_attachments_message_id 
FOREIGN KEY (message_id) REFERENCES messages(id); 
Назначение полей: message_id - привязка к конкретному сообщению file_name - имя файла mime_type - тип данных: "application/zip", "application/pdf", "image/png" и т.д. file_size - размер файла в байтах location - расположение файла СКРИПТЫ Описание работы: первый скрипт подключается к почтовому серверу, записывает в базу данных UID-ы новых писем, а второй скрипт, который будет рассмотрен позднее, по UID писем закачивает содержимое писем с вложениями и другой информацией. Скрипт для чтения новых писем (reader.php)
uid;
			wr("add message $message_uid");
			
			//создаем запись в таблице messages,
			//тем самым поставив сообщение в очередь на загрузку
			$sql = "INSERT INTO messages(mailbox_id,uid,create_date,is_ready)
					VALUES($mailbox_id,$message_uid,now(),0)";
			mysql_query($sql) or die(mysql_error());
		}
		
		if($message_uid != - 1){
			wr("last message uid = $message_uid");
			
			//если появились новые сообщения, 
			//то сохраняем UID последнего сообщения
			$sql = "UPDATE mailboxes 
					SET last_message_uid = $message_uid
					WHERE id = $mailbox_id";
			mysql_query($sql) or die(mysql_error());
		}else{
			//нет новых сообщений
			wr("no new messages");
		}
	}
	
	mysql_query("COMMIT");//завершаем транзакцию

	//закрываем IMAP-поток
	imap_close($mail);
}
?>

Сделать в слове первую букву заглавной (Java)

Для того чтобы сделать первую букву в слове заглавной, напишем собственную функцию firstUpperCase. Функция firstUpperCase будет принимать слово, а возвращать тоже слово, но с первой заглавной буквой.
public String firstUpperCase(String word){
	if(word == null || word.isEmpty()) return "";//или return word;
	return word.substring(0, 1).toUpperCase() + word.substring(1);
}
word.substring(0, 1) - возвращает первую букву в слове word.substring(0, 1).toUpperCase() - переводит первую букву в верхний регистр word.substring(1) - добавляет остальные символы без изменения Пример использования:
String var = "name";
System.out.println("get" + firstUpperCase(var) + "()");//Выведет: "getName()"