├── Help.pdf ├── LibreWeb-admin-1.0.3.oxt ├── LibreWeb-admin-1.0.4.oxt ├── LibreWeb-user-1.0.3.oxt ├── LibreWeb-user-1.0.4.oxt ├── LibreWeb ├── Images │ ├── About_16.png │ ├── About_26.png │ ├── Settings_16.png │ ├── Settings_26.png │ ├── extensionIcon.png │ ├── extensionLogo.png │ ├── Start_Service_16.png │ ├── Start_Service_26.png │ ├── Support_Forum_16.png │ ├── Support_Forum_26.png │ ├── Check_SSL_Module_16.png │ ├── Check_SSL_Module_26.png │ ├── Check_For_Updates_16.png │ ├── Check_For_Updates_26.png │ ├── Download_Help_File_16.png │ ├── Download_Help_File_26.png │ ├── Export_Web_Settings_16.png │ ├── Export_Web_Settings_26.png │ ├── Import_Web_Settings_16.png │ ├── Import_Web_Settings_26.png │ └── LibreWeb_Icon.svg ├── pythonpath │ ├── parsermodule.py │ ├── settings.py │ ├── dialog.py │ ├── messagebox.py │ ├── savemodule.py │ ├── importexport.py │ ├── dialogsettings.py │ ├── listeners.py │ └── tools.py └── main.py └── .gitignore /Help.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladboscaneanu/LibreWeb/HEAD/Help.pdf -------------------------------------------------------------------------------- /LibreWeb-admin-1.0.3.oxt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladboscaneanu/LibreWeb/HEAD/LibreWeb-admin-1.0.3.oxt -------------------------------------------------------------------------------- /LibreWeb-admin-1.0.4.oxt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladboscaneanu/LibreWeb/HEAD/LibreWeb-admin-1.0.4.oxt -------------------------------------------------------------------------------- /LibreWeb-user-1.0.3.oxt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladboscaneanu/LibreWeb/HEAD/LibreWeb-user-1.0.3.oxt -------------------------------------------------------------------------------- /LibreWeb-user-1.0.4.oxt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladboscaneanu/LibreWeb/HEAD/LibreWeb-user-1.0.4.oxt -------------------------------------------------------------------------------- /LibreWeb/Images/About_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladboscaneanu/LibreWeb/HEAD/LibreWeb/Images/About_16.png -------------------------------------------------------------------------------- /LibreWeb/Images/About_26.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladboscaneanu/LibreWeb/HEAD/LibreWeb/Images/About_26.png -------------------------------------------------------------------------------- /LibreWeb/Images/Settings_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladboscaneanu/LibreWeb/HEAD/LibreWeb/Images/Settings_16.png -------------------------------------------------------------------------------- /LibreWeb/Images/Settings_26.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladboscaneanu/LibreWeb/HEAD/LibreWeb/Images/Settings_26.png -------------------------------------------------------------------------------- /LibreWeb/Images/extensionIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladboscaneanu/LibreWeb/HEAD/LibreWeb/Images/extensionIcon.png -------------------------------------------------------------------------------- /LibreWeb/Images/extensionLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladboscaneanu/LibreWeb/HEAD/LibreWeb/Images/extensionLogo.png -------------------------------------------------------------------------------- /LibreWeb/Images/Start_Service_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladboscaneanu/LibreWeb/HEAD/LibreWeb/Images/Start_Service_16.png -------------------------------------------------------------------------------- /LibreWeb/Images/Start_Service_26.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladboscaneanu/LibreWeb/HEAD/LibreWeb/Images/Start_Service_26.png -------------------------------------------------------------------------------- /LibreWeb/Images/Support_Forum_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladboscaneanu/LibreWeb/HEAD/LibreWeb/Images/Support_Forum_16.png -------------------------------------------------------------------------------- /LibreWeb/Images/Support_Forum_26.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladboscaneanu/LibreWeb/HEAD/LibreWeb/Images/Support_Forum_26.png -------------------------------------------------------------------------------- /LibreWeb/Images/Check_SSL_Module_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladboscaneanu/LibreWeb/HEAD/LibreWeb/Images/Check_SSL_Module_16.png -------------------------------------------------------------------------------- /LibreWeb/Images/Check_SSL_Module_26.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladboscaneanu/LibreWeb/HEAD/LibreWeb/Images/Check_SSL_Module_26.png -------------------------------------------------------------------------------- /LibreWeb/Images/Check_For_Updates_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladboscaneanu/LibreWeb/HEAD/LibreWeb/Images/Check_For_Updates_16.png -------------------------------------------------------------------------------- /LibreWeb/Images/Check_For_Updates_26.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladboscaneanu/LibreWeb/HEAD/LibreWeb/Images/Check_For_Updates_26.png -------------------------------------------------------------------------------- /LibreWeb/Images/Download_Help_File_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladboscaneanu/LibreWeb/HEAD/LibreWeb/Images/Download_Help_File_16.png -------------------------------------------------------------------------------- /LibreWeb/Images/Download_Help_File_26.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladboscaneanu/LibreWeb/HEAD/LibreWeb/Images/Download_Help_File_26.png -------------------------------------------------------------------------------- /LibreWeb/Images/Export_Web_Settings_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladboscaneanu/LibreWeb/HEAD/LibreWeb/Images/Export_Web_Settings_16.png -------------------------------------------------------------------------------- /LibreWeb/Images/Export_Web_Settings_26.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladboscaneanu/LibreWeb/HEAD/LibreWeb/Images/Export_Web_Settings_26.png -------------------------------------------------------------------------------- /LibreWeb/Images/Import_Web_Settings_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladboscaneanu/LibreWeb/HEAD/LibreWeb/Images/Import_Web_Settings_16.png -------------------------------------------------------------------------------- /LibreWeb/Images/Import_Web_Settings_26.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladboscaneanu/LibreWeb/HEAD/LibreWeb/Images/Import_Web_Settings_26.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | * .pyc 2 | __pycache__ 3 | myvenv 4 | .idea 5 | .git 6 | db.sqlite3 7 | LibreWeb.odt 8 | To Do list.odt 9 | desktop.ini 10 | Licenza.odt 11 | .gitignore 12 | Project's structure.odt 13 | Test document.ods 14 | .~lock.Test document.ods# 15 | Tools -------------------------------------------------------------------------------- /LibreWeb/pythonpath/parsermodule.py: -------------------------------------------------------------------------------- 1 | # parser module of LibreWeb project 2 | 3 | from html.parser import HTMLParser 4 | 5 | 6 | class LibreWebParser(HTMLParser): 7 | def __init__(self, target_tag): 8 | ''' Please select a target_tag 9 | for your web page. 10 | Don't forget to use the feed() function.''' 11 | HTMLParser.__init__(self) 12 | self.targetTag = target_tag 13 | self.targetFound = False 14 | self.collectedData = [] 15 | 16 | def handle_starttag(self, tag, attrs): 17 | self.targetFound = False 18 | if tag == self.targetTag: 19 | self.targetFound = True 20 | 21 | def handle_endtag(self, tag): 22 | if tag == self.targetTag: 23 | self.targetFound = False 24 | 25 | def handle_data(self, data): 26 | if self.targetFound: 27 | if isinstance(data, str): 28 | data = data.strip() 29 | self.collectedData.append(data) 30 | -------------------------------------------------------------------------------- /LibreWeb/pythonpath/settings.py: -------------------------------------------------------------------------------- 1 | # settings module 2 | 3 | # Accepted tags 4 | tags = ["h1", "h2", "h3", "h4", "h5", "h6", 5 | "b", "p", "a", "div", "em", "span", "strong", 6 | "i", "em", "mark", "q", "blockquote", "abbr", 7 | "address", "cite", "th", "td", "li"] 8 | 9 | # Support url forum 10 | support_forum = "https://forum.openoffice.org/en/forum/viewtopic.php?f=47&t=88724" 11 | 12 | # save file manipulations 13 | save_file_name = "libreweb.data" 14 | save_dir_name = "LibreWebSettings" 15 | # collected data for listeners 16 | _collected_items = [] 17 | # collection of update sites 18 | update_source = ( 19 | ("https://extensions.libreoffice.org/extensions/libreweb", "span"), 20 | ("https://github.com/vladboscaneanu/LibreWeb", "a") 21 | ) 22 | # libreweb.settings 23 | settings_file = "libreweb.settings" 24 | # last update key 25 | last_update_key = "LAST_UPDATE_VERIFY" 26 | # check update period 27 | check_update_period= 7 28 | #url of help file 29 | url_help_file="https://github.com/vladboscaneanu/LibreWeb" 30 | -------------------------------------------------------------------------------- /LibreWeb/pythonpath/dialog.py: -------------------------------------------------------------------------------- 1 | # This is a part of LibreWeb project 2 | 3 | 4 | class DialogModel: 5 | '''A class that create a dialog model''' 6 | 7 | def __init__(self, ctx, dlg_model_props): 8 | self.model = ctx.getServiceManager().createInstanceWithContext( 9 | "com.sun.star.awt.UnoControlDialogModel", ctx) 10 | for key, value in dlg_model_props.items(): 11 | setattr(self.model, key, value) 12 | 13 | def add_elements(self, args): 14 | '''args = (name=String, type=String, props={}), ''' 15 | for elem in args: 16 | item = self.model.createInstance('com.sun.star.awt.UnoControl' + elem[1] + "Model") 17 | for key, value in elem[2].items(): 18 | setattr(item, key, value) 19 | self.model.insertByName(elem[0], item) 20 | 21 | 22 | def get_dialog_control(ctx, dialog_model): 23 | dialog_control = ctx.getServiceManager().createInstance("com.sun.star.awt.UnoControlDialog") 24 | dialog_control.setModel(dialog_model) 25 | toolkit = ctx.getServiceManager().createInstance("com.sun.star.awt.ExtToolkit") 26 | dialog_control.setVisible(False) 27 | dialog_control.createPeer(toolkit, None) 28 | return dialog_control 29 | -------------------------------------------------------------------------------- /LibreWeb/pythonpath/messagebox.py: -------------------------------------------------------------------------------- 1 | # This is a part of LibreWeb project 2 | ################################### 3 | #import uno 4 | 5 | from com.sun.star.awt.MessageBoxType import MESSAGEBOX, INFOBOX, WARNINGBOX, ERRORBOX, QUERYBOX 6 | from com.sun.star.awt.MessageBoxResults import OK, YES, NO, CANCEL 7 | from com.sun.star.awt.MessageBoxButtons import BUTTONS_OK, BUTTONS_OK_CANCEL, BUTTONS_YES_NO, \ 8 | BUTTONS_YES_NO_CANCEL, BUTTONS_RETRY_CANCEL, \ 9 | BUTTONS_ABORT_IGNORE_RETRY 10 | 11 | 12 | # initialisate class 13 | 14 | 15 | class MsgBox(): 16 | def __init__(self, desktop): 17 | '''As an argument, give the XSCRIPTCONTEXT.getDesktop()''' 18 | 19 | self.parentwin = desktop.getCurrentComponent() 20 | self.parentwin = self.parentwin.CurrentController 21 | self.parentwin = self.parentwin.Frame.ContainerWindow 22 | self.toolkit = self.parentwin.getToolkit() 23 | 24 | def show(self, boxText="Your text", boxTitle="Your title", boxType=MESSAGEBOX, buttonType=BUTTONS_OK): 25 | '''Change to your pleasure boxType, buttonType, boxTitle and boxText ''' 26 | 27 | box = self.toolkit.createMessageBox(self.parentwin, boxType, buttonType, boxTitle, boxText) 28 | return box.execute() 29 | -------------------------------------------------------------------------------- /LibreWeb/pythonpath/savemodule.py: -------------------------------------------------------------------------------- 1 | # this is a part of LibreWeb project 2 | 3 | import pickle 4 | 5 | 6 | class LibreWebPickle: 7 | def __init__(self, name="libreweb.data"): 8 | '''Set your name for saved/created file''' 9 | self.name = name 10 | 11 | def save(self, my_variable): 12 | with open(self.name, "wb") as file: 13 | pickle.dump(my_variable, file) 14 | file.close() 15 | 16 | def read(self): 17 | with open(self.name, "rb") as file: 18 | return pickle.load(file) 19 | 20 | 21 | def insert_data(docs, doc_name, sheet_name, url, tag, array_nr, cell_address, insert_as): 22 | 23 | if doc_name in docs: 24 | target = docs[doc_name] 25 | if sheet_name in target: 26 | target = target[sheet_name] 27 | if url in target: 28 | target = target[url] 29 | if tag in target: 30 | docs[doc_name][sheet_name][url][tag][cell_address] = [array_nr, insert_as] 31 | else: 32 | docs[doc_name][sheet_name][url][tag] = {cell_address: [array_nr, insert_as]} 33 | else: 34 | docs[doc_name][sheet_name][url] = {tag: {cell_address: [array_nr, insert_as]}} 35 | else: 36 | docs[doc_name][sheet_name] = {url: {tag: {cell_address: [array_nr, insert_as]}}} 37 | else: 38 | docs[doc_name] = {sheet_name: {url: {tag: {cell_address: [array_nr, insert_as]}}}} 39 | return docs 40 | -------------------------------------------------------------------------------- /LibreWeb/pythonpath/importexport.py: -------------------------------------------------------------------------------- 1 | class ImportWebData: 2 | '''Import web settings''' 3 | 4 | def __init__(self, ctx, msgbox, move_to): 5 | from settings import save_file_name 6 | self.msg_box = msgbox 7 | self.destination = move_to 8 | self.dialog = ctx.ServiceManager.createInstance("com.sun.star.ui.dialogs.FilePicker") 9 | self.dialog.appendFilter("A LibreWeb file", save_file_name) 10 | self.dialog.setMultiSelectionMode(False) 11 | 12 | def import_web_data(self): 13 | '''Shows the dialog ,pick a file, then 14 | import entire file.''' 15 | self.dialog.execute() 16 | file = self.dialog.getSelectedFiles() 17 | if file: 18 | from shutil import copyfile 19 | import os.path 20 | from unohelper import fileUrlToSystemPath 21 | from messagebox import BUTTONS_OK_CANCEL, WARNINGBOX, INFOBOX 22 | file_url = fileUrlToSystemPath(file[0]) 23 | try: 24 | if os.path.isfile(self.destination): 25 | answer = self.msg_box.show("The file exists, replace?", "Warning", WARNINGBOX, BUTTONS_OK_CANCEL) 26 | if answer: 27 | copyfile(file_url, self.destination) 28 | self.msg_box.show("Web settings imported successfully", "Message", INFOBOX) 29 | except OSError as error: 30 | if error.errno == 13: 31 | self.msg_box.show("You have no rights to create settings file", 32 | "Attention", WARNINGBOX) 33 | 34 | 35 | class ExportWebData: 36 | '''Export web settings''' 37 | 38 | def __init__(self, ctx, msgbox, move_from): 39 | self.move_from = move_from 40 | self.msg_box = msgbox 41 | self.dialog = ctx.ServiceManager.createInstance("com.sun.star.ui.dialogs.FolderPicker") 42 | 43 | def export_web_data(self): 44 | '''Pick a directory,then export web settings''' 45 | self.dialog.execute() 46 | folder = self.dialog.getDirectory() 47 | if folder: 48 | from shutil import copy 49 | import os.path 50 | from unohelper import fileUrlToSystemPath 51 | from settings import save_file_name 52 | from messagebox import BUTTONS_OK_CANCEL, WARNINGBOX, INFOBOX 53 | folder_url = fileUrlToSystemPath(folder) 54 | file = os.path.join(folder_url, save_file_name) 55 | try: 56 | if os.path.isfile(file): 57 | answer = self.msg_box.show("The file exists, replace?", "Warning", WARNINGBOX, BUTTONS_OK_CANCEL) 58 | if answer: 59 | copy(self.move_from, folder_url) 60 | self.msg_box.show("Web settings exported successfully", "Message", INFOBOX) 61 | else: 62 | copy(self.move_from, folder_url) 63 | self.msg_box.show("Web settings exported successfully", "Message", INFOBOX) 64 | except OSError as error: 65 | if error.errno == 13: 66 | self.msg_box.show("You have no rights to save here file ", 67 | "Attention", WARNINGBOX) 68 | -------------------------------------------------------------------------------- /LibreWeb/pythonpath/dialogsettings.py: -------------------------------------------------------------------------------- 1 | '''Set the Settings dialog''' 2 | dialog_model_props = {"PositionX": 0, "PositionY": 0, 3 | "Width": 400, "Height": 300, 4 | "Title": "LibreWeb Settings"} 5 | 6 | # dialog items general settings 7 | 8 | # DocumentName 9 | DocumentName_props = {"Border": 3, "FontHeight": 15, "PositionX": 10, 10 | "PositionY": 0, "Width": 380, "Height": 20, 11 | "Align": 1, "VerticalAlign": 1} 12 | 13 | # URL TextBox 14 | URLTextBox_props = {"Border": 3, "FontHeight": 15, "PositionX": 10, 15 | "PositionY": 30, "Width": 380, "Height": 20} 16 | 17 | # Sheet Control 18 | SheetControl_props = {"PositionX": 0, "PositionY": 60, "Width": 200, 19 | "Height": 90, "Label": "Sheet Control", "FontHeight": 10} 20 | 21 | # Tag Control 22 | TagControl_props = {"PositionX": 200, "PositionY": 60, "Width": 200, 23 | "Height": 90, "Label": "Tag Control", "FontHeight": 10} 24 | 25 | # SheetsListBox 26 | SheetName_props = {"PositionX": 10, "PositionY": 80, "Width": 180, 27 | "Height": 20, "Border": 3, 28 | "VerticalAlign": 1, "Align": 1, 29 | "FontHeight": 15} 30 | 31 | # ElementToSearch 32 | ElementToSearch_props = {"Border": 3, "FontHeight": 15, "PositionX": 210, 33 | "PositionY": 80, "Width": 180, "Align": 1, 34 | "Height": 20} 35 | 36 | # ColumnListBox 37 | 38 | Columns_props = {"Border": 3, "FontHeight": 15, "PositionX": 10, 39 | "PositionY": 110, "Width": 80, "Height": 20, "Align": 1, 40 | "Dropdown": True} 41 | 42 | # RowListBox 43 | 44 | Rows_props = {"Border": 3, "FontHeight": 15, "PositionX": 110, 45 | "PositionY": 110, "Width": 80, "Height": 20, "Dropdown": True, 46 | "Align": 1} 47 | 48 | # TagCountListBox 49 | 50 | TagCount_props = {"Border": 3, "Align": 1, "Dropdown": True, "FontHeight": 15, 51 | "PositionX": 210, "PositionY": 110, "Width": 180, 52 | "Height": 20, "Enabled": False} 53 | 54 | # TagResult 55 | 56 | TagResult_props = {"Label": "Tag Result", "FontHeight": 10, "PositionX": 0, 57 | "PositionY": 160, "Width": 400, "Height": 80} 58 | 59 | # ResultLabel 60 | 61 | ResultLabel_props = {"Label": "No data.", "Align": 1, "FontHeight": 15, "Border": 3, 62 | "Width": 380, "Height": 60, "PositionX": 10, "PositionY": 170, 63 | "VerticalAlign": 1, "MultiLine": True} 64 | 65 | # Control Panel 66 | 67 | ControlPanel_props = {"Label": "Control Panel", "FontHeight": 10, "PositionX": 0, 68 | "PositionY": 250, "Width": 400, "Height": 50} 69 | 70 | # CheckURLButton 71 | 72 | CheckURL_props = {"Label": "Check URL", "Align": 1, "FontHeight": 15, "Width": 80, 73 | "Height": 20, "PositionX": 10, "PositionY": 270, 74 | "VerticalAlign": 1} 75 | 76 | # SaveAs 77 | 78 | SaveAs_props = {"Label": "Save as:", "FontHeight": 15, "Align": 1, "Border": 0, 79 | "Width": 50, "Height": 20, "PositionX": 110, "PositionY": 270, 80 | "VerticalAlign": 1} 81 | # DataType 82 | DataType_props = {"Align": 1, "Dropdown": True, "Width": 120, 83 | "Height": 20, "PositionX": 170, "PositionY": 270, 84 | "Border": 3, "FontHeight": 15, 85 | "StringItemList": ["String", "Value"]} 86 | 87 | # SaveButton 88 | 89 | SaveButton_props = {"Align": 1, "Label": "Save", "FontHeight": 15, "Width": 80, 90 | "Height": 20, "PositionX": 310, "PositionY": 270, 91 | "VerticalAlign": 1, "Enabled": True} 92 | 93 | # the final variable 94 | dialog_items = (("DocumentName", "FixedText", DocumentName_props), 95 | ("URLTextBox", "Edit", URLTextBox_props), 96 | ("SheetsControl", "GroupBox", SheetControl_props), 97 | ("TagControl", "GroupBox", TagControl_props), 98 | ("SheetName", "FixedText", SheetName_props), 99 | ("ElementToSearch", "Edit", ElementToSearch_props), 100 | ("ColumnListBox", "ListBox", Columns_props), 101 | ("RowListBox", "ListBox", Rows_props), 102 | ("TagCountListBox", "ListBox", TagCount_props), 103 | ("TagResult", "GroupBox", TagResult_props), 104 | ("ResultLabel", "FixedText", ResultLabel_props), 105 | ("ControlPanel", "GroupBox", ControlPanel_props), 106 | ("CheckURLButton", "Button", CheckURL_props), 107 | ("SaveAs", "FixedText", SaveAs_props), 108 | ("DataTypeListBox", "ListBox", DataType_props), 109 | ("SaveButton", "Button", SaveButton_props) 110 | ) 111 | -------------------------------------------------------------------------------- /LibreWeb/pythonpath/listeners.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | import unohelper 4 | from com.sun.star.awt import XActionListener 5 | from settings import _collected_items 6 | 7 | collected_items = _collected_items 8 | 9 | 10 | class TagCountListener(unohelper.Base, XActionListener): 11 | def __init__(self, tag_count_control, result_label_control): 12 | self.TagCount_control = tag_count_control 13 | self.ResultLabel_control = result_label_control 14 | 15 | def actionPerformed(self, event): 16 | item_position = self.TagCount_control.getSelectedItemPos() 17 | if item_position >= 0: 18 | global collected_items 19 | self.ResultLabel_control.setText(collected_items[item_position]) 20 | 21 | def disposing(self, event): 22 | pass 23 | 24 | 25 | # -- SaveButtonListener 26 | class SaveButtonListener(unohelper.Base, XActionListener): 27 | def __init__(self, msg_box, save_file, document, 28 | ColumnListBox_ctrl, RowListBox_ctrl, 29 | TagCount_ctrl, ElementToSearch_ctrl, 30 | URLTextBox_ctrl, DataTypeListBox_ctrl): 31 | from tools import open_url 32 | from savemodule import LibreWebPickle, insert_data 33 | from settings import tags 34 | 35 | self.open_url = open_url 36 | self.insert_data = insert_data 37 | self.doc = document 38 | self.ColumnListBox_ctrl = ColumnListBox_ctrl 39 | self.RowList_ctrl = RowListBox_ctrl 40 | self.TagCount_ctrl = TagCount_ctrl 41 | self.ElementToSearch_ctrl = ElementToSearch_ctrl 42 | self.URLTextBox_ctrl = URLTextBox_ctrl 43 | self.DataTypeListBox_ctrl = DataTypeListBox_ctrl 44 | self.sv_file = save_file 45 | 46 | self.save_ins = LibreWebPickle(self.sv_file) 47 | self.msg_box = msg_box 48 | 49 | self.tags = tags 50 | 51 | def actionPerformed(self, event): 52 | # Check if file for save data exists,otherwise let's create 53 | 54 | if os.path.isfile(self.sv_file): 55 | try: 56 | if self.ColumnListBox_ctrl.getSelectedItemPos() == -1: 57 | self.msg_box.show("Please select a column", "Error", 2) 58 | elif self.RowList_ctrl.getSelectedItemPos() == -1: 59 | self.msg_box.show("Please select a row", "Error", 2) 60 | elif self.TagCount_ctrl.getSelectedItemPos() == -1: 61 | self.msg_box.show("Please select a tag number", "Error", 2) 62 | elif self.ElementToSearch_ctrl.Text.strip() not in self.tags: 63 | self.msg_box.show("Not supported tag", "Attention", 2) 64 | elif not self.open_url(self.URLTextBox_ctrl.Text.strip(), self.msg_box): 65 | pass 66 | elif self.DataTypeListBox_ctrl.getSelectedItemPos() == -1: 67 | self.msg_box.show("Please select type of inserted data", 68 | "Attention", 2) 69 | else: 70 | # start to save our data 71 | docs = self.save_ins.read() 72 | sheet_name = self.doc.getCurrentController().ActiveSheet.Name 73 | url = self.URLTextBox_ctrl.Text 74 | tag = self.ElementToSearch_ctrl.Text 75 | array_nr = self.TagCount_ctrl.getSelectedItemPos() 76 | column = str(self.ColumnListBox_ctrl.getSelectedItem()) 77 | row = str(self.RowList_ctrl.getSelectedItem()) 78 | cell_address = column + row 79 | insert_as = self.DataTypeListBox_ctrl.getSelectedItem() 80 | # insert_data is a function, that create our new entry in savefile 81 | doc_title = self.doc.getTitle() 82 | new_docs = self.insert_data(docs, doc_title, sheet_name, url, tag, array_nr, cell_address, 83 | insert_as) 84 | # then save all data 85 | self.save_ins.save(new_docs) 86 | self.msg_box.show("Operation Completed!", "Well done", 1) 87 | except OSError as error: 88 | if error.errno == 13: 89 | self.msg_box.show("You have no rights to insert new data", 90 | "Attention", 2) 91 | 92 | def disposing(self, event): 93 | pass 94 | 95 | 96 | class CheckURLListener(unohelper.Base, XActionListener): 97 | def __init__(self, msg_box, 98 | ElementToSearch_ctrl, URLTextBox_ctrl, 99 | TagCount_ctrl, ResultLabel_ctrl): 100 | from settings import tags 101 | self.tags = tags 102 | self.msg_box = msg_box 103 | self.URLTextBox_ctrl = URLTextBox_ctrl 104 | self.ElementToSearch_ctrl = ElementToSearch_ctrl 105 | self.TagCount_ctrl = TagCount_ctrl 106 | self.ResultLabel_ctrl = ResultLabel_ctrl 107 | 108 | def actionPerformed(self, event): 109 | from tools import open_url 110 | target_tag = self.ElementToSearch_ctrl.Text.strip() 111 | target_url = self.URLTextBox_ctrl.Text.strip() 112 | global collected_items 113 | # -- clean previous items 114 | if collected_items: 115 | self.TagCount_ctrl.removeItems(0, len(collected_items)) 116 | self.TagCount_ctrl.setEnable(False) 117 | self.ResultLabel_ctrl.setText("No data.") 118 | if target_tag in self.tags: 119 | result = open_url(target_url, self.msg_box) 120 | if result: 121 | from parsermodule import LibreWebParser 122 | my_parser = LibreWebParser(target_tag) 123 | my_parser.feed(result) 124 | collected_items = my_parser.collectedData 125 | if collected_items: 126 | self.TagCount_ctrl.addItems([x for x in range(0, len(collected_items))], 0) 127 | self.TagCount_ctrl.setEnable(True) 128 | else: 129 | self.msg_box.show("Not supported tag!", "Attention!", 2) 130 | self.msg_box.show("Operation completed.", "Message",1) 131 | def disposing(self, event): 132 | pass 133 | -------------------------------------------------------------------------------- /LibreWeb/main.py: -------------------------------------------------------------------------------- 1 | # 2 | 3 | ctx = XSCRIPTCONTEXT.getComponentContext() 4 | smgr = ctx.ServiceManager 5 | desktop = XSCRIPTCONTEXT.getDesktop() 6 | document = XSCRIPTCONTEXT.getDocument() 7 | from messagebox import MsgBox, INFOBOX, WARNINGBOX, QUERYBOX, BUTTONS_OK_CANCEL, OK 8 | 9 | msg_box = MsgBox(desktop) 10 | 11 | 12 | def Set_Data(*args): 13 | from dialogsettings import dialog_model_props, dialog_items 14 | from dialog import DialogModel, get_dialog_control 15 | from listeners import TagCountListener, SaveButtonListener, CheckURLListener 16 | 17 | dlg_instance = DialogModel(ctx, dialog_model_props) 18 | dlg_instance.add_elements(dialog_items) 19 | dlg_model = dlg_instance.model 20 | dlg_control = get_dialog_control(ctx, dlg_model) 21 | 22 | # getting items control 23 | 24 | URLTextBox_control = dlg_control.getControl("URLTextBox") 25 | ElementToSearch_control = dlg_control.getControl("ElementToSearch") 26 | TagCount_control = dlg_control.getControl("TagCountListBox") 27 | CheckURL_control = dlg_control.getControl("CheckURLButton") 28 | ResultLabel_control = dlg_control.getControl("ResultLabel") 29 | DocumentName_control = dlg_control.getControl("DocumentName") 30 | SheetName_control = dlg_control.getControl("SheetName") 31 | SaveButton_control = dlg_control.getControl("SaveButton") 32 | ColumnListBox_control = dlg_control.getControl("ColumnListBox") 33 | RowListBox_control = dlg_control.getControl("RowListBox") 34 | DataTypeListBox_control = dlg_control.getControl("DataTypeListBox") 35 | # listeners bloc 36 | 37 | TagCount_control.addActionListener(TagCountListener( 38 | TagCount_control, ResultLabel_control 39 | )) 40 | SaveButton_control.addActionListener(SaveButtonListener( 41 | msg_box, smgr, document, 42 | ColumnListBox_control, RowListBox_control, 43 | TagCount_control, ElementToSearch_control, 44 | URLTextBox_control, DataTypeListBox_control 45 | )) 46 | CheckURL_control.addActionListener(CheckURLListener( 47 | msg_box, 48 | ElementToSearch_control, 49 | URLTextBox_control, TagCount_control, 50 | ResultLabel_control 51 | )) 52 | 53 | # add some informations at the runtime moment 54 | 55 | # -- Current sheet's name 56 | sheet_name = document.getCurrentController().ActiveSheet.Name 57 | SheetName_control.setText(sheet_name) 58 | DocumentName_control.setText(document.getTitle()) 59 | columns_count = document.CurrentController.ActiveSheet.Columns.ElementNames[:40] 60 | ColumnListBox_control.addItems(columns_count, 0) 61 | rows_count = [x for x in range(1, 41)] 62 | RowListBox_control.addItems(rows_count, 0) 63 | 64 | # -- run dialog 65 | dlg_control.execute() 66 | 67 | 68 | def Start_Service(*args): 69 | from tools import start_service # get_save_file 70 | # save_file = get_save_file(ctx, msg_box) 71 | start_service(smgr, document, msg_box) 72 | 73 | 74 | def Get_Support(*args): 75 | import webbrowser 76 | from settings import support_forum 77 | webbrowser.open(support_forum) 78 | 79 | 80 | def Check_SSL(*args): 81 | '''A function that tries to import ssl module, 82 | shows error on ImportError''' 83 | try: 84 | import ssl 85 | msg_box.show("It seems SSL module works", "Message", INFOBOX) 86 | except ImportError: 87 | msg_box.show("It seems SSL module is broken!", "Attention", WARNINGBOX) 88 | 89 | 90 | def Import_Web_Settings(*args): 91 | from importexport import ImportWebData 92 | from tools import get_local_data 93 | to_file = get_local_data(ctx) 94 | if to_file: 95 | to_file_instance = ImportWebData(ctx, msg_box, to_file) 96 | to_file_instance.import_web_data() 97 | 98 | 99 | def Export_Web_Settings(*args): 100 | from importexport import ExportWebData 101 | from tools import get_local_data 102 | move_from = get_local_data(ctx) 103 | if move_from: 104 | move_from_instance = ExportWebData(ctx, msg_box, move_from) 105 | move_from_instance.export_web_data() 106 | 107 | 108 | def Verify_Update(*args): 109 | from tools import verify_update 110 | if not (verify_update(ctx, msg_box)): 111 | msg_box.show("No update available", "Message", INFOBOX) 112 | 113 | 114 | def Read_Help(*args): 115 | ''' Read incorporated help ''' 116 | from tools import get_help_file 117 | from settings import extension_id, help_file 118 | get_help_file(smgr, desktop, extension_id, help_file) 119 | 120 | 121 | def Donate_Paypal(*args): 122 | from settings import url_paypal 123 | import webbrowser 124 | webbrowser.open(url_paypal) 125 | 126 | 127 | def About(*args): 128 | '''Getting current version''' 129 | from tools import get_cur_version 130 | current_version = get_cur_version(ctx) 131 | msg_box.show("An internet tool for LibreOffice.\n" + 132 | "Current version : " + current_version, "LibreWeb", INFOBOX) 133 | 134 | 135 | def Send_Email(*args): 136 | '''Send me an email, using a client''' 137 | from messagebox import BUTTONS_OK_CANCEL, CANCEL, QUERYBOX 138 | from dialog import DialogModel, get_dialog_control 139 | from dialogsendemail import dialog_model_props, dialog_items 140 | from listeners import SendEmailButtonListener 141 | if msg_box.show( 142 | "For a correct work of this feature \n you must have an email client.\n Continue ?", 143 | "Email client ", QUERYBOX, BUTTONS_OK_CANCEL) == CANCEL: 144 | return 145 | # create dialog 146 | dialog_instance = DialogModel(ctx, dialog_model_props) 147 | dialog_instance.add_elements(dialog_items) 148 | dialog_control = get_dialog_control(ctx, dialog_instance.model) 149 | SendButton_control = dialog_control.getControl("SendButton") 150 | Subject_control = dialog_control.getControl("Subject") 151 | Message_control = dialog_control.getControl("Message") 152 | SendButton_control.addActionListener( 153 | SendEmailButtonListener(ctx, Subject_control, Message_control, msg_box) 154 | ) 155 | dialog_control.execute() 156 | 157 | 158 | def Import_Old_Data(*args): 159 | import os 160 | from tools import get_local_data 161 | old_storage = get_local_data(ctx) 162 | if os.path.isfile(old_storage): 163 | from savemodule import LibreWebPickle 164 | old_instance = LibreWebPickle(old_storage) 165 | old_data = old_instance.read() 166 | if document.Title in old_data: 167 | if msg_box.show("Would you like to move local data to document?", 168 | "Please confirm", QUERYBOX, BUTTONS_OK_CANCEL) == OK: 169 | from docsave import save_file, check_save_file 170 | if check_save_file(document): 171 | if msg_box.show("Document storage data will be rewritten, continue?", 172 | "Please confirm", QUERYBOX, BUTTONS_OK_CANCEL) == OK: 173 | save_file(smgr, document, old_data[document.Title]) 174 | del old_data[document.Title] 175 | old_instance.save(old_data) 176 | msg_box.show( 177 | "Local data was imported correctly", "Message", INFOBOX) 178 | 179 | else: 180 | save_file(smgr, document, old_data[document.Title]) 181 | del old_data[document.Title] 182 | old_instance.save(old_data) 183 | msg_box.show( 184 | "Local data was imported correctly", "Message", INFOBOX) 185 | else: 186 | msg_box.show("No local data found for this document", 187 | "Message", INFOBOX) 188 | else: 189 | msg_box.show("No local data found", "Message", INFOBOX) 190 | 191 | 192 | def cancel_me(*args): 193 | from docsave import read_file 194 | stored_data = read_file(smgr, document) 195 | msg_box.show(str(stored_data)) 196 | # End of script 197 | -------------------------------------------------------------------------------- /LibreWeb/pythonpath/tools.py: -------------------------------------------------------------------------------- 1 | # This is a part of LibreWeb project 2 | 3 | 4 | def dir_as_string(argument): 5 | string = "" 6 | for i in dir(argument): 7 | string = string + i + " -- " 8 | return string 9 | 10 | 11 | def get_save_dir(ctx): 12 | '''Returns the save file directory, if don't 13 | exists, it will be created''' 14 | from settings import save_dir_name 15 | import unohelper 16 | import os 17 | _path = ctx.ServiceManager.createInstance("com.sun.star.util.PathSubstitution") 18 | user_dir = _path.getSubstituteVariableValue("$(user)") 19 | user_dir = unohelper.fileUrlToSystemPath(user_dir) 20 | save_dir = os.path.join(user_dir, save_dir_name) 21 | if save_dir_name not in os.listdir(user_dir): 22 | os.mkdir(save_dir) 23 | return save_dir 24 | 25 | 26 | def get_save_file(ctx, msg_box): 27 | '''Returns the save file ''' 28 | from settings import save_file_name 29 | import os.path 30 | file_url = os.path.join(get_save_dir(ctx), save_file_name) 31 | if not os.path.isfile(file_url): 32 | try: 33 | from savemodule import LibreWebPickle 34 | file = LibreWebPickle(file_url) 35 | file.save({}) 36 | except OSError as error: 37 | if error.errno == 13: 38 | msg_box.show("You have no rights to create settings file", 39 | "Attention, 2") 40 | return file_url 41 | 42 | 43 | def get_settings_file(ctx, msg_box): 44 | '''Returns the settings file''' 45 | from settings import settings_file 46 | import os.path 47 | file_url = os.path.join(get_save_dir(ctx), settings_file) 48 | if not os.path.isfile(file_url): 49 | try: 50 | from savemodule import LibreWebPickle 51 | file = LibreWebPickle(file_url) 52 | file.save({}) 53 | except OSError as error: 54 | if error.errno == 13: 55 | msg_box.show("You have no rights to create settings file", 56 | "Attention, 2") 57 | return file_url 58 | 59 | 60 | def open_url(url, message_box, default_decoding="utf-8"): 61 | '''Function that try to open,read and decode a web site 62 | ''' 63 | import urllib.error 64 | import urllib.request 65 | try: 66 | result = urllib.request.urlopen(url).read().decode(default_decoding) 67 | return result 68 | except UnicodeDecodeError: 69 | message_box.show("Site is not utf-8 encoded", "Error", 2) 70 | 71 | except ValueError as error: 72 | message_box.show("Invalid URL", "Attention", 2) 73 | 74 | except urllib.error.URLError: 75 | message_box.show("Site not reachable or internet connection is missing", 76 | "Attention", 2) 77 | 78 | except Exception as error: 79 | str_error = "" 80 | for i in error.args: 81 | str_error = str_error + "\n" + str(i) 82 | message_box.show(str_error, "Attention", 2) 83 | 84 | 85 | def start_service(save_file, document, message_box, *args): 86 | try: 87 | from savemodule import LibreWebPickle 88 | from parsermodule import LibreWebParser 89 | 90 | documents = LibreWebPickle(save_file).read() 91 | doc_title = document.getTitle() 92 | 93 | if doc_title in documents: 94 | sheets = document.Sheets.ElementNames 95 | sheets_list = list(documents[doc_title].keys()) 96 | for sheet_name in sheets_list: 97 | if sheet_name in sheets: 98 | sheet = document.Sheets.getByName(sheet_name) 99 | url_list = list(documents[doc_title][sheet_name].keys()) 100 | for url in url_list: 101 | result = open_url(url, message_box) 102 | if result: 103 | tag_list = list(documents[doc_title][sheet_name][url].keys()) 104 | for tag in tag_list: 105 | my_parser = LibreWebParser(tag) 106 | my_parser.feed(result) 107 | if my_parser.collectedData: 108 | cell_list = list(documents[doc_title][sheet_name][url][tag].keys()) 109 | for cell in cell_list: 110 | cell_items = documents[doc_title][sheet_name][url][tag][cell] 111 | cell_data = my_parser.collectedData[cell_items[0]] 112 | if cell_items[1] == "String": 113 | sheet.getCellRangeByName(cell).setString(cell_data) 114 | elif cell_items[1] == "Value": 115 | sheet.getCellRangeByName(cell).setValue(cell_data) 116 | else: 117 | message_box.show("No valid sheets names found", "Error", 2) 118 | return 119 | 120 | message_box.show("Operation completed.", "Message", 1) 121 | 122 | else: 123 | message_box.show("This document has no saved data,go to Settings", "Attention", 1) 124 | 125 | except FileNotFoundError: 126 | message_box.show("No settings file detected,first save some data!", "Attention", 2) 127 | 128 | 129 | def get_cur_version(ctx): 130 | '''A function that return a string with current extension version''' 131 | ext = ctx.ServiceManager.createInstance( 132 | "com.sun.star.comp.deployment.PackageInformationProvider" 133 | ) 134 | for i in ext.ExtensionList: 135 | if "com.libreweb.web" in i[0]: 136 | return i[1] 137 | 138 | 139 | def get_online_version(): 140 | '''A function that looks for an update on different sites, 141 | like extensions site and github 142 | returns a tuple with 2 args,arg[0] = version nr' 143 | arg[1] = update's web site''' 144 | from parsermodule import LibreWebParser 145 | from settings import update_source as sites 146 | import urllib.request 147 | try: 148 | for arg in sites: 149 | result = urllib.request.urlopen(arg[0]).read().decode() 150 | parser = LibreWebParser(arg[1]) 151 | parser.feed(result) 152 | for elem in parser.collectedData: 153 | if "LibreWeb" and ".oxt" in elem: 154 | return (elem[-9:-4], arg[0]) 155 | except: 156 | pass 157 | 158 | 159 | def _verify_update(ctx, msg_box): 160 | '''Function that asks for download if a new version is 161 | available,if positive answer opens a web page with new version.''' 162 | from messagebox import BUTTONS_OK_CANCEL, OK, QUERYBOX 163 | 164 | online_version = get_online_version() 165 | cur_version = get_cur_version(ctx) 166 | if online_version and online_version[0] > cur_version: 167 | if msg_box.show( 168 | "Would you like to download it?", 169 | "Version " + online_version[0] + " is available", QUERYBOX, BUTTONS_OK_CANCEL) == OK: 170 | import webbrowser 171 | webbrowser.open(online_version[1]) 172 | else: 173 | return False 174 | 175 | def do_update(ctx, msg_box): 176 | '''Function that check date of last update,if greater than 177 | a settings value, does the ''' 178 | from datetime import date 179 | from savemodule import LibreWebPickle 180 | from settings import last_update_key, check_update_period 181 | file_url = get_settings_file(ctx, msg_box) 182 | file = LibreWebPickle(file_url) 183 | file_read = file.read() 184 | today = date.today() 185 | if last_update_key not in file.read().keys(): 186 | _verify_update(ctx, msg_box) 187 | file_read[last_update_key] = today 188 | file.save(file_read) 189 | else: 190 | delta = today - file_read[last_update_key] 191 | if delta.days >= check_update_period: 192 | _verify_update(ctx, msg_box) 193 | file_read[last_update_key] = today 194 | file.save(file_read) 195 | 196 | -------------------------------------------------------------------------------- /LibreWeb/Images/LibreWeb_Icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 24 | 26 | 27 | 29 | image/svg+xml 30 | 32 | 33 | 34 | 35 | 36 | 63 | 65 | 72 | 79 | 84 | 85 | 87 | 90 | 95 | 96 | 97 | 99 | 103 | 104 | 106 | 110 | 111 | 119 | 123 | 127 | 131 | 132 | 134 | 140 | 141 | 144 | 148 | 152 | 157 | 158 | 159 | 160 | 162 | 166 | 167 | 175 | 179 | 183 | 187 | 191 | 195 | 199 | 203 | 207 | 211 | 215 | 219 | 223 | 227 | 231 | 235 | 239 | 243 | 247 | 251 | 255 | 259 | 263 | 267 | 271 | 275 | 279 | 283 | 287 | 291 | 295 | 299 | 303 | 307 | 311 | 315 | 319 | 323 | 327 | 331 | 335 | 339 | 343 | 347 | 351 | 355 | 359 | 363 | 367 | 371 | 375 | 379 | 383 | 387 | 391 | 395 | 399 | 403 | 407 | 411 | 415 | 419 | 423 | 427 | 431 | 435 | 436 | 438 | 442 | 443 | 451 | 455 | 459 | 463 | 467 | 471 | 475 | 479 | 483 | 487 | 491 | 495 | 499 | 503 | 507 | 511 | 515 | 519 | 520 | 522 | 526 | 527 | 535 | 539 | 543 | 547 | 551 | 555 | 559 | 563 | 567 | 571 | 575 | 579 | 583 | 587 | 591 | 595 | 599 | 603 | 607 | 611 | 615 | 619 | 623 | 627 | 631 | 635 | 639 | 643 | 647 | 651 | 655 | 659 | 663 | 667 | 671 | 675 | 679 | 683 | 687 | 691 | 695 | 699 | 703 | 707 | 711 | 715 | 719 | 723 | 727 | 731 | 735 | 739 | 743 | 747 | 751 | 755 | 759 | 763 | 767 | 771 | 775 | 779 | 783 | 787 | 791 | 795 | 799 | 803 | 807 | 811 | 815 | 819 | 823 | 827 | 831 | 835 | 839 | 843 | 847 | 851 | 855 | 859 | 863 | 867 | 871 | 875 | 879 | 883 | 887 | 891 | 895 | 899 | 903 | 907 | 911 | 915 | 919 | 923 | 927 | 931 | 935 | 939 | 943 | 947 | 951 | 955 | 959 | 963 | 967 | 971 | 975 | 979 | 983 | 987 | 991 | 995 | 999 | 1003 | 1007 | 1011 | 1012 | 1014 | 1017 | 1022 | 1023 | 1024 | 1026 | 1030 | 1031 | 1033 | 1037 | 1038 | 1046 | 1050 | 1054 | 1058 | 1059 | 1061 | 1067 | 1068 | 1071 | 1075 | 1079 | 1084 | 1085 | 1086 | 1087 | 1089 | 1095 | 1096 | 1099 | 1104 | 1105 | 1107 | 1110 | 1117 | 1118 | 1119 | 1121 | 1125 | 1126 | 1128 | 1132 | 1133 | 1135 | 1139 | 1140 | 1142 | 1148 | 1149 | 1152 | 1157 | 1158 | 1160 | 1166 | 1167 | 1170 | 1174 | 1178 | 1182 | 1189 | 1190 | 1191 | 1192 | 1193 | 1195 | 1201 | 1202 | 1205 | 1210 | 1211 | 1213 | 1216 | 1223 | 1224 | 1225 | 1227 | 1231 | 1232 | 1234 | 1238 | 1239 | 1241 | 1245 | 1246 | 1248 | 1251 | 1256 | 1257 | 1258 | 1260 | 1264 | 1265 | 1267 | 1271 | 1272 | 1274 | 1278 | 1279 | 1281 | 1285 | 1286 | 1288 | 1292 | 1293 | 1295 | 1299 | 1300 | 1308 | 1312 | 1316 | 1320 | 1324 | 1328 | 1329 | 1331 | 1337 | 1338 | 1341 | 1345 | 1349 | 1353 | 1357 | 1361 | 1365 | 1370 | 1371 | 1372 | 1373 | 1374 | 1375 | 1376 | 1377 | 1379 | 1385 | 1386 | 1389 | 1397 | 1398 | 1400 | 1406 | 1407 | 1410 | 1414 | 1418 | 1422 | 1429 | 1430 | 1431 | 1432 | 1433 | 1435 | 1441 | 1442 | 1445 | 1450 | 1451 | 1453 | 1456 | 1463 | 1464 | 1465 | 1467 | 1471 | 1472 | 1474 | 1478 | 1479 | 1481 | 1485 | 1486 | 1488 | 1491 | 1496 | 1497 | 1498 | 1500 | 1504 | 1505 | 1507 | 1511 | 1512 | 1514 | 1518 | 1519 | 1521 | 1525 | 1526 | 1528 | 1532 | 1533 | 1535 | 1539 | 1540 | 1548 | 1552 | 1556 | 1560 | 1561 | 1563 | 1569 | 1570 | 1573 | 1577 | 1581 | 1585 | 1589 | 1593 | 1597 | 1602 | 1603 | 1604 | 1605 | 1606 | 1607 | 1608 | 1609 | 1611 | 1617 | 1618 | 1621 | 1629 | 1630 | 1632 | 1638 | 1639 | 1642 | 1646 | 1650 | 1654 | 1661 | 1662 | 1663 | 1664 | 1665 | 1667 | 1673 | 1674 | 1677 | 1682 | 1683 | 1685 | 1688 | 1695 | 1696 | 1697 | 1699 | 1703 | 1704 | 1706 | 1710 | 1711 | 1713 | 1717 | 1718 | 1720 | 1723 | 1728 | 1729 | 1730 | 1732 | 1736 | 1737 | 1739 | 1743 | 1744 | 1746 | 1750 | 1751 | 1753 | 1757 | 1758 | 1760 | 1764 | 1765 | 1767 | 1771 | 1772 | 1780 | 1784 | 1788 | 1792 | 1793 | 1795 | 1801 | 1802 | 1805 | 1809 | 1813 | 1817 | 1821 | 1825 | 1829 | 1834 | 1835 | 1836 | 1837 | 1838 | 1839 | 1840 | 1841 | 1843 | 1849 | 1850 | 1853 | 1861 | 1862 | 1864 | 1870 | 1871 | 1874 | 1878 | 1882 | 1886 | 1893 | 1894 | 1895 | 1896 | 1897 | 1899 | 1905 | 1906 | 1909 | 1914 | 1915 | 1917 | 1920 | 1927 | 1928 | 1929 | 1931 | 1935 | 1936 | 1938 | 1942 | 1943 | 1945 | 1949 | 1950 | 1952 | 1955 | 1960 | 1961 | 1962 | 1964 | 1968 | 1969 | 1971 | 1975 | 1976 | 1978 | 1982 | 1983 | 1985 | 1989 | 1990 | 1992 | 1996 | 1997 | 1999 | 2003 | 2004 | 2012 | 2016 | 2020 | 2024 | 2025 | 2027 | 2033 | 2034 | 2037 | 2041 | 2045 | 2049 | 2053 | 2057 | 2061 | 2066 | 2067 | 2068 | 2069 | 2070 | 2071 | 2072 | 2073 | 2075 | 2081 | 2082 | 2085 | 2093 | 2094 | 2096 | 2102 | 2103 | 2106 | 2110 | 2114 | 2118 | 2125 | 2126 | 2127 | 2128 | 2129 | 2131 | 2137 | 2138 | 2141 | 2146 | 2147 | 2149 | 2152 | 2159 | 2160 | 2161 | 2163 | 2167 | 2168 | 2170 | 2174 | 2175 | 2177 | 2181 | 2182 | 2184 | 2187 | 2192 | 2193 | 2194 | 2196 | 2200 | 2201 | 2203 | 2207 | 2208 | 2210 | 2214 | 2215 | 2217 | 2221 | 2222 | 2224 | 2228 | 2229 | 2231 | 2235 | 2236 | 2244 | 2248 | 2252 | 2256 | 2257 | 2259 | 2265 | 2266 | 2269 | 2273 | 2277 | 2281 | 2285 | 2289 | 2293 | 2298 | 2299 | 2300 | 2301 | 2302 | 2303 | 2304 | 2305 | 2307 | 2313 | 2314 | 2317 | 2325 | 2326 | 2328 | 2334 | 2335 | 2338 | 2342 | 2346 | 2350 | 2357 | 2358 | 2359 | 2360 | 2361 | 2363 | 2369 | 2370 | 2373 | 2378 | 2379 | 2381 | 2384 | 2391 | 2392 | 2393 | 2395 | 2399 | 2400 | 2402 | 2406 | 2407 | 2409 | 2413 | 2414 | 2416 | 2419 | 2424 | 2425 | 2426 | 2428 | 2432 | 2433 | 2435 | 2439 | 2440 | 2442 | 2446 | 2447 | 2449 | 2453 | 2454 | 2456 | 2460 | 2461 | 2463 | 2467 | 2468 | 2476 | 2480 | 2484 | 2488 | 2489 | 2491 | 2497 | 2498 | 2501 | 2505 | 2509 | 2513 | 2517 | 2521 | 2525 | 2530 | 2531 | 2532 | 2533 | 2534 | 2535 | 2536 | 2537 | 2539 | 2545 | 2546 | 2549 | 2557 | 2558 | 2560 | 2566 | 2567 | 2570 | 2574 | 2578 | 2582 | 2589 | 2590 | 2591 | 2592 | 2593 | 2595 | 2601 | 2602 | 2605 | 2610 | 2611 | 2613 | 2616 | 2623 | 2624 | 2625 | 2627 | 2631 | 2632 | 2634 | 2638 | 2639 | 2641 | 2645 | 2646 | 2648 | 2651 | 2656 | 2657 | 2658 | 2660 | 2664 | 2665 | 2667 | 2671 | 2672 | 2674 | 2678 | 2679 | 2681 | 2685 | 2686 | 2688 | 2692 | 2693 | 2695 | 2699 | 2700 | 2708 | 2712 | 2716 | 2720 | 2724 | 2725 | 2727 | 2733 | 2734 | 2737 | 2741 | 2745 | 2749 | 2753 | 2757 | 2761 | 2766 | 2767 | 2768 | 2769 | 2770 | 2771 | 2772 | 2773 | 2775 | 2781 | 2782 | 2785 | 2793 | 2794 | 2796 | 2802 | 2803 | 2806 | 2810 | 2814 | 2818 | 2825 | 2826 | 2827 | 2828 | 2829 | 2831 | 2837 | 2838 | 2841 | 2846 | 2847 | 2849 | 2852 | 2859 | 2860 | 2861 | 2863 | 2867 | 2868 | 2870 | 2874 | 2875 | 2877 | 2881 | 2882 | 2884 | 2887 | 2892 | 2893 | 2894 | 2896 | 2900 | 2901 | 2903 | 2907 | 2908 | 2910 | 2914 | 2915 | 2917 | 2921 | 2922 | 2924 | 2928 | 2929 | 2931 | 2935 | 2936 | 2944 | 2948 | 2952 | 2956 | 2957 | 2959 | 2965 | 2966 | 2969 | 2973 | 2977 | 2981 | 2985 | 2989 | 2993 | 2998 | 2999 | 3000 | 3001 | 3002 | 3003 | 3004 | 3005 | 3007 | 3013 | 3014 | 3017 | 3025 | 3026 | 3028 | 3034 | 3035 | 3038 | 3042 | 3046 | 3050 | 3057 | 3058 | 3059 | 3060 | 3061 | 3063 | 3069 | 3070 | 3073 | 3078 | 3079 | 3081 | 3084 | 3091 | 3092 | 3093 | 3095 | 3099 | 3100 | 3102 | 3106 | 3107 | 3109 | 3113 | 3114 | 3116 | 3119 | 3124 | 3125 | 3126 | 3128 | 3132 | 3133 | 3135 | 3139 | 3140 | 3142 | 3146 | 3147 | 3149 | 3153 | 3154 | 3156 | 3160 | 3161 | 3163 | 3167 | 3168 | 3176 | 3180 | 3184 | 3188 | 3189 | 3191 | 3197 | 3198 | 3201 | 3205 | 3209 | 3213 | 3217 | 3221 | 3225 | 3230 | 3231 | 3232 | 3233 | 3234 | 3235 | 3236 | 3237 | 3239 | 3245 | 3246 | 3249 | 3257 | 3258 | 3260 | 3266 | 3267 | 3270 | 3274 | 3278 | 3282 | 3289 | 3290 | 3291 | 3292 | 3293 | 3295 | 3301 | 3302 | 3305 | 3310 | 3311 | 3313 | 3316 | 3323 | 3324 | 3325 | 3327 | 3331 | 3332 | 3334 | 3338 | 3339 | 3341 | 3345 | 3346 | 3348 | 3351 | 3356 | 3357 | 3358 | 3360 | 3364 | 3365 | 3367 | 3371 | 3372 | 3374 | 3378 | 3379 | 3381 | 3385 | 3386 | 3388 | 3392 | 3393 | 3395 | 3399 | 3400 | 3408 | 3412 | 3416 | 3420 | 3421 | 3423 | 3429 | 3430 | 3433 | 3437 | 3441 | 3445 | 3449 | 3453 | 3457 | 3462 | 3463 | 3464 | 3465 | 3466 | 3467 | 3468 | 3469 | 3471 | 3477 | 3478 | 3481 | 3489 | 3490 | 3492 | 3498 | 3499 | 3502 | 3506 | 3510 | 3514 | 3521 | 3522 | 3523 | 3524 | 3525 | 3527 | 3533 | 3534 | 3537 | 3542 | 3543 | 3545 | 3548 | 3555 | 3556 | 3557 | 3559 | 3563 | 3564 | 3566 | 3570 | 3571 | 3573 | 3577 | 3578 | 3580 | 3583 | 3588 | 3589 | 3590 | 3592 | 3596 | 3597 | 3599 | 3603 | 3604 | 3606 | 3610 | 3611 | 3613 | 3617 | 3618 | 3620 | 3624 | 3625 | 3627 | 3631 | 3632 | 3640 | 3644 | 3648 | 3652 | 3653 | 3655 | 3661 | 3662 | 3665 | 3669 | 3673 | 3677 | 3681 | 3685 | 3689 | 3694 | 3695 | 3696 | 3697 | 3698 | 3699 | 3700 | 3701 | 3703 | 3709 | 3710 | 3713 | 3721 | 3722 | 3724 | 3730 | 3731 | 3734 | 3738 | 3742 | 3746 | 3753 | 3754 | 3755 | 3756 | 3757 | 3759 | 3765 | 3766 | 3769 | 3774 | 3775 | 3777 | 3780 | 3787 | 3788 | 3789 | 3791 | 3795 | 3796 | 3798 | 3802 | 3803 | 3805 | 3809 | 3810 | 3812 | 3815 | 3820 | 3821 | 3822 | 3824 | 3828 | 3829 | 3831 | 3835 | 3836 | 3838 | 3842 | 3843 | 3845 | 3849 | 3850 | 3852 | 3856 | 3857 | 3859 | 3863 | 3864 | 3872 | 3876 | 3880 | 3884 | 3885 | 3887 | 3893 | 3894 | 3897 | 3901 | 3905 | 3909 | 3913 | 3917 | 3921 | 3926 | 3927 | 3928 | 3929 | 3930 | 3931 | 3932 | 3933 | 3935 | 3941 | 3942 | 3945 | 3953 | 3954 | 3956 | 3962 | 3963 | 3966 | 3970 | 3974 | 3978 | 3985 | 3986 | 3987 | 3988 | 3989 | 3991 | 3997 | 3998 | 4001 | 4006 | 4007 | 4009 | 4012 | 4019 | 4020 | 4021 | 4023 | 4027 | 4028 | 4030 | 4034 | 4035 | 4037 | 4041 | 4042 | 4044 | 4047 | 4052 | 4053 | 4054 | 4056 | 4060 | 4061 | 4063 | 4067 | 4068 | 4070 | 4074 | 4075 | 4077 | 4081 | 4082 | 4084 | 4088 | 4089 | 4091 | 4095 | 4096 | 4104 | 4108 | 4112 | 4116 | 4120 | 4124 | 4125 | 4127 | 4133 | 4134 | 4137 | 4141 | 4145 | 4149 | 4153 | 4157 | 4161 | 4166 | 4167 | 4168 | 4169 | 4170 | 4171 | 4172 | 4173 | 4175 | 4181 | 4182 | 4185 | 4193 | 4194 | 4196 | 4202 | 4203 | 4206 | 4210 | 4214 | 4218 | 4225 | 4226 | 4227 | 4228 | 4229 | 4231 | 4237 | 4238 | 4241 | 4246 | 4247 | 4249 | 4252 | 4259 | 4260 | 4261 | 4263 | 4267 | 4268 | 4270 | 4274 | 4275 | 4277 | 4281 | 4282 | 4284 | 4287 | 4292 | 4293 | 4294 | 4296 | 4300 | 4301 | 4303 | 4307 | 4308 | 4310 | 4314 | 4315 | 4317 | 4321 | 4322 | 4324 | 4328 | 4329 | 4331 | 4335 | 4336 | 4344 | 4348 | 4352 | 4356 | 4357 | 4359 | 4365 | 4366 | 4369 | 4373 | 4377 | 4381 | 4385 | 4389 | 4393 | 4398 | 4399 | 4400 | 4401 | 4402 | 4403 | 4404 | 4405 | 4407 | 4413 | 4414 | 4417 | 4425 | 4426 | 4428 | 4434 | 4435 | 4438 | 4442 | 4446 | 4450 | 4457 | 4458 | 4459 | 4460 | 4461 | 4463 | 4467 | 4471 | 4472 | 4482 | 4483 | 4490 | 4496 | 4500 | 4506 | 4507 | 4515 | 4516 | 4522 | 4529 | 4530 | 4531 | --------------------------------------------------------------------------------