Вариации на тему Digital Dashboard

Виталий Сизов

Введение

Внедренный WebBrowser

Класс Internet Explorer

Введение

Суть современной информационной технологии Digital Dashboard (DD), основанной на программных продуктах Microsoft, заключается в интеграции сведений, получаемых из различных источников информации в одной или нескольких Web-страницах, разрабатываемых для конкретных пользователей — лиц, принимающих решения. Другими словами, эта технология предназначена для организации рабочих мест для ответственных работников коммерческих предприятий: бизнесменов, аналитиков, руководителей разных уровней. Ключевым моментом, определяющим эффективность DD, является наличие достаточно разнообразных источников информации, используемых для принятия решений. Принята следующая классификация таких источников:

  • внешние источники — сведения, получаемые из Интернета и интранета. Это разного рода Web-страницы, Web-запросы, тикеры, Web-камеры и другие средства, доступные в глобальной Сети;
  • корпоративные источники — сведения о положении дел на предприятии в целом и в его подразделениях, в том числе внутренние документы, отчеты и базы данных;
  • групповые источники — средства, предоставляемые технологией Team Folder: календарь проекта, почта и задачи, общие для группы работников;
  • личные источники — предполагается, что эта группа полностью основана на стандартных приложениях Outlook: личной электронной почте, календаре, задачах и контактах.

Наиболее трудоемким процессом в создании DD является интеграция корпоративных источников — требуется ревизия всего документооборота на предприятии и преобразование данных в формы, удобные для анализа. Предполагается, что лучшими инструментами для работы с корпоративной информацией являются Microsoft Office и Microsoft SQL Server. Поэтому технология DD в первую очередь обеспечивает взаимодействие именно с этими средствами. Таким образом, привлекательность новой технологии заключается в том, что она позволяет соединить способность гипертекстовых документов интегрировать разнородную информацию, представленную в самых разнообразных формах, с мощными средствами ее обработки, имеющимися в составе Microsoft Office.

Технически все это выглядит следующим образом. DD — узел из Web-страниц, изготовленных с помощью Visual InterDev, который дополнительно оснащен специальным модулем расширения (Add-In) из пакета DDRK (Digital Dashboard Resource Kit). Стандартная страница DD состоит из совокупности динамических окон, в каждом из которых помещается Web Part — элемент, представляющий собой источник информации. Для отображения DD используется не обычный обозреватель, а Microsoft Outlook, причем домашняя страница DD заменяет стандартный Outlook Today, для чего переписывается его адрес в реестре Windows. DD открывается в приложении Microsoft Outlook, являющемся компонентом Microsoft Office, благодаря чему обеспечивается необходимая связь между Web-страницей и средствами Office.

Однако в действительности все обстоит намного проще. Ключевую роль в системе с DD играет библиотека SHDocVw, которая имеется на любом компьютере, где установлен обозреватель Internet Explorer, и обычно расположена по адресу c:\windows\system\ shdocvw.dll. А Outlook выполняет функцию контейнерного приложения для объектов этой библиотеки. Вероятно, многие программисты, просматривая список доступных элементов управления ActiveX, обнаруживали на своей машине или WebBrowser, или, в русской версии, Обозреватель Web-страниц Microsoft. Это не что иное, как один из компонентов SHDocVw.

Так что возможность организации взаимодействия Web-страниц с приложениями Office, являющаяся основополагающей для технологии DD, существовала довольно давно, по крайней мере с момента появления Microsoft Office 97, оснащенного VBA.

В настоящей статье описываются варианты организации такого взаимодействия, что позволяет создавать DD альтернативным способом, в обход жестких требований к программному обеспечению, предписанных корпорацией Microsoft. Вместе с тем все возможности «стандартных» DD, построенных на базе DDRK, сохраняются и могут быть реализованы по мере необходимости.

В начало В начало

Внедренный WebBrowser

В справочной документации для Microsoft Access 97 прямо рекомендуется использовать элемент управления WebBrowser в формах базы данных для придания проекту возможности отображать Web-страницы. Однако WebBrowser прекрасно внедряется не только в формы, но и в обычные документы Office — текстовые документы Word и страницы рабочих книг Excel. Чтобы внедрить WebBrowser, на панели инструментов Элементы управления классических приложений Office достаточно раскрыть опцию Дополнительные элементы и в открывшемся списке выбрать Обозреватель Web-страниц Microsoft. В результате этих действий на рабочей поверхности документа появится прямоугольник с эмблемой Windows на черном фоне. Размеры этого прямоугольника можно изменить с помощью мыши. Если WebBrowser внедрить на лист Excel, то в строке редактирования можно обнаружить команду: =ВНЕДРИТЬ(”Shell.Explorer.2”;””), а в коллекции объектов листа добавится имя WebBrowser1.

Теперь в качестве контейнерного приложения вместо Outlook выступает объект Worksheet. Если перейти в окно кода этого объекта, то в ниспадающем списке Объекты наряду с Worksheet будет присутствовать объект WebBrowser1, а в ниспадающем списке Процедуры появится список из двух десятков событий, предусмотренных для этого объекта.

Единственное неудобство, сопутствующее такому внедрению, будет заключаться в постоянном переключении панелей управления приложения. Как только фокус переместится на объект WebBrowser, будет автоматически открываться панель инструментов Web — кстати говоря, совершенно бесполезная, поскольку ее команды воздействуют не на внедренный объект, а на внешний обозреватель Internet Explorer. Напротив, при утрате фокуса будут открываться стандартные панели инструментов рабочего листа. Аналогичное переключение панелей наблюдается и при внедрении графиков (объекты Chart) на листы Worksheet, но в этом случае такое переключение вполне уместно.

Однако не следует забывать, что внедрение WebBrowser было задумано для отображения DD — Web-страницы с большим количеством разнообразных элементов. Очевидно, что для такой страницы желательно выделить максимум доступного пространства на экране дисплея. Поэтому следует избавиться не только от «неправильной» панели Web, но и ото всех панелей управления, включая основное меню приложения, и не допускать их «самовольного» появления.

Кроме того, необходимо предусмотреть типичные команды управления навигацией, применяемые во всех обозревателях: Назад, Далее, Остановить, Обновить, Домой, Избранное и ComboBox Переход. Сделать это нетрудно, тем более что на отвергнутой панели Web такие элементы управления присутствуют, поэтому у них можно позаимствовать все необходимое, за исключением свойств onAction. Установка необходимого обрамления выполняется с помощью следующей процедуры:

‘—   Формирование Excel Settings      
    Dim objCBar As CommandBar      
    Dim objControl As CommandBarControl      
    Dim objCBoxTo As CommandBarComboBox      
    Dim objCBoxFrom As CommandBarComboBox      
    Dim objWB As WebBrowser      
    Dim i As Integer      
       
    With Application      
      ‘— скрытие всех панелей инструментов      
      For   Each objCBar In .CommandBars      
        If objCBar.Visible And objCBar.Name <> _      
           “Worksheet Menu Bar” Then      
          objCBar.Visible = False      
        End If      
      Next      
       
      ‘— только нужные панели Excel      
      .DisplayFormulaBar   = False      
      .DisplayStatusBar = True      
       
      ‘— удаление   всех меню      
      Set objCBar = .CommandBars(“Worksheet Menu Bar”)      
      For Each objControl In objCBar.Controls      
        objControl.Delete      
      Next      
    End With      
       
    ‘— формирование   панели инструментов      
    With objCBar      
       
      ‘—   кнопка Назад      
     Set objControl = .Controls.Add      
       (Type:=msoControlButton)      
      With objControl      
        .FaceId = 1017      
        .Caption = “&Назад”      
        .OnAction = “GoBack”      
      End With      
       
      ‘— кнопка   Далее      
      Set objControl = .Controls.Add      
        (Type:=msoControlButton)      
      With objControl      
        .FaceId = 1018      
        .Caption = “Да&лее”      
        .OnAction = “GoForward”      
      End With      
       
      ‘— кнопка   Остановить      
      Set objControl = .Controls.Add      
        (Type:=msoControlButton)      
      With objControl      
        .FaceId = 1019      
        .Caption = “Ос&тановить переход”      
        .OnAction   = “StopNavigate”      
      End With      
       
      ‘— кнопка   Обновить      
      Set objControl = .Controls.Add      
        (Type:=msoControlButton)      
      With objControl      
        .FaceId = 1020      
        .Caption = “О&бновить текущую страницу”      
        .OnAction   = “Refresh”      
      End With      
       
      ‘— кнопка   Домой      
      Set objControl = .Controls.Add      
        (Type:=msoControlButton)      
      With objControl      
        .FaceId = 1016      
        .Caption = “На&чальная страница”      
        .OnAction   = “GoHome”      
      End With      
       
      ‘— меню   Избранное      
      Application.CommandBars(“WEB”).Controls(7).      
        Copy objCBar      
       
      ‘— ComboBox для   ввода Адреса      
      Set objControl = _      
        .Controls.Add(Type:=msoControlComboBox)      
      With objControl      
        .Caption = “Пере&ход”      
        .OnAction = “GoAddress”      
        .Width = 256      
        Set objCBoxTo = objControl      
        Set objCBoxFrom = _      
          Application.CommandBars(“WEB”).Controls(10)      
        For i = 1 To objCBoxFrom.ListCount      
          objCBoxTo.AddItem objCBoxFrom.List(i)      
        Next      
       
        ‘— адрес открытой страницы      
        Set   objWB = _      
          ThisWorkbook.Worksheets(“Browser”).WebBrowser1      
        objCBoxTo.Text = objWB.LocationURL      
      End With      
    End With      
End Sub 

Обратите внимание, что при формировании нового комбинированного списка Переход в его раскрывающийся список копируются все адреса из старого ComboBox со стандартной панели элементов Web.

Естественно, необходимо предусмотреть и вторую процедуру, выполняющую обратные действия. Она совсем простая:

Private Sub   RestoreSettings()      
‘—   Восстановление   Excel Settings      
    With Application      
      .CommandBars(“Worksheet Menu Bar”).Reset      
      .CommandBars(“Standard”).Visible = True      
      .CommandBars(“Formatting”).Visible = True      
      .CommandBars(“Web”).Visible = False      
      .DisplayFormulaBar = True      
      .DisplayStatusBar = True      
    End With      
End Sub

Вызывать приведенные процедуры нужно не только при первоначальном открытии и закрытии рабочей книги, но и при ее активации/деактивации:

Private Sub   Workbook_Activate()      
    SetSettings      
End   Sub      
       
Private   Sub Workbook_BeforeClose(Cancel As Boolean)      
    RestoreSettings      
End   Sub      
       
Private   Sub Workbook_Deactivate()      
    RestoreSettings      
End   Sub      
       
Private   Sub Workbook_Open()      
    ThisWorkbook.Worksheets(“Browser”).Activate      
    SetSettings      
    With Application      
      .WindowState = xlMaximized      
       
      ‘— максимальный   размер для WebBrowser      
      If   ThisWorkbook.Worksheets(“Browser”) _      
         .OLEObjects(1).Height <> .UsableHeight Then      
        ThisWorkbook.Worksheets(“Browser”) _      
        .OLEObjects(1).Height = .UsableHeight      
      End If      
      If ThisWorkbook.Worksheets(“Browser”) _      
         .OLEObjects(1).Width <> .UsableWidth Then      
        ThisWorkbook.Worksheets(“Browser”) _      
        .OLEObjects(1).Width = .UsableWidth      
      End If      
    End With      
       
    ‘— загрузка домашней страницы      
    GoHome      
End Sub      

Следует отметить, что при открытии рабочей книги для внедренного OLE-объекта (а это наш WebBrowser) выделяется все доступное свободное пространство внутри приложения (свойства UsableHeight и UsableWidth). При необходимости размеры этого окна можно сократить, предусмотрев место для какой-нибудь панели управления непосредственно на листе Excel, скомбинировав Web-страницу и документ Office.

Что касается самих процедур, вызываемых при нажатии кнопок управления на новой панели инструментов, то их реализация также не вызывает труда, так как все необходимые команды совпадают с методами, предусмотренными для объекта класса WebBrowser. Рассмотрим только две из них, поскольку все остальные процедуры отличаются от GoHome только именем метода или адресом перехода:

Const   HOMEPAGE As String = “file:///C:/MyDD/index.html”      
       
Public   Sub GoHome()      
‘—   Открыть домашнюю страницу      
    Dim objWB As WebBrowser      
       
    Set   objWB = _      
      ThisWorkbook.Worksheets(“Browser”).WebBrowser1      
    If ActiveWorkbook.Name <> ThisWorkbook.Name Then      
      ThisWorkbook.Activate      
    End If      
    If ActiveSheet.Name <> “Browser” Then      
      ThisWorkbook.Worksheets(“Browser”).Activate      
    End If      
       
    On Error Resume Next      
    objWB.Navigate HOMEPAGE      
       
    If Err <> 0 Then      
      MsgBox Error$, vbCritical      
    End If      
       
    HideAll      
End Sub

В начале процедуры производится инициализация объектной переменной и активизируется рабочая книга и лист, содержащий внедренный объект. Последнее является целесообразным, поскольку выполнение команды для невидимого объекта вряд ли интересует пользователя. Собственно полезное действие выполняется над объектом objWB при отключенном обработчике ошибок. В конце процедуры вызывается вспомогательная процедура HideAll, скрывающая возможно появившиеся, но нежелательные панели инструментов:

Private   Sub HideAll()      
‘—   Скрыть все панели управления      
    Dim   objCBar As CommandBar      
    With Application      
      For Each objCBar In .CommandBars      
        If objCBar.Visible And objCBar.Name <> _      
           “Worksheet Menu Bar” Then      
          objCBar.Visible = False      
        End If      
      Next      
    End With      
End Sub

Несколько более сложная процедура выполняется при вводе адреса перехода в комбинированный список:

Private   Sub GoAddress()      
‘—   Переход по   адресу      
    Dim objCBar As CommandBar      
    Dim objCBox As CommandBarComboBox      
    Dim objWB As WebBrowser      
       
    Set objWB = _      
      ThisWorkbook.Worksheets(“Browser”).WebBrowser1      
    If ActiveWorkbook.Name <> ThisWorkbook.Name Then      
      ThisWorkbook.Activate      
    End If      
    If ActiveSheet.Name <> “Browser” Then      
      ThisWorkbook.Worksheets(“Browser”).Activate      
    End If      
       
    On Error Resume Next      
       
    Set objCBar = _      
      Application.CommandBars(“Worksheet Menu Bar”)      
    Set objCBox = objCBar.Controls(7)      
       
    ‘— добавить в список страниц      
    If objCBox.ListIndex = 0 Then      
      objCBox.AddItem objCBox.Text      
    End If      
       
    ‘— переход      
    objWB.Navigate objCBox.Text      
       
    If Err <> 0 Then      
      MsgBox Error$, vbCritical      
    End If      
    HideAll      
End Sub

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

В результате произведенных операций получился весьма симпатичный обозреватель Web-страниц, показанный на рисунке.

Кроме всего прочего, этот обозреватель замечателен тем, что к нему не цепляются всевозможные «Powered» Add-Ins-компоненты, которые модифицируют меню и панели инструментов стандартного Internet Explorer и от которых порой очень трудно избавиться.

В начало В начало

Класс Internet Explorer

Вышеописанное решение нельзя считать универсальным. Поскольку обозреватель Web-страниц жестко привязан к определенному документу Office, для работы с DD требуется постоянно держать этот документ открытым. Конечно, если DD является частью интерфейса какого-либо проекта, реализованного в среде офисного приложения, то данное решение целесообразно. Например, конкретное рабочее место может быть организовано в виде совокупности таблиц, графиков, форм и макросов Excel. В таком проекте DD сможет выступать в качестве центрального документа, откуда вызываются все формы и макросы и куда помещается сводная информация.

Однако в общем случае DD не является частью локального прикладного проекта. В задачу DD входит интеграция Web-страниц со всеми приложениями Office, поэтому выбор Outlook в качестве контейнера не случаен. Сделав такой выбор, Microsoft дает понять, что приложение Outlook является центральным звеном в семействе Office и должно оставаться открытым на протяжении всей работы на компьютере. К сожалению, это не всегда справедливо. Многие пользователи не в полной мере используют Outlook по разным причинам. Чаще всего это связано с тем, что в качестве почтового агента выбрана другая программа, например Outlook Express. Понятно, что использование другого почтового агента подразумевает и иную адресную книгу, в результате чего большая часть возможностей Outlook остается невостребованной.

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

Зато стандартный обозреватель Internet Explorer, устанавливаемый вместе с операционной системой Windows, известен практически всем пользователям, имеющим выход в Internet. А раз так, то почему бы для отображения DD не использовать этот обозреватель в неизменном виде?

Такая возможность существует и реализуется с помощью все той же библиотеки SHDocVw. Только в этом случае необходимо применять не класс WebBrowser, а другой класс — InternetExplorer. Создание объекта этого класса приводит к открытию нового отдельного окна обозревателя Internet Explorer со всеми стандартными элементами управления — меню и панелями инструментов. Для того чтобы обеспечить доступ к событиям этого объекта, создается контейнер нового класса, содержащий описание InternetExplorer c ключевым словом WithEvents. Такой новый класс («упаковка») ничуть не уступает формам или документам Office по возможностям обращения к свойствам, методам и событиям внедренных объектов.

Создать новый класс можно в любом приложении Office, переключившись в редактор VBE с помощью заветной комбинации клавиш Alt+F11. Единственное, что нужно сделать дополнительно, — подключить к проекту ссылку на библиотеку SHDocVw. Выполняется это с помощью команды Сервис|Ссылки…, а в окне доступных ссылок ставится галочка против имени Microsoft Internet Controls. Создаваемый класс InternetExplorerWithEvents может выглядеть следующим образом:

Option   Explicit      
‘—   Константы для   API      
Private   Const W_HIDE = 0      
Private   Const W_SHOWNORMAL = 1      
Private   Const W_SHOWMINIMIZED = 2      
Private   Const W_SHOWMAXIMIZED = 3      
Private   Const W_TITLE = “Microsoft Internet Explorer”      
Private   Const W_TITLE_NEW = _      
    “Microsoft Internet Explorer Powered by VBA”      
       
‘—   Класс InternetExplorerWithEvents      
Public   WithEvents IE As InternetExplorer      
Private   blnClosed As Boolean  ‘ IE закрыт      
Private   lngHwnd As Long       ‘ описатель окна      
       
‘—   Функции API      
Private   Declare Function FindWindow Lib “user32” _      
    Alias “FindWindowA” _      
    (ByVal lpClassName As String, _      
    ByVal lpWindowName As String) As Long      
Private   Declare Function ShowWindow Lib “user32” _      
    (ByVal hwnd As Long, _      
    ByVal nCmdShow As Long) As Long      
Private   Declare Function SetWindowText       
    Lib “user32” _      
    Alias “SetWindowTextA” _      
    (ByVal hwnd As Long, _      
    ByVal lpString As String) As Long      
       
Private   Sub Class_Initialize()      
    Dim objIE As New InternetExplorer      
       
    Set IE = objIE      
       
    ‘— maximize IE window      
    lngHwnd = FindWindow(vbNullString, W_TITLE)      
    If lngHwnd > 0 Then      
      SetWindowText lngHwnd, W_TITLE_NEW      
      ShowWindow lngHwnd, W_SHOWMAXIMIZED      
    End If      
    IE.Visible = True      
    blnClosed = False      
End   Sub      
       
Private   Sub Class_Terminate()      
    Set IE = Nothing      
End   Sub      
       
Public   Property Get Closed() As Boolean      
    Closed = blnClosed      
End   Property      
       
Public   Property Get hwnd() As Long      
    hwnd = lngHwnd      
End   Property      
       
Private   Sub IE_TitleChange(ByVal Text As String)      
    Dim strTitle As String      
       
    ‘— новое название окна IE      
    strTitle = Text & “ - “ & W_TITLE_NEW      
    SetWindowText lngHwnd, strTitle      
End   Sub      
       
Private   Sub IE_OnQuit()      
    Set IE = Nothing      
    blnClosed = True      
End Sub 

В приведенном примере для класса в целом обрабатываются события Initialize и Terminate. Основное свойство — объектная переменная IE, ссылающаяся на объект InternetExplorer, — объявлено общим (Public). Предусмотрено два дополнительных свойства, доступные только для чтения — Closed и hwnd. Внутри класса описаны две процедуры, обрабатывающие события TitleChange и OnQuit для внутреннего объекта IE. Кроме того, присутствует описание трех функций WinAPI.

Чтобы понять, как все это работает, рассмотрим типичный случай. Допустим, в некотором внешнем модуле имеется описание объекта класса InternetExplorerWithEvents. В тот момент, когда в этом модуле создается новый экземпляр объекта с помощью команды Set, вызывается конструктор Class_Initialize, в котором сначала создается новый экземпляр объекта InternetExplorer. Это равносильно открытию нового окна обозревателя с пустой (blank) домашней страницей. Затем вызываются функции API — для придания этому окну желаемого вида. Сначала, с помощью функции FindWindow, определяется дескриптор окна, в заголовке которого написано Microsoft Internet Explorer. Текст в заголовке найденного окна дополняется словами Powered by VBA с помощью функции SetWindowText. Наконец, это окно увеличивается до максимального размера с помощью функции ShowWindow, а управление возвращается в вызывающую программу. Теперь внешняя программа может вызывать навигацию, обращаясь к методам объекта IE. Особой необходимости в функциях Windows API нет, но объект InternetExplorer не имеет собственных свойств, позволяющих выбирать один из трех типичных размеров окна, и всегда открывается в окне среднего размера (Normal). Дополнение текста в заголовке словами Powered by VBA позволяет визуально контролировать наличие и утрату связи между обозревателем и VBA, то есть возможность реализации специальных функций DD. Для той же цели предусмотрен и обработчик события TitleChange. Если в заголовке имеется упоминание о VBA, то связь с Office возможна. Если же таких слов нет, то объект — упаковка InternetExplorerWithEvents — уничтожен. Это может произойти в том случае, если приложение Office, открывшее Internet Explorer, закрылось раньше обозревателя.

Противоположная ситуация может создаться в том случае, если закрывается окно Internet Explorer, в то время как объект InternetExplorerWithEvents еще существует. Для контроля этого состояния используется свойство Closed, которое принимает значение FALSE в момент открытия обозревателя и переключается в TRUE в обработчике события OnQuit. Внешняя программа может проверять это свойство и, если ранее открытый обозреватель уже закрыт, создавать новый экземпляр объекта InternetExplorerWithEvents.

Имея в своем распоряжении подобный класс, можно реализовать и макрос, открывающий DD в стандартном обозревателе Internet Explorer:

Const   HOMEPAGE As String = “file:///C:/MyDD/index.html”      
       
Public   gobjIE As InternetExplorerWithEvents      
       
Public   Sub DigitalDashboard()      
‘—   Открытие Digital Dashboard      
       
    ‘— создание глобального объекта      
    If   gobjIE Is Nothing Then      
      Set gobjIE = New InternetExplorerWithEvents      
    Else      
      If gobjIE.Closed Then      
        Set gobjIE = Nothing      
        Set gobjIE = New InternetExplorerWithEvents      
      End If      
    End If      
       
    ‘— открытие домашней   страницы      
    gobjIE.IE.Navigate HOMEPAGE      
       
    ‘—   фокус на   Internet Explorer      
  gobjIE.IE.Visible   = True      
End Sub

Все коды, приведенные в текущем разделе, не зависят от приложения. Следовательно, как модуль класса InternetExplorerWithEvents, так и макрос DigitalDashboard могут быть импортированы в неизменном виде в любое приложение Office. Более того, они могут быть импортированы в каждое приложение, например в шаблон Normal Microsoft Word и в общую книгу макросов PERSONAL.XLS приложения Microsoft Excel. Остается только добавить кнопку вызова макроса на панель инструментов каждого приложения — и положительный результат налицо. В любой момент из каждого приложения Office можно вызвать DD или обозреватель Internet Explorer, чтобы побродить по лабиринтам Всемирной паутины.

 

(Продолжение следует)

КомпьютерПресс 3'2001

1999 1 2 3 4 5 6 7 8 9 10 11 12
2000 1 2 3 4 5 6 7 8 9 10 11 12
2001 1 2 3 4 5 6 7 8 9 10 11 12
2002 1 2 3 4 5 6 7 8 9 10 11 12
2003 1 2 3 4 5 6 7 8 9 10 11 12
2004 1 2 3 4 5 6 7 8 9 10 11 12
2005 1 2 3 4 5 6 7 8 9 10 11 12
2006 1 2 3 4 5 6 7 8 9 10 11 12
2007 1 2 3 4 5 6 7 8 9 10 11 12
2008 1 2 3 4 5 6 7 8 9 10 11 12
2009 1 2 3 4 5 6 7 8 9 10 11 12
2010 1 2 3 4 5 6 7 8 9 10 11 12
2011 1 2 3 4 5 6 7 8 9 10 11 12
2012 1 2 3 4 5 6 7 8 9 10 11 12
2013 1 2 3 4 5 6 7 8 9 10 11 12
Популярные статьи
КомпьютерПресс использует