--- /dev/null
+---
+Language: Cpp
+BasedOnStyle: Google
+AccessModifierOffset: -4
+AlignAfterOpenBracket: Align
+AlignConsecutiveAssignments: false
+AlignConsecutiveDeclarations: true
+AlignEscapedNewlinesLeft: true
+AlignOperands: true
+AlignTrailingComments: true
+AllowAllParametersOfDeclarationOnNextLine: true
+AllowShortBlocksOnASingleLine: false
+AllowShortCaseLabelsOnASingleLine: false
+AllowShortFunctionsOnASingleLine: Inline
+AllowShortIfStatementsOnASingleLine: true
+AllowShortLoopsOnASingleLine: true
+AlwaysBreakAfterDefinitionReturnType: None
+AlwaysBreakAfterReturnType: None
+AlwaysBreakBeforeMultilineStrings: true
+AlwaysBreakTemplateDeclarations: true
+BinPackArguments: true
+BinPackParameters: true
+BraceWrapping:
+ AfterClass: false
+ AfterControlStatement: false
+ AfterEnum: false
+ AfterFunction: false
+ AfterNamespace: false
+ AfterObjCDeclaration: false
+ AfterStruct: false
+ AfterUnion: false
+ BeforeCatch: false
+ BeforeElse: false
+ IndentBraces: false
+BreakBeforeBinaryOperators: None
+BreakBeforeBraces: WebKit
+BreakBeforeTernaryOperators: true
+BreakConstructorInitializersBeforeComma: false
+ColumnLimit: 80
+CommentPragmas: '^ IWYU pragma:'
+ConstructorInitializerAllOnOneLineOrOnePerLine: true
+ConstructorInitializerIndentWidth: 4
+ContinuationIndentWidth: 4
+Cpp11BracedListStyle: true
+DerivePointerAlignment: true
+DisableFormat: false
+ExperimentalAutoDetectBinPacking: false
+ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
+IncludeCategories:
+ - Regex: '^<.*\.h>'
+ Priority: 1
+ - Regex: '^<.*'
+ Priority: 2
+ - Regex: '.*'
+ Priority: 3
+IndentCaseLabels: false
+IndentWidth: 4
+IndentWrappedFunctionNames: false
+KeepEmptyLinesAtTheStartOfBlocks: false
+MacroBlockBegin: ''
+MacroBlockEnd: ''
+MaxEmptyLinesToKeep: 1
+NamespaceIndentation: None
+ObjCBlockIndentWidth: 2
+ObjCSpaceAfterProperty: false
+ObjCSpaceBeforeProtocolList: false
+PenaltyBreakBeforeFirstCallParameter: 1
+PenaltyBreakComment: 300
+PenaltyBreakFirstLessLess: 120
+PenaltyBreakString: 1000
+PenaltyExcessCharacter: 1000000
+PenaltyReturnTypeOnItsOwnLine: 200
+PointerAlignment: Right
+ReflowComments: true
+SortIncludes: true
+SpaceAfterCStyleCast: false
+SpaceBeforeAssignmentOperators: true
+SpaceBeforeParens: ControlStatements
+SpaceInEmptyParentheses: false
+SpacesBeforeTrailingComments: 2
+SpacesInAngles: false
+SpacesInContainerLiterals: true
+SpacesInCStyleCastParentheses: false
+SpacesInParentheses: false
+SpacesInSquareBrackets: false
+Standard: Auto
+TabWidth: 4
+UseTab: Never
+...
+
--- /dev/null
+build*/
+.vscode/
+misc/rpm/
+node_modules/
+*_pb.js
+__pycache__
+*.pyc
+*.pyo
+*.pc
+v
+aurum_pb2*.py
--- /dev/null
+Wonki Kim <wonki_.kim@samsung.com>
--- /dev/null
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
--- /dev/null
+Copyright (c) 2019 Samsung Electronics Co., Ltd. All rights reserved.
+Except as noted, this software is licensed under Apache License, Version 2.
+Please, see the COPYING file for Apache License terms and conditions.
--- /dev/null
+subdir('server')
--- /dev/null
+[Unit]
+Description=Server for testing UI testing
+
+[Service]
+Type=simple
+ExecStart=/usr/bin/aurum_bootstrap
+EnvironmentFile=-/run/tizen-system-env
--- /dev/null
+#ifndef aurum_IMPL_H
+#define aurum_IMPL_H
+
+#include <grpcpp/grpcpp.h>
+#include "Commands/Command.h"
+#include "aurum.grpc.pb.h"
+
+class aurumServiceImpl final : public aurum::Bootstrap::Service {
+public:
+ aurumServiceImpl();
+ virtual ~aurumServiceImpl();
+
+protected:
+ ::grpc::Status execute(Command &cmd);
+
+public:
+ ::grpc::Status sync(::grpc::ServerContext * context,
+ const ::aurum::ReqEmpty *request,
+ ::aurum::RspEmpty * response) override;
+ ::grpc::Status killServer(::grpc::ServerContext * context,
+ const ::aurum::ReqEmpty *request,
+ ::aurum::RspEmpty * response) override;
+
+ ::grpc::Status findElement(::grpc::ServerContext * context,
+ const ::aurum::ReqFindElement *request,
+ ::aurum::RspFindElement *response) override;
+
+ ::grpc::Status getValue(::grpc::ServerContext * context,
+ const ::aurum::ReqGetValue *request,
+ ::aurum::RspGetValue * response) override;
+ ::grpc::Status setValue(::grpc::ServerContext * context,
+ const ::aurum::ReqSetValue *request,
+ ::aurum::RspSetValue * response) override;
+ ::grpc::Status getAttribute(::grpc::ServerContext * context,
+ const ::aurum::ReqGetAttribute *request,
+ ::aurum::RspGetAttribute *response) override;
+ ::grpc::Status getSize(::grpc::ServerContext * context,
+ const ::aurum::ReqGetSize *request,
+ ::aurum::RspGetSize * response) override;
+ ::grpc::Status clear(::grpc::ServerContext * context,
+ const ::aurum::ReqClear *request,
+ ::aurum::RspClear * response) override;
+ ::grpc::Status installApp(
+ ::grpc::ServerContext * context,
+ ::grpc::ServerReader< ::aurum::ReqInstallApp> *reader,
+ ::aurum::RspInstallApp * response) override;
+ ::grpc::Status removeApp(::grpc::ServerContext * context,
+ const ::aurum::ReqRemoveApp *request,
+ ::aurum::RspRemoveApp * response) override;
+ ::grpc::Status getAppInfo(::grpc::ServerContext * context,
+ const ::aurum::ReqGetAppInfo *request,
+ ::aurum::RspGetAppInfo * response) override;
+ ::grpc::Status launchApp(::grpc::ServerContext * context,
+ const ::aurum::ReqLaunchApp *request,
+ ::aurum::RspLaunchApp * response) override;
+ ::grpc::Status closeApp(::grpc::ServerContext * context,
+ const ::aurum::ReqCloseApp *request,
+ ::aurum::RspCloseApp * response) override;
+
+ ::grpc::Status click(::grpc::ServerContext * context,
+ const ::aurum::ReqClick *request,
+ ::aurum::RspClick * response) override;
+ ::grpc::Status longClick(::grpc::ServerContext * context,
+ const ::aurum::ReqClick *request,
+ ::aurum::RspClick * response) override;
+ ::grpc::Status flick(::grpc::ServerContext * context,
+ const ::aurum::ReqFlick *request,
+ ::aurum::RspFlick * response) override;
+
+ ::grpc::Status touchDown(::grpc::ServerContext * context,
+ const ::aurum::ReqTouchDown *request,
+ ::aurum::RspTouchDown * response) override;
+ ::grpc::Status touchUp(::grpc::ServerContext * context,
+ const ::aurum::ReqTouchUp *request,
+ ::aurum::RspTouchUp * response) override;
+ ::grpc::Status touchMove(::grpc::ServerContext * context,
+ const ::aurum::ReqTouchMove *request,
+ ::aurum::RspTouchMove * response) override;
+
+ ::grpc::Status getDeviceTime(::grpc::ServerContext * context,
+ const ::aurum::ReqGetDeviceTime *request,
+ ::aurum::RspGetDeviceTime *response) override;
+ ::grpc::Status getLocation(::grpc::ServerContext * context,
+ const ::aurum::ReqGetLocation *request,
+ ::aurum::RspGetLocation *response) override;
+ ::grpc::Status sendKey(::grpc::ServerContext *context,
+ const ::aurum::ReqKey *request,
+ ::aurum::RspKey * response) override;
+};
+
+#endif
\ No newline at end of file
--- /dev/null
+#ifndef CLEAR_COMMAND_H
+#define CLEAR_COMMAND_H
+
+#include <gio/gio.h>
+#include <grpcpp/grpcpp.h>
+#include "Commands/Command.h"
+#include "ObjectMapper.h"
+#include "aurum.grpc.pb.h"
+#include "config.h"
+
+class ClearCommand : public Command {
+private:
+ const ::aurum::ReqClear* mRequest;
+ ::aurum::RspClear* mResponse;
+
+public:
+ ClearCommand(const ::aurum::ReqClear* request, ::aurum::RspClear* response);
+ ;
+ ::grpc::Status execute() override;
+};
+
+#endif
\ No newline at end of file
--- /dev/null
+#ifndef CLICK_COMMAND_H
+#define CLICK_COMMAND_H
+
+#include <gio/gio.h>
+#include <grpcpp/grpcpp.h>
+#include "Commands/Command.h"
+#include "ObjectMapper.h"
+#include "aurum.grpc.pb.h"
+#include "config.h"
+
+class ClickCommand : public Command {
+private:
+ const ::aurum::ReqClick* mRequest;
+ ::aurum::RspClick* mResponse;
+
+public:
+ ClickCommand(const ::aurum::ReqClick* request, ::aurum::RspClick* response);
+ ;
+ ::grpc::Status execute() override;
+};
+
+#endif
\ No newline at end of file
--- /dev/null
+#ifndef CLOSE_APP_COMMAND_H
+#define CLOSE_APP_COMMAND_H
+
+#include <gio/gio.h>
+#include <grpcpp/grpcpp.h>
+#include "Commands/Command.h"
+#include "ObjectMapper.h"
+#include "aurum.grpc.pb.h"
+#include "config.h"
+
+class CloseAppCommand : public Command {
+private:
+ const ::aurum::ReqCloseApp* mRequest;
+ ::aurum::RspCloseApp* mResponse;
+
+public:
+ CloseAppCommand(const ::aurum::ReqCloseApp* request,
+ ::aurum::RspCloseApp* response);
+ ;
+ ::grpc::Status execute() override;
+};
+
+#endif
\ No newline at end of file
--- /dev/null
+#ifndef COMMAND_H
+#define COMMAND_H
+
+#include <gio/gio.h>
+#include <grpcpp/grpcpp.h>
+#include "ObjectMapper.h"
+#include "aurum.grpc.pb.h"
+
+#include "config.h"
+
+class Command {
+public:
+ virtual ~Command(){};
+ virtual ::grpc::Status execute() = 0;
+};
+
+#endif
\ No newline at end of file
--- /dev/null
+#ifndef COMMANDS_H
+#define COMMANDS_H
+
+#include "Commands/KillServerCommand.h"
+#include "Commands/SyncCommand.h"
+
+#include "Commands/FindElementCommand.h"
+
+#include "Commands/GetAttributeCommand.h"
+#include "Commands/GetValueCommand.h"
+#include "Commands/SetValueCommand.h"
+
+#include "Commands/ClearCommand.h"
+#include "Commands/GetSizeCommand.h"
+
+#include "Commands/ClickCommand.h"
+#include "Commands/FlickCommand.h"
+#include "Commands/LongClickCommand.h"
+
+#include "Commands/TouchDownCommand.h"
+#include "Commands/TouchMoveCommand.h"
+#include "Commands/TouchUpCommand.h"
+
+#include "Commands/CloseAppCommand.h"
+#include "Commands/GetAppInfoCommand.h"
+#include "Commands/InstallAppCommand.h"
+#include "Commands/LaunchAppCommand.h"
+#include "Commands/RemoveAppCommand.h"
+
+#include "Commands/GetDeviceTimeCommand.h"
+#include "Commands/GetLocationCommand.h"
+#include "Commands/SendKeyCommand.h"
+
+#endif
\ No newline at end of file
--- /dev/null
+#ifndef FIND_ELEMENT_COMMAND_H
+#define FIND_ELEMENT_COMMAND_H
+
+#include <gio/gio.h>
+#include <grpcpp/grpcpp.h>
+#include "Commands/Command.h"
+#include "ObjectMapper.h"
+#include "aurum.grpc.pb.h"
+#include "config.h"
+
+class FindElementCommand : public Command {
+private:
+ const ::aurum::ReqFindElement* mRequest;
+ ::aurum::RspFindElement* mResponse;
+
+private:
+ ObjectMapper* mObjMap;
+
+public:
+ FindElementCommand(const ::aurum::ReqFindElement* request,
+ ::aurum::RspFindElement* response);
+ ::grpc::Status execute() override;
+};
+
+#endif
\ No newline at end of file
--- /dev/null
+#ifndef FLICK_COMMAND_H
+#define FLICK_COMMAND_H
+
+#include <gio/gio.h>
+#include <grpcpp/grpcpp.h>
+#include "Commands/Command.h"
+#include "ObjectMapper.h"
+#include "aurum.grpc.pb.h"
+#include "config.h"
+
+class FlickCommand : public Command {
+private:
+ const ::aurum::ReqFlick* mRequest;
+ ::aurum::RspFlick* mResponse;
+
+public:
+ FlickCommand(const ::aurum::ReqFlick* request, ::aurum::RspFlick* response);
+ ;
+ ::grpc::Status execute() override;
+};
+
+#endif
\ No newline at end of file
--- /dev/null
+#ifndef IS_APP_INSTALLED_COMMAND_H
+#define IS_APP_INSTALLED_COMMAND_H
+
+#include <gio/gio.h>
+#include <grpcpp/grpcpp.h>
+#include "Commands/Command.h"
+#include "ObjectMapper.h"
+#include "aurum.grpc.pb.h"
+#include "config.h"
+
+class GetAppInfoCommand : public Command {
+private:
+ const ::aurum::ReqGetAppInfo* mRequest;
+ ::aurum::RspGetAppInfo* mResponse;
+
+public:
+ GetAppInfoCommand(const ::aurum::ReqGetAppInfo* request,
+ ::aurum::RspGetAppInfo* response);
+ ;
+ ::grpc::Status execute() override;
+};
+
+#endif
\ No newline at end of file
--- /dev/null
+#ifndef GET_ATTRIBUTE_COMMAND_H
+#define GET_ATTRIBUTE_COMMAND_H
+
+#include <gio/gio.h>
+#include <grpcpp/grpcpp.h>
+#include "Commands/Command.h"
+#include "ObjectMapper.h"
+#include "aurum.grpc.pb.h"
+#include "config.h"
+
+class GetAttributeCommand : public Command {
+private:
+ const ::aurum::ReqGetAttribute* mRequest;
+ ::aurum::RspGetAttribute* mResponse;
+
+public:
+ GetAttributeCommand(const ::aurum::ReqGetAttribute* request,
+ ::aurum::RspGetAttribute* response);
+ ;
+ ::grpc::Status execute() override;
+};
+
+#endif
\ No newline at end of file
--- /dev/null
+#ifndef GET_DEVICE_TIME_COMMAND_H
+#define GET_DEVICE_TIME_COMMAND_H
+
+#include <gio/gio.h>
+#include <grpcpp/grpcpp.h>
+#include "Commands/Command.h"
+#include "ObjectMapper.h"
+#include "aurum.grpc.pb.h"
+#include "config.h"
+
+class GetDeviceTimeCommand : public Command {
+private:
+ const ::aurum::ReqGetDeviceTime* mRequest;
+ ::aurum::RspGetDeviceTime* mResponse;
+
+public:
+ GetDeviceTimeCommand(const ::aurum::ReqGetDeviceTime* request,
+ ::aurum::RspGetDeviceTime* response);
+ ;
+ ::grpc::Status execute() override;
+};
+
+#endif
\ No newline at end of file
--- /dev/null
+#ifndef GET_LOCATION_COMMAND_H
+#define GET_LOCATION_COMMAND_H
+
+#include <gio/gio.h>
+#include <grpcpp/grpcpp.h>
+#include "Commands/Command.h"
+#include "ObjectMapper.h"
+#include "aurum.grpc.pb.h"
+#include "config.h"
+
+class GetLocationCommand : public Command {
+private:
+ const ::aurum::ReqGetLocation* mRequest;
+ ::aurum::RspGetLocation* mResponse;
+
+public:
+ GetLocationCommand(const ::aurum::ReqGetLocation* request,
+ ::aurum::RspGetLocation* response);
+ ;
+ ::grpc::Status execute() override;
+};
+
+#endif
\ No newline at end of file
--- /dev/null
+#ifndef GET_SIZE_COMMAND_H
+#define GET_SIZE_COMMAND_H
+
+#include <gio/gio.h>
+#include <grpcpp/grpcpp.h>
+#include "Commands/Command.h"
+#include "ObjectMapper.h"
+#include "aurum.grpc.pb.h"
+#include "config.h"
+
+class GetSizeCommand : public Command {
+private:
+ const ::aurum::ReqGetSize* mRequest;
+ ::aurum::RspGetSize* mResponse;
+
+public:
+ GetSizeCommand(const ::aurum::ReqGetSize* request,
+ ::aurum::RspGetSize* response);
+ ;
+ ::grpc::Status execute() override;
+};
+
+#endif
\ No newline at end of file
--- /dev/null
+#ifndef GET_VALUE_COMMAND_H
+#define GET_VALUE_COMMAND_H
+
+#include <gio/gio.h>
+#include <grpcpp/grpcpp.h>
+#include "Commands/Command.h"
+#include "ObjectMapper.h"
+#include "aurum.grpc.pb.h"
+#include "config.h"
+
+class GetValueCommand : public Command {
+private:
+ const ::aurum::ReqGetValue* mRequest;
+ ::aurum::RspGetValue* mResponse;
+
+public:
+ GetValueCommand(const ::aurum::ReqGetValue* request,
+ ::aurum::RspGetValue* response);
+ ;
+ ::grpc::Status execute() override;
+};
+
+#endif
\ No newline at end of file
--- /dev/null
+#ifndef INSTALL_APP_COMMAND_H
+#define INSTALL_APP_COMMAND_H
+
+#include <gio/gio.h>
+#include <grpcpp/grpcpp.h>
+#include "Commands/Command.h"
+#include "ObjectMapper.h"
+#include "aurum.grpc.pb.h"
+#include "config.h"
+
+class InstallAppCommand : public Command {
+private:
+ ::grpc::ServerReader< ::aurum::ReqInstallApp>* mRequest;
+ ::aurum::RspInstallApp* mResponse;
+
+public:
+ InstallAppCommand(::grpc::ServerReader< ::aurum::ReqInstallApp>* request,
+ ::aurum::RspInstallApp* response);
+ ::grpc::Status execute() override;
+};
+
+#endif
\ No newline at end of file
--- /dev/null
+#ifndef KILL_SERVER_COMMAND_H
+#define KILL_SERVER_COMMAND_H
+
+#include <gio/gio.h>
+#include <grpcpp/grpcpp.h>
+#include "Commands/Command.h"
+#include "ObjectMapper.h"
+#include "aurum.grpc.pb.h"
+#include "config.h"
+
+class KillServerCommand : public Command {
+private:
+ const ::aurum::ReqEmpty* mRequest;
+ ::aurum::RspEmpty* mResponse;
+
+public:
+ KillServerCommand(const ::aurum::ReqEmpty* request,
+ ::aurum::RspEmpty* response);
+ ;
+ ::grpc::Status execute() override;
+};
+
+#endif
\ No newline at end of file
--- /dev/null
+#ifndef LAUNCH_APP_COMMAND_H
+#define LAUNCH_APP_COMMAND_H
+
+#include <gio/gio.h>
+#include <grpcpp/grpcpp.h>
+#include "Commands/Command.h"
+#include "ObjectMapper.h"
+#include "aurum.grpc.pb.h"
+#include "config.h"
+
+class LaunchAppCommand : public Command {
+private:
+ const ::aurum::ReqLaunchApp* mRequest;
+ ::aurum::RspLaunchApp* mResponse;
+
+public:
+ LaunchAppCommand(const ::aurum::ReqLaunchApp* request,
+ ::aurum::RspLaunchApp* response);
+ ;
+ ::grpc::Status execute() override;
+};
+
+#endif
\ No newline at end of file
--- /dev/null
+#ifndef LONG_CLICK_COMMAND_H
+#define LONG_CLICK_COMMAND_H
+
+#include <gio/gio.h>
+#include <grpcpp/grpcpp.h>
+#include "Commands/Command.h"
+#include "ObjectMapper.h"
+#include "aurum.grpc.pb.h"
+#include "config.h"
+
+class LongClickCommand : public Command {
+private:
+ const ::aurum::ReqClick* mRequest;
+ ::aurum::RspClick* mResponse;
+
+public:
+ LongClickCommand(const ::aurum::ReqClick* request,
+ ::aurum::RspClick* response);
+ ::grpc::Status execute() override;
+};
+
+#endif
\ No newline at end of file
--- /dev/null
+#ifndef POST_COMMAND_H
+#define POST_COMMAND_H
+
+#include <gio/gio.h>
+#include <grpcpp/grpcpp.h>
+#include "Commands/Command.h"
+#include "aurum.grpc.pb.h"
+#include "config.h"
+
+class PostCommand : public Command {
+private:
+ Command *mCommand;
+ PostCommand();
+
+public:
+ PostCommand(Command *cmd);
+ ::grpc::Status execute() override;
+};
+
+#endif
\ No newline at end of file
--- /dev/null
+#ifndef PRE_COMMAND_H
+#define PRE_COMMAND_H
+
+#include <gio/gio.h>
+#include <grpcpp/grpcpp.h>
+#include "Commands/Command.h"
+#include "aurum.grpc.pb.h"
+#include "config.h"
+
+class PreCommand : public Command {
+private:
+ Command *mCommand;
+ PreCommand();
+
+public:
+ PreCommand(Command *cmd);
+ ::grpc::Status execute() override;
+};
+
+#endif
\ No newline at end of file
--- /dev/null
+#ifndef REMOVE_APP_COMMAND_H
+#define REMOVE_APP_COMMAND_H
+
+#include <gio/gio.h>
+#include <grpcpp/grpcpp.h>
+#include "Commands/Command.h"
+#include "ObjectMapper.h"
+#include "aurum.grpc.pb.h"
+#include "config.h"
+
+class RemoveAppCommand : public Command {
+private:
+ const ::aurum::ReqRemoveApp* mRequest;
+ ::aurum::RspRemoveApp* mResponse;
+
+public:
+ RemoveAppCommand(const ::aurum::ReqRemoveApp* request,
+ ::aurum::RspRemoveApp* response);
+ ;
+ ::grpc::Status execute() override;
+};
+
+#endif
\ No newline at end of file
--- /dev/null
+#ifndef SEND_KEY_COMMAND_H
+#define SEND_KEY_COMMAND_H
+
+#include <gio/gio.h>
+#include <grpcpp/grpcpp.h>
+#include "Commands/Command.h"
+#include "ObjectMapper.h"
+#include "aurum.grpc.pb.h"
+#include "config.h"
+
+class SendKeyCommand : public Command {
+private:
+ const ::aurum::ReqKey* mRequest;
+ ::aurum::RspKey* mResponse;
+
+public:
+ SendKeyCommand(const ::aurum::ReqKey* request, ::aurum::RspKey* response);
+ ::grpc::Status execute() override;
+};
+
+#endif
\ No newline at end of file
--- /dev/null
+#ifndef SET_VALUE_COMMAND_H
+#define SET_VALUE_COMMAND_H
+
+#include <gio/gio.h>
+#include <grpcpp/grpcpp.h>
+#include "Commands/Command.h"
+#include "ObjectMapper.h"
+#include "aurum.grpc.pb.h"
+#include "config.h"
+
+class SetValueCommand : public Command {
+private:
+ const ::aurum::ReqSetValue* mRequest;
+ ::aurum::RspSetValue* mResponse;
+
+public:
+ SetValueCommand(const ::aurum::ReqSetValue* request,
+ ::aurum::RspSetValue* response);
+ ::grpc::Status execute() override;
+};
+
+#endif
\ No newline at end of file
--- /dev/null
+#ifndef SYNC_COMMAND_H
+#define SYNC_COMMAND_H
+
+#include <gio/gio.h>
+#include <grpcpp/grpcpp.h>
+#include "Commands/Command.h"
+#include "ObjectMapper.h"
+#include "aurum.grpc.pb.h"
+#include "config.h"
+
+class SyncCommand : public Command {
+private:
+ const ::aurum::ReqEmpty* mRequest;
+ ::aurum::RspEmpty* mResponse;
+
+public:
+ SyncCommand(const ::aurum::ReqEmpty* request, ::aurum::RspEmpty* response);
+ ::grpc::Status execute() override;
+};
+
+#endif
\ No newline at end of file
--- /dev/null
+#ifndef TOUCH_DOWN_COMMAND_H
+#define TOUCH_DOWN_COMMAND_H
+
+#include <gio/gio.h>
+#include <grpcpp/grpcpp.h>
+#include "Commands/Command.h"
+#include "ObjectMapper.h"
+#include "aurum.grpc.pb.h"
+#include "config.h"
+
+class TouchDownCommand : public Command {
+private:
+ const ::aurum::ReqTouchDown* mRequest;
+ ::aurum::RspTouchDown* mResponse;
+
+public:
+ TouchDownCommand(const ::aurum::ReqTouchDown* request,
+ ::aurum::RspTouchDown* response);
+ ::grpc::Status execute() override;
+};
+
+#endif
\ No newline at end of file
--- /dev/null
+#ifndef TOUCH_MOVE_COMMAND_H
+#define TOUCH_MOVE_COMMAND_H
+
+#include <gio/gio.h>
+#include <grpcpp/grpcpp.h>
+#include "Commands/Command.h"
+#include "ObjectMapper.h"
+#include "aurum.grpc.pb.h"
+#include "config.h"
+
+class TouchMoveCommand : public Command {
+private:
+ const ::aurum::ReqTouchMove* mRequest;
+ ::aurum::RspTouchMove* mResponse;
+
+public:
+ TouchMoveCommand(const ::aurum::ReqTouchMove* request,
+ ::aurum::RspTouchMove* response);
+ ::grpc::Status execute() override;
+};
+
+#endif
\ No newline at end of file
--- /dev/null
+#ifndef TOUCH_UP_COMMAND_H
+#define TOUCH_UP_COMMAND_H
+
+#include <gio/gio.h>
+#include <grpcpp/grpcpp.h>
+#include "Commands/Command.h"
+#include "ObjectMapper.h"
+#include "aurum.grpc.pb.h"
+#include "config.h"
+
+class TouchUpCommand : public Command {
+private:
+ const ::aurum::ReqTouchUp* mRequest;
+ ::aurum::RspTouchUp* mResponse;
+
+public:
+ TouchUpCommand(const ::aurum::ReqTouchUp* request,
+ ::aurum::RspTouchUp* response);
+ ::grpc::Status execute() override;
+};
+
+#endif
\ No newline at end of file
--- /dev/null
+#ifndef OBJECT_MAPPER_H
+#define OBJECT_MAPPER_H
+
+#include <map>
+#include <string>
+
+#include "UiObject.h"
+
+class ObjectMapper {
+private:
+ std::map<std::string, std::unique_ptr<UiObject>> mObjectMap;
+ unsigned long long mObjCounter;
+
+private:
+ ObjectMapper();
+
+public:
+ ~ObjectMapper();
+
+public:
+ static ObjectMapper *getInstance();
+ std::string addElement(std::unique_ptr<UiObject> object);
+ UiObject * getElement(const std::string &key);
+};
+
+#endif
\ No newline at end of file
--- /dev/null
+bootstrap_svr_inc = [
+ libaurum_inc,
+ root_inc,
+ include_directories('inc'),
+ include_directories('inc/Commands'),
+ loguru_inc,
+]
+
+bootstrap_svr_src = [
+ files('src/BootstrapServer.cc'),
+ files('src/AurumServiceImpl.cc'),
+ files('src/ObjectMapper.cc'),
+]
+
+bootstrap_svr_src += [
+ files('src/Commands/ClearCommand.cc'),
+ files('src/Commands/ClickCommand.cc'),
+ files('src/Commands/CloseAppCommand.cc'),
+ files('src/Commands/FindElementCommand.cc'),
+ files('src/Commands/FlickCommand.cc'),
+ files('src/Commands/GetAttributeCommand.cc'),
+ files('src/Commands/GetDeviceTimeCommand.cc'),
+ files('src/Commands/GetLocationCommand.cc'),
+ files('src/Commands/GetSizeCommand.cc'),
+ files('src/Commands/GetValueCommand.cc'),
+ files('src/Commands/InstallAppCommand.cc'),
+ files('src/Commands/GetAppInfoCommand.cc'),
+ files('src/Commands/LaunchAppCommand.cc'),
+ files('src/Commands/LongClickCommand.cc'),
+ files('src/Commands/RemoveAppCommand.cc'),
+ files('src/Commands/SendKeyCommand.cc'),
+ files('src/Commands/SetValueCommand.cc'),
+ files('src/Commands/TouchDownCommand.cc'),
+ files('src/Commands/TouchMoveCommand.cc'),
+ files('src/Commands/TouchUpCommand.cc'),
+ files('src/Commands/SyncCommand.cc'),
+ files('src/Commands/KillServerCommand.cc'),
+ files('src/Commands/Command.cc'),
+ files('src/Commands/PreCommand.cc'),
+ files('src/Commands/PostCommand.cc'),
+]
+
+bootstrap_svr_dep = [
+ libaurum,
+ grpc_deps,
+ loguru_deps,
+]
+
+if get_option('tizen') == true
+bootstrap_svr_dep += [
+ dependency('capi-appfw-app-control'),
+ dependency('capi-appfw-app-manager'),
+ dependency('capi-appfw-package-manager'),
+]
+endif
+
+bootstrap_svr_bin = executable(
+ 'aurum_bootstrap',
+ [bootstrap_svr_src, grpc_src, grpc_pb_src],
+ dependencies: bootstrap_svr_dep,
+ include_directories: bootstrap_svr_inc,
+ link_with: libloguru,
+ install:true,
+)
+
+system_unit_dir = ''
+user_unit_dir = ''
+
+systemd = dependency('systemd', required: false)
+if systemd.found()
+ user_unit_dir = systemd.get_pkgconfig_variable('systemduserunitdir')
+endif
+
+install_data('aurum-bootstrap.service', install_dir:user_unit_dir)
--- /dev/null
+#include "AurumServiceImpl.h"
+
+#include <Accessible.h>
+#include "Commands/Commands.h"
+#include "Commands/PostCommand.h"
+#include "Commands/PreCommand.h"
+
+#include "config.h"
+#include "loguru.hpp"
+
+using namespace grpc;
+using namespace aurum;
+
+aurumServiceImpl::aurumServiceImpl()
+{
+ Accessible::getInstance();
+}
+
+::grpc::Status aurumServiceImpl::execute(Command& cmd)
+{
+ PreCommand proxyPreCmd{&cmd};
+ PostCommand proxyPostCmd{&proxyPreCmd};
+ ::grpc::Status rst = proxyPostCmd.execute();
+ return rst;
+}
+
+aurumServiceImpl::~aurumServiceImpl() {}
+::grpc::Status aurumServiceImpl::aurumServiceImpl::sync(
+ ::grpc::ServerContext* context, const ::aurum::ReqEmpty* request,
+ ::aurum::RspEmpty* response)
+{
+ SyncCommand cmd(request, response);
+ return execute(cmd);
+}
+::grpc::Status aurumServiceImpl::aurumServiceImpl::killServer(
+ ::grpc::ServerContext* context, const ::aurum::ReqEmpty* request,
+ ::aurum::RspEmpty* response)
+{
+ KillServerCommand cmd(request, response);
+ return execute(cmd);
+}
+::grpc::Status aurumServiceImpl::aurumServiceImpl::findElement(
+ ::grpc::ServerContext* context, const ::aurum::ReqFindElement* request,
+ ::aurum::RspFindElement* response)
+{
+ FindElementCommand cmd(request, response);
+ return execute(cmd);
+}
+::grpc::Status aurumServiceImpl::aurumServiceImpl::click(
+ ::grpc::ServerContext* context, const ::aurum::ReqClick* request,
+ ::aurum::RspClick* response)
+{
+ ClickCommand cmd(request, response);
+ return execute(cmd);
+}
+::grpc::Status aurumServiceImpl::getValue(::grpc::ServerContext* context,
+ const ::aurum::ReqGetValue* request,
+ ::aurum::RspGetValue* response)
+{
+ GetValueCommand cmd(request, response);
+ return execute(cmd);
+}
+::grpc::Status aurumServiceImpl::setValue(::grpc::ServerContext* context,
+ const ::aurum::ReqSetValue* request,
+ ::aurum::RspSetValue* response)
+{
+ SetValueCommand cmd(request, response);
+ return execute(cmd);
+}
+::grpc::Status aurumServiceImpl::getAttribute(
+ ::grpc::ServerContext* context, const ::aurum::ReqGetAttribute* request,
+ ::aurum::RspGetAttribute* response)
+{
+ GetAttributeCommand cmd(request, response);
+ return execute(cmd);
+}
+::grpc::Status aurumServiceImpl::getSize(::grpc::ServerContext* context,
+ const ::aurum::ReqGetSize* request,
+ ::aurum::RspGetSize* response)
+{
+ GetSizeCommand cmd(request, response);
+ return execute(cmd);
+}
+::grpc::Status aurumServiceImpl::clear(::grpc::ServerContext* context,
+ const ::aurum::ReqClear* request,
+ ::aurum::RspClear* response)
+{
+ ClearCommand cmd(request, response);
+ return execute(cmd);
+}
+::grpc::Status aurumServiceImpl::installApp(
+ ::grpc::ServerContext* context,
+ ::grpc::ServerReader< ::aurum::ReqInstallApp>* request,
+ ::aurum::RspInstallApp* response)
+{
+ InstallAppCommand cmd(request, response);
+ return execute(cmd);
+}
+::grpc::Status aurumServiceImpl::removeApp(::grpc::ServerContext* context,
+ const ::aurum::ReqRemoveApp* request,
+ ::aurum::RspRemoveApp* response)
+{
+ RemoveAppCommand cmd(request, response);
+ return execute(cmd);
+}
+::grpc::Status aurumServiceImpl::getAppInfo(
+ ::grpc::ServerContext* context, const ::aurum::ReqGetAppInfo* request,
+ ::aurum::RspGetAppInfo* response)
+{
+ GetAppInfoCommand cmd(request, response);
+ return execute(cmd);
+}
+::grpc::Status aurumServiceImpl::launchApp(::grpc::ServerContext* context,
+ const ::aurum::ReqLaunchApp* request,
+ ::aurum::RspLaunchApp* response)
+{
+ LaunchAppCommand cmd(request, response);
+ return execute(cmd);
+}
+::grpc::Status aurumServiceImpl::closeApp(::grpc::ServerContext* context,
+ const ::aurum::ReqCloseApp* request,
+ ::aurum::RspCloseApp* response)
+{
+ CloseAppCommand cmd(request, response);
+ return execute(cmd);
+}
+::grpc::Status aurumServiceImpl::touchDown(::grpc::ServerContext* context,
+ const ::aurum::ReqTouchDown* request,
+ ::aurum::RspTouchDown* response)
+{
+ TouchDownCommand cmd(request, response);
+ return execute(cmd);
+}
+::grpc::Status aurumServiceImpl::touchUp(::grpc::ServerContext* context,
+ const ::aurum::ReqTouchUp* request,
+ ::aurum::RspTouchUp* response)
+{
+ TouchUpCommand cmd(request, response);
+ return execute(cmd);
+}
+::grpc::Status aurumServiceImpl::touchMove(::grpc::ServerContext* context,
+ const ::aurum::ReqTouchMove* request,
+ ::aurum::RspTouchMove* response)
+{
+ TouchMoveCommand cmd(request, response);
+ return execute(cmd);
+}
+::grpc::Status aurumServiceImpl::longClick(::grpc::ServerContext* context,
+ const ::aurum::ReqClick* request,
+ ::aurum::RspClick* response)
+{
+ LongClickCommand cmd(request, response);
+ return execute(cmd);
+}
+::grpc::Status aurumServiceImpl::flick(::grpc::ServerContext* context,
+ const ::aurum::ReqFlick* request,
+ ::aurum::RspFlick* response)
+{
+ FlickCommand cmd(request, response);
+ return execute(cmd);
+}
+::grpc::Status aurumServiceImpl::getDeviceTime(
+ ::grpc::ServerContext* context, const ::aurum::ReqGetDeviceTime* request,
+ ::aurum::RspGetDeviceTime* response)
+{
+ GetDeviceTimeCommand cmd(request, response);
+ return execute(cmd);
+}
+::grpc::Status aurumServiceImpl::getLocation(
+ ::grpc::ServerContext* context, const ::aurum::ReqGetLocation* request,
+ ::aurum::RspGetLocation* response)
+{
+ GetLocationCommand cmd(request, response);
+ return execute(cmd);
+}
+::grpc::Status aurumServiceImpl::sendKey(::grpc::ServerContext* context,
+ const ::aurum::ReqKey* request,
+ ::aurum::RspKey* response)
+{
+ SendKeyCommand cmd(request, response);
+ return execute(cmd);
+}
--- /dev/null
+#include <iostream>
+
+#include <gio/gio.h>
+#include <grpcpp/grpcpp.h>
+#include "aurum.grpc.pb.h"
+
+#include "AurumServiceImpl.h"
+#include "config.h"
+#include "loguru.hpp"
+
+using namespace grpc;
+
+int main(int argc, char **argv)
+{
+ const char *logPath = "/tmp/ua.log";
+ loguru::init(argc, argv);
+ loguru::g_preamble = false;
+ loguru::add_file(logPath, loguru::Append, loguru::Verbosity_MAX);
+ LOG_SCOPE_F(INFO, "Log : %s", logPath);
+
+ std::string binding("0.0.0.0:50051");
+ aurumServiceImpl service;
+ ServerBuilder builder;
+
+ LOG_F(INFO, "Server Listening on %s", binding.c_str());
+ builder.AddListeningPort(binding, grpc::InsecureServerCredentials());
+ builder.RegisterService(&service);
+ std::unique_ptr<Server> server(builder.BuildAndStart());
+ server->Wait();
+
+ return 0;
+}
--- /dev/null
+#include "ClearCommand.h"
+#include <UiObject.h>
+#include <loguru.hpp>
+
+ClearCommand::ClearCommand(const ::aurum::ReqClear* request,
+ ::aurum::RspClear* response)
+ : mRequest{request}, mResponse{response}
+{
+}
+
+::grpc::Status ClearCommand::execute()
+{
+ LOG_SCOPE_F(INFO, "Clear --------------- ");
+ ObjectMapper* mObjMap = ObjectMapper::getInstance();
+ UiObject* obj = mObjMap->getElement(mRequest->elementid());
+ if (obj) {
+ ;
+ }
+ return grpc::Status::OK;
+}
\ No newline at end of file
--- /dev/null
+#include "ClickCommand.h"
+
+#include "UiObject.h"
+
+#include <loguru.hpp>
+
+ClickCommand::ClickCommand(const ::aurum::ReqClick* request,
+ ::aurum::RspClick* response)
+ : mRequest{request}, mResponse{response}
+{
+}
+
+::grpc::Status ClickCommand::execute()
+{
+ LOG_SCOPE_F(INFO, "Click --------------- ");
+
+ ObjectMapper* mObjMap = ObjectMapper::getInstance();
+ ::aurum::ReqClick_RequestType type = mRequest->type();
+
+ if (type == ::aurum::ReqClick_RequestType_ELEMENTID) {
+ UiObject* obj = mObjMap->getElement(mRequest->elementid());
+ if (obj) {
+ obj->click();
+ mResponse->set_status(::aurum::RspStatus::OK);
+ } else
+ mResponse->set_status(::aurum::RspStatus::ERROR);
+ } else if (type == ::aurum::ReqClick_RequestType_COORD) {
+ mResponse->set_status(::aurum::RspStatus::ERROR);
+ } else if (type == ::aurum::ReqClick_RequestType_ATSPI) {
+ mResponse->set_status(::aurum::RspStatus::ERROR);
+ }
+
+ return grpc::Status::OK;
+}
--- /dev/null
+#include "CloseAppCommand.h"
+#include <loguru.hpp>
+#ifdef GBSBUILD
+#include <app_manager_extension.h>
+#endif
+
+CloseAppCommand::CloseAppCommand(const ::aurum::ReqCloseApp* request,
+ ::aurum::RspCloseApp* response)
+ : mRequest{request}, mResponse{response}
+{
+}
+
+::grpc::Status CloseAppCommand::execute()
+{
+ LOG_SCOPE_F(INFO, "CloseApp --------------- ");
+#ifdef GBSBUILD
+ std::string packageName = mRequest->packagename();
+ app_context_h app_context = NULL;
+
+ LOG_F(INFO, "close req : %s", packageName.c_str());
+
+ int ret = app_manager_get_app_context(packageName.c_str(), &app_context);
+ if (ret) {
+ LOG_SCOPE_F(INFO, "Terminate Failed(1/2) Err Code : %d", ret);
+ mResponse->set_status(::aurum::RspStatus::ERROR);
+ return grpc::Status::OK;
+ }
+ ret = app_manager_terminate_app(app_context);
+ if (ret) {
+ LOG_SCOPE_F(INFO, "Terminate Failed(2/2) Err Code : %d", ret);
+ mResponse->set_status(::aurum::RspStatus::ERROR);
+ return grpc::Status::OK;
+ }
+#endif
+ return grpc::Status::OK;
+}
\ No newline at end of file
--- /dev/null
+#include "Command.h"
+#include <loguru.hpp>
\ No newline at end of file
--- /dev/null
+#include "FindElementCommand.h"
+
+#include "ISearchable.h"
+
+#include "Sel.h"
+#include "UiDevice.h"
+#include "UiObject.h"
+#include "UiSelector.h"
+
+#include <loguru.hpp>
+
+FindElementCommand::FindElementCommand(const ::aurum::ReqFindElement* request,
+ ::aurum::RspFindElement* response)
+ : mRequest{request}, mResponse{response}
+{
+ mObjMap = ObjectMapper::getInstance();
+}
+
+::grpc::Status FindElementCommand::execute()
+{
+ LOG_SCOPE_F(INFO, "findElement --------------- ");
+
+ bool fromObject = mRequest->elementid().empty() == false;
+ ISearchable* searchableObj = nullptr;
+
+ LOG_SCOPE_F(INFO, "fromObject:%d ei:%s tf:%s", fromObject,
+ mRequest->elementid().c_str(), mRequest->textfield().c_str());
+
+ if (fromObject) searchableObj = mObjMap->getElement(mRequest->elementid());
+
+ if (searchableObj == nullptr)
+ searchableObj = UiDevice::getInstance(DeviceType::DEFAULT);
+
+ std::unique_ptr<UiSelector> sel = Sel::text(mRequest->textfield());
+ sel->type(mRequest->widgettype());
+
+ std::vector<std::unique_ptr<UiObject>> founds =
+ searchableObj->findObjects(sel.get());
+
+ if (founds.size() > 0) {
+ for (auto& found : founds) {
+ UiObject* obj = found.get();
+ std::string key = mObjMap->addElement(std::move(found));
+ LOG_F(INFO, "found object : %s key:%s",
+ obj->getResourceName().c_str(), key.c_str());
+ ::aurum::Element* elm = mResponse->add_elements();
+ elm->set_elementid(key);
+ }
+ mResponse->set_status(::aurum::RspStatus::OK);
+ }
+
+ return grpc::Status::OK;
+}
\ No newline at end of file
--- /dev/null
+#include "FlickCommand.h"
+#include <loguru.hpp>
+
+#include <UiDevice.h>
+
+FlickCommand::FlickCommand(const ::aurum::ReqFlick *request,
+ ::aurum::RspFlick * response)
+ : mRequest{request}, mResponse{response}
+{
+}
+
+::grpc::Status FlickCommand::execute()
+{
+ LOG_SCOPE_F(INFO, "Flick --------------- ");
+ // ObjectMapper *mObjMap = ObjectMapper::getInstance();
+
+ const ::aurum::Point &startPoint = mRequest->startpoint();
+ const ::aurum::Point &endPoint = mRequest->endpoint();
+ int durationMs = mRequest->durationms();
+
+ UiDevice *device = UiDevice::getInstance(DeviceType::DEFAULT);
+
+ device->drag(10, 200, 400, 400, durationMs);
+
+ return grpc::Status::OK;
+}
\ No newline at end of file
--- /dev/null
+#include "GetAppInfoCommand.h"
+#include <loguru.hpp>
+#ifdef GBSBUILD
+#include <app_manager_extension.h>
+#include <package_manager.h>
+#endif
+
+GetAppInfoCommand::GetAppInfoCommand(const ::aurum::ReqGetAppInfo* request,
+ ::aurum::RspGetAppInfo* response)
+ : mRequest{request}, mResponse{response}
+{
+}
+
+::grpc::Status GetAppInfoCommand::execute()
+{
+ LOG_SCOPE_F(INFO, "GetAppInfo --------------- ");
+#ifdef GBSBUILD
+ std::string packageName = mRequest->packagename();
+
+ app_context_h app_context;
+ package_info_h package_info;
+ app_state_e appState;
+
+ char* label = nullptr;
+ bool terminated = false;
+ int ret = -1;
+
+ mResponse->set_status(::aurum::RspStatus::OK);
+
+ package_manager_get_package_info(packageName.c_str(), &package_info);
+ package_info_get_label(package_info, &label);
+ if (label) {
+ free(label);
+ mResponse->set_isinstalled(true);
+ } else {
+ mResponse->set_isinstalled(false);
+ return grpc::Status::OK;
+ }
+
+ ret = app_manager_get_app_context(packageName.c_str(), &app_context);
+ if (ret) {
+ mResponse->set_isrunning(false);
+ return grpc::Status::OK;
+ }
+
+ ret = app_context_get_app_state(app_context, &appState);
+ if (ret) {
+ mResponse->set_status(::aurum::RspStatus::ERROR);
+ return grpc::Status::OK;
+ }
+ mResponse->set_isrunning(!(appState & APP_STATE_TERMINATED));
+ mResponse->set_isfocused(appState & APP_STATE_FOREGROUND);
+#endif
+ return grpc::Status::OK;
+}
\ No newline at end of file
--- /dev/null
+#include "GetAttributeCommand.h"
+#include <loguru.hpp>
+
+GetAttributeCommand::GetAttributeCommand(
+ const ::aurum::ReqGetAttribute* request, ::aurum::RspGetAttribute* response)
+ : mRequest{request}, mResponse{response}
+{
+}
+
+::grpc::Status GetAttributeCommand::execute()
+{
+ LOG_SCOPE_F(INFO, "GetAttribute --------------- ");
+ // ObjectMapper *mObjMap = ObjectMapper::getInstance();
+ return grpc::Status::OK;
+}
\ No newline at end of file
--- /dev/null
+#include "GetDeviceTimeCommand.h"
+#include <loguru.hpp>
+
+GetDeviceTimeCommand::GetDeviceTimeCommand(
+ const ::aurum::ReqGetDeviceTime* request,
+ ::aurum::RspGetDeviceTime* response)
+ : mRequest{request}, mResponse{response}
+{
+}
+
+::grpc::Status GetDeviceTimeCommand::execute()
+{
+ LOG_SCOPE_F(INFO, "GetDeviceTime --------------- ");
+ // ObjectMapper *mObjMap = ObjectMapper::getInstance();
+ return grpc::Status::OK;
+}
\ No newline at end of file
--- /dev/null
+#include "GetLocationCommand.h"
+#include <loguru.hpp>
+
+GetLocationCommand::GetLocationCommand(const ::aurum::ReqGetLocation* request,
+ ::aurum::RspGetLocation* response)
+ : mRequest{request}, mResponse{response}
+{
+}
+
+::grpc::Status GetLocationCommand::execute()
+{
+ LOG_SCOPE_F(INFO, "CliGetLocation --------------- ");
+ // ObjectMapper *mObjMap = ObjectMapper::getInstance();
+ return grpc::Status::OK;
+}
\ No newline at end of file
--- /dev/null
+#include "GetSizeCommand.h"
+#include <loguru.hpp>
+
+GetSizeCommand::GetSizeCommand(const ::aurum::ReqGetSize* request,
+ ::aurum::RspGetSize* response)
+ : mRequest{request}, mResponse{response}
+{
+}
+
+::grpc::Status GetSizeCommand::execute()
+{
+ LOG_SCOPE_F(INFO, "GetSize --------------- ");
+ // ObjectMapper *mObjMap = ObjectMapper::getInstance();
+ return grpc::Status::OK;
+}
\ No newline at end of file
--- /dev/null
+#include "GetValueCommand.h"
+#include <loguru.hpp>
+
+GetValueCommand::GetValueCommand(const ::aurum::ReqGetValue* request,
+ ::aurum::RspGetValue* response)
+ : mRequest{request}, mResponse{response}
+{
+}
+
+::grpc::Status GetValueCommand::execute()
+{
+ LOG_SCOPE_F(INFO, "GetValue --------------- ");
+ // ObjectMapper *mObjMap = ObjectMapper::getInstance();
+ return grpc::Status::OK;
+}
\ No newline at end of file
--- /dev/null
+#include "InstallAppCommand.h"
+#include <fstream>
+#include <loguru.hpp>
+#ifdef GBSBUILD
+#include <package_manager.h>
+#endif
+
+InstallAppCommand::InstallAppCommand(
+ ::grpc::ServerReader<::aurum::ReqInstallApp> *request,
+ ::aurum::RspInstallApp * response)
+ : mRequest{request}, mResponse{response}
+{
+}
+
+::grpc::Status InstallAppCommand::execute()
+{
+ LOG_SCOPE_F(INFO, "InstallApp --------------- ");
+#ifdef GBSBUILD
+ ::aurum::ReqInstallApp chunk;
+
+ std::ofstream outfile("/tmp/app.tpk", std::ofstream::binary);
+
+ while (mRequest->Read(&chunk)) {
+ std::size_t size = chunk.package().length();
+ const char *bufptr = chunk.package().c_str();
+ outfile.write(bufptr, size);
+ }
+ outfile.close();
+
+ package_manager_request_h pkgRequest;
+ int id;
+
+ package_manager_request_create(&pkgRequest);
+ package_manager_request_install(pkgRequest, "/tmp/app.tpk", &id);
+#endif
+ return grpc::Status::OK;
+}
\ No newline at end of file
--- /dev/null
+#include "KillServerCommand.h"
+#include <loguru.hpp>
+
+KillServerCommand::KillServerCommand(const ::aurum::ReqEmpty* request,
+ ::aurum::RspEmpty* response)
+ : mRequest{request}, mResponse{response}
+{
+}
+
+::grpc::Status KillServerCommand::execute()
+{
+ LOG_SCOPE_F(INFO, "Kill Server ");
+
+ exit(1);
+
+ return grpc::Status::OK;
+}
\ No newline at end of file
--- /dev/null
+#include "LaunchAppCommand.h"
+#include <loguru.hpp>
+#ifdef GBSBUILD
+#include <app_control.h>
+#endif
+
+LaunchAppCommand::LaunchAppCommand(const ::aurum::ReqLaunchApp* request,
+ ::aurum::RspLaunchApp* response)
+ : mRequest{request}, mResponse{response}
+{
+}
+
+::grpc::Status LaunchAppCommand::execute()
+{
+ LOG_SCOPE_F(INFO, "LaunchApp --------------- ");
+#ifdef GBSBUILD
+ app_control_h appControl;
+ std::string packageName = mRequest->packagename();
+ int ret = -1;
+
+ if (packageName.empty()) return grpc::Status::OK;
+
+ ret = app_control_create(&appControl);
+ if (ret) {
+ LOG_SCOPE_F(INFO, "Launch Failed(1/3) Err Code : %ull", ret);
+ mResponse->set_status(::aurum::RspStatus::ERROR);
+ return grpc::Status::OK;
+ }
+
+ ret = app_control_set_app_id(appControl, packageName.c_str());
+ if (ret) {
+ LOG_SCOPE_F(INFO, "Launch Failed(2/3) Err Code : %ull", ret);
+ mResponse->set_status(::aurum::RspStatus::ERROR);
+ return grpc::Status::OK;
+ }
+
+ ret = app_control_send_launch_request(appControl, NULL, NULL);
+ if (ret) {
+ LOG_SCOPE_F(INFO, "Launch Failed(3/3) Err Code : %ull", ret);
+ mResponse->set_status(::aurum::RspStatus::ERROR);
+ return grpc::Status::OK;
+ }
+#endif
+ return grpc::Status::OK;
+}
\ No newline at end of file
--- /dev/null
+#include "LongClickCommand.h"
+#include <loguru.hpp>
+
+LongClickCommand::LongClickCommand(const ::aurum::ReqClick* request,
+ ::aurum::RspClick* response)
+ : mRequest{request}, mResponse{response}
+{
+}
+
+::grpc::Status LongClickCommand::execute()
+{
+ LOG_SCOPE_F(INFO, "LongClick --------------- ");
+ // ObjectMapper *mObjMap = ObjectMapper::getInstance();
+ return grpc::Status::OK;
+}
\ No newline at end of file
--- /dev/null
+#include "PostCommand.h"
+#include <atspi/atspi.h>
+#include <loguru.hpp>
+
+PostCommand::PostCommand() {}
+PostCommand::PostCommand(Command *cmd) : mCommand{cmd} {}
+
+::grpc::Status PostCommand::execute()
+{
+ ::grpc::Status rst = mCommand->execute();
+ LOG_SCOPE_F(INFO, "PostCommand --------------- ");
+ // do post-command
+ return rst;
+}
\ No newline at end of file
--- /dev/null
+#include "PreCommand.h"
+#include <atspi/atspi.h>
+#include <loguru.hpp>
+
+PreCommand::PreCommand() {}
+PreCommand::PreCommand(Command *cmd) : mCommand{cmd} {}
+
+::grpc::Status PreCommand::execute()
+{
+ {
+ LOG_SCOPE_F(INFO, "PreCommand --------------- ");
+ AtspiAccessible *n = atspi_get_desktop(0);
+ free(atspi_accessible_get_name(n, NULL));
+ g_object_unref(n);
+ }
+
+ return mCommand->execute();
+}
\ No newline at end of file
--- /dev/null
+#include "RemoveAppCommand.h"
+#include <loguru.hpp>
+#ifdef GBSBUILD
+#include <package_manager.h>
+#endif
+
+RemoveAppCommand::RemoveAppCommand(const ::aurum::ReqRemoveApp* request,
+ ::aurum::RspRemoveApp* response)
+ : mRequest{request}, mResponse{response}
+{
+}
+
+::grpc::Status RemoveAppCommand::execute()
+{
+ LOG_SCOPE_F(INFO, "RemoveApp --------------- ");
+#ifdef GBSBUILD
+ package_manager_request_h pkgRequest;
+ std::string name = mRequest->packagename();
+ int id;
+ LOG_F(INFO, "package name :%s", name.c_str());
+
+ package_manager_request_create(&pkgRequest);
+ package_manager_request_uninstall(pkgRequest, name.c_str(), &id);
+#endif
+
+ return grpc::Status::OK;
+}
\ No newline at end of file
--- /dev/null
+#include "SendKeyCommand.h"
+#include <loguru.hpp>
+
+#include <UiDevice.h>
+
+SendKeyCommand::SendKeyCommand(const ::aurum::ReqKey* request,
+ ::aurum::RspKey* response)
+ : mRequest{request}, mResponse{response}
+{
+}
+
+::grpc::Status SendKeyCommand::execute()
+{
+ LOG_SCOPE_F(INFO, "SendKey --------------- ");
+ UiDevice* mDevice = UiDevice::getInstance(DeviceType::DEFAULT);
+ ::aurum::ReqKey_KeyType type = mRequest->type();
+
+ if (type == ::aurum::ReqKey_KeyType::ReqKey_KeyType_BACK)
+ mDevice->pressBack();
+ else if (type == ::aurum::ReqKey_KeyType::ReqKey_KeyType_HOME)
+ mDevice->pressHome();
+ else if (type == ::aurum::ReqKey_KeyType::ReqKey_KeyType_MENU)
+ mDevice->pressMenu();
+ else {
+ // TODO : handle keycode
+ }
+ return grpc::Status::OK;
+}
\ No newline at end of file
--- /dev/null
+#include "SetValueCommand.h"
+#include <loguru.hpp>
+
+SetValueCommand::SetValueCommand(const ::aurum::ReqSetValue* request,
+ ::aurum::RspSetValue* response)
+ : mRequest{request}, mResponse{response}
+{
+}
+
+::grpc::Status SetValueCommand::execute()
+{
+ LOG_SCOPE_F(INFO, "SetValue --------------- ");
+ ObjectMapper* mObjMap = ObjectMapper::getInstance();
+ UiObject* obj = mObjMap->getElement(mRequest->elementid());
+ obj->setText(const_cast<std::string&>(mRequest->stringvalue()));
+ LOG_F(INFO, "%p %s", obj, mRequest->stringvalue().c_str());
+
+ return grpc::Status::OK;
+}
\ No newline at end of file
--- /dev/null
+#include "SyncCommand.h"
+#include <loguru.hpp>
+
+#include <Accessible.h>
+#include <AccessibleNode.h>
+
+SyncCommand::SyncCommand(const ::aurum::ReqEmpty *request,
+ ::aurum::RspEmpty * response)
+ : mRequest{request}, mResponse{response}
+{
+}
+
+::grpc::Status SyncCommand::execute()
+{
+ LOG_SCOPE_F(INFO, "Sync Command ");
+ const Accessible *accObj = Accessible::getInstance();
+
+ AccessibleNode *root = accObj->getRootNode();
+ AccessibleNode *top = accObj->getTopNode();
+ LOG_F(INFO, "%p(%p) %p(%p)", root, root->getAccessible(), top,
+ top->getAccessible());
+
+ root->print(0, 2);
+ LOG_F(INFO, "---------");
+ top->print(0, 2);
+
+ return grpc::Status::OK;
+}
\ No newline at end of file
--- /dev/null
+#include "TouchDownCommand.h"
+#include <UiDevice.h>
+#include <loguru.hpp>
+
+TouchDownCommand::TouchDownCommand(const ::aurum::ReqTouchDown* request,
+ ::aurum::RspTouchDown* response)
+ : mRequest{request}, mResponse{response}
+{
+}
+
+::grpc::Status TouchDownCommand::execute()
+{
+ LOG_SCOPE_F(INFO, "TouchDown --------------- ");
+ const aurum::Point& point_ = mRequest->coordination();
+ mResponse->set_seqid(0);
+ UiDevice::getInstance(DeviceType::DEFAULT)
+ ->touchDown(point_.x(), point_.y());
+ return grpc::Status::OK;
+}
\ No newline at end of file
--- /dev/null
+#include "TouchMoveCommand.h"
+#include <UiDevice.h>
+#include <loguru.hpp>
+
+TouchMoveCommand::TouchMoveCommand(const ::aurum::ReqTouchMove* request,
+ ::aurum::RspTouchMove* response)
+ : mRequest{request}, mResponse{response}
+{
+}
+
+::grpc::Status TouchMoveCommand::execute()
+{
+ LOG_SCOPE_F(INFO, "TouchMove --------------- ");
+ const aurum::Point& point = mRequest->coordination();
+ UiDevice::getInstance(DeviceType::DEFAULT)->touchMove(point.x(), point.y());
+ return grpc::Status::OK;
+}
\ No newline at end of file
--- /dev/null
+#include "TouchUpCommand.h"
+#include <UiDevice.h>
+#include <loguru.hpp>
+
+TouchUpCommand::TouchUpCommand(const ::aurum::ReqTouchUp* request,
+ ::aurum::RspTouchUp* response)
+ : mRequest{request}, mResponse{response}
+{
+}
+
+::grpc::Status TouchUpCommand::execute()
+{
+ LOG_SCOPE_F(INFO, "TouchUp --------------- ");
+ const aurum::Point& point = mRequest->coordination();
+ UiDevice::getInstance(DeviceType::DEFAULT)->touchUp(point.x(), point.y());
+ return grpc::Status::OK;
+}
\ No newline at end of file
--- /dev/null
+#include "ObjectMapper.h"
+
+ObjectMapper::ObjectMapper() : mObjectMap{}, mObjCounter{0} {}
+
+ObjectMapper::~ObjectMapper() {}
+
+ObjectMapper *ObjectMapper::getInstance()
+{
+ static ObjectMapper *mInstance = new ObjectMapper();
+ return mInstance;
+}
+
+std::string ObjectMapper::addElement(std::unique_ptr<UiObject> object)
+{
+ ++mObjCounter;
+ std::string key = std::to_string(mObjCounter);
+ mObjectMap[key] = std::move(object);
+ return key;
+}
+
+UiObject *ObjectMapper::getElement(const std::string &key)
+{
+ unsigned long long keyCnt = std::stoi(key);
+ if (keyCnt <= 0 || keyCnt > mObjCounter) return nullptr;
+ if (mObjectMap.count(key)) {
+ UiObject *obj = mObjectMap[key].get();
+ const_cast<const UiObject *>(obj)->refresh();
+ return obj;
+ }
+ return nullptr;
+}
--- /dev/null
+#ifndef ACCESSIBLE_H
+#define ACCESSIBLE_H
+
+#include <atspi/atspi.h>
+#include "AccessibleNode.h"
+
+#include <list>
+#include <map>
+#include <memory>
+#include <vector>
+
+#include <gio/gio.h>
+#include <mutex>
+#include <shared_mutex>
+#include "config.h"
+
+enum class WindowActivateInfoType {
+ DEFAULT_LABEL_ENALBED = 0x00,
+ DEFAULT_LABEL_ENALBED_WITHOUT_WINDOW = 0x01,
+ DEFAULT_LABEL_DISABLED = 0x02,
+ KEYBOARD = 0x04,
+};
+
+class IAtspiEvents {
+public:
+ virtual ~IAtspiEvents() {}
+ virtual void onActivate(AtspiAccessible * node,
+ WindowActivateInfoType type) const = 0;
+ virtual void onDeactivate(AtspiAccessible *node) const = 0;
+ virtual void onVisibilityChanged(AtspiAccessible *node,
+ bool visible) const = 0;
+ virtual void onObjectDefunct(AtspiAccessible *node) const = 0;
+};
+
+class Accessible : public IAtspiEvents {
+private:
+ Accessible();
+
+public:
+ static const Accessible *getInstance();
+ virtual ~Accessible();
+
+public:
+ AccessibleNode *getRootNode() const;
+ AccessibleNode *getTopNode() const;
+
+ void onActivate(AtspiAccessible * node,
+ WindowActivateInfoType type) const override;
+ void onDeactivate(AtspiAccessible *node) const override;
+ void onVisibilityChanged(AtspiAccessible *node,
+ bool visible) const override;
+ void onObjectDefunct(AtspiAccessible *node) const override;
+
+private:
+ void clearWindowList() const;
+ static void onAtspiWindowEvent(AtspiEvent *event, void *user_data);
+
+private:
+ static AtspiEventListener * listener;
+ mutable std::list<AtspiAccessible *> mWindowList;
+ GDBusProxy * mDbusProxy;
+ std::map<AtspiAccessible *, AccessibleNode *> mAccessibleNode;
+ mutable std::mutex mLock;
+};
+
+#endif
--- /dev/null
+#ifndef ACCESSIBLE_NODE_H
+#define ACCESSIBLE_NODE_H
+#include "config.h"
+
+#include <atspi/atspi.h>
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+enum class AccessibleNodeInterface {
+ ACTION = 0x0001,
+ COLLECTION = 0X0002,
+ COMPONENT = 0X0004,
+ DOCUMENT = 0X0008,
+
+ EDITABLETEXT = 0X0010,
+ HYPERTEXT = 0X0020,
+ IMAGE = 0X0040,
+ SELECTION = 0X0080,
+
+ TEXT = 0X0100,
+ VALUE = 0X0200,
+ ACCESSIBLE = 0X0400,
+ TABLE = 0X0800,
+
+ TABLECELL = 0X1000,
+};
+
+enum class NodeFeatureProperties {
+ CHECKABLE = 0x0001,
+ CHECKED = 0X0002,
+ CLICKABLE = 0X0004,
+ ENABLED = 0X0008,
+ FOCUSABLE = 0X0010,
+ FOCUSED = 0X0020,
+ LONGCLICKABLE = 0X0040,
+ SCROLLABLE = 0X0080,
+
+ SELECTABLE = 0X0100,
+ SELECTED = 0X0200,
+};
+
+template <typename T>
+class Point2D {
+public:
+ Point2D() : x{0}, y{0} {}
+ Point2D(const Point2D &src)
+ {
+ x = src.x;
+ y = src.y;
+ }
+ Point2D(const T &x, const T &y)
+ {
+ this->x = x;
+ this->y = y;
+ }
+ T x;
+ T y;
+};
+
+template <typename T>
+class Rect {
+public:
+ Rect() : mTopLeft{0, 0}, mBottomRight{0, 0} {}
+ Rect(const Point2D<T> &tl, const Point2D<T> &br)
+ : mTopLeft(tl), mBottomRight(br)
+ {
+ }
+ Rect(const T &x1, const T &y1, const T &x2, const T &y2)
+ : mTopLeft{x1, y1}, mBottomRight{x2, y2}
+ {
+ }
+ Rect(const Rect<T> &src)
+
+ {
+ this->mTopLeft = Point2D<int>{src.mTopLeft};
+ this->mBottomRight = Point2D<int>{src.mBottomRight};
+ }
+ Point2D<T> midPoint() const
+ {
+ return Point2D<T>{mTopLeft.x + static_cast<T>(width() / 2),
+ mTopLeft.y + static_cast<T>(height() / 2)};
+ }
+ T width() const { return mBottomRight.x - mTopLeft.x; }
+
+ T height() const { return mBottomRight.y - mTopLeft.y; }
+ Point2D<T> mTopLeft;
+ Point2D<T> mBottomRight;
+};
+
+class AccessibleNode {
+private:
+ AccessibleNode();
+ AccessibleNode(AtspiAccessible *node);
+
+public:
+ static AccessibleNode *get(AtspiAccessible *node);
+ ~AccessibleNode();
+
+public:
+ int getChildCount() const;
+ AccessibleNode * getChildAt(int index) const;
+ AccessibleNode * getParent() const;
+ AtspiAccessible *getAccessible();
+
+public:
+ std::string getDesc() const;
+ std::string getText() const;
+ std::string getPkg() const;
+ std::string getRes() const;
+ std::string getType() const;
+ std::string getStyle() const;
+ Rect<int> getBoundingBox() const;
+
+ bool isCheckable() const;
+ bool isChecked() const;
+ bool isClickable() const;
+ bool isEnabled() const;
+ bool isFocusable() const;
+ bool isFocused() const;
+ bool isLongClickable() const;
+ bool isScrollable() const;
+ bool isSelectable() const;
+ bool isSelected() const;
+
+public:
+ void print(int) const;
+ void print(int, int) const;
+ void refresh() const;
+
+ void setValue(std::string &text) const;
+
+private:
+ bool isSupporting(AccessibleNodeInterface thisIface) const;
+ bool hasFeatureProperty(NodeFeatureProperties prop) const;
+ void setFeatureProperty(NodeFeatureProperties prop, bool has);
+ static std::map<AtspiAccessible *, AccessibleNode *> mNodeMap;
+
+private:
+ AtspiAccessible *mNode;
+
+ mutable std::string mText;
+ mutable std::string mPkg;
+ mutable std::string mRole;
+ mutable std::string mDesc;
+ mutable std::string mRes;
+ mutable std::string mType;
+ mutable std::string mStyle;
+
+ mutable Rect<int> mBoundingBox;
+
+ int mSupportingIfaces;
+ int mFeatureProperty;
+ bool mIsAlive;
+};
+
+#endif
--- /dev/null
+#ifndef COMPARER_H
+#define COMPARER_H
+#include "config.h"
+
+#include "AccessibleNode.h"
+#include "UiDevice.h"
+#include "UiSelector.h"
+
+#include "PartialMatch.h"
+
+#include <list>
+#include <memory>
+#include <vector>
+
+class Comparer {
+private:
+ Comparer(const UiDevice *device, const UiSelector *selector,
+ const bool &earlyReturn);
+ ~Comparer();
+
+public:
+ static AccessibleNode * findObject(const UiDevice * device,
+ const UiSelector * selector,
+ const AccessibleNode *root);
+ static std::vector<AccessibleNode *> findObjects(
+ const UiDevice *device, const UiSelector *selector,
+ const AccessibleNode *root);
+
+private:
+ std::vector<AccessibleNode *> findObjects(const AccessibleNode *root);
+ std::vector<AccessibleNode *> findObjects(
+ const AccessibleNode *root, const int &index, const int &depth,
+ std::list<std::shared_ptr<PartialMatch>> &partialMatches);
+
+private:
+ std::unique_ptr<PartialMatch> accept(const AccessibleNode *node,
+ const UiSelector * selector,
+ const int &index, const int &depth,
+ const int &relDepth);
+
+private:
+ const UiDevice * mDevice;
+ const UiSelector *mSelector;
+ bool mEarlyReturn;
+};
+
+#endif
--- /dev/null
+#ifndef DEVICE_GENERAL_H
+#define DEVICE_GENERAL_H
+#include "config.h"
+
+#include "IDevice.h"
+
+#ifdef GBS_BUILD
+#include <efl_util.h>
+#endif
+
+class TM1Impl : public IDevice {
+public:
+ TM1Impl();
+ ~TM1Impl();
+
+ bool click(const int x, const int y) override;
+ bool drag(const int sx, const int sy, const int ex, const int ey,
+ const int steps) override;
+
+ bool touchDown(const int x, const int y) override;
+ bool touchMove(const int x, const int y) override;
+ bool touchUp(const int x, const int y) override;
+
+ bool pressBack() override;
+ bool pressHome() override;
+ bool pressMenu() override;
+ bool pressVolUp() override;
+ bool pressVolDown() override;
+ bool pressPower() override;
+ bool pressKeyCode(std::string keycode) override;
+ bool takeScreenshot(std::string path, float scale, int quality) override;
+
+private:
+#ifdef GBS_BUILD
+ efl_util_inputgen_h mFakeTouchHandle;
+ efl_util_inputgen_h mFakeKeyboardHandle;
+
+#endif
+};
+
+#endif
\ No newline at end of file
--- /dev/null
+#ifndef IDEVICE_H
+#define IDEVICE_H
+#include "config.h"
+
+#include <string>
+
+class IDevice {
+public:
+ virtual ~IDevice() {}
+
+ virtual bool click(const int x, const int y) = 0;
+ virtual bool drag(const int sx, const int sy, const int ex, const int ey,
+ const int steps) = 0;
+
+ virtual bool touchDown(const int x, const int y) = 0;
+ virtual bool touchMove(const int x, const int y) = 0;
+ virtual bool touchUp(const int x, const int y) = 0;
+
+ virtual bool pressBack() = 0;
+ virtual bool pressHome() = 0;
+ virtual bool pressMenu() = 0;
+ virtual bool pressVolUp() = 0;
+ virtual bool pressVolDown() = 0;
+ virtual bool pressPower() = 0;
+ virtual bool pressKeyCode(std::string keycode) = 0;
+
+ virtual bool takeScreenshot(std::string path, float scale, int quality) = 0;
+};
+#endif
\ No newline at end of file
--- /dev/null
+#ifndef ISEARCHABLE_H
+#define ISEARCHABLE_H
+#include "config.h"
+
+#include "UiSelector.h"
+
+#include <memory>
+#include <vector>
+
+class UiObject;
+
+class ISearchable {
+public:
+ virtual ~ISearchable() {}
+ virtual bool hasObject(const UiSelector *selector) const = 0;
+ virtual std::unique_ptr<UiObject> findObject(
+ const UiSelector *selector) const = 0;
+ virtual std::vector<std::unique_ptr<UiObject>> findObjects(
+ const UiSelector *selector) const = 0;
+};
+
+#endif
\ No newline at end of file
--- /dev/null
+#ifndef PARTIAL_MATCH_H
+#define PARTIAL_MATCH_H
+
+#include <list>
+#include <memory>
+#include <vector>
+
+#include "AccessibleNode.h"
+#include "UiSelector.h"
+
+class PartialMatch {
+private:
+ PartialMatch();
+
+ const UiSelector * mSelector;
+ const int mDepth;
+ std::list<std::shared_ptr<PartialMatch>> mPartialMatches;
+
+public:
+ PartialMatch(const UiSelector *selector, const int absDepth);
+ void update(const AccessibleNode *node, int index, int depth,
+ std::list<std::shared_ptr<PartialMatch>> &partialMatches);
+ bool finalizeMatch();
+
+public:
+ static std::shared_ptr<PartialMatch> accept(const AccessibleNode *node,
+ const UiSelector * selector,
+ int index, int depth);
+ static std::shared_ptr<PartialMatch> accept(const AccessibleNode *node,
+ const UiSelector * selector,
+ int index, int absoluteDepth,
+ int relativeDepth);
+
+private:
+ static bool checkCriteria(const UiSelector * sel,
+ const AccessibleNode *node);
+};
+
+#endif
\ No newline at end of file
--- /dev/null
+#ifndef SEL_H
+#define SEL_H
+#include "config.h"
+
+#include <memory>
+#include <string>
+
+#include "UiSelector.h"
+
+class Sel {
+public:
+ static std::unique_ptr<UiSelector> text(const std::string &text);
+ static std::unique_ptr<UiSelector> type(const std::string &text);
+ static std::unique_ptr<UiSelector> depth(const int &depth);
+};
+
+#endif
\ No newline at end of file
--- /dev/null
+#ifndef UIDEVICE_H
+#define UIDEVICE_H
+#include "config.h"
+
+#include "UiObject.h"
+#include "UiSelector.h"
+
+#include "IDevice.h"
+#include "ISearchable.h"
+
+#include "AccessibleNode.h"
+#include "Waiter.h"
+
+#include <functional>
+#include <string>
+
+enum class DeviceType {
+ DEFAULT,
+ NUM_DEVICETYPE,
+};
+
+class UiDevice : public IDevice, public ISearchable {
+public:
+ bool click(const int x, const int y) override;
+ bool drag(const int sx, const int sy, const int ex, const int ey,
+ const int steps) override;
+
+ bool touchDown(const int x, const int y) override;
+ bool touchMove(const int x, const int y) override;
+ bool touchUp(const int x, const int y) override;
+
+ bool pressBack() override;
+ bool pressHome() override;
+ bool pressMenu() override;
+ bool pressVolUp() override;
+ bool pressVolDown() override;
+ bool pressPower() override;
+
+ bool pressKeyCode(std::string keycode) override;
+
+ bool takeScreenshot(std::string path, float scale, int quality);
+
+public:
+ bool hasObject(const UiSelector *selector) const override;
+ std::unique_ptr<UiObject> findObject(
+ const UiSelector *selector) const override;
+ std::vector<std::unique_ptr<UiObject>> findObjects(
+ const UiSelector *selector) const override;
+
+ bool waitFor(
+ const std::function<bool(const ISearchable *)> condition) const;
+ std::unique_ptr<UiObject> waitFor(
+ const std::function<std::unique_ptr<UiObject>(const ISearchable *)>
+ condition) const;
+
+public:
+ static UiDevice *getInstance(DeviceType type);
+
+private:
+ const AccessibleNode *getWindowRoot() const;
+
+private:
+ UiDevice();
+ UiDevice(DeviceType type, IDevice *impl);
+ virtual ~UiDevice();
+
+private:
+ DeviceType mType;
+ IDevice * mDeviceImpl;
+ const Waiter *mWaiter;
+};
+
+#endif
\ No newline at end of file
--- /dev/null
+#ifndef UI_OBJECT_H
+#define UI_OBJECT_H
+#include "config.h"
+
+#include "AccessibleNode.h"
+#include "ISearchable.h"
+#include "UiSelector.h"
+#include "Waiter.h"
+
+#include <memory>
+#include <vector>
+
+class UiDevice;
+
+class UiObject : public ISearchable {
+public:
+ UiObject(const UiDevice *device, const UiSelector *selector,
+ const AccessibleNode *node);
+ UiObject(const UiObject &src); // copy constroctur
+ UiObject(UiObject &&src); // move constructor
+
+ virtual ~UiObject();
+
+ bool hasObject(const UiSelector *selector) const override;
+ std::unique_ptr<UiObject> findObject(
+ const UiSelector *selector) const override;
+ std::vector<std::unique_ptr<UiObject>> findObjects(
+ const UiSelector *selector) const override;
+
+ bool waitFor(
+ const std::function<bool(const ISearchable *)> condition) const;
+ std::unique_ptr<UiObject> waitFor(
+ const std::function<std::unique_ptr<UiObject>(const ISearchable *)>
+ condition) const;
+ bool waitFor(const std::function<bool(const UiObject *)> condition) const;
+
+public:
+ UiObject * getParent() const;
+ int getChildCount() const;
+ std::vector<std::unique_ptr<UiObject>> getChildren() const;
+
+ std::string getContentDescription() const;
+ std::string getApplicationPackage() const;
+ std::string getResourceName() const;
+
+ std::string getText() const;
+ void setText(std::string &text);
+
+ bool isCheckable() const;
+ bool isChecked() const;
+ bool isClickable() const;
+ bool isEnabled() const;
+ bool isFocusable() const;
+ bool isFocused() const;
+ bool isLongClickable() const;
+ bool isScrollable() const;
+ bool isSelectable() const;
+ bool isSelected() const;
+
+ void click() const;
+ void refresh() const;
+
+private:
+ UiObject();
+ const AccessibleNode *getAccessibleNode() const;
+
+private:
+ const UiDevice * mDevice;
+ const UiSelector * mSelector;
+ const AccessibleNode *mNode;
+ const Waiter * mWaiter;
+};
+
+#endif
\ No newline at end of file
--- /dev/null
+#ifndef UI_SELECTOR_H
+#define UI_SELECTOR_H
+#include "config.h"
+
+#include <string>
+#include <vector>
+
+class UiSelector {
+public:
+ UiSelector();
+ UiSelector(UiSelector &selector);
+
+ // UiSelector(const UiSelector &src);
+ // UiSelector &operator= (const UiSelector& src);
+
+public:
+ UiSelector *text(const std::string &text);
+ UiSelector *pkg(const std::string &text);
+ UiSelector *res(const std::string &text);
+ UiSelector *desc(const std::string &text);
+ UiSelector *type(const std::string &text);
+
+ UiSelector *depth(int depth);
+
+ UiSelector *hasChild(UiSelector *child);
+
+public:
+ std::string mText;
+ std::string mPkg;
+ std::string mRes;
+ std::string mDesc;
+ std::string mType;
+ int mDepth;
+
+ std::vector<UiSelector *> mChild;
+};
+
+#endif
\ No newline at end of file
--- /dev/null
+#ifndef UNTIL_H
+#define UNTIL_H
+
+#include <functional>
+#include "ISearchable.h"
+#include "UiSelector.h"
+
+class Until {
+private:
+ Until();
+ Until(const UiSelector *selector);
+ Until(const Until &src);
+ Until(const Until &&src);
+
+public:
+ ~Until();
+
+public:
+ static std::function<bool(const ISearchable *)> hasObject(
+ const UiSelector *selector);
+ static std::function<std::unique_ptr<UiObject>(const ISearchable *)>
+ findObject(const UiSelector *selector);
+ static std::function<bool(const UiObject *)> checkable(
+ const bool isCheckable);
+};
+#endif
+
+// Until::hasObject(Sel::text("text").get())
\ No newline at end of file
--- /dev/null
+#ifndef WAITER_H
+#define WAITER_H
+
+#include "ISearchable.h"
+
+#include <functional>
+
+class Waiter {
+private:
+ Waiter();
+
+public:
+ Waiter(const ISearchable *searchableObject,
+ const UiObject * uiObject = nullptr); // : mObject{object}
+ ~Waiter();
+
+public:
+ template <typename R>
+ R waitFor(const std::function<R(const ISearchable *)> condition) const;
+ template <typename R>
+ R waitFor(const std::function<R(const UiObject *)> object) const;
+
+private:
+ const ISearchable *mSearchableObject;
+ const UiObject * mUiObject;
+ const int WAIT_INTERVAL_MS;
+ const int WAIT_TIMEOUT_MS;
+};
+
+#endif
\ No newline at end of file
--- /dev/null
+libaurum_inc = [
+ include_directories('./inc'),
+ root_inc,
+ loguru_inc,
+]
+
+libaurum_src = [
+ files('src/Sel.cc'),
+ files('src/UiDevice.cc'),
+ files('src/UiObject.cc'),
+ files('src/UiSelector.cc'),
+ files('src/Accessible.cc'),
+ files('src/AccessibleNode.cc'),
+ files('src/Comparer.cc'),
+ files('src/Until.cc'),
+ files('src/Waiter.cc'),
+ files('src/PartialMatch.cc'),
+]
+
+if get_option('tizen') == true
+libaurum_src +=[
+ files('src/DeviceImpl/TM1Impl.cc'),
+]
+endif
+
+libaurum_dep = [
+ dependency('atspi-2'),
+ dependency('gio-2.0'),
+ dependency('threads'),
+ loguru_deps,
+]
+
+if get_option('tizen') == true
+ libaurum_dep += [
+ dependency('capi-system-info'),
+ dependency('dlog'),
+ dependency('capi-ui-efl-util'),
+ dependency('elementary'),
+ ]
+endif
+
+libaurum_lib = library('aurum', libaurum_src,
+ dependencies: libaurum_dep,
+ include_directories: libaurum_inc,
+ link_with: libloguru,
+ install: true,
+ version: meson.project_version(),
+ )
+
+libaurum = declare_dependency(link_with: libaurum_lib,
+ dependencies: libaurum_dep,
+ include_directories: libaurum_inc,
+ )
--- /dev/null
+
+#include "Accessible.h"
+
+#include <string.h>
+#include <iostream>
+#include <utility>
+
+#include "loguru.hpp"
+
+AtspiEventListener *Accessible::listener = nullptr;
+
+static bool iShowingNode(AtspiAccessible *node)
+{
+ char *name = atspi_accessible_get_name(node, NULL);
+ char *pname = atspi_accessible_get_name(
+ atspi_accessible_get_parent(node, NULL), NULL);
+
+ LOG_SCOPE_F(INFO, "isShowing %s %s", name, pname);
+
+ if (!strcmp(name, "Keyboard") && !strcmp(pname, "ise-default")) {
+ free(name);
+ free(pname);
+ return false;
+ }
+ free(name);
+ free(pname);
+
+ AtspiStateSet *stateSet = atspi_accessible_get_state_set(node);
+ if (atspi_state_set_contains(stateSet, ATSPI_STATE_ACTIVE) &&
+ atspi_state_set_contains(stateSet, ATSPI_STATE_SHOWING)) {
+ g_object_unref(stateSet);
+ return true;
+ }
+ return false;
+}
+
+static AtspiAccessible *findActiveNode(AtspiAccessible *node, int depth,
+ int max_depth)
+{
+ if (depth >= max_depth) return NULL;
+
+ if (iShowingNode(node)) {
+ g_object_ref(node);
+
+ char *name = atspi_accessible_get_name(node, NULL);
+ char *pname = atspi_accessible_get_name(
+ atspi_accessible_get_parent(node, NULL), NULL);
+ LOG_SCOPE_F(INFO, "%s %s", name, pname);
+ return node;
+ }
+
+ int nchild = atspi_accessible_get_child_count(node, NULL);
+ for (int i = 0; i < nchild; i++) {
+ AtspiAccessible *child =
+ atspi_accessible_get_child_at_index(node, i, NULL);
+ AtspiAccessible *active = findActiveNode(child, depth + 1, max_depth);
+ g_object_unref(child);
+ if (active) return active;
+ }
+
+ return NULL;
+}
+
+Accessible::Accessible() : mWindowList{}
+{
+ GVariant *enabled_variant = nullptr, *result = nullptr;
+ GError * error = nullptr;
+ atspi_init();
+
+ mDbusProxy = g_dbus_proxy_new_for_bus_sync(
+ G_BUS_TYPE_SESSION, G_DBUS_PROXY_FLAGS_NONE,
+ NULL, /* GDBusInterfaceInfo */
+ "org.a11y.Bus", "/org/a11y/bus", "org.freedesktop.DBus.Properties",
+ NULL, &error);
+
+ enabled_variant = g_variant_new_boolean(true);
+ result = g_dbus_proxy_call_sync(
+ mDbusProxy, "Set",
+ g_variant_new("(ssv)", "org.a11y.Status", "IsEnabled", enabled_variant),
+ G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);
+
+ g_variant_unref(enabled_variant);
+ g_variant_unref(result);
+
+ listener =
+ atspi_event_listener_new(Accessible::onAtspiWindowEvent, this, NULL);
+ atspi_event_listener_register(listener, "window:", NULL);
+ atspi_event_listener_register(listener, "object:", NULL);
+}
+
+Accessible::~Accessible()
+{
+ for (auto it = mAccessibleNode.begin(); it != mAccessibleNode.end(); ++it) {
+ g_object_unref(it->first);
+ delete it->second;
+ }
+ atspi_event_listener_deregister(listener, "window:", NULL);
+ atspi_event_listener_deregister(listener, "object:", NULL);
+
+ g_object_unref(listener);
+ g_object_unref(mDbusProxy);
+
+ atspi_event_quit();
+ atspi_exit();
+}
+
+AccessibleNode *Accessible::getRootNode() const
+{
+ AtspiAccessible *node = atspi_get_desktop(0);
+ AccessibleNode * accNode = AccessibleNode::get(node);
+ if (node) g_object_unref(node);
+ return accNode;
+}
+
+AccessibleNode *Accessible::getTopNode() const
+{
+ AtspiAccessible *topNode = nullptr, *activeNode = nullptr,
+ *rootNode = nullptr;
+ {
+ std::unique_lock<std::mutex> lock(mLock);
+ if (!mWindowList.empty()) {
+ topNode = mWindowList.front();
+ }
+ }
+
+#ifdef TIZEN
+ char *name, *pname;
+ name = atspi_accessible_get_name(topNode, NULL);
+ pname = atspi_accessible_get_parent(topNode, NULL)
+ ? atspi_accessible_get_name(
+ atspi_accessible_get_parent(topNode, NULL), NULL)
+ : NULL;
+
+ LOG_F(INFO, "topNode unique id: %s / name: %s pname :%s",
+ atspi_accessible_get_unique_id(topNode, NULL), name, pname);
+
+ free(name);
+ free(pname);
+#endif
+
+ if (topNode) {
+ if (iShowingNode(topNode)) {
+ AccessibleNode *node = AccessibleNode::get(topNode);
+ // g_object_unref(activeNode);
+ return node;
+ }
+ }
+
+ rootNode = atspi_get_desktop(0);
+
+ if (rootNode) {
+ activeNode = findActiveNode(rootNode, 0, 2);
+
+#ifdef TIZEN
+ char *name, *pname;
+ name = atspi_accessible_get_name(activeNode, NULL);
+ pname = atspi_accessible_get_parent(activeNode, NULL)
+ ? atspi_accessible_get_name(
+ atspi_accessible_get_parent(activeNode, NULL), NULL)
+ : NULL;
+
+ LOG_F(INFO, "activeNode unique id: %s / name: %s pname:%s",
+ atspi_accessible_get_unique_id(activeNode, NULL), name, pname);
+ free(name);
+ free(pname);
+#endif
+
+ if (activeNode) {
+ AccessibleNode *node = AccessibleNode::get(activeNode);
+ return node;
+ }
+ AccessibleNode *node = AccessibleNode::get(rootNode);
+ return node;
+ }
+ return nullptr;
+}
+
+void Accessible::onAtspiWindowEvent(AtspiEvent *event, void *user_data)
+{
+ char * name, *pname;
+ const IAtspiEvents *instance = (IAtspiEvents *)user_data;
+
+ AtspiAccessible *p = atspi_accessible_get_parent(event->source, NULL);
+
+ name = atspi_accessible_get_name(event->source, NULL);
+ pname = atspi_accessible_get_name(p, NULL);
+
+ LOG_SCOPE_F(INFO, "event:%s, src:%p(%s), p:%p(%s), d1:%p d2:%p instance:%p",
+ event->type, event->source, name, p, pname, event->detail1,
+ event->detail2, instance);
+
+ if (!strcmp(event->type, "window:activate")) {
+ instance->onActivate(
+ static_cast<AtspiAccessible *>(event->source),
+ static_cast<WindowActivateInfoType>(event->detail1));
+ } else if (!strcmp(event->type, "window:deactivate")) {
+ instance->onDeactivate(static_cast<AtspiAccessible *>(event->source));
+ } else if (!strcmp(event->type, "object:state-changed:visible")) {
+ instance->onVisibilityChanged(
+ static_cast<AtspiAccessible *>(event->source),
+ (event->detail1 != 0));
+ } else if (!strcmp(event->type, "object:state-changed:defunct")) {
+ instance->onObjectDefunct(
+ static_cast<AtspiAccessible *>(event->source));
+ }
+}
+
+const Accessible *Accessible::getInstance()
+{
+ static Accessible *mInstance = nullptr;
+ if (!mInstance) mInstance = new Accessible();
+ return mInstance;
+}
+
+void Accessible::clearWindowList() const
+{
+ std::unique_lock<std::mutex> lock(mLock);
+ while (!mWindowList.empty()) {
+ AtspiAccessible *n = mWindowList.front();
+ mWindowList.pop_front();
+ g_object_unref(n);
+ }
+}
+
+void Accessible::onActivate(AtspiAccessible * node,
+ WindowActivateInfoType type) const
+{
+ std::unique_lock<std::mutex> lock(mLock);
+
+ char *name = atspi_accessible_get_name(node, NULL);
+ char *pname = atspi_accessible_get_name(
+ atspi_accessible_get_parent(node, NULL), NULL);
+ LOG_SCOPE_F(INFO, "%s %s", name, pname);
+
+ mWindowList.remove_if([&](auto &n) { return n == node; });
+ if (!strcmp(name, "Keyboard") && !strcmp(pname, "ise-default")) return;
+ mWindowList.push_front(node);
+}
+
+void Accessible::onDeactivate(AtspiAccessible *node) const
+{
+ std::unique_lock<std::mutex> lock(mLock);
+ mWindowList.remove_if([&](auto &n) { return n == node; });
+ mWindowList.push_back(node);
+}
+
+void Accessible::onVisibilityChanged(AtspiAccessible *node, bool visible) const
+{
+}
+
+void Accessible::onObjectDefunct(AtspiAccessible *node) const
+{
+ LOG_SCOPE_F(INFO, "object defuncted %p", node);
+}
\ No newline at end of file
--- /dev/null
+#include "AccessibleNode.h"
+#include <string.h>
+#include <iostream>
+
+#include "loguru.hpp"
+
+#include "config.h"
+
+std::map<AtspiAccessible *, AccessibleNode *> AccessibleNode::mNodeMap{};
+
+AccessibleNode::~AccessibleNode()
+{
+ g_object_unref(mNode);
+}
+
+AccessibleNode::AccessibleNode()
+{
+ // No meaning without AtspiAccessbile object
+ // prohibited to create this object with this constructor
+}
+
+AccessibleNode::AccessibleNode(AtspiAccessible *node)
+ : mNode(node), mSupportingIfaces(0), mIsAlive(true)
+{
+ // prohibited to create this object this constructor
+ // better to use AccessibleNode::get factory method.
+ LOG_SCOPE_F(1, "AccessibleNode constructor %p", node);
+ g_object_ref(node);
+ GArray *ifaces = atspi_accessible_get_interfaces(mNode);
+ if (ifaces) {
+ for (unsigned int i = 0; i < ifaces->len; i++) {
+ char *iface = g_array_index(ifaces, char *, i);
+ if (!strcmp(iface, "Action"))
+ mSupportingIfaces |=
+ static_cast<int>(AccessibleNodeInterface::ACTION);
+ else if (!strcmp(iface, "Collection"))
+ mSupportingIfaces |=
+ static_cast<int>(AccessibleNodeInterface::COLLECTION);
+ else if (!strcmp(iface, "Component"))
+ mSupportingIfaces |=
+ static_cast<int>(AccessibleNodeInterface::COMPONENT);
+ else if (!strcmp(iface, "Document"))
+ mSupportingIfaces |=
+ static_cast<int>(AccessibleNodeInterface::DOCUMENT);
+ else if (!strcmp(iface, "EditableText"))
+ mSupportingIfaces |=
+ static_cast<int>(AccessibleNodeInterface::EDITABLETEXT);
+ else if (!strcmp(iface, "Hypertext"))
+ mSupportingIfaces |=
+ static_cast<int>(AccessibleNodeInterface::HYPERTEXT);
+ else if (!strcmp(iface, "Image"))
+ mSupportingIfaces |=
+ static_cast<int>(AccessibleNodeInterface::IMAGE);
+ else if (!strcmp(iface, "Selection"))
+ mSupportingIfaces |=
+ static_cast<int>(AccessibleNodeInterface::SELECTION);
+ else if (!strcmp(iface, "Text"))
+ mSupportingIfaces |=
+ static_cast<int>(AccessibleNodeInterface::TEXT);
+ else if (!strcmp(iface, "Value"))
+ mSupportingIfaces |=
+ static_cast<int>(AccessibleNodeInterface::VALUE);
+ else if (!strcmp(iface, "Accessible"))
+ mSupportingIfaces |=
+ static_cast<int>(AccessibleNodeInterface::ACCESSIBLE);
+ else if (!strcmp(iface, "Table"))
+ mSupportingIfaces |=
+ static_cast<int>(AccessibleNodeInterface::TABLE);
+ else if (!strcmp(iface, "TableCell"))
+ mSupportingIfaces |=
+ static_cast<int>(AccessibleNodeInterface::TABLECELL);
+ else
+ LOG_F(WARNING, "Not Supported interface found %s", iface);
+ }
+ }
+ this->refresh();
+}
+
+AccessibleNode *AccessibleNode::get(AtspiAccessible *node)
+{
+ LOG_SCOPE_F(9, "Accessible Node Factory %p", node);
+ if (node == nullptr) return nullptr;
+
+ AccessibleNode *cache = mNodeMap[node];
+ LOG_F(9, "Cache hit ? %p", cache);
+
+ if (!cache)
+ mNodeMap[node] = new AccessibleNode(node);
+ else
+ cache->refresh();
+
+ return mNodeMap[node];
+}
+
+void AccessibleNode::refresh() const
+{
+ gchar *rolename = atspi_accessible_get_role_name(mNode, NULL);
+ mRole = rolename;
+ g_free(rolename);
+
+#ifdef GBS_BUILD
+ gchar *uID = atspi_accessible_get_unique_id(mNode, NULL);
+ mRes = uID;
+ g_free(uID);
+#else
+ mRes = "Not_Supported";
+#endif
+
+ /*
+ GHashTable *attributes = atspi_accessible_get_attributes(mNode, NULL);
+ char *t = (char*)g_hash_table_lookup(attributes, "type");
+ char *s = (char*)g_hash_table_lookup(attributes, "style");
+
+ //LOG_F(INFO, "%s %s", t, s);
+
+ if (t) mType = std::string(t);
+ if (s) mStyle = std::string(s);
+
+ free(t);
+ free(s);
+
+ g_hash_table_unref(attributes);
+ */
+}
+
+int AccessibleNode::getChildCount() const
+{
+ return atspi_accessible_get_child_count(mNode, NULL);
+}
+
+AccessibleNode *AccessibleNode::getChildAt(int index) const
+{
+ AtspiAccessible *child =
+ atspi_accessible_get_child_at_index(mNode, index, NULL);
+ AccessibleNode *node = AccessibleNode::get(child);
+ if (child) g_object_unref(child);
+ return node;
+}
+
+AccessibleNode *AccessibleNode::getParent() const
+{
+ AtspiAccessible *parent = atspi_accessible_get_parent(mNode, NULL);
+ AccessibleNode * node = AccessibleNode::get(parent);
+ if (parent) g_object_unref(parent);
+ return node;
+}
+
+void AccessibleNode::print(int d, int m) const
+{
+ if (m <= 0 || d > m) return;
+
+ int n = 0;
+ AccessibleNode *child = nullptr;
+
+ this->print(d);
+ n = getChildCount();
+
+ for (int i = 0; i < n; i++) {
+ child = getChildAt(i);
+ if (child) child->print(d + 1, m);
+ }
+}
+
+void AccessibleNode::print(int d) const
+{
+ char *name = atspi_accessible_get_name(mNode, NULL);
+ char *role = atspi_accessible_get_role_name(mNode, NULL);
+ LOG_F(INFO, "%s - %p(%s) / role:%s, pkg:%s, text:%s",
+ std::string(d, ' ').c_str(), mNode, name, role, getPkg().c_str(),
+ getText().c_str());
+ free(name);
+ free(role);
+}
+
+bool AccessibleNode::isSupporting(AccessibleNodeInterface thisIface) const
+{
+ return (mSupportingIfaces & static_cast<int>(thisIface)) != 0;
+}
+
+bool AccessibleNode::hasFeatureProperty(NodeFeatureProperties prop) const
+{
+ return (mFeatureProperty & static_cast<int>(prop)) != 0;
+}
+
+void AccessibleNode::setFeatureProperty(NodeFeatureProperties prop, bool has)
+{
+ if (has)
+ mFeatureProperty |= static_cast<int>(prop);
+ else
+ mFeatureProperty &= ~static_cast<int>(prop);
+}
+
+std::string AccessibleNode::getDesc() const
+{
+ return mDesc;
+}
+
+std::string AccessibleNode::getText() const
+{
+ gchar *name = atspi_accessible_get_name(mNode, NULL);
+ mText = name;
+ mPkg = name;
+ g_free(name);
+
+ return mText;
+}
+
+std::string AccessibleNode::getPkg() const
+{
+ return mPkg;
+}
+
+std::string AccessibleNode::getRes() const
+{
+ return mRes;
+}
+std::string AccessibleNode::getType() const
+{
+ return mType;
+}
+Rect<int> AccessibleNode::getBoundingBox() const
+{
+ AtspiComponent *component = atspi_accessible_get_component_iface(mNode);
+ if (component) {
+ AtspiRect *extent = atspi_component_get_extents(
+ component, ATSPI_COORD_TYPE_SCREEN, NULL);
+ if (extent) {
+ mBoundingBox =
+ Rect<int>{extent->x, extent->y, extent->x + extent->width,
+ extent->y + extent->height};
+ g_free(extent);
+ }
+ g_object_unref(component);
+ }
+
+ return mBoundingBox;
+}
+
+bool AccessibleNode::isCheckable() const
+{
+ return hasFeatureProperty(NodeFeatureProperties::CHECKABLE);
+}
+
+bool AccessibleNode::isChecked() const
+{
+ return hasFeatureProperty(NodeFeatureProperties::CHECKED);
+}
+
+bool AccessibleNode::isClickable() const
+{
+ return hasFeatureProperty(NodeFeatureProperties::CLICKABLE);
+}
+
+bool AccessibleNode::isEnabled() const
+{
+ return hasFeatureProperty(NodeFeatureProperties::ENABLED);
+}
+
+bool AccessibleNode::isFocusable() const
+{
+ return hasFeatureProperty(NodeFeatureProperties::FOCUSABLE);
+}
+
+bool AccessibleNode::isFocused() const
+{
+ return hasFeatureProperty(NodeFeatureProperties::FOCUSED);
+}
+
+bool AccessibleNode::isLongClickable() const
+{
+ return hasFeatureProperty(NodeFeatureProperties::LONGCLICKABLE);
+}
+
+bool AccessibleNode::isScrollable() const
+{
+ return hasFeatureProperty(NodeFeatureProperties::SCROLLABLE);
+}
+
+bool AccessibleNode::isSelectable() const
+{
+ return hasFeatureProperty(NodeFeatureProperties::SELECTABLE);
+}
+
+bool AccessibleNode::isSelected() const
+{
+ return hasFeatureProperty(NodeFeatureProperties::SELECTED);
+}
+
+AtspiAccessible *AccessibleNode::getAccessible()
+{
+ return mNode;
+}
+
+void AccessibleNode::setValue(std::string &text) const
+{
+ AtspiEditableText *iface = atspi_accessible_get_editable_text(mNode);
+ if (iface) {
+ atspi_editable_text_insert_text(iface, 0, text.c_str(), text.length(),
+ NULL);
+ }
+}
\ No newline at end of file
--- /dev/null
+#include "Comparer.h"
+
+#include "loguru.hpp"
+
+Comparer::Comparer(const UiDevice *device, const UiSelector *selector,
+ const bool &earlyReturn)
+ : mDevice(device), mSelector(selector), mEarlyReturn(earlyReturn)
+{
+}
+
+Comparer::~Comparer() {}
+
+AccessibleNode *Comparer::findObject(const UiDevice * device,
+ const UiSelector * selector,
+ const AccessibleNode *root)
+{
+ Comparer comparer(device, selector, true);
+ std::vector<AccessibleNode *> ret = comparer.findObjects(root);
+ if (ret.size() > 0)
+ return ret[0];
+ else
+ return nullptr;
+}
+
+std::vector<AccessibleNode *> Comparer::findObjects(const UiDevice * device,
+ const UiSelector *selector,
+ const AccessibleNode *root)
+{
+ Comparer comparer(device, selector, false);
+ std::vector<AccessibleNode *> ret = comparer.findObjects(root);
+ return std::move(ret);
+}
+
+std::vector<AccessibleNode *> Comparer::findObjects(const AccessibleNode *root)
+{
+ std::list<std::shared_ptr<PartialMatch>> partialList{};
+ std::vector<AccessibleNode *> ret = findObjects(root, 0, 0, partialList);
+ return std::move(ret);
+}
+
+std::vector<AccessibleNode *> Comparer::findObjects(
+ const AccessibleNode *root, const int &index, const int &depth,
+ std::list<std::shared_ptr<PartialMatch>> &partialMatches)
+{
+ std::vector<AccessibleNode *> ret;
+ root->refresh();
+
+ // LOG_F(INFO, "%p %s / i:%d d:%d", root, root->getText().c_str(), index,
+ // depth);
+
+ for (auto match : partialMatches)
+ match->update(root, index, depth, partialMatches);
+
+ std::shared_ptr<PartialMatch> currentMatch =
+ PartialMatch::accept(root, mSelector, index, depth);
+ if (currentMatch) partialMatches.push_front(currentMatch);
+
+ int childCnt = root->getChildCount();
+ for (int i = 0; i < childCnt; i++) {
+ AccessibleNode * childNode = root->getChildAt(i);
+ std::vector<AccessibleNode *> childret =
+ findObjects(childNode, i, depth + 1, partialMatches);
+ ret.insert(ret.end(), childret.begin(), childret.end());
+
+ if (!ret.empty() && mEarlyReturn) return ret;
+ }
+
+ if (currentMatch && currentMatch->finalizeMatch())
+ ret.push_back(const_cast<AccessibleNode *>(root));
+
+ return ret;
+}
\ No newline at end of file
--- /dev/null
+#include "DeviceImpl/TM1Impl.h"
+
+#include <stdlib.h>
+#include <iostream>
+
+#include <stdlib.h>
+#include "loguru.hpp"
+
+TM1Impl::TM1Impl()
+{
+ LOG_SCOPE_F(INFO, "device implementation init");
+#ifdef GBSBUILD
+ mFakeTouchHandle =
+ efl_util_input_initialize_generator(EFL_UTIL_INPUT_DEVTYPE_TOUCHSCREEN);
+ mFakeKeyboardHandle =
+ efl_util_input_initialize_generator(EFL_UTIL_INPUT_DEVTYPE_KEYBOARD);
+#endif
+}
+
+TM1Impl::~TM1Impl()
+{
+#ifdef GBSBUILD
+ efl_util_input_deinitialize_generator(mFakeTouchHandle);
+ efl_util_input_deinitialize_generator(mFakeKeyboardHandle);
+#endif
+}
+
+bool TM1Impl::click(const int x, const int y)
+{
+ LOG_SCOPE_F(INFO, "click at (%d, %d)", x, y);
+#ifdef GBSBUILD
+ efl_util_input_generate_touch(mFakeTouchHandle, 0,
+ EFL_UTIL_INPUT_TOUCH_BEGIN, x, y);
+ usleep(50);
+ efl_util_input_generate_touch(mFakeTouchHandle, 0, EFL_UTIL_INPUT_TOUCH_END,
+ x, y);
+ return true;
+#else
+ return false;
+#endif
+}
+
+bool TM1Impl::touchDown(const int x, const int y)
+{
+#ifdef GBSBUILD
+ LOG_F(INFO, "%d %d", x, y);
+ efl_util_input_generate_touch(mFakeTouchHandle, 0,
+ EFL_UTIL_INPUT_TOUCH_BEGIN, x, y);
+#endif
+ return true;
+}
+
+bool TM1Impl::touchMove(const int x, const int y)
+{
+#ifdef GBSBUILD
+ LOG_F(INFO, "%d %d", x, y);
+ efl_util_input_generate_touch(mFakeTouchHandle, 0,
+ EFL_UTIL_INPUT_TOUCH_UPDATE, x, y);
+#endif
+ return true;
+}
+
+bool TM1Impl::touchUp(const int x, const int y)
+{
+#ifdef GBSBUILD
+ LOG_F(INFO, "%d %d", x, y);
+ efl_util_input_generate_touch(mFakeTouchHandle, 0, EFL_UTIL_INPUT_TOUCH_END,
+ x, y);
+#endif
+ return true;
+}
+
+bool TM1Impl::drag(const int sx, const int sy, const int ex, const int ey,
+ const int duration)
+{
+#ifdef GBSBUILD
+ int i, j;
+
+ // TODO fixed fps implementation
+
+ i = sx, j = sy;
+ LOG_SCOPE_F(INFO, "flicking (%d, %d)", i, j);
+
+ efl_util_input_generate_touch(mFakeTouchHandle, 0,
+ EFL_UTIL_INPUT_TOUCH_BEGIN, i, j);
+ for (; i <= ex && j <= ey; i += (ex - sx) / 10, j += (ey - sy) / 10) {
+ efl_util_input_generate_touch(mFakeTouchHandle, 0,
+ EFL_UTIL_INPUT_TOUCH_UPDATE, i, j);
+ usleep(duration * 1000);
+ LOG_SCOPE_F(INFO, "flicking (%d, %d)", i, j);
+ }
+ LOG_SCOPE_F(INFO, "flicking (%d, %d)", i, j);
+ efl_util_input_generate_touch(mFakeTouchHandle, 0, EFL_UTIL_INPUT_TOUCH_END,
+ i, j);
+#endif
+ return true;
+}
+
+bool TM1Impl::pressBack()
+{
+ return pressKeyCode("XF86Back");
+}
+
+bool TM1Impl::pressHome()
+{
+ return pressKeyCode("XF86Home");
+}
+
+bool TM1Impl::pressMenu()
+{
+ return pressKeyCode("XF86Menu");
+}
+
+bool TM1Impl::pressVolUp()
+{
+ return pressKeyCode("XF86AudioRaiseVolume");
+}
+
+bool TM1Impl::pressVolDown()
+{
+ return pressKeyCode("XF86AudioLowerVolume");
+}
+
+bool TM1Impl::pressPower()
+{
+ return pressKeyCode("XF86PowerOff");
+}
+
+bool TM1Impl::pressKeyCode(std::string keycode)
+{
+#ifdef GBSBUILD
+ efl_util_input_generate_key(mFakeKeyboardHandle, keycode.c_str(), 1);
+ efl_util_input_generate_key(mFakeKeyboardHandle, keycode.c_str(), 0);
+#endif
+ return true;
+}
+
+bool TM1Impl::takeScreenshot(std::string path, float scale, int quality)
+{
+ return false;
+}
\ No newline at end of file
--- /dev/null
+#include "PartialMatch.h"
+
+#include <iostream>
+#include <set>
+
+#include "loguru.hpp"
+
+bool PartialMatch::checkCriteria(const UiSelector * sel,
+ const AccessibleNode *node)
+{
+ if (sel->mPkg.length() > 0 && sel->mPkg.compare(node->getPkg()))
+ return false;
+ if (sel->mRes.length() > 0 && sel->mRes.compare(node->getRes()))
+ return false;
+ if (sel->mText.length() > 0 && sel->mText.compare(node->getText()))
+ return false;
+ if (sel->mDesc.length() > 0 && sel->mDesc.compare(node->getDesc()))
+ return false;
+ if (sel->mType.length() > 0 && sel->mType.compare(node->getType()))
+ return false;
+
+ LOG_F(INFO, "node mPkg :%s, sel->desc :%s | %ld", node->getPkg().c_str(),
+ sel->mPkg.c_str(), sel->mPkg.length());
+ LOG_F(INFO, "node mRes :%s, sel->desc :%s | %ld", node->getRes().c_str(),
+ sel->mRes.c_str(), sel->mRes.length());
+ LOG_F(INFO, "node mText :%s, sel->desc :%s | %ld", node->getText().c_str(),
+ sel->mText.c_str(), sel->mText.length());
+ LOG_F(INFO, "node mDesc :%s, sel->desc :%s | %ld", node->getDesc().c_str(),
+ sel->mDesc.c_str(), sel->mDesc.length());
+ LOG_F(INFO, "node mType :%s, sel->type :%s | %ld", node->getType().c_str(),
+ sel->mType.c_str(), sel->mType.length());
+
+ return true;
+}
+
+PartialMatch::PartialMatch() : mSelector{nullptr}, mDepth{-1}, mPartialMatches{}
+{
+}
+
+PartialMatch::PartialMatch(const UiSelector *selector, const int absDepth)
+ : mSelector{selector}, mDepth{absDepth}, mPartialMatches{}
+{
+}
+
+std::shared_ptr<PartialMatch> PartialMatch::accept(const AccessibleNode *node,
+ const UiSelector *selector,
+ int index, int depth)
+{
+ return PartialMatch::accept(node, selector, index, depth, depth);
+}
+
+std::shared_ptr<PartialMatch> PartialMatch::accept(const AccessibleNode *node,
+ const UiSelector *selector,
+ int index, int absoluteDepth,
+ int relativeDepth)
+{
+ PartialMatch *match = nullptr;
+
+ if (PartialMatch::checkCriteria(selector, node)) {
+ LOG_SCOPE_F(INFO, "New Match found %p %d", selector, absoluteDepth);
+ match = new PartialMatch(selector, absoluteDepth);
+ }
+
+ return std::shared_ptr<PartialMatch>(match);
+}
+
+void PartialMatch::update(
+ const AccessibleNode *node, int index, int depth,
+ std::list<std::shared_ptr<PartialMatch>> &partialMatches)
+{
+ for (auto childSelector : mSelector->mChild) {
+ auto match = PartialMatch::accept(node, childSelector, index, depth,
+ depth - mDepth);
+ if (match) {
+ mPartialMatches.push_back(match);
+ partialMatches.push_front(match);
+ }
+ }
+}
+
+bool PartialMatch::finalizeMatch()
+{
+ std::set<UiSelector *> matches;
+ for (auto match : mPartialMatches) {
+ if (match->finalizeMatch()) {
+ matches.insert(const_cast<UiSelector *>(match->mSelector));
+ }
+ }
+
+ for (auto sel : mSelector->mChild) {
+ if (!matches.count(sel)) return false;
+ }
+ return true;
+}
--- /dev/null
+#include "Sel.h"
+#include <utility>
+
+std::unique_ptr<UiSelector> Sel::text(const std::string &text)
+{
+ std::unique_ptr<UiSelector> sel = std::make_unique<UiSelector>();
+ sel->text(text);
+ return sel;
+}
+
+std::unique_ptr<UiSelector> Sel::type(const std::string &text)
+{
+ std::unique_ptr<UiSelector> sel = std::make_unique<UiSelector>();
+ sel->type(text);
+ return sel;
+}
+
+std::unique_ptr<UiSelector> Sel::depth(const int &depth)
+{
+ std::unique_ptr<UiSelector> sel = std::make_unique<UiSelector>();
+ sel->depth(depth);
+ return sel;
+}
\ No newline at end of file
--- /dev/null
+#include "UiDevice.h"
+#include "Accessible.h"
+#include "Comparer.h"
+#include "DeviceImpl/TM1Impl.h"
+
+#include <unistd.h>
+#include <utility>
+#include <vector>
+
+UiDevice::UiDevice() : UiDevice(DeviceType::DEFAULT, nullptr) {}
+
+UiDevice::UiDevice(DeviceType type, IDevice *impl)
+ : mType(type), mDeviceImpl(impl), mWaiter(new Waiter{this})
+{
+}
+
+UiDevice::~UiDevice()
+{
+ delete mDeviceImpl;
+ delete mWaiter;
+}
+
+UiDevice *UiDevice::getInstance(DeviceType type)
+{
+ static UiDevice *device = nullptr;
+#ifdef TIZEN
+ if (!device) device = new UiDevice(type, new TM1Impl());
+#endif
+ return device;
+}
+
+const AccessibleNode *UiDevice::getWindowRoot() const
+{
+ AccessibleNode *root = Accessible::getInstance()->getTopNode();
+ // root->print(0,6);
+ return root;
+}
+
+bool UiDevice::hasObject(const UiSelector *selector) const
+{
+ AccessibleNode *node =
+ Comparer::findObject(this, selector, getWindowRoot());
+ if (node != nullptr) return true;
+ return false;
+}
+
+std::unique_ptr<UiObject> UiDevice::findObject(const UiSelector *selector) const
+{
+ AccessibleNode *node =
+ Comparer::findObject(this, selector, getWindowRoot());
+ if (node)
+ return std::make_unique<UiObject>(this, selector, node);
+ else
+ return std::unique_ptr<UiObject>{nullptr};
+}
+
+std::vector<std::unique_ptr<UiObject>> UiDevice::findObjects(
+ const UiSelector *selector) const
+{
+ std::vector<std::unique_ptr<UiObject>> ret{};
+ std::vector<AccessibleNode *> nodes =
+ Comparer::findObjects(this, selector, getWindowRoot());
+ for (const AccessibleNode *node : nodes)
+ ret.push_back(std::make_unique<UiObject>(this, selector, node));
+
+ return std::move(ret);
+}
+bool UiDevice::waitFor(
+ const std::function<bool(const ISearchable *)> condition) const
+{
+ return mWaiter->waitFor(condition);
+}
+
+std::unique_ptr<UiObject> UiDevice::waitFor(
+ const std::function<std::unique_ptr<UiObject>(const ISearchable *)>
+ condition) const
+{
+ return mWaiter->waitFor(condition);
+}
+
+bool UiDevice::click(const int x, const int y)
+{
+ return mDeviceImpl->click(x, y);
+}
+
+bool UiDevice::drag(const int sx, const int sy, const int ex, const int ey,
+ const int steps)
+{
+ return mDeviceImpl->drag(sx, sy, ex, ey, steps);
+}
+
+bool UiDevice::touchDown(const int x, const int y)
+{
+ return mDeviceImpl->touchDown(x, y);
+}
+
+bool UiDevice::touchMove(const int x, const int y)
+{
+ return mDeviceImpl->touchMove(x, y);
+}
+
+bool UiDevice::touchUp(const int x, const int y)
+{
+ return mDeviceImpl->touchUp(x, y);
+}
+
+bool UiDevice::pressBack()
+{
+ return mDeviceImpl->pressBack();
+}
+
+bool UiDevice::pressHome()
+{
+ return mDeviceImpl->pressHome();
+}
+
+bool UiDevice::pressMenu()
+{
+ return mDeviceImpl->pressMenu();
+}
+
+bool UiDevice::pressVolUp()
+{
+ return mDeviceImpl->pressVolUp();
+}
+
+bool UiDevice::pressVolDown()
+{
+ return mDeviceImpl->pressVolDown();
+}
+
+bool UiDevice::pressPower()
+{
+ return mDeviceImpl->pressPower();
+}
+
+bool UiDevice::pressKeyCode(std::string keycode)
+{
+ return mDeviceImpl->pressKeyCode(keycode);
+}
+
+bool UiDevice::takeScreenshot(std::string path, float scale, int quality)
+{
+ return mDeviceImpl->takeScreenshot(path, scale, quality);
+}
\ No newline at end of file
--- /dev/null
+#include "UiObject.h"
+#include "Comparer.h"
+#include "Sel.h"
+
+#include <iostream>
+#include <utility>
+
+#include "loguru.hpp"
+
+UiObject::UiObject() {}
+
+UiObject::~UiObject()
+{
+ if (mWaiter) delete mWaiter;
+}
+
+UiObject::UiObject(const UiDevice *device, const UiSelector *selector,
+ const AccessibleNode *node)
+ : mDevice(device),
+ mSelector(selector),
+ mNode(node),
+ mWaiter(new Waiter{this, this})
+{
+ // tood interface to interact with input interface
+ // mInputImple = mDevice->getInputInterface();
+}
+
+UiObject::UiObject(const UiObject &src)
+ : mDevice(src.mDevice),
+ mSelector(src.mSelector),
+ mNode(src.mNode),
+ mWaiter{src.mWaiter}
+{
+}
+
+UiObject::UiObject(UiObject &&src)
+ : mDevice(src.mDevice),
+ mSelector(src.mSelector),
+ mNode(src.mNode),
+ mWaiter{src.mWaiter}
+{
+ src.mDevice = nullptr;
+ src.mSelector = nullptr;
+ src.mNode = nullptr;
+ src.mWaiter = nullptr;
+}
+
+bool UiObject::hasObject(const UiSelector *selector) const
+{
+ AccessibleNode *node =
+ Comparer::findObject(mDevice, selector, getAccessibleNode());
+ if (node != nullptr) {
+ // todo : what is this node.recycle()
+ return true;
+ }
+ return false;
+}
+
+std::unique_ptr<UiObject> UiObject::findObject(const UiSelector *selector) const
+{
+ AccessibleNode *node =
+ Comparer::findObject(mDevice, selector, getAccessibleNode());
+ if (node)
+ return std::make_unique<UiObject>(mDevice, selector, node);
+ else
+ return std::unique_ptr<UiObject>{nullptr};
+}
+
+std::vector<std::unique_ptr<UiObject>> UiObject::findObjects(
+ const UiSelector *selector) const
+{
+ return std::vector<std::unique_ptr<UiObject>>{};
+}
+
+bool UiObject::waitFor(
+ const std::function<bool(const ISearchable *)> condition) const
+{
+ return mWaiter->waitFor(condition);
+}
+
+std::unique_ptr<UiObject> UiObject::waitFor(
+ const std::function<std::unique_ptr<UiObject>(const ISearchable *)>
+ condition) const
+{
+ return mWaiter->waitFor(condition);
+}
+
+bool UiObject::waitFor(
+ const std::function<bool(const UiObject *)> condition) const
+{
+ LOG_F(INFO, "asdf");
+ return mWaiter->waitFor(condition);
+}
+
+UiObject *UiObject::getParent() const
+{
+ AccessibleNode *node = getAccessibleNode()->getParent();
+ if (!node) return nullptr;
+ return new UiObject(mDevice, mSelector, node);
+}
+
+int UiObject::getChildCount() const
+{
+ return getAccessibleNode()->getChildCount();
+}
+
+std::vector<std::unique_ptr<UiObject>> UiObject::getChildren() const
+{
+ return findObjects(Sel::depth(1).get());
+}
+
+std::string UiObject::getContentDescription() const
+{
+ return getAccessibleNode()->getDesc();
+}
+
+std::string UiObject::getApplicationPackage() const
+{
+ return getAccessibleNode()->getPkg();
+}
+
+std::string UiObject::getResourceName() const
+{
+ return getAccessibleNode()->getRes();
+}
+
+std::string UiObject::getText() const
+{
+ return getAccessibleNode()->getText();
+}
+
+void UiObject::setText(std::string &text)
+{
+ getAccessibleNode()->setValue(text);
+}
+
+bool UiObject::isCheckable() const
+{
+ return getAccessibleNode()->isCheckable();
+}
+
+bool UiObject::isChecked() const
+{
+ return getAccessibleNode()->isChecked();
+}
+
+bool UiObject::isClickable() const
+{
+ return getAccessibleNode()->isClickable();
+}
+
+bool UiObject::isEnabled() const
+{
+ return getAccessibleNode()->isEnabled();
+}
+
+bool UiObject::isFocusable() const
+{
+ return getAccessibleNode()->isFocusable();
+}
+
+bool UiObject::isFocused() const
+{
+ return getAccessibleNode()->isFocused();
+}
+
+bool UiObject::isLongClickable() const
+{
+ return getAccessibleNode()->isLongClickable();
+}
+
+bool UiObject::isScrollable() const
+{
+ return getAccessibleNode()->isScrollable();
+}
+
+bool UiObject::isSelectable() const
+{
+ return getAccessibleNode()->isSelectable();
+}
+
+bool UiObject::isSelected() const
+{
+ return getAccessibleNode()->isSelected();
+}
+
+void UiObject::refresh() const
+{
+ mNode->refresh();
+}
+
+void UiObject::click() const
+{
+ LOG_SCOPE_F(INFO, "click on obj %p", this);
+ mNode->refresh();
+ const Rect<int> rect = mNode->getBoundingBox();
+ std::cout << rect.mTopLeft.x << ", " << rect.mTopLeft.y << std::endl;
+ const Point2D<int> midPoint = rect.midPoint();
+ const_cast<UiDevice *>(mDevice)->click(midPoint.x, midPoint.y);
+ // todo click implementation
+}
+
+const AccessibleNode *UiObject::getAccessibleNode() const
+{
+ if (mNode == nullptr) throw;
+
+ // TODO : wait for animation and refresh current node
+ // mDevice->waitForIdle();
+ // mNode->refresh();
+
+ return mNode;
+}
\ No newline at end of file
--- /dev/null
+#include "UiSelector.h"
+#include <string>
+
+UiSelector::UiSelector()
+ : mText{""}, mPkg{""}, mRes{""}, mDesc{""}, mType{""}, mDepth{-1}, mChild{}
+{
+}
+/*
+UiSelector::UiSelector(const UiSelector &src)
+{
+ // 복사 생성자
+}
+
+UiSelector& UiSelector::operator= (const UiSelector& src)
+{
+ // = 오버라이드
+ if (this == &src) return *this; // 자기 대입 방지
+ return *this;
+}
+*/
+
+UiSelector *UiSelector::desc(const std::string &text)
+{
+ this->mDesc = text;
+ return this;
+}
+
+UiSelector *UiSelector::text(const std::string &text)
+{
+ this->mText = text;
+ return this;
+}
+
+UiSelector *UiSelector::pkg(const std::string &text)
+{
+ this->mPkg = text;
+ return this;
+}
+
+UiSelector *UiSelector::res(const std::string &text)
+{
+ this->mRes = text;
+ return this;
+}
+
+UiSelector *UiSelector::type(const std::string &text)
+{
+ this->mType = text;
+ return this;
+}
+
+UiSelector *UiSelector::depth(int depth)
+{
+ this->mDepth = depth;
+ return this;
+}
+
+UiSelector *UiSelector::hasChild(UiSelector *child)
+{
+ mChild.push_back(child);
+ return this;
+}
--- /dev/null
+#include <Until.h>
+
+#include <UiObject.h>
+#include <loguru.hpp>
+
+std::function<bool(const ISearchable *)> Until::hasObject(
+ const UiSelector *selector)
+{
+ return [=](const ISearchable *searchable) -> bool {
+ LOG_SCOPE_F(INFO, "sel:%p, search:%p", selector, searchable);
+ std::unique_ptr<UiObject> obj = searchable->findObject(selector);
+ return obj.get() != nullptr;
+ };
+}
+
+std::function<std::unique_ptr<UiObject>(const ISearchable *)> Until::findObject(
+ const UiSelector *selector)
+{
+ return [=](const ISearchable *searchable) -> std::unique_ptr<UiObject> {
+ LOG_SCOPE_F(INFO, "sel:%p, search:%p", selector, searchable);
+ std::unique_ptr<UiObject> obj = searchable->findObject(selector);
+ return obj;
+ };
+}
+
+std::function<bool(const UiObject *)> Until::checkable(const bool isCheckable)
+{
+ return [=](const UiObject *object) -> bool {
+ LOG_SCOPE_F(INFO, "waitfor ischeckable %d for obj %p", isCheckable,
+ object);
+ return object->isClickable() == isCheckable;
+ };
+}
\ No newline at end of file
--- /dev/null
+#include "Waiter.h"
+#include <unistd.h>
+#include <chrono>
+#include <thread>
+
+#include "ISearchable.h"
+#include "UiObject.h"
+#include "loguru.hpp"
+
+Waiter::Waiter() : Waiter(nullptr) {}
+
+Waiter::~Waiter() {}
+
+Waiter::Waiter(const ISearchable *searchableObject, const UiObject *uiObject)
+ : mSearchableObject{searchableObject},
+ mUiObject{uiObject},
+ WAIT_INTERVAL_MS{500},
+ WAIT_TIMEOUT_MS{5000}
+{
+}
+
+template bool Waiter::waitFor(
+ const std::function<bool(const ISearchable *)> condition) const;
+
+template std::unique_ptr<UiObject> Waiter::waitFor(
+ const std::function<std::unique_ptr<UiObject>(const ISearchable *)>
+ condition) const;
+
+template bool Waiter::waitFor(
+ const std::function<bool(const UiObject *)> condition) const;
+
+template <typename R>
+R Waiter::waitFor(const std::function<R(const ISearchable *)> condition) const
+{
+ // startTime = currentTime();
+ std::chrono::system_clock::time_point start =
+ std::chrono::system_clock::now();
+ R result = condition(mSearchableObject);
+ while (!result) {
+ if ((std::chrono::system_clock::now() - start) >
+ std::chrono::milliseconds{WAIT_TIMEOUT_MS})
+ break;
+ std::this_thread::sleep_for(
+ std::chrono::milliseconds{WAIT_INTERVAL_MS});
+ result = condition(mSearchableObject);
+ }
+ return result;
+}
+
+template <typename R>
+R Waiter::waitFor(const std::function<R(const UiObject *)> condition) const
+{
+ LOG_F(INFO, "1");
+ if (mUiObject) {
+ LOG_F(INFO, "2");
+ std::chrono::system_clock::time_point start =
+ std::chrono::system_clock::now();
+ R result = condition(mUiObject);
+ LOG_F(INFO, "3 : %d", result);
+ while (!result) {
+ if ((std::chrono::system_clock::now() - start) >
+ std::chrono::milliseconds{WAIT_TIMEOUT_MS})
+ break;
+ std::this_thread::sleep_for(
+ std::chrono::milliseconds{WAIT_INTERVAL_MS});
+ result = condition(mUiObject);
+ LOG_F(INFO, "4 : %d", result);
+ }
+ return result;
+ }
+ return R();
+}
\ No newline at end of file
--- /dev/null
+/*
+Loguru logging library for C++, by Emil Ernerfeldt.
+www.github.com/emilk/loguru
+If you find Loguru useful, please let me know on twitter or in a mail!
+Twitter: @ernerfeldt
+Mail: emil.ernerfeldt@gmail.com
+Website: www.ilikebigbits.com
+
+# License
+ This software is in the public domain. Where that dedication is not
+ recognized, you are granted a perpetual, irrevocable license to
+ copy, modify and distribute it as you see fit.
+
+# Inspiration
+ Much of Loguru was inspired by GLOG, https://code.google.com/p/google-glog/.
+ The choice of public domain is fully due Sean T. Barrett
+ and his wonderful stb libraries at https://github.com/nothings/stb.
+
+# Version history
+ * Version 0.1.0 - 2015-03-22 - Works great on Mac.
+ * Version 0.2.0 - 2015-09-17 - Removed the only dependency.
+ * Version 0.3.0 - 2015-10-02 - Drop-in replacement for most of GLOG
+ * Version 0.4.0 - 2015-10-07 - Single-file!
+ * Version 0.5.0 - 2015-10-17 - Improved file logging
+ * Version 0.6.0 - 2015-10-24 - Add stack traces
+ * Version 0.7.0 - 2015-10-27 - Signals
+ * Version 0.8.0 - 2015-10-30 - Color logging.
+ * Version 0.9.0 - 2015-11-26 - ABORT_S and proper handling of FATAL
+ * Version 1.0.0 - 2016-02-14 - ERROR_CONTEXT
+ * Version 1.1.0 - 2016-02-19 - -v OFF, -v INFO etc
+ * Version 1.1.1 - 2016-02-20 - textprintf vs strprintf
+ * Version 1.1.2 - 2016-02-22 - Remove g_alsologtostderr
+ * Version 1.1.3 - 2016-02-29 - ERROR_CONTEXT as linked list
+ * Version 1.2.0 - 2016-03-19 - Add get_thread_name()
+ * Version 1.2.1 - 2016-03-20 - Minor fixes
+ * Version 1.2.2 - 2016-03-29 - Fix issues with set_fatal_handler throwing an exception
+ * Version 1.2.3 - 2016-05-16 - Log current working directory in loguru::init().
+ * Version 1.2.4 - 2016-05-18 - Custom replacement for -v in loguru::init() by bjoernpollex
+ * Version 1.2.5 - 2016-05-18 - Add ability to print ERROR_CONTEXT of parent thread.
+ * Version 1.2.6 - 2016-05-19 - Bug fix regarding VLOG verbosity argument lacking ().
+ * Version 1.2.7 - 2016-05-23 - Fix PATH_MAX problem.
+ * Version 1.2.8 - 2016-05-26 - Add shutdown() and remove_all_callbacks()
+ * Version 1.2.9 - 2016-06-09 - Use a monotonic clock for uptime.
+ * Version 1.3.0 - 2016-07-20 - Fix issues with callback flush/close not being called.
+ * Version 1.3.1 - 2016-07-20 - Add LOGURU_UNSAFE_SIGNAL_HANDLER to toggle stacktrace on signals.
+ * Version 1.3.2 - 2016-07-20 - Add loguru::arguments()
+ * Version 1.4.0 - 2016-09-15 - Semantic versioning + add loguru::create_directories
+ * Version 1.4.1 - 2016-09-29 - Customize formating with LOGURU_FILENAME_WIDTH
+ * Version 1.5.0 - 2016-12-22 - LOGURU_USE_FMTLIB by kolis and LOGURU_WITH_FILEABS by scinart
+ * Version 1.5.1 - 2017-08-08 - Terminal colors on Windows 10 thanks to looki
+ * Version 1.6.0 - 2018-01-03 - Add LOGURU_RTTI and LOGURU_STACKTRACES settings
+ * Version 1.7.0 - 2018-01-03 - Add ability to turn off the preamble with loguru::g_preamble
+ * Version 1.7.1 - 2018-04-05 - Add function get_fatal_handler
+ * Version 1.7.2 - 2018-04-22 - Fix a bug where large file names could cause stack corruption (thanks @ccamporesi)
+ * Version 1.8.0 - 2018-04-23 - Shorten long file names to keep preamble fixed width
+ * Version 1.9.0 - 2018-09-22 - Adjust terminal colors, add LOGURU_VERBOSE_SCOPE_ENDINGS, add LOGURU_SCOPE_TIME_PRECISION, add named log levels
+ * Version 2.0.0 - 2018-09-22 - Split loguru.hpp into loguru.hpp and loguru.cpp
+
+# Compiling
+ Just include <loguru.hpp> where you want to use Loguru.
+ Then, in one .cpp file #include <loguru.cpp>
+ Make sure you compile with -std=c++11 -lstdc++ -lpthread -ldl
+
+# Usage
+ For details, please see the official documentation at emilk.github.io/loguru
+
+ #include <loguru.hpp>
+
+ int main(int argc, char* argv[]) {
+ loguru::init(argc, argv);
+
+ // Put every log message in "everything.log":
+ loguru::add_file("everything.log", loguru::Append, loguru::Verbosity_MAX);
+
+ LOG_F(INFO, "The magic number is %d", 42);
+ }
+
+*/
+
+#if defined(LOGURU_IMPLEMENTATION)
+ #warning "You are defining LOGURU_IMPLEMENTATION. This is for older versions of Loguru. You should now instead include loguru.cpp (or build it and link with it)"
+#endif
+
+// Disable all warnings from gcc/clang:
+#if defined(__clang__)
+ #pragma clang system_header
+#elif defined(__GNUC__)
+ #pragma GCC system_header
+#endif
+
+#ifndef LOGURU_HAS_DECLARED_FORMAT_HEADER
+#define LOGURU_HAS_DECLARED_FORMAT_HEADER
+
+// Semantic versioning. Loguru version can be printed with printf("%d.%d.%d", LOGURU_VERSION_MAJOR, LOGURU_VERSION_MINOR, LOGURU_VERSION_PATCH);
+#define LOGURU_VERSION_MAJOR 2
+#define LOGURU_VERSION_MINOR 0
+#define LOGURU_VERSION_PATCH 0
+
+#if defined(_MSC_VER)
+#include <sal.h> // Needed for _In_z_ etc annotations
+#endif
+
+// ----------------------------------------------------------------------------
+
+#ifndef LOGURU_EXPORT
+ // Define to your project's export declaration if needed for use in a shared library.
+ #define LOGURU_EXPORT
+#endif
+
+#ifndef LOGURU_SCOPE_TEXT_SIZE
+ // Maximum length of text that can be printed by a LOG_SCOPE.
+ // This should be long enough to get most things, but short enough not to clutter the stack.
+ #define LOGURU_SCOPE_TEXT_SIZE 196
+#endif
+
+#ifndef LOGURU_FILENAME_WIDTH
+ // Width of the column containing the file name
+ #define LOGURU_FILENAME_WIDTH 23
+#endif
+
+#ifndef LOGURU_THREADNAME_WIDTH
+ // Width of the column containing the thread name
+ #define LOGURU_THREADNAME_WIDTH 16
+#endif
+
+#ifndef LOGURU_SCOPE_TIME_PRECISION
+ // Resolution of scope timers. 3=ms, 6=us, 9=ns
+ #define LOGURU_SCOPE_TIME_PRECISION 3
+#endif
+
+#ifndef LOGURU_CATCH_SIGABRT
+ // Should Loguru catch SIGABRT to print stack trace etc?
+ #define LOGURU_CATCH_SIGABRT 1
+#endif
+
+#ifndef LOGURU_VERBOSE_SCOPE_ENDINGS
+ // Show milliseconds and scope name at end of scope.
+ #define LOGURU_VERBOSE_SCOPE_ENDINGS 1
+#endif
+
+#ifndef LOGURU_REDEFINE_ASSERT
+ #define LOGURU_REDEFINE_ASSERT 0
+#endif
+
+#ifndef LOGURU_WITH_STREAMS
+ #define LOGURU_WITH_STREAMS 0
+#endif
+
+#ifndef LOGURU_REPLACE_GLOG
+ #define LOGURU_REPLACE_GLOG 0
+#endif
+
+#if LOGURU_REPLACE_GLOG
+ #undef LOGURU_WITH_STREAMS
+ #define LOGURU_WITH_STREAMS 1
+#endif
+
+#ifndef LOGURU_UNSAFE_SIGNAL_HANDLER
+ #define LOGURU_UNSAFE_SIGNAL_HANDLER 1
+#endif
+
+#if LOGURU_IMPLEMENTATION
+ #undef LOGURU_WITH_STREAMS
+ #define LOGURU_WITH_STREAMS 1
+#endif
+
+#ifndef LOGURU_USE_FMTLIB
+ #define LOGURU_USE_FMTLIB 0
+#endif
+
+#ifndef LOGURU_WITH_FILEABS
+ #define LOGURU_WITH_FILEABS 0
+#endif
+
+#ifndef LOGURU_RTTI
+#if defined(__clang__)
+ #if __has_feature(cxx_rtti)
+ #define LOGURU_RTTI 1
+ #endif
+#elif defined(__GNUG__)
+ #if defined(__GXX_RTTI)
+ #define LOGURU_RTTI 1
+ #endif
+#elif defined(_MSC_VER)
+ #if defined(_CPPRTTI)
+ #define LOGURU_RTTI 1
+ #endif
+#endif
+#endif
+
+// --------------------------------------------------------------------
+// Utility macros
+
+#define LOGURU_CONCATENATE_IMPL(s1, s2) s1 ## s2
+#define LOGURU_CONCATENATE(s1, s2) LOGURU_CONCATENATE_IMPL(s1, s2)
+
+#ifdef __COUNTER__
+# define LOGURU_ANONYMOUS_VARIABLE(str) LOGURU_CONCATENATE(str, __COUNTER__)
+#else
+# define LOGURU_ANONYMOUS_VARIABLE(str) LOGURU_CONCATENATE(str, __LINE__)
+#endif
+
+#if defined(__clang__) || defined(__GNUC__)
+ // Helper macro for declaring functions as having similar signature to printf.
+ // This allows the compiler to catch format errors at compile-time.
+ #define LOGURU_PRINTF_LIKE(fmtarg, firstvararg) __attribute__((__format__ (__printf__, fmtarg, firstvararg)))
+ #define LOGURU_FORMAT_STRING_TYPE const char*
+#elif defined(_MSC_VER)
+ #define LOGURU_PRINTF_LIKE(fmtarg, firstvararg)
+ #define LOGURU_FORMAT_STRING_TYPE _In_z_ _Printf_format_string_ const char*
+#else
+ #define LOGURU_PRINTF_LIKE(fmtarg, firstvararg)
+ #define LOGURU_FORMAT_STRING_TYPE const char*
+#endif
+
+// Used to mark log_and_abort for the benefit of the static analyzer and optimizer.
+#if defined(_MSC_VER)
+#define LOGURU_NORETURN __declspec(noreturn)
+#else
+#define LOGURU_NORETURN __attribute__((noreturn))
+#endif
+
+#if defined(_MSC_VER)
+#define LOGURU_PREDICT_FALSE(x) (x)
+#define LOGURU_PREDICT_TRUE(x) (x)
+#else
+#define LOGURU_PREDICT_FALSE(x) (__builtin_expect(x, 0))
+#define LOGURU_PREDICT_TRUE(x) (__builtin_expect(!!(x), 1))
+#endif
+
+#if LOGURU_USE_FMTLIB
+ #include <fmt/format.h>
+#endif
+
+#ifdef _WIN32
+ #define STRDUP(str) _strdup(str)
+#else
+ #define STRDUP(str) strdup(str)
+#endif
+
+// --------------------------------------------------------------------
+
+namespace loguru
+{
+ // Simple RAII ownership of a char*.
+ class LOGURU_EXPORT Text
+ {
+ public:
+ explicit Text(char* owned_str) : _str(owned_str) {}
+ ~Text();
+ Text(Text&& t)
+ {
+ _str = t._str;
+ t._str = nullptr;
+ }
+ Text(Text& t) = delete;
+ Text& operator=(Text& t) = delete;
+ void operator=(Text&& t) = delete;
+
+ const char* c_str() const { return _str; }
+ bool empty() const { return _str == nullptr || *_str == '\0'; }
+
+ char* release()
+ {
+ auto result = _str;
+ _str = nullptr;
+ return result;
+ }
+
+ private:
+ char* _str;
+ };
+
+ // Like printf, but returns the formated text.
+ LOGURU_EXPORT
+ Text textprintf(LOGURU_FORMAT_STRING_TYPE format, ...) LOGURU_PRINTF_LIKE(1, 2);
+
+ // Overloaded for variadic template matching.
+ LOGURU_EXPORT
+ Text textprintf();
+
+ using Verbosity = int;
+
+#undef FATAL
+#undef ERROR
+#undef WARNING
+#undef INFO
+#undef MAX
+
+ enum NamedVerbosity : Verbosity
+ {
+ // Used to mark an invalid verbosity. Do not log to this level.
+ Verbosity_INVALID = -10, // Never do LOG_F(INVALID)
+
+ // You may use Verbosity_OFF on g_stderr_verbosity, but for nothing else!
+ Verbosity_OFF = -9, // Never do LOG_F(OFF)
+
+ // Prefer to use ABORT_F or ABORT_S over LOG_F(FATAL) or LOG_S(FATAL).
+ Verbosity_FATAL = -3,
+ Verbosity_ERROR = -2,
+ Verbosity_WARNING = -1,
+
+ // Normal messages. By default written to stderr.
+ Verbosity_INFO = 0,
+
+ // Same as Verbosity_INFO in every way.
+ Verbosity_0 = 0,
+
+ // Verbosity levels 1-9 are generally not written to stderr, but are written to file.
+ Verbosity_1 = +1,
+ Verbosity_2 = +2,
+ Verbosity_3 = +3,
+ Verbosity_4 = +4,
+ Verbosity_5 = +5,
+ Verbosity_6 = +6,
+ Verbosity_7 = +7,
+ Verbosity_8 = +8,
+ Verbosity_9 = +9,
+
+ // Don not use higher verbosity levels, as that will make grepping log files harder.
+ Verbosity_MAX = +9,
+ };
+
+ struct Message
+ {
+ // You would generally print a Message by just concating the buffers without spacing.
+ // Optionally, ignore preamble and indentation.
+ Verbosity verbosity; // Already part of preamble
+ const char* filename; // Already part of preamble
+ unsigned line; // Already part of preamble
+ const char* preamble; // Date, time, uptime, thread, file:line, verbosity.
+ const char* indentation; // Just a bunch of spacing.
+ const char* prefix; // Assertion failure info goes here (or "").
+ const char* message; // User message goes here.
+ };
+
+ /* Everything with a verbosity equal or greater than g_stderr_verbosity will be
+ written to stderr. You can set this in code or via the -v argument.
+ Set to loguru::Verbosity_OFF to write nothing to stderr.
+ Default is 0, i.e. only log ERROR, WARNING and INFO are written to stderr.
+ */
+ LOGURU_EXPORT extern Verbosity g_stderr_verbosity;
+ LOGURU_EXPORT extern bool g_colorlogtostderr; // True by default.
+ LOGURU_EXPORT extern unsigned g_flush_interval_ms; // 0 (unbuffered) by default.
+ LOGURU_EXPORT extern bool g_preamble; // Prefix each log line with date, time etc? True by default.
+
+ /* Specify the verbosity used by loguru to log its info messages including the header
+ logged when logged::init() is called or on exit. Default is 0 (INFO).
+ */
+ LOGURU_EXPORT extern Verbosity g_internal_verbosity;
+
+ // Turn off individual parts of the preamble
+ LOGURU_EXPORT extern bool g_preamble_date; // The date field
+ LOGURU_EXPORT extern bool g_preamble_time; // The time of the current day
+ LOGURU_EXPORT extern bool g_preamble_uptime; // The time since init call
+ LOGURU_EXPORT extern bool g_preamble_thread; // The logging thread
+ LOGURU_EXPORT extern bool g_preamble_file; // The file from which the log originates from
+ LOGURU_EXPORT extern bool g_preamble_verbose; // The verbosity field
+ LOGURU_EXPORT extern bool g_preamble_pipe; // The pipe symbol right before the message
+
+ // May not throw!
+ typedef void (*log_handler_t)(void* user_data, const Message& message);
+ typedef void (*close_handler_t)(void* user_data);
+ typedef void (*flush_handler_t)(void* user_data);
+
+ // May throw if that's how you'd like to handle your errors.
+ typedef void (*fatal_handler_t)(const Message& message);
+
+ // Given a verbosity level, return the level's name or nullptr.
+ typedef const char* (*verbosity_to_name_t)(Verbosity verbosity);
+
+ // Given a verbosity level name, return the verbosity level or
+ // Verbosity_INVALID if name is not recognized.
+ typedef Verbosity (*name_to_verbosity_t)(const char* name);
+
+ /* Should be called from the main thread.
+ You don't *need* to call this, but if you do you get:
+ * Signal handlers installed
+ * Program arguments logged
+ * Working dir logged
+ * Optional -v verbosity flag parsed
+ * Main thread name set to "main thread"
+ * Explanation of the preamble (date, threanmae etc) logged
+
+ loguru::init() will look for arguments meant for loguru and remove them.
+ Arguments meant for loguru are:
+ -v n Set loguru::g_stderr_verbosity level. Examples:
+ -v 3 Show verbosity level 3 and lower.
+ -v 0 Only show INFO, WARNING, ERROR, FATAL (default).
+ -v INFO Only show INFO, WARNING, ERROR, FATAL (default).
+ -v WARNING Only show WARNING, ERROR, FATAL.
+ -v ERROR Only show ERROR, FATAL.
+ -v FATAL Only show FATAL.
+ -v OFF Turn off logging to stderr.
+
+ Tip: You can set g_stderr_verbosity before calling loguru::init.
+ That way you can set the default but have the user override it with the -v flag.
+ Note that -v does not affect file logging (see loguru::add_file).
+
+ You can use something else instead of "-v" via verbosity_flag.
+ You can also set verbosity_flag to nullptr.
+ */
+ LOGURU_EXPORT
+ void init(int& argc, char* argv[], const char* verbosity_flag = "-v");
+
+ // Will call remove_all_callbacks(). After calling this, logging will still go to stderr.
+ // You generally don't need to call this.
+ LOGURU_EXPORT
+ void shutdown();
+
+ // What ~ will be replaced with, e.g. "/home/your_user_name/"
+ LOGURU_EXPORT
+ const char* home_dir();
+
+ /* Returns the name of the app as given in argv[0] but without leading path.
+ That is, if argv[0] is "../foo/app" this will return "app".
+ */
+ LOGURU_EXPORT
+ const char* argv0_filename();
+
+ // Returns all arguments given to loguru::init(), but escaped with a single space as separator.
+ LOGURU_EXPORT
+ const char* arguments();
+
+ // Returns the path to the current working dir when loguru::init() was called.
+ LOGURU_EXPORT
+ const char* current_dir();
+
+ // Returns the part of the path after the last / or \ (if any).
+ LOGURU_EXPORT
+ const char* filename(const char* path);
+
+ // e.g. "foo/bar/baz.ext" will create the directories "foo/" and "foo/bar/"
+ LOGURU_EXPORT
+ bool create_directories(const char* file_path_const);
+
+ // Writes date and time with millisecond precision, e.g. "20151017_161503.123"
+ LOGURU_EXPORT
+ void write_date_time(char* buff, unsigned buff_size);
+
+ // Helper: thread-safe version strerror
+ LOGURU_EXPORT
+ Text errno_as_text();
+
+ /* Given a prefix of e.g. "~/loguru/" this might return
+ "/home/your_username/loguru/app_name/20151017_161503.123.log"
+
+ where "app_name" is a sanitized version of argv[0].
+ */
+ LOGURU_EXPORT
+ void suggest_log_path(const char* prefix, char* buff, unsigned buff_size);
+
+ enum FileMode { Truncate, Append };
+
+ /* Will log to a file at the given path.
+ Any logging message with a verbosity lower or equal to
+ the given verbosity will be included.
+ The function will create all directories in 'path' if needed.
+ If path starts with a ~, it will be replaced with loguru::home_dir()
+ To stop the file logging, just call loguru::remove_callback(path) with the same path.
+ */
+ LOGURU_EXPORT
+ bool add_file(const char* path, FileMode mode, Verbosity verbosity);
+
+ /* Will be called right before abort().
+ You can for instance use this to print custom error messages, or throw an exception.
+ Feel free to call LOG:ing function from this, but not FATAL ones! */
+ LOGURU_EXPORT
+ void set_fatal_handler(fatal_handler_t handler);
+
+ // Get the current fatal handler, if any. Default value is nullptr.
+ LOGURU_EXPORT
+ fatal_handler_t get_fatal_handler();
+
+ /* Will be called on each log messages with a verbosity less or equal to the given one.
+ Useful for displaying messages on-screen in a game, for example.
+ The given on_close is also expected to flush (if desired).
+ */
+ LOGURU_EXPORT
+ void add_callback(
+ const char* id,
+ log_handler_t callback,
+ void* user_data,
+ Verbosity verbosity,
+ close_handler_t on_close = nullptr,
+ flush_handler_t on_flush = nullptr);
+
+ /* Set a callback that returns custom verbosity level names. If callback
+ is nullptr or returns nullptr, default log names will be used.
+ */
+ LOGURU_EXPORT
+ void set_verbosity_to_name_callback(verbosity_to_name_t callback);
+
+ /* Set a callback that returns the verbosity level matching a name. The
+ callback should return Verbosity_INVALID if the name is not
+ recognized.
+ */
+ LOGURU_EXPORT
+ void set_name_to_verbosity_callback(name_to_verbosity_t callback);
+
+ /* Get a custom name for a specific verbosity, if one exists, or nullptr. */
+ LOGURU_EXPORT
+ const char* get_verbosity_name(Verbosity verbosity);
+
+ /* Get the verbosity enum value from a custom 4-character level name, if one exists.
+ If the name does not match a custom level name, Verbosity_INVALID is returned.
+ */
+ LOGURU_EXPORT
+ Verbosity get_verbosity_from_name(const char* name);
+
+ // Returns true iff the callback was found (and removed).
+ LOGURU_EXPORT
+ bool remove_callback(const char* id);
+
+ // Shut down all file logging and any other callback hooks installed.
+ LOGURU_EXPORT
+ void remove_all_callbacks();
+
+ // Returns the maximum of g_stderr_verbosity and all file/custom outputs.
+ LOGURU_EXPORT
+ Verbosity current_verbosity_cutoff();
+
+#if LOGURU_USE_FMTLIB
+ // Actual logging function. Use the LOG macro instead of calling this directly.
+ LOGURU_EXPORT
+ void log(Verbosity verbosity, const char* file, unsigned line, LOGURU_FORMAT_STRING_TYPE format, fmt::ArgList args);
+ FMT_VARIADIC(void, log, Verbosity, const char*, unsigned, LOGURU_FORMAT_STRING_TYPE)
+
+ // Log without any preamble or indentation.
+ LOGURU_EXPORT
+ void raw_log(Verbosity verbosity, const char* file, unsigned line, LOGURU_FORMAT_STRING_TYPE format, fmt::ArgList args);
+ FMT_VARIADIC(void, raw_log, Verbosity, const char*, unsigned, LOGURU_FORMAT_STRING_TYPE)
+#else // LOGURU_USE_FMTLIB?
+ // Actual logging function. Use the LOG macro instead of calling this directly.
+ LOGURU_EXPORT
+ void log(Verbosity verbosity, const char* file, unsigned line, LOGURU_FORMAT_STRING_TYPE format, ...) LOGURU_PRINTF_LIKE(4, 5);
+
+ // Log without any preamble or indentation.
+ LOGURU_EXPORT
+ void raw_log(Verbosity verbosity, const char* file, unsigned line, LOGURU_FORMAT_STRING_TYPE format, ...) LOGURU_PRINTF_LIKE(4, 5);
+#endif // !LOGURU_USE_FMTLIB
+
+ // Helper class for LOG_SCOPE_F
+ class LOGURU_EXPORT LogScopeRAII
+ {
+ public:
+ LogScopeRAII() : _file(nullptr) {} // No logging
+ LogScopeRAII(Verbosity verbosity, const char* file, unsigned line, LOGURU_FORMAT_STRING_TYPE format, ...) LOGURU_PRINTF_LIKE(5, 6);
+ ~LogScopeRAII();
+
+#if defined(_MSC_VER) && _MSC_VER > 1800
+ // older MSVC default move ctors close the scope on move. See
+ // issue #43
+ LogScopeRAII(LogScopeRAII&& other)
+ : _verbosity(other._verbosity)
+ , _file(other._file)
+ , _line(other._line)
+ , _indent_stderr(other._indent_stderr)
+ , _start_time_ns(other._start_time_ns)
+ {
+ // Make sure the tmp object's destruction doesn't close the scope:
+ other._file = nullptr;
+
+ for (unsigned int i = 0; i < LOGURU_SCOPE_TEXT_SIZE; ++i) {
+ _name[i] = other._name[i];
+ }
+ }
+#else
+ LogScopeRAII(LogScopeRAII&&) = default;
+#endif
+
+ private:
+ LogScopeRAII(const LogScopeRAII&) = delete;
+ LogScopeRAII& operator=(const LogScopeRAII&) = delete;
+ void operator=(LogScopeRAII&&) = delete;
+
+ Verbosity _verbosity;
+ const char* _file; // Set to null if we are disabled due to verbosity
+ unsigned _line;
+ bool _indent_stderr; // Did we?
+ long long _start_time_ns;
+ char _name[LOGURU_SCOPE_TEXT_SIZE];
+ };
+
+ // Marked as 'noreturn' for the benefit of the static analyzer and optimizer.
+ // stack_trace_skip is the number of extrace stack frames to skip above log_and_abort.
+ LOGURU_EXPORT
+ LOGURU_NORETURN void log_and_abort(int stack_trace_skip, const char* expr, const char* file, unsigned line, LOGURU_FORMAT_STRING_TYPE format, ...) LOGURU_PRINTF_LIKE(5, 6);
+ LOGURU_EXPORT
+ LOGURU_NORETURN void log_and_abort(int stack_trace_skip, const char* expr, const char* file, unsigned line);
+
+ // Flush output to stderr and files.
+ // If g_flush_interval_ms is set to non-zero, this will be called automatically this often.
+ // If not set, you do not need to call this at all.
+ LOGURU_EXPORT
+ void flush();
+
+ template<class T> inline Text format_value(const T&) { return textprintf("N/A"); }
+ template<> inline Text format_value(const char& v) { return textprintf("%c", v); }
+ template<> inline Text format_value(const int& v) { return textprintf("%d", v); }
+ template<> inline Text format_value(const unsigned int& v) { return textprintf("%u", v); }
+ template<> inline Text format_value(const long& v) { return textprintf("%lu", v); }
+ template<> inline Text format_value(const unsigned long& v) { return textprintf("%ld", v); }
+ template<> inline Text format_value(const long long& v) { return textprintf("%llu", v); }
+ template<> inline Text format_value(const unsigned long long& v) { return textprintf("%lld", v); }
+ template<> inline Text format_value(const float& v) { return textprintf("%f", v); }
+ template<> inline Text format_value(const double& v) { return textprintf("%f", v); }
+
+ /* Thread names can be set for the benefit of readable logs.
+ If you do not set the thread name, a hex id will be shown instead.
+ These thread names may or may not be the same as the system thread names,
+ depending on the system.
+ Try to limit the thread name to 15 characters or less. */
+ LOGURU_EXPORT
+ void set_thread_name(const char* name);
+
+ /* Returns the thread name for this thread.
+ On OSX this will return the system thread name (settable from both within and without Loguru).
+ On other systems it will return whatever you set in set_thread_name();
+ If no thread name is set, this will return a hexadecimal thread id.
+ length should be the number of bytes available in the buffer.
+ 17 is a good number for length.
+ right_align_hext_id means any hexadecimal thread id will be written to the end of buffer.
+ */
+ LOGURU_EXPORT
+ void get_thread_name(char* buffer, unsigned long long length, bool right_align_hext_id);
+
+ /* Generates a readable stacktrace as a string.
+ 'skip' specifies how many stack frames to skip.
+ For instance, the default skip (1) means:
+ don't include the call to loguru::stacktrace in the stack trace. */
+ LOGURU_EXPORT
+ Text stacktrace(int skip = 1);
+
+ /* Add a string to be replaced with something else in the stack output.
+
+ For instance, instead of having a stack trace look like this:
+ 0x41f541 some_function(std::basic_ofstream<char, std::char_traits<char> >&)
+ You can clean it up with:
+ auto verbose_type_name = loguru::demangle(typeid(std::ofstream).name());
+ loguru::add_stack_cleanup(verbose_type_name.c_str(); "std::ofstream");
+ So the next time you will instead see:
+ 0x41f541 some_function(std::ofstream&)
+
+ `replace_with_this` must be shorter than `find_this`.
+ */
+ LOGURU_EXPORT
+ void add_stack_cleanup(const char* find_this, const char* replace_with_this);
+
+ // Example: demangle(typeid(std::ofstream).name()) -> "std::basic_ofstream<char, std::char_traits<char> >"
+ LOGURU_EXPORT
+ Text demangle(const char* name);
+
+ // ------------------------------------------------------------------------
+ /*
+ Not all terminals support colors, but if they do, and g_colorlogtostderr
+ is set, Loguru will write them to stderr to make errors in red, etc.
+
+ You also have the option to manually use them, via the function below.
+
+ Note, however, that if you do, the color codes could end up in your logfile!
+
+ This means if you intend to use them functions you should either:
+ * Use them on the stderr/stdout directly (bypass Loguru).
+ * Don't add file outputs to Loguru.
+ * Expect some \e[1m things in your logfile.
+
+ Usage:
+ printf("%sRed%sGreen%sBold green%sClear again\n",
+ loguru::terminal_red(), loguru::terminal_green(),
+ loguru::terminal_bold(), loguru::terminal_reset());
+
+ If the terminal at hand does not support colors the above output
+ will just not have funky \e[1m things showing.
+ */
+
+ // Do the output terminal support colors?
+ LOGURU_EXPORT
+ bool terminal_has_color();
+
+ // Colors
+ LOGURU_EXPORT const char* terminal_black();
+ LOGURU_EXPORT const char* terminal_red();
+ LOGURU_EXPORT const char* terminal_green();
+ LOGURU_EXPORT const char* terminal_yellow();
+ LOGURU_EXPORT const char* terminal_blue();
+ LOGURU_EXPORT const char* terminal_purple();
+ LOGURU_EXPORT const char* terminal_cyan();
+ LOGURU_EXPORT const char* terminal_light_gray();
+ LOGURU_EXPORT const char* terminal_light_red();
+ LOGURU_EXPORT const char* terminal_white();
+
+ // Formating
+ LOGURU_EXPORT const char* terminal_bold();
+ LOGURU_EXPORT const char* terminal_underline();
+
+ // You should end each line with this!
+ LOGURU_EXPORT const char* terminal_reset();
+
+ // --------------------------------------------------------------------
+ // Error context related:
+
+ struct StringStream;
+
+ // Use this in your EcEntryBase::print_value overload.
+ LOGURU_EXPORT
+ void stream_print(StringStream& out_string_stream, const char* text);
+
+ class LOGURU_EXPORT EcEntryBase
+ {
+ public:
+ EcEntryBase(const char* file, unsigned line, const char* descr);
+ ~EcEntryBase();
+ EcEntryBase(const EcEntryBase&) = delete;
+ EcEntryBase(EcEntryBase&&) = delete;
+ EcEntryBase& operator=(const EcEntryBase&) = delete;
+ EcEntryBase& operator=(EcEntryBase&&) = delete;
+
+ virtual void print_value(StringStream& out_string_stream) const = 0;
+
+ EcEntryBase* previous() const { return _previous; }
+
+ // private:
+ const char* _file;
+ unsigned _line;
+ const char* _descr;
+ EcEntryBase* _previous;
+ };
+
+ template<typename T>
+ class EcEntryData : public EcEntryBase
+ {
+ public:
+ using Printer = Text(*)(T data);
+
+ EcEntryData(const char* file, unsigned line, const char* descr, T data, Printer&& printer)
+ : EcEntryBase(file, line, descr), _data(data), _printer(printer) {}
+
+ virtual void print_value(StringStream& out_string_stream) const override
+ {
+ const auto str = _printer(_data);
+ stream_print(out_string_stream, str.c_str());
+ }
+
+ private:
+ T _data;
+ Printer _printer;
+ };
+
+ // template<typename Printer>
+ // class EcEntryLambda : public EcEntryBase
+ // {
+ // public:
+ // EcEntryLambda(const char* file, unsigned line, const char* descr, Printer&& printer)
+ // : EcEntryBase(file, line, descr), _printer(std::move(printer)) {}
+
+ // virtual void print_value(StringStream& out_string_stream) const override
+ // {
+ // const auto str = _printer();
+ // stream_print(out_string_stream, str.c_str());
+ // }
+
+ // private:
+ // Printer _printer;
+ // };
+
+ // template<typename Printer>
+ // EcEntryLambda<Printer> make_ec_entry_lambda(const char* file, unsigned line, const char* descr, Printer&& printer)
+ // {
+ // return {file, line, descr, std::move(printer)};
+ // }
+
+ template <class T>
+ struct decay_char_array { using type = T; };
+
+ template <unsigned long long N>
+ struct decay_char_array<const char(&)[N]> { using type = const char*; };
+
+ template <class T>
+ struct make_const_ptr { using type = T; };
+
+ template <class T>
+ struct make_const_ptr<T*> { using type = const T*; };
+
+ template <class T>
+ struct make_ec_type { using type = typename make_const_ptr<typename decay_char_array<T>::type>::type; };
+
+ /* A stack trace gives you the names of the function at the point of a crash.
+ With ERROR_CONTEXT, you can also get the values of select local variables.
+ Usage:
+
+ void process_customers(const std::string& filename)
+ {
+ ERROR_CONTEXT("Processing file", filename.c_str());
+ for (int customer_index : ...)
+ {
+ ERROR_CONTEXT("Customer index", customer_index);
+ ...
+ }
+ }
+
+ The context is in effect during the scope of the ERROR_CONTEXT.
+ Use loguru::get_error_context() to get the contents of the active error contexts.
+
+ Example result:
+
+ ------------------------------------------------
+ [ErrorContext] main.cpp:416 Processing file: "customers.json"
+ [ErrorContext] main.cpp:417 Customer index: 42
+ ------------------------------------------------
+
+ Error contexts are printed automatically on crashes, and only on crashes.
+ This makes them much faster than logging the value of a variable.
+ */
+ #define ERROR_CONTEXT(descr, data) \
+ const loguru::EcEntryData<loguru::make_ec_type<decltype(data)>::type> \
+ LOGURU_ANONYMOUS_VARIABLE(error_context_scope_)( \
+ __FILE__, __LINE__, descr, data, \
+ static_cast<loguru::EcEntryData<loguru::make_ec_type<decltype(data)>::type>::Printer>(loguru::ec_to_text) ) // For better error messages
+
+/*
+ #define ERROR_CONTEXT(descr, data) \
+ const auto LOGURU_ANONYMOUS_VARIABLE(error_context_scope_)( \
+ loguru::make_ec_entry_lambda(__FILE__, __LINE__, descr, \
+ [=](){ return loguru::ec_to_text(data); }))
+*/
+
+ using EcHandle = const EcEntryBase*;
+
+ /*
+ Get a light-weight handle to the error context stack on this thread.
+ The handle is valid as long as the current thread has no changes to its error context stack.
+ You can pass the handle to loguru::get_error_context on another thread.
+ This can be very useful for when you have a parent thread spawning several working threads,
+ and you want the error context of the parent thread to get printed (too) when there is an
+ error on the child thread. You can accomplish this thusly:
+
+ void foo(const char* parameter)
+ {
+ ERROR_CONTEXT("parameter", parameter)
+ const auto parent_ec_handle = loguru::get_thread_ec_handle();
+
+ std::thread([=]{
+ loguru::set_thread_name("child thread");
+ ERROR_CONTEXT("parent context", parent_ec_handle);
+ dangerous_code();
+ }.join();
+ }
+
+ */
+ LOGURU_EXPORT
+ EcHandle get_thread_ec_handle();
+
+ // Get a string describing the current stack of error context. Empty string if there is none.
+ LOGURU_EXPORT
+ Text get_error_context();
+
+ // Get a string describing the error context of the given thread handle.
+ LOGURU_EXPORT
+ Text get_error_context_for(EcHandle ec_handle);
+
+ // ------------------------------------------------------------------------
+
+ LOGURU_EXPORT Text ec_to_text(const char* data);
+ LOGURU_EXPORT Text ec_to_text(char data);
+ LOGURU_EXPORT Text ec_to_text(int data);
+ LOGURU_EXPORT Text ec_to_text(unsigned int data);
+ LOGURU_EXPORT Text ec_to_text(long data);
+ LOGURU_EXPORT Text ec_to_text(unsigned long data);
+ LOGURU_EXPORT Text ec_to_text(long long data);
+ LOGURU_EXPORT Text ec_to_text(unsigned long long data);
+ LOGURU_EXPORT Text ec_to_text(float data);
+ LOGURU_EXPORT Text ec_to_text(double data);
+ LOGURU_EXPORT Text ec_to_text(long double data);
+ LOGURU_EXPORT Text ec_to_text(EcHandle);
+
+ /*
+ You can add ERROR_CONTEXT support for your own types by overloading ec_to_text. Here's how:
+
+ some.hpp:
+ namespace loguru {
+ Text ec_to_text(MySmallType data)
+ Text ec_to_text(const MyBigType* data)
+ } // namespace loguru
+
+ some.cpp:
+ namespace loguru {
+ Text ec_to_text(MySmallType small_value)
+ {
+ // Called only when needed, i.e. on a crash.
+ std::string str = small_value.as_string(); // Format 'small_value' here somehow.
+ return Text{STRDUP(str.c_str())};
+ }
+
+ Text ec_to_text(const MyBigType* big_value)
+ {
+ // Called only when needed, i.e. on a crash.
+ std::string str = big_value->as_string(); // Format 'big_value' here somehow.
+ return Text{STRDUP(str.c_str())};
+ }
+ } // namespace loguru
+
+ Any file that include some.hpp:
+ void foo(MySmallType small, const MyBigType& big)
+ {
+ ERROR_CONTEXT("Small", small); // Copy ´small` by value.
+ ERROR_CONTEXT("Big", &big); // `big` should not change during this scope!
+ ....
+ }
+ */
+} // namespace loguru
+
+// --------------------------------------------------------------------
+// Logging macros
+
+// LOG_F(2, "Only logged if verbosity is 2 or higher: %d", some_number);
+#define VLOG_F(verbosity, ...) \
+ ((verbosity) > loguru::current_verbosity_cutoff()) ? (void)0 \
+ : loguru::log(verbosity, __FILE__, __LINE__, __VA_ARGS__)
+
+// LOG_F(INFO, "Foo: %d", some_number);
+#define LOG_F(verbosity_name, ...) VLOG_F(loguru::Verbosity_ ## verbosity_name, __VA_ARGS__)
+
+#define VLOG_IF_F(verbosity, cond, ...) \
+ ((verbosity) > loguru::current_verbosity_cutoff() || (cond) == false) \
+ ? (void)0 \
+ : loguru::log(verbosity, __FILE__, __LINE__, __VA_ARGS__)
+
+#define LOG_IF_F(verbosity_name, cond, ...) \
+ VLOG_IF_F(loguru::Verbosity_ ## verbosity_name, cond, __VA_ARGS__)
+
+#define VLOG_SCOPE_F(verbosity, ...) \
+ loguru::LogScopeRAII LOGURU_ANONYMOUS_VARIABLE(error_context_RAII_) = \
+ ((verbosity) > loguru::current_verbosity_cutoff()) ? loguru::LogScopeRAII() : \
+ loguru::LogScopeRAII(verbosity, __FILE__, __LINE__, __VA_ARGS__)
+
+// Raw logging - no preamble, no indentation. Slightly faster than full logging.
+#define RAW_VLOG_F(verbosity, ...) \
+ ((verbosity) > loguru::current_verbosity_cutoff()) ? (void)0 \
+ : loguru::raw_log(verbosity, __FILE__, __LINE__, __VA_ARGS__)
+
+#define RAW_LOG_F(verbosity_name, ...) RAW_VLOG_F(loguru::Verbosity_ ## verbosity_name, __VA_ARGS__)
+
+// Use to book-end a scope. Affects logging on all threads.
+#define LOG_SCOPE_F(verbosity_name, ...) \
+ VLOG_SCOPE_F(loguru::Verbosity_ ## verbosity_name, __VA_ARGS__)
+
+#define LOG_SCOPE_FUNCTION(verbosity_name) LOG_SCOPE_F(verbosity_name, __func__)
+
+// -----------------------------------------------
+// ABORT_F macro. Usage: ABORT_F("Cause of error: %s", error_str);
+
+// Message is optional
+#define ABORT_F(...) loguru::log_and_abort(0, "ABORT: ", __FILE__, __LINE__, __VA_ARGS__)
+
+// --------------------------------------------------------------------
+// CHECK_F macros:
+
+#define CHECK_WITH_INFO_F(test, info, ...) \
+ LOGURU_PREDICT_TRUE((test) == true) ? (void)0 : loguru::log_and_abort(0, "CHECK FAILED: " info " ", __FILE__, \
+ __LINE__, ##__VA_ARGS__)
+
+/* Checked at runtime too. Will print error, then call fatal_handler (if any), then 'abort'.
+ Note that the test must be boolean.
+ CHECK_F(ptr); will not compile, but CHECK_F(ptr != nullptr); will. */
+#define CHECK_F(test, ...) CHECK_WITH_INFO_F(test, #test, ##__VA_ARGS__)
+
+#define CHECK_NOTNULL_F(x, ...) CHECK_WITH_INFO_F((x) != nullptr, #x " != nullptr", ##__VA_ARGS__)
+
+#define CHECK_OP_F(expr_left, expr_right, op, ...) \
+ do \
+ { \
+ auto val_left = expr_left; \
+ auto val_right = expr_right; \
+ if (! LOGURU_PREDICT_TRUE(val_left op val_right)) \
+ { \
+ auto str_left = loguru::format_value(val_left); \
+ auto str_right = loguru::format_value(val_right); \
+ auto fail_info = loguru::textprintf("CHECK FAILED: %s %s %s (%s %s %s) ", \
+ #expr_left, #op, #expr_right, str_left.c_str(), #op, str_right.c_str()); \
+ auto user_msg = loguru::textprintf(__VA_ARGS__); \
+ loguru::log_and_abort(0, fail_info.c_str(), __FILE__, __LINE__, \
+ "%s", user_msg.c_str()); \
+ } \
+ } while (false)
+
+#ifndef LOGURU_DEBUG_LOGGING
+ #ifndef NDEBUG
+ #define LOGURU_DEBUG_LOGGING 1
+ #else
+ #define LOGURU_DEBUG_LOGGING 0
+ #endif
+#endif
+
+#if LOGURU_DEBUG_LOGGING
+ // Debug logging enabled:
+ #define DLOG_F(verbosity_name, ...) LOG_F(verbosity_name, __VA_ARGS__)
+ #define DVLOG_F(verbosity, ...) VLOG_F(verbosity, __VA_ARGS__)
+ #define DLOG_IF_F(verbosity_name, ...) LOG_IF_F(verbosity_name, __VA_ARGS__)
+ #define DVLOG_IF_F(verbosity, ...) VLOG_IF_F(verbosity, __VA_ARGS__)
+ #define DRAW_LOG_F(verbosity_name, ...) RAW_LOG_F(verbosity_name, __VA_ARGS__)
+ #define DRAW_VLOG_F(verbosity, ...) RAW_VLOG_F(verbosity, __VA_ARGS__)
+#else
+ // Debug logging disabled:
+ #define DLOG_F(verbosity_name, ...)
+ #define DVLOG_F(verbosity, ...)
+ #define DLOG_IF_F(verbosity_name, ...)
+ #define DVLOG_IF_F(verbosity, ...)
+ #define DRAW_LOG_F(verbosity_name, ...)
+ #define DRAW_VLOG_F(verbosity, ...)
+#endif
+
+#define CHECK_EQ_F(a, b, ...) CHECK_OP_F(a, b, ==, ##__VA_ARGS__)
+#define CHECK_NE_F(a, b, ...) CHECK_OP_F(a, b, !=, ##__VA_ARGS__)
+#define CHECK_LT_F(a, b, ...) CHECK_OP_F(a, b, < , ##__VA_ARGS__)
+#define CHECK_GT_F(a, b, ...) CHECK_OP_F(a, b, > , ##__VA_ARGS__)
+#define CHECK_LE_F(a, b, ...) CHECK_OP_F(a, b, <=, ##__VA_ARGS__)
+#define CHECK_GE_F(a, b, ...) CHECK_OP_F(a, b, >=, ##__VA_ARGS__)
+
+#ifndef LOGURU_DEBUG_CHECKS
+ #ifndef NDEBUG
+ #define LOGURU_DEBUG_CHECKS 1
+ #else
+ #define LOGURU_DEBUG_CHECKS 0
+ #endif
+#endif
+
+#if LOGURU_DEBUG_CHECKS
+ // Debug checks enabled:
+ #define DCHECK_F(test, ...) CHECK_F(test, ##__VA_ARGS__)
+ #define DCHECK_NOTNULL_F(x, ...) CHECK_NOTNULL_F(x, ##__VA_ARGS__)
+ #define DCHECK_EQ_F(a, b, ...) CHECK_EQ_F(a, b, ##__VA_ARGS__)
+ #define DCHECK_NE_F(a, b, ...) CHECK_NE_F(a, b, ##__VA_ARGS__)
+ #define DCHECK_LT_F(a, b, ...) CHECK_LT_F(a, b, ##__VA_ARGS__)
+ #define DCHECK_LE_F(a, b, ...) CHECK_LE_F(a, b, ##__VA_ARGS__)
+ #define DCHECK_GT_F(a, b, ...) CHECK_GT_F(a, b, ##__VA_ARGS__)
+ #define DCHECK_GE_F(a, b, ...) CHECK_GE_F(a, b, ##__VA_ARGS__)
+#else
+ // Debug checks disabled:
+ #define DCHECK_F(test, ...)
+ #define DCHECK_NOTNULL_F(x, ...)
+ #define DCHECK_EQ_F(a, b, ...)
+ #define DCHECK_NE_F(a, b, ...)
+ #define DCHECK_LT_F(a, b, ...)
+ #define DCHECK_LE_F(a, b, ...)
+ #define DCHECK_GT_F(a, b, ...)
+ #define DCHECK_GE_F(a, b, ...)
+#endif // NDEBUG
+
+
+#if LOGURU_REDEFINE_ASSERT
+ #undef assert
+ #ifndef NDEBUG
+ // Debug:
+ #define assert(test) CHECK_WITH_INFO_F(!!(test), #test) // HACK
+ #else
+ #define assert(test)
+ #endif
+#endif // LOGURU_REDEFINE_ASSERT
+
+#endif // LOGURU_HAS_DECLARED_FORMAT_HEADER
+
+// ----------------------------------------------------------------------------
+// .dP"Y8 888888 88""Yb 888888 db 8b d8 .dP"Y8
+// `Ybo." 88 88__dP 88__ dPYb 88b d88 `Ybo."
+// o.`Y8b 88 88"Yb 88"" dP__Yb 88YbdP88 o.`Y8b
+// 8bodP' 88 88 Yb 888888 dP""""Yb 88 YY 88 8bodP'
+
+#if LOGURU_WITH_STREAMS
+#ifndef LOGURU_HAS_DECLARED_STREAMS_HEADER
+#define LOGURU_HAS_DECLARED_STREAMS_HEADER
+
+/* This file extends loguru to enable std::stream-style logging, a la Glog.
+ It's an optional feature behind the LOGURU_WITH_STREAMS settings
+ because including it everywhere will slow down compilation times.
+*/
+
+#include <cstdarg>
+#include <sstream> // Adds about 38 kLoC on clang.
+#include <string>
+
+namespace loguru
+{
+ // Like sprintf, but returns the formated text.
+ LOGURU_EXPORT
+ std::string strprintf(LOGURU_FORMAT_STRING_TYPE format, ...) LOGURU_PRINTF_LIKE(1, 2);
+
+ // Like vsprintf, but returns the formated text.
+ LOGURU_EXPORT
+ std::string vstrprintf(LOGURU_FORMAT_STRING_TYPE format, va_list) LOGURU_PRINTF_LIKE(1, 0);
+
+ class LOGURU_EXPORT StreamLogger
+ {
+ public:
+ StreamLogger(Verbosity verbosity, const char* file, unsigned line) : _verbosity(verbosity), _file(file), _line(line) {}
+ ~StreamLogger() noexcept(false);
+
+ template<typename T>
+ StreamLogger& operator<<(const T& t)
+ {
+ _ss << t;
+ return *this;
+ }
+
+ // std::endl and other iomanip:s.
+ StreamLogger& operator<<(std::ostream&(*f)(std::ostream&))
+ {
+ f(_ss);
+ return *this;
+ }
+
+ private:
+ Verbosity _verbosity;
+ const char* _file;
+ unsigned _line;
+ std::ostringstream _ss;
+ };
+
+ class LOGURU_EXPORT AbortLogger
+ {
+ public:
+ AbortLogger(const char* expr, const char* file, unsigned line) : _expr(expr), _file(file), _line(line) { }
+ LOGURU_NORETURN ~AbortLogger() noexcept(false);
+
+ template<typename T>
+ AbortLogger& operator<<(const T& t)
+ {
+ _ss << t;
+ return *this;
+ }
+
+ // std::endl and other iomanip:s.
+ AbortLogger& operator<<(std::ostream&(*f)(std::ostream&))
+ {
+ f(_ss);
+ return *this;
+ }
+
+ private:
+ const char* _expr;
+ const char* _file;
+ unsigned _line;
+ std::ostringstream _ss;
+ };
+
+ class LOGURU_EXPORT Voidify
+ {
+ public:
+ Voidify() {}
+ // This has to be an operator with a precedence lower than << but higher than ?:
+ void operator&(const StreamLogger&) { }
+ void operator&(const AbortLogger&) { }
+ };
+
+ /* Helper functions for CHECK_OP_S macro.
+ GLOG trick: The (int, int) specialization works around the issue that the compiler
+ will not instantiate the template version of the function on values of unnamed enum type. */
+ #define DEFINE_CHECK_OP_IMPL(name, op) \
+ template <typename T1, typename T2> \
+ inline std::string* name(const char* expr, const T1& v1, const char* op_str, const T2& v2) \
+ { \
+ if (LOGURU_PREDICT_TRUE(v1 op v2)) { return NULL; } \
+ std::ostringstream ss; \
+ ss << "CHECK FAILED: " << expr << " (" << v1 << " " << op_str << " " << v2 << ") "; \
+ return new std::string(ss.str()); \
+ } \
+ inline std::string* name(const char* expr, int v1, const char* op_str, int v2) \
+ { \
+ return name<int, int>(expr, v1, op_str, v2); \
+ }
+
+ DEFINE_CHECK_OP_IMPL(check_EQ_impl, ==)
+ DEFINE_CHECK_OP_IMPL(check_NE_impl, !=)
+ DEFINE_CHECK_OP_IMPL(check_LE_impl, <=)
+ DEFINE_CHECK_OP_IMPL(check_LT_impl, < )
+ DEFINE_CHECK_OP_IMPL(check_GE_impl, >=)
+ DEFINE_CHECK_OP_IMPL(check_GT_impl, > )
+ #undef DEFINE_CHECK_OP_IMPL
+
+ /* GLOG trick: Function is overloaded for integral types to allow static const integrals
+ declared in classes and not defined to be used as arguments to CHECK* macros. */
+ template <class T>
+ inline const T& referenceable_value(const T& t) { return t; }
+ inline char referenceable_value(char t) { return t; }
+ inline unsigned char referenceable_value(unsigned char t) { return t; }
+ inline signed char referenceable_value(signed char t) { return t; }
+ inline short referenceable_value(short t) { return t; }
+ inline unsigned short referenceable_value(unsigned short t) { return t; }
+ inline int referenceable_value(int t) { return t; }
+ inline unsigned int referenceable_value(unsigned int t) { return t; }
+ inline long referenceable_value(long t) { return t; }
+ inline unsigned long referenceable_value(unsigned long t) { return t; }
+ inline long long referenceable_value(long long t) { return t; }
+ inline unsigned long long referenceable_value(unsigned long long t) { return t; }
+} // namespace loguru
+
+// -----------------------------------------------
+// Logging macros:
+
+// usage: LOG_STREAM(INFO) << "Foo " << std::setprecision(10) << some_value;
+#define VLOG_IF_S(verbosity, cond) \
+ ((verbosity) > loguru::current_verbosity_cutoff() || (cond) == false) \
+ ? (void)0 \
+ : loguru::Voidify() & loguru::StreamLogger(verbosity, __FILE__, __LINE__)
+#define LOG_IF_S(verbosity_name, cond) VLOG_IF_S(loguru::Verbosity_ ## verbosity_name, cond)
+#define VLOG_S(verbosity) VLOG_IF_S(verbosity, true)
+#define LOG_S(verbosity_name) VLOG_S(loguru::Verbosity_ ## verbosity_name)
+
+// -----------------------------------------------
+// ABORT_S macro. Usage: ABORT_S() << "Causo of error: " << details;
+
+#define ABORT_S() loguru::Voidify() & loguru::AbortLogger("ABORT: ", __FILE__, __LINE__)
+
+// -----------------------------------------------
+// CHECK_S macros:
+
+#define CHECK_WITH_INFO_S(cond, info) \
+ LOGURU_PREDICT_TRUE((cond) == true) \
+ ? (void)0 \
+ : loguru::Voidify() & loguru::AbortLogger("CHECK FAILED: " info " ", __FILE__, __LINE__)
+
+#define CHECK_S(cond) CHECK_WITH_INFO_S(cond, #cond)
+#define CHECK_NOTNULL_S(x) CHECK_WITH_INFO_S((x) != nullptr, #x " != nullptr")
+
+#define CHECK_OP_S(function_name, expr1, op, expr2) \
+ while (auto error_string = loguru::function_name(#expr1 " " #op " " #expr2, \
+ loguru::referenceable_value(expr1), #op, \
+ loguru::referenceable_value(expr2))) \
+ loguru::AbortLogger(error_string->c_str(), __FILE__, __LINE__)
+
+#define CHECK_EQ_S(expr1, expr2) CHECK_OP_S(check_EQ_impl, expr1, ==, expr2)
+#define CHECK_NE_S(expr1, expr2) CHECK_OP_S(check_NE_impl, expr1, !=, expr2)
+#define CHECK_LE_S(expr1, expr2) CHECK_OP_S(check_LE_impl, expr1, <=, expr2)
+#define CHECK_LT_S(expr1, expr2) CHECK_OP_S(check_LT_impl, expr1, < , expr2)
+#define CHECK_GE_S(expr1, expr2) CHECK_OP_S(check_GE_impl, expr1, >=, expr2)
+#define CHECK_GT_S(expr1, expr2) CHECK_OP_S(check_GT_impl, expr1, > , expr2)
+
+#if LOGURU_DEBUG_LOGGING
+ // Debug logging enabled:
+ #define DVLOG_IF_S(verbosity, cond) VLOG_IF_S(verbosity, cond)
+ #define DLOG_IF_S(verbosity_name, cond) LOG_IF_S(verbosity_name, cond)
+ #define DVLOG_S(verbosity) VLOG_S(verbosity)
+ #define DLOG_S(verbosity_name) LOG_S(verbosity_name)
+#else
+ // Debug logging disabled:
+ #define DVLOG_IF_S(verbosity, cond) \
+ (true || (verbosity) > loguru::current_verbosity_cutoff() || (cond) == false) \
+ ? (void)0 \
+ : loguru::Voidify() & loguru::StreamLogger(verbosity, __FILE__, __LINE__)
+
+ #define DLOG_IF_S(verbosity_name, cond) DVLOG_IF_S(loguru::Verbosity_ ## verbosity_name, cond)
+ #define DVLOG_S(verbosity) DVLOG_IF_S(verbosity, true)
+ #define DLOG_S(verbosity_name) DVLOG_S(loguru::Verbosity_ ## verbosity_name)
+#endif
+
+#if LOGURU_DEBUG_CHECKS
+ // Debug checks enabled:
+ #define DCHECK_S(cond) CHECK_S(cond)
+ #define DCHECK_NOTNULL_S(x) CHECK_NOTNULL_S(x)
+ #define DCHECK_EQ_S(a, b) CHECK_EQ_S(a, b)
+ #define DCHECK_NE_S(a, b) CHECK_NE_S(a, b)
+ #define DCHECK_LT_S(a, b) CHECK_LT_S(a, b)
+ #define DCHECK_LE_S(a, b) CHECK_LE_S(a, b)
+ #define DCHECK_GT_S(a, b) CHECK_GT_S(a, b)
+ #define DCHECK_GE_S(a, b) CHECK_GE_S(a, b)
+#else
+// Debug checks disabled:
+ #define DCHECK_S(cond) CHECK_S(true || (cond))
+ #define DCHECK_NOTNULL_S(x) CHECK_S(true || (x) != nullptr)
+ #define DCHECK_EQ_S(a, b) CHECK_S(true || (a) == (b))
+ #define DCHECK_NE_S(a, b) CHECK_S(true || (a) != (b))
+ #define DCHECK_LT_S(a, b) CHECK_S(true || (a) < (b))
+ #define DCHECK_LE_S(a, b) CHECK_S(true || (a) <= (b))
+ #define DCHECK_GT_S(a, b) CHECK_S(true || (a) > (b))
+ #define DCHECK_GE_S(a, b) CHECK_S(true || (a) >= (b))
+#endif
+
+#if LOGURU_REPLACE_GLOG
+ #undef LOG
+ #undef VLOG
+ #undef LOG_IF
+ #undef VLOG_IF
+ #undef CHECK
+ #undef CHECK_NOTNULL
+ #undef CHECK_EQ
+ #undef CHECK_NE
+ #undef CHECK_LT
+ #undef CHECK_LE
+ #undef CHECK_GT
+ #undef CHECK_GE
+ #undef DLOG
+ #undef DVLOG
+ #undef DLOG_IF
+ #undef DVLOG_IF
+ #undef DCHECK
+ #undef DCHECK_NOTNULL
+ #undef DCHECK_EQ
+ #undef DCHECK_NE
+ #undef DCHECK_LT
+ #undef DCHECK_LE
+ #undef DCHECK_GT
+ #undef DCHECK_GE
+ #undef VLOG_IS_ON
+
+ #define LOG LOG_S
+ #define VLOG VLOG_S
+ #define LOG_IF LOG_IF_S
+ #define VLOG_IF VLOG_IF_S
+ #define CHECK(cond) CHECK_S(!!(cond))
+ #define CHECK_NOTNULL CHECK_NOTNULL_S
+ #define CHECK_EQ CHECK_EQ_S
+ #define CHECK_NE CHECK_NE_S
+ #define CHECK_LT CHECK_LT_S
+ #define CHECK_LE CHECK_LE_S
+ #define CHECK_GT CHECK_GT_S
+ #define CHECK_GE CHECK_GE_S
+ #define DLOG DLOG_S
+ #define DVLOG DVLOG_S
+ #define DLOG_IF DLOG_IF_S
+ #define DVLOG_IF DVLOG_IF_S
+ #define DCHECK DCHECK_S
+ #define DCHECK_NOTNULL DCHECK_NOTNULL_S
+ #define DCHECK_EQ DCHECK_EQ_S
+ #define DCHECK_NE DCHECK_NE_S
+ #define DCHECK_LT DCHECK_LT_S
+ #define DCHECK_LE DCHECK_LE_S
+ #define DCHECK_GT DCHECK_GT_S
+ #define DCHECK_GE DCHECK_GE_S
+ #define VLOG_IS_ON(verbosity) ((verbosity) <= loguru::current_verbosity_cutoff())
+
+#endif // LOGURU_REPLACE_GLOG
+
+#endif // LOGURU_WITH_STREAMS
+
+#endif // LOGURU_HAS_DECLARED_STREAMS_HEADER
\ No newline at end of file
--- /dev/null
+loguru_inc = [
+ include_directories('inc'),
+]
+
+loguru_src = [
+ files('src/loguru.cpp'),
+]
+
+loguru_deps = [
+ dependency('threads'),
+ meson.get_compiler('cpp').find_library('dl', required : true),
+]
+
+libloguru = static_library(
+ 'libloguru',
+ loguru_src,
+ dependencies: loguru_deps,
+ include_directories: loguru_inc,
+ install:false
+)
\ No newline at end of file
--- /dev/null
+#ifndef _WIN32
+// Disable all warnings from gcc/clang:
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wpragmas"
+
+#pragma GCC diagnostic ignored "-Wc++98-compat"
+#pragma GCC diagnostic ignored "-Wc++98-compat-pedantic"
+#pragma GCC diagnostic ignored "-Wexit-time-destructors"
+#pragma GCC diagnostic ignored "-Wformat-nonliteral"
+#pragma GCC diagnostic ignored "-Wglobal-constructors"
+#pragma GCC diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
+#pragma GCC diagnostic ignored "-Wmissing-prototypes"
+#pragma GCC diagnostic ignored "-Wpadded"
+#pragma GCC diagnostic ignored "-Wsign-compare"
+#pragma GCC diagnostic ignored "-Wsign-conversion"
+#pragma GCC diagnostic ignored "-Wunknown-pragmas"
+#pragma GCC diagnostic ignored "-Wunused-macros"
+#pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant"
+#endif
+
+#include "loguru.hpp"
+
+#ifndef LOGURU_HAS_BEEN_IMPLEMENTED
+#define LOGURU_HAS_BEEN_IMPLEMENTED
+
+#define LOGURU_PREAMBLE_WIDTH (53 + LOGURU_THREADNAME_WIDTH + LOGURU_FILENAME_WIDTH)
+
+#undef min
+#undef max
+
+#include <algorithm>
+#include <atomic>
+#include <chrono>
+#include <cstdarg>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <mutex>
+#include <regex>
+#include <string>
+#include <thread>
+#include <vector>
+
+#ifdef _WIN32
+ #include <direct.h>
+
+ #define localtime_r(a, b) localtime_s(b, a) // No localtime_r with MSVC, but arguments are swapped for localtime_s
+#else
+ #include <signal.h>
+ #include <sys/stat.h> // mkdir
+ #include <unistd.h> // STDERR_FILENO
+#endif
+
+#ifdef __linux__
+ #include <linux/limits.h> // PATH_MAX
+#elif !defined(_WIN32)
+ #include <limits.h> // PATH_MAX
+#endif
+
+#ifndef PATH_MAX
+ #define PATH_MAX 1024
+#endif
+
+#ifdef __APPLE__
+ #include "TargetConditionals.h"
+#endif
+
+// TODO: use defined(_POSIX_VERSION) for some of these things?
+
+#if defined(_WIN32) || defined(__CYGWIN__)
+ #define LOGURU_PTHREADS 0
+ #define LOGURU_WINTHREADS 1
+ #ifndef LOGURU_STACKTRACES
+ #define LOGURU_STACKTRACES 0
+ #endif
+#elif defined(__rtems__) || defined(__ANDROID__)
+ #define LOGURU_PTHREADS 1
+ #define LOGURU_WINTHREADS 0
+ #ifndef LOGURU_STACKTRACES
+ #define LOGURU_STACKTRACES 0
+ #endif
+#else
+ #define LOGURU_PTHREADS 1
+ #define LOGURU_WINTHREADS 0
+ #ifndef LOGURU_STACKTRACES
+ #define LOGURU_STACKTRACES 1
+ #endif
+#endif
+
+#if LOGURU_STACKTRACES
+ #include <cxxabi.h> // for __cxa_demangle
+ #include <dlfcn.h> // for dladdr
+ #include <execinfo.h> // for backtrace
+#endif // LOGURU_STACKTRACES
+
+#if LOGURU_PTHREADS
+ #include <pthread.h>
+ #if defined(__FreeBSD__)
+ #include <pthread_np.h>
+ #include <sys/thr.h>
+ #elif defined(__OpenBSD__)
+ #include <pthread_np.h>
+ #endif
+
+ #ifdef __linux__
+ /* On Linux, the default thread name is the same as the name of the binary.
+ Additionally, all new threads inherit the name of the thread it got forked from.
+ For this reason, Loguru use the pthread Thread Local Storage
+ for storing thread names on Linux. */
+ #define LOGURU_PTLS_NAMES 1
+ #endif
+#endif
+
+#if LOGURU_WINTHREADS
+ #ifndef _WIN32_WINNT
+ #define _WIN32_WINNT 0x0502
+ #endif
+ #define WIN32_LEAN_AND_MEAN
+ #define NOMINMAX
+ #include <windows.h>
+#endif
+
+#ifndef LOGURU_PTLS_NAMES
+ #define LOGURU_PTLS_NAMES 0
+#endif
+
+namespace loguru
+{
+ using namespace std::chrono;
+
+#if LOGURU_WITH_FILEABS
+ struct FileAbs
+ {
+ char path[PATH_MAX];
+ char mode_str[4];
+ Verbosity verbosity;
+ struct stat st;
+ FILE* fp;
+ bool is_reopening = false; // to prevent recursive call in file_reopen.
+ decltype(steady_clock::now()) last_check_time = steady_clock::now();
+ };
+#else
+ typedef FILE* FileAbs;
+#endif
+
+ struct Callback
+ {
+ std::string id;
+ log_handler_t callback;
+ void* user_data;
+ Verbosity verbosity; // Does not change!
+ close_handler_t close;
+ flush_handler_t flush;
+ unsigned indentation;
+ };
+
+ using CallbackVec = std::vector<Callback>;
+
+ using StringPair = std::pair<std::string, std::string>;
+ using StringPairList = std::vector<StringPair>;
+
+ const auto s_start_time = steady_clock::now();
+
+ Verbosity g_stderr_verbosity = Verbosity_0;
+ bool g_colorlogtostderr = true;
+ unsigned g_flush_interval_ms = 0;
+ bool g_preamble = true;
+
+ Verbosity g_internal_verbosity = Verbosity_0;
+
+ // Preamble details
+ bool g_preamble_date = true;
+ bool g_preamble_time = true;
+ bool g_preamble_uptime = true;
+ bool g_preamble_thread = true;
+ bool g_preamble_file = true;
+ bool g_preamble_verbose = true;
+ bool g_preamble_pipe = true;
+
+ static std::recursive_mutex s_mutex;
+ static Verbosity s_max_out_verbosity = Verbosity_OFF;
+ static std::string s_argv0_filename;
+ static std::string s_arguments;
+ static char s_current_dir[PATH_MAX];
+ static CallbackVec s_callbacks;
+ static fatal_handler_t s_fatal_handler = nullptr;
+ static verbosity_to_name_t s_verbosity_to_name_callback = nullptr;
+ static name_to_verbosity_t s_name_to_verbosity_callback = nullptr;
+ static StringPairList s_user_stack_cleanups;
+ static bool s_strip_file_path = true;
+ static std::atomic<unsigned> s_stderr_indentation { 0 };
+
+ // For periodic flushing:
+ static std::thread* s_flush_thread = nullptr;
+ static bool s_needs_flushing = false;
+
+ static const bool s_terminal_has_color = [](){
+ #ifdef _WIN32
+ #ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
+ #define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
+ #endif
+
+ HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
+ if (hOut != INVALID_HANDLE_VALUE) {
+ DWORD dwMode = 0;
+ GetConsoleMode(hOut, &dwMode);
+ dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
+ return SetConsoleMode(hOut, dwMode) != 0;
+ }
+ return false;
+ #else
+ if (const char* term = getenv("TERM")) {
+ return 0 == strcmp(term, "cygwin")
+ || 0 == strcmp(term, "linux")
+ || 0 == strcmp(term, "rxvt-unicode-256color")
+ || 0 == strcmp(term, "screen")
+ || 0 == strcmp(term, "screen-256color")
+ || 0 == strcmp(term, "screen.xterm-256color")
+ || 0 == strcmp(term, "tmux-256color")
+ || 0 == strcmp(term, "xterm")
+ || 0 == strcmp(term, "xterm-256color")
+ || 0 == strcmp(term, "xterm-termite")
+ || 0 == strcmp(term, "xterm-color");
+ } else {
+ return false;
+ }
+ #endif
+ }();
+
+ static void print_preamble_header(char* out_buff, size_t out_buff_size);
+
+ #if LOGURU_PTLS_NAMES
+ static pthread_once_t s_pthread_key_once = PTHREAD_ONCE_INIT;
+ static pthread_key_t s_pthread_key_name;
+
+ void make_pthread_key_name()
+ {
+ (void)pthread_key_create(&s_pthread_key_name, free);
+ }
+ #endif
+
+ // ------------------------------------------------------------------------------
+ // Colors
+
+ bool terminal_has_color() { return s_terminal_has_color; }
+
+ // Colors
+
+#ifdef _WIN32
+#define VTSEQ(ID) ("\x1b[1;" #ID "m")
+#else
+#define VTSEQ(ID) ("\x1b[" #ID "m")
+#endif
+
+ const char* terminal_black() { return s_terminal_has_color ? VTSEQ(30) : ""; }
+ const char* terminal_red() { return s_terminal_has_color ? VTSEQ(31) : ""; }
+ const char* terminal_green() { return s_terminal_has_color ? VTSEQ(32) : ""; }
+ const char* terminal_yellow() { return s_terminal_has_color ? VTSEQ(33) : ""; }
+ const char* terminal_blue() { return s_terminal_has_color ? VTSEQ(34) : ""; }
+ const char* terminal_purple() { return s_terminal_has_color ? VTSEQ(35) : ""; }
+ const char* terminal_cyan() { return s_terminal_has_color ? VTSEQ(36) : ""; }
+ const char* terminal_light_gray() { return s_terminal_has_color ? VTSEQ(37) : ""; }
+ const char* terminal_white() { return s_terminal_has_color ? VTSEQ(37) : ""; }
+ const char* terminal_light_red() { return s_terminal_has_color ? VTSEQ(91) : ""; }
+ const char* terminal_dim() { return s_terminal_has_color ? VTSEQ(2) : ""; }
+
+ // Formating
+ const char* terminal_bold() { return s_terminal_has_color ? VTSEQ(1) : ""; }
+ const char* terminal_underline() { return s_terminal_has_color ? VTSEQ(4) : ""; }
+
+ // You should end each line with this!
+ const char* terminal_reset() { return s_terminal_has_color ? VTSEQ(0) : ""; }
+
+ // ------------------------------------------------------------------------------
+#if LOGURU_WITH_FILEABS
+ void file_reopen(void* user_data);
+ inline FILE* to_file(void* user_data) { return reinterpret_cast<FileAbs*>(user_data)->fp; }
+#else
+ inline FILE* to_file(void* user_data) { return reinterpret_cast<FILE*>(user_data); }
+#endif
+
+ void file_log(void* user_data, const Message& message)
+ {
+#if LOGURU_WITH_FILEABS
+ FileAbs* file_abs = reinterpret_cast<FileAbs*>(user_data);
+ if (file_abs->is_reopening) {
+ return;
+ }
+ // It is better checking file change every minute/hour/day,
+ // instead of doing this every time we log.
+ // Here check_interval is set to zero to enable checking every time;
+ const auto check_interval = seconds(0);
+ if (duration_cast<seconds>(steady_clock::now() - file_abs->last_check_time) > check_interval) {
+ file_abs->last_check_time = steady_clock::now();
+ file_reopen(user_data);
+ }
+ FILE* file = to_file(user_data);
+ if (!file) {
+ return;
+ }
+#else
+ FILE* file = to_file(user_data);
+#endif
+ fprintf(file, "%s%s%s%s\n",
+ message.preamble, message.indentation, message.prefix, message.message);
+ if (g_flush_interval_ms == 0) {
+ fflush(file);
+ }
+ }
+
+ void file_close(void* user_data)
+ {
+ FILE* file = to_file(user_data);
+ if (file) {
+ fclose(file);
+ }
+#if LOGURU_WITH_FILEABS
+ delete reinterpret_cast<FileAbs*>(user_data);
+#endif
+ }
+
+ void file_flush(void* user_data)
+ {
+ FILE* file = to_file(user_data);
+ fflush(file);
+ }
+
+#if LOGURU_WITH_FILEABS
+ void file_reopen(void* user_data)
+ {
+ FileAbs * file_abs = reinterpret_cast<FileAbs*>(user_data);
+ struct stat st;
+ int ret;
+ if (!file_abs->fp || (ret = stat(file_abs->path, &st)) == -1 || (st.st_ino != file_abs->st.st_ino)) {
+ file_abs->is_reopening = true;
+ if (file_abs->fp) {
+ fclose(file_abs->fp);
+ }
+ if (!file_abs->fp) {
+ VLOG_F(g_internal_verbosity, "Reopening file '%s' due to previous error", file_abs->path);
+ }
+ else if (ret < 0) {
+ const auto why = errno_as_text();
+ VLOG_F(g_internal_verbosity, "Reopening file '%s' due to '%s'", file_abs->path, why.c_str());
+ } else {
+ VLOG_F(g_internal_verbosity, "Reopening file '%s' due to file changed", file_abs->path);
+ }
+ // try reopen current file.
+ if (!create_directories(file_abs->path)) {
+ LOG_F(ERROR, "Failed to create directories to '%s'", file_abs->path);
+ }
+ file_abs->fp = fopen(file_abs->path, file_abs->mode_str);
+ if (!file_abs->fp) {
+ LOG_F(ERROR, "Failed to open '%s'", file_abs->path);
+ } else {
+ stat(file_abs->path, &file_abs->st);
+ }
+ file_abs->is_reopening = false;
+ }
+ }
+#endif
+ // ------------------------------------------------------------------------------
+
+ // Helpers:
+
+ Text::~Text() { free(_str); }
+
+ LOGURU_PRINTF_LIKE(1, 0)
+ static Text vtextprintf(const char* format, va_list vlist)
+ {
+#ifdef _WIN32
+ int bytes_needed = _vscprintf(format, vlist);
+ CHECK_F(bytes_needed >= 0, "Bad string format: '%s'", format);
+ char* buff = (char*)malloc(bytes_needed+1);
+ vsnprintf(buff, bytes_needed+1, format, vlist);
+ return Text(buff);
+#else
+ char* buff = nullptr;
+ int result = vasprintf(&buff, format, vlist);
+ CHECK_F(result >= 0, "Bad string format: '%s'", format);
+ return Text(buff);
+#endif
+ }
+
+ Text textprintf(const char* format, ...)
+ {
+ va_list vlist;
+ va_start(vlist, format);
+ auto result = vtextprintf(format, vlist);
+ va_end(vlist);
+ return result;
+ }
+
+ // Overloaded for variadic template matching.
+ Text textprintf()
+ {
+ return Text(static_cast<char*>(calloc(1, 1)));
+ }
+
+ static const char* indentation(unsigned depth)
+ {
+ static const char buff[] =
+ ". . . . . . . . . . " ". . . . . . . . . . "
+ ". . . . . . . . . . " ". . . . . . . . . . "
+ ". . . . . . . . . . " ". . . . . . . . . . "
+ ". . . . . . . . . . " ". . . . . . . . . . "
+ ". . . . . . . . . . " ". . . . . . . . . . ";
+ static const size_t INDENTATION_WIDTH = 4;
+ static const size_t NUM_INDENTATIONS = (sizeof(buff) - 1) / INDENTATION_WIDTH;
+ depth = std::min<unsigned>(depth, NUM_INDENTATIONS);
+ return buff + INDENTATION_WIDTH * (NUM_INDENTATIONS - depth);
+ }
+
+ static void parse_args(int& argc, char* argv[], const char* verbosity_flag)
+ {
+ int arg_dest = 1;
+ int out_argc = argc;
+
+ for (int arg_it = 1; arg_it < argc; ++arg_it) {
+ auto cmd = argv[arg_it];
+ auto arg_len = strlen(verbosity_flag);
+ if (strncmp(cmd, verbosity_flag, arg_len) == 0 && !std::isalpha(cmd[arg_len], std::locale(""))) {
+ out_argc -= 1;
+ auto value_str = cmd + arg_len;
+ if (value_str[0] == '\0') {
+ // Value in separate argument
+ arg_it += 1;
+ CHECK_LT_F(arg_it, argc, "Missing verbosiy level after %s", verbosity_flag);
+ value_str = argv[arg_it];
+ out_argc -= 1;
+ }
+ if (*value_str == '=') { value_str += 1; }
+
+ auto req_verbosity = get_verbosity_from_name(value_str);
+ if (req_verbosity != Verbosity_INVALID) {
+ g_stderr_verbosity = req_verbosity;
+ } else {
+ char* end = 0;
+ g_stderr_verbosity = static_cast<int>(strtol(value_str, &end, 10));
+ CHECK_F(end && *end == '\0',
+ "Invalid verbosity. Expected integer, INFO, WARNING, ERROR or OFF, got '%s'", value_str);
+ }
+ } else {
+ argv[arg_dest++] = argv[arg_it];
+ }
+ }
+
+ argc = out_argc;
+ argv[argc] = nullptr;
+ }
+
+ static long long now_ns()
+ {
+ return duration_cast<nanoseconds>(high_resolution_clock::now().time_since_epoch()).count();
+ }
+
+ // Returns the part of the path after the last / or \ (if any).
+ const char* filename(const char* path)
+ {
+ for (auto ptr = path; *ptr; ++ptr) {
+ if (*ptr == '/' || *ptr == '\\') {
+ path = ptr + 1;
+ }
+ }
+ return path;
+ }
+
+ // ------------------------------------------------------------------------------
+
+ static void on_atexit()
+ {
+ VLOG_F(g_internal_verbosity, "atexit");
+ flush();
+ }
+
+ static void install_signal_handlers();
+
+ static void write_hex_digit(std::string& out, unsigned num)
+ {
+ DCHECK_LT_F(num, 16u);
+ if (num < 10u) { out.push_back(char('0' + num)); }
+ else { out.push_back(char('A' + num - 10)); }
+ }
+
+ static void write_hex_byte(std::string& out, uint8_t n)
+ {
+ write_hex_digit(out, n >> 4u);
+ write_hex_digit(out, n & 0x0f);
+ }
+
+ static void escape(std::string& out, const std::string& str)
+ {
+ for (char c : str) {
+ /**/ if (c == '\a') { out += "\\a"; }
+ else if (c == '\b') { out += "\\b"; }
+ else if (c == '\f') { out += "\\f"; }
+ else if (c == '\n') { out += "\\n"; }
+ else if (c == '\r') { out += "\\r"; }
+ else if (c == '\t') { out += "\\t"; }
+ else if (c == '\v') { out += "\\v"; }
+ else if (c == '\\') { out += "\\\\"; }
+ else if (c == '\'') { out += "\\\'"; }
+ else if (c == '\"') { out += "\\\""; }
+ else if (c == ' ') { out += "\\ "; }
+ else if (0 <= c && c < 0x20) { // ASCI control character:
+ // else if (c < 0x20 || c != (c & 127)) { // ASCII control character or UTF-8:
+ out += "\\x";
+ write_hex_byte(out, static_cast<uint8_t>(c));
+ } else { out += c; }
+ }
+ }
+
+ Text errno_as_text()
+ {
+ char buff[256];
+ #if defined(__GLIBC__) && defined(_GNU_SOURCE)
+ // GNU Version
+ return Text(STRDUP(strerror_r(errno, buff, sizeof(buff))));
+ #elif defined(__APPLE__) || _POSIX_C_SOURCE >= 200112L
+ // XSI Version
+ strerror_r(errno, buff, sizeof(buff));
+ return Text(strdup(buff));
+ #elif defined(_WIN32)
+ strerror_s(buff, sizeof(buff), errno);
+ return Text(STRDUP(buff));
+ #else
+ // Not thread-safe.
+ return Text(STRDUP(strerror(errno)));
+ #endif
+ }
+
+ void init(int& argc, char* argv[], const char* verbosity_flag)
+ {
+ CHECK_GT_F(argc, 0, "Expected proper argc/argv");
+ CHECK_EQ_F(argv[argc], nullptr, "Expected proper argc/argv");
+
+ s_argv0_filename = filename(argv[0]);
+
+ #ifdef _WIN32
+ #define getcwd _getcwd
+ #endif
+
+ if (!getcwd(s_current_dir, sizeof(s_current_dir)))
+ {
+ const auto error_text = errno_as_text();
+ LOG_F(WARNING, "Failed to get current working directory: %s", error_text.c_str());
+ }
+
+ s_arguments = "";
+ for (int i = 0; i < argc; ++i) {
+ escape(s_arguments, argv[i]);
+ if (i + 1 < argc) {
+ s_arguments += " ";
+ }
+ }
+
+ if (verbosity_flag) {
+ parse_args(argc, argv, verbosity_flag);
+ }
+
+ #if LOGURU_PTLS_NAMES || LOGURU_WINTHREADS
+ set_thread_name("main thread");
+ #elif LOGURU_PTHREADS
+ char old_thread_name[16] = {0};
+ auto this_thread = pthread_self();
+ #if defined(__APPLE__) || defined(__linux__)
+ pthread_getname_np(this_thread, old_thread_name, sizeof(old_thread_name));
+ #endif
+ if (old_thread_name[0] == 0) {
+ #ifdef __APPLE__
+ pthread_setname_np("main thread");
+ #elif defined(__FreeBSD__) || defined(__OpenBSD__)
+ pthread_set_name_np(this_thread, "main thread");
+ #elif defined(__linux__)
+ pthread_setname_np(this_thread, "main thread");
+ #endif
+ }
+ #endif // LOGURU_PTHREADS
+
+ if (g_stderr_verbosity >= Verbosity_INFO) {
+ if (g_preamble) {
+ char preamble_explain[LOGURU_PREAMBLE_WIDTH];
+ print_preamble_header(preamble_explain, sizeof(preamble_explain));
+ if (g_colorlogtostderr && s_terminal_has_color) {
+ fprintf(stderr, "%s%s%s\n", terminal_reset(), terminal_dim(), preamble_explain);
+ } else {
+ fprintf(stderr, "%s\n", preamble_explain);
+ }
+ }
+ fflush(stderr);
+ }
+ VLOG_F(g_internal_verbosity, "arguments: %s", s_arguments.c_str());
+ if (strlen(s_current_dir) != 0)
+ {
+ VLOG_F(g_internal_verbosity, "Current dir: %s", s_current_dir);
+ }
+ VLOG_F(g_internal_verbosity, "stderr verbosity: %d", g_stderr_verbosity);
+ VLOG_F(g_internal_verbosity, "-----------------------------------");
+
+ install_signal_handlers();
+
+ atexit(on_atexit);
+ }
+
+ void shutdown()
+ {
+ VLOG_F(g_internal_verbosity, "loguru::shutdown()");
+ remove_all_callbacks();
+ set_fatal_handler(nullptr);
+ set_verbosity_to_name_callback(nullptr);
+ set_name_to_verbosity_callback(nullptr);
+ }
+
+ void write_date_time(char* buff, size_t buff_size)
+ {
+ auto now = system_clock::now();
+ long long ms_since_epoch = duration_cast<milliseconds>(now.time_since_epoch()).count();
+ time_t sec_since_epoch = time_t(ms_since_epoch / 1000);
+ tm time_info;
+ localtime_r(&sec_since_epoch, &time_info);
+ snprintf(buff, buff_size, "%04d%02d%02d_%02d%02d%02d.%03lld",
+ 1900 + time_info.tm_year, 1 + time_info.tm_mon, time_info.tm_mday,
+ time_info.tm_hour, time_info.tm_min, time_info.tm_sec, ms_since_epoch % 1000);
+ }
+
+ const char* argv0_filename()
+ {
+ return s_argv0_filename.c_str();
+ }
+
+ const char* arguments()
+ {
+ return s_arguments.c_str();
+ }
+
+ const char* current_dir()
+ {
+ return s_current_dir;
+ }
+
+ const char* home_dir()
+ {
+ #ifdef _WIN32
+ auto user_profile = getenv("USERPROFILE");
+ CHECK_F(user_profile != nullptr, "Missing USERPROFILE");
+ return user_profile;
+ #else // _WIN32
+ auto home = getenv("HOME");
+ CHECK_F(home != nullptr, "Missing HOME");
+ return home;
+ #endif // _WIN32
+ }
+
+ void suggest_log_path(const char* prefix, char* buff, unsigned buff_size)
+ {
+ if (prefix[0] == '~') {
+ snprintf(buff, buff_size - 1, "%s%s", home_dir(), prefix + 1);
+ } else {
+ snprintf(buff, buff_size - 1, "%s", prefix);
+ }
+
+ // Check for terminating /
+ size_t n = strlen(buff);
+ if (n != 0) {
+ if (buff[n - 1] != '/') {
+ CHECK_F(n + 2 < buff_size, "Filename buffer too small");
+ buff[n] = '/';
+ buff[n + 1] = '\0';
+ }
+ }
+
+ strncat(buff, s_argv0_filename.c_str(), buff_size - strlen(buff) - 1);
+ strncat(buff, "/", buff_size - strlen(buff) - 1);
+ write_date_time(buff + strlen(buff), buff_size - strlen(buff));
+ strncat(buff, ".log", buff_size - strlen(buff) - 1);
+ }
+
+ bool create_directories(const char* file_path_const)
+ {
+ CHECK_F(file_path_const && *file_path_const);
+ char* file_path = STRDUP(file_path_const);
+ for (char* p = strchr(file_path + 1, '/'); p; p = strchr(p + 1, '/')) {
+ *p = '\0';
+
+ #ifdef _WIN32
+ if (_mkdir(file_path) == -1) {
+ #else
+ if (mkdir(file_path, 0755) == -1) {
+ #endif
+ if (errno != EEXIST) {
+ LOG_F(ERROR, "Failed to create directory '%s'", file_path);
+ LOG_IF_F(ERROR, errno == EACCES, "EACCES");
+ LOG_IF_F(ERROR, errno == ENAMETOOLONG, "ENAMETOOLONG");
+ LOG_IF_F(ERROR, errno == ENOENT, "ENOENT");
+ LOG_IF_F(ERROR, errno == ENOTDIR, "ENOTDIR");
+ LOG_IF_F(ERROR, errno == ELOOP, "ELOOP");
+
+ *p = '/';
+ free(file_path);
+ return false;
+ }
+ }
+ *p = '/';
+ }
+ free(file_path);
+ return true;
+ }
+ bool add_file(const char* path_in, FileMode mode, Verbosity verbosity)
+ {
+ char path[PATH_MAX];
+ if (path_in[0] == '~') {
+ snprintf(path, sizeof(path) - 1, "%s%s", home_dir(), path_in + 1);
+ } else {
+ snprintf(path, sizeof(path) - 1, "%s", path_in);
+ }
+
+ if (!create_directories(path)) {
+ LOG_F(ERROR, "Failed to create directories to '%s'", path);
+ }
+
+ const char* mode_str = (mode == FileMode::Truncate ? "w" : "a");
+ auto file = fopen(path, mode_str);
+ if (!file) {
+ LOG_F(ERROR, "Failed to open '%s'", path);
+ return false;
+ }
+#if LOGURU_WITH_FILEABS
+ FileAbs* file_abs = new FileAbs(); // this is deleted in file_close;
+ snprintf(file_abs->path, sizeof(file_abs->path) - 1, "%s", path);
+ snprintf(file_abs->mode_str, sizeof(file_abs->mode_str) - 1, "%s", mode_str);
+ stat(file_abs->path, &file_abs->st);
+ file_abs->fp = file;
+ file_abs->verbosity = verbosity;
+ add_callback(path_in, file_log, file_abs, verbosity, file_close, file_flush);
+#else
+ add_callback(path_in, file_log, file, verbosity, file_close, file_flush);
+#endif
+
+ if (mode == FileMode::Append) {
+ fprintf(file, "\n\n\n\n\n");
+ }
+ if (!s_arguments.empty()) {
+ fprintf(file, "arguments: %s\n", s_arguments.c_str());
+ }
+ if (strlen(s_current_dir) != 0) {
+ fprintf(file, "Current dir: %s\n", s_current_dir);
+ }
+ fprintf(file, "File verbosity level: %d\n", verbosity);
+ if (g_preamble) {
+ char preamble_explain[LOGURU_PREAMBLE_WIDTH];
+ print_preamble_header(preamble_explain, sizeof(preamble_explain));
+ fprintf(file, "%s\n", preamble_explain);
+ }
+ fflush(file);
+
+ VLOG_F(g_internal_verbosity, "Logging to '%s', mode: '%s', verbosity: %d", path, mode_str, verbosity);
+ return true;
+ }
+
+ // Will be called right before abort().
+ void set_fatal_handler(fatal_handler_t handler)
+ {
+ s_fatal_handler = handler;
+ }
+
+ fatal_handler_t get_fatal_handler()
+ {
+ return s_fatal_handler;
+ }
+
+ void set_verbosity_to_name_callback(verbosity_to_name_t callback)
+ {
+ s_verbosity_to_name_callback = callback;
+ }
+
+ void set_name_to_verbosity_callback(name_to_verbosity_t callback)
+ {
+ s_name_to_verbosity_callback = callback;
+ }
+
+ void add_stack_cleanup(const char* find_this, const char* replace_with_this)
+ {
+ if (strlen(find_this) <= strlen(replace_with_this)) {
+ LOG_F(WARNING, "add_stack_cleanup: the replacement should be shorter than the pattern!");
+ return;
+ }
+
+ s_user_stack_cleanups.push_back(StringPair(find_this, replace_with_this));
+ }
+
+ static void on_callback_change()
+ {
+ s_max_out_verbosity = Verbosity_OFF;
+ for (const auto& callback : s_callbacks) {
+ s_max_out_verbosity = std::max(s_max_out_verbosity, callback.verbosity);
+ }
+ }
+
+ void add_callback(
+ const char* id,
+ log_handler_t callback,
+ void* user_data,
+ Verbosity verbosity,
+ close_handler_t on_close,
+ flush_handler_t on_flush)
+ {
+ std::lock_guard<std::recursive_mutex> lock(s_mutex);
+ s_callbacks.push_back(Callback{id, callback, user_data, verbosity, on_close, on_flush, 0});
+ on_callback_change();
+ }
+
+ // Returns a custom verbosity name if one is available, or nullptr.
+ // See also set_verbosity_to_name_callback.
+ const char* get_verbosity_name(Verbosity verbosity)
+ {
+ auto name = s_verbosity_to_name_callback
+ ? (*s_verbosity_to_name_callback)(verbosity)
+ : nullptr;
+
+ // Use standard replacements if callback fails:
+ if (!name)
+ {
+ if (verbosity <= Verbosity_FATAL) {
+ name = "FATL";
+ } else if (verbosity == Verbosity_ERROR) {
+ name = "ERR";
+ } else if (verbosity == Verbosity_WARNING) {
+ name = "WARN";
+ } else if (verbosity == Verbosity_INFO) {
+ name = "INFO";
+ }
+ }
+
+ return name;
+ }
+
+ // Returns Verbosity_INVALID if the name is not found.
+ // See also set_name_to_verbosity_callback.
+ Verbosity get_verbosity_from_name(const char* name)
+ {
+ auto verbosity = s_name_to_verbosity_callback
+ ? (*s_name_to_verbosity_callback)(name)
+ : Verbosity_INVALID;
+
+ // Use standard replacements if callback fails:
+ if (verbosity == Verbosity_INVALID) {
+ if (strcmp(name, "OFF") == 0) {
+ verbosity = Verbosity_OFF;
+ } else if (strcmp(name, "INFO") == 0) {
+ verbosity = Verbosity_INFO;
+ } else if (strcmp(name, "WARNING") == 0) {
+ verbosity = Verbosity_WARNING;
+ } else if (strcmp(name, "ERROR") == 0) {
+ verbosity = Verbosity_ERROR;
+ } else if (strcmp(name, "FATAL") == 0) {
+ verbosity = Verbosity_FATAL;
+ }
+ }
+
+ return verbosity;
+ }
+
+ bool remove_callback(const char* id)
+ {
+ std::lock_guard<std::recursive_mutex> lock(s_mutex);
+ auto it = std::find_if(begin(s_callbacks), end(s_callbacks), [&](const Callback& c) { return c.id == id; });
+ if (it != s_callbacks.end()) {
+ if (it->close) { it->close(it->user_data); }
+ s_callbacks.erase(it);
+ on_callback_change();
+ return true;
+ } else {
+ LOG_F(ERROR, "Failed to locate callback with id '%s'", id);
+ return false;
+ }
+ }
+
+ void remove_all_callbacks()
+ {
+ std::lock_guard<std::recursive_mutex> lock(s_mutex);
+ for (auto& callback : s_callbacks) {
+ if (callback.close) {
+ callback.close(callback.user_data);
+ }
+ }
+ s_callbacks.clear();
+ on_callback_change();
+ }
+
+ // Returns the maximum of g_stderr_verbosity and all file/custom outputs.
+ Verbosity current_verbosity_cutoff()
+ {
+ return g_stderr_verbosity > s_max_out_verbosity ?
+ g_stderr_verbosity : s_max_out_verbosity;
+ }
+
+#if LOGURU_WINTHREADS
+ char* get_thread_name_win32()
+ {
+ __declspec( thread ) static char thread_name[LOGURU_THREADNAME_WIDTH + 1] = {0};
+ return &thread_name[0];
+ }
+#endif // LOGURU_WINTHREADS
+
+ void set_thread_name(const char* name)
+ {
+ #if LOGURU_PTLS_NAMES
+ (void)pthread_once(&s_pthread_key_once, make_pthread_key_name);
+ (void)pthread_setspecific(s_pthread_key_name, STRDUP(name));
+
+ #elif LOGURU_PTHREADS
+ #ifdef __APPLE__
+ pthread_setname_np(name);
+ #elif defined(__FreeBSD__) || defined(__OpenBSD__)
+ pthread_set_name_np(pthread_self(), name);
+ #elif defined(__linux__)
+ pthread_setname_np(pthread_self(), name);
+ #endif
+ #elif LOGURU_WINTHREADS
+ strncpy_s(get_thread_name_win32(), LOGURU_THREADNAME_WIDTH + 1, name, _TRUNCATE);
+ #else // LOGURU_PTHREADS
+ (void)name;
+ #endif // LOGURU_PTHREADS
+ }
+
+#if LOGURU_PTLS_NAMES
+ const char* get_thread_name_ptls()
+ {
+ (void)pthread_once(&s_pthread_key_once, make_pthread_key_name);
+ return static_cast<const char*>(pthread_getspecific(s_pthread_key_name));
+ }
+#endif // LOGURU_PTLS_NAMES
+
+ void get_thread_name(char* buffer, unsigned long long length, bool right_align_hext_id)
+ {
+#ifdef _WIN32
+ (void)right_align_hext_id;
+#endif
+ CHECK_NE_F(length, 0u, "Zero length buffer in get_thread_name");
+ CHECK_NOTNULL_F(buffer, "nullptr in get_thread_name");
+#if LOGURU_PTHREADS
+ auto thread = pthread_self();
+ #if LOGURU_PTLS_NAMES
+ if (const char* name = get_thread_name_ptls()) {
+ snprintf(buffer, length, "%s", name);
+ } else {
+ buffer[0] = 0;
+ }
+ #elif defined(__APPLE__) || defined(__linux__)
+ pthread_getname_np(thread, buffer, length);
+ #else
+ buffer[0] = 0;
+ #endif
+
+ if (buffer[0] == 0) {
+ #ifdef __APPLE__
+ uint64_t thread_id;
+ pthread_threadid_np(thread, &thread_id);
+ #elif defined(__FreeBSD__)
+ long thread_id;
+ (void)thr_self(&thread_id);
+ #elif defined(__OpenBSD__)
+ unsigned thread_id = -1;
+ #else
+ uint64_t thread_id = thread;
+ #endif
+ if (right_align_hext_id) {
+ snprintf(buffer, length, "%*X", static_cast<int>(length - 1), static_cast<unsigned>(thread_id));
+ } else {
+ snprintf(buffer, length, "%X", static_cast<unsigned>(thread_id));
+ }
+ }
+#elif LOGURU_WINTHREADS
+ if (const char* name = get_thread_name_win32()) {
+ snprintf(buffer, (size_t)length, "%s", name);
+ } else {
+ buffer[0] = 0;
+ }
+#else // !LOGURU_WINTHREADS && !LOGURU_WINTHREADS
+ buffer[0] = 0;
+#endif
+
+ }
+
+ // ------------------------------------------------------------------------
+ // Stack traces
+
+#if LOGURU_STACKTRACES
+ Text demangle(const char* name)
+ {
+ int status = -1;
+ char* demangled = abi::__cxa_demangle(name, 0, 0, &status);
+ Text result{status == 0 ? demangled : STRDUP(name)};
+ return result;
+ }
+
+ #if LOGURU_RTTI
+ template <class T>
+ std::string type_name()
+ {
+ auto demangled = demangle(typeid(T).name());
+ return demangled.c_str();
+ }
+ #endif // LOGURU_RTTI
+
+ static const StringPairList REPLACE_LIST = {
+ #if LOGURU_RTTI
+ { type_name<std::string>(), "std::string" },
+ { type_name<std::wstring>(), "std::wstring" },
+ { type_name<std::u16string>(), "std::u16string" },
+ { type_name<std::u32string>(), "std::u32string" },
+ #endif // LOGURU_RTTI
+ { "std::__1::", "std::" },
+ { "__thiscall ", "" },
+ { "__cdecl ", "" },
+ };
+
+ void do_replacements(const StringPairList& replacements, std::string& str)
+ {
+ for (auto&& p : replacements) {
+ if (p.first.size() <= p.second.size()) {
+ // On gcc, "type_name<std::string>()" is "std::string"
+ continue;
+ }
+
+ size_t it;
+ while ((it=str.find(p.first)) != std::string::npos) {
+ str.replace(it, p.first.size(), p.second);
+ }
+ }
+ }
+
+ std::string prettify_stacktrace(const std::string& input)
+ {
+ std::string output = input;
+
+ do_replacements(s_user_stack_cleanups, output);
+ do_replacements(REPLACE_LIST, output);
+
+ try {
+ std::regex std_allocator_re(R"(,\s*std::allocator<[^<>]+>)");
+ output = std::regex_replace(output, std_allocator_re, std::string(""));
+
+ std::regex template_spaces_re(R"(<\s*([^<> ]+)\s*>)");
+ output = std::regex_replace(output, template_spaces_re, std::string("<$1>"));
+ } catch (std::regex_error&) {
+ // Probably old GCC.
+ }
+
+ return output;
+ }
+
+ std::string stacktrace_as_stdstring(int skip)
+ {
+ // From https://gist.github.com/fmela/591333
+ void* callstack[128];
+ const auto max_frames = sizeof(callstack) / sizeof(callstack[0]);
+ int num_frames = backtrace(callstack, max_frames);
+ char** symbols = backtrace_symbols(callstack, num_frames);
+
+ std::string result;
+ // Print stack traces so the most relevant ones are written last
+ // Rationale: http://yellerapp.com/posts/2015-01-22-upside-down-stacktraces.html
+ for (int i = num_frames - 1; i >= skip; --i) {
+ char buf[1024];
+ Dl_info info;
+ if (dladdr(callstack[i], &info) && info.dli_sname) {
+ char* demangled = NULL;
+ int status = -1;
+ if (info.dli_sname[0] == '_') {
+ demangled = abi::__cxa_demangle(info.dli_sname, 0, 0, &status);
+ }
+ snprintf(buf, sizeof(buf), "%-3d %*p %s + %zd\n",
+ i - skip, int(2 + sizeof(void*) * 2), callstack[i],
+ status == 0 ? demangled :
+ info.dli_sname == 0 ? symbols[i] : info.dli_sname,
+ static_cast<char*>(callstack[i]) - static_cast<char*>(info.dli_saddr));
+ free(demangled);
+ } else {
+ snprintf(buf, sizeof(buf), "%-3d %*p %s\n",
+ i - skip, int(2 + sizeof(void*) * 2), callstack[i], symbols[i]);
+ }
+ result += buf;
+ }
+ free(symbols);
+
+ if (num_frames == max_frames) {
+ result = "[truncated]\n" + result;
+ }
+
+ if (!result.empty() && result[result.size() - 1] == '\n') {
+ result.resize(result.size() - 1);
+ }
+
+ return prettify_stacktrace(result);
+ }
+
+#else // LOGURU_STACKTRACES
+ Text demangle(const char* name)
+ {
+ return Text(STRDUP(name));
+ }
+
+ std::string stacktrace_as_stdstring(int)
+ {
+ // No stacktraces available on this platform"
+ return "";
+ }
+
+#endif // LOGURU_STACKTRACES
+
+ Text stacktrace(int skip)
+ {
+ auto str = stacktrace_as_stdstring(skip + 1);
+ return Text(STRDUP(str.c_str()));
+ }
+
+ // ------------------------------------------------------------------------
+
+ static void print_preamble_header(char* out_buff, size_t out_buff_size)
+ {
+ if (out_buff_size == 0) { return; }
+ out_buff[0] = '\0';
+ long pos = 0;
+ if (g_preamble_date && pos < out_buff_size) {
+ pos += snprintf(out_buff + pos, out_buff_size - pos, "date ");
+ }
+ if (g_preamble_time && pos < out_buff_size) {
+ pos += snprintf(out_buff + pos, out_buff_size - pos, "time ");
+ }
+ if (g_preamble_uptime && pos < out_buff_size) {
+ pos += snprintf(out_buff + pos, out_buff_size - pos, "( uptime ) ");
+ }
+ if (g_preamble_thread && pos < out_buff_size) {
+ pos += snprintf(out_buff + pos, out_buff_size - pos, "[%-*s]", LOGURU_THREADNAME_WIDTH, " thread name/id");
+ }
+ if (g_preamble_file && pos < out_buff_size) {
+ pos += snprintf(out_buff + pos, out_buff_size - pos, "%*s:line ", LOGURU_FILENAME_WIDTH, "file");
+ }
+ if (g_preamble_verbose && pos < out_buff_size) {
+ pos += snprintf(out_buff + pos, out_buff_size - pos, " v");
+ }
+ if (g_preamble_pipe && pos < out_buff_size) {
+ pos += snprintf(out_buff + pos, out_buff_size - pos, "| ");
+ }
+ }
+
+ static void print_preamble(char* out_buff, size_t out_buff_size, Verbosity verbosity, const char* file, unsigned line)
+ {
+ if (out_buff_size == 0) { return; }
+ out_buff[0] = '\0';
+ if (!g_preamble) { return; }
+ long long ms_since_epoch = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
+ time_t sec_since_epoch = time_t(ms_since_epoch / 1000);
+ tm time_info;
+ localtime_r(&sec_since_epoch, &time_info);
+
+ auto uptime_ms = duration_cast<milliseconds>(steady_clock::now() - s_start_time).count();
+ auto uptime_sec = uptime_ms / 1000.0;
+
+ char thread_name[LOGURU_THREADNAME_WIDTH + 1] = {0};
+ get_thread_name(thread_name, LOGURU_THREADNAME_WIDTH + 1, true);
+
+ if (s_strip_file_path) {
+ file = filename(file);
+ }
+
+ char level_buff[6];
+ const char* custom_level_name = get_verbosity_name(verbosity);
+ if (custom_level_name) {
+ snprintf(level_buff, sizeof(level_buff) - 1, "%s", custom_level_name);
+ } else {
+ snprintf(level_buff, sizeof(level_buff) - 1, "% 4d", verbosity);
+ }
+
+ long pos = 0;
+
+ if (g_preamble_date && pos < out_buff_size) {
+ pos += snprintf(out_buff + pos, out_buff_size - pos, "%04d-%02d-%02d ",
+ 1900 + time_info.tm_year, 1 + time_info.tm_mon, time_info.tm_mday);
+ }
+ if (g_preamble_time && pos < out_buff_size) {
+ pos += snprintf(out_buff + pos, out_buff_size - pos, "%02d:%02d:%02d.%03lld ",
+ time_info.tm_hour, time_info.tm_min, time_info.tm_sec, ms_since_epoch % 1000);
+ }
+ if (g_preamble_uptime && pos < out_buff_size) {
+ pos += snprintf(out_buff + pos, out_buff_size - pos, "(%8.3fs) ",
+ uptime_sec);
+ }
+ if (g_preamble_thread && pos < out_buff_size) {
+ pos += snprintf(out_buff + pos, out_buff_size - pos, "[%-*s]",
+ LOGURU_THREADNAME_WIDTH, thread_name);
+ }
+ if (g_preamble_file && pos < out_buff_size) {
+ char shortened_filename[LOGURU_FILENAME_WIDTH + 1];
+ snprintf(shortened_filename, LOGURU_FILENAME_WIDTH + 1, "%s", file);
+ pos += snprintf(out_buff + pos, out_buff_size - pos, "%*s:%-5u ",
+ LOGURU_FILENAME_WIDTH, shortened_filename, line);
+ }
+ if (g_preamble_verbose && pos < out_buff_size) {
+ pos += snprintf(out_buff + pos, out_buff_size - pos, "%4s",
+ level_buff);
+ }
+ if (g_preamble_pipe && pos < out_buff_size) {
+ pos += snprintf(out_buff + pos, out_buff_size - pos, "| ");
+ }
+ }
+
+ // stack_trace_skip is just if verbosity == FATAL.
+ static void log_message(int stack_trace_skip, Message& message, bool with_indentation, bool abort_if_fatal)
+ {
+ const auto verbosity = message.verbosity;
+ std::lock_guard<std::recursive_mutex> lock(s_mutex);
+
+ if (message.verbosity == Verbosity_FATAL) {
+ auto st = loguru::stacktrace(stack_trace_skip + 2);
+ if (!st.empty()) {
+ RAW_LOG_F(ERROR, "Stack trace:\n%s", st.c_str());
+ }
+
+ auto ec = loguru::get_error_context();
+ if (!ec.empty()) {
+ RAW_LOG_F(ERROR, "%s", ec.c_str());
+ }
+ }
+
+ if (with_indentation) {
+ message.indentation = indentation(s_stderr_indentation);
+ }
+
+ if (verbosity <= g_stderr_verbosity) {
+ if (g_colorlogtostderr && s_terminal_has_color) {
+ if (verbosity > Verbosity_WARNING) {
+ fprintf(stderr, "%s%s%s%s%s%s%s%s\n",
+ terminal_reset(),
+ terminal_dim(),
+ message.preamble,
+ message.indentation,
+ verbosity == Verbosity_INFO ? terminal_reset() : "", // un-dim for info
+ message.prefix,
+ message.message,
+ terminal_reset());
+ } else {
+ fprintf(stderr, "%s%s%s%s%s%s%s\n",
+ terminal_reset(),
+ verbosity == Verbosity_WARNING ? terminal_yellow() : terminal_red(),
+ message.preamble,
+ message.indentation,
+ message.prefix,
+ message.message,
+ terminal_reset());
+ }
+ } else {
+ fprintf(stderr, "%s%s%s%s\n",
+ message.preamble, message.indentation, message.prefix, message.message);
+ }
+
+ if (g_flush_interval_ms == 0) {
+ fflush(stderr);
+ } else {
+ s_needs_flushing = true;
+ }
+ }
+
+ for (auto& p : s_callbacks) {
+ if (verbosity <= p.verbosity) {
+ if (with_indentation) {
+ message.indentation = indentation(p.indentation);
+ }
+ p.callback(p.user_data, message);
+ if (g_flush_interval_ms == 0) {
+ if (p.flush) { p.flush(p.user_data); }
+ } else {
+ s_needs_flushing = true;
+ }
+ }
+ }
+
+ if (g_flush_interval_ms > 0 && !s_flush_thread) {
+ s_flush_thread = new std::thread([](){
+ for (;;) {
+ if (s_needs_flushing) {
+ flush();
+ }
+ std::this_thread::sleep_for(std::chrono::milliseconds(g_flush_interval_ms));
+ }
+ });
+ }
+
+ if (message.verbosity == Verbosity_FATAL) {
+ flush();
+
+ if (s_fatal_handler) {
+ s_fatal_handler(message);
+ flush();
+ }
+
+ if (abort_if_fatal) {
+#if LOGURU_CATCH_SIGABRT && !defined(_WIN32)
+ // Make sure we don't catch our own abort:
+ signal(SIGABRT, SIG_DFL);
+#endif
+ abort();
+ }
+ }
+ }
+
+ // stack_trace_skip is just if verbosity == FATAL.
+ void log_to_everywhere(int stack_trace_skip, Verbosity verbosity,
+ const char* file, unsigned line,
+ const char* prefix, const char* buff)
+ {
+ char preamble_buff[LOGURU_PREAMBLE_WIDTH];
+ print_preamble(preamble_buff, sizeof(preamble_buff), verbosity, file, line);
+ auto message = Message{verbosity, file, line, preamble_buff, "", prefix, buff};
+ log_message(stack_trace_skip + 1, message, true, true);
+ }
+
+#if LOGURU_USE_FMTLIB
+ void log(Verbosity verbosity, const char* file, unsigned line, const char* format, fmt::ArgList args)
+ {
+ auto formatted = fmt::format(format, args);
+ log_to_everywhere(1, verbosity, file, line, "", formatted.c_str());
+ }
+
+ void raw_log(Verbosity verbosity, const char* file, unsigned line, const char* format, fmt::ArgList args)
+ {
+ auto formatted = fmt::format(format, args);
+ auto message = Message{verbosity, file, line, "", "", "", formatted.c_str()};
+ log_message(1, message, false, true);
+ }
+
+#else
+ void log(Verbosity verbosity, const char* file, unsigned line, const char* format, ...)
+ {
+ va_list vlist;
+ va_start(vlist, format);
+ auto buff = vtextprintf(format, vlist);
+ log_to_everywhere(1, verbosity, file, line, "", buff.c_str());
+ va_end(vlist);
+ }
+
+ void raw_log(Verbosity verbosity, const char* file, unsigned line, const char* format, ...)
+ {
+ va_list vlist;
+ va_start(vlist, format);
+ auto buff = vtextprintf(format, vlist);
+ auto message = Message{verbosity, file, line, "", "", "", buff.c_str()};
+ log_message(1, message, false, true);
+ va_end(vlist);
+ }
+#endif
+
+ void flush()
+ {
+ std::lock_guard<std::recursive_mutex> lock(s_mutex);
+ fflush(stderr);
+ for (const auto& callback : s_callbacks)
+ {
+ if (callback.flush) {
+ callback.flush(callback.user_data);
+ }
+ }
+ s_needs_flushing = false;
+ }
+
+ LogScopeRAII::LogScopeRAII(Verbosity verbosity, const char* file, unsigned line, const char* format, ...)
+ : _verbosity(verbosity), _file(file), _line(line)
+ {
+ if (verbosity <= current_verbosity_cutoff()) {
+ std::lock_guard<std::recursive_mutex> lock(s_mutex);
+ _indent_stderr = (verbosity <= g_stderr_verbosity);
+ _start_time_ns = now_ns();
+ va_list vlist;
+ va_start(vlist, format);
+ vsnprintf(_name, sizeof(_name), format, vlist);
+ log_to_everywhere(1, _verbosity, file, line, "{ ", _name);
+ va_end(vlist);
+
+ if (_indent_stderr) {
+ ++s_stderr_indentation;
+ }
+
+ for (auto& p : s_callbacks) {
+ if (verbosity <= p.verbosity) {
+ ++p.indentation;
+ }
+ }
+ } else {
+ _file = nullptr;
+ }
+ }
+
+ LogScopeRAII::~LogScopeRAII()
+ {
+ if (_file) {
+ std::lock_guard<std::recursive_mutex> lock(s_mutex);
+ if (_indent_stderr && s_stderr_indentation > 0) {
+ --s_stderr_indentation;
+ }
+ for (auto& p : s_callbacks) {
+ // Note: Callback indentation cannot change!
+ if (_verbosity <= p.verbosity) {
+ // in unlikely case this callback is new
+ if (p.indentation > 0) {
+ --p.indentation;
+ }
+ }
+ }
+#if LOGURU_VERBOSE_SCOPE_ENDINGS
+ auto duration_sec = (now_ns() - _start_time_ns) / 1e9;
+ auto buff = textprintf("%.*f s: %s", LOGURU_SCOPE_TIME_PRECISION, duration_sec, _name);
+ log_to_everywhere(1, _verbosity, _file, _line, "} ", buff.c_str());
+#else
+ log_to_everywhere(1, _verbosity, _file, _line, "}", "");
+#endif
+ }
+ }
+
+ void log_and_abort(int stack_trace_skip, const char* expr, const char* file, unsigned line, const char* format, ...)
+ {
+ va_list vlist;
+ va_start(vlist, format);
+ auto buff = vtextprintf(format, vlist);
+ log_to_everywhere(stack_trace_skip + 1, Verbosity_FATAL, file, line, expr, buff.c_str());
+ va_end(vlist);
+ abort(); // log_to_everywhere already does this, but this makes the analyzer happy.
+ }
+
+ void log_and_abort(int stack_trace_skip, const char* expr, const char* file, unsigned line)
+ {
+ log_and_abort(stack_trace_skip + 1, expr, file, line, " ");
+ }
+
+ // ----------------------------------------------------------------------------
+ // Streams:
+
+ std::string vstrprintf(const char* format, va_list vlist)
+ {
+ auto text = vtextprintf(format, vlist);
+ std::string result = text.c_str();
+ return result;
+ }
+
+ std::string strprintf(const char* format, ...)
+ {
+ va_list vlist;
+ va_start(vlist, format);
+ auto result = vstrprintf(format, vlist);
+ va_end(vlist);
+ return result;
+ }
+
+ #if LOGURU_WITH_STREAMS
+
+ StreamLogger::~StreamLogger() noexcept(false)
+ {
+ auto message = _ss.str();
+ log(_verbosity, _file, _line, "%s", message.c_str());
+ }
+
+ AbortLogger::~AbortLogger() noexcept(false)
+ {
+ auto message = _ss.str();
+ loguru::log_and_abort(1, _expr, _file, _line, "%s", message.c_str());
+ }
+
+ #endif // LOGURU_WITH_STREAMS
+
+ // ----------------------------------------------------------------------------
+ // 888888 88""Yb 88""Yb dP"Yb 88""Yb dP""b8 dP"Yb 88b 88 888888 888888 Yb dP 888888
+ // 88__ 88__dP 88__dP dP Yb 88__dP dP `" dP Yb 88Yb88 88 88__ YbdP 88
+ // 88"" 88"Yb 88"Yb Yb dP 88"Yb Yb Yb dP 88 Y88 88 88"" dPYb 88
+ // 888888 88 Yb 88 Yb YbodP 88 Yb YboodP YbodP 88 Y8 88 888888 dP Yb 88
+ // ----------------------------------------------------------------------------
+
+ struct StringStream
+ {
+ std::string str;
+ };
+
+ // Use this in your EcPrinter implementations.
+ void stream_print(StringStream& out_string_stream, const char* text)
+ {
+ out_string_stream.str += text;
+ }
+
+ // ----------------------------------------------------------------------------
+
+ using ECPtr = EcEntryBase*;
+
+#if defined(_WIN32) || (defined(__APPLE__) && !TARGET_OS_IPHONE)
+ #ifdef __APPLE__
+ #define LOGURU_THREAD_LOCAL __thread
+ #else
+ #define LOGURU_THREAD_LOCAL thread_local
+ #endif
+ static LOGURU_THREAD_LOCAL ECPtr thread_ec_ptr = nullptr;
+
+ ECPtr& get_thread_ec_head_ref()
+ {
+ return thread_ec_ptr;
+ }
+#else // !thread_local
+ static pthread_once_t s_ec_pthread_once = PTHREAD_ONCE_INIT;
+ static pthread_key_t s_ec_pthread_key;
+
+ void free_ec_head_ref(void* io_error_context)
+ {
+ delete reinterpret_cast<ECPtr*>(io_error_context);
+ }
+
+ void ec_make_pthread_key()
+ {
+ (void)pthread_key_create(&s_ec_pthread_key, free_ec_head_ref);
+ }
+
+ ECPtr& get_thread_ec_head_ref()
+ {
+ (void)pthread_once(&s_ec_pthread_once, ec_make_pthread_key);
+ auto ec = reinterpret_cast<ECPtr*>(pthread_getspecific(s_ec_pthread_key));
+ if (ec == nullptr) {
+ ec = new ECPtr(nullptr);
+ (void)pthread_setspecific(s_ec_pthread_key, ec);
+ }
+ return *ec;
+ }
+#endif // !thread_local
+
+ // ----------------------------------------------------------------------------
+
+ EcHandle get_thread_ec_handle()
+ {
+ return get_thread_ec_head_ref();
+ }
+
+ Text get_error_context()
+ {
+ return get_error_context_for(get_thread_ec_head_ref());
+ }
+
+ Text get_error_context_for(const EcEntryBase* ec_head)
+ {
+ std::vector<const EcEntryBase*> stack;
+ while (ec_head) {
+ stack.push_back(ec_head);
+ ec_head = ec_head->_previous;
+ }
+ std::reverse(stack.begin(), stack.end());
+
+ StringStream result;
+ if (!stack.empty()) {
+ result.str += "------------------------------------------------\n";
+ for (auto entry : stack) {
+ const auto description = std::string(entry->_descr) + ":";
+ auto prefix = textprintf("[ErrorContext] %*s:%-5u %-20s ",
+ LOGURU_FILENAME_WIDTH, filename(entry->_file), entry->_line, description.c_str());
+ result.str += prefix.c_str();
+ entry->print_value(result);
+ result.str += "\n";
+ }
+ result.str += "------------------------------------------------";
+ }
+ return Text(STRDUP(result.str.c_str()));
+ }
+
+ EcEntryBase::EcEntryBase(const char* file, unsigned line, const char* descr)
+ : _file(file), _line(line), _descr(descr)
+ {
+ EcEntryBase*& ec_head = get_thread_ec_head_ref();
+ _previous = ec_head;
+ ec_head = this;
+ }
+
+ EcEntryBase::~EcEntryBase()
+ {
+ get_thread_ec_head_ref() = _previous;
+ }
+
+ // ------------------------------------------------------------------------
+
+ Text ec_to_text(const char* value)
+ {
+ // Add quotes around the string to make it obvious where it begin and ends.
+ // This is great for detecting erroneous leading or trailing spaces in e.g. an identifier.
+ auto str = "\"" + std::string(value) + "\"";
+ return Text{STRDUP(str.c_str())};
+ }
+
+ Text ec_to_text(char c)
+ {
+ // Add quotes around the character to make it obvious where it begin and ends.
+ std::string str = "'";
+
+ auto write_hex_digit = [&](unsigned num)
+ {
+ if (num < 10u) { str += char('0' + num); }
+ else { str += char('a' + num - 10); }
+ };
+
+ auto write_hex_16 = [&](uint16_t n)
+ {
+ write_hex_digit((n >> 12u) & 0x0f);
+ write_hex_digit((n >> 8u) & 0x0f);
+ write_hex_digit((n >> 4u) & 0x0f);
+ write_hex_digit((n >> 0u) & 0x0f);
+ };
+
+ if (c == '\\') { str += "\\\\"; }
+ else if (c == '\"') { str += "\\\""; }
+ else if (c == '\'') { str += "\\\'"; }
+ else if (c == '\0') { str += "\\0"; }
+ else if (c == '\b') { str += "\\b"; }
+ else if (c == '\f') { str += "\\f"; }
+ else if (c == '\n') { str += "\\n"; }
+ else if (c == '\r') { str += "\\r"; }
+ else if (c == '\t') { str += "\\t"; }
+ else if (0 <= c && c < 0x20) {
+ str += "\\u";
+ write_hex_16(static_cast<uint16_t>(c));
+ } else { str += c; }
+
+ str += "'";
+
+ return Text{STRDUP(str.c_str())};
+ }
+
+ #define DEFINE_EC(Type) \
+ Text ec_to_text(Type value) \
+ { \
+ auto str = std::to_string(value); \
+ return Text{STRDUP(str.c_str())}; \
+ }
+
+ DEFINE_EC(int)
+ DEFINE_EC(unsigned int)
+ DEFINE_EC(long)
+ DEFINE_EC(unsigned long)
+ DEFINE_EC(long long)
+ DEFINE_EC(unsigned long long)
+ DEFINE_EC(float)
+ DEFINE_EC(double)
+ DEFINE_EC(long double)
+
+ #undef DEFINE_EC
+
+ Text ec_to_text(EcHandle ec_handle)
+ {
+ Text parent_ec = get_error_context_for(ec_handle);
+ char* with_newline = reinterpret_cast<char*>(malloc(strlen(parent_ec.c_str()) + 2));
+ with_newline[0] = '\n';
+ strcpy(with_newline + 1, parent_ec.c_str());
+ return Text(with_newline);
+ }
+
+ // ----------------------------------------------------------------------------
+
+} // namespace loguru
+
+// ----------------------------------------------------------------------------
+// .dP"Y8 88 dP""b8 88b 88 db 88 .dP"Y8
+// `Ybo." 88 dP `" 88Yb88 dPYb 88 `Ybo."
+// o.`Y8b 88 Yb "88 88 Y88 dP__Yb 88 .o o.`Y8b
+// 8bodP' 88 YboodP 88 Y8 dP""""Yb 88ood8 8bodP'
+// ----------------------------------------------------------------------------
+
+#ifdef _WIN32
+namespace loguru {
+ void install_signal_handlers()
+ {
+ #if defined(_MSC_VER)
+ #pragma message ( "No signal handlers on Win32" )
+ #else
+ #warning "No signal handlers on Win32"
+ #endif
+ }
+} // namespace loguru
+
+#else // _WIN32
+
+namespace loguru
+{
+ struct Signal
+ {
+ int number;
+ const char* name;
+ };
+ const Signal ALL_SIGNALS[] = {
+#if LOGURU_CATCH_SIGABRT
+ { SIGABRT, "SIGABRT" },
+#endif
+ { SIGBUS, "SIGBUS" },
+ { SIGFPE, "SIGFPE" },
+ { SIGILL, "SIGILL" },
+ { SIGINT, "SIGINT" },
+ { SIGSEGV, "SIGSEGV" },
+ { SIGTERM, "SIGTERM" },
+ };
+
+ void write_to_stderr(const char* data, size_t size)
+ {
+ auto result = write(STDERR_FILENO, data, size);
+ (void)result; // Ignore errors.
+ }
+
+ void write_to_stderr(const char* data)
+ {
+ write_to_stderr(data, strlen(data));
+ }
+
+ void call_default_signal_handler(int signal_number)
+ {
+ struct sigaction sig_action;
+ memset(&sig_action, 0, sizeof(sig_action));
+ sigemptyset(&sig_action.sa_mask);
+ sig_action.sa_handler = SIG_DFL;
+ sigaction(signal_number, &sig_action, NULL);
+ kill(getpid(), signal_number);
+ }
+
+ void signal_handler(int signal_number, siginfo_t*, void*)
+ {
+ const char* signal_name = "UNKNOWN SIGNAL";
+
+ for (const auto& s : ALL_SIGNALS) {
+ if (s.number == signal_number) {
+ signal_name = s.name;
+ break;
+ }
+ }
+
+ // --------------------------------------------------------------------
+ /* There are few things that are safe to do in a signal handler,
+ but writing to stderr is one of them.
+ So we first print out what happened to stderr so we're sure that gets out,
+ then we do the unsafe things, like logging the stack trace.
+ */
+
+ if (g_colorlogtostderr && s_terminal_has_color) {
+ write_to_stderr(terminal_reset());
+ write_to_stderr(terminal_bold());
+ write_to_stderr(terminal_light_red());
+ }
+ write_to_stderr("\n");
+ write_to_stderr("Loguru caught a signal: ");
+ write_to_stderr(signal_name);
+ write_to_stderr("\n");
+ if (g_colorlogtostderr && s_terminal_has_color) {
+ write_to_stderr(terminal_reset());
+ }
+
+ // --------------------------------------------------------------------
+
+#if LOGURU_UNSAFE_SIGNAL_HANDLER
+ // --------------------------------------------------------------------
+ /* Now we do unsafe things. This can for example lead to deadlocks if
+ the signal was triggered from the system's memory management functions
+ and the code below tries to do allocations.
+ */
+
+ flush();
+ char preamble_buff[LOGURU_PREAMBLE_WIDTH];
+ print_preamble(preamble_buff, sizeof(preamble_buff), Verbosity_FATAL, "", 0);
+ auto message = Message{Verbosity_FATAL, "", 0, preamble_buff, "", "Signal: ", signal_name};
+ try {
+ log_message(1, message, false, false);
+ } catch (...) {
+ // This can happed due to s_fatal_handler.
+ write_to_stderr("Exception caught and ignored by Loguru signal handler.\n");
+ }
+ flush();
+
+ // --------------------------------------------------------------------
+#endif // LOGURU_UNSAFE_SIGNAL_HANDLER
+
+ call_default_signal_handler(signal_number);
+ }
+
+ void install_signal_handlers()
+ {
+ struct sigaction sig_action;
+ memset(&sig_action, 0, sizeof(sig_action));
+ sigemptyset(&sig_action.sa_mask);
+ sig_action.sa_flags |= SA_SIGINFO;
+ sig_action.sa_sigaction = &signal_handler;
+ for (const auto& s : ALL_SIGNALS) {
+ CHECK_F(sigaction(s.number, &sig_action, NULL) != -1,
+ "Failed to install handler for %s", s.name);
+ }
+ }
+} // namespace loguru
+
+#endif // _WIN32
+
+#endif // LOGURU_IMPLEMENTATION
\ No newline at end of file
--- /dev/null
+project('aurum', ['cpp'],
+ version: '0.0.1',
+ default_options : ['buildtype=debugoptimized', 'cpp_std=c++17'],
+ meson_version : '>=0.47'
+)
+
+config_h = configuration_data()
+if get_option('tizen') == true
+ config_h.set10('GBS_BUILD', true)
+ config_h.set10('GBSBUILD', true)
+ config_h.set10('TIZEN', true)
+else
+ message('')
+endif
+
+root_inc = include_directories('./')
+
+subdir('protocol')
+subdir('libloguru')
+subdir('libaurum')
+subdir('bootstrap')
+subdir('tests')
+
+configure_file(
+ output: 'config.h',
+ configuration: config_h
+)
+
--- /dev/null
+option('tizen',
+ type: 'boolean',
+ value: false,
+ description: 'enable tizen specific dependancy'
+)
+
+
--- /dev/null
+#!/bin/bash -xe
+
+repo_url=http://download.tizen.org/snapshots/tizen/unified/latest/repos/standard/packages/armv7l/
+repo_dbg_url=http://download.tizen.org/snapshots/tizen/unified/latest/repos/standard/debug/
+
+libgrpc_filter=" -A libgrpc* "
+grpc_filter=" -A grpc-* "
+grpc_dbg_filter=" -A grpc-debug*armv7l* -A libatspi-debug*armv7l&"
+libgrpc_dbg_filter=" -A libgrpc-debug*armv7l* "
+
+test -d rpm && rm -rf rpm
+
+wget -P rpm --recursive -nd -nH -np $repo_url $grpc_filter
+wget -P rpm --recursive -nd -nH -np $repo_url $libgrpc_filter
+
+wget -P rpm --recursive -nd -nH -np $repo_dbg_url $grpc_dbg_filter
+wget -P rpm --recursive -nd -nH -np $repo_dbg_url $libgrpc_dbg_filter
--- /dev/null
+export TIZEN_WAYLAND_SHM_DIR=/run/.efl
+export beam_delta=0.5
+export EVAS_FONT_DPI=72
+export HOSTNAME=
+export LISTEN_PID=774
+export beam=15
+export WAYLAND_DISPLAY=wayland-0
+export ECORE_INPUT_CANCEL=1
+export EINA_LOG_ABORT_LEVEL=0
+export SHELL=/bin/bash
+export left_context=0
+export HISTSIZE=1000
+export fbank_conf=/usr/apps/org.tizen.stt-engine-embedded/shared/res/model/conf/fbank.conf
+export ac_weight=0.75
+export ELM_ENGINE=wayland_egl
+export LC_ALL=POSIX
+export lattice_beam=8.0
+export USER=owner
+export GST_DEBUG=2
+export WRT_BLOCK_SINGLE_PROCESS=OFF
+export right_context=3
+export symtab=/usr/apps/org.tizen.stt-engine-embedded/shared/res/model/lm/words.txt
+export ECORE_IMF_MODULE=wayland
+export MAIL=/var/spool/mail/owner
+export PATH=/bin:/usr/bin:/sbin:/usr/sbin
+export ECTOR_BACKEND=default
+export LISTEN_FDNAMES=launchpad-process-pool.socket
+export max_active=7000
+export EINA_LOG_DLOG_ENABLE=1
+export ELM_ATSPI_MODE=1
+export online=true
+export PWD=/opt/usr/home/owner
+export result=/usr/apps/org.tizen.stt-engine-embedded/shared/res/result.txt
+export lattice_out=lat.kor
+export nnet_in=/usr/apps/org.tizen.stt-engine-embedded/shared/res/model/am/converted_2_Eigen_Mat.nnet
+export prior=/usr/apps/org.tizen.stt-engine-embedded/shared/res/model/am/label.counts
+export LANG=en_US.UTF-8
+export PYTHONSTARTUP=/etc/pythonstart
+export global_cmvn=/usr/apps/org.tizen.stt-engine-embedded/shared/res/model/am/global_cmvn0412.ark
+export EVAS_SHM_FLUSH=1
+export fst_in=/usr/apps/org.tizen.stt-engine-embedded/shared/res/model/lm/TLG.fst
+export HISTCONTROL=ignoredups
+export hyp_filtering_cmd=cat
+export EINA_LOG_LEVEL=2
+export SHLVL=1
+export HOME=/opt/usr/home/owner
+export use_gpu=no
+export ECORE_ANIMATOR_SKIP=1
+export big_lm=/usr/apps/org.tizen.stt-engine-embedded/shared/res/model/lm/Mix_Bixby_VD_64k.1e8.arpa.carpa
+export ECORE_IMF_INPUT_PANEL_ENABLED=1
+export LOGNAME=owner
+export splice_conf=/usr/apps/org.tizen.stt-engine-embedded/shared/res/model/conf/splice.conf
+export cmvn_conf=/usr/apps/org.tizen.stt-engine-embedded/shared/res/model/conf/online_cmvn.conf
+export EVAS_GL_NO_BLACKLIST=1
+export DBUS_SESSION_BUS_ADDRESS="kernel:path=/sys/fs/kdbus/5001-user/bus;unix:path=/run/user/5001/bus"
+export res_dir=/usr/apps/org.tizen.stt-engine-embedded/shared/res
+export word_ins_penalty=1.0
+export delta_conf=/usr/apps/org.tizen.stt-engine-embedded/shared/res/model/conf/delta.conf
+export MANAGERPID=610
+export JOURNAL_STREAM=7:22973
+export EINA_LOG_ABORT=1
+export XDG_RUNTIME_DIR=/run/user/5001
+export ELM_DISPLAY=wl
+export GTK_IM_MODULE=scim
+export LISTEN_FDS=1
+export G_BROKEN_FILENAMES=1
+export ELM_PROFILE=mobile
+export work_dir=/usr/apps/org.tizen.stt-engine-embedded/shared/res/model
+export _=/usr/bin/launchpad-process-pool
--- /dev/null
+#!/bin/bash
+
+sdb forward --remove-all
+sdb forward tcp:50051 tcp:50051
+sdb shell "su - owner -c 'systemctl --user start aurum-bootstrap'"
+sdb shell "ps -ef | grep aurum-bootstrap"
--- /dev/null
+<manifest>
+ <request>
+ <domain name="_"/>
+ </request>
+</manifest>
\ No newline at end of file
--- /dev/null
+Name: aurum
+Version: 0.1.0
+Release: 0
+License: Apache-2.0
+Summary: Automation framework for Ui testing
+Group: UI Framework
+Source: %{name}-%{version}.tar.gz
+Source1001: %{name}.manifest
+
+BuildRequires: meson
+BuildRequires: pkgconfig(grpc)
+BuildRequires: pkgconfig(grpc++)
+BuildRequires: pkgconfig(atspi-2)
+BuildRequires: pkgconfig(capi-system-info)
+BuildRequires: pkgconfig(capi-ui-efl-util)
+BuildRequires: pkgconfig(dlog)
+BuildRequires: pkgconfig(elementary)
+BuildRequires: gtest-devel
+
+BuildRequires: pkgconfig(aul)
+BuildRequires: pkgconfig(capi-appfw-package-manager)
+BuildRequires: pkgconfig(capi-appfw-app-control)
+BuildRequires: pkgconfig(capi-appfw-app-manager)
+
+Requires: pkgconfig(atspi-2)
+Requires: pkgconfig(dlog)
+
+%description
+aurum is a project for testing ui.
+it provides interfaces through gRPC protocol.
+
+%package devel
+Summary: devel package for libaurum
+
+%description devel
+devel package for libaurum
+
+%package bootstrap
+Summary: bootstrap
+License: Apache-2.0
+Requires: %{name} = %{version}-%{release}
+Requires: pkgconfig(grpc)
+Requires: pkgconfig(grpc++)
+
+%description bootstrap
+gRPC Server
+
+%prep
+%setup -q
+cp %{SOURCE1001} .
+
+meson \
+ --prefix /usr \
+ --libdir %{_libdir} \
+ -Dcpp_std=c++17 \
+ -Dtizen=true \
+ gbsbuild 2>&1
+
+%build
+
+ninja \
+ -C gbsbuild \
+ -j %(echo "`/usr/bin/getconf _NPROCESSORS_ONLN`") \
+ -v \
+ all
+
+ninja \
+ -C gbsbuild \
+ -j %(echo "`/usr/bin/getconf _NPROCESSORS_ONLN`") \
+ -v \
+ test
+
+%install
+
+export DESTDIR=%{buildroot}
+ninja -C gbsbuild install
+
+%post
+sbin/ldconfig
+
+%postun
+sbin/ldconfig
+
+%post bootstrap
+#/sbin/ldconfig
+chsmack -e "User" %{_bindir}/bootstrap_server
+
+%postun bootstrap
+/sbin/ldconfig
+
+%files
+%manifest %{name}.manifest
+%defattr(-,root,root)
+%license COPYING
+%{_libdir}/libaurum.so.*
+
+%files devel
+%manifest %{name}.manifest
+%defattr(-,root,root)
+%license COPYING
+%{_libdir}/libaurum.so
+
+%files bootstrap
+%manifest %{name}.manifest
+%defattr(-,root,root)
+%license COPYING
+%{_bindir}/aurum_bootstrap
+%{_unitdir_user}/aurum-bootstrap.service
--- /dev/null
+syntax = "proto3";
+package aurum;
+
+service Bootstrap {
+ rpc sync(ReqEmpty) returns (RspEmpty) {}
+ rpc killServer(ReqEmpty) returns (RspEmpty) {}
+
+ rpc findElement(ReqFindElement) returns (RspFindElement) {}
+
+ rpc getValue(ReqGetValue) returns (RspGetValue) {}
+ rpc setValue(ReqSetValue) returns (RspSetValue) {}
+ rpc getSize(ReqGetSize) returns (RspGetSize) {}
+ rpc clear(ReqClear) returns (RspClear) {}
+ rpc getAttribute(ReqGetAttribute) returns (RspGetAttribute) {}
+
+ rpc click(ReqClick) returns (RspClick) {}
+ rpc longClick(ReqClick) returns (RspClick) {}
+ rpc flick(ReqFlick) returns (RspFlick) {}
+
+ rpc touchDown(ReqTouchDown) returns (RspTouchDown) {}
+ rpc touchMove(ReqTouchMove) returns (RspTouchMove) {}
+ rpc touchUp(ReqTouchUp) returns (RspTouchUp) {}
+
+ rpc installApp(stream ReqInstallApp) returns (RspInstallApp) {}
+ rpc removeApp(ReqRemoveApp) returns (RspRemoveApp) {}
+ rpc getAppInfo(ReqGetAppInfo) returns (RspGetAppInfo) {}
+ rpc launchApp(ReqLaunchApp) returns (RspLaunchApp) {}
+ rpc closeApp(ReqCloseApp) returns (RspCloseApp) {}
+
+ rpc getDeviceTime(ReqGetDeviceTime) returns (RspGetDeviceTime) {}
+ rpc getLocation(ReqGetLocation) returns (RspGetLocation) {}
+ rpc sendKey(ReqKey) returns (RspKey) {}
+}
+
+// ------------------------------------ //
+
+enum RspStatus {
+ OK = 0;
+ NA = 1;
+ ERROR = 2;
+}
+
+enum ParamType {
+ STRING = 0;
+ INT = 1;
+ DOUBLE = 2;
+ BOOL = 3;
+}
+
+message Element {
+ string elementId = 1;
+}
+
+message Point {
+ int32 x = 1;
+ int32 y = 2;
+}
+
+message Rect {
+ int32 x = 1;
+ int32 y = 2;
+ int32 width = 3;
+ int32 height = 4;
+}
+
+// ------------------------------------ //
+
+message ReqFindElement {
+ enum RequestType {
+ AUTOMATIONID = 0;
+ TEXT = 1;
+ TYPE = 2;
+ STYLE = 3;
+ }
+ string elementId = 1;
+ RequestType strategy = 2;
+ oneof params {
+ string automationId = 3;
+ string textField = 4;
+ string widgetType = 5;
+ string widgetStyle = 6;
+ }
+}
+message RspFindElement {
+ RspStatus status = 1;
+ repeated Element elements = 2;
+}
+
+// ------------------------------------ //
+
+message ReqGetValue {
+ string elementId = 1;
+}
+message RspGetValue {
+ RspStatus status = 1;
+ ParamType type = 2;
+ oneof params {
+ string stringValue = 3;
+ int32 intValue = 4;
+ double doubleValue = 5;
+ double boolValue = 6;
+ }
+}
+
+message ReqSetValue {
+ string elementId = 1;
+ ParamType type = 2;
+ oneof params {
+ string stringValue = 3;
+ int32 intValue = 4;
+ double doubleValue = 5;
+ double boolValue = 6;
+ }
+}
+message RspSetValue {
+ RspStatus status = 1;
+}
+
+message ReqGetSize{
+ string elementId = 1;
+}
+message RspGetSize{
+ RspStatus status = 1;
+ Rect size = 2;
+}
+
+message ReqClear{
+ string elementId = 1;
+}
+message RspClear{
+ RspStatus status = 1;
+}
+
+message ReqGetAttribute {
+ enum RequestType {
+ VISIBLE = 0;
+ FOCUSABLE = 1;
+ FOCUSED = 2;
+ ENABLED = 3;
+ CLICKABLE = 4;
+ SCROLLABLE = 5;
+ CHECKABLE = 6;
+ CHECKED = 7;
+ SELECTED = 8;
+ SELECTABLE = 9;
+ }
+ string elementId = 1;
+ RequestType attribute = 2;
+}
+message RspGetAttribute {
+ RspStatus status = 1;
+ ParamType type = 2;
+ oneof params {
+ string stringValue = 3;
+ int32 intValue = 4;
+ double doubleValue = 5;
+ double boolValue = 6;
+ }
+}
+
+// ------------------------------------ //
+
+message ReqClick{
+ enum RequestType {
+ ELEMENTID = 0;
+ COORD = 1;
+ ATSPI = 2;
+ }
+ RequestType type = 1;
+ oneof params {
+ string elementId = 2;
+ Point coordination = 3;
+ }
+}
+message RspClick{
+ RspStatus status = 1;
+}
+
+message ReqFlick{
+ Point startPoint = 1;
+ Point endPoint = 2;
+ int32 durationMs = 3;
+}
+message RspFlick{
+ RspStatus status = 1;
+}
+
+message ReqTouchDown{
+ Point coordination = 1;
+}
+message RspTouchDown{
+ RspStatus status = 1;
+ int32 seqId = 2;
+}
+
+message ReqTouchMove{
+ int32 seqId = 1;
+ Point coordination = 2;
+}
+message RspTouchMove{
+ RspStatus status = 1;
+}
+
+message ReqTouchUp{
+ int32 seqId = 1;
+ Point coordination = 2;
+}
+message RspTouchUp{
+ RspStatus status = 1;
+}
+
+// ------------------------------------ //
+
+message ReqInstallApp{
+ bytes package = 1;
+}
+message RspInstallApp{
+ RspStatus status = 1;
+}
+
+message ReqRemoveApp{
+ string packageName = 1;
+}
+message RspRemoveApp{
+ RspStatus status = 1;
+}
+
+message ReqGetAppInfo{
+ string packageName = 1;
+}
+message RspGetAppInfo {
+ RspStatus status = 1;
+ bool isInstalled = 2;
+ bool isRunning = 3;
+ bool isFocused = 4;
+}
+
+message ReqLaunchApp{
+ string packageName = 1;
+}
+message RspLaunchApp{
+ RspStatus status = 1;
+}
+
+message ReqCloseApp{
+ string packageName = 1;
+}
+message RspCloseApp{
+ RspStatus status = 1;
+}
+
+// ------------------------------------ //
+
+message ReqGetDeviceTime{
+}
+message RspGetDeviceTime{
+ RspStatus status = 1;
+}
+
+message ReqGetLocation{
+}
+message RspGetLocation{
+ RspStatus status = 1;
+ string alt = 2;
+ string lat = 3;
+}
+
+message ReqKey{
+ enum KeyType{
+ BACK = 0;
+ MENU = 1;
+ HOME = 2;
+ VOLUP = 3;
+ VOLDOWN = 4;
+ POWER = 5;
+ KEY = 6;
+ XF86 = 7;
+ }
+ enum KeyActionType{
+ PRESS = 0;
+ RELEASE = 1;
+ STROKE = 2;
+ LONG_STROKE = 3;
+ }
+ KeyType type = 1;
+ KeyActionType actionType = 2;
+ oneof keys {
+ uint32 keyCode = 3;
+ string XF86keyCode = 4;
+ }
+}
+message RspKey{
+ RspStatus status = 1;
+}
+
+// ------------------------------------ //
+
+message ReqEmpty {
+}
+message RspEmpty {
+}
--- /dev/null
+int main(){
+ return 0;
+}
\ No newline at end of file
--- /dev/null
+```sh
+npm install
+npm install -g grpc-tools
+
+grpc_tools_node_protoc --js_out=import_style=commonjs,binary:./ --grpc_out=./ --plugin=protoc-gen-grpc=`which grpc_tools_node_protoc_plugin` ../../aurum.proto
+
+grpc_tools_node_protoc --js_out=import_style=commonjs,binary:../node/static_codegen/route_guide/ --grpc_out=../node/static_codegen/route_guide/ --plugin=protoc-gen-grpc=`which grpc_tools_node_protoc_plugin` aurum.proto
+```
--- /dev/null
+
+var messages = require('./aurum_pb');
+var services = require('./aurum_grpc_pb');
+
+var grpc = require('grpc');
+
+function main() {
+ var client = new services.BootstrapClient('localhost:50051',
+ grpc.credentials.createInsecure());
+
+ var request = new messages.ReqFindElement();
+
+ client.sync(new messages.ReqEmpty(), function(err, res){console.log(res)});
+
+ request.setStrategy(proto.aurum.ReqFindElement.RequestType.TEXT);
+ request.setTextfield("DONE");
+
+ client.findElement(request, function(err, response) {
+ if (err) {
+ console.log(err);
+ return;
+ }
+ var returnList = response.getElementsList();
+ console.log(returnList);
+ if (returnList.length > 0)
+ {
+ var request2 = new messages.ReqClick();
+ request2.setType(proto.aurum.ReqClick.RequestType.ELEMENTID)
+ request2.setElementid(returnList[0].getElementid());
+ client.click(request2, function(err, response2) {
+ if (err) {
+ console.log(err);
+ return;
+ }
+ console.log(response2);
+ });
+ }
+ });
+}
+
+main();
--- /dev/null
+#!/bin/bash
+
+grpc_tools_node_protoc --js_out=import_style=commonjs,binary:./ \
+ --grpc_out=./ --plugin=protoc-gen-grpc=`which grpc_tools_node_protoc_plugin`\
+ -I ./../../ ../../aurum.proto
+
--- /dev/null
+{
+ "name": "ua-node-example",
+ "version": "0.1.0",
+ "lockfileVersion": 1,
+ "requires": true,
+ "dependencies": {
+ "@grpc/proto-loader": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.1.0.tgz",
+ "integrity": "sha512-GHoZBR5N+65AWazsCiJDxeMSbUpp2qNYbjeD3mP27L2PT25+GvIupIIJiCgULH87NAiAd9SmWMRBVz+uSiHpgA==",
+ "requires": {
+ "@types/lodash": "^4.14.104",
+ "@types/node": "^9.4.6",
+ "lodash": "^4.17.5",
+ "protobufjs": "^6.8.6"
+ }
+ },
+ "@protobufjs/aspromise": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz",
+ "integrity": "sha1-m4sMxmPWaafY9vXQiToU00jzD78="
+ },
+ "@protobufjs/base64": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz",
+ "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg=="
+ },
+ "@protobufjs/codegen": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz",
+ "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg=="
+ },
+ "@protobufjs/eventemitter": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz",
+ "integrity": "sha1-NVy8mLr61ZePntCV85diHx0Ga3A="
+ },
+ "@protobufjs/fetch": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz",
+ "integrity": "sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU=",
+ "requires": {
+ "@protobufjs/aspromise": "^1.1.1",
+ "@protobufjs/inquire": "^1.1.0"
+ }
+ },
+ "@protobufjs/float": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz",
+ "integrity": "sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E="
+ },
+ "@protobufjs/inquire": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz",
+ "integrity": "sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik="
+ },
+ "@protobufjs/path": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz",
+ "integrity": "sha1-bMKyDFya1q0NzP0hynZz2Nf79o0="
+ },
+ "@protobufjs/pool": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz",
+ "integrity": "sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q="
+ },
+ "@protobufjs/utf8": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz",
+ "integrity": "sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA="
+ },
+ "@types/bytebuffer": {
+ "version": "5.0.40",
+ "resolved": "https://registry.npmjs.org/@types/bytebuffer/-/bytebuffer-5.0.40.tgz",
+ "integrity": "sha512-h48dyzZrPMz25K6Q4+NCwWaxwXany2FhQg/ErOcdZS1ZpsaDnDMZg8JYLMTGz7uvXKrcKGJUZJlZObyfgdaN9g==",
+ "requires": {
+ "@types/long": "*",
+ "@types/node": "*"
+ }
+ },
+ "@types/lodash": {
+ "version": "4.14.138",
+ "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.138.tgz",
+ "integrity": "sha512-A4uJgHz4hakwNBdHNPdxOTkYmXNgmUAKLbXZ7PKGslgeV0Mb8P3BlbYfPovExek1qnod4pDfRbxuzcVs3dlFLg=="
+ },
+ "@types/long": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.0.tgz",
+ "integrity": "sha512-1w52Nyx4Gq47uuu0EVcsHBxZFJgurQ+rTKS3qMHxR1GY2T8c2AJYd6vZoZ9q1rupaDjU0yT+Jc2XTyXkjeMA+Q=="
+ },
+ "@types/node": {
+ "version": "9.6.51",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-9.6.51.tgz",
+ "integrity": "sha512-5lhC7QM2J3b/+epdwaNfRuG2peN4c9EX+mkd27+SqLKhJSdswHTZvc4aZLBZChi+Wo32+E1DeMZs0fSpu/uBXQ=="
+ },
+ "ansi-regex": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
+ },
+ "ascli": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/ascli/-/ascli-1.0.1.tgz",
+ "integrity": "sha1-vPpZdKYvGOgcq660lzKrSoj5Brw=",
+ "requires": {
+ "colour": "~0.7.1",
+ "optjs": "~3.2.2"
+ }
+ },
+ "async": {
+ "version": "1.5.2",
+ "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz",
+ "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo="
+ },
+ "bytebuffer": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/bytebuffer/-/bytebuffer-5.0.1.tgz",
+ "integrity": "sha1-WC7qSxqHO20CCkjVjfhfC7ps/d0=",
+ "requires": {
+ "long": "~3"
+ },
+ "dependencies": {
+ "long": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/long/-/long-3.2.0.tgz",
+ "integrity": "sha1-2CG3E4yhy1gcFymQ7xTbIAtcR0s="
+ }
+ }
+ },
+ "camelcase": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz",
+ "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8="
+ },
+ "cliui": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz",
+ "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=",
+ "requires": {
+ "string-width": "^1.0.1",
+ "strip-ansi": "^3.0.1",
+ "wrap-ansi": "^2.0.0"
+ }
+ },
+ "code-point-at": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
+ "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c="
+ },
+ "colour": {
+ "version": "0.7.1",
+ "resolved": "https://registry.npmjs.org/colour/-/colour-0.7.1.tgz",
+ "integrity": "sha1-nLFpkX7F0SwHNtPoaFdG3xyt93g="
+ },
+ "decamelize": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
+ "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA="
+ },
+ "google-protobuf": {
+ "version": "3.9.1",
+ "resolved": "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.9.1.tgz",
+ "integrity": "sha512-tkz7SVwBktFbqFK3teXFUY/VM57+mbUgV9bSD+sZH1ocHJ7uk7BfEWMRdU24dd0ciUDokreA7ghH2fYFIczQdw=="
+ },
+ "grpc": {
+ "version": "1.23.3",
+ "resolved": "https://registry.npmjs.org/grpc/-/grpc-1.23.3.tgz",
+ "integrity": "sha512-7vdzxPw9s5UYch4aUn4hyM5tMaouaxUUkwkgJlwbR4AXMxiYZJOv19N2ps2eKiuUbJovo5fnGF9hg/X91gWYjw==",
+ "requires": {
+ "@types/bytebuffer": "^5.0.40",
+ "lodash.camelcase": "^4.3.0",
+ "lodash.clone": "^4.5.0",
+ "nan": "^2.13.2",
+ "node-pre-gyp": "^0.13.0",
+ "protobufjs": "^5.0.3"
+ },
+ "dependencies": {
+ "abbrev": {
+ "version": "1.1.1",
+ "bundled": true
+ },
+ "ansi-regex": {
+ "version": "2.1.1",
+ "bundled": true
+ },
+ "aproba": {
+ "version": "1.2.0",
+ "bundled": true
+ },
+ "are-we-there-yet": {
+ "version": "1.1.5",
+ "bundled": true,
+ "requires": {
+ "delegates": "^1.0.0",
+ "readable-stream": "^2.0.6"
+ }
+ },
+ "balanced-match": {
+ "version": "1.0.0",
+ "bundled": true
+ },
+ "brace-expansion": {
+ "version": "1.1.11",
+ "bundled": true,
+ "requires": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "chownr": {
+ "version": "1.1.2",
+ "bundled": true
+ },
+ "code-point-at": {
+ "version": "1.1.0",
+ "bundled": true
+ },
+ "concat-map": {
+ "version": "0.0.1",
+ "bundled": true
+ },
+ "console-control-strings": {
+ "version": "1.1.0",
+ "bundled": true
+ },
+ "core-util-is": {
+ "version": "1.0.2",
+ "bundled": true
+ },
+ "debug": {
+ "version": "3.2.6",
+ "bundled": true,
+ "requires": {
+ "ms": "^2.1.1"
+ }
+ },
+ "deep-extend": {
+ "version": "0.6.0",
+ "bundled": true
+ },
+ "delegates": {
+ "version": "1.0.0",
+ "bundled": true
+ },
+ "detect-libc": {
+ "version": "1.0.3",
+ "bundled": true
+ },
+ "fs-minipass": {
+ "version": "1.2.6",
+ "bundled": true,
+ "requires": {
+ "minipass": "^2.2.1"
+ }
+ },
+ "fs.realpath": {
+ "version": "1.0.0",
+ "bundled": true
+ },
+ "gauge": {
+ "version": "2.7.4",
+ "bundled": true,
+ "requires": {
+ "aproba": "^1.0.3",
+ "console-control-strings": "^1.0.0",
+ "has-unicode": "^2.0.0",
+ "object-assign": "^4.1.0",
+ "signal-exit": "^3.0.0",
+ "string-width": "^1.0.1",
+ "strip-ansi": "^3.0.1",
+ "wide-align": "^1.1.0"
+ }
+ },
+ "glob": {
+ "version": "7.1.4",
+ "bundled": true,
+ "requires": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ },
+ "has-unicode": {
+ "version": "2.0.1",
+ "bundled": true
+ },
+ "iconv-lite": {
+ "version": "0.4.24",
+ "bundled": true,
+ "requires": {
+ "safer-buffer": ">= 2.1.2 < 3"
+ }
+ },
+ "ignore-walk": {
+ "version": "3.0.1",
+ "bundled": true,
+ "requires": {
+ "minimatch": "^3.0.4"
+ }
+ },
+ "inflight": {
+ "version": "1.0.6",
+ "bundled": true,
+ "requires": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "inherits": {
+ "version": "2.0.4",
+ "bundled": true
+ },
+ "ini": {
+ "version": "1.3.5",
+ "bundled": true
+ },
+ "is-fullwidth-code-point": {
+ "version": "1.0.0",
+ "bundled": true,
+ "requires": {
+ "number-is-nan": "^1.0.0"
+ }
+ },
+ "isarray": {
+ "version": "1.0.0",
+ "bundled": true
+ },
+ "minimatch": {
+ "version": "3.0.4",
+ "bundled": true,
+ "requires": {
+ "brace-expansion": "^1.1.7"
+ }
+ },
+ "minimist": {
+ "version": "1.2.0",
+ "bundled": true
+ },
+ "minipass": {
+ "version": "2.3.5",
+ "bundled": true,
+ "requires": {
+ "safe-buffer": "^5.1.2",
+ "yallist": "^3.0.0"
+ }
+ },
+ "minizlib": {
+ "version": "1.2.1",
+ "bundled": true,
+ "requires": {
+ "minipass": "^2.2.1"
+ }
+ },
+ "mkdirp": {
+ "version": "0.5.1",
+ "bundled": true,
+ "requires": {
+ "minimist": "0.0.8"
+ },
+ "dependencies": {
+ "minimist": {
+ "version": "0.0.8",
+ "bundled": true
+ }
+ }
+ },
+ "ms": {
+ "version": "2.1.2",
+ "bundled": true
+ },
+ "needle": {
+ "version": "2.4.0",
+ "bundled": true,
+ "requires": {
+ "debug": "^3.2.6",
+ "iconv-lite": "^0.4.4",
+ "sax": "^1.2.4"
+ }
+ },
+ "node-pre-gyp": {
+ "version": "0.13.0",
+ "bundled": true,
+ "requires": {
+ "detect-libc": "^1.0.2",
+ "mkdirp": "^0.5.1",
+ "needle": "^2.2.1",
+ "nopt": "^4.0.1",
+ "npm-packlist": "^1.1.6",
+ "npmlog": "^4.0.2",
+ "rc": "^1.2.7",
+ "rimraf": "^2.6.1",
+ "semver": "^5.3.0",
+ "tar": "^4"
+ }
+ },
+ "nopt": {
+ "version": "4.0.1",
+ "bundled": true,
+ "requires": {
+ "abbrev": "1",
+ "osenv": "^0.1.4"
+ }
+ },
+ "npm-bundled": {
+ "version": "1.0.6",
+ "bundled": true
+ },
+ "npm-packlist": {
+ "version": "1.4.4",
+ "bundled": true,
+ "requires": {
+ "ignore-walk": "^3.0.1",
+ "npm-bundled": "^1.0.1"
+ }
+ },
+ "npmlog": {
+ "version": "4.1.2",
+ "bundled": true,
+ "requires": {
+ "are-we-there-yet": "~1.1.2",
+ "console-control-strings": "~1.1.0",
+ "gauge": "~2.7.3",
+ "set-blocking": "~2.0.0"
+ }
+ },
+ "number-is-nan": {
+ "version": "1.0.1",
+ "bundled": true
+ },
+ "object-assign": {
+ "version": "4.1.1",
+ "bundled": true
+ },
+ "once": {
+ "version": "1.4.0",
+ "bundled": true,
+ "requires": {
+ "wrappy": "1"
+ }
+ },
+ "os-homedir": {
+ "version": "1.0.2",
+ "bundled": true
+ },
+ "os-tmpdir": {
+ "version": "1.0.2",
+ "bundled": true
+ },
+ "osenv": {
+ "version": "0.1.5",
+ "bundled": true,
+ "requires": {
+ "os-homedir": "^1.0.0",
+ "os-tmpdir": "^1.0.0"
+ }
+ },
+ "path-is-absolute": {
+ "version": "1.0.1",
+ "bundled": true
+ },
+ "process-nextick-args": {
+ "version": "2.0.1",
+ "bundled": true
+ },
+ "protobufjs": {
+ "version": "5.0.3",
+ "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-5.0.3.tgz",
+ "integrity": "sha512-55Kcx1MhPZX0zTbVosMQEO5R6/rikNXd9b6RQK4KSPcrSIIwoXTtebIczUrXlwaSrbz4x8XUVThGPob1n8I4QA==",
+ "requires": {
+ "ascli": "~1",
+ "bytebuffer": "~5",
+ "glob": "^7.0.5",
+ "yargs": "^3.10.0"
+ }
+ },
+ "rc": {
+ "version": "1.2.8",
+ "bundled": true,
+ "requires": {
+ "deep-extend": "^0.6.0",
+ "ini": "~1.3.0",
+ "minimist": "^1.2.0",
+ "strip-json-comments": "~2.0.1"
+ }
+ },
+ "readable-stream": {
+ "version": "2.3.6",
+ "bundled": true,
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "rimraf": {
+ "version": "2.7.1",
+ "bundled": true,
+ "requires": {
+ "glob": "^7.1.3"
+ }
+ },
+ "safe-buffer": {
+ "version": "5.1.2",
+ "bundled": true
+ },
+ "safer-buffer": {
+ "version": "2.1.2",
+ "bundled": true
+ },
+ "sax": {
+ "version": "1.2.4",
+ "bundled": true
+ },
+ "semver": {
+ "version": "5.7.1",
+ "bundled": true
+ },
+ "set-blocking": {
+ "version": "2.0.0",
+ "bundled": true
+ },
+ "signal-exit": {
+ "version": "3.0.2",
+ "bundled": true
+ },
+ "string-width": {
+ "version": "1.0.2",
+ "bundled": true,
+ "requires": {
+ "code-point-at": "^1.0.0",
+ "is-fullwidth-code-point": "^1.0.0",
+ "strip-ansi": "^3.0.0"
+ }
+ },
+ "string_decoder": {
+ "version": "1.1.1",
+ "bundled": true,
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "3.0.1",
+ "bundled": true,
+ "requires": {
+ "ansi-regex": "^2.0.0"
+ }
+ },
+ "strip-json-comments": {
+ "version": "2.0.1",
+ "bundled": true
+ },
+ "tar": {
+ "version": "4.4.10",
+ "bundled": true,
+ "requires": {
+ "chownr": "^1.1.1",
+ "fs-minipass": "^1.2.5",
+ "minipass": "^2.3.5",
+ "minizlib": "^1.2.1",
+ "mkdirp": "^0.5.0",
+ "safe-buffer": "^5.1.2",
+ "yallist": "^3.0.3"
+ }
+ },
+ "util-deprecate": {
+ "version": "1.0.2",
+ "bundled": true
+ },
+ "wide-align": {
+ "version": "1.1.3",
+ "bundled": true,
+ "requires": {
+ "string-width": "^1.0.2 || 2"
+ }
+ },
+ "wrappy": {
+ "version": "1.0.2",
+ "bundled": true
+ },
+ "yallist": {
+ "version": "3.0.3",
+ "bundled": true
+ }
+ }
+ },
+ "invert-kv": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz",
+ "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY="
+ },
+ "is-fullwidth-code-point": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
+ "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
+ "requires": {
+ "number-is-nan": "^1.0.0"
+ }
+ },
+ "lcid": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz",
+ "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=",
+ "requires": {
+ "invert-kv": "^1.0.0"
+ }
+ },
+ "lodash": {
+ "version": "4.17.15",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
+ "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A=="
+ },
+ "lodash.camelcase": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
+ "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY="
+ },
+ "lodash.clone": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/lodash.clone/-/lodash.clone-4.5.0.tgz",
+ "integrity": "sha1-GVhwRQ9aExkkeN9Lw9I9LeoZB7Y="
+ },
+ "long": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz",
+ "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA=="
+ },
+ "minimist": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+ "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
+ },
+ "nan": {
+ "version": "2.14.0",
+ "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz",
+ "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg=="
+ },
+ "npm": {
+ "version": "6.11.2",
+ "resolved": "https://registry.npmjs.org/npm/-/npm-6.11.2.tgz",
+ "integrity": "sha512-OAkXqI4bm5MUvqVvqe6rxCXmJqrln8VDlkdftpOoayHKazz8IOCJAiCuKmz0TchL224EAKeG86umuD6RYNpuEg==",
+ "requires": {
+ "JSONStream": "^1.3.5",
+ "abbrev": "~1.1.1",
+ "ansicolors": "~0.3.2",
+ "ansistyles": "~0.1.3",
+ "aproba": "^2.0.0",
+ "archy": "~1.0.0",
+ "bin-links": "^1.1.3",
+ "bluebird": "^3.5.5",
+ "byte-size": "^5.0.1",
+ "cacache": "^12.0.3",
+ "call-limit": "^1.1.1",
+ "chownr": "^1.1.2",
+ "ci-info": "^2.0.0",
+ "cli-columns": "^3.1.2",
+ "cli-table3": "^0.5.1",
+ "cmd-shim": "^3.0.3",
+ "columnify": "~1.5.4",
+ "config-chain": "^1.1.12",
+ "debuglog": "*",
+ "detect-indent": "~5.0.0",
+ "detect-newline": "^2.1.0",
+ "dezalgo": "~1.0.3",
+ "editor": "~1.0.0",
+ "figgy-pudding": "^3.5.1",
+ "find-npm-prefix": "^1.0.2",
+ "fs-vacuum": "~1.2.10",
+ "fs-write-stream-atomic": "~1.0.10",
+ "gentle-fs": "^2.2.1",
+ "glob": "^7.1.4",
+ "graceful-fs": "^4.2.2",
+ "has-unicode": "~2.0.1",
+ "hosted-git-info": "^2.8.2",
+ "iferr": "^1.0.2",
+ "imurmurhash": "*",
+ "infer-owner": "^1.0.4",
+ "inflight": "~1.0.6",
+ "inherits": "^2.0.4",
+ "ini": "^1.3.5",
+ "init-package-json": "^1.10.3",
+ "is-cidr": "^3.0.0",
+ "json-parse-better-errors": "^1.0.2",
+ "lazy-property": "~1.0.0",
+ "libcipm": "^4.0.3",
+ "libnpm": "^3.0.1",
+ "libnpmaccess": "^3.0.2",
+ "libnpmhook": "^5.0.3",
+ "libnpmorg": "^1.0.1",
+ "libnpmsearch": "^2.0.2",
+ "libnpmteam": "^1.0.2",
+ "libnpx": "^10.2.0",
+ "lock-verify": "^2.1.0",
+ "lockfile": "^1.0.4",
+ "lodash._baseindexof": "*",
+ "lodash._baseuniq": "~4.6.0",
+ "lodash._bindcallback": "*",
+ "lodash._cacheindexof": "*",
+ "lodash._createcache": "*",
+ "lodash._getnative": "*",
+ "lodash.clonedeep": "~4.5.0",
+ "lodash.restparam": "*",
+ "lodash.union": "~4.6.0",
+ "lodash.uniq": "~4.5.0",
+ "lodash.without": "~4.4.0",
+ "lru-cache": "^5.1.1",
+ "meant": "~1.0.1",
+ "mississippi": "^3.0.0",
+ "mkdirp": "~0.5.1",
+ "move-concurrently": "^1.0.1",
+ "node-gyp": "^5.0.3",
+ "nopt": "~4.0.1",
+ "normalize-package-data": "^2.5.0",
+ "npm-audit-report": "^1.3.2",
+ "npm-cache-filename": "~1.0.2",
+ "npm-install-checks": "~3.0.0",
+ "npm-lifecycle": "^3.1.3",
+ "npm-package-arg": "^6.1.1",
+ "npm-packlist": "^1.4.4",
+ "npm-pick-manifest": "^3.0.0",
+ "npm-profile": "^4.0.2",
+ "npm-registry-fetch": "^4.0.0",
+ "npm-user-validate": "~1.0.0",
+ "npmlog": "~4.1.2",
+ "once": "~1.4.0",
+ "opener": "^1.5.1",
+ "osenv": "^0.1.5",
+ "pacote": "^9.5.8",
+ "path-is-inside": "~1.0.2",
+ "promise-inflight": "~1.0.1",
+ "qrcode-terminal": "^0.12.0",
+ "query-string": "^6.8.2",
+ "qw": "~1.0.1",
+ "read": "~1.0.7",
+ "read-cmd-shim": "^1.0.3",
+ "read-installed": "~4.0.3",
+ "read-package-json": "^2.1.0",
+ "read-package-tree": "^5.3.1",
+ "readable-stream": "^3.4.0",
+ "readdir-scoped-modules": "^1.1.0",
+ "request": "^2.88.0",
+ "retry": "^0.12.0",
+ "rimraf": "^2.6.3",
+ "safe-buffer": "^5.1.2",
+ "semver": "^5.7.1",
+ "sha": "^3.0.0",
+ "slide": "~1.1.6",
+ "sorted-object": "~2.0.1",
+ "sorted-union-stream": "~2.1.3",
+ "ssri": "^6.0.1",
+ "stringify-package": "^1.0.0",
+ "tar": "^4.4.10",
+ "text-table": "~0.2.0",
+ "tiny-relative-date": "^1.3.0",
+ "uid-number": "0.0.6",
+ "umask": "~1.1.0",
+ "unique-filename": "^1.1.1",
+ "unpipe": "~1.0.0",
+ "update-notifier": "^2.5.0",
+ "uuid": "^3.3.2",
+ "validate-npm-package-license": "^3.0.4",
+ "validate-npm-package-name": "~3.0.0",
+ "which": "^1.3.1",
+ "worker-farm": "^1.7.0",
+ "write-file-atomic": "^2.4.3"
+ },
+ "dependencies": {
+ "JSONStream": {
+ "version": "1.3.5",
+ "bundled": true,
+ "requires": {
+ "jsonparse": "^1.2.0",
+ "through": ">=2.2.7 <3"
+ }
+ },
+ "abbrev": {
+ "version": "1.1.1",
+ "bundled": true
+ },
+ "agent-base": {
+ "version": "4.3.0",
+ "bundled": true,
+ "requires": {
+ "es6-promisify": "^5.0.0"
+ }
+ },
+ "agentkeepalive": {
+ "version": "3.5.2",
+ "bundled": true,
+ "requires": {
+ "humanize-ms": "^1.2.1"
+ }
+ },
+ "ajv": {
+ "version": "5.5.2",
+ "bundled": true,
+ "requires": {
+ "co": "^4.6.0",
+ "fast-deep-equal": "^1.0.0",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.3.0"
+ }
+ },
+ "ansi-align": {
+ "version": "2.0.0",
+ "bundled": true,
+ "requires": {
+ "string-width": "^2.0.0"
+ }
+ },
+ "ansi-regex": {
+ "version": "2.1.1",
+ "bundled": true
+ },
+ "ansi-styles": {
+ "version": "3.2.1",
+ "bundled": true,
+ "requires": {
+ "color-convert": "^1.9.0"
+ }
+ },
+ "ansicolors": {
+ "version": "0.3.2",
+ "bundled": true
+ },
+ "ansistyles": {
+ "version": "0.1.3",
+ "bundled": true
+ },
+ "aproba": {
+ "version": "2.0.0",
+ "bundled": true
+ },
+ "archy": {
+ "version": "1.0.0",
+ "bundled": true
+ },
+ "are-we-there-yet": {
+ "version": "1.1.4",
+ "bundled": true,
+ "requires": {
+ "delegates": "^1.0.0",
+ "readable-stream": "^2.0.6"
+ },
+ "dependencies": {
+ "readable-stream": {
+ "version": "2.3.6",
+ "bundled": true,
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "string_decoder": {
+ "version": "1.1.1",
+ "bundled": true,
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ }
+ }
+ }
+ },
+ "asap": {
+ "version": "2.0.6",
+ "bundled": true
+ },
+ "asn1": {
+ "version": "0.2.4",
+ "bundled": true,
+ "requires": {
+ "safer-buffer": "~2.1.0"
+ }
+ },
+ "assert-plus": {
+ "version": "1.0.0",
+ "bundled": true
+ },
+ "asynckit": {
+ "version": "0.4.0",
+ "bundled": true
+ },
+ "aws-sign2": {
+ "version": "0.7.0",
+ "bundled": true
+ },
+ "aws4": {
+ "version": "1.8.0",
+ "bundled": true
+ },
+ "balanced-match": {
+ "version": "1.0.0",
+ "bundled": true
+ },
+ "bcrypt-pbkdf": {
+ "version": "1.0.2",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "tweetnacl": "^0.14.3"
+ }
+ },
+ "bin-links": {
+ "version": "1.1.3",
+ "bundled": true,
+ "requires": {
+ "bluebird": "^3.5.3",
+ "cmd-shim": "^3.0.0",
+ "gentle-fs": "^2.0.1",
+ "graceful-fs": "^4.1.15",
+ "write-file-atomic": "^2.3.0"
+ }
+ },
+ "bluebird": {
+ "version": "3.5.5",
+ "bundled": true
+ },
+ "boxen": {
+ "version": "1.3.0",
+ "bundled": true,
+ "requires": {
+ "ansi-align": "^2.0.0",
+ "camelcase": "^4.0.0",
+ "chalk": "^2.0.1",
+ "cli-boxes": "^1.0.0",
+ "string-width": "^2.0.0",
+ "term-size": "^1.2.0",
+ "widest-line": "^2.0.0"
+ }
+ },
+ "brace-expansion": {
+ "version": "1.1.11",
+ "bundled": true,
+ "requires": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "buffer-from": {
+ "version": "1.0.0",
+ "bundled": true
+ },
+ "builtins": {
+ "version": "1.0.3",
+ "bundled": true
+ },
+ "byline": {
+ "version": "5.0.0",
+ "bundled": true
+ },
+ "byte-size": {
+ "version": "5.0.1",
+ "bundled": true
+ },
+ "cacache": {
+ "version": "12.0.3",
+ "bundled": true,
+ "requires": {
+ "bluebird": "^3.5.5",
+ "chownr": "^1.1.1",
+ "figgy-pudding": "^3.5.1",
+ "glob": "^7.1.4",
+ "graceful-fs": "^4.1.15",
+ "infer-owner": "^1.0.3",
+ "lru-cache": "^5.1.1",
+ "mississippi": "^3.0.0",
+ "mkdirp": "^0.5.1",
+ "move-concurrently": "^1.0.1",
+ "promise-inflight": "^1.0.1",
+ "rimraf": "^2.6.3",
+ "ssri": "^6.0.1",
+ "unique-filename": "^1.1.1",
+ "y18n": "^4.0.0"
+ }
+ },
+ "call-limit": {
+ "version": "1.1.1",
+ "bundled": true
+ },
+ "camelcase": {
+ "version": "4.1.0",
+ "bundled": true
+ },
+ "capture-stack-trace": {
+ "version": "1.0.0",
+ "bundled": true
+ },
+ "caseless": {
+ "version": "0.12.0",
+ "bundled": true
+ },
+ "chalk": {
+ "version": "2.4.1",
+ "bundled": true,
+ "requires": {
+ "ansi-styles": "^3.2.1",
+ "escape-string-regexp": "^1.0.5",
+ "supports-color": "^5.3.0"
+ }
+ },
+ "chownr": {
+ "version": "1.1.2",
+ "bundled": true
+ },
+ "ci-info": {
+ "version": "2.0.0",
+ "bundled": true
+ },
+ "cidr-regex": {
+ "version": "2.0.10",
+ "bundled": true,
+ "requires": {
+ "ip-regex": "^2.1.0"
+ }
+ },
+ "cli-boxes": {
+ "version": "1.0.0",
+ "bundled": true
+ },
+ "cli-columns": {
+ "version": "3.1.2",
+ "bundled": true,
+ "requires": {
+ "string-width": "^2.0.0",
+ "strip-ansi": "^3.0.1"
+ }
+ },
+ "cli-table3": {
+ "version": "0.5.1",
+ "bundled": true,
+ "requires": {
+ "colors": "^1.1.2",
+ "object-assign": "^4.1.0",
+ "string-width": "^2.1.1"
+ }
+ },
+ "cliui": {
+ "version": "4.1.0",
+ "bundled": true,
+ "requires": {
+ "string-width": "^2.1.1",
+ "strip-ansi": "^4.0.0",
+ "wrap-ansi": "^2.0.0"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "3.0.0",
+ "bundled": true
+ },
+ "strip-ansi": {
+ "version": "4.0.0",
+ "bundled": true,
+ "requires": {
+ "ansi-regex": "^3.0.0"
+ }
+ }
+ }
+ },
+ "clone": {
+ "version": "1.0.4",
+ "bundled": true
+ },
+ "cmd-shim": {
+ "version": "3.0.3",
+ "bundled": true,
+ "requires": {
+ "graceful-fs": "^4.1.2",
+ "mkdirp": "~0.5.0"
+ }
+ },
+ "co": {
+ "version": "4.6.0",
+ "bundled": true
+ },
+ "code-point-at": {
+ "version": "1.1.0",
+ "bundled": true
+ },
+ "color-convert": {
+ "version": "1.9.1",
+ "bundled": true,
+ "requires": {
+ "color-name": "^1.1.1"
+ }
+ },
+ "color-name": {
+ "version": "1.1.3",
+ "bundled": true
+ },
+ "colors": {
+ "version": "1.3.3",
+ "bundled": true,
+ "optional": true
+ },
+ "columnify": {
+ "version": "1.5.4",
+ "bundled": true,
+ "requires": {
+ "strip-ansi": "^3.0.0",
+ "wcwidth": "^1.0.0"
+ }
+ },
+ "combined-stream": {
+ "version": "1.0.6",
+ "bundled": true,
+ "requires": {
+ "delayed-stream": "~1.0.0"
+ }
+ },
+ "concat-map": {
+ "version": "0.0.1",
+ "bundled": true
+ },
+ "concat-stream": {
+ "version": "1.6.2",
+ "bundled": true,
+ "requires": {
+ "buffer-from": "^1.0.0",
+ "inherits": "^2.0.3",
+ "readable-stream": "^2.2.2",
+ "typedarray": "^0.0.6"
+ },
+ "dependencies": {
+ "readable-stream": {
+ "version": "2.3.6",
+ "bundled": true,
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "string_decoder": {
+ "version": "1.1.1",
+ "bundled": true,
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ }
+ }
+ }
+ },
+ "config-chain": {
+ "version": "1.1.12",
+ "bundled": true,
+ "requires": {
+ "ini": "^1.3.4",
+ "proto-list": "~1.2.1"
+ }
+ },
+ "configstore": {
+ "version": "3.1.2",
+ "bundled": true,
+ "requires": {
+ "dot-prop": "^4.1.0",
+ "graceful-fs": "^4.1.2",
+ "make-dir": "^1.0.0",
+ "unique-string": "^1.0.0",
+ "write-file-atomic": "^2.0.0",
+ "xdg-basedir": "^3.0.0"
+ }
+ },
+ "console-control-strings": {
+ "version": "1.1.0",
+ "bundled": true
+ },
+ "copy-concurrently": {
+ "version": "1.0.5",
+ "bundled": true,
+ "requires": {
+ "aproba": "^1.1.1",
+ "fs-write-stream-atomic": "^1.0.8",
+ "iferr": "^0.1.5",
+ "mkdirp": "^0.5.1",
+ "rimraf": "^2.5.4",
+ "run-queue": "^1.0.0"
+ },
+ "dependencies": {
+ "aproba": {
+ "version": "1.2.0",
+ "bundled": true
+ },
+ "iferr": {
+ "version": "0.1.5",
+ "bundled": true
+ }
+ }
+ },
+ "core-util-is": {
+ "version": "1.0.2",
+ "bundled": true
+ },
+ "create-error-class": {
+ "version": "3.0.2",
+ "bundled": true,
+ "requires": {
+ "capture-stack-trace": "^1.0.0"
+ }
+ },
+ "cross-spawn": {
+ "version": "5.1.0",
+ "bundled": true,
+ "requires": {
+ "lru-cache": "^4.0.1",
+ "shebang-command": "^1.2.0",
+ "which": "^1.2.9"
+ },
+ "dependencies": {
+ "lru-cache": {
+ "version": "4.1.5",
+ "bundled": true,
+ "requires": {
+ "pseudomap": "^1.0.2",
+ "yallist": "^2.1.2"
+ }
+ },
+ "yallist": {
+ "version": "2.1.2",
+ "bundled": true
+ }
+ }
+ },
+ "crypto-random-string": {
+ "version": "1.0.0",
+ "bundled": true
+ },
+ "cyclist": {
+ "version": "0.2.2",
+ "bundled": true
+ },
+ "dashdash": {
+ "version": "1.14.1",
+ "bundled": true,
+ "requires": {
+ "assert-plus": "^1.0.0"
+ }
+ },
+ "debug": {
+ "version": "3.1.0",
+ "bundled": true,
+ "requires": {
+ "ms": "2.0.0"
+ },
+ "dependencies": {
+ "ms": {
+ "version": "2.0.0",
+ "bundled": true
+ }
+ }
+ },
+ "debuglog": {
+ "version": "1.0.1",
+ "bundled": true
+ },
+ "decamelize": {
+ "version": "1.2.0",
+ "bundled": true
+ },
+ "decode-uri-component": {
+ "version": "0.2.0",
+ "bundled": true
+ },
+ "deep-extend": {
+ "version": "0.5.1",
+ "bundled": true
+ },
+ "defaults": {
+ "version": "1.0.3",
+ "bundled": true,
+ "requires": {
+ "clone": "^1.0.2"
+ }
+ },
+ "define-properties": {
+ "version": "1.1.3",
+ "bundled": true,
+ "requires": {
+ "object-keys": "^1.0.12"
+ }
+ },
+ "delayed-stream": {
+ "version": "1.0.0",
+ "bundled": true
+ },
+ "delegates": {
+ "version": "1.0.0",
+ "bundled": true
+ },
+ "detect-indent": {
+ "version": "5.0.0",
+ "bundled": true
+ },
+ "detect-newline": {
+ "version": "2.1.0",
+ "bundled": true
+ },
+ "dezalgo": {
+ "version": "1.0.3",
+ "bundled": true,
+ "requires": {
+ "asap": "^2.0.0",
+ "wrappy": "1"
+ }
+ },
+ "dot-prop": {
+ "version": "4.2.0",
+ "bundled": true,
+ "requires": {
+ "is-obj": "^1.0.0"
+ }
+ },
+ "dotenv": {
+ "version": "5.0.1",
+ "bundled": true
+ },
+ "duplexer3": {
+ "version": "0.1.4",
+ "bundled": true
+ },
+ "duplexify": {
+ "version": "3.6.0",
+ "bundled": true,
+ "requires": {
+ "end-of-stream": "^1.0.0",
+ "inherits": "^2.0.1",
+ "readable-stream": "^2.0.0",
+ "stream-shift": "^1.0.0"
+ },
+ "dependencies": {
+ "readable-stream": {
+ "version": "2.3.6",
+ "bundled": true,
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "string_decoder": {
+ "version": "1.1.1",
+ "bundled": true,
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ }
+ }
+ }
+ },
+ "ecc-jsbn": {
+ "version": "0.1.2",
+ "bundled": true,
+ "optional": true,
+ "requires": {
+ "jsbn": "~0.1.0",
+ "safer-buffer": "^2.1.0"
+ }
+ },
+ "editor": {
+ "version": "1.0.0",
+ "bundled": true
+ },
+ "encoding": {
+ "version": "0.1.12",
+ "bundled": true,
+ "requires": {
+ "iconv-lite": "~0.4.13"
+ }
+ },
+ "end-of-stream": {
+ "version": "1.4.1",
+ "bundled": true,
+ "requires": {
+ "once": "^1.4.0"
+ }
+ },
+ "env-paths": {
+ "version": "1.0.0",
+ "bundled": true
+ },
+ "err-code": {
+ "version": "1.1.2",
+ "bundled": true
+ },
+ "errno": {
+ "version": "0.1.7",
+ "bundled": true,
+ "requires": {
+ "prr": "~1.0.1"
+ }
+ },
+ "es-abstract": {
+ "version": "1.12.0",
+ "bundled": true,
+ "requires": {
+ "es-to-primitive": "^1.1.1",
+ "function-bind": "^1.1.1",
+ "has": "^1.0.1",
+ "is-callable": "^1.1.3",
+ "is-regex": "^1.0.4"
+ }
+ },
+ "es-to-primitive": {
+ "version": "1.2.0",
+ "bundled": true,
+ "requires": {
+ "is-callable": "^1.1.4",
+ "is-date-object": "^1.0.1",
+ "is-symbol": "^1.0.2"
+ }
+ },
+ "es6-promise": {
+ "version": "4.2.8",
+ "bundled": true
+ },
+ "es6-promisify": {
+ "version": "5.0.0",
+ "bundled": true,
+ "requires": {
+ "es6-promise": "^4.0.3"
+ }
+ },
+ "escape-string-regexp": {
+ "version": "1.0.5",
+ "bundled": true
+ },
+ "execa": {
+ "version": "0.7.0",
+ "bundled": true,
+ "requires": {
+ "cross-spawn": "^5.0.1",
+ "get-stream": "^3.0.0",
+ "is-stream": "^1.1.0",
+ "npm-run-path": "^2.0.0",
+ "p-finally": "^1.0.0",
+ "signal-exit": "^3.0.0",
+ "strip-eof": "^1.0.0"
+ },
+ "dependencies": {
+ "get-stream": {
+ "version": "3.0.0",
+ "bundled": true
+ }
+ }
+ },
+ "extend": {
+ "version": "3.0.2",
+ "bundled": true
+ },
+ "extsprintf": {
+ "version": "1.3.0",
+ "bundled": true
+ },
+ "fast-deep-equal": {
+ "version": "1.1.0",
+ "bundled": true
+ },
+ "fast-json-stable-stringify": {
+ "version": "2.0.0",
+ "bundled": true
+ },
+ "figgy-pudding": {
+ "version": "3.5.1",
+ "bundled": true
+ },
+ "find-npm-prefix": {
+ "version": "1.0.2",
+ "bundled": true
+ },
+ "find-up": {
+ "version": "2.1.0",
+ "bundled": true,
+ "requires": {
+ "locate-path": "^2.0.0"
+ }
+ },
+ "flush-write-stream": {
+ "version": "1.0.3",
+ "bundled": true,
+ "requires": {
+ "inherits": "^2.0.1",
+ "readable-stream": "^2.0.4"
+ },
+ "dependencies": {
+ "readable-stream": {
+ "version": "2.3.6",
+ "bundled": true,
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "string_decoder": {
+ "version": "1.1.1",
+ "bundled": true,
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ }
+ }
+ }
+ },
+ "forever-agent": {
+ "version": "0.6.1",
+ "bundled": true
+ },
+ "form-data": {
+ "version": "2.3.2",
+ "bundled": true,
+ "requires": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "1.0.6",
+ "mime-types": "^2.1.12"
+ }
+ },
+ "from2": {
+ "version": "2.3.0",
+ "bundled": true,
+ "requires": {
+ "inherits": "^2.0.1",
+ "readable-stream": "^2.0.0"
+ },
+ "dependencies": {
+ "readable-stream": {
+ "version": "2.3.6",
+ "bundled": true,
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "string_decoder": {
+ "version": "1.1.1",
+ "bundled": true,
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ }
+ }
+ }
+ },
+ "fs-minipass": {
+ "version": "1.2.6",
+ "bundled": true,
+ "requires": {
+ "minipass": "^2.2.1"
+ }
+ },
+ "fs-vacuum": {
+ "version": "1.2.10",
+ "bundled": true,
+ "requires": {
+ "graceful-fs": "^4.1.2",
+ "path-is-inside": "^1.0.1",
+ "rimraf": "^2.5.2"
+ }
+ },
+ "fs-write-stream-atomic": {
+ "version": "1.0.10",
+ "bundled": true,
+ "requires": {
+ "graceful-fs": "^4.1.2",
+ "iferr": "^0.1.5",
+ "imurmurhash": "^0.1.4",
+ "readable-stream": "1 || 2"
+ },
+ "dependencies": {
+ "iferr": {
+ "version": "0.1.5",
+ "bundled": true
+ },
+ "readable-stream": {
+ "version": "2.3.6",
+ "bundled": true,
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "string_decoder": {
+ "version": "1.1.1",
+ "bundled": true,
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ }
+ }
+ }
+ },
+ "fs.realpath": {
+ "version": "1.0.0",
+ "bundled": true
+ },
+ "function-bind": {
+ "version": "1.1.1",
+ "bundled": true
+ },
+ "gauge": {
+ "version": "2.7.4",
+ "bundled": true,
+ "requires": {
+ "aproba": "^1.0.3",
+ "console-control-strings": "^1.0.0",
+ "has-unicode": "^2.0.0",
+ "object-assign": "^4.1.0",
+ "signal-exit": "^3.0.0",
+ "string-width": "^1.0.1",
+ "strip-ansi": "^3.0.1",
+ "wide-align": "^1.1.0"
+ },
+ "dependencies": {
+ "aproba": {
+ "version": "1.2.0",
+ "bundled": true
+ },
+ "string-width": {
+ "version": "1.0.2",
+ "bundled": true,
+ "requires": {
+ "code-point-at": "^1.0.0",
+ "is-fullwidth-code-point": "^1.0.0",
+ "strip-ansi": "^3.0.0"
+ }
+ }
+ }
+ },
+ "genfun": {
+ "version": "5.0.0",
+ "bundled": true
+ },
+ "gentle-fs": {
+ "version": "2.2.1",
+ "bundled": true,
+ "requires": {
+ "aproba": "^1.1.2",
+ "chownr": "^1.1.2",
+ "fs-vacuum": "^1.2.10",
+ "graceful-fs": "^4.1.11",
+ "iferr": "^0.1.5",
+ "infer-owner": "^1.0.4",
+ "mkdirp": "^0.5.1",
+ "path-is-inside": "^1.0.2",
+ "read-cmd-shim": "^1.0.1",
+ "slide": "^1.1.6"
+ },
+ "dependencies": {
+ "aproba": {
+ "version": "1.2.0",
+ "bundled": true
+ },
+ "iferr": {
+ "version": "0.1.5",
+ "bundled": true
+ }
+ }
+ },
+ "get-caller-file": {
+ "version": "1.0.2",
+ "bundled": true
+ },
+ "get-stream": {
+ "version": "4.1.0",
+ "bundled": true,
+ "requires": {
+ "pump": "^3.0.0"
+ }
+ },
+ "getpass": {
+ "version": "0.1.7",
+ "bundled": true,
+ "requires": {
+ "assert-plus": "^1.0.0"
+ }
+ },
+ "glob": {
+ "version": "7.1.4",
+ "bundled": true,
+ "requires": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.0.4",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ },
+ "global-dirs": {
+ "version": "0.1.1",
+ "bundled": true,
+ "requires": {
+ "ini": "^1.3.4"
+ }
+ },
+ "got": {
+ "version": "6.7.1",
+ "bundled": true,
+ "requires": {
+ "create-error-class": "^3.0.0",
+ "duplexer3": "^0.1.4",
+ "get-stream": "^3.0.0",
+ "is-redirect": "^1.0.0",
+ "is-retry-allowed": "^1.0.0",
+ "is-stream": "^1.0.0",
+ "lowercase-keys": "^1.0.0",
+ "safe-buffer": "^5.0.1",
+ "timed-out": "^4.0.0",
+ "unzip-response": "^2.0.1",
+ "url-parse-lax": "^1.0.0"
+ },
+ "dependencies": {
+ "get-stream": {
+ "version": "3.0.0",
+ "bundled": true
+ }
+ }
+ },
+ "graceful-fs": {
+ "version": "4.2.2",
+ "bundled": true
+ },
+ "har-schema": {
+ "version": "2.0.0",
+ "bundled": true
+ },
+ "har-validator": {
+ "version": "5.1.0",
+ "bundled": true,
+ "requires": {
+ "ajv": "^5.3.0",
+ "har-schema": "^2.0.0"
+ }
+ },
+ "has": {
+ "version": "1.0.3",
+ "bundled": true,
+ "requires": {
+ "function-bind": "^1.1.1"
+ }
+ },
+ "has-flag": {
+ "version": "3.0.0",
+ "bundled": true
+ },
+ "has-symbols": {
+ "version": "1.0.0",
+ "bundled": true
+ },
+ "has-unicode": {
+ "version": "2.0.1",
+ "bundled": true
+ },
+ "hosted-git-info": {
+ "version": "2.8.2",
+ "bundled": true,
+ "requires": {
+ "lru-cache": "^5.1.1"
+ }
+ },
+ "http-cache-semantics": {
+ "version": "3.8.1",
+ "bundled": true
+ },
+ "http-proxy-agent": {
+ "version": "2.1.0",
+ "bundled": true,
+ "requires": {
+ "agent-base": "4",
+ "debug": "3.1.0"
+ }
+ },
+ "http-signature": {
+ "version": "1.2.0",
+ "bundled": true,
+ "requires": {
+ "assert-plus": "^1.0.0",
+ "jsprim": "^1.2.2",
+ "sshpk": "^1.7.0"
+ }
+ },
+ "https-proxy-agent": {
+ "version": "2.2.2",
+ "bundled": true,
+ "requires": {
+ "agent-base": "^4.3.0",
+ "debug": "^3.1.0"
+ }
+ },
+ "humanize-ms": {
+ "version": "1.2.1",
+ "bundled": true,
+ "requires": {
+ "ms": "^2.0.0"
+ }
+ },
+ "iconv-lite": {
+ "version": "0.4.23",
+ "bundled": true,
+ "requires": {
+ "safer-buffer": ">= 2.1.2 < 3"
+ }
+ },
+ "iferr": {
+ "version": "1.0.2",
+ "bundled": true
+ },
+ "ignore-walk": {
+ "version": "3.0.1",
+ "bundled": true,
+ "requires": {
+ "minimatch": "^3.0.4"
+ }
+ },
+ "import-lazy": {
+ "version": "2.1.0",
+ "bundled": true
+ },
+ "imurmurhash": {
+ "version": "0.1.4",
+ "bundled": true
+ },
+ "infer-owner": {
+ "version": "1.0.4",
+ "bundled": true
+ },
+ "inflight": {
+ "version": "1.0.6",
+ "bundled": true,
+ "requires": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "inherits": {
+ "version": "2.0.4",
+ "bundled": true
+ },
+ "ini": {
+ "version": "1.3.5",
+ "bundled": true
+ },
+ "init-package-json": {
+ "version": "1.10.3",
+ "bundled": true,
+ "requires": {
+ "glob": "^7.1.1",
+ "npm-package-arg": "^4.0.0 || ^5.0.0 || ^6.0.0",
+ "promzard": "^0.3.0",
+ "read": "~1.0.1",
+ "read-package-json": "1 || 2",
+ "semver": "2.x || 3.x || 4 || 5",
+ "validate-npm-package-license": "^3.0.1",
+ "validate-npm-package-name": "^3.0.0"
+ }
+ },
+ "invert-kv": {
+ "version": "1.0.0",
+ "bundled": true
+ },
+ "ip": {
+ "version": "1.1.5",
+ "bundled": true
+ },
+ "ip-regex": {
+ "version": "2.1.0",
+ "bundled": true
+ },
+ "is-callable": {
+ "version": "1.1.4",
+ "bundled": true
+ },
+ "is-ci": {
+ "version": "1.1.0",
+ "bundled": true,
+ "requires": {
+ "ci-info": "^1.0.0"
+ },
+ "dependencies": {
+ "ci-info": {
+ "version": "1.6.0",
+ "bundled": true
+ }
+ }
+ },
+ "is-cidr": {
+ "version": "3.0.0",
+ "bundled": true,
+ "requires": {
+ "cidr-regex": "^2.0.10"
+ }
+ },
+ "is-date-object": {
+ "version": "1.0.1",
+ "bundled": true
+ },
+ "is-fullwidth-code-point": {
+ "version": "1.0.0",
+ "bundled": true,
+ "requires": {
+ "number-is-nan": "^1.0.0"
+ }
+ },
+ "is-installed-globally": {
+ "version": "0.1.0",
+ "bundled": true,
+ "requires": {
+ "global-dirs": "^0.1.0",
+ "is-path-inside": "^1.0.0"
+ }
+ },
+ "is-npm": {
+ "version": "1.0.0",
+ "bundled": true
+ },
+ "is-obj": {
+ "version": "1.0.1",
+ "bundled": true
+ },
+ "is-path-inside": {
+ "version": "1.0.1",
+ "bundled": true,
+ "requires": {
+ "path-is-inside": "^1.0.1"
+ }
+ },
+ "is-redirect": {
+ "version": "1.0.0",
+ "bundled": true
+ },
+ "is-regex": {
+ "version": "1.0.4",
+ "bundled": true,
+ "requires": {
+ "has": "^1.0.1"
+ }
+ },
+ "is-retry-allowed": {
+ "version": "1.1.0",
+ "bundled": true
+ },
+ "is-stream": {
+ "version": "1.1.0",
+ "bundled": true
+ },
+ "is-symbol": {
+ "version": "1.0.2",
+ "bundled": true,
+ "requires": {
+ "has-symbols": "^1.0.0"
+ }
+ },
+ "is-typedarray": {
+ "version": "1.0.0",
+ "bundled": true
+ },
+ "isarray": {
+ "version": "1.0.0",
+ "bundled": true
+ },
+ "isexe": {
+ "version": "2.0.0",
+ "bundled": true
+ },
+ "isstream": {
+ "version": "0.1.2",
+ "bundled": true
+ },
+ "jsbn": {
+ "version": "0.1.1",
+ "bundled": true,
+ "optional": true
+ },
+ "json-parse-better-errors": {
+ "version": "1.0.2",
+ "bundled": true
+ },
+ "json-schema": {
+ "version": "0.2.3",
+ "bundled": true
+ },
+ "json-schema-traverse": {
+ "version": "0.3.1",
+ "bundled": true
+ },
+ "json-stringify-safe": {
+ "version": "5.0.1",
+ "bundled": true
+ },
+ "jsonparse": {
+ "version": "1.3.1",
+ "bundled": true
+ },
+ "jsprim": {
+ "version": "1.4.1",
+ "bundled": true,
+ "requires": {
+ "assert-plus": "1.0.0",
+ "extsprintf": "1.3.0",
+ "json-schema": "0.2.3",
+ "verror": "1.10.0"
+ }
+ },
+ "latest-version": {
+ "version": "3.1.0",
+ "bundled": true,
+ "requires": {
+ "package-json": "^4.0.0"
+ }
+ },
+ "lazy-property": {
+ "version": "1.0.0",
+ "bundled": true
+ },
+ "lcid": {
+ "version": "1.0.0",
+ "bundled": true,
+ "requires": {
+ "invert-kv": "^1.0.0"
+ }
+ },
+ "libcipm": {
+ "version": "4.0.3",
+ "bundled": true,
+ "requires": {
+ "bin-links": "^1.1.2",
+ "bluebird": "^3.5.1",
+ "figgy-pudding": "^3.5.1",
+ "find-npm-prefix": "^1.0.2",
+ "graceful-fs": "^4.1.11",
+ "ini": "^1.3.5",
+ "lock-verify": "^2.0.2",
+ "mkdirp": "^0.5.1",
+ "npm-lifecycle": "^3.0.0",
+ "npm-logical-tree": "^1.2.1",
+ "npm-package-arg": "^6.1.0",
+ "pacote": "^9.1.0",
+ "read-package-json": "^2.0.13",
+ "rimraf": "^2.6.2",
+ "worker-farm": "^1.6.0"
+ }
+ },
+ "libnpm": {
+ "version": "3.0.1",
+ "bundled": true,
+ "requires": {
+ "bin-links": "^1.1.2",
+ "bluebird": "^3.5.3",
+ "find-npm-prefix": "^1.0.2",
+ "libnpmaccess": "^3.0.2",
+ "libnpmconfig": "^1.2.1",
+ "libnpmhook": "^5.0.3",
+ "libnpmorg": "^1.0.1",
+ "libnpmpublish": "^1.1.2",
+ "libnpmsearch": "^2.0.2",
+ "libnpmteam": "^1.0.2",
+ "lock-verify": "^2.0.2",
+ "npm-lifecycle": "^3.0.0",
+ "npm-logical-tree": "^1.2.1",
+ "npm-package-arg": "^6.1.0",
+ "npm-profile": "^4.0.2",
+ "npm-registry-fetch": "^4.0.0",
+ "npmlog": "^4.1.2",
+ "pacote": "^9.5.3",
+ "read-package-json": "^2.0.13",
+ "stringify-package": "^1.0.0"
+ }
+ },
+ "libnpmaccess": {
+ "version": "3.0.2",
+ "bundled": true,
+ "requires": {
+ "aproba": "^2.0.0",
+ "get-stream": "^4.0.0",
+ "npm-package-arg": "^6.1.0",
+ "npm-registry-fetch": "^4.0.0"
+ }
+ },
+ "libnpmconfig": {
+ "version": "1.2.1",
+ "bundled": true,
+ "requires": {
+ "figgy-pudding": "^3.5.1",
+ "find-up": "^3.0.0",
+ "ini": "^1.3.5"
+ },
+ "dependencies": {
+ "find-up": {
+ "version": "3.0.0",
+ "bundled": true,
+ "requires": {
+ "locate-path": "^3.0.0"
+ }
+ },
+ "locate-path": {
+ "version": "3.0.0",
+ "bundled": true,
+ "requires": {
+ "p-locate": "^3.0.0",
+ "path-exists": "^3.0.0"
+ }
+ },
+ "p-limit": {
+ "version": "2.2.0",
+ "bundled": true,
+ "requires": {
+ "p-try": "^2.0.0"
+ }
+ },
+ "p-locate": {
+ "version": "3.0.0",
+ "bundled": true,
+ "requires": {
+ "p-limit": "^2.0.0"
+ }
+ },
+ "p-try": {
+ "version": "2.2.0",
+ "bundled": true
+ }
+ }
+ },
+ "libnpmhook": {
+ "version": "5.0.3",
+ "bundled": true,
+ "requires": {
+ "aproba": "^2.0.0",
+ "figgy-pudding": "^3.4.1",
+ "get-stream": "^4.0.0",
+ "npm-registry-fetch": "^4.0.0"
+ }
+ },
+ "libnpmorg": {
+ "version": "1.0.1",
+ "bundled": true,
+ "requires": {
+ "aproba": "^2.0.0",
+ "figgy-pudding": "^3.4.1",
+ "get-stream": "^4.0.0",
+ "npm-registry-fetch": "^4.0.0"
+ }
+ },
+ "libnpmpublish": {
+ "version": "1.1.2",
+ "bundled": true,
+ "requires": {
+ "aproba": "^2.0.0",
+ "figgy-pudding": "^3.5.1",
+ "get-stream": "^4.0.0",
+ "lodash.clonedeep": "^4.5.0",
+ "normalize-package-data": "^2.4.0",
+ "npm-package-arg": "^6.1.0",
+ "npm-registry-fetch": "^4.0.0",
+ "semver": "^5.5.1",
+ "ssri": "^6.0.1"
+ }
+ },
+ "libnpmsearch": {
+ "version": "2.0.2",
+ "bundled": true,
+ "requires": {
+ "figgy-pudding": "^3.5.1",
+ "get-stream": "^4.0.0",
+ "npm-registry-fetch": "^4.0.0"
+ }
+ },
+ "libnpmteam": {
+ "version": "1.0.2",
+ "bundled": true,
+ "requires": {
+ "aproba": "^2.0.0",
+ "figgy-pudding": "^3.4.1",
+ "get-stream": "^4.0.0",
+ "npm-registry-fetch": "^4.0.0"
+ }
+ },
+ "libnpx": {
+ "version": "10.2.0",
+ "bundled": true,
+ "requires": {
+ "dotenv": "^5.0.1",
+ "npm-package-arg": "^6.0.0",
+ "rimraf": "^2.6.2",
+ "safe-buffer": "^5.1.0",
+ "update-notifier": "^2.3.0",
+ "which": "^1.3.0",
+ "y18n": "^4.0.0",
+ "yargs": "^11.0.0"
+ }
+ },
+ "locate-path": {
+ "version": "2.0.0",
+ "bundled": true,
+ "requires": {
+ "p-locate": "^2.0.0",
+ "path-exists": "^3.0.0"
+ }
+ },
+ "lock-verify": {
+ "version": "2.1.0",
+ "bundled": true,
+ "requires": {
+ "npm-package-arg": "^6.1.0",
+ "semver": "^5.4.1"
+ }
+ },
+ "lockfile": {
+ "version": "1.0.4",
+ "bundled": true,
+ "requires": {
+ "signal-exit": "^3.0.2"
+ }
+ },
+ "lodash._baseindexof": {
+ "version": "3.1.0",
+ "bundled": true
+ },
+ "lodash._baseuniq": {
+ "version": "4.6.0",
+ "bundled": true,
+ "requires": {
+ "lodash._createset": "~4.0.0",
+ "lodash._root": "~3.0.0"
+ }
+ },
+ "lodash._bindcallback": {
+ "version": "3.0.1",
+ "bundled": true
+ },
+ "lodash._cacheindexof": {
+ "version": "3.0.2",
+ "bundled": true
+ },
+ "lodash._createcache": {
+ "version": "3.1.2",
+ "bundled": true,
+ "requires": {
+ "lodash._getnative": "^3.0.0"
+ }
+ },
+ "lodash._createset": {
+ "version": "4.0.3",
+ "bundled": true
+ },
+ "lodash._getnative": {
+ "version": "3.9.1",
+ "bundled": true
+ },
+ "lodash._root": {
+ "version": "3.0.1",
+ "bundled": true
+ },
+ "lodash.clonedeep": {
+ "version": "4.5.0",
+ "bundled": true
+ },
+ "lodash.restparam": {
+ "version": "3.6.1",
+ "bundled": true
+ },
+ "lodash.union": {
+ "version": "4.6.0",
+ "bundled": true
+ },
+ "lodash.uniq": {
+ "version": "4.5.0",
+ "bundled": true
+ },
+ "lodash.without": {
+ "version": "4.4.0",
+ "bundled": true
+ },
+ "lowercase-keys": {
+ "version": "1.0.1",
+ "bundled": true
+ },
+ "lru-cache": {
+ "version": "5.1.1",
+ "bundled": true,
+ "requires": {
+ "yallist": "^3.0.2"
+ }
+ },
+ "make-dir": {
+ "version": "1.3.0",
+ "bundled": true,
+ "requires": {
+ "pify": "^3.0.0"
+ }
+ },
+ "make-fetch-happen": {
+ "version": "5.0.0",
+ "bundled": true,
+ "requires": {
+ "agentkeepalive": "^3.4.1",
+ "cacache": "^12.0.0",
+ "http-cache-semantics": "^3.8.1",
+ "http-proxy-agent": "^2.1.0",
+ "https-proxy-agent": "^2.2.1",
+ "lru-cache": "^5.1.1",
+ "mississippi": "^3.0.0",
+ "node-fetch-npm": "^2.0.2",
+ "promise-retry": "^1.1.1",
+ "socks-proxy-agent": "^4.0.0",
+ "ssri": "^6.0.0"
+ }
+ },
+ "meant": {
+ "version": "1.0.1",
+ "bundled": true
+ },
+ "mem": {
+ "version": "1.1.0",
+ "bundled": true,
+ "requires": {
+ "mimic-fn": "^1.0.0"
+ }
+ },
+ "mime-db": {
+ "version": "1.35.0",
+ "bundled": true
+ },
+ "mime-types": {
+ "version": "2.1.19",
+ "bundled": true,
+ "requires": {
+ "mime-db": "~1.35.0"
+ }
+ },
+ "mimic-fn": {
+ "version": "1.2.0",
+ "bundled": true
+ },
+ "minimatch": {
+ "version": "3.0.4",
+ "bundled": true,
+ "requires": {
+ "brace-expansion": "^1.1.7"
+ }
+ },
+ "minimist": {
+ "version": "0.0.8",
+ "bundled": true
+ },
+ "minipass": {
+ "version": "2.3.3",
+ "bundled": true,
+ "requires": {
+ "safe-buffer": "^5.1.2",
+ "yallist": "^3.0.0"
+ },
+ "dependencies": {
+ "yallist": {
+ "version": "3.0.2",
+ "bundled": true
+ }
+ }
+ },
+ "minizlib": {
+ "version": "1.2.1",
+ "bundled": true,
+ "requires": {
+ "minipass": "^2.2.1"
+ }
+ },
+ "mississippi": {
+ "version": "3.0.0",
+ "bundled": true,
+ "requires": {
+ "concat-stream": "^1.5.0",
+ "duplexify": "^3.4.2",
+ "end-of-stream": "^1.1.0",
+ "flush-write-stream": "^1.0.0",
+ "from2": "^2.1.0",
+ "parallel-transform": "^1.1.0",
+ "pump": "^3.0.0",
+ "pumpify": "^1.3.3",
+ "stream-each": "^1.1.0",
+ "through2": "^2.0.0"
+ }
+ },
+ "mkdirp": {
+ "version": "0.5.1",
+ "bundled": true,
+ "requires": {
+ "minimist": "0.0.8"
+ }
+ },
+ "move-concurrently": {
+ "version": "1.0.1",
+ "bundled": true,
+ "requires": {
+ "aproba": "^1.1.1",
+ "copy-concurrently": "^1.0.0",
+ "fs-write-stream-atomic": "^1.0.8",
+ "mkdirp": "^0.5.1",
+ "rimraf": "^2.5.4",
+ "run-queue": "^1.0.3"
+ },
+ "dependencies": {
+ "aproba": {
+ "version": "1.2.0",
+ "bundled": true
+ }
+ }
+ },
+ "ms": {
+ "version": "2.1.1",
+ "bundled": true
+ },
+ "mute-stream": {
+ "version": "0.0.7",
+ "bundled": true
+ },
+ "node-fetch-npm": {
+ "version": "2.0.2",
+ "bundled": true,
+ "requires": {
+ "encoding": "^0.1.11",
+ "json-parse-better-errors": "^1.0.0",
+ "safe-buffer": "^5.1.1"
+ }
+ },
+ "node-gyp": {
+ "version": "5.0.3",
+ "bundled": true,
+ "requires": {
+ "env-paths": "^1.0.0",
+ "glob": "^7.0.3",
+ "graceful-fs": "^4.1.2",
+ "mkdirp": "^0.5.0",
+ "nopt": "2 || 3",
+ "npmlog": "0 || 1 || 2 || 3 || 4",
+ "request": "^2.87.0",
+ "rimraf": "2",
+ "semver": "~5.3.0",
+ "tar": "^4.4.8",
+ "which": "1"
+ },
+ "dependencies": {
+ "nopt": {
+ "version": "3.0.6",
+ "bundled": true,
+ "requires": {
+ "abbrev": "1"
+ }
+ },
+ "semver": {
+ "version": "5.3.0",
+ "bundled": true
+ }
+ }
+ },
+ "nopt": {
+ "version": "4.0.1",
+ "bundled": true,
+ "requires": {
+ "abbrev": "1",
+ "osenv": "^0.1.4"
+ }
+ },
+ "normalize-package-data": {
+ "version": "2.5.0",
+ "bundled": true,
+ "requires": {
+ "hosted-git-info": "^2.1.4",
+ "resolve": "^1.10.0",
+ "semver": "2 || 3 || 4 || 5",
+ "validate-npm-package-license": "^3.0.1"
+ },
+ "dependencies": {
+ "resolve": {
+ "version": "1.10.0",
+ "bundled": true,
+ "requires": {
+ "path-parse": "^1.0.6"
+ }
+ }
+ }
+ },
+ "npm-audit-report": {
+ "version": "1.3.2",
+ "bundled": true,
+ "requires": {
+ "cli-table3": "^0.5.0",
+ "console-control-strings": "^1.1.0"
+ }
+ },
+ "npm-bundled": {
+ "version": "1.0.6",
+ "bundled": true
+ },
+ "npm-cache-filename": {
+ "version": "1.0.2",
+ "bundled": true
+ },
+ "npm-install-checks": {
+ "version": "3.0.0",
+ "bundled": true,
+ "requires": {
+ "semver": "^2.3.0 || 3.x || 4 || 5"
+ }
+ },
+ "npm-lifecycle": {
+ "version": "3.1.3",
+ "bundled": true,
+ "requires": {
+ "byline": "^5.0.0",
+ "graceful-fs": "^4.1.15",
+ "node-gyp": "^5.0.2",
+ "resolve-from": "^4.0.0",
+ "slide": "^1.1.6",
+ "uid-number": "0.0.6",
+ "umask": "^1.1.0",
+ "which": "^1.3.1"
+ }
+ },
+ "npm-logical-tree": {
+ "version": "1.2.1",
+ "bundled": true
+ },
+ "npm-package-arg": {
+ "version": "6.1.1",
+ "bundled": true,
+ "requires": {
+ "hosted-git-info": "^2.7.1",
+ "osenv": "^0.1.5",
+ "semver": "^5.6.0",
+ "validate-npm-package-name": "^3.0.0"
+ }
+ },
+ "npm-packlist": {
+ "version": "1.4.4",
+ "bundled": true,
+ "requires": {
+ "ignore-walk": "^3.0.1",
+ "npm-bundled": "^1.0.1"
+ }
+ },
+ "npm-pick-manifest": {
+ "version": "3.0.0",
+ "bundled": true,
+ "requires": {
+ "figgy-pudding": "^3.5.1",
+ "npm-package-arg": "^6.0.0",
+ "semver": "^5.4.1"
+ }
+ },
+ "npm-profile": {
+ "version": "4.0.2",
+ "bundled": true,
+ "requires": {
+ "aproba": "^1.1.2 || 2",
+ "figgy-pudding": "^3.4.1",
+ "npm-registry-fetch": "^4.0.0"
+ }
+ },
+ "npm-registry-fetch": {
+ "version": "4.0.0",
+ "bundled": true,
+ "requires": {
+ "JSONStream": "^1.3.4",
+ "bluebird": "^3.5.1",
+ "figgy-pudding": "^3.4.1",
+ "lru-cache": "^5.1.1",
+ "make-fetch-happen": "^5.0.0",
+ "npm-package-arg": "^6.1.0"
+ }
+ },
+ "npm-run-path": {
+ "version": "2.0.2",
+ "bundled": true,
+ "requires": {
+ "path-key": "^2.0.0"
+ }
+ },
+ "npm-user-validate": {
+ "version": "1.0.0",
+ "bundled": true
+ },
+ "npmlog": {
+ "version": "4.1.2",
+ "bundled": true,
+ "requires": {
+ "are-we-there-yet": "~1.1.2",
+ "console-control-strings": "~1.1.0",
+ "gauge": "~2.7.3",
+ "set-blocking": "~2.0.0"
+ }
+ },
+ "number-is-nan": {
+ "version": "1.0.1",
+ "bundled": true
+ },
+ "oauth-sign": {
+ "version": "0.9.0",
+ "bundled": true
+ },
+ "object-assign": {
+ "version": "4.1.1",
+ "bundled": true
+ },
+ "object-keys": {
+ "version": "1.0.12",
+ "bundled": true
+ },
+ "object.getownpropertydescriptors": {
+ "version": "2.0.3",
+ "bundled": true,
+ "requires": {
+ "define-properties": "^1.1.2",
+ "es-abstract": "^1.5.1"
+ }
+ },
+ "once": {
+ "version": "1.4.0",
+ "bundled": true,
+ "requires": {
+ "wrappy": "1"
+ }
+ },
+ "opener": {
+ "version": "1.5.1",
+ "bundled": true
+ },
+ "os-homedir": {
+ "version": "1.0.2",
+ "bundled": true
+ },
+ "os-locale": {
+ "version": "2.1.0",
+ "bundled": true,
+ "requires": {
+ "execa": "^0.7.0",
+ "lcid": "^1.0.0",
+ "mem": "^1.1.0"
+ }
+ },
+ "os-tmpdir": {
+ "version": "1.0.2",
+ "bundled": true
+ },
+ "osenv": {
+ "version": "0.1.5",
+ "bundled": true,
+ "requires": {
+ "os-homedir": "^1.0.0",
+ "os-tmpdir": "^1.0.0"
+ }
+ },
+ "p-finally": {
+ "version": "1.0.0",
+ "bundled": true
+ },
+ "p-limit": {
+ "version": "1.2.0",
+ "bundled": true,
+ "requires": {
+ "p-try": "^1.0.0"
+ }
+ },
+ "p-locate": {
+ "version": "2.0.0",
+ "bundled": true,
+ "requires": {
+ "p-limit": "^1.1.0"
+ }
+ },
+ "p-try": {
+ "version": "1.0.0",
+ "bundled": true
+ },
+ "package-json": {
+ "version": "4.0.1",
+ "bundled": true,
+ "requires": {
+ "got": "^6.7.1",
+ "registry-auth-token": "^3.0.1",
+ "registry-url": "^3.0.3",
+ "semver": "^5.1.0"
+ }
+ },
+ "pacote": {
+ "version": "9.5.8",
+ "bundled": true,
+ "requires": {
+ "bluebird": "^3.5.3",
+ "cacache": "^12.0.2",
+ "chownr": "^1.1.2",
+ "figgy-pudding": "^3.5.1",
+ "get-stream": "^4.1.0",
+ "glob": "^7.1.3",
+ "infer-owner": "^1.0.4",
+ "lru-cache": "^5.1.1",
+ "make-fetch-happen": "^5.0.0",
+ "minimatch": "^3.0.4",
+ "minipass": "^2.3.5",
+ "mississippi": "^3.0.0",
+ "mkdirp": "^0.5.1",
+ "normalize-package-data": "^2.4.0",
+ "npm-package-arg": "^6.1.0",
+ "npm-packlist": "^1.1.12",
+ "npm-pick-manifest": "^3.0.0",
+ "npm-registry-fetch": "^4.0.0",
+ "osenv": "^0.1.5",
+ "promise-inflight": "^1.0.1",
+ "promise-retry": "^1.1.1",
+ "protoduck": "^5.0.1",
+ "rimraf": "^2.6.2",
+ "safe-buffer": "^5.1.2",
+ "semver": "^5.6.0",
+ "ssri": "^6.0.1",
+ "tar": "^4.4.10",
+ "unique-filename": "^1.1.1",
+ "which": "^1.3.1"
+ },
+ "dependencies": {
+ "minipass": {
+ "version": "2.3.5",
+ "bundled": true,
+ "requires": {
+ "safe-buffer": "^5.1.2",
+ "yallist": "^3.0.0"
+ }
+ }
+ }
+ },
+ "parallel-transform": {
+ "version": "1.1.0",
+ "bundled": true,
+ "requires": {
+ "cyclist": "~0.2.2",
+ "inherits": "^2.0.3",
+ "readable-stream": "^2.1.5"
+ },
+ "dependencies": {
+ "readable-stream": {
+ "version": "2.3.6",
+ "bundled": true,
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "string_decoder": {
+ "version": "1.1.1",
+ "bundled": true,
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ }
+ }
+ }
+ },
+ "path-exists": {
+ "version": "3.0.0",
+ "bundled": true
+ },
+ "path-is-absolute": {
+ "version": "1.0.1",
+ "bundled": true
+ },
+ "path-is-inside": {
+ "version": "1.0.2",
+ "bundled": true
+ },
+ "path-key": {
+ "version": "2.0.1",
+ "bundled": true
+ },
+ "path-parse": {
+ "version": "1.0.6",
+ "bundled": true
+ },
+ "performance-now": {
+ "version": "2.1.0",
+ "bundled": true
+ },
+ "pify": {
+ "version": "3.0.0",
+ "bundled": true
+ },
+ "prepend-http": {
+ "version": "1.0.4",
+ "bundled": true
+ },
+ "process-nextick-args": {
+ "version": "2.0.0",
+ "bundled": true
+ },
+ "promise-inflight": {
+ "version": "1.0.1",
+ "bundled": true
+ },
+ "promise-retry": {
+ "version": "1.1.1",
+ "bundled": true,
+ "requires": {
+ "err-code": "^1.0.0",
+ "retry": "^0.10.0"
+ },
+ "dependencies": {
+ "retry": {
+ "version": "0.10.1",
+ "bundled": true
+ }
+ }
+ },
+ "promzard": {
+ "version": "0.3.0",
+ "bundled": true,
+ "requires": {
+ "read": "1"
+ }
+ },
+ "proto-list": {
+ "version": "1.2.4",
+ "bundled": true
+ },
+ "protoduck": {
+ "version": "5.0.1",
+ "bundled": true,
+ "requires": {
+ "genfun": "^5.0.0"
+ }
+ },
+ "prr": {
+ "version": "1.0.1",
+ "bundled": true
+ },
+ "pseudomap": {
+ "version": "1.0.2",
+ "bundled": true
+ },
+ "psl": {
+ "version": "1.1.29",
+ "bundled": true
+ },
+ "pump": {
+ "version": "3.0.0",
+ "bundled": true,
+ "requires": {
+ "end-of-stream": "^1.1.0",
+ "once": "^1.3.1"
+ }
+ },
+ "pumpify": {
+ "version": "1.5.1",
+ "bundled": true,
+ "requires": {
+ "duplexify": "^3.6.0",
+ "inherits": "^2.0.3",
+ "pump": "^2.0.0"
+ },
+ "dependencies": {
+ "pump": {
+ "version": "2.0.1",
+ "bundled": true,
+ "requires": {
+ "end-of-stream": "^1.1.0",
+ "once": "^1.3.1"
+ }
+ }
+ }
+ },
+ "punycode": {
+ "version": "1.4.1",
+ "bundled": true
+ },
+ "qrcode-terminal": {
+ "version": "0.12.0",
+ "bundled": true
+ },
+ "qs": {
+ "version": "6.5.2",
+ "bundled": true
+ },
+ "query-string": {
+ "version": "6.8.2",
+ "bundled": true,
+ "requires": {
+ "decode-uri-component": "^0.2.0",
+ "split-on-first": "^1.0.0",
+ "strict-uri-encode": "^2.0.0"
+ }
+ },
+ "qw": {
+ "version": "1.0.1",
+ "bundled": true
+ },
+ "rc": {
+ "version": "1.2.7",
+ "bundled": true,
+ "requires": {
+ "deep-extend": "^0.5.1",
+ "ini": "~1.3.0",
+ "minimist": "^1.2.0",
+ "strip-json-comments": "~2.0.1"
+ },
+ "dependencies": {
+ "minimist": {
+ "version": "1.2.0",
+ "bundled": true
+ }
+ }
+ },
+ "read": {
+ "version": "1.0.7",
+ "bundled": true,
+ "requires": {
+ "mute-stream": "~0.0.4"
+ }
+ },
+ "read-cmd-shim": {
+ "version": "1.0.3",
+ "bundled": true,
+ "requires": {
+ "graceful-fs": "^4.1.2"
+ }
+ },
+ "read-installed": {
+ "version": "4.0.3",
+ "bundled": true,
+ "requires": {
+ "debuglog": "^1.0.1",
+ "graceful-fs": "^4.1.2",
+ "read-package-json": "^2.0.0",
+ "readdir-scoped-modules": "^1.0.0",
+ "semver": "2 || 3 || 4 || 5",
+ "slide": "~1.1.3",
+ "util-extend": "^1.0.1"
+ }
+ },
+ "read-package-json": {
+ "version": "2.1.0",
+ "bundled": true,
+ "requires": {
+ "glob": "^7.1.1",
+ "graceful-fs": "^4.1.2",
+ "json-parse-better-errors": "^1.0.1",
+ "normalize-package-data": "^2.0.0",
+ "slash": "^1.0.0"
+ }
+ },
+ "read-package-tree": {
+ "version": "5.3.1",
+ "bundled": true,
+ "requires": {
+ "read-package-json": "^2.0.0",
+ "readdir-scoped-modules": "^1.0.0",
+ "util-promisify": "^2.1.0"
+ }
+ },
+ "readable-stream": {
+ "version": "3.4.0",
+ "bundled": true,
+ "requires": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ }
+ },
+ "readdir-scoped-modules": {
+ "version": "1.1.0",
+ "bundled": true,
+ "requires": {
+ "debuglog": "^1.0.1",
+ "dezalgo": "^1.0.0",
+ "graceful-fs": "^4.1.2",
+ "once": "^1.3.0"
+ }
+ },
+ "registry-auth-token": {
+ "version": "3.3.2",
+ "bundled": true,
+ "requires": {
+ "rc": "^1.1.6",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "registry-url": {
+ "version": "3.1.0",
+ "bundled": true,
+ "requires": {
+ "rc": "^1.0.1"
+ }
+ },
+ "request": {
+ "version": "2.88.0",
+ "bundled": true,
+ "requires": {
+ "aws-sign2": "~0.7.0",
+ "aws4": "^1.8.0",
+ "caseless": "~0.12.0",
+ "combined-stream": "~1.0.6",
+ "extend": "~3.0.2",
+ "forever-agent": "~0.6.1",
+ "form-data": "~2.3.2",
+ "har-validator": "~5.1.0",
+ "http-signature": "~1.2.0",
+ "is-typedarray": "~1.0.0",
+ "isstream": "~0.1.2",
+ "json-stringify-safe": "~5.0.1",
+ "mime-types": "~2.1.19",
+ "oauth-sign": "~0.9.0",
+ "performance-now": "^2.1.0",
+ "qs": "~6.5.2",
+ "safe-buffer": "^5.1.2",
+ "tough-cookie": "~2.4.3",
+ "tunnel-agent": "^0.6.0",
+ "uuid": "^3.3.2"
+ }
+ },
+ "require-directory": {
+ "version": "2.1.1",
+ "bundled": true
+ },
+ "require-main-filename": {
+ "version": "1.0.1",
+ "bundled": true
+ },
+ "resolve-from": {
+ "version": "4.0.0",
+ "bundled": true
+ },
+ "retry": {
+ "version": "0.12.0",
+ "bundled": true
+ },
+ "rimraf": {
+ "version": "2.6.3",
+ "bundled": true,
+ "requires": {
+ "glob": "^7.1.3"
+ }
+ },
+ "run-queue": {
+ "version": "1.0.3",
+ "bundled": true,
+ "requires": {
+ "aproba": "^1.1.1"
+ },
+ "dependencies": {
+ "aproba": {
+ "version": "1.2.0",
+ "bundled": true
+ }
+ }
+ },
+ "safe-buffer": {
+ "version": "5.1.2",
+ "bundled": true
+ },
+ "safer-buffer": {
+ "version": "2.1.2",
+ "bundled": true
+ },
+ "semver": {
+ "version": "5.7.1",
+ "bundled": true
+ },
+ "semver-diff": {
+ "version": "2.1.0",
+ "bundled": true,
+ "requires": {
+ "semver": "^5.0.3"
+ }
+ },
+ "set-blocking": {
+ "version": "2.0.0",
+ "bundled": true
+ },
+ "sha": {
+ "version": "3.0.0",
+ "bundled": true,
+ "requires": {
+ "graceful-fs": "^4.1.2"
+ }
+ },
+ "shebang-command": {
+ "version": "1.2.0",
+ "bundled": true,
+ "requires": {
+ "shebang-regex": "^1.0.0"
+ }
+ },
+ "shebang-regex": {
+ "version": "1.0.0",
+ "bundled": true
+ },
+ "signal-exit": {
+ "version": "3.0.2",
+ "bundled": true
+ },
+ "slash": {
+ "version": "1.0.0",
+ "bundled": true
+ },
+ "slide": {
+ "version": "1.1.6",
+ "bundled": true
+ },
+ "smart-buffer": {
+ "version": "4.0.2",
+ "bundled": true
+ },
+ "socks": {
+ "version": "2.3.2",
+ "bundled": true,
+ "requires": {
+ "ip": "^1.1.5",
+ "smart-buffer": "4.0.2"
+ }
+ },
+ "socks-proxy-agent": {
+ "version": "4.0.2",
+ "bundled": true,
+ "requires": {
+ "agent-base": "~4.2.1",
+ "socks": "~2.3.2"
+ },
+ "dependencies": {
+ "agent-base": {
+ "version": "4.2.1",
+ "bundled": true,
+ "requires": {
+ "es6-promisify": "^5.0.0"
+ }
+ }
+ }
+ },
+ "sorted-object": {
+ "version": "2.0.1",
+ "bundled": true
+ },
+ "sorted-union-stream": {
+ "version": "2.1.3",
+ "bundled": true,
+ "requires": {
+ "from2": "^1.3.0",
+ "stream-iterate": "^1.1.0"
+ },
+ "dependencies": {
+ "from2": {
+ "version": "1.3.0",
+ "bundled": true,
+ "requires": {
+ "inherits": "~2.0.1",
+ "readable-stream": "~1.1.10"
+ }
+ },
+ "isarray": {
+ "version": "0.0.1",
+ "bundled": true
+ },
+ "readable-stream": {
+ "version": "1.1.14",
+ "bundled": true,
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.1",
+ "isarray": "0.0.1",
+ "string_decoder": "~0.10.x"
+ }
+ },
+ "string_decoder": {
+ "version": "0.10.31",
+ "bundled": true
+ }
+ }
+ },
+ "spdx-correct": {
+ "version": "3.0.0",
+ "bundled": true,
+ "requires": {
+ "spdx-expression-parse": "^3.0.0",
+ "spdx-license-ids": "^3.0.0"
+ }
+ },
+ "spdx-exceptions": {
+ "version": "2.1.0",
+ "bundled": true
+ },
+ "spdx-expression-parse": {
+ "version": "3.0.0",
+ "bundled": true,
+ "requires": {
+ "spdx-exceptions": "^2.1.0",
+ "spdx-license-ids": "^3.0.0"
+ }
+ },
+ "spdx-license-ids": {
+ "version": "3.0.3",
+ "bundled": true
+ },
+ "split-on-first": {
+ "version": "1.1.0",
+ "bundled": true
+ },
+ "sshpk": {
+ "version": "1.14.2",
+ "bundled": true,
+ "requires": {
+ "asn1": "~0.2.3",
+ "assert-plus": "^1.0.0",
+ "bcrypt-pbkdf": "^1.0.0",
+ "dashdash": "^1.12.0",
+ "ecc-jsbn": "~0.1.1",
+ "getpass": "^0.1.1",
+ "jsbn": "~0.1.0",
+ "safer-buffer": "^2.0.2",
+ "tweetnacl": "~0.14.0"
+ }
+ },
+ "ssri": {
+ "version": "6.0.1",
+ "bundled": true,
+ "requires": {
+ "figgy-pudding": "^3.5.1"
+ }
+ },
+ "stream-each": {
+ "version": "1.2.2",
+ "bundled": true,
+ "requires": {
+ "end-of-stream": "^1.1.0",
+ "stream-shift": "^1.0.0"
+ }
+ },
+ "stream-iterate": {
+ "version": "1.2.0",
+ "bundled": true,
+ "requires": {
+ "readable-stream": "^2.1.5",
+ "stream-shift": "^1.0.0"
+ },
+ "dependencies": {
+ "readable-stream": {
+ "version": "2.3.6",
+ "bundled": true,
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "string_decoder": {
+ "version": "1.1.1",
+ "bundled": true,
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ }
+ }
+ }
+ },
+ "stream-shift": {
+ "version": "1.0.0",
+ "bundled": true
+ },
+ "strict-uri-encode": {
+ "version": "2.0.0",
+ "bundled": true
+ },
+ "string-width": {
+ "version": "2.1.1",
+ "bundled": true,
+ "requires": {
+ "is-fullwidth-code-point": "^2.0.0",
+ "strip-ansi": "^4.0.0"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "3.0.0",
+ "bundled": true
+ },
+ "is-fullwidth-code-point": {
+ "version": "2.0.0",
+ "bundled": true
+ },
+ "strip-ansi": {
+ "version": "4.0.0",
+ "bundled": true,
+ "requires": {
+ "ansi-regex": "^3.0.0"
+ }
+ }
+ }
+ },
+ "string_decoder": {
+ "version": "1.2.0",
+ "bundled": true,
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ }
+ },
+ "stringify-package": {
+ "version": "1.0.0",
+ "bundled": true
+ },
+ "strip-ansi": {
+ "version": "3.0.1",
+ "bundled": true,
+ "requires": {
+ "ansi-regex": "^2.0.0"
+ }
+ },
+ "strip-eof": {
+ "version": "1.0.0",
+ "bundled": true
+ },
+ "strip-json-comments": {
+ "version": "2.0.1",
+ "bundled": true
+ },
+ "supports-color": {
+ "version": "5.4.0",
+ "bundled": true,
+ "requires": {
+ "has-flag": "^3.0.0"
+ }
+ },
+ "tar": {
+ "version": "4.4.10",
+ "bundled": true,
+ "requires": {
+ "chownr": "^1.1.1",
+ "fs-minipass": "^1.2.5",
+ "minipass": "^2.3.5",
+ "minizlib": "^1.2.1",
+ "mkdirp": "^0.5.0",
+ "safe-buffer": "^5.1.2",
+ "yallist": "^3.0.3"
+ },
+ "dependencies": {
+ "minipass": {
+ "version": "2.3.5",
+ "bundled": true,
+ "requires": {
+ "safe-buffer": "^5.1.2",
+ "yallist": "^3.0.0"
+ }
+ },
+ "yallist": {
+ "version": "3.0.3",
+ "bundled": true
+ }
+ }
+ },
+ "term-size": {
+ "version": "1.2.0",
+ "bundled": true,
+ "requires": {
+ "execa": "^0.7.0"
+ }
+ },
+ "text-table": {
+ "version": "0.2.0",
+ "bundled": true
+ },
+ "through": {
+ "version": "2.3.8",
+ "bundled": true
+ },
+ "through2": {
+ "version": "2.0.3",
+ "bundled": true,
+ "requires": {
+ "readable-stream": "^2.1.5",
+ "xtend": "~4.0.1"
+ },
+ "dependencies": {
+ "readable-stream": {
+ "version": "2.3.6",
+ "bundled": true,
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "string_decoder": {
+ "version": "1.1.1",
+ "bundled": true,
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ }
+ }
+ }
+ },
+ "timed-out": {
+ "version": "4.0.1",
+ "bundled": true
+ },
+ "tiny-relative-date": {
+ "version": "1.3.0",
+ "bundled": true
+ },
+ "tough-cookie": {
+ "version": "2.4.3",
+ "bundled": true,
+ "requires": {
+ "psl": "^1.1.24",
+ "punycode": "^1.4.1"
+ }
+ },
+ "tunnel-agent": {
+ "version": "0.6.0",
+ "bundled": true,
+ "requires": {
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "tweetnacl": {
+ "version": "0.14.5",
+ "bundled": true,
+ "optional": true
+ },
+ "typedarray": {
+ "version": "0.0.6",
+ "bundled": true
+ },
+ "uid-number": {
+ "version": "0.0.6",
+ "bundled": true
+ },
+ "umask": {
+ "version": "1.1.0",
+ "bundled": true
+ },
+ "unique-filename": {
+ "version": "1.1.1",
+ "bundled": true,
+ "requires": {
+ "unique-slug": "^2.0.0"
+ }
+ },
+ "unique-slug": {
+ "version": "2.0.0",
+ "bundled": true,
+ "requires": {
+ "imurmurhash": "^0.1.4"
+ }
+ },
+ "unique-string": {
+ "version": "1.0.0",
+ "bundled": true,
+ "requires": {
+ "crypto-random-string": "^1.0.0"
+ }
+ },
+ "unpipe": {
+ "version": "1.0.0",
+ "bundled": true
+ },
+ "unzip-response": {
+ "version": "2.0.1",
+ "bundled": true
+ },
+ "update-notifier": {
+ "version": "2.5.0",
+ "bundled": true,
+ "requires": {
+ "boxen": "^1.2.1",
+ "chalk": "^2.0.1",
+ "configstore": "^3.0.0",
+ "import-lazy": "^2.1.0",
+ "is-ci": "^1.0.10",
+ "is-installed-globally": "^0.1.0",
+ "is-npm": "^1.0.0",
+ "latest-version": "^3.0.0",
+ "semver-diff": "^2.0.0",
+ "xdg-basedir": "^3.0.0"
+ }
+ },
+ "url-parse-lax": {
+ "version": "1.0.0",
+ "bundled": true,
+ "requires": {
+ "prepend-http": "^1.0.1"
+ }
+ },
+ "util-deprecate": {
+ "version": "1.0.2",
+ "bundled": true
+ },
+ "util-extend": {
+ "version": "1.0.3",
+ "bundled": true
+ },
+ "util-promisify": {
+ "version": "2.1.0",
+ "bundled": true,
+ "requires": {
+ "object.getownpropertydescriptors": "^2.0.3"
+ }
+ },
+ "uuid": {
+ "version": "3.3.2",
+ "bundled": true
+ },
+ "validate-npm-package-license": {
+ "version": "3.0.4",
+ "bundled": true,
+ "requires": {
+ "spdx-correct": "^3.0.0",
+ "spdx-expression-parse": "^3.0.0"
+ }
+ },
+ "validate-npm-package-name": {
+ "version": "3.0.0",
+ "bundled": true,
+ "requires": {
+ "builtins": "^1.0.3"
+ }
+ },
+ "verror": {
+ "version": "1.10.0",
+ "bundled": true,
+ "requires": {
+ "assert-plus": "^1.0.0",
+ "core-util-is": "1.0.2",
+ "extsprintf": "^1.2.0"
+ }
+ },
+ "wcwidth": {
+ "version": "1.0.1",
+ "bundled": true,
+ "requires": {
+ "defaults": "^1.0.3"
+ }
+ },
+ "which": {
+ "version": "1.3.1",
+ "bundled": true,
+ "requires": {
+ "isexe": "^2.0.0"
+ }
+ },
+ "which-module": {
+ "version": "2.0.0",
+ "bundled": true
+ },
+ "wide-align": {
+ "version": "1.1.2",
+ "bundled": true,
+ "requires": {
+ "string-width": "^1.0.2"
+ },
+ "dependencies": {
+ "string-width": {
+ "version": "1.0.2",
+ "bundled": true,
+ "requires": {
+ "code-point-at": "^1.0.0",
+ "is-fullwidth-code-point": "^1.0.0",
+ "strip-ansi": "^3.0.0"
+ }
+ }
+ }
+ },
+ "widest-line": {
+ "version": "2.0.0",
+ "bundled": true,
+ "requires": {
+ "string-width": "^2.1.1"
+ }
+ },
+ "worker-farm": {
+ "version": "1.7.0",
+ "bundled": true,
+ "requires": {
+ "errno": "~0.1.7"
+ }
+ },
+ "wrap-ansi": {
+ "version": "2.1.0",
+ "bundled": true,
+ "requires": {
+ "string-width": "^1.0.1",
+ "strip-ansi": "^3.0.1"
+ },
+ "dependencies": {
+ "string-width": {
+ "version": "1.0.2",
+ "bundled": true,
+ "requires": {
+ "code-point-at": "^1.0.0",
+ "is-fullwidth-code-point": "^1.0.0",
+ "strip-ansi": "^3.0.0"
+ }
+ }
+ }
+ },
+ "wrappy": {
+ "version": "1.0.2",
+ "bundled": true
+ },
+ "write-file-atomic": {
+ "version": "2.4.3",
+ "bundled": true,
+ "requires": {
+ "graceful-fs": "^4.1.11",
+ "imurmurhash": "^0.1.4",
+ "signal-exit": "^3.0.2"
+ }
+ },
+ "xdg-basedir": {
+ "version": "3.0.0",
+ "bundled": true
+ },
+ "xtend": {
+ "version": "4.0.1",
+ "bundled": true
+ },
+ "y18n": {
+ "version": "4.0.0",
+ "bundled": true
+ },
+ "yallist": {
+ "version": "3.0.3",
+ "bundled": true
+ },
+ "yargs": {
+ "version": "11.0.0",
+ "bundled": true,
+ "requires": {
+ "cliui": "^4.0.0",
+ "decamelize": "^1.1.1",
+ "find-up": "^2.1.0",
+ "get-caller-file": "^1.0.1",
+ "os-locale": "^2.0.0",
+ "require-directory": "^2.1.1",
+ "require-main-filename": "^1.0.1",
+ "set-blocking": "^2.0.0",
+ "string-width": "^2.0.0",
+ "which-module": "^2.0.0",
+ "y18n": "^3.2.1",
+ "yargs-parser": "^9.0.2"
+ },
+ "dependencies": {
+ "y18n": {
+ "version": "3.2.1",
+ "bundled": true
+ }
+ }
+ },
+ "yargs-parser": {
+ "version": "9.0.2",
+ "bundled": true,
+ "requires": {
+ "camelcase": "^4.1.0"
+ }
+ }
+ }
+ },
+ "number-is-nan": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
+ "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0="
+ },
+ "optjs": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/optjs/-/optjs-3.2.2.tgz",
+ "integrity": "sha1-aabOicRCpEQDFBrS+bNwvVu29O4="
+ },
+ "os-locale": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz",
+ "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=",
+ "requires": {
+ "lcid": "^1.0.0"
+ }
+ },
+ "protobufjs": {
+ "version": "6.8.8",
+ "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.8.8.tgz",
+ "integrity": "sha512-AAmHtD5pXgZfi7GMpllpO3q1Xw1OYldr+dMUlAnffGTAhqkg72WdmSY71uKBF/JuyiKs8psYbtKrhi0ASCD8qw==",
+ "requires": {
+ "@protobufjs/aspromise": "^1.1.2",
+ "@protobufjs/base64": "^1.1.2",
+ "@protobufjs/codegen": "^2.0.4",
+ "@protobufjs/eventemitter": "^1.1.0",
+ "@protobufjs/fetch": "^1.1.0",
+ "@protobufjs/float": "^1.0.2",
+ "@protobufjs/inquire": "^1.1.0",
+ "@protobufjs/path": "^1.1.2",
+ "@protobufjs/pool": "^1.1.0",
+ "@protobufjs/utf8": "^1.1.0",
+ "@types/long": "^4.0.0",
+ "@types/node": "^10.1.0",
+ "long": "^4.0.0"
+ },
+ "dependencies": {
+ "@types/node": {
+ "version": "10.14.16",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-10.14.16.tgz",
+ "integrity": "sha512-/opXIbfn0P+VLt+N8DE4l8Mn8rbhiJgabU96ZJ0p9mxOkIks5gh6RUnpHak7Yh0SFkyjO/ODbxsQQPV2bpMmyA=="
+ }
+ }
+ },
+ "string-width": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
+ "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
+ "requires": {
+ "code-point-at": "^1.0.0",
+ "is-fullwidth-code-point": "^1.0.0",
+ "strip-ansi": "^3.0.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+ "requires": {
+ "ansi-regex": "^2.0.0"
+ }
+ },
+ "window-size": {
+ "version": "0.1.4",
+ "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.4.tgz",
+ "integrity": "sha1-+OGqHuWlPsW/FR/6CXQqatdpeHY="
+ },
+ "wrap-ansi": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
+ "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=",
+ "requires": {
+ "string-width": "^1.0.1",
+ "strip-ansi": "^3.0.1"
+ }
+ },
+ "y18n": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz",
+ "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE="
+ },
+ "yargs": {
+ "version": "3.32.0",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.32.0.tgz",
+ "integrity": "sha1-AwiOnr+edWtpdRYR0qXvWRSCyZU=",
+ "requires": {
+ "camelcase": "^2.0.1",
+ "cliui": "^3.0.3",
+ "decamelize": "^1.1.1",
+ "os-locale": "^1.4.0",
+ "string-width": "^1.0.1",
+ "window-size": "^0.1.4",
+ "y18n": "^3.2.0"
+ }
+ }
+ }
+}
--- /dev/null
+{
+ "name": "ua-node-example",
+ "version": "0.1.0",
+ "dependencies": {
+ "@grpc/proto-loader": "^0.1.0",
+ "async": "^1.5.2",
+ "google-protobuf": "^3.0.0",
+ "grpc": "^1.11.0",
+ "lodash": "^4.6.1",
+ "minimist": "^1.2.0",
+ "npm": "^6.11.2"
+ }
+}
--- /dev/null
+```sh
+
+python3 -m venv v
+
+source v/bin/active
+
+pip3 install -r requiements.txt
+
+./gen.sh
+
+python3 sample01.py
+
+./deactivate
+
+```
--- /dev/null
+#!/bin/bash
+
+python3 -m grpc_tools.protoc --python_out=./ --grpc_python_out=./ -I ./../../ ../../aurum.proto
+
--- /dev/null
+from __future__ import print_function
+import aurum_pb2
+import aurum_pb2_grpc
+import logging
+import grpc
+
+def run():
+ with grpc.insecure_channel('127.0.0.1:50051') as channel:
+ stub = aurum_pb2_grpc.BootstrapStub(channel)
+ stub.killServer(aurum_pb2.ReqEmpty())
+
+if __name__ == '__main__':
+ logging.basicConfig()
+ run()
\ No newline at end of file
--- /dev/null
+grpcio==1.23.0
+grpcio-tools==1.23.0
+pkg-resources==0.0.0
+protobuf==3.9.1
+six==1.12.0
--- /dev/null
+from __future__ import print_function
+import aurum_pb2
+import aurum_pb2_grpc
+import logging
+import grpc
+import time
+
+def back(stub):
+ rsp_key = stub.sendKey(aurum_pb2.ReqKey(
+ type='BACK',
+ actionType='STROKE',
+ )
+ )
+
+ rsp_find = stub.findElement(aurum_pb2.ReqFindElement(
+ strategy='TEXT',
+ textField='TestMemo'
+ )
+ )
+
+ for item in rsp_find.elements:
+ print(item)
+ stub.click(aurum_pb2.ReqClick(
+ type='ELEMENTID',
+ elementId=item.elementId
+ )
+ )
+
+def findNclick(stub, text):
+ rsp_find = stub.findElement(aurum_pb2.ReqFindElement(
+ strategy='TEXT',
+ textField=text
+ )
+ )
+
+ for item in rsp_find.elements:
+ print(item)
+ stub.click(aurum_pb2.ReqClick(
+ type='ELEMENTID',
+ elementId=item.elementId
+ )
+ )
+
+def flick(stub):
+ rsp_flick = stub.flick(aurum_pb2.ReqFlick(
+ startPoint=aurum_pb2.Point(x=100, y=100),
+ endPoint=aurum_pb2.Point(x=400, y=400),
+ durationMs=1
+ ))
+
+def launchApp(stub):
+ rsp_launch = stub.launchApp(aurum_pb2.ReqLaunchApp(
+ packageName='org.example.uicomponents'
+ ))
+
+def closeApp(stub):
+ rsp_launch = stub.closeApp(aurum_pb2.ReqCloseApp(
+ packageName='org.example.uicomponents'
+ ))
+
+CHUNK_SIZE = 1024 * 1024
+def get_file_chunks(filename):
+ with open(filename, 'rb') as f:
+ while True:
+ piece = f.read(CHUNK_SIZE)
+ if len(piece) == 0:
+ return
+ yield aurum_pb2.ReqInstallApp(package=piece)
+
+def installApp(stub):
+ in_file_name = './org.tizen.uicomponents.arm.tpk'
+ chunks_generator = get_file_chunks(in_file_name)
+ rsp_install = stub.installApp(chunks_generator)
+
+def removeApp(stub):
+ rsp_install = stub.removeApp(aurum_pb2.ReqRemoveApp(
+ packageName='org.example.uicomponents'
+ )
+ )
+
+def getAppInfo(stub):
+ rsp_info = stub.getAppInfo(aurum_pb2.ReqGetAppInfo(packageName='org.example.uicomponents'))
+ print(rsp_info)
+
+def touchdown(stub, xx, yy):
+ rsp = stub.touchDown(aurum_pb2.ReqTouchDown(coordination=aurum_pb2.Point(x=xx,y=yy)))
+ print(rsp)
+
+def touchmove(stub, xx, yy):
+ rsp = stub.touchMove(aurum_pb2.ReqTouchMove(coordination=aurum_pb2.Point(x=xx,y=yy)))
+ print(rsp)
+
+def touchup(stub, xx, yy):
+ rsp = stub.touchUp(aurum_pb2.ReqTouchUp(coordination=aurum_pb2.Point(x=xx,y=yy)))
+ print(rsp)
+
+def sync(stub):
+ rsp = stub.sync(aurum_pb2.ReqEmpty())
+ print(rsp)
+
+def run():
+ with grpc.insecure_channel('127.0.0.1:50051') as channel:
+ stub = aurum_pb2_grpc.BootstrapStub(channel)
+
+ findNclick(stub, 'Testmemo')
+ back(stub)
+ flick(stub)
+ installApp(stub)
+ time.sleep(1)
+ launchApp(stub)
+ time.sleep(1)
+ getAppInfo(stub)
+ time.sleep(1)
+ closeApp(stub)
+ time.sleep(1)
+# removeApp(stub)
+ flick(stub)
+ touchdown(stub, 300, 300)
+ touchmove(stub, 250, 250)
+ touchmove(stub, 200, 200)
+ touchmove(stub, 110, 110)
+ touchup(stub, 100, 100)
+
+if __name__ == '__main__':
+ logging.basicConfig()
+ run()
--- /dev/null
+from __future__ import print_function
+import aurum_pb2
+import aurum_pb2_grpc
+import logging
+import grpc
+import time
+
+def sendKey(stub, key):
+ rsp_key = stub.sendKey(aurum_pb2.ReqKey(
+ type=key,
+ actionType='STROKE',
+ )
+ )
+ time.sleep(1)
+
+def launchApp(stub, pkgname):
+ rsp_launch = stub.launchApp(aurum_pb2.ReqLaunchApp(
+ packageName=pkgname
+ ))
+
+def closeApp(stub, pkgname):
+ rsp_launch = stub.closeApp(aurum_pb2.ReqCloseApp(
+ packageName=pkgname
+ ))
+
+def getAppInfo(stub, pkgname):
+ rsp_info = stub.getAppInfo(aurum_pb2.ReqGetAppInfo(packageName=pkgname))
+ print(rsp_info)
+
+def touchdown(stub, xx, yy):
+ rsp = stub.touchDown(aurum_pb2.ReqTouchDown(coordination=aurum_pb2.Point(x=xx,y=yy)))
+ print(rsp)
+
+def touchmove(stub, xx, yy):
+ rsp = stub.touchMove(aurum_pb2.ReqTouchMove(coordination=aurum_pb2.Point(x=xx,y=yy)))
+ print(rsp)
+
+def touchup(stub, xx, yy):
+ rsp = stub.touchUp(aurum_pb2.ReqTouchUp(coordination=aurum_pb2.Point(x=xx,y=yy)))
+ print(rsp)
+
+def sync(stub):
+ rsp = stub.sync(aurum_pb2.ReqEmpty())
+ print(rsp)
+
+
+def new_memo(stub):
+ touchdown(stub, 630,1140)
+ time.sleep(0.1)
+ touchup(stub, 630,1140)
+ time.sleep(0.5)
+
+def findElementByText(stub, text):
+ rsp_find = stub.findElement(aurum_pb2.ReqFindElement(
+ strategy='TEXT',
+ textField=text
+ )
+ )
+ for item in rsp_find.elements:
+ return item.elementId
+ return None
+
+def findElementsByText(stub, text):
+ rsp_find = stub.findElement(aurum_pb2.ReqFindElement(
+ strategy='TEXT',
+ textField=text
+ )
+ )
+ return rsp_find.elements
+
+def clickById(stub, id):
+ stub.click(aurum_pb2.ReqClick(
+ type='ELEMENTID',
+ elementId=id
+ )
+ )
+
+def run_memo(stub):
+ foundId = findElementByText(stub, 'All apps')
+ time.sleep(1)
+ if foundId != None:
+ clickById(stub, foundId)
+ time.sleep(1)
+
+ foundId = findElementByText(stub, 'Memo')
+ time.sleep(1)
+ if foundId != None:
+ clickById(stub, foundId)
+ time.sleep(2)
+
+def set_text(stub, text):
+ foundId = findElementByText(stub, 'Title')
+ if foundId != None:
+ clickById(stub, foundId)
+ time.sleep(1.2)
+ stub.setValue(aurum_pb2.ReqSetValue(
+ elementId=foundId,
+ stringValue=text))
+ foundIds = findElementsByText(stub, "Memo")
+ if len(foundIds) >= 2:
+ stub.setValue(aurum_pb2.ReqSetValue(
+ elementId=foundIds[1].elementId,
+ stringValue=text))
+ time.sleep(0.2)
+ foundId = findElementByText(stub, 'DONE')
+ if foundId != None:
+ clickById(stub, foundId)
+
+
+def run():
+ with grpc.insecure_channel('127.0.0.1:50051') as channel:
+ stub = aurum_pb2_grpc.BootstrapStub(channel)
+
+ getAppInfo(stub, 'org.tizen.memo')
+ time.sleep(1)
+ sendKey(stub, 'HOME')
+ time.sleep(1)
+ closeApp(stub, 'org.tizen.memo')
+ time.sleep(1)
+ getAppInfo(stub, 'org.tizen.memo')
+ time.sleep(1)
+ run_memo(stub)
+ time.sleep(1)
+ new_memo(stub)
+ time.sleep(1)
+ set_text(stub, 'hello')
+
+if __name__ == '__main__':
+ logging.basicConfig()
+ run()
--- /dev/null
+from __future__ import print_function
+import aurum_pb2
+import aurum_pb2_grpc
+import logging
+import grpc
+import time
+
+def sendKey(stub, key):
+ rsp_key = stub.sendKey(aurum_pb2.ReqKey(
+ type=key,
+ actionType='STROKE',
+ )
+ )
+ time.sleep(1.5)
+
+def launchApp(stub, pkgname):
+ rsp_launch = stub.launchApp(aurum_pb2.ReqLaunchApp(
+ packageName=pkgname
+ ))
+
+def closeApp(stub, pkgname):
+ rsp_launch = stub.closeApp(aurum_pb2.ReqCloseApp(
+ packageName=pkgname
+ ))
+
+def getAppInfo(stub, pkgname):
+ rsp_info = stub.getAppInfo(aurum_pb2.ReqGetAppInfo(packageName=pkgname))
+ print(rsp_info)
+
+def touchdown(stub, xx, yy):
+ rsp = stub.touchDown(aurum_pb2.ReqTouchDown(coordination=aurum_pb2.Point(x=xx,y=yy)))
+ print(rsp)
+
+def touchmove(stub, xx, yy):
+ rsp = stub.touchMove(aurum_pb2.ReqTouchMove(coordination=aurum_pb2.Point(x=xx,y=yy)))
+ print(rsp)
+
+def touchup(stub, xx, yy):
+ rsp = stub.touchUp(aurum_pb2.ReqTouchUp(coordination=aurum_pb2.Point(x=xx,y=yy)))
+ print(rsp)
+
+def sync(stub):
+ rsp = stub.sync(aurum_pb2.ReqEmpty())
+ print(rsp)
+
+
+def new_memo(stub):
+ touchdown(stub, 630,1140)
+ time.sleep(0.1)
+ touchup(stub, 630,1140)
+ time.sleep(0.3)
+
+def findElementByText(stub, text):
+ rsp_find = stub.findElement(aurum_pb2.ReqFindElement(
+ strategy='TEXT',
+ textField=text
+ )
+ )
+ for item in rsp_find.elements:
+ return item.elementId
+ return None
+
+def findElementsByText(stub, text):
+ rsp_find = stub.findElement(aurum_pb2.ReqFindElement(
+ strategy='TEXT',
+ textField=text
+ )
+ )
+ els = []
+ for el in rsp_find.elements:
+ els.append(el.elementId)
+ return els
+
+def clickById(stub, id):
+ stub.click(aurum_pb2.ReqClick(
+ type='ELEMENTID',
+ elementId=id
+ )
+ )
+
+def run_memo(stub):
+ foundId = findElementByText(stub, 'All apps')
+ time.sleep(1.5)
+ if foundId != None:
+ clickById(stub, foundId)
+ time.sleep(1.5)
+
+ foundId = findElementByText(stub, 'Memo')
+ time.sleep(1.5)
+ if foundId != None:
+ clickById(stub, foundId)
+ time.sleep(2.5)
+
+def set_text(stub, text):
+ foundIds = findElementsByText(stub, "Memo")
+ foundIds += (findElementsByText(stub, "Title"))
+ print(foundIds)
+ for el in foundIds:
+ print(el)
+ stub.setValue(aurum_pb2.ReqSetValue(
+ elementId=el,
+ stringValue=text))
+
+ #foundId = findElementByText(stub, 'DONE')
+ #if foundId != None:
+ # clickById(stub, foundId)
+
+
+def run():
+ with grpc.insecure_channel('127.0.0.1:50051') as channel:
+ stub = aurum_pb2_grpc.BootstrapStub(channel)
+ set_text(stub, 'hello')
+
+if __name__ == '__main__':
+ logging.basicConfig()
+ run()
--- /dev/null
+grpc_deps = []
+grpc_deps += dependency('protobuf')
+grpc_deps += dependency('grpc')
+grpc_deps += dependency('grpc++')
+
+grpc_protoc_prog = find_program('protoc')
+grpc_cpp_plug_prog = find_program('grpc_cpp_plugin')
+
+grpc_pb_gen = generator(
+ grpc_protoc_prog,
+ output : ['@BASENAME@.pb.cc', '@BASENAME@.pb.h'],
+ arguments : ['--proto_path=@CURRENT_SOURCE_DIR@', '--cpp_out=@BUILD_DIR@', '@INPUT@']
+)
+
+grpc_grpc_gen = generator(
+ grpc_protoc_prog,
+ output : ['@BASENAME@.grpc.pb.cc', '@BASENAME@.grpc.pb.h'],
+ arguments : ['--proto_path=@CURRENT_SOURCE_DIR@', '--grpc_out=@BUILD_DIR@', '--plugin=protoc-gen-grpc='+grpc_cpp_plug_prog.path(), '@INPUT@']
+)
+
+grpc_pb_src = grpc_pb_gen.process(files('aurum.proto'))
+grpc_src = grpc_grpc_gen.process(files('aurum.proto'))
+
+ui_protocol_bin = executable('ui_protocol_bin',
+ files('empty.cpp'), grpc_pb_src, grpc_src,
+ dependencies: [grpc_deps]
+)
--- /dev/null
+test_src = [
+ files('ua_test.cpp'),
+]
+
+test_inc = [
+ include_directories('./')
+]
+
+test_deps = [
+ dependency('gtest', main:true),
+ libaurum,
+]
+
+test_bin = executable('ua_test', test_src,
+ include_directories: test_inc,
+ dependencies: test_deps,
+ )
+
+test('ua test', test_bin)
\ No newline at end of file
--- /dev/null
+#include <gtest/gtest.h>
+
+#include <UiDevice.h>
+#include <UiObject.h>
+#include <UiSelector.h>
+#include <Sel.h>
+
+class UaTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ }
+
+ void TearDown() override {
+ }
+};
+
+TEST_F(UaTest, EmptyTest)
+{
+ ASSERT_EQ(true, true);
+}
+
+TEST_F(UaTest, DeviceInit)
+{
+ const UiDevice *mDevice = UiDevice::getInstance(DeviceType::DEFAULT);
+ ASSERT_NE(mDevice, nullptr);
+}
+
+TEST_F(UaTest, TextSelector)
+{
+ std::unique_ptr<UiSelector> sel = Sel::text("test");
+ ASSERT_NE(sel.get(), nullptr);
+}
\ No newline at end of file