当前位置: 首页>>代码示例>>Python>>正文


Python queryexecuter.QueryExecuter类代码示例

本文整理汇总了Python中stoqlib.database.queryexecuter.QueryExecuter的典型用法代码示例。如果您正苦于以下问题:Python QueryExecuter类的具体用法?Python QueryExecuter怎么用?Python QueryExecuter使用的例子?那么恭喜您, 这里精选的类代码示例或许可以为您提供帮助。


在下文中一共展示了QueryExecuter类的15个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的Python代码示例。

示例1: get_query_executer

    def get_query_executer(self):
        """
        Fetchs the QueryExecuter for the SearchContainer

        :returns: a querty executer
        :rtype: a :class:`QueryExecuter` subclass
        """
        if self._query_executer is None:
            executer = QueryExecuter(self.store)
            if not self._lazy_search:
                executer.set_limit(sysparam.get_int('MAX_SEARCH_RESULTS'))
            if self._search_spec is not None:
                executer.set_search_spec(self._search_spec)
            self._query_executer = executer
        return self._query_executer
开发者ID:Guillon88,项目名称:stoq,代码行数:15,代码来源:searchslave.py

示例2: _setup_widgets

    def _setup_widgets(self):
        self._replace_widget()

        # Add the two buttons
        self.find_button = self._create_button(gtk.STOCK_FIND)
        self.edit_button = self._create_button(gtk.STOCK_NEW)
        can_edit = self._entry.get_editable() and self._entry.get_sensitive()
        self.find_button.set_sensitive(can_edit)

        self.find_button.set_tooltip_text(self.find_tooltip)
        self.edit_button.set_tooltip_text(self.new_tooltip)

        # the entry needs a completion to work in MODE_DATA
        self._completion = gtk.EntryCompletion()
        self._entry.set_completion(self._completion)
        self._entry.set_mode(ENTRY_MODE_DATA)

        initial_value = getattr(self._model, self._model_property)
        self.set_value(initial_value)

        # The filter that will be used. This is not really in the interface. We
        # will just use it to perform the search.
        self._filter = StringSearchFilter('')
        self._executer = QueryExecuter(self.store)
        self._executer.set_search_spec(self._search_class.search_spec)
        self._executer.set_filter_columns(self._filter, self._search_columns)
开发者ID:barkinet,项目名称:stoq,代码行数:26,代码来源:searchentry.py

示例3: __init__

    def __init__(self, entry, store, initial_value=None,
                 parent=None, run_editor=None):
        """
        :param entry: The entry that we should modify
        :param store: The store that will be used for database queries
        :param initial_value: Initial value for the entry
        :param parent: The parent that should be respected when running other
          dialogs
        """
        super(QueryEntryGadget, self).__init__()

        self._current_obj = None
        self._parent = parent
        self._on_run_editor = run_editor
        self.entry = entry
        self.entry.set_mode(ENTRY_MODE_DATA)
        self.store = store

        # The filter that will be used. This is not really in the interface.
        # We will just use it to perform the search.
        self._filter = StringSearchFilter('')
        self._executer = QueryExecuter(self.store)
        self._executer.set_search_spec(self.SEARCH_SPEC)
        self._executer.set_filter_columns(self._filter, self.SEARCH_COLUMNS)

        self._last_operation = None
        self._source_id = None
        self._is_person = issubclass(self.ITEM_EDITOR, BasePersonRoleEditor)

        self._setup()
        self.set_value(initial_value, force=True)
开发者ID:leandrodax,项目名称:stoq,代码行数:31,代码来源:queryentry.py

示例4: _date_query

 def _date_query(self, search_spec, column):
     sfilter = object()
     executer = QueryExecuter(self.store)
     executer.set_filter_columns(sfilter, [column])
     executer.set_search_spec(search_spec)
     state = DateIntervalQueryState(filter=sfilter, start=self.start, end=self.end)
     return executer.search([state])
开发者ID:amaurihamasu,项目名称:stoq,代码行数:7,代码来源:sintegragenerator.py

示例5: _create_search

 def _create_search(self):
     self.search = SearchSlave(self._get_columns(self.model.kind))
     self.search.connect('result-item-activated',
                         self._on_search__item_activated)
     self.search.enable_advanced_search()
     self.query = QueryExecuter(self.app.store)
     self.search.set_query_executer(self.query)
     self.search.set_result_view(FinancialSearchResults)
     self.result_view = self.search.result_view
     self.result_view.page = self
     tree_view = self.search.result_view.get_treeview()
     tree_view.set_rules_hint(True)
     tree_view.set_grid_lines(gtk.TREE_VIEW_GRID_LINES_BOTH)
开发者ID:tmaxter,项目名称:stoq,代码行数:13,代码来源:financial.py

示例6: _setup_slaves

    def _setup_slaves(self):
        self.search = SearchSlave(self._get_columns(),
                                  restore_name=self.__class__.__name__)
        self.attach_slave('search_group_holder', self.search)

        executer = QueryExecuter(self.store)
        executer.set_table(QuotationView)
        self.search.set_query_executer(executer)

        self.search.set_text_field_columns(['supplier_name'])
        filter = self.search.get_primary_filter()
        filter.set_label(_(u'Supplier:'))
        self.search.focus_search_entry()
        self.search.results.connect('selection-changed',
                                    self._on_searchlist__selection_changed)
        self.search.results.connect('row-activated',
                                    self._on_searchlist__row_activated)

        date_filter = DateSearchFilter(_('Date:'))
        self.search.add_filter(date_filter, columns=['open_date', 'deadline'])

        self.edit_button.set_sensitive(False)
        self.remove_button.set_sensitive(False)
开发者ID:tmaxter,项目名称:stoq,代码行数:23,代码来源:purchasequotewizard.py

示例7: setup_slaves

 def setup_slaves(self):
     self.search = SearchSlave(self._get_columns(),
                               restore_name=self.__class__.__name__)
     self.search.enable_advanced_search()
     self.attach_slave('place_holder', self.search)
     self.executer = QueryExecuter(self.store)
     self.search.set_query_executer(self.executer)
     self.executer.set_table(LoanView)
     self.executer.add_query_callback(self.get_extra_query)
     self._create_filters()
     self.search.results.connect('selection-changed',
                                 self._on_results_selection_changed)
     self.search.results.set_selection_mode(gtk.SELECTION_MULTIPLE)
     self.search.focus_search_entry()
开发者ID:tmaxter,项目名称:stoq,代码行数:14,代码来源:loanwizard.py

示例8: __init__

    def __init__(self, store, search_table=None, hide_footer=True,
                 title='', selection_mode=None, double_click_confirm=False):
        """
        A base class for search dialog inheritance

        :param store: a store
        :param table:
        :param search_table:
        :param hide_footer:
        :param title:
        :param selection_mode:
        :param double_click_confirm: If double click a item in the list should
          automatically confirm
        """

        self.store = store
        self.search_table = search_table or self.search_table
        if not self.search_table:
            raise ValueError("%r needs a search table" % self)
        self.selection_mode = self._setup_selection_mode(selection_mode)
        self.summary_label = None
        self.double_click_confirm = double_click_confirm

        BasicDialog.__init__(self, hide_footer=hide_footer,
                             main_label_text=self.main_label_text,
                             title=title or self.title,
                             size=self.size)

        self.executer = QueryExecuter(store)
        # FIXME: Remove this limit, but we need to migrate all existing
        #        searches to use lazy lists first. That in turn require
        #        us to rewrite the queries in such a way that count(*)
        #        will work properly.
        self.executer.set_limit(sysparam(self.store).MAX_SEARCH_RESULTS)
        self.set_table(self.search_table)

        self.enable_window_controls()
        self.disable_ok()
        self.set_ok_label(_('Se_lect Items'))
        self._setup_search()
        self._setup_details_slave()

        self.create_filters()
        self.setup_widgets()
        if self.search_label:
            self.set_searchbar_label(self.search_label)
开发者ID:tmaxter,项目名称:stoq,代码行数:46,代码来源:searchdialog.py

示例9: QueryExecuterTest

class QueryExecuterTest(DomainTest):
    def setUp(self):
        DomainTest.setUp(self)
        self.qe = QueryExecuter(self.store)
        self.qe.set_search_spec(ClientCategory)
        self.sfilter = mock.Mock()
        self.qe.set_filter_columns(self.sfilter, ['name'])

    def _search_string_all(self, text):
        return self.qe.search([
            StringQueryState(filter=self.sfilter,
                             mode=StringQueryState.CONTAINS_ALL,
                             text=text)])

    def _search_string_exactly(self, text):
        return self.qe.search([
            StringQueryState(filter=self.sfilter,
                             mode=StringQueryState.CONTAINS_EXACTLY,
                             text=text)])

    def _search_string_not(self, text):
        return self.qe.search([
            StringQueryState(filter=self.sfilter,
                             mode=StringQueryState.NOT_CONTAINS,
                             text=text)])

    def test_string_query(self):
        self.assertEquals(self.store.find(ClientCategory).count(), 0)
        self.create_client_category(u'EYE MOON FLARE 110 0.5')
        self.create_client_category(u'EYE MOON FLARE 120 1.0')
        self.create_client_category(u'EYE SUN FLARE 120 1.0')
        self.create_client_category(u'EYE SUN FLARE 110 1.0')
        self.create_client_category(u'EYE SUN STONE 120 0.5')

        self.assertEquals(self._search_string_all(u'eye flare 110').count(), 2)
        self.assertEquals(self._search_string_all(u'eye 0.5').count(), 2)
        self.assertEquals(self._search_string_all(u'eye 120').count(), 3)

        self.assertEquals(self._search_string_exactly(u'eye flare 110').count(), 0)
        self.assertEquals(self._search_string_exactly(u'eye 0.5').count(), 0)
        self.assertEquals(self._search_string_exactly(u'eye 120').count(), 0)

        self.assertEquals(self._search_string_not(u'stone 110').count(), 2)
        self.assertEquals(self._search_string_not(u'eye').count(), 0)
        self.assertEquals(self._search_string_not(u'moon 120').count(), 1)
开发者ID:Joaldino,项目名称:stoq,代码行数:45,代码来源:test_queryexecuter.py

示例10: __init__

    def __init__(self, entry, store, initial_value=None,
                 parent=None, run_editor=None,
                 edit_button=None, info_button=None,
                 search_clause=None):
        """
        :param entry: The entry that we should modify
        :param store: The store that will be used for database queries
        :param initial_value: Initial value for the entry
        :param parent: The parent that should be respected when running other
          dialogs
        """
        super(QueryEntryGadget, self).__init__()

        self._parent = parent
        self._on_run_editor = run_editor
        self._can_edit = False
        self._search_clause = search_clause
        self.entry = entry
        self.entry.set_mode(ENTRY_MODE_DATA)
        self.edit_button = edit_button
        self.info_button = info_button
        self.store = store

        # The filter that will be used. This is not really in the interface.
        # We will just use it to perform the search.
        self._filter = StringSearchFilter('')
        self._executer = QueryExecuter(self.store)
        self._executer.set_search_spec(self.search_spec)
        self._executer.set_filter_columns(self._filter, self.search_columns)
        self._executer.set_order_by(self.order_by)

        self._last_operation = None
        self._source_id = None

        self._setup()
        self.set_value(initial_value, force=True)
开发者ID:hackedbellini,项目名称:stoq,代码行数:36,代码来源:queryentry.py

示例11: TransactionPage

class TransactionPage(object):
    # shows either a list of:
    #   - transactions
    #   - payments
    def __init__(self, model, app, parent):
        self.model = model
        self.app = app
        self.parent_window = parent
        self._block = False

        self._create_search()
        self._add_date_filter()

        self._setup_search()
        self.refresh()

    def get_toplevel(self):
        return self.parent_window

    def _create_search(self):
        self.search = SearchSlave(self._get_columns(self.model.kind))
        self.search.connect('result-item-activated',
                            self._on_search__item_activated)
        self.search.enable_advanced_search()
        self.query = QueryExecuter(self.app.store)
        self.search.set_query_executer(self.query)
        self.search.set_result_view(FinancialSearchResults)
        self.result_view = self.search.result_view
        self.result_view.page = self
        tree_view = self.search.result_view.get_treeview()
        tree_view.set_rules_hint(True)
        tree_view.set_grid_lines(gtk.TREE_VIEW_GRID_LINES_BOTH)

    def _add_date_filter(self):
        self.date_filter = DateSearchFilter(_('Date:'))
        self.date_filter.clear_options()
        self.date_filter.add_option(Any, 0)
        year = datetime.datetime.today().year
        month_names = get_month_names()
        for i, month in enumerate(month_names):
            name = month_names[i]
            option = type(name + 'Option', (MonthOption, ),
                          {'name': _(name),
                           'month': i + 1,
                           'year': year})
            self.date_filter.add_option(option, i + 1)
        self.date_filter.add_custom_options()
        self.date_filter.mode.select_item_by_position(0)
        self.search.add_filter(self.date_filter)

    def _append_date_query(self, field):
        date = self.date_filter.get_state()
        queries = []
        if isinstance(date, DateQueryState) and date.date is not None:
            queries.append(Date(field) == date.date)
        elif isinstance(date, DateIntervalQueryState):
            queries.append(Date(field) >= date.start)
            queries.append(Date(field) <= date.end)
        return queries

    def _payment_query(self, store):
        queries = self._append_date_query(self.query.table.due_date)
        if queries:
            return store.find(self.query.table, And(*queries))

        return store.find(self.query.table)

    def _transaction_query(self, store):
        queries = [Or(self.model.id == AccountTransaction.account_id,
                      self.model.id == AccountTransaction.source_account_id)]

        queries.extend(self._append_date_query(AccountTransaction.date))
        return store.find(AccountTransactionView, And(*queries))

    def show(self):
        self.search.show()

    def _setup_search(self):
        if self.model.kind == 'account':
            self.query.set_table(AccountTransactionView)
            self.search.set_text_field_columns(['description'])
            self.query.set_query(self._transaction_query)
        elif self.model.kind == 'payable':
            self.search.set_text_field_columns(['description', 'supplier_name'])
            self.query.set_table(OutPaymentView)
            self.query.set_query(self._payment_query)
        elif self.model.kind == 'receivable':
            self.search.set_text_field_columns(['description', 'drawee'])
            self.query.set_table(InPaymentView)
            self.query.set_query(self._payment_query)
        else:
            raise TypeError("unknown model kind: %r" % (self.model.kind, ))

    def refresh(self):
        self.search.result_view.clear()
        if self.model.kind == 'account':
            transactions = AccountTransactionView.get_for_account(self.model, self.app.store)
            self.append_transactions(transactions)
        elif self.model.kind == 'payable':
            self._populate_payable_payments(OutPaymentView)
#.........这里部分代码省略.........
开发者ID:tmaxter,项目名称:stoq,代码行数:101,代码来源:financial.py

示例12: SearchEntryGadget

class SearchEntryGadget(object):
    find_tooltip = _('Search')
    edit_tooltip = _('Edit')
    new_tooltip = _('Create')

    def __init__(self, entry, store, model, model_property,
                 search_columns, search_class, parent):
        """
        This gadget modifies a ProxyEntry turning it into a replacement for
        ProxyComboEntry.

        When instanciated, the gadget will remove the entry from the editor, add
        a gtk.HBox on its place, and re-attach the entry to the newly created
        hbox. This hbox will also have two buttons: One for showing the related
        search dialog (or search editor), and another one to add/edit a new
        object.

        There are a few advantages in using this instead of a combo:

        - There is no need to prefill the combo with all the options, which can
          be very slow depending on the number of objects.
        - This allows the user to use a better search mechanism, allowing him to
          filter using multiple keywords and even candidade keys (like a client
          document)

        :param entry: The entry that we should modify
        :param store: The store that will be used for database queries
        :param model: The model that we are updating
        :param model_property: Property name of the model that should be updated
        :param search_columns: Columns that will be queried when the user
          activates the entry
        :param search_class: Class of the search editor/dialog that will be
          displayed when more than one object is found
        :param parent: The parent that should be respected when running other
          dialogs
        :param find_tooltip: the tooltip to use for the search button
        :param edit_tooltip: the tooltip to use for the edit button
        :param new_tooltip: the tooltip to use for the new button
        """
        self.store = store
        self._entry = entry
        self._model = model
        # TODO: Maybe this two variables shoulb be a list of properties of the
        # table instead of strings
        self._model_property = model_property
        self._search_columns = search_columns
        self._search_class = search_class
        self._parent = parent

        # TODO: Respect permission manager
        self._editor_class = search_class.editor_class

        # If the search is for a person, the editor is called with a special
        # function
        if issubclass(search_class, BasePersonSearch):
            self._is_person = True
        else:
            self._is_person = False

        self._setup_widgets()
        self._setup_callbacks()

    #
    #   Private API
    #

    def _setup_widgets(self):
        self._replace_widget()

        # Add the two buttons
        self.find_button = self._create_button(gtk.STOCK_FIND)
        self.edit_button = self._create_button(gtk.STOCK_NEW)
        can_edit = self._entry.get_editable() and self._entry.get_sensitive()
        self.find_button.set_sensitive(can_edit)

        self.find_button.set_tooltip_text(self.find_tooltip)
        self.edit_button.set_tooltip_text(self.new_tooltip)

        # the entry needs a completion to work in MODE_DATA
        self._completion = gtk.EntryCompletion()
        self._entry.set_completion(self._completion)
        self._entry.set_mode(ENTRY_MODE_DATA)

        initial_value = getattr(self._model, self._model_property)
        self.set_value(initial_value)

        # The filter that will be used. This is not really in the interface. We
        # will just use it to perform the search.
        self._filter = StringSearchFilter('')
        self._executer = QueryExecuter(self.store)
        self._executer.set_search_spec(self._search_class.search_spec)
        self._executer.set_filter_columns(self._filter, self._search_columns)

    def _create_button(self, stock):
        image = gtk.image_new_from_stock(stock, gtk.ICON_SIZE_MENU)
        button = gtk.Button()
        button.set_relief(gtk.RELIEF_NONE)
        button.set_image(image)
        button.show()
        self.box.pack_start(button, False, False)
#.........这里部分代码省略.........
开发者ID:barkinet,项目名称:stoq,代码行数:101,代码来源:searchentry.py

示例13: LoanSelectionStep

class LoanSelectionStep(BaseWizardStep):
    gladefile = 'HolderTemplate'

    def __init__(self, wizard, store):
        BaseWizardStep.__init__(self, store, wizard)
        self.setup_slaves()

    def _create_filters(self):
        self.search.set_text_field_columns(['client_name'])

    def _get_columns(self):
        return [IdentifierColumn('identifier', sorted=True),
                SearchColumn('responsible_name', title=_(u'Responsible'),
                             data_type=str, expand=True),
                SearchColumn('client_name', title=_(u'Client'),
                             data_type=str, expand=True),
                SearchColumn('open_date', title=_(u'Opened'),
                             data_type=datetime.date),
                SearchColumn('expire_date', title=_(u'Expire'),
                             data_type=datetime.date),
                Column('loaned', title=_(u'Loaned'),
                       data_type=Decimal),
                ]

    def _refresh_next(self, value=None):
        can_continue = False
        selected_rows = self.search.results.get_selected_rows()
        if selected_rows:
            client = selected_rows[0].client_id
            branch = selected_rows[0].branch_id
            # Only loans that belong to the same client and are from the same
            # branch can be closed together
            can_continue = all(v.client_id == client and v.branch_id == branch
                               for v in selected_rows)
        self.wizard.refresh_next(can_continue)

    def get_extra_query(self, states):
        return LoanView.status == Loan.STATUS_OPEN

    def setup_slaves(self):
        self.search = SearchSlave(self._get_columns(),
                                  restore_name=self.__class__.__name__)
        self.search.enable_advanced_search()
        self.attach_slave('place_holder', self.search)
        self.executer = QueryExecuter(self.store)
        self.search.set_query_executer(self.executer)
        self.executer.set_table(LoanView)
        self.executer.add_query_callback(self.get_extra_query)
        self._create_filters()
        self.search.results.connect('selection-changed',
                                    self._on_results_selection_changed)
        self.search.results.set_selection_mode(gtk.SELECTION_MULTIPLE)
        self.search.focus_search_entry()

    #
    # WizardStep
    #

    def has_previous_step(self):
        return False

    def post_init(self):
        self.register_validate_function(self._refresh_next)
        self.force_validation()

    def next_step(self):
        # FIXME: For some reason, the loan isn't in self.store
        views = self.search.results.get_selected_rows()
        self.wizard.models = [self.store.fetch(v.loan) for v in views]
        return LoanItemSelectionStep(self.wizard, self, self.store,
                                     self.wizard.models)

    #
    # Callbacks
    #

    def _on_results_selection_changed(self, widget, selection):
        self._refresh_next()
开发者ID:tmaxter,项目名称:stoq,代码行数:78,代码来源:loanwizard.py

示例14: SearchDialog

class SearchDialog(BasicDialog):
    """  Base class for *all* the search dialogs, responsible for the list
    construction and "Filter" and "Clear" buttons management.

    This class must be subclassed and its subclass *must* implement the methods
    'get_columns' and 'get_query_and_args' (if desired, 'get_query_and_args'
    can be implemented in the user's slave class, so SearchDialog will get its
    slave instance and call the method directly). Its subclass also must
    implement a setup_slaves method and call its equivalent base class method
    as in:

    >>> def setup_slave(self):
    ...    SearchDialog.setup_slaves(self)

    or then, call it in its constructor, like:

    >>> def __init__(self, *args):
    ...     SearchDialog.__init__(self)
    """
    main_label_text = ''

    #: Title that will appear in the window, for instance 'Product Search'
    title = ''

    # The table type which we will query on to get the objects.
    search_table = None

    #: The label that will be used for the main filter in this dialog
    search_label = None

    #: Selection mode to use (if its possible to select more than one row)
    selection_mode = gtk.SELECTION_BROWSE

    #: Default size for this dialog
    size = ()

    #: If the advanced search is enabled or disabled. When ``True`` we will
    #: instrospect the columns returned by :meth:`get_columns`,and use those
    #: that are subclasses of :class:`stoqlib.gui.columns.SearchColumn` to add
    #: as options for the user to filter the results.
    advanced_search = True

    tree = False

    def __init__(self, store, search_table=None, hide_footer=True,
                 title='', selection_mode=None, double_click_confirm=False):
        """
        A base class for search dialog inheritance

        :param store: a store
        :param table:
        :param search_table:
        :param hide_footer:
        :param title:
        :param selection_mode:
        :param double_click_confirm: If double click a item in the list should
          automatically confirm
        """

        self.store = store
        self.search_table = search_table or self.search_table
        if not self.search_table:
            raise ValueError("%r needs a search table" % self)
        self.selection_mode = self._setup_selection_mode(selection_mode)
        self.summary_label = None
        self.double_click_confirm = double_click_confirm

        BasicDialog.__init__(self, hide_footer=hide_footer,
                             main_label_text=self.main_label_text,
                             title=title or self.title,
                             size=self.size)

        self.executer = QueryExecuter(store)
        # FIXME: Remove this limit, but we need to migrate all existing
        #        searches to use lazy lists first. That in turn require
        #        us to rewrite the queries in such a way that count(*)
        #        will work properly.
        self.executer.set_limit(sysparam(self.store).MAX_SEARCH_RESULTS)
        self.set_table(self.search_table)

        self.enable_window_controls()
        self.disable_ok()
        self.set_ok_label(_('Se_lect Items'))
        self._setup_search()
        self._setup_details_slave()

        self.create_filters()
        self.setup_widgets()
        if self.search_label:
            self.set_searchbar_label(self.search_label)

    def _setup_selection_mode(self, selection_mode):
        # For consistency do not allow none or single, in other words,
        # only allowed values are browse and multiple so we always will
        # be able to use both the keyboard and the mouse to select items
        # in the search list.
        selection_mode = selection_mode or self.selection_mode
        if (selection_mode != gtk.SELECTION_BROWSE and
            selection_mode != gtk.SELECTION_MULTIPLE):
            raise ValueError('Invalid selection mode %r' % selection_mode)
#.........这里部分代码省略.........
开发者ID:tmaxter,项目名称:stoq,代码行数:101,代码来源:searchdialog.py

示例15: setUp

 def setUp(self):
     DomainTest.setUp(self)
     self.qe = QueryExecuter(self.store)
     self.qe.set_search_spec(ClientCategory)
     self.sfilter = mock.Mock()
     self.qe.set_filter_columns(self.sfilter, ['name'])
开发者ID:Joaldino,项目名称:stoq,代码行数:6,代码来源:test_queryexecuter.py


注:本文中的stoqlib.database.queryexecuter.QueryExecuter类示例由纯净天空整理自Github/MSDocs等开源代码及文档管理平台,相关代码片段筛选自各路编程大神贡献的开源项目,源码版权归原作者所有,传播和使用请参考对应项目的License;未经允许,请勿转载。