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


Python packages.TakesPackageService类代码示例

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


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

示例1: enhance_with_archive_items

    def enhance_with_archive_items(self, items):
        if items:
            ids = list(set([item.get("item_id") for item in items if item.get("item_id")]))
            archive_items = []
            archive_lookup = {}
            if ids:
                query = {"$and": [{config.ID_FIELD: {"$in": ids}}]}
                archive_req = ParsedRequest()
                archive_req.max_results = len(ids)
                # can't access published from elastic due filter on the archive resource hence going to mongo
                archive_items = list(
                    superdesk.get_resource_service(ARCHIVE).get_from_mongo(req=archive_req, lookup=query)
                )

                takes_service = TakesPackageService()
                takes_service.enhance_items_with_takes_packages(archive_items)
                for item in archive_items:
                    handle_existing_data(item)
                    archive_lookup[item[config.ID_FIELD]] = item

            for item in items:
                archive_item = archive_lookup.get(item.get("item_id"), {config.VERSION: item.get(config.VERSION, 1)})

                updates = {
                    config.ID_FIELD: item.get("item_id"),
                    "item_id": item.get(config.ID_FIELD),
                    "lock_user": archive_item.get("lock_user", None),
                    "lock_time": archive_item.get("lock_time", None),
                    "lock_session": archive_item.get("lock_session", None),
                    "archive_item": archive_item if archive_item else None,
                }

                item.update(updates)
                handle_existing_data(item)
开发者ID:superdesk,项目名称:superdesk-core,代码行数:34,代码来源:published_item.py

示例2: validate_embargo

    def validate_embargo(self, item):
        """
        Validates the embargo of the item. Following are checked:
            1. Item can't be a package or a take or a re-write of another story
            2. Publish Schedule and Embargo are mutually exclusive
            3. Always a future date except in case of Corrected and Killed.
        :raises: SuperdeskApiError.badRequestError() if the validation fails
        """

        if item[ITEM_TYPE] != CONTENT_TYPE.COMPOSITE:
            if EMBARGO in item:
                embargo = item.get(SCHEDULE_SETTINGS, {}).get('utc_{}'.format(EMBARGO))
                if embargo:
                    if item.get(PUBLISH_SCHEDULE) or item[ITEM_STATE] == CONTENT_STATE.SCHEDULED:
                        raise SuperdeskApiError.badRequestError("An item can't have both Publish Schedule and Embargo")

                    if (item[ITEM_STATE] not in {CONTENT_STATE.KILLED, CONTENT_STATE.SCHEDULED}) \
                            and embargo <= utcnow():
                        raise SuperdeskApiError.badRequestError("Embargo cannot be earlier than now")

                    package = TakesPackageService().get_take_package(item)
                    if package and package.get(SEQUENCE, 1) > 1:
                        raise SuperdeskApiError.badRequestError("Takes doesn't support Embargo")

                    if item.get('rewrite_of'):
                        raise SuperdeskApiError.badRequestError("Rewrites doesn't support Embargo")

                    if not isinstance(embargo, datetime.date) or not embargo.time():
                        raise SuperdeskApiError.badRequestError("Invalid Embargo")

        elif is_normal_package(item):
            if item.get(EMBARGO):
                raise SuperdeskApiError.badRequestError("A Package doesn't support Embargo")

            self.packageService.check_if_any_item_in_package_has_embargo(item)
开发者ID:MiczFlor,项目名称:superdesk-core,代码行数:35,代码来源:archive.py

示例3: on_update

    def on_update(self, updates, original):
        """
        Overridden to validate the updates to the article and take necessary actions depending on the updates. In brief,
        it does the following:
            1. Sets state, item operation, version created, version creator, sign off and word count.
            2. Resets Item Expiry
            3. If the request is to de-schedule then checks and de-schedules the associated Takes Package also.
            4. Creates Crops if article is a picture
        """
        user = get_user()
        self._validate_updates(original, updates, user)

        if 'publish_schedule' in updates and original[ITEM_STATE] == CONTENT_STATE.SCHEDULED:
            self.deschedule_item(updates, original)  # this is an deschedule action

            # check if there is a takes package and deschedule the takes package.
            package = TakesPackageService().get_take_package(original)
            if package and package.get('state') == 'scheduled':
                package_updates = {'publish_schedule': None, 'groups': package.get('groups')}
                self.patch(package.get(config.ID_FIELD), package_updates)

            return

        if self.__is_req_for_save(updates):
            update_state(original, updates)

        remove_unwanted(updates)
        self._add_system_updates(original, updates, user)

        if original[ITEM_TYPE] == CONTENT_TYPE.PICTURE:  # create crops
            CropService().create_multiple_crops(updates, original)
开发者ID:copyfun,项目名称:superdesk,代码行数:31,代码来源:archive.py

示例4: enhance_with_archive_items

    def enhance_with_archive_items(self, items):
        if items:
            ids = list(set([item.get('item_id') for item in items if item.get('item_id')]))
            archive_items = []
            if ids:
                query = {'$and': [{config.ID_FIELD: {'$in': ids}}]}
                archive_req = ParsedRequest()
                archive_req.max_results = len(ids)
                # can't access published from elastic due filter on the archive resource hence going to mongo
                archive_items = list(superdesk.get_resource_service(ARCHIVE)
                                     .get_from_mongo(req=archive_req, lookup=query))

                takes_service = TakesPackageService()
                for item in archive_items:
                    handle_existing_data(item)
                    takes_service.enhance_with_package_info(item)

            for item in items:
                archive_item = [i for i in archive_items if i.get(config.ID_FIELD) == item.get('item_id')]
                archive_item = archive_item[0] if len(archive_item) > 0 else \
                    {config.VERSION: item.get(config.VERSION, 1)}

                updates = {
                    config.ID_FIELD: item.get('item_id'),
                    'item_id': item.get(config.ID_FIELD),
                    'lock_user': archive_item.get('lock_user', None),
                    'lock_time': archive_item.get('lock_time', None),
                    'lock_session': archive_item.get('lock_session', None),
                    'archive_item': archive_item if archive_item else None
                }

                item.update(updates)
                handle_existing_data(item)
开发者ID:PressAssociation,项目名称:superdesk,代码行数:33,代码来源:published_item.py

示例5: set_usn

 def set_usn(self, odbc_item, article):
     """
     Set the usn (unique story number) in the odbc item
     :param odbc_item:
     :param article:
     :return:
     """
     takes_package_service = TakesPackageService()
     pkg = takes_package_service.get_take_package(article)
     if pkg is not None:
         odbc_item['usn'] = pkg.get('unique_id', None)  # @usn
     else:
         odbc_item['usn'] = article.get('unique_id', None)  # @usn
开发者ID:akintolga,项目名称:superdesk-aap,代码行数:13,代码来源:aap_odbc_formatter.py

示例6: _update_rewrite

    def _update_rewrite(self, original):
        """Removes the reference from the rewritten story in published collection."""
        rewrite_service = ArchiveRewriteService()
        if original.get('rewrite_of') and original.get('event_id'):
            rewrite_service._clear_rewritten_flag(original.get('event_id'),
                                                  original[config.ID_FIELD], 'rewritten_by')

        # write the rewritten_by to the take before spiked
        archive_service = get_resource_service(ARCHIVE)
        published_service = get_resource_service('published')
        takes_service = TakesPackageService()
        takes_package = takes_service.get_take_package(original)

        if takes_package and takes_package.get(SEQUENCE, 0) > 1 and original.get('rewritten_by'):
            # get the rewritten by
            rewritten_by = archive_service.find_one(req=None, _id=original.get('rewritten_by'))
            # get the take
            take_id = takes_service.get_take_by_take_no(original,
                                                        take_no=takes_package.get(SEQUENCE) - 1,
                                                        package=takes_package)
            take = archive_service.find_one(req=None, _id=take_id)

            # update the take and takes package with rewritten_by
            if take.get('rewritten_by') != rewritten_by[config.ID_FIELD]:
                if take.get(ITEM_STATE) in PUBLISH_STATES:
                    published_service.update_published_items(take_id, 'rewritten_by', rewritten_by[config.ID_FIELD])

                archive_service.system_update(take[config.ID_FIELD],
                                              {'rewritten_by': rewritten_by[config.ID_FIELD]}, take)

            if takes_package.get('rewritten_by') != rewritten_by[config.ID_FIELD]:
                if takes_package.get(ITEM_STATE) in PUBLISH_STATES:
                    published_service.update_published_items(takes_package.get(config.ID_FIELD),
                                                             'rewritten_by', rewritten_by[config.ID_FIELD])

                archive_service.system_update(takes_package[config.ID_FIELD],
                                              {'rewritten_by': rewritten_by[config.ID_FIELD]}, takes_package)

            if rewritten_by.get('rewrite_of') != takes_package.get(config.ID_FIELD):
                archive_service.system_update(rewritten_by[config.ID_FIELD],
                                              {'rewrite_of': takes_package.get(config.ID_FIELD)},
                                              rewritten_by)
        elif original.get('rewritten_by') or (takes_package and takes_package.get('rewritten_by')):
            # you are spike the story from which the rewrite was triggered.
            # in this case both rewrite_of and rewritten_by are published.
            rewrite_id = original.get('rewritten_by') or takes_package.get('rewritten_by')
            rewritten_by = archive_service.find_one(req=None, _id=rewrite_id)
            archive_service.system_update(rewrite_id, {'rewrite_of': None, 'rewrite_sequence': 0}, rewritten_by)
开发者ID:hlmnrmr,项目名称:superdesk-core,代码行数:48,代码来源:archive_spike.py

示例7: on_update

    def on_update(self, updates, original):
        """
        Overridden to validate the updates to the article and take necessary actions depending on the updates. In brief,
        it does the following:
            1. Sets state, item operation, version created, version creator, sign off and word count.
            2. Resets Item Expiry
            3. If the request is to de-schedule then checks and de-schedules the associated Takes Package also.
            4. Creates Crops if article is a picture
        """
        user = get_user()
        self._validate_updates(original, updates, user)

        if PUBLISH_SCHEDULE in updates and original[ITEM_STATE] == CONTENT_STATE.SCHEDULED:
            self.deschedule_item(updates, original)  # this is an deschedule action

            # check if there is a takes package and deschedule the takes package.
            takes_service = TakesPackageService()
            package = takes_service.get_take_package(original)
            if package and package.get(ITEM_STATE) == CONTENT_STATE.SCHEDULED:
                get_resource_service('published').delete_by_article_id(package.get(config.ID_FIELD))
                self.delete_by_article_ids([package.get(config.ID_FIELD)])
                updates[LINKED_IN_PACKAGES] = [package for package in original.get(LINKED_IN_PACKAGES, [])
                                               if package.get(PACKAGE_TYPE) != TAKES_PACKAGE]
            return

        if self.__is_req_for_save(updates):
            update_state(original, updates)

        remove_unwanted(updates)
        self._add_system_updates(original, updates, user)

        self._add_desk_metadata(updates, original)

        if original[ITEM_TYPE] == CONTENT_TYPE.PICTURE:  # create crops
            CropService().create_multiple_crops(updates, original)

        updates_feature_image = updates.get('associations', {}).get('featureimage')
        if updates_feature_image and 'poi' in updates_feature_image:
            original_feature_image = original.get('associations', {}).get('featureimage', {})
            if original_feature_image and original_feature_image.get('poi', {}) == updates_feature_image['poi']:
                return
            _id = updates_feature_image[config.ID_FIELD] if config.ID_FIELD in updates_feature_image \
                else original_feature_image[config.ID_FIELD]
            image_item = self.find_one(req=None, _id=_id)
            if image_item:
                image_item['poi'] = updates_feature_image['poi']
                image_item = self.patch(_id, image_item)
                updates['associations']['featureimage']['renditions'] = image_item['renditions']
开发者ID:akintolga,项目名称:superdesk-core,代码行数:48,代码来源:archive.py

示例8: on_update

    def on_update(self, updates, original):
        """Runs on archive update.

        Overridden to validate the updates to the article and take necessary actions depending on the updates. In brief,
        it does the following:
            1. Sets state, item operation, version created, version creator, sign off and word count.
            2. Resets Item Expiry
            3. If the request is to de-schedule then checks and de-schedules the associated Takes Package also.
            4. Creates Crops if article is a picture
        """
        user = get_user()
        self._validate_updates(original, updates, user)

        if PUBLISH_SCHEDULE in updates and original[ITEM_STATE] == CONTENT_STATE.SCHEDULED:
            # check if there is a takes package and deschedule the takes package.
            takes_service = TakesPackageService()
            package = takes_service.get_take_package(original)
            if package and package.get(ITEM_STATE) == CONTENT_STATE.SCHEDULED:
                get_resource_service('published').delete_by_article_id(package.get(config.ID_FIELD))
                self.delete_by_article_ids([package.get(config.ID_FIELD)])
                updates[LINKED_IN_PACKAGES] = [package for package in original.get(LINKED_IN_PACKAGES, [])
                                               if package.get(PACKAGE_TYPE) != TAKES_PACKAGE]
            return

        if self.__is_req_for_save(updates):
            update_state(original, updates)

        remove_unwanted(updates)
        self._add_system_updates(original, updates, user)

        self._add_desk_metadata(updates, original)

        if original[ITEM_TYPE] == CONTENT_TYPE.PICTURE:  # create crops
            CropService().create_multiple_crops(updates, original)

        # iterate over associations. Validate and process them if they are stored in database
        if 'associations' in updates:
            for item_name, item_obj in updates.get('associations').items():
                if item_obj and config.ID_FIELD in item_obj:
                    _id = item_obj[config.ID_FIELD]
                    stored_item = self.find_one(req=None, _id=_id)
                    if stored_item:
                        self._validate_updates(stored_item, item_obj, user)
                        if stored_item[ITEM_TYPE] == CONTENT_TYPE.PICTURE:  # create crops
                            CropService().create_multiple_crops(item_obj, stored_item)
                        stored_item.update(item_obj)
                        updates['associations'][item_name] = stored_item
开发者ID:mugurrus,项目名称:superdesk-core,代码行数:47,代码来源:archive.py

示例9: enhance_with_archive_items

    def enhance_with_archive_items(self, items):
        if items:
            ids = list(set([item.get("item_id") for item in items if item.get("item_id")]))
            archive_items = []
            if ids:
                query = {"$and": [{config.ID_FIELD: {"$in": ids}}]}
                archive_req = ParsedRequest()
                archive_req.max_results = len(ids)
                # can't access published from elastic due filter on the archive resource hence going to mongo
                archive_items = list(
                    superdesk.get_resource_service(ARCHIVE).get_from_mongo(req=archive_req, lookup=query)
                )

                takes_service = TakesPackageService()
                for item in archive_items:
                    handle_existing_data(item)
                    takes_service.enhance_with_package_info(item)

            for item in items:
                try:
                    archive_item = [i for i in archive_items if i.get(config.ID_FIELD) == item.get("item_id")][0]
                except IndexError:
                    logger.exception(
                        (
                            "Data inconsistency found for the published item {}. "
                            "Cannot find item {} in the archive collection."
                        ).format(item.get(config.ID_FIELD), item.get("item_id"))
                    )
                    archive_item = {}

                updates = {
                    config.ID_FIELD: item.get("item_id"),
                    "item_id": item.get(config.ID_FIELD),
                    "lock_user": archive_item.get("lock_user", None),
                    "lock_time": archive_item.get("lock_time", None),
                    "lock_session": archive_item.get("lock_session", None),
                    "archive_item": archive_item if archive_item else None,
                }

                item.update(updates)
                handle_existing_data(item)
开发者ID:m038,项目名称:superdesk,代码行数:41,代码来源:published_item.py

示例10: enhance_with_archive_items

    def enhance_with_archive_items(self, items):
        if items:
            ids = list(set([item.get('item_id') for item in items if item.get('item_id')]))
            archive_items = []
            if ids:
                query = {'$and': [{'_id': {'$in': ids}}]}
                archive_req = ParsedRequest()
                archive_req.max_results = len(ids)
                # can't access published from elastic due filter on the archive resource hence going to mongo
                archive_items = list(superdesk.get_resource_service(ARCHIVE)
                                     .get_from_mongo(req=archive_req, lookup=query))

                takes_service = TakesPackageService()
                for item in archive_items:
                    handle_existing_data(item)
                    takes_service.enhance_with_package_info(item)

            for item in items:
                try:
                    archive_item = [i for i in archive_items if i.get('_id') == item.get('item_id')][0]
                except IndexError:
                    logger.exception(('Data inconsistency found for the published item {}. '
                                      'Cannot find item {} in the archive collection.')
                                     .format(item.get('_id'), item.get('item_id')))
                    archive_item = {}

                updates = {
                    '_id': item.get('item_id'),
                    'item_id': item.get('_id'),
                    'lock_user': archive_item.get('lock_user', None),
                    'lock_time': archive_item.get('lock_time', None),
                    'lock_session': archive_item.get('lock_session', None),
                    'archive_item': archive_item if archive_item else None
                }

                item.update(updates)
                handle_existing_data(item)
开发者ID:jey07ro,项目名称:superdesk,代码行数:37,代码来源:published_item.py

示例11: _validate_take

 def _validate_take(self, original):
     takes_service = TakesPackageService()
     if not takes_service.is_last_takes_package_item(original):
         raise SuperdeskApiError.badRequestError(message="Only last take of the package can be spiked.")
开发者ID:oxcarh,项目名称:superdesk,代码行数:4,代码来源:archive_spike.py

示例12: _validate_updates

    def _validate_updates(self, original, updates, user):
        """
        Validates updates to the article for the below conditions, if any of them then exception is raised:
            1.  Is article locked by another user other than the user requesting for update
            2.  Is state of the article is Killed?
            3.  Is user trying to update the package with Public Service Announcements?
            4.  Is user authorized to update unique name of the article?
            5.  Is user trying to update the genre of a broadcast article?
            6.  Is article being scheduled and is in a package?
            7.  Is article being scheduled and schedule timestamp is invalid?
            8.  Does article has valid crops if the article type is a picture?
            9.  Is article a valid package if the article type is a package?
            10. Does article has a valid Embargo?
            11. Make sure that there are no duplicate anpa_category codes in the article.
            12. Make sure there are no duplicate subjects in the upadte

        :raises:
            SuperdeskApiError.forbiddenError()
                - if state of the article is killed or user is not authorized to update unique name or if article is
                  locked by another user
            SuperdeskApiError.badRequestError()
                - if Public Service Announcements are being added to a package or genre is being updated for a
                broadcast, is invalid for scheduling, the updates contain duplicate anpa_category or subject codes
        """

        lock_user = original.get('lock_user', None)
        force_unlock = updates.get('force_unlock', False)
        str_user_id = str(user.get(config.ID_FIELD)) if user else None

        if lock_user and str(lock_user) != str_user_id and not force_unlock:
            raise SuperdeskApiError.forbiddenError('The item was locked by another user')

        if original.get(ITEM_STATE) == CONTENT_STATE.KILLED:
            raise SuperdeskApiError.forbiddenError("Item isn't in a valid state to be updated.")

        if updates.get('body_footer') and is_normal_package(original):
            raise SuperdeskApiError.badRequestError("Package doesn't support Public Service Announcements")

        if 'unique_name' in updates and not is_admin(user) \
                and (user['active_privileges'].get('metadata_uniquename', 0) == 0):
            raise SuperdeskApiError.forbiddenError("Unauthorized to modify Unique Name")

        # if broadcast then update to genre is not allowed.
        if original.get('broadcast') and updates.get('genre') and \
                any(genre.get('value', '').lower() != BROADCAST_GENRE.lower() for genre in updates.get('genre')):
            raise SuperdeskApiError.badRequestError('Cannot change the genre for broadcast content.')

        if updates.get('publish_schedule') and original[ITEM_STATE] != CONTENT_STATE.SCHEDULED \
                and datetime.datetime.fromtimestamp(0).date() != updates['publish_schedule'].date():
            if is_item_in_package(original):
                raise SuperdeskApiError.badRequestError(
                    'This item is in a package and it needs to be removed before the item can be scheduled!')

            package = TakesPackageService().get_take_package(original) or {}
            validate_schedule(updates['publish_schedule'], package.get(SEQUENCE, 1))

        if original[ITEM_TYPE] == CONTENT_TYPE.PICTURE:
            CropService().validate_multiple_crops(updates, original)
        elif original[ITEM_TYPE] == CONTENT_TYPE.COMPOSITE:
            self.packageService.on_update(updates, original)

        # Do the validation after Circular Reference check passes in Package Service
        updated = original.copy()
        updated.update(updates)
        self.validate_embargo(updated)

        # Ensure that there are no duplicate categories in the update
        category_qcodes = [q['qcode'] for q in updates.get('anpa_category', []) or []]
        if category_qcodes and len(category_qcodes) != len(set(category_qcodes)):
            raise SuperdeskApiError.badRequestError("Duplicate category codes are not allowed")

        # Ensure that there are no duplicate subjects in the update
        subject_qcodes = [q['qcode'] for q in updates.get('subject', []) or []]
        if subject_qcodes and len(subject_qcodes) != len(set(subject_qcodes)):
            raise SuperdeskApiError.badRequestError("Duplicate subjects are not allowed")
开发者ID:copyfun,项目名称:superdesk,代码行数:75,代码来源:archive.py

示例13: on_update

    def on_update(self, updates, original):
        updates[ITEM_OPERATION] = ITEM_UPDATE
        is_update_allowed(original)
        user = get_user()

        if 'publish_schedule' in updates and original['state'] == 'scheduled':
            # this is an deschedule action
            self.deschedule_item(updates, original)
            # check if there is a takes package and deschedule the takes package.
            package = TakesPackageService().get_take_package(original)
            if package and package.get('state') == 'scheduled':
                package_updates = {'publish_schedule': None, 'groups': package.get('groups')}
                self.patch(package.get(config.ID_FIELD), package_updates)
            return

        if updates.get('publish_schedule'):

            if datetime.datetime.fromtimestamp(0).date() == updates.get('publish_schedule').date():
                # publish_schedule field will be cleared
                updates['publish_schedule'] = None
            else:
                # validate the schedule
                if is_item_in_package(original):
                    raise SuperdeskApiError.badRequestError(message='This item is in a package' +
                                                            ' it needs to be removed before the item can be scheduled!')
                package = TakesPackageService().get_take_package(original) or {}
                validate_schedule(updates.get('publish_schedule'), package.get(SEQUENCE, 1))

        if 'unique_name' in updates and not is_admin(user) \
                and (user['active_privileges'].get('metadata_uniquename', 0) == 0):
            raise SuperdeskApiError.forbiddenError("Unauthorized to modify Unique Name")

        remove_unwanted(updates)

        if self.__is_req_for_save(updates):
            update_state(original, updates)

        lock_user = original.get('lock_user', None)
        force_unlock = updates.get('force_unlock', False)

        updates.setdefault('original_creator', original.get('original_creator'))

        str_user_id = str(user.get('_id')) if user else None
        if lock_user and str(lock_user) != str_user_id and not force_unlock:
            raise SuperdeskApiError.forbiddenError('The item was locked by another user')

        updates['versioncreated'] = utcnow()
        set_item_expiry(updates, original)
        updates['version_creator'] = str_user_id
        set_sign_off(updates, original=original)
        update_word_count(updates)

        if force_unlock:
            del updates['force_unlock']

        # create crops
        crop_service = ArchiveCropService()
        crop_service.validate_multiple_crops(updates, original)
        crop_service.create_multiple_crops(updates, original)

        if original[ITEM_TYPE] == CONTENT_TYPE.COMPOSITE:
            self.packageService.on_update(updates, original)

        update_version(updates, original)

        # Do the validation after Circular Reference check passes in Package Service
        updated = original.copy()
        updated.update(updates)
        self.validate_embargo(updated)
开发者ID:chalkjockey,项目名称:superdesk,代码行数:69,代码来源:archive.py

示例14: on_update

 def on_update(self, updates, original):
     updates[ITEM_OPERATION] = ITEM_SPIKE
     takes_service = TakesPackageService()
     if not takes_service.can_spike_takes_package_item(original):
         raise SuperdeskApiError.badRequestError(message="Only last take of the package can be spiked.")
开发者ID:m038,项目名称:superdesk,代码行数:5,代码来源:archive_spike.py


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